pipeline: generalize _cogl_pipeline_equal

_cogl_pipeline_equal now accepts a mask of pipeline differences and layer
differences to constrain what state will be compared. In addition a set
of flags are passed that can tweak the comparison semantics for some
state groups. For example when comparing layer textures we sometimes
only need to compare the texture target and can ignore the data itself.

In updating the code this patch also changes it so all required pipeline
authorities are resolved in one step up-front instead of resolving the
authority for each state group in turn and repeatedly having to traverse
the pipeline's ancestry. This adds two new functions
_cogl_pipeline_resolve_authorities and
_cogl_pipeline_layer_resolve_authorities to handle resolving a set of
authorities.
This commit is contained in:
Robert Bragg 2010-12-03 11:36:49 +00:00
parent 8e899985c6
commit 2c9cd76baa
3 changed files with 309 additions and 136 deletions

View File

@ -406,13 +406,12 @@ compare_entry_pipelines (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
{ {
/* batch rectangles using compatible pipelines */ /* batch rectangles using compatible pipelines */
/* XXX: _cogl_pipeline_equal may give false negatives since it avoids
* deep comparisons as an optimization. It aims to compare enough so
* that we that we are able to batch the 90% common cases, but may not
* look at less common differences. */
if (_cogl_pipeline_equal (entry0->pipeline, if (_cogl_pipeline_equal (entry0->pipeline,
entry1->pipeline, entry1->pipeline,
TRUE)) (COGL_PIPELINE_STATE_ALL &
~COGL_PIPELINE_STATE_COLOR),
COGL_PIPELINE_LAYER_STATE_ALL,
0))
return TRUE; return TRUE;
else else
return FALSE; return FALSE;

View File

@ -71,30 +71,55 @@ typedef struct _CoglPipelineLayer CoglPipelineLayer;
#define COGL_PIPELINE_BACKEND_DEFAULT 0 #define COGL_PIPELINE_BACKEND_DEFAULT 0
#define COGL_PIPELINE_BACKEND_UNDEFINED 3 #define COGL_PIPELINE_BACKEND_UNDEFINED 3
/* XXX: should I rename these as
* COGL_PIPELINE_LAYER_STATE_INDEX_XYZ... ?
*/
typedef enum typedef enum
{ {
COGL_PIPELINE_LAYER_STATE_UNIT = 1L<<0, /* sparse state */
COGL_PIPELINE_LAYER_STATE_TEXTURE = 1L<<1, COGL_PIPELINE_LAYER_STATE_UNIT_INDEX,
COGL_PIPELINE_LAYER_STATE_FILTERS = 1L<<2, COGL_PIPELINE_LAYER_STATE_TEXTURE_INDEX,
COGL_PIPELINE_LAYER_STATE_WRAP_MODES = 1L<<3, COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX,
COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
COGL_PIPELINE_LAYER_STATE_COMBINE = 1L<<4, /* note: layers don't currently have any non-sparse state */
COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT = 1L<<5,
COGL_PIPELINE_LAYER_STATE_USER_MATRIX = 1L<<6,
COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS = 1L<<7, COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT,
COGL_PIPELINE_LAYER_STATE_COUNT = COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT
} CoglPipelineLayerStateIndex;
typedef enum
{
COGL_PIPELINE_LAYER_STATE_UNIT =
1L<<COGL_PIPELINE_LAYER_STATE_UNIT_INDEX,
COGL_PIPELINE_LAYER_STATE_TEXTURE =
1L<<COGL_PIPELINE_LAYER_STATE_TEXTURE_INDEX,
COGL_PIPELINE_LAYER_STATE_FILTERS =
1L<<COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
COGL_PIPELINE_LAYER_STATE_WRAP_MODES =
1L<<COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX,
COGL_PIPELINE_LAYER_STATE_COMBINE =
1L<<COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT =
1L<<COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
COGL_PIPELINE_LAYER_STATE_USER_MATRIX =
1L<<COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS =
1L<<COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
/* COGL_PIPELINE_LAYER_STATE_TEXTURE_INTERN = 1L<<8, */ /* COGL_PIPELINE_LAYER_STATE_TEXTURE_INTERN = 1L<<8, */
COGL_PIPELINE_LAYER_STATE_ALL =
(1L<<COGL_PIPELINE_LAYER_STATE_COUNT) - 1,
COGL_PIPELINE_LAYER_STATE_ALL_SPARSE = COGL_PIPELINE_LAYER_STATE_ALL_SPARSE =
COGL_PIPELINE_LAYER_STATE_UNIT | (1L<<COGL_PIPELINE_LAYER_STATE_COUNT) - 1,
COGL_PIPELINE_LAYER_STATE_TEXTURE |
COGL_PIPELINE_LAYER_STATE_FILTERS |
COGL_PIPELINE_LAYER_STATE_WRAP_MODES |
COGL_PIPELINE_LAYER_STATE_COMBINE |
COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT |
COGL_PIPELINE_LAYER_STATE_USER_MATRIX |
COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS,
COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE = COGL_PIPELINE_LAYER_STATE_NEEDS_BIG_STATE =
COGL_PIPELINE_LAYER_STATE_COMBINE | COGL_PIPELINE_LAYER_STATE_COMBINE |
@ -259,37 +284,68 @@ struct _CoglPipelineLayer
}; };
/* XXX: should I rename these as
* COGL_PIPELINE_STATE_INDEX_XYZ... ?
*/
typedef enum
{
/* sparse state */
COGL_PIPELINE_STATE_COLOR_INDEX,
COGL_PIPELINE_STATE_BLEND_ENABLE_INDEX,
COGL_PIPELINE_STATE_LAYERS_INDEX,
COGL_PIPELINE_STATE_LIGHTING_INDEX,
COGL_PIPELINE_STATE_ALPHA_FUNC_INDEX,
COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE_INDEX,
COGL_PIPELINE_STATE_BLEND_INDEX,
COGL_PIPELINE_STATE_USER_SHADER_INDEX,
COGL_PIPELINE_STATE_DEPTH_INDEX,
COGL_PIPELINE_STATE_FOG_INDEX,
COGL_PIPELINE_STATE_POINT_SIZE_INDEX,
/* non-sparse */
COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX,
COGL_PIPELINE_STATE_COUNT,
COGL_PIPELINE_STATE_SPARSE_COUNT = COGL_PIPELINE_STATE_COUNT - 1,
} CoglPipelineStateIndex;
/* Used in pipeline->differences masks and for notifying pipeline /* Used in pipeline->differences masks and for notifying pipeline
* state changes... */ * state changes... */
typedef enum _CoglPipelineState typedef enum _CoglPipelineState
{ {
COGL_PIPELINE_STATE_COLOR = 1L<<0, COGL_PIPELINE_STATE_COLOR =
COGL_PIPELINE_STATE_BLEND_ENABLE = 1L<<1, 1L<<COGL_PIPELINE_STATE_COLOR_INDEX,
COGL_PIPELINE_STATE_LAYERS = 1L<<2, COGL_PIPELINE_STATE_BLEND_ENABLE =
1L<<COGL_PIPELINE_STATE_BLEND_ENABLE_INDEX,
COGL_PIPELINE_STATE_LAYERS =
1L<<COGL_PIPELINE_STATE_LAYERS_INDEX,
COGL_PIPELINE_STATE_LIGHTING = 1L<<3, COGL_PIPELINE_STATE_LIGHTING =
COGL_PIPELINE_STATE_ALPHA_FUNC = 1L<<4, 1L<<COGL_PIPELINE_STATE_LIGHTING_INDEX,
COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE = 1L<<5, COGL_PIPELINE_STATE_ALPHA_FUNC =
COGL_PIPELINE_STATE_BLEND = 1L<<6, 1L<<COGL_PIPELINE_STATE_ALPHA_FUNC_INDEX,
COGL_PIPELINE_STATE_USER_SHADER = 1L<<7, COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE =
COGL_PIPELINE_STATE_DEPTH = 1L<<8, 1L<<COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE_INDEX,
COGL_PIPELINE_STATE_FOG = 1L<<9, COGL_PIPELINE_STATE_BLEND =
COGL_PIPELINE_STATE_POINT_SIZE = 1L<<10, 1L<<COGL_PIPELINE_STATE_BLEND_INDEX,
COGL_PIPELINE_STATE_USER_SHADER =
1L<<COGL_PIPELINE_STATE_USER_SHADER_INDEX,
COGL_PIPELINE_STATE_DEPTH =
1L<<COGL_PIPELINE_STATE_DEPTH_INDEX,
COGL_PIPELINE_STATE_FOG =
1L<<COGL_PIPELINE_STATE_FOG_INDEX,
COGL_PIPELINE_STATE_POINT_SIZE =
1L<<COGL_PIPELINE_STATE_POINT_SIZE_INDEX,
COGL_PIPELINE_STATE_REAL_BLEND_ENABLE = 1L<<11, COGL_PIPELINE_STATE_REAL_BLEND_ENABLE =
1L<<COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX,
COGL_PIPELINE_STATE_ALL =
((1L<<COGL_PIPELINE_STATE_COUNT) - 1),
COGL_PIPELINE_STATE_ALL_SPARSE = COGL_PIPELINE_STATE_ALL_SPARSE =
COGL_PIPELINE_STATE_COLOR | (COGL_PIPELINE_STATE_ALL
COGL_PIPELINE_STATE_BLEND_ENABLE | & ~COGL_PIPELINE_STATE_REAL_BLEND_ENABLE),
COGL_PIPELINE_STATE_LAYERS |
COGL_PIPELINE_STATE_LIGHTING |
COGL_PIPELINE_STATE_ALPHA_FUNC |
COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE |
COGL_PIPELINE_STATE_BLEND |
COGL_PIPELINE_STATE_USER_SHADER |
COGL_PIPELINE_STATE_DEPTH |
COGL_PIPELINE_STATE_FOG |
COGL_PIPELINE_STATE_POINT_SIZE,
COGL_PIPELINE_STATE_AFFECTS_BLENDING = COGL_PIPELINE_STATE_AFFECTS_BLENDING =
COGL_PIPELINE_STATE_COLOR | COGL_PIPELINE_STATE_COLOR |
@ -834,10 +890,23 @@ unsigned long
_cogl_pipeline_compare_differences (CoglPipeline *pipeline0, _cogl_pipeline_compare_differences (CoglPipeline *pipeline0,
CoglPipeline *pipeline1); CoglPipeline *pipeline1);
/* Sometimes when evaluating pipelines, either during comparisons or
* if calculating a hash value we need to tweak the evaluation
* semantics */
typedef enum _CoglPipelineEvalFlags
{
/* When evaluating a pipeline-layer with associated textures then
* evaluate the texture target, but don't consider the texture data
* itself. */
COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA = 1L<<0
} CoglPipelineEvalFlags;
gboolean gboolean
_cogl_pipeline_equal (CoglPipeline *pipeline0, _cogl_pipeline_equal (CoglPipeline *pipeline0,
CoglPipeline *pipeline1, CoglPipeline *pipeline1,
gboolean skip_gl_color); unsigned long differences,
unsigned long layer_differences,
CoglPipelineEvalFlags flags);
CoglPipeline * CoglPipeline *
_cogl_pipeline_journal_ref (CoglPipeline *pipeline); _cogl_pipeline_journal_ref (CoglPipeline *pipeline);

View File

@ -2708,7 +2708,8 @@ _cogl_pipeline_apply_overrides (CoglPipeline *pipeline,
static gboolean static gboolean
_cogl_pipeline_layer_texture_equal (CoglPipelineLayer *authority0, _cogl_pipeline_layer_texture_equal (CoglPipelineLayer *authority0,
CoglPipelineLayer *authority1) CoglPipelineLayer *authority1,
CoglPipelineEvalFlags flags)
{ {
GLuint gl_handle0, gl_handle1; GLuint gl_handle0, gl_handle1;
GLenum gl_target0, gl_target1; GLenum gl_target0, gl_target1;
@ -2716,8 +2717,10 @@ _cogl_pipeline_layer_texture_equal (CoglPipelineLayer *authority0,
cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, &gl_target0); cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, &gl_target0);
cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, &gl_target1); cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, &gl_target1);
return (gl_handle0 == gl_handle1 && if (flags & COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA)
gl_target0 == gl_target1); return (gl_target0 == gl_target1);
else
return (gl_handle0 == gl_handle1 && gl_target0 == gl_target1);
} }
/* Determine the mask of differences between two layers. /* Determine the mask of differences between two layers.
@ -2915,24 +2918,58 @@ typedef gboolean
CoglPipelineLayer *authority1); CoglPipelineLayer *authority1);
static gboolean static gboolean
layer_state_equal (CoglPipelineLayerState state, layer_state_equal (CoglPipelineLayerStateIndex state_index,
CoglPipelineLayer *layer0, CoglPipelineLayer **authorities0,
CoglPipelineLayer *layer1, CoglPipelineLayer **authorities1,
CoglPipelineLayerStateComparitor comparitor) CoglPipelineLayerStateComparitor comparitor)
{ {
CoglPipelineLayer *authority0 = return comparitor (authorities0[state_index], authorities1[state_index]);
_cogl_pipeline_layer_get_authority (layer0, state); }
CoglPipelineLayer *authority1 =
_cogl_pipeline_layer_get_authority (layer1, state);
return comparitor (authority0, authority1); static void
_cogl_pipeline_layer_resolve_authorities (CoglPipelineLayer *layer,
unsigned long differences,
CoglPipelineLayer **authorities)
{
unsigned long remaining = differences;
CoglPipelineLayer *authority = layer;
do
{
unsigned long found = authority->differences & remaining;
int i;
if (found == 0)
continue;
for (i = 0; True; i++)
{
unsigned long state = (1L<<i);
if (state & found)
authorities[i] = authority;
else if (state > found)
break;
}
remaining &= ~found;
if (remaining == 0)
return;
}
while ((authority = _cogl_pipeline_layer_get_parent (authority)));
g_assert (remaining == 0);
} }
static gboolean static gboolean
_cogl_pipeline_layer_equal (CoglPipelineLayer *layer0, _cogl_pipeline_layer_equal (CoglPipelineLayer *layer0,
CoglPipelineLayer *layer1) CoglPipelineLayer *layer1,
unsigned long differences_mask,
CoglPipelineEvalFlags flags)
{ {
unsigned long layers_difference; unsigned long layers_difference;
CoglPipelineLayer *authorities0[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT];
CoglPipelineLayer *authorities1[COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT];
if (layer0 == layer1) if (layer0 == layer1)
return TRUE; return TRUE;
@ -2940,45 +2977,59 @@ _cogl_pipeline_layer_equal (CoglPipelineLayer *layer0,
layers_difference = layers_difference =
_cogl_pipeline_layer_compare_differences (layer0, layer1); _cogl_pipeline_layer_compare_differences (layer0, layer1);
if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE && /* Only compare the sparse state groups requested by the caller... */
!layer_state_equal (COGL_PIPELINE_LAYER_STATE_TEXTURE, layers_difference &= differences_mask;
layer0, layer1,
_cogl_pipeline_layer_texture_equal)) _cogl_pipeline_layer_resolve_authorities (layer0,
return FALSE; layers_difference,
authorities0);
_cogl_pipeline_layer_resolve_authorities (layer1,
layers_difference,
authorities1);
if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE)
{
CoglPipelineLayerStateIndex state_index =
COGL_PIPELINE_LAYER_STATE_TEXTURE_INDEX;
if (!_cogl_pipeline_layer_texture_equal (authorities0[state_index],
authorities1[state_index],
flags))
return FALSE;
}
if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE && if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE &&
!layer_state_equal (COGL_PIPELINE_LAYER_STATE_COMBINE, !layer_state_equal (COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
layer0, layer1, authorities0, authorities1,
_cogl_pipeline_layer_combine_state_equal)) _cogl_pipeline_layer_combine_state_equal))
return FALSE; return FALSE;
if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT && if (layers_difference & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT &&
!layer_state_equal (COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT, !layer_state_equal (COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT_INDEX,
layer0, layer1, authorities0, authorities1,
_cogl_pipeline_layer_combine_constant_equal)) _cogl_pipeline_layer_combine_constant_equal))
return FALSE; return FALSE;
if (layers_difference & COGL_PIPELINE_LAYER_STATE_FILTERS && if (layers_difference & COGL_PIPELINE_LAYER_STATE_FILTERS &&
!layer_state_equal (COGL_PIPELINE_LAYER_STATE_FILTERS, !layer_state_equal (COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
layer0, layer1, authorities0, authorities1,
_cogl_pipeline_layer_filters_equal)) _cogl_pipeline_layer_filters_equal))
return FALSE; return FALSE;
if (layers_difference & COGL_PIPELINE_LAYER_STATE_WRAP_MODES && if (layers_difference & COGL_PIPELINE_LAYER_STATE_WRAP_MODES &&
!layer_state_equal (COGL_PIPELINE_LAYER_STATE_WRAP_MODES, !layer_state_equal (COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX,
layer0, layer1, authorities0, authorities1,
_cogl_pipeline_layer_wrap_modes_equal)) _cogl_pipeline_layer_wrap_modes_equal))
return FALSE; return FALSE;
if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX && if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX &&
!layer_state_equal (COGL_PIPELINE_LAYER_STATE_USER_MATRIX, !layer_state_equal (COGL_PIPELINE_LAYER_STATE_USER_MATRIX_INDEX,
layer0, layer1, authorities0, authorities1,
_cogl_pipeline_layer_user_matrix_equal)) _cogl_pipeline_layer_user_matrix_equal))
return FALSE; return FALSE;
if (layers_difference & COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS && if (layers_difference & COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS &&
!layer_state_equal (COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS, !layer_state_equal (COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS_INDEX,
layer0, layer1, authorities0, authorities1,
_cogl_pipeline_layer_point_sprite_coords_equal)) _cogl_pipeline_layer_point_sprite_coords_equal))
return FALSE; return FALSE;
@ -3065,9 +3116,15 @@ _cogl_pipeline_blend_state_equal (CoglPipeline *authority0,
blend_state1->blend_dst_factor_rgb) blend_state1->blend_dst_factor_rgb)
return FALSE; return FALSE;
#ifndef HAVE_COGL_GLES #ifndef HAVE_COGL_GLES
if (!cogl_color_equal (&blend_state0->blend_constant, if (blend_state0->blend_src_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR ||
&blend_state1->blend_constant)) blend_state0->blend_src_factor_rgb == GL_CONSTANT_COLOR ||
return FALSE; blend_state0->blend_dst_factor_rgb == GL_ONE_MINUS_CONSTANT_COLOR ||
blend_state0->blend_dst_factor_rgb == GL_CONSTANT_COLOR)
{
if (!cogl_color_equal (&blend_state0->blend_constant,
&blend_state1->blend_constant))
return FALSE;
}
#endif #endif
return TRUE; return TRUE;
@ -3121,7 +3178,9 @@ _cogl_pipeline_user_shader_equal (CoglPipeline *authority0,
static gboolean static gboolean
_cogl_pipeline_layers_equal (CoglPipeline *authority0, _cogl_pipeline_layers_equal (CoglPipeline *authority0,
CoglPipeline *authority1) CoglPipeline *authority1,
unsigned long differences,
CoglPipelineEvalFlags flags)
{ {
int i; int i;
@ -3134,7 +3193,9 @@ _cogl_pipeline_layers_equal (CoglPipeline *authority0,
for (i = 0; i < authority0->n_layers; i++) for (i = 0; i < authority0->n_layers; i++)
{ {
if (!_cogl_pipeline_layer_equal (authority0->layers_cache[i], if (!_cogl_pipeline_layer_equal (authority0->layers_cache[i],
authority1->layers_cache[i])) authority1->layers_cache[i],
differences,
flags))
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
@ -3229,21 +3290,55 @@ _cogl_pipeline_compare_differences (CoglPipeline *pipeline0,
} }
static gboolean static gboolean
simple_property_equal (CoglPipeline *pipeline0, simple_property_equal (CoglPipeline **authorities0,
CoglPipeline *pipeline1, CoglPipeline **authorities1,
unsigned long pipelines_difference, unsigned long pipelines_difference,
CoglPipelineState state, CoglPipelineStateIndex state_index,
CoglPipelineStateComparitor comparitor) CoglPipelineStateComparitor comparitor)
{ {
if (pipelines_difference & state) if (pipelines_difference & (1L<<state_index))
{ {
if (!comparitor (_cogl_pipeline_get_authority (pipeline0, state), if (!comparitor (authorities0[state_index], authorities1[state_index]))
_cogl_pipeline_get_authority (pipeline1, state)))
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
} }
static void
_cogl_pipeline_resolve_authorities (CoglPipeline *pipeline,
unsigned long differences,
CoglPipeline **authorities)
{
unsigned long remaining = differences;
CoglPipeline *authority = pipeline;
do
{
unsigned long found = authority->differences & remaining;
int i;
if (found == 0)
continue;
for (i = 0; True; i++)
{
unsigned long state = (1L<<i);
if (state & found)
authorities[i] = authority;
else if (state > found)
break;
}
remaining &= ~found;
if (remaining == 0)
return;
}
while ((authority = _cogl_pipeline_get_parent (authority)));
g_assert (remaining == 0);
}
/* Comparison of two arbitrary pipelines is done by: /* Comparison of two arbitrary pipelines is done by:
* 1) walking up the parents of each pipeline until a common * 1) walking up the parents of each pipeline until a common
* ancestor is found, and at each step ORing together the * ancestor is found, and at each step ORing together the
@ -3252,30 +3347,29 @@ simple_property_equal (CoglPipeline *pipeline0,
* 2) using the final difference mask to determine which state * 2) using the final difference mask to determine which state
* groups to compare. * groups to compare.
* *
* This is used by the Cogl journal to compare pipelines so that it * This is used, for example, by the Cogl journal to compare pipelines so that
* can split up geometry that needs different OpenGL state. * it can split up geometry that needs different OpenGL state.
* *
* It is acceptable to have false negatives - although they will result * XXX: When comparing texture layers, _cogl_pipeline_equal will actually
* in redundant OpenGL calls that try and update the state. * compare the underlying GL texture handle that the Cogl texture uses so that
* * atlas textures and sub textures will be considered equal if they point to
* When comparing texture layers, _cogl_pipeline_equal will actually * the same texture. This is useful for comparing pipelines in the journal but
* compare the underlying GL texture handle that the Cogl texture uses * it means that _cogl_pipeline_equal doesn't strictly compare whether the
* so that atlas textures and sub textures will be considered equal if * pipelines are the same. If we needed those semantics we could perhaps add
* they point to the same texture. This is useful for comparing * another function or some flags to control the behaviour.
* pipelines in the journal but it means that _cogl_pipeline_equal
* doesn't strictly compare whether the pipelines are the same. If we
* needed those semantics we could perhaps add another function or
* some flags to control the behaviour.
*
* False positives aren't allowed.
*/ */
gboolean gboolean
_cogl_pipeline_equal (CoglPipeline *pipeline0, _cogl_pipeline_equal (CoglPipeline *pipeline0,
CoglPipeline *pipeline1, CoglPipeline *pipeline1,
gboolean skip_gl_color) unsigned long differences,
unsigned long layer_differences,
CoglPipelineEvalFlags flags)
{ {
unsigned long pipelines_difference; unsigned long pipelines_difference;
CoglPipeline *authorities0[COGL_PIPELINE_STATE_SPARSE_COUNT];
CoglPipeline *authorities1[COGL_PIPELINE_STATE_SPARSE_COUNT];
gboolean ret; gboolean ret;
COGL_STATIC_TIMER (pipeline_equal_timer, COGL_STATIC_TIMER (pipeline_equal_timer,
"Mainloop", /* parent */ "Mainloop", /* parent */
"_cogl_pipeline_equal", "_cogl_pipeline_equal",
@ -3294,7 +3388,8 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0,
/* First check non-sparse properties */ /* First check non-sparse properties */
if (pipeline0->real_blend_enable != pipeline1->real_blend_enable) if (differences & COGL_PIPELINE_STATE_REAL_BLEND_ENABLE &&
pipeline0->real_blend_enable != pipeline1->real_blend_enable)
goto done; goto done;
/* Then check sparse properties */ /* Then check sparse properties */
@ -3302,34 +3397,43 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0,
pipelines_difference = pipelines_difference =
_cogl_pipeline_compare_differences (pipeline0, pipeline1); _cogl_pipeline_compare_differences (pipeline0, pipeline1);
if (pipelines_difference & COGL_PIPELINE_STATE_COLOR && /* Only compare the sparse state groups requested by the caller... */
!skip_gl_color) pipelines_difference &= differences;
_cogl_pipeline_resolve_authorities (pipeline0,
pipelines_difference,
authorities0);
_cogl_pipeline_resolve_authorities (pipeline1,
pipelines_difference,
authorities1);
/* FIXME: we should resolve all the required authorities up front since
* that should reduce some repeat ancestor traversals. */
if (pipelines_difference & COGL_PIPELINE_STATE_COLOR)
{ {
CoglPipelineState state = COGL_PIPELINE_STATE_COLOR; CoglPipeline *authority0 = authorities0[COGL_PIPELINE_STATE_COLOR_INDEX];
CoglPipeline *authority0 = CoglPipeline *authority1 = authorities1[COGL_PIPELINE_STATE_COLOR_INDEX];
_cogl_pipeline_get_authority (pipeline0, state);
CoglPipeline *authority1 =
_cogl_pipeline_get_authority (pipeline1, state);
if (!cogl_color_equal (&authority0->color, &authority1->color)) if (!cogl_color_equal (&authority0->color, &authority1->color))
goto done; goto done;
} }
if (!simple_property_equal (pipeline0, pipeline1, if (!simple_property_equal (authorities0, authorities1,
pipelines_difference, pipelines_difference,
COGL_PIPELINE_STATE_LIGHTING, COGL_PIPELINE_STATE_LIGHTING_INDEX,
_cogl_pipeline_lighting_state_equal)) _cogl_pipeline_lighting_state_equal))
goto done; goto done;
if (!simple_property_equal (pipeline0, pipeline1, if (!simple_property_equal (authorities0, authorities1,
pipelines_difference, pipelines_difference,
COGL_PIPELINE_STATE_ALPHA_FUNC, COGL_PIPELINE_STATE_ALPHA_FUNC_INDEX,
_cogl_pipeline_alpha_func_state_equal)) _cogl_pipeline_alpha_func_state_equal))
goto done; goto done;
if (!simple_property_equal (pipeline0, pipeline1, if (!simple_property_equal (authorities0, authorities1,
pipelines_difference, pipelines_difference,
COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE, COGL_PIPELINE_STATE_ALPHA_FUNC_REFERENCE_INDEX,
_cogl_pipeline_alpha_func_reference_state_equal)) _cogl_pipeline_alpha_func_reference_state_equal))
goto done; goto done;
@ -3338,11 +3442,8 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0,
if (pipeline0->real_blend_enable && if (pipeline0->real_blend_enable &&
pipelines_difference & COGL_PIPELINE_STATE_BLEND) pipelines_difference & COGL_PIPELINE_STATE_BLEND)
{ {
CoglPipelineState state = COGL_PIPELINE_STATE_BLEND; CoglPipeline *authority0 = authorities0[COGL_PIPELINE_STATE_BLEND_INDEX];
CoglPipeline *authority0 = CoglPipeline *authority1 = authorities1[COGL_PIPELINE_STATE_BLEND_INDEX];
_cogl_pipeline_get_authority (pipeline0, state);
CoglPipeline *authority1 =
_cogl_pipeline_get_authority (pipeline1, state);
if (!_cogl_pipeline_blend_state_equal (authority0, authority1)) if (!_cogl_pipeline_blend_state_equal (authority0, authority1))
goto done; goto done;
@ -3351,42 +3452,46 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0,
/* XXX: we don't need to compare the BLEND_ENABLE state because it's /* XXX: we don't need to compare the BLEND_ENABLE state because it's
* already reflected in ->real_blend_enable */ * already reflected in ->real_blend_enable */
#if 0 #if 0
if (!simple_property_equal (pipeline0, pipeline1, if (!simple_property_equal (authorities0, authorities1,
pipelines_difference, pipelines_difference,
COGL_PIPELINE_STATE_BLEND, COGL_PIPELINE_STATE_BLEND_INDEX,
_cogl_pipeline_blend_enable_equal)) _cogl_pipeline_blend_enable_equal))
return FALSE; return FALSE;
#endif #endif
if (!simple_property_equal (pipeline0, pipeline1, if (!simple_property_equal (authorities0, authorities1,
pipelines_difference, pipelines_difference,
COGL_PIPELINE_STATE_DEPTH, COGL_PIPELINE_STATE_DEPTH_INDEX,
_cogl_pipeline_depth_state_equal)) _cogl_pipeline_depth_state_equal))
goto done; goto done;
if (!simple_property_equal (pipeline0, pipeline1, if (!simple_property_equal (authorities0, authorities1,
pipelines_difference, pipelines_difference,
COGL_PIPELINE_STATE_FOG, COGL_PIPELINE_STATE_FOG_INDEX,
_cogl_pipeline_fog_state_equal)) _cogl_pipeline_fog_state_equal))
goto done; goto done;
if (!simple_property_equal (pipeline0, pipeline1, if (!simple_property_equal (authorities0, authorities1,
pipelines_difference, pipelines_difference,
COGL_PIPELINE_STATE_POINT_SIZE, COGL_PIPELINE_STATE_POINT_SIZE_INDEX,
_cogl_pipeline_point_size_equal)) _cogl_pipeline_point_size_equal))
goto done; goto done;
if (!simple_property_equal (pipeline0, pipeline1, if (!simple_property_equal (authorities0, authorities1,
pipelines_difference, pipelines_difference,
COGL_PIPELINE_STATE_USER_SHADER, COGL_PIPELINE_STATE_USER_SHADER_INDEX,
_cogl_pipeline_user_shader_equal)) _cogl_pipeline_user_shader_equal))
goto done; goto done;
if (!simple_property_equal (pipeline0, pipeline1, if (pipelines_difference & COGL_PIPELINE_STATE_LAYERS)
pipelines_difference, {
COGL_PIPELINE_STATE_LAYERS, CoglPipelineStateIndex state_index = COGL_PIPELINE_STATE_LAYERS_INDEX;
_cogl_pipeline_layers_equal)) if (!_cogl_pipeline_layers_equal (authorities0[state_index],
goto done; authorities1[state_index],
layer_differences,
flags))
goto done;
}
ret = TRUE; ret = TRUE;
done: done: