diff --git a/clutter/cogl/cogl/cogl-pipeline-fragend-arbfp.c b/clutter/cogl/cogl/cogl-pipeline-fragend-arbfp.c index b5c8b5264..61767a84b 100644 --- a/clutter/cogl/cogl/cogl-pipeline-fragend-arbfp.c +++ b/clutter/cogl/cogl/cogl-pipeline-fragend-arbfp.c @@ -72,30 +72,6 @@ #define GL_TEXTURE_3D 0x806F #endif -/* When we add new pipeline or layer state groups we need to be careful to - * update backends to understand if that new state is associated with vertex, - * fragment or other processing. The idea here is to attribute which groups - * affect fragment processing and more specifically which contribute to arbfp - * code generation. - */ - -#define COGL_PIPELINE_FRAGEND_ARBFP_FRAGMENT_STATE_MASK \ - (COGL_PIPELINE_STATE_LAYERS | \ - COGL_PIPELINE_STATE_USER_SHADER) - -#define COGL_PIPELINE_FRAGEND_ARBFP_FRAGMENT_PROGRAM_STATE_MASK \ - COGL_PIPELINE_FRAGEND_ARBFP_FRAGMENT_STATE_MASK - -#define COGL_PIPELINE_FRAGEND_ARBFP_LAYER_FRAGMENT_STATE_MASK \ - COGL_PIPELINE_LAYER_STATE_ALL - -#define COGL_PIPELINE_FRAGEND_ARBFP_LAYER_FRAGMENT_PROGRAM_STATE_MASK \ - (COGL_PIPELINE_FRAGEND_ARBFP_LAYER_FRAGMENT_STATE_MASK & \ - ~(COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT | \ - COGL_PIPELINE_LAYER_STATE_FILTERS | \ - COGL_PIPELINE_LAYER_STATE_WRAP_MODES | \ - COGL_PIPELINE_LAYER_STATE_USER_MATRIX)) - typedef struct _UnitState { int constant_id; /* The program.local[] index */ @@ -254,7 +230,12 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline, * arbfp-authority to maximize the chance that other pipelines can * share it. */ - authority = _cogl_pipeline_find_codegen_authority (pipeline, user_program); + authority = _cogl_pipeline_find_equivalent_parent + (pipeline, + COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN & + ~COGL_PIPELINE_STATE_LAYERS, + COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN, + COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET); authority_priv = get_arbfp_priv (authority); if (authority_priv && authority_priv->arbfp_program_state) @@ -346,9 +327,9 @@ unsigned int _cogl_pipeline_fragend_arbfp_hash (const void *data) { unsigned long fragment_state = - COGL_PIPELINE_FRAGEND_ARBFP_FRAGMENT_PROGRAM_STATE_MASK; + COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN; unsigned long layer_fragment_state = - COGL_PIPELINE_FRAGEND_ARBFP_LAYER_FRAGMENT_PROGRAM_STATE_MASK; + COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN; CoglPipelineEvalFlags flags = COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA; return _cogl_pipeline_hash ((CoglPipeline *)data, @@ -360,9 +341,9 @@ gboolean _cogl_pipeline_fragend_arbfp_equal (const void *a, const void *b) { unsigned long fragment_state = - COGL_PIPELINE_FRAGEND_ARBFP_FRAGMENT_PROGRAM_STATE_MASK; + COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN; unsigned long layer_fragment_state = - COGL_PIPELINE_FRAGEND_ARBFP_LAYER_FRAGMENT_PROGRAM_STATE_MASK; + COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN; CoglPipelineEvalFlags flags = COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA; return _cogl_pipeline_equal ((CoglPipeline *)a, (CoglPipeline *)b, @@ -1049,10 +1030,8 @@ _cogl_pipeline_fragend_arbfp_pipeline_pre_change_notify ( CoglPipelineState change, const CoglColor *new_color) { - if (!(change & COGL_PIPELINE_FRAGEND_ARBFP_FRAGMENT_PROGRAM_STATE_MASK)) - return; - - dirty_arbfp_program_state (pipeline); + if ((change & COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN)) + dirty_arbfp_program_state (pipeline); } /* NB: layers are considered immutable once they have any dependants @@ -1073,7 +1052,7 @@ _cogl_pipeline_fragend_arbfp_layer_pre_change_notify ( if (!priv) return; - if (change & COGL_PIPELINE_FRAGEND_ARBFP_LAYER_FRAGMENT_PROGRAM_STATE_MASK) + if ((change & COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN)) { dirty_arbfp_program_state (owner); return; diff --git a/clutter/cogl/cogl/cogl-pipeline-fragend-glsl.c b/clutter/cogl/cogl/cogl-pipeline-fragend-glsl.c index 69a7df364..dd50ddfce 100644 --- a/clutter/cogl/cogl/cogl-pipeline-fragend-glsl.c +++ b/clutter/cogl/cogl/cogl-pipeline-fragend-glsl.c @@ -319,8 +319,13 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline, * glsl-authority to maximize the chance that other pipelines can * share it. */ - authority = - _cogl_pipeline_find_codegen_authority (pipeline, user_program); + authority = _cogl_pipeline_find_equivalent_parent + (pipeline, + COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN & + ~COGL_PIPELINE_STATE_LAYERS, + COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN, + COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET); + authority_priv = get_glsl_priv (authority); if (!authority_priv) { diff --git a/clutter/cogl/cogl/cogl-pipeline-private.h b/clutter/cogl/cogl/cogl-pipeline-private.h index 9f05e4dde..13354c50a 100644 --- a/clutter/cogl/cogl/cogl-pipeline-private.h +++ b/clutter/cogl/cogl/cogl-pipeline-private.h @@ -127,6 +127,18 @@ typedef enum COGL_PIPELINE_LAYER_STATE_USER_MATRIX | COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS, + COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN = + COGL_PIPELINE_LAYER_STATE_COMBINE | + /* FIXME: Only texture target changes should really affect the + codegen, but this is difficult to detect */ + COGL_PIPELINE_LAYER_STATE_TEXTURE | + /* On GLES2 we need to use a different varying for the texture + lookups when point sprite coords are enabled */ +#ifdef HAVE_COGL_GLES2 + COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS | +#endif + COGL_PIPELINE_LAYER_STATE_UNIT + } CoglPipelineLayerState; typedef struct @@ -363,7 +375,16 @@ typedef enum _CoglPipelineState COGL_PIPELINE_STATE_USER_SHADER | COGL_PIPELINE_STATE_DEPTH | COGL_PIPELINE_STATE_FOG | - COGL_PIPELINE_STATE_POINT_SIZE + COGL_PIPELINE_STATE_POINT_SIZE, + + COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN = + COGL_PIPELINE_STATE_LAYERS | +#ifdef HAVE_COGL_GLES2 + /* Under GLES2 the alpha func becomes part of the fragment program + so we can't share programs there */ + COGL_PIPELINE_STATE_ALPHA_FUNC | +#endif + COGL_PIPELINE_STATE_USER_SHADER } CoglPipelineState; @@ -458,6 +479,12 @@ typedef struct CoglPipelineLayer *layer; } CoglPipelineLayerCacheEntry; +/* Flags used for _cogl_pipeline_find_equivalent_parent */ +typedef enum +{ + COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET = 1L<<0 +} CoglPipelineFindEquivalentFlags; + /* * CoglPipelineDestroyCallback * @pipeline: The #CoglPipeline that has been destroyed @@ -958,6 +985,12 @@ CoglPipeline * _cogl_pipeline_get_authority (CoglPipeline *pipeline, unsigned long difference); +CoglPipeline * +_cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline, + CoglPipelineState pipeline_state, + CoglPipelineLayerState layer_state, + CoglPipelineFindEquivalentFlags flags); + CoglHandle _cogl_pipeline_get_layer_texture (CoglPipeline *pipeline, int layer_index); @@ -1046,10 +1079,6 @@ gboolean _cogl_pipeline_need_texture_combine_separate (CoglPipelineLayer *combine_authority); -CoglPipeline * -_cogl_pipeline_find_codegen_authority (CoglPipeline *pipeline, - CoglHandle user_program); - void _cogl_pipeline_init_state_hash_functions (void); diff --git a/clutter/cogl/cogl/cogl-pipeline.c b/clutter/cogl/cogl/cogl-pipeline.c index 2d98796ec..d829e8278 100644 --- a/clutter/cogl/cogl/cogl-pipeline.c +++ b/clutter/cogl/cogl/cogl-pipeline.c @@ -6290,51 +6290,6 @@ add_layer_to_array_cb (CoglPipelineLayer *layer, return TRUE; } -static gboolean -layers_codegen_would_differ (CoglPipelineLayer **pipeline0_layers, - CoglPipelineLayer **pipeline1_layers, - int n_layers) -{ - int i; - /* The layer state that affects codegen... */ - unsigned long codegen_modifiers = - COGL_PIPELINE_LAYER_STATE_COMBINE | - COGL_PIPELINE_LAYER_STATE_UNIT; - - for (i = 0; i < n_layers; i++) - { - CoglPipelineLayer *layer0 = pipeline0_layers[i]; - CoglPipelineLayer *layer1 = pipeline1_layers[i]; - unsigned long layer_differences; - - if (layer0 == layer1) - continue; - - layer_differences = - _cogl_pipeline_layer_compare_differences (layer0, layer1); - - if (layer_differences & codegen_modifiers) - return TRUE; - - /* When it comes to texture differences the only thing that - * affects the codegen is the target enum... */ - if ((layer_differences & COGL_PIPELINE_LAYER_STATE_TEXTURE)) - { - CoglHandle tex0 = _cogl_pipeline_layer_get_texture (layer0); - CoglHandle tex1 = _cogl_pipeline_layer_get_texture (layer1); - GLenum gl_target0; - GLenum gl_target1; - - cogl_texture_get_gl_texture (tex0, NULL, &gl_target0); - cogl_texture_get_gl_texture (tex1, NULL, &gl_target1); - if (gl_target0 != gl_target1) - return TRUE; - } - } - - return FALSE; -} - /* Determines if we need to handle the RGB and A texture combining * separately or is the same function used for both channel masks and * with the same arguments... @@ -6409,45 +6364,73 @@ _cogl_pipeline_need_texture_combine_separate return FALSE; } -/* This tries to find the oldest ancestor whos state would generate - * the same shader program as the current pipeline. This is a simple - * mechanism for reducing the number of programs we have to generate. - */ +static gboolean +layers_differ_for_find_equivalent (CoglPipelineLayerState layer_state, + CoglPipelineFindEquivalentFlags flags, + CoglPipelineLayer *layer0, + CoglPipelineLayer *layer1) +{ + unsigned long layer_differences; + + if (layer0 == layer1) + return FALSE; + + layer_differences = + _cogl_pipeline_layer_compare_differences (layer0, layer1); + + if (layer_differences & layer_state) + return TRUE; + + /* When generating a shader we need to detect when the texture + target changes but we don't care if the texture object + changes so we have a flag to handle this special case */ + if ((flags & COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET) && + (layer_differences & COGL_PIPELINE_LAYER_STATE_TEXTURE)) + { + CoglHandle tex0 = _cogl_pipeline_layer_get_texture (layer0); + CoglHandle tex1 = _cogl_pipeline_layer_get_texture (layer1); + GLenum gl_target0; + GLenum gl_target1; + + cogl_texture_get_gl_texture (tex0, NULL, &gl_target0); + cogl_texture_get_gl_texture (tex1, NULL, &gl_target1); + if (gl_target0 != gl_target1) + return TRUE; + } + + return FALSE; +} + +/* This tries to find the oldest ancestor whose pipeline and layer + state matches the given flags. This is mostly used to detect code + gen authorities so that we can reduce the numer of programs + generated */ CoglPipeline * -_cogl_pipeline_find_codegen_authority (CoglPipeline *pipeline, - CoglHandle user_program) +_cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline, + CoglPipelineState pipeline_state, + CoglPipelineLayerState layer_state, + CoglPipelineFindEquivalentFlags flags) { CoglPipeline *authority0; CoglPipeline *authority1; int n_layers; CoglPipelineLayer **authority0_layers; CoglPipelineLayer **authority1_layers; - /* Under GLES2 the alpha func becomes part of the fragment program - so we can't share programs there */ - const int codegen_state = (COGL_PIPELINE_STATE_LAYERS -#ifdef HAVE_COGL_GLES2 - | COGL_PIPELINE_STATE_ALPHA_FUNC -#endif - ); - - /* XXX: we'll need to update this when we add fog support to the - * codegen */ - - if (user_program != COGL_INVALID_HANDLE) - return pipeline; /* Find the first pipeline that modifies state that affects the - * codegen... */ + * state or any layer state... */ authority0 = _cogl_pipeline_get_authority (pipeline, - codegen_state); + pipeline_state | + COGL_PIPELINE_STATE_LAYERS); - /* Find the next ancestor after that, that also modifies state - * affecting codegen... */ + /* Find the next ancestor after that, that also modifies the + * state... */ if (_cogl_pipeline_get_parent (authority0)) { authority1 = _cogl_pipeline_get_authority (_cogl_pipeline_get_parent (authority0), - codegen_state); + pipeline_state | + COGL_PIPELINE_STATE_LAYERS); } else return authority0; @@ -6457,15 +6440,16 @@ _cogl_pipeline_find_codegen_authority (CoglPipeline *pipeline, for (;;) { AddLayersToArrayState state; + int i; if (n_layers != cogl_pipeline_get_n_layers (authority1)) return authority0; /* If the programs differ by anything that isn't part of the layer state then we can't continue */ - if ((codegen_state & ~COGL_PIPELINE_STATE_LAYERS) && + if (pipeline_state && (_cogl_pipeline_compare_differences (authority0, authority1) & - (codegen_state & ~COGL_PIPELINE_STATE_LAYERS))) + pipeline_state)) return authority0; authority0_layers = @@ -6484,9 +6468,11 @@ _cogl_pipeline_find_codegen_authority (CoglPipeline *pipeline, add_layer_to_array_cb, &state); - if (layers_codegen_would_differ (authority0_layers, authority1_layers, - n_layers)) - return authority0; + for (i = 0; i < n_layers; i++) + if (layers_differ_for_find_equivalent (layer_state, flags, + authority0_layers[i], + authority1_layers[i])) + return authority0; /* Find the next ancestor after that, that also modifies state * affecting codegen... */ @@ -6497,7 +6483,8 @@ _cogl_pipeline_find_codegen_authority (CoglPipeline *pipeline, authority0 = authority1; authority1 = _cogl_pipeline_get_authority (_cogl_pipeline_get_parent (authority1), - codegen_state); + pipeline_state | + COGL_PIPELINE_STATE_LAYERS); if (authority1 == authority0) break; }