cogl-pipeline: Make find codegen authority more general

The pipeline function _cogl_pipeline_find_codegen_authority has been
renamed to _cogl_pipeline_find_equivalent_parent and it now takes a
set of flags for the pipeline and layer state that affects the
authority. This is needed so that we can reuse the same code in the
vertend and progends.
This commit is contained in:
Neil Roberts 2010-12-01 17:06:18 +00:00
parent 6b7139b008
commit 7562a17685
4 changed files with 116 additions and 116 deletions

View File

@ -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;

View File

@ -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)
{

View File

@ -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);

View File

@ -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;
}