mutter/cogl/driver/gl/cogl-pipeline-progend-glsl.c

1046 lines
34 KiB
C
Raw Normal View History

/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*
*
* Authors:
* Neil Roberts <neil@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
#include <string.h>
#include "cogl-util.h"
#include "cogl-context-private.h"
#include "cogl-pipeline-private.h"
#include "cogl-pipeline-opengl-private.h"
#include "cogl-offscreen.h"
#ifdef COGL_PIPELINE_PROGEND_GLSL
#include "cogl-internal.h"
#include "cogl-context-private.h"
#include "cogl-object-private.h"
#include "cogl-program-private.h"
#include "cogl-pipeline-fragend-glsl-private.h"
#include "cogl-pipeline-vertend-glsl-private.h"
#include "cogl-pipeline-cache.h"
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
#include "cogl-pipeline-state-private.h"
#include "cogl-attribute-private.h"
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
#include "cogl-framebuffer-private.h"
Add -Wmissing-declarations to maintainer flags and fix problems This option to GCC makes it give a warning whenever a global function is defined without a declaration. This should catch cases were we've defined a function but forgot to put it in a header. In that case it is either only used within one file so we should make it static or we should declare it in a header. The following changes where made to fix problems: • Some functions were made static • cogl-path.h (the one containing the 1.0 API) was split into two files, one defining the functions and one defining the enums so that cogl-path.c can include the enum and function declarations from the 2.0 API as well as the function declarations from the 1.0 API. • cogl2-clip-state has been removed. This only had one experimental function called cogl_clip_push_from_path but as this is unstable we might as well remove it favour of the equivalent cogl_framebuffer_* API. • The GLX, SDL and WGL winsys's now have a private header to define their get_vtable function instead of directly declaring in the C file where it is called. • All places that were calling COGL_OBJECT_DEFINE need to have the cogl_is_whatever function declared so these have been added either as a public function or in a private header. • Some files that were not including the header containing their function declarations have been fixed to do so. • Any unused error quark functions have been removed. If we later want them we should add them back one by one and add a declaration for them in a header. • _cogl_is_framebuffer has been renamed to cogl_is_framebuffer and made a public function with a declaration in cogl-framebuffer.h • Similarly for CoglOnscreen. • cogl_vdraw_indexed_attributes is called cogl_framebuffer_vdraw_indexed_attributes in the header. The definition has been changed to match the header. • cogl_index_buffer_allocate has been removed. This had no declaration and I'm not sure what it's supposed to do. • CoglJournal has been changed to use the internal CoglObject macro so that it won't define an exported cogl_is_journal symbol. • The _cogl_blah_pointer_from_handle functions have been removed. CoglHandle isn't used much anymore anyway and in the few places where it is used I think it's safe to just use the implicit cast from void* to the right type. • The test-utils.h header for the conformance tests explicitly disables the -Wmissing-declaration option using a pragma because all of the tests declare their main function without a header. Any mistakes relating to missing declarations aren't really important for the tests. • cogl_quaternion_init_from_quaternion and init_from_matrix have been given declarations in cogl-quaternion.h Reviewed-by: Robert Bragg <robert@linux.intel.com>
2012-03-06 18:21:28 +00:00
#include "cogl-pipeline-progend-glsl-private.h"
/* These are used to generalise updating some uniforms that are
required when building for drivers missing some fixed function
state that we use */
typedef void (* UpdateUniformFunc) (CoglPipeline *pipeline,
int uniform_location,
void *getter_func);
static void update_float_uniform (CoglPipeline *pipeline,
int uniform_location,
void *getter_func);
typedef struct
{
const char *uniform_name;
void *getter_func;
UpdateUniformFunc update_func;
CoglPipelineState change;
/* This builtin is only necessary if the following private feature
* is not implemented in the driver */
CoglPrivateFeatureFlags feature_replacement;
} BuiltinUniformData;
static BuiltinUniformData builtin_uniforms[] =
{
{ "cogl_point_size_in",
cogl_pipeline_get_point_size, update_float_uniform,
COGL_PIPELINE_STATE_POINT_SIZE,
COGL_PRIVATE_FEATURE_BUILTIN_POINT_SIZE_UNIFORM },
{ "_cogl_alpha_test_ref",
cogl_pipeline_get_alpha_test_reference, update_float_uniform,
COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE,
COGL_PRIVATE_FEATURE_ALPHA_TEST }
};
const CoglPipelineProgend _cogl_pipeline_glsl_progend;
typedef struct _UnitState
{
unsigned int dirty_combine_constant:1;
unsigned int dirty_texture_matrix:1;
GLint combine_constant_uniform;
GLint texture_matrix_uniform;
} UnitState;
typedef struct
{
unsigned int ref_count;
/* Age that the user program had last time we generated a GL
program. If it's different then we need to relink the program */
unsigned int user_program_age;
GLuint program;
unsigned long dirty_builtin_uniforms;
GLint builtin_uniform_locations[G_N_ELEMENTS (builtin_uniforms)];
GLint modelview_uniform;
GLint projection_uniform;
GLint mvp_uniform;
Re-design the matrix stack using a graph of ops This re-designs the matrix stack so we now keep track of each separate operation such as rotating, scaling, translating and multiplying as immutable, ref-counted nodes in a graph. Being a "graph" here means that different transformations composed of a sequence of linked operation nodes may share nodes. The first node in a matrix-stack is always a LOAD_IDENTITY operation. As an example consider if an application where to draw three rectangles A, B and C something like this: cogl_framebuffer_scale (fb, 2, 2, 2); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_translate (fb, 10, 0, 0); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_rotate (fb, 45, 0, 0, 1); cogl_framebuffer_draw_rectangle (...); /* A */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_draw_rectangle (...); /* B */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_set_modelview_matrix (fb, &mv); cogl_framebuffer_draw_rectangle (...); /* C */ cogl_framebuffer_pop_matrix(fb); That would result in a graph of nodes like this: LOAD_IDENTITY | SCALE / \ SAVE LOAD | | TRANSLATE RECTANGLE(C) | \ SAVE RECTANGLE(B) | ROTATE | RECTANGLE(A) Each push adds a SAVE operation which serves as a marker to rewind too when a corresponding pop is issued and also each SAVE node may also store a cached matrix representing the composition of all its ancestor nodes. This means if we repeatedly need to resolve a real CoglMatrix for a given node then we don't need to repeat the composition. Some advantages of this design are: - A single pointer to any node in the graph can now represent a complete, immutable transformation that can be logged for example into a journal. Previously we were storing a full CoglMatrix in each journal entry which is 16 floats for the matrix itself as well as space for flags and another 16 floats for possibly storing a cache of the inverse. This means that we significantly reduce the size of the journal when drawing lots of primitives and we also avoid copying over 128 bytes per entry. - It becomes much cheaper to check for equality. In cases where some (unlikely) false negatives are allowed simply comparing the pointers of two matrix stack graph entries is enough. Previously we would use memcmp() to compare matrices. - It becomes easier to do comparisons of transformations. By looking for the common ancestry between nodes we can determine the operations that differentiate the transforms and use those to gain a high level understanding of the differences. For example we use this in the journal to be able to efficiently determine when two rectangle transforms only differ by some translation so that we can perform software clipping. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit f75aee93f6b293ca7a7babbd8fcc326ee6bf7aef)
2012-02-20 15:59:48 +00:00
CoglMatrixEntryCache projection_cache;
CoglMatrixEntryCache modelview_cache;
/* We need to track the last pipeline that the program was used with
* so know if we need to update all of the uniforms */
CoglPipeline *last_used_for_pipeline;
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
/* Array of GL uniform locations indexed by Cogl's uniform
location. We are careful only to allocated this array if a custom
uniform is actually set */
GArray *uniform_locations;
/* Array of attribute locations. */
GArray *attribute_locations;
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
/* The 'flip' uniform is used to flip the geometry upside-down when
the framebuffer requires it only when there are vertex
snippets. Otherwise this is acheived using the projection
matrix */
GLint flip_uniform;
int flushed_flip_state;
UnitState *unit_state;
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
} CoglPipelineProgramState;
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
static CoglUserDataKey program_state_key;
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
static CoglPipelineProgramState *
get_program_state (CoglPipeline *pipeline)
{
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
return cogl_object_get_user_data (COGL_OBJECT (pipeline), &program_state_key);
}
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
#define UNIFORM_LOCATION_UNKNOWN -2
#define ATTRIBUTE_LOCATION_UNKNOWN -2
/* Under GLES2 the vertex attribute API needs to query the attribute
numbers because it can't used the fixed function API to set the
builtin attributes. We cache the attributes here because the
progend knows when the program is changed so it can clear the
cache. This should always be called after the pipeline is flushed
so they can assert that the gl program is valid */
/* All attributes names get internally mapped to a global set of
* sequential indices when they are setup which we need to need to
* then be able to map to a GL attribute location once we have
* a linked GLSL program */
int
_cogl_pipeline_progend_glsl_get_attrib_location (CoglPipeline *pipeline,
int name_index)
{
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
CoglPipelineProgramState *program_state = get_program_state (pipeline);
int *locations;
_COGL_GET_CONTEXT (ctx, -1);
_COGL_RETURN_VAL_IF_FAIL (program_state != NULL, -1);
_COGL_RETURN_VAL_IF_FAIL (program_state->program != 0, -1);
if (G_UNLIKELY (program_state->attribute_locations == NULL))
program_state->attribute_locations =
g_array_new (FALSE, FALSE, sizeof (int));
if (G_UNLIKELY (program_state->attribute_locations->len <= name_index))
{
int i = program_state->attribute_locations->len;
g_array_set_size (program_state->attribute_locations, name_index + 1);
for (; i < program_state->attribute_locations->len; i++)
g_array_index (program_state->attribute_locations, int, i)
= ATTRIBUTE_LOCATION_UNKNOWN;
}
locations = &g_array_index (program_state->attribute_locations, int, 0);
if (locations[name_index] == ATTRIBUTE_LOCATION_UNKNOWN)
{
CoglAttributeNameState *name_state =
g_array_index (ctx->attribute_name_index_map,
CoglAttributeNameState *, name_index);
_COGL_RETURN_VAL_IF_FAIL (name_state != NULL, 0);
GE_RET( locations[name_index],
ctx, glGetAttribLocation (program_state->program,
name_state->name) );
}
return locations[name_index];
}
static void
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
clear_attribute_cache (CoglPipelineProgramState *program_state)
{
if (program_state->attribute_locations)
{
g_array_free (program_state->attribute_locations, TRUE);
program_state->attribute_locations = NULL;
}
}
static void
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
clear_flushed_matrix_stacks (CoglPipelineProgramState *program_state)
{
Re-design the matrix stack using a graph of ops This re-designs the matrix stack so we now keep track of each separate operation such as rotating, scaling, translating and multiplying as immutable, ref-counted nodes in a graph. Being a "graph" here means that different transformations composed of a sequence of linked operation nodes may share nodes. The first node in a matrix-stack is always a LOAD_IDENTITY operation. As an example consider if an application where to draw three rectangles A, B and C something like this: cogl_framebuffer_scale (fb, 2, 2, 2); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_translate (fb, 10, 0, 0); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_rotate (fb, 45, 0, 0, 1); cogl_framebuffer_draw_rectangle (...); /* A */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_draw_rectangle (...); /* B */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_set_modelview_matrix (fb, &mv); cogl_framebuffer_draw_rectangle (...); /* C */ cogl_framebuffer_pop_matrix(fb); That would result in a graph of nodes like this: LOAD_IDENTITY | SCALE / \ SAVE LOAD | | TRANSLATE RECTANGLE(C) | \ SAVE RECTANGLE(B) | ROTATE | RECTANGLE(A) Each push adds a SAVE operation which serves as a marker to rewind too when a corresponding pop is issued and also each SAVE node may also store a cached matrix representing the composition of all its ancestor nodes. This means if we repeatedly need to resolve a real CoglMatrix for a given node then we don't need to repeat the composition. Some advantages of this design are: - A single pointer to any node in the graph can now represent a complete, immutable transformation that can be logged for example into a journal. Previously we were storing a full CoglMatrix in each journal entry which is 16 floats for the matrix itself as well as space for flags and another 16 floats for possibly storing a cache of the inverse. This means that we significantly reduce the size of the journal when drawing lots of primitives and we also avoid copying over 128 bytes per entry. - It becomes much cheaper to check for equality. In cases where some (unlikely) false negatives are allowed simply comparing the pointers of two matrix stack graph entries is enough. Previously we would use memcmp() to compare matrices. - It becomes easier to do comparisons of transformations. By looking for the common ancestry between nodes we can determine the operations that differentiate the transforms and use those to gain a high level understanding of the differences. For example we use this in the journal to be able to efficiently determine when two rectangle transforms only differ by some translation so that we can perform software clipping. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit f75aee93f6b293ca7a7babbd8fcc326ee6bf7aef)
2012-02-20 15:59:48 +00:00
_cogl_matrix_entry_cache_destroy (&program_state->projection_cache);
_cogl_matrix_entry_cache_init (&program_state->projection_cache);
_cogl_matrix_entry_cache_destroy (&program_state->modelview_cache);
_cogl_matrix_entry_cache_init (&program_state->modelview_cache);
}
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
static CoglPipelineProgramState *
program_state_new (int n_layers)
{
CoglPipelineProgramState *program_state;
program_state = g_slice_new (CoglPipelineProgramState);
program_state->ref_count = 1;
program_state->program = 0;
program_state->unit_state = g_new (UnitState, n_layers);
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
program_state->uniform_locations = NULL;
program_state->attribute_locations = NULL;
Re-design the matrix stack using a graph of ops This re-designs the matrix stack so we now keep track of each separate operation such as rotating, scaling, translating and multiplying as immutable, ref-counted nodes in a graph. Being a "graph" here means that different transformations composed of a sequence of linked operation nodes may share nodes. The first node in a matrix-stack is always a LOAD_IDENTITY operation. As an example consider if an application where to draw three rectangles A, B and C something like this: cogl_framebuffer_scale (fb, 2, 2, 2); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_translate (fb, 10, 0, 0); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_rotate (fb, 45, 0, 0, 1); cogl_framebuffer_draw_rectangle (...); /* A */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_draw_rectangle (...); /* B */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_set_modelview_matrix (fb, &mv); cogl_framebuffer_draw_rectangle (...); /* C */ cogl_framebuffer_pop_matrix(fb); That would result in a graph of nodes like this: LOAD_IDENTITY | SCALE / \ SAVE LOAD | | TRANSLATE RECTANGLE(C) | \ SAVE RECTANGLE(B) | ROTATE | RECTANGLE(A) Each push adds a SAVE operation which serves as a marker to rewind too when a corresponding pop is issued and also each SAVE node may also store a cached matrix representing the composition of all its ancestor nodes. This means if we repeatedly need to resolve a real CoglMatrix for a given node then we don't need to repeat the composition. Some advantages of this design are: - A single pointer to any node in the graph can now represent a complete, immutable transformation that can be logged for example into a journal. Previously we were storing a full CoglMatrix in each journal entry which is 16 floats for the matrix itself as well as space for flags and another 16 floats for possibly storing a cache of the inverse. This means that we significantly reduce the size of the journal when drawing lots of primitives and we also avoid copying over 128 bytes per entry. - It becomes much cheaper to check for equality. In cases where some (unlikely) false negatives are allowed simply comparing the pointers of two matrix stack graph entries is enough. Previously we would use memcmp() to compare matrices. - It becomes easier to do comparisons of transformations. By looking for the common ancestry between nodes we can determine the operations that differentiate the transforms and use those to gain a high level understanding of the differences. For example we use this in the journal to be able to efficiently determine when two rectangle transforms only differ by some translation so that we can perform software clipping. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit f75aee93f6b293ca7a7babbd8fcc326ee6bf7aef)
2012-02-20 15:59:48 +00:00
_cogl_matrix_entry_cache_init (&program_state->modelview_cache);
_cogl_matrix_entry_cache_init (&program_state->projection_cache);
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
return program_state;
}
static void
destroy_program_state (void *user_data,
void *instance)
{
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
CoglPipelineProgramState *program_state = user_data;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* If the program state was last used for this pipeline then clear
it so that if same address gets used again for a new pipeline
then we won't think it's the same pipeline and avoid updating the
uniforms */
if (program_state->last_used_for_pipeline == instance)
program_state->last_used_for_pipeline = NULL;
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
if (--program_state->ref_count == 0)
{
clear_attribute_cache (program_state);
_cogl_matrix_entry_cache_destroy (&program_state->projection_cache);
_cogl_matrix_entry_cache_destroy (&program_state->modelview_cache);
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
if (program_state->program)
GE( ctx, glDeleteProgram (program_state->program) );
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
g_free (program_state->unit_state);
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
if (program_state->uniform_locations)
g_array_free (program_state->uniform_locations, TRUE);
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
g_slice_free (CoglPipelineProgramState, program_state);
}
}
static void
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
set_program_state (CoglPipeline *pipeline,
CoglPipelineProgramState *program_state)
{
_cogl_object_set_user_data (COGL_OBJECT (pipeline),
&program_state_key,
program_state,
destroy_program_state);
}
static void
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
dirty_program_state (CoglPipeline *pipeline)
{
cogl_object_set_user_data (COGL_OBJECT (pipeline),
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
&program_state_key,
NULL,
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
NULL);
}
static void
link_program (GLint gl_program)
{
GLint link_status;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
GE( ctx, glLinkProgram (gl_program) );
GE( ctx, glGetProgramiv (gl_program, GL_LINK_STATUS, &link_status) );
if (!link_status)
{
GLint log_length;
GLsizei out_log_length;
char *log;
GE( ctx, glGetProgramiv (gl_program, GL_INFO_LOG_LENGTH, &log_length) );
log = g_malloc (log_length);
GE( ctx, glGetProgramInfoLog (gl_program, log_length,
&out_log_length, log) );
g_warning ("Failed to link GLSL program:\n%.*s\n",
log_length, log);
g_free (log);
}
}
typedef struct
{
int unit;
GLuint gl_program;
CoglBool update_all;
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
CoglPipelineProgramState *program_state;
} UpdateUniformsState;
static CoglBool
get_uniform_cb (CoglPipeline *pipeline,
int layer_index,
void *user_data)
{
UpdateUniformsState *state = user_data;
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
CoglPipelineProgramState *program_state = state->program_state;
UnitState *unit_state = &program_state->unit_state[state->unit];
GLint uniform_location;
_COGL_GET_CONTEXT (ctx, FALSE);
/* We can reuse the source buffer to create the uniform name because
the program has now been linked */
g_string_set_size (ctx->codegen_source_buffer, 0);
g_string_append_printf (ctx->codegen_source_buffer,
"cogl_sampler%i", layer_index);
GE_RET( uniform_location,
ctx, glGetUniformLocation (state->gl_program,
ctx->codegen_source_buffer->str) );
/* We can set the uniform immediately because the samplers are the
unit index not the texture object number so it will never
change. Unfortunately GL won't let us use a constant instead of a
uniform */
if (uniform_location != -1)
GE( ctx, glUniform1i (uniform_location, state->unit) );
g_string_set_size (ctx->codegen_source_buffer, 0);
g_string_append_printf (ctx->codegen_source_buffer,
"_cogl_layer_constant_%i", layer_index);
GE_RET( uniform_location,
ctx, glGetUniformLocation (state->gl_program,
ctx->codegen_source_buffer->str) );
unit_state->combine_constant_uniform = uniform_location;
g_string_set_size (ctx->codegen_source_buffer, 0);
g_string_append_printf (ctx->codegen_source_buffer,
"cogl_texture_matrix[%i]", layer_index);
GE_RET( uniform_location,
ctx, glGetUniformLocation (state->gl_program,
ctx->codegen_source_buffer->str) );
unit_state->texture_matrix_uniform = uniform_location;
state->unit++;
return TRUE;
}
static CoglBool
update_constants_cb (CoglPipeline *pipeline,
int layer_index,
void *user_data)
{
UpdateUniformsState *state = user_data;
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
CoglPipelineProgramState *program_state = state->program_state;
UnitState *unit_state = &program_state->unit_state[state->unit++];
_COGL_GET_CONTEXT (ctx, FALSE);
if (unit_state->combine_constant_uniform != -1 &&
(state->update_all || unit_state->dirty_combine_constant))
{
float constant[4];
_cogl_pipeline_get_layer_combine_constant (pipeline,
layer_index,
constant);
GE (ctx, glUniform4fv (unit_state->combine_constant_uniform,
1, constant));
unit_state->dirty_combine_constant = FALSE;
}
if (unit_state->texture_matrix_uniform != -1 &&
(state->update_all || unit_state->dirty_texture_matrix))
{
const CoglMatrix *matrix;
const float *array;
matrix = _cogl_pipeline_get_layer_matrix (pipeline, layer_index);
array = cogl_matrix_get_array (matrix);
GE (ctx, glUniformMatrix4fv (unit_state->texture_matrix_uniform,
1, FALSE, array));
unit_state->dirty_texture_matrix = FALSE;
}
return TRUE;
}
static void
update_builtin_uniforms (CoglContext *context,
CoglPipeline *pipeline,
GLuint gl_program,
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
CoglPipelineProgramState *program_state)
{
int i;
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
if (program_state->dirty_builtin_uniforms == 0)
return;
for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
if ((context->private_feature_flags &
builtin_uniforms[i].feature_replacement) == 0 &&
(program_state->dirty_builtin_uniforms & (1 << i)) &&
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
program_state->builtin_uniform_locations[i] != -1)
builtin_uniforms[i].update_func (pipeline,
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
program_state
->builtin_uniform_locations[i],
builtin_uniforms[i].getter_func);
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
program_state->dirty_builtin_uniforms = 0;
}
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
typedef struct
{
CoglPipelineProgramState *program_state;
unsigned long *uniform_differences;
int n_differences;
CoglContext *ctx;
const CoglBoxedValue *values;
int value_index;
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
} FlushUniformsClosure;
static CoglBool
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
flush_uniform_cb (int uniform_num, void *user_data)
{
FlushUniformsClosure *data = user_data;
if (COGL_FLAGS_GET (data->uniform_differences, uniform_num))
{
GArray *uniform_locations;
GLint uniform_location;
if (data->program_state->uniform_locations == NULL)
data->program_state->uniform_locations =
g_array_new (FALSE, FALSE, sizeof (GLint));
uniform_locations = data->program_state->uniform_locations;
if (uniform_locations->len <= uniform_num)
{
unsigned int old_len = uniform_locations->len;
g_array_set_size (uniform_locations, uniform_num + 1);
while (old_len <= uniform_num)
{
g_array_index (uniform_locations, GLint, old_len) =
UNIFORM_LOCATION_UNKNOWN;
old_len++;
}
}
uniform_location = g_array_index (uniform_locations, GLint, uniform_num);
if (uniform_location == UNIFORM_LOCATION_UNKNOWN)
{
const char *uniform_name =
g_ptr_array_index (data->ctx->uniform_names, uniform_num);
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
uniform_location =
data->ctx->glGetUniformLocation (data->program_state->program,
uniform_name);
g_array_index (uniform_locations, GLint, uniform_num) =
uniform_location;
}
if (uniform_location != -1)
_cogl_boxed_value_set_uniform (data->ctx,
uniform_location,
data->values + data->value_index);
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
data->n_differences--;
COGL_FLAGS_SET (data->uniform_differences, uniform_num, FALSE);
}
data->value_index++;
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
return data->n_differences > 0;
}
static void
_cogl_pipeline_progend_glsl_flush_uniforms (CoglPipeline *pipeline,
CoglPipelineProgramState *
program_state,
GLuint gl_program,
CoglBool program_changed)
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
{
CoglPipelineUniformsState *uniforms_state;
FlushUniformsClosure data;
int n_uniform_longs;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS)
uniforms_state = &pipeline->big_state->uniforms_state;
else
uniforms_state = NULL;
data.program_state = program_state;
data.ctx = ctx;
n_uniform_longs = COGL_FLAGS_N_LONGS_FOR_SIZE (ctx->n_uniform_names);
data.uniform_differences = g_newa (unsigned long, n_uniform_longs);
/* Try to find a common ancestor for the values that were already
flushed on the pipeline that this program state was last used for
so we can avoid flushing those */
if (program_changed || program_state->last_used_for_pipeline == NULL)
{
if (program_changed)
{
/* The program has changed so all of the uniform locations
are invalid */
if (program_state->uniform_locations)
g_array_set_size (program_state->uniform_locations, 0);
}
/* We need to flush everything so mark all of the uniforms as
dirty */
memset (data.uniform_differences, 0xff,
n_uniform_longs * sizeof (unsigned long));
data.n_differences = G_MAXINT;
}
else if (program_state->last_used_for_pipeline)
{
int i;
memset (data.uniform_differences, 0,
n_uniform_longs * sizeof (unsigned long));
_cogl_pipeline_compare_uniform_differences
(data.uniform_differences,
program_state->last_used_for_pipeline,
pipeline);
/* We need to be sure to flush any uniforms that have changed
since the last flush */
if (uniforms_state)
_cogl_bitmask_set_flags (&uniforms_state->changed_mask,
data.uniform_differences);
/* Count the number of differences. This is so we can stop early
when we've flushed all of them */
data.n_differences = 0;
for (i = 0; i < n_uniform_longs; i++)
data.n_differences +=
_cogl_util_popcountl (data.uniform_differences[i]);
}
while (pipeline && data.n_differences > 0)
{
if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS)
{
const CoglPipelineUniformsState *parent_uniforms_state =
&pipeline->big_state->uniforms_state;
data.values = parent_uniforms_state->override_values;
data.value_index = 0;
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
_cogl_bitmask_foreach (&parent_uniforms_state->override_mask,
flush_uniform_cb,
&data);
}
pipeline = _cogl_pipeline_get_parent (pipeline);
}
if (uniforms_state)
_cogl_bitmask_clear_all (&uniforms_state->changed_mask);
}
Clearly define 3 progends that own the frag+vertends This adds a new "fixed-arbfp" progend so we now have 3 distinct ways of setting up the state of a pipeline: » fixed; where the vertex and fragment processing are implemented using fixed function opengl apis. » fixed-arbfp; where vertex processing is implemented using fixed function opengl apis but fragment processing is implemented using the ARB Fragment Processing language. » glsl; there vertex and fragment processing are both implemented using glsl. This means we avoid unusual, combinations such as glsl for vertex processing and arbfp for fragment processing, and also avoid pairing fixed-function vertex processing with glsl fragment processing which we happen to know hits some awkward code paths in Mesa that lead to poor performance. As part of this change, the progend now implies specific vertend and fragend choices so instead of associating a vertend and fragend with a pipeline we now just associate a progend choice. When flushing a pipeline and choosing what progend to use, we now call a progend->start() method that is able to determine if the vertend and fragend together will be able to handle the given pipeline so the vertend and fragend ->start() methods no longer need to return a boolean status. Since we now don't need to support glsl used in conjunction with fixed function this will allow us to avoid ever using OpenGL builtin attribute names, though this patch doesn't change that yet. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit cec381f50c7a2f2186bd4a8c5f38fecd5f099075)
2012-09-25 20:08:10 +00:00
static CoglBool
_cogl_pipeline_progend_glsl_start (CoglPipeline *pipeline)
{
CoglHandle user_program;
_COGL_GET_CONTEXT (ctx, FALSE);
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
return FALSE;
user_program = cogl_pipeline_get_user_program (pipeline);
if (user_program &&
_cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
return FALSE;
return TRUE;
}
static void
_cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
unsigned long pipelines_difference)
{
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
CoglPipelineProgramState *program_state;
GLuint gl_program;
CoglBool program_changed = FALSE;
UpdateUniformsState state;
CoglProgram *user_program;
CoglPipeline *template_pipeline = NULL;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
program_state = get_program_state (pipeline);
user_program = cogl_pipeline_get_user_program (pipeline);
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
if (program_state == NULL)
{
CoglPipeline *authority;
/* Get the authority for anything affecting program state. This
should include both fragment codegen state and vertex codegen
state */
authority = _cogl_pipeline_find_equivalent_parent
(pipeline,
(COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN |
Dynamically load the GL or GLES library The GL or GLES library is now dynamically loaded by the CoglRenderer so that it can choose between GL, GLES1 and GLES2 at runtime. The library is loaded by the renderer because it needs to be done before calling eglInitialize. There is a new environment variable called COGL_DRIVER to choose between gl, gles1 or gles2. The #ifdefs for HAVE_COGL_GL, HAVE_COGL_GLES and HAVE_COGL_GLES2 have been changed so that they don't assume the ifdefs are mutually exclusive. They haven't been removed entirely so that it's possible to compile the GLES backends without the the enums from the GL headers. When using GLX the winsys additionally dynamically loads libGL because that also contains the GLX API. It can't be linked in directly because that would probably conflict with the GLES API if the EGL is selected. When compiling with EGL support the library links directly to libEGL because it doesn't contain any GL API so it shouldn't have any conflicts. When building for WGL or OSX Cogl still directly links against the GL API so there is a #define in config.h so that Cogl won't try to dlopen the library. Cogl-pango previously had a #ifdef to detect when the GL backend is used so that it can sneakily pass GL_QUADS to cogl_vertex_buffer_draw. This is now changed so that it queries the CoglContext for the backend. However to get this to work Cogl now needs to export the _cogl_context_get_default symbol and cogl-pango needs some extra -I flags to so that it can include cogl-context-private.h
2011-07-07 19:44:56 +00:00
_cogl_pipeline_get_state_for_fragment_codegen (ctx)) &
~COGL_PIPELINE_STATE_LAYERS,
Dynamically load the GL or GLES library The GL or GLES library is now dynamically loaded by the CoglRenderer so that it can choose between GL, GLES1 and GLES2 at runtime. The library is loaded by the renderer because it needs to be done before calling eglInitialize. There is a new environment variable called COGL_DRIVER to choose between gl, gles1 or gles2. The #ifdefs for HAVE_COGL_GL, HAVE_COGL_GLES and HAVE_COGL_GLES2 have been changed so that they don't assume the ifdefs are mutually exclusive. They haven't been removed entirely so that it's possible to compile the GLES backends without the the enums from the GL headers. When using GLX the winsys additionally dynamically loads libGL because that also contains the GLX API. It can't be linked in directly because that would probably conflict with the GLES API if the EGL is selected. When compiling with EGL support the library links directly to libEGL because it doesn't contain any GL API so it shouldn't have any conflicts. When building for WGL or OSX Cogl still directly links against the GL API so there is a #define in config.h so that Cogl won't try to dlopen the library. Cogl-pango previously had a #ifdef to detect when the GL backend is used so that it can sneakily pass GL_QUADS to cogl_vertex_buffer_draw. This is now changed so that it queries the CoglContext for the backend. However to get this to work Cogl now needs to export the _cogl_context_get_default symbol and cogl-pango needs some extra -I flags to so that it can include cogl-context-private.h
2011-07-07 19:44:56 +00:00
_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) |
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
program_state = get_program_state (authority);
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
if (program_state == NULL)
{
/* Check if there is already a similar cached pipeline whose
program state we can share */
if (G_LIKELY (!(COGL_DEBUG_ENABLED
(COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
{
template_pipeline =
_cogl_pipeline_cache_get_combined_template (ctx->pipeline_cache,
authority);
program_state = get_program_state (template_pipeline);
}
if (program_state)
program_state->ref_count++;
else
program_state
= program_state_new (cogl_pipeline_get_n_layers (authority));
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
set_program_state (authority, program_state);
if (template_pipeline)
{
program_state->ref_count++;
set_program_state (template_pipeline, program_state);
}
}
if (authority != pipeline)
{
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
program_state->ref_count++;
set_program_state (pipeline, program_state);
}
}
/* If the program has changed since the last link then we do
* need to relink */
if (program_state->program && user_program &&
user_program->age != program_state->user_program_age)
{
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
GE( ctx, glDeleteProgram (program_state->program) );
program_state->program = 0;
}
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
if (program_state->program == 0)
{
GLuint backend_shader;
GSList *l;
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
GE_RET( program_state->program, ctx, glCreateProgram () );
/* Attach all of the shader from the user program */
if (user_program)
{
for (l = user_program->attached_shaders; l; l = l->next)
{
CoglShader *shader = l->data;
_cogl_shader_compile_real (shader, pipeline);
g_assert (shader->language == COGL_SHADER_LANGUAGE_GLSL);
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
GE( ctx, glAttachShader (program_state->program,
shader->gl_handle) );
}
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
program_state->user_program_age = user_program->age;
}
/* Attach any shaders from the GLSL backends */
Clearly define 3 progends that own the frag+vertends This adds a new "fixed-arbfp" progend so we now have 3 distinct ways of setting up the state of a pipeline: » fixed; where the vertex and fragment processing are implemented using fixed function opengl apis. » fixed-arbfp; where vertex processing is implemented using fixed function opengl apis but fragment processing is implemented using the ARB Fragment Processing language. » glsl; there vertex and fragment processing are both implemented using glsl. This means we avoid unusual, combinations such as glsl for vertex processing and arbfp for fragment processing, and also avoid pairing fixed-function vertex processing with glsl fragment processing which we happen to know hits some awkward code paths in Mesa that lead to poor performance. As part of this change, the progend now implies specific vertend and fragend choices so instead of associating a vertend and fragend with a pipeline we now just associate a progend choice. When flushing a pipeline and choosing what progend to use, we now call a progend->start() method that is able to determine if the vertend and fragend together will be able to handle the given pipeline so the vertend and fragend ->start() methods no longer need to return a boolean status. Since we now don't need to support glsl used in conjunction with fixed function this will allow us to avoid ever using OpenGL builtin attribute names, though this patch doesn't change that yet. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit cec381f50c7a2f2186bd4a8c5f38fecd5f099075)
2012-09-25 20:08:10 +00:00
if ((backend_shader = _cogl_pipeline_fragend_glsl_get_shader (pipeline)))
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
GE( ctx, glAttachShader (program_state->program, backend_shader) );
Clearly define 3 progends that own the frag+vertends This adds a new "fixed-arbfp" progend so we now have 3 distinct ways of setting up the state of a pipeline: » fixed; where the vertex and fragment processing are implemented using fixed function opengl apis. » fixed-arbfp; where vertex processing is implemented using fixed function opengl apis but fragment processing is implemented using the ARB Fragment Processing language. » glsl; there vertex and fragment processing are both implemented using glsl. This means we avoid unusual, combinations such as glsl for vertex processing and arbfp for fragment processing, and also avoid pairing fixed-function vertex processing with glsl fragment processing which we happen to know hits some awkward code paths in Mesa that lead to poor performance. As part of this change, the progend now implies specific vertend and fragend choices so instead of associating a vertend and fragend with a pipeline we now just associate a progend choice. When flushing a pipeline and choosing what progend to use, we now call a progend->start() method that is able to determine if the vertend and fragend together will be able to handle the given pipeline so the vertend and fragend ->start() methods no longer need to return a boolean status. Since we now don't need to support glsl used in conjunction with fixed function this will allow us to avoid ever using OpenGL builtin attribute names, though this patch doesn't change that yet. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit cec381f50c7a2f2186bd4a8c5f38fecd5f099075)
2012-09-25 20:08:10 +00:00
if ((backend_shader = _cogl_pipeline_vertend_glsl_get_shader (pipeline)))
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
GE( ctx, glAttachShader (program_state->program, backend_shader) );
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
link_program (program_state->program);
program_changed = TRUE;
}
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
gl_program = program_state->program;
Clearly define 3 progends that own the frag+vertends This adds a new "fixed-arbfp" progend so we now have 3 distinct ways of setting up the state of a pipeline: » fixed; where the vertex and fragment processing are implemented using fixed function opengl apis. » fixed-arbfp; where vertex processing is implemented using fixed function opengl apis but fragment processing is implemented using the ARB Fragment Processing language. » glsl; there vertex and fragment processing are both implemented using glsl. This means we avoid unusual, combinations such as glsl for vertex processing and arbfp for fragment processing, and also avoid pairing fixed-function vertex processing with glsl fragment processing which we happen to know hits some awkward code paths in Mesa that lead to poor performance. As part of this change, the progend now implies specific vertend and fragend choices so instead of associating a vertend and fragend with a pipeline we now just associate a progend choice. When flushing a pipeline and choosing what progend to use, we now call a progend->start() method that is able to determine if the vertend and fragend together will be able to handle the given pipeline so the vertend and fragend ->start() methods no longer need to return a boolean status. Since we now don't need to support glsl used in conjunction with fixed function this will allow us to avoid ever using OpenGL builtin attribute names, though this patch doesn't change that yet. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit cec381f50c7a2f2186bd4a8c5f38fecd5f099075)
2012-09-25 20:08:10 +00:00
_cogl_use_fragment_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
_cogl_use_vertex_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
state.unit = 0;
state.gl_program = gl_program;
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
state.program_state = program_state;
if (program_changed)
{
cogl_pipeline_foreach_layer (pipeline,
get_uniform_cb,
&state);
clear_attribute_cache (program_state);
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
GE_RET (program_state->flip_uniform,
ctx, glGetUniformLocation (gl_program, "_cogl_flip_vector"));
program_state->flushed_flip_state = -1;
}
state.unit = 0;
state.update_all = (program_changed ||
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
program_state->last_used_for_pipeline != pipeline);
cogl_pipeline_foreach_layer (pipeline,
update_constants_cb,
&state);
if (program_changed)
{
int i;
clear_flushed_matrix_stacks (program_state);
for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
if ((ctx->private_feature_flags &
builtin_uniforms[i].feature_replacement) == 0)
GE_RET( program_state->builtin_uniform_locations[i], ctx,
glGetUniformLocation (gl_program,
builtin_uniforms[i].uniform_name) );
GE_RET( program_state->modelview_uniform, ctx,
glGetUniformLocation (gl_program,
"cogl_modelview_matrix") );
GE_RET( program_state->projection_uniform, ctx,
glGetUniformLocation (gl_program,
"cogl_projection_matrix") );
GE_RET( program_state->mvp_uniform, ctx,
glGetUniformLocation (gl_program,
"cogl_modelview_projection_matrix") );
Dynamically load the GL or GLES library The GL or GLES library is now dynamically loaded by the CoglRenderer so that it can choose between GL, GLES1 and GLES2 at runtime. The library is loaded by the renderer because it needs to be done before calling eglInitialize. There is a new environment variable called COGL_DRIVER to choose between gl, gles1 or gles2. The #ifdefs for HAVE_COGL_GL, HAVE_COGL_GLES and HAVE_COGL_GLES2 have been changed so that they don't assume the ifdefs are mutually exclusive. They haven't been removed entirely so that it's possible to compile the GLES backends without the the enums from the GL headers. When using GLX the winsys additionally dynamically loads libGL because that also contains the GLX API. It can't be linked in directly because that would probably conflict with the GLES API if the EGL is selected. When compiling with EGL support the library links directly to libEGL because it doesn't contain any GL API so it shouldn't have any conflicts. When building for WGL or OSX Cogl still directly links against the GL API so there is a #define in config.h so that Cogl won't try to dlopen the library. Cogl-pango previously had a #ifdef to detect when the GL backend is used so that it can sneakily pass GL_QUADS to cogl_vertex_buffer_draw. This is now changed so that it queries the CoglContext for the backend. However to get this to work Cogl now needs to export the _cogl_context_get_default symbol and cogl-pango needs some extra -I flags to so that it can include cogl-context-private.h
2011-07-07 19:44:56 +00:00
}
if (program_changed ||
program_state->last_used_for_pipeline != pipeline)
program_state->dirty_builtin_uniforms = ~(unsigned long) 0;
update_builtin_uniforms (ctx, pipeline, gl_program, program_state);
cogl-pipeline: Add support for setting uniform values This adds the following new public experimental functions to set uniform values on a CoglPipeline: void cogl_pipeline_set_uniform_1f (CoglPipeline *pipeline, int uniform_location, float value); void cogl_pipeline_set_uniform_1i (CoglPipeline *pipeline, int uniform_location, int value); void cogl_pipeline_set_uniform_float (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const float *value); void cogl_pipeline_set_uniform_int (CoglPipeline *pipeline, int uniform_location, int n_components, int count, const int *value); void cogl_pipeline_set_uniform_matrix (CoglPipeline *pipeline, int uniform_location, int dimensions, int count, gboolean transpose, const float *value); These are similar to the old functions used to set uniforms on a CoglProgram. To get a value to pass in as the uniform_location there is also: int cogl_pipeline_get_uniform_location (CoglPipeline *pipeline, const char *uniform_name); Conceptually the uniform locations are tied to the pipeline so that whenever setting a value for a new pipeline the application is expected to call this function. However in practice the uniform locations are global to the CoglContext. The names are stored in a linked list where the position in the list is the uniform location. The global indices are used so that each pipeline can store a mask of which uniforms it overrides. That way it is quicker to detect which uniforms are different from the last pipeline that used the same CoglProgramState so it can avoid flushing uniforms that haven't changed. Currently the values are not actually compared which means that it will only avoid flushing a uniform if there is a common ancestor that sets the value (or if the same pipeline is being flushed again - in which case the pipeline and its common ancestor are the same thing). The uniform values are stored in the big state of the pipeline as a sparse linked list. A bitmask stores which values have been overridden and only overridden values are stored in the linked list. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-03 17:20:43 +00:00
_cogl_pipeline_progend_glsl_flush_uniforms (pipeline,
program_state,
gl_program,
program_changed);
if (user_program)
_cogl_program_flush_uniforms (user_program,
gl_program,
program_changed);
/* We need to track the last pipeline that the program was used with
* so know if we need to update all of the uniforms */
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
program_state->last_used_for_pipeline = pipeline;
}
static void
_cogl_pipeline_progend_glsl_pre_change_notify (CoglPipeline *pipeline,
CoglPipelineState change,
const CoglColor *new_color)
{
Dynamically load the GL or GLES library The GL or GLES library is now dynamically loaded by the CoglRenderer so that it can choose between GL, GLES1 and GLES2 at runtime. The library is loaded by the renderer because it needs to be done before calling eglInitialize. There is a new environment variable called COGL_DRIVER to choose between gl, gles1 or gles2. The #ifdefs for HAVE_COGL_GL, HAVE_COGL_GLES and HAVE_COGL_GLES2 have been changed so that they don't assume the ifdefs are mutually exclusive. They haven't been removed entirely so that it's possible to compile the GLES backends without the the enums from the GL headers. When using GLX the winsys additionally dynamically loads libGL because that also contains the GLX API. It can't be linked in directly because that would probably conflict with the GLES API if the EGL is selected. When compiling with EGL support the library links directly to libEGL because it doesn't contain any GL API so it shouldn't have any conflicts. When building for WGL or OSX Cogl still directly links against the GL API so there is a #define in config.h so that Cogl won't try to dlopen the library. Cogl-pango previously had a #ifdef to detect when the GL backend is used so that it can sneakily pass GL_QUADS to cogl_vertex_buffer_draw. This is now changed so that it queries the CoglContext for the backend. However to get this to work Cogl now needs to export the _cogl_context_get_default symbol and cogl-pango needs some extra -I flags to so that it can include cogl-context-private.h
2011-07-07 19:44:56 +00:00
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if ((change & (_cogl_pipeline_get_state_for_fragment_codegen (ctx) |
COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN)))
{
dirty_program_state (pipeline);
}
else
{
int i;
for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
if ((ctx->private_feature_flags &
builtin_uniforms[i].feature_replacement) == 0 &&
(change & builtin_uniforms[i].change))
{
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
CoglPipelineProgramState *program_state
= get_program_state (pipeline);
if (program_state)
program_state->dirty_builtin_uniforms |= 1 << i;
return;
}
}
}
/* NB: layers are considered immutable once they have any dependants
* so although multiple pipelines can end up depending on a single
* static layer, we can guarantee that if a layer is being *changed*
* then it can only have one pipeline depending on it.
*
* XXX: Don't forget this is *pre* change, we can't read the new value
* yet!
*/
static void
_cogl_pipeline_progend_glsl_layer_pre_change_notify (
CoglPipeline *owner,
CoglPipelineLayer *layer,
CoglPipelineLayerState change)
{
Dynamically load the GL or GLES library The GL or GLES library is now dynamically loaded by the CoglRenderer so that it can choose between GL, GLES1 and GLES2 at runtime. The library is loaded by the renderer because it needs to be done before calling eglInitialize. There is a new environment variable called COGL_DRIVER to choose between gl, gles1 or gles2. The #ifdefs for HAVE_COGL_GL, HAVE_COGL_GLES and HAVE_COGL_GLES2 have been changed so that they don't assume the ifdefs are mutually exclusive. They haven't been removed entirely so that it's possible to compile the GLES backends without the the enums from the GL headers. When using GLX the winsys additionally dynamically loads libGL because that also contains the GLX API. It can't be linked in directly because that would probably conflict with the GLES API if the EGL is selected. When compiling with EGL support the library links directly to libEGL because it doesn't contain any GL API so it shouldn't have any conflicts. When building for WGL or OSX Cogl still directly links against the GL API so there is a #define in config.h so that Cogl won't try to dlopen the library. Cogl-pango previously had a #ifdef to detect when the GL backend is used so that it can sneakily pass GL_QUADS to cogl_vertex_buffer_draw. This is now changed so that it queries the CoglContext for the backend. However to get this to work Cogl now needs to export the _cogl_context_get_default symbol and cogl-pango needs some extra -I flags to so that it can include cogl-context-private.h
2011-07-07 19:44:56 +00:00
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if ((change & (_cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) |
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN)))
{
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
dirty_program_state (owner);
}
else if (change & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT)
{
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
CoglPipelineProgramState *program_state = get_program_state (owner);
if (program_state)
{
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
program_state->unit_state[unit_index].dirty_combine_constant = TRUE;
}
}
else if (change & COGL_PIPELINE_LAYER_STATE_USER_MATRIX)
{
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
CoglPipelineProgramState *program_state = get_program_state (owner);
if (program_state)
{
int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
program_state->unit_state[unit_index].dirty_texture_matrix = TRUE;
}
}
}
static void
Re-design the matrix stack using a graph of ops This re-designs the matrix stack so we now keep track of each separate operation such as rotating, scaling, translating and multiplying as immutable, ref-counted nodes in a graph. Being a "graph" here means that different transformations composed of a sequence of linked operation nodes may share nodes. The first node in a matrix-stack is always a LOAD_IDENTITY operation. As an example consider if an application where to draw three rectangles A, B and C something like this: cogl_framebuffer_scale (fb, 2, 2, 2); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_translate (fb, 10, 0, 0); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_rotate (fb, 45, 0, 0, 1); cogl_framebuffer_draw_rectangle (...); /* A */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_draw_rectangle (...); /* B */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_set_modelview_matrix (fb, &mv); cogl_framebuffer_draw_rectangle (...); /* C */ cogl_framebuffer_pop_matrix(fb); That would result in a graph of nodes like this: LOAD_IDENTITY | SCALE / \ SAVE LOAD | | TRANSLATE RECTANGLE(C) | \ SAVE RECTANGLE(B) | ROTATE | RECTANGLE(A) Each push adds a SAVE operation which serves as a marker to rewind too when a corresponding pop is issued and also each SAVE node may also store a cached matrix representing the composition of all its ancestor nodes. This means if we repeatedly need to resolve a real CoglMatrix for a given node then we don't need to repeat the composition. Some advantages of this design are: - A single pointer to any node in the graph can now represent a complete, immutable transformation that can be logged for example into a journal. Previously we were storing a full CoglMatrix in each journal entry which is 16 floats for the matrix itself as well as space for flags and another 16 floats for possibly storing a cache of the inverse. This means that we significantly reduce the size of the journal when drawing lots of primitives and we also avoid copying over 128 bytes per entry. - It becomes much cheaper to check for equality. In cases where some (unlikely) false negatives are allowed simply comparing the pointers of two matrix stack graph entries is enough. Previously we would use memcmp() to compare matrices. - It becomes easier to do comparisons of transformations. By looking for the common ancestry between nodes we can determine the operations that differentiate the transforms and use those to gain a high level understanding of the differences. For example we use this in the journal to be able to efficiently determine when two rectangle transforms only differ by some translation so that we can perform software clipping. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit f75aee93f6b293ca7a7babbd8fcc326ee6bf7aef)
2012-02-20 15:59:48 +00:00
_cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline,
CoglFramebuffer *framebuffer)
{
CoglBool needs_flip;
Re-design the matrix stack using a graph of ops This re-designs the matrix stack so we now keep track of each separate operation such as rotating, scaling, translating and multiplying as immutable, ref-counted nodes in a graph. Being a "graph" here means that different transformations composed of a sequence of linked operation nodes may share nodes. The first node in a matrix-stack is always a LOAD_IDENTITY operation. As an example consider if an application where to draw three rectangles A, B and C something like this: cogl_framebuffer_scale (fb, 2, 2, 2); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_translate (fb, 10, 0, 0); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_rotate (fb, 45, 0, 0, 1); cogl_framebuffer_draw_rectangle (...); /* A */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_draw_rectangle (...); /* B */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_set_modelview_matrix (fb, &mv); cogl_framebuffer_draw_rectangle (...); /* C */ cogl_framebuffer_pop_matrix(fb); That would result in a graph of nodes like this: LOAD_IDENTITY | SCALE / \ SAVE LOAD | | TRANSLATE RECTANGLE(C) | \ SAVE RECTANGLE(B) | ROTATE | RECTANGLE(A) Each push adds a SAVE operation which serves as a marker to rewind too when a corresponding pop is issued and also each SAVE node may also store a cached matrix representing the composition of all its ancestor nodes. This means if we repeatedly need to resolve a real CoglMatrix for a given node then we don't need to repeat the composition. Some advantages of this design are: - A single pointer to any node in the graph can now represent a complete, immutable transformation that can be logged for example into a journal. Previously we were storing a full CoglMatrix in each journal entry which is 16 floats for the matrix itself as well as space for flags and another 16 floats for possibly storing a cache of the inverse. This means that we significantly reduce the size of the journal when drawing lots of primitives and we also avoid copying over 128 bytes per entry. - It becomes much cheaper to check for equality. In cases where some (unlikely) false negatives are allowed simply comparing the pointers of two matrix stack graph entries is enough. Previously we would use memcmp() to compare matrices. - It becomes easier to do comparisons of transformations. By looking for the common ancestry between nodes we can determine the operations that differentiate the transforms and use those to gain a high level understanding of the differences. For example we use this in the journal to be able to efficiently determine when two rectangle transforms only differ by some translation so that we can perform software clipping. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit f75aee93f6b293ca7a7babbd8fcc326ee6bf7aef)
2012-02-20 15:59:48 +00:00
CoglMatrixEntry *projection_entry;
CoglMatrixEntry *modelview_entry;
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
CoglPipelineProgramState *program_state;
CoglBool modelview_changed;
CoglBool projection_changed;
CoglBool need_modelview;
CoglBool need_projection;
CoglMatrix modelview, projection;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
pipeline: Unify how the backends store private data Previously the fragends had a separate private data pointer which was used by the GLSL and ARBfp fragends to store a tiny struct containing a single pointer to the ref-counted shader state. The space for the private data pointer is reserved in all of the pipelines for all of the potential backends. The vertends and progends however did this differently by directly storing the pointer to the ref counted data using cogl_object_set_user_data. This patch unifies the different methods so that they all use cogl_object_set_user_data and the fragends don't bother with the separate tiny allocation for the private data. The private data pointer array has been removed from CoglPipeline and the corresponding fragend virtual to free the private data has also been removed because this can instead be done with the destroy notify from the object user data. The variable names used have been unified so that all of the vertends and fragends name their data struct CoglPipelineShaderState and use a variable called shader_state to refer to it. The progend uses CoglPipelineProgramState and a variable called program_state. This should also fix two potential bugs. the ARBfp fragend was apprently leaking a reference to the private state when it creates the private data because it was adding a reference before stroring the pointer to the newly allocated data but the ref count is already set to 1 on creation. The other potential bug is that the free function for CoglPipeline was only calling the free_priv virtual for the currently used fragend of the pipeline. The design of the fragends is meant to allow a pipeline to have multiple fragend priv datas because a child pipeline could be attaching its fragend data to the ancestor and its allowed to pick a different fragend.
2011-06-30 12:39:48 +00:00
program_state = get_program_state (pipeline);
Re-design the matrix stack using a graph of ops This re-designs the matrix stack so we now keep track of each separate operation such as rotating, scaling, translating and multiplying as immutable, ref-counted nodes in a graph. Being a "graph" here means that different transformations composed of a sequence of linked operation nodes may share nodes. The first node in a matrix-stack is always a LOAD_IDENTITY operation. As an example consider if an application where to draw three rectangles A, B and C something like this: cogl_framebuffer_scale (fb, 2, 2, 2); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_translate (fb, 10, 0, 0); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_rotate (fb, 45, 0, 0, 1); cogl_framebuffer_draw_rectangle (...); /* A */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_draw_rectangle (...); /* B */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_set_modelview_matrix (fb, &mv); cogl_framebuffer_draw_rectangle (...); /* C */ cogl_framebuffer_pop_matrix(fb); That would result in a graph of nodes like this: LOAD_IDENTITY | SCALE / \ SAVE LOAD | | TRANSLATE RECTANGLE(C) | \ SAVE RECTANGLE(B) | ROTATE | RECTANGLE(A) Each push adds a SAVE operation which serves as a marker to rewind too when a corresponding pop is issued and also each SAVE node may also store a cached matrix representing the composition of all its ancestor nodes. This means if we repeatedly need to resolve a real CoglMatrix for a given node then we don't need to repeat the composition. Some advantages of this design are: - A single pointer to any node in the graph can now represent a complete, immutable transformation that can be logged for example into a journal. Previously we were storing a full CoglMatrix in each journal entry which is 16 floats for the matrix itself as well as space for flags and another 16 floats for possibly storing a cache of the inverse. This means that we significantly reduce the size of the journal when drawing lots of primitives and we also avoid copying over 128 bytes per entry. - It becomes much cheaper to check for equality. In cases where some (unlikely) false negatives are allowed simply comparing the pointers of two matrix stack graph entries is enough. Previously we would use memcmp() to compare matrices. - It becomes easier to do comparisons of transformations. By looking for the common ancestry between nodes we can determine the operations that differentiate the transforms and use those to gain a high level understanding of the differences. For example we use this in the journal to be able to efficiently determine when two rectangle transforms only differ by some translation so that we can perform software clipping. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit f75aee93f6b293ca7a7babbd8fcc326ee6bf7aef)
2012-02-20 15:59:48 +00:00
projection_entry = ctx->current_projection_entry;
modelview_entry = ctx->current_modelview_entry;
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
/* An initial pipeline is flushed while creating the context. At
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
this point there are no matrices selected so we can't do
anything */
Re-design the matrix stack using a graph of ops This re-designs the matrix stack so we now keep track of each separate operation such as rotating, scaling, translating and multiplying as immutable, ref-counted nodes in a graph. Being a "graph" here means that different transformations composed of a sequence of linked operation nodes may share nodes. The first node in a matrix-stack is always a LOAD_IDENTITY operation. As an example consider if an application where to draw three rectangles A, B and C something like this: cogl_framebuffer_scale (fb, 2, 2, 2); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_translate (fb, 10, 0, 0); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_rotate (fb, 45, 0, 0, 1); cogl_framebuffer_draw_rectangle (...); /* A */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_draw_rectangle (...); /* B */ cogl_framebuffer_pop_matrix(fb); cogl_framebuffer_push_matrix(fb); cogl_framebuffer_set_modelview_matrix (fb, &mv); cogl_framebuffer_draw_rectangle (...); /* C */ cogl_framebuffer_pop_matrix(fb); That would result in a graph of nodes like this: LOAD_IDENTITY | SCALE / \ SAVE LOAD | | TRANSLATE RECTANGLE(C) | \ SAVE RECTANGLE(B) | ROTATE | RECTANGLE(A) Each push adds a SAVE operation which serves as a marker to rewind too when a corresponding pop is issued and also each SAVE node may also store a cached matrix representing the composition of all its ancestor nodes. This means if we repeatedly need to resolve a real CoglMatrix for a given node then we don't need to repeat the composition. Some advantages of this design are: - A single pointer to any node in the graph can now represent a complete, immutable transformation that can be logged for example into a journal. Previously we were storing a full CoglMatrix in each journal entry which is 16 floats for the matrix itself as well as space for flags and another 16 floats for possibly storing a cache of the inverse. This means that we significantly reduce the size of the journal when drawing lots of primitives and we also avoid copying over 128 bytes per entry. - It becomes much cheaper to check for equality. In cases where some (unlikely) false negatives are allowed simply comparing the pointers of two matrix stack graph entries is enough. Previously we would use memcmp() to compare matrices. - It becomes easier to do comparisons of transformations. By looking for the common ancestry between nodes we can determine the operations that differentiate the transforms and use those to gain a high level understanding of the differences. For example we use this in the journal to be able to efficiently determine when two rectangle transforms only differ by some translation so that we can perform software clipping. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit f75aee93f6b293ca7a7babbd8fcc326ee6bf7aef)
2012-02-20 15:59:48 +00:00
if (modelview_entry == NULL || projection_entry == NULL)
return;
needs_flip = cogl_is_offscreen (ctx->current_draw_buffer);
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
projection_changed =
_cogl_matrix_entry_cache_maybe_update (&program_state->projection_cache,
projection_entry,
(needs_flip &&
program_state->flip_uniform ==
-1));
modelview_changed =
_cogl_matrix_entry_cache_maybe_update (&program_state->modelview_cache,
modelview_entry,
/* never flip modelview */
FALSE);
if (modelview_changed || projection_changed)
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
{
if (program_state->mvp_uniform != -1)
need_modelview = need_projection = TRUE;
else
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
{
need_projection = (program_state->projection_uniform != -1 &&
projection_changed);
need_modelview = (program_state->modelview_uniform != -1 &&
modelview_changed);
}
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
if (need_modelview)
_cogl_matrix_entry_get (modelview_entry, &modelview);
if (need_projection)
{
if (needs_flip && program_state->flip_uniform == -1)
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
{
CoglMatrix tmp_matrix;
_cogl_matrix_entry_get (projection_entry, &tmp_matrix);
cogl_matrix_multiply (&projection,
&ctx->y_flip_matrix,
&tmp_matrix);
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
}
else
_cogl_matrix_entry_get (projection_entry, &projection);
}
if (projection_changed && program_state->projection_uniform != -1)
GE (ctx, glUniformMatrix4fv (program_state->projection_uniform,
1, /* count */
FALSE, /* transpose */
cogl_matrix_get_array (&projection)));
if (modelview_changed && program_state->modelview_uniform != -1)
GE (ctx, glUniformMatrix4fv (program_state->modelview_uniform,
1, /* count */
FALSE, /* transpose */
cogl_matrix_get_array (&modelview)));
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
if (program_state->mvp_uniform != -1)
{
/* The journal usually uses an identity matrix for the
modelview so we can optimise this common case by
avoiding the matrix multiplication */
if (_cogl_matrix_entry_has_identity_flag (modelview_entry))
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
{
GE (ctx,
glUniformMatrix4fv (program_state->mvp_uniform,
1, /* count */
FALSE, /* transpose */
cogl_matrix_get_array (&projection)));
}
else
{
CoglMatrix combined;
cogl_matrix_multiply (&combined,
&projection,
&modelview);
GE (ctx,
glUniformMatrix4fv (program_state->mvp_uniform,
1, /* count */
FALSE, /* transpose */
cogl_matrix_get_array (&combined)));
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
}
}
}
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
if (program_state->flip_uniform != -1
&& program_state->flushed_flip_state != needs_flip)
{
Flush matrices in the progend and flip with a vector Previously flushing the matrices was performed as part of the framebuffer state. When on GLES2 this matrix flushing is actually diverted so that it only keeps a reference to the intended matrix stack. This is necessary because on GLES2 there are no builtin uniforms so it can't actually flush the matrices until the program for the pipeline is generated. When the matrices are flushed it would store the age of modifications on the matrix stack so that it could detect when the matrix hasn't changed and avoid flushing it. This patch changes it so that the pipeline is responsible for flushing the matrices even when we are using the GL builtins. The same mechanism for detecting unmodified matrix stacks is used in all cases. There is a new CoglMatrixStackCache type which is used to store a reference to the intended matrix stack along with its last flushed age. There are now two of these attached to the CoglContext to track the flushed state for the global matrix builtins and also two for each glsl progend program state to track the flushed state for a program. The framebuffer matrix flush now just updates the intended matrix stacks without actually trying to flush. When a vertex snippet is attached to the pipeline, the GLSL vertend will now avoid using the projection matrix to flip the rendering. This is necessary because any vertex snippet may cause the projection matrix not to be used. Instead the flip is done as a forced final step by multiplying cogl_position_out by a vec4 uniform. This uniform is updated as part of the progend pre_paint depending on whether the framebuffer is offscreen or not. Reviewed-by: Robert Bragg <robert@linux.intel.com>
2011-11-29 14:21:07 +00:00
static const float do_flip[4] = { 1.0f, -1.0f, 1.0f, 1.0f };
static const float dont_flip[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
GE( ctx, glUniform4fv (program_state->flip_uniform,
1, /* count */
needs_flip ? do_flip : dont_flip) );
program_state->flushed_flip_state = needs_flip;
}
}
static void
update_float_uniform (CoglPipeline *pipeline,
int uniform_location,
void *getter_func)
{
float (* float_getter_func) (CoglPipeline *) = getter_func;
float value;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
value = float_getter_func (pipeline);
GE( ctx, glUniform1f (uniform_location, value) );
}
const CoglPipelineProgend _cogl_pipeline_glsl_progend =
{
Clearly define 3 progends that own the frag+vertends This adds a new "fixed-arbfp" progend so we now have 3 distinct ways of setting up the state of a pipeline: » fixed; where the vertex and fragment processing are implemented using fixed function opengl apis. » fixed-arbfp; where vertex processing is implemented using fixed function opengl apis but fragment processing is implemented using the ARB Fragment Processing language. » glsl; there vertex and fragment processing are both implemented using glsl. This means we avoid unusual, combinations such as glsl for vertex processing and arbfp for fragment processing, and also avoid pairing fixed-function vertex processing with glsl fragment processing which we happen to know hits some awkward code paths in Mesa that lead to poor performance. As part of this change, the progend now implies specific vertend and fragend choices so instead of associating a vertend and fragend with a pipeline we now just associate a progend choice. When flushing a pipeline and choosing what progend to use, we now call a progend->start() method that is able to determine if the vertend and fragend together will be able to handle the given pipeline so the vertend and fragend ->start() methods no longer need to return a boolean status. Since we now don't need to support glsl used in conjunction with fixed function this will allow us to avoid ever using OpenGL builtin attribute names, though this patch doesn't change that yet. Reviewed-by: Neil Roberts <neil@linux.intel.com> (cherry picked from commit cec381f50c7a2f2186bd4a8c5f38fecd5f099075)
2012-09-25 20:08:10 +00:00
COGL_PIPELINE_VERTEND_GLSL,
COGL_PIPELINE_FRAGEND_GLSL,
_cogl_pipeline_progend_glsl_start,
_cogl_pipeline_progend_glsl_end,
_cogl_pipeline_progend_glsl_pre_change_notify,
_cogl_pipeline_progend_glsl_layer_pre_change_notify,
_cogl_pipeline_progend_glsl_pre_paint
};
#endif /* COGL_PIPELINE_PROGEND_GLSL */