pipeline: differentiate texture target and data state

There are several places where we need to compare the texture state of a
pipeline and sometimes we need to take into consideration if the
underlying texture has changed but other times we may only care to know
if the texture target has changed.

For example the fragends typically generate programs that they want to
share with all pipelines with equivalent fragment processing state, and
in this case when comparing pipelines we only care about the texture
targets since changes to the underlying texture won't affect the
programs generated.

Prior to this we had tried to handle this by passing around some special
flags to various functions that evaluate pipeline state to say when we
do/don't care about the texture data, but this wasn't working in all
cases and was more awkward to manage than the new approach.

Now we simply have two state bits:
COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET and
COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA and CoglPipelineLayer has an
additional target member. Since all the appropriate code takes masks of
these state bits to determine what to evaluate we don't need any extra
magic flags.
This commit is contained in:
Robert Bragg 2011-01-11 16:02:06 +00:00
parent a6628ca113
commit 03dbf67ca4
8 changed files with 224 additions and 131 deletions

View File

@ -240,8 +240,7 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
(pipeline, (pipeline,
COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN & COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN &
~COGL_PIPELINE_STATE_LAYERS, ~COGL_PIPELINE_STATE_LAYERS,
COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN, COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN);
COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET);
authority_priv = get_arbfp_priv (authority); authority_priv = get_arbfp_priv (authority);
if (authority_priv && if (authority_priv &&
authority_priv->arbfp_program_state) authority_priv->arbfp_program_state)
@ -336,11 +335,10 @@ _cogl_pipeline_fragend_arbfp_hash (const void *data)
COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN; COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN;
unsigned long layer_fragment_state = unsigned long layer_fragment_state =
COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN; COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN;
CoglPipelineEvalFlags flags = COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA;
return _cogl_pipeline_hash ((CoglPipeline *)data, return _cogl_pipeline_hash ((CoglPipeline *)data,
fragment_state, layer_fragment_state, fragment_state, layer_fragment_state,
flags); 0);
} }
gboolean gboolean
@ -350,11 +348,10 @@ _cogl_pipeline_fragend_arbfp_equal (const void *a, const void *b)
COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN; COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN;
unsigned long layer_fragment_state = unsigned long layer_fragment_state =
COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN; COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN;
CoglPipelineEvalFlags flags = COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA;
return _cogl_pipeline_equal ((CoglPipeline *)a, (CoglPipeline *)b, return _cogl_pipeline_equal ((CoglPipeline *)a, (CoglPipeline *)b,
fragment_state, layer_fragment_state, fragment_state, layer_fragment_state,
flags); 0);
} }
static const char * static const char *

View File

@ -139,22 +139,19 @@ _cogl_pipeline_fragend_fixed_add_layer (CoglPipeline *pipeline,
} }
/* Handle enabling or disabling the right texture target */ /* Handle enabling or disabling the right texture target */
if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE) if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET)
{ {
CoglPipelineLayer *authority = CoglPipelineLayer *tex_authority =
_cogl_pipeline_layer_get_authority (layer, _cogl_pipeline_layer_get_authority (layer,
COGL_PIPELINE_LAYER_STATE_TEXTURE); COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
CoglHandle texture; CoglPipelineLayer *target_authority =
GLuint gl_texture; _cogl_pipeline_layer_get_authority (layer,
GLenum gl_target; COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET);
/* XXX: currently layers with no associated texture fallback to
texture = (authority->texture == COGL_INVALID_HANDLE ? * using ctx->default_gl_texture_2d_tex so they have a texture
ctx->default_gl_texture_2d_tex : * target of GL_TEXTURE_2D */
authority->texture); GLenum gl_target =
tex_authority->texture ? target_authority->target : GL_TEXTURE_2D;
cogl_texture_get_gl_texture (texture,
&gl_texture,
&gl_target);
_cogl_set_active_texture_unit (unit_index); _cogl_set_active_texture_unit (unit_index);

View File

@ -240,8 +240,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
(pipeline, (pipeline,
COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN & COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN &
~COGL_PIPELINE_STATE_LAYERS, ~COGL_PIPELINE_STATE_LAYERS,
COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN, COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN);
COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET);
authority_priv = get_glsl_priv (authority); authority_priv = get_glsl_priv (authority);
if (!authority_priv) if (!authority_priv)

View File

@ -674,11 +674,11 @@ flush_layers_common_gl_state_cb (CoglPipelineLayer *layer, void *user_data)
return FALSE; return FALSE;
} }
if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE) if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
{ {
unsigned long state = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
CoglPipelineLayer *authority = CoglPipelineLayer *authority =
_cogl_pipeline_layer_get_authority (layer, _cogl_pipeline_layer_get_authority (layer, state);
COGL_PIPELINE_LAYER_STATE_TEXTURE);
CoglHandle texture; CoglHandle texture;
GLuint gl_texture; GLuint gl_texture;
GLenum gl_target; GLenum gl_target;
@ -909,7 +909,8 @@ compare_layer_differences_cb (CoglPipelineLayer *layer, void *user_data)
* then we force an update of the texture state... * then we force an update of the texture state...
*/ */
if (unit->texture_storage_changed) if (unit->texture_storage_changed)
state->layer_differences[state->i] |= COGL_PIPELINE_LAYER_STATE_TEXTURE; state->layer_differences[state->i] |=
COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
state->i++; state->i++;

View File

@ -116,7 +116,8 @@ typedef enum
{ {
/* sparse state */ /* sparse state */
COGL_PIPELINE_LAYER_STATE_UNIT_INDEX, COGL_PIPELINE_LAYER_STATE_UNIT_INDEX,
COGL_PIPELINE_LAYER_STATE_TEXTURE_INDEX, COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX,
COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX,
COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX, COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX, COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX,
COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX, COGL_PIPELINE_LAYER_STATE_COMBINE_INDEX,
@ -141,8 +142,10 @@ typedef enum
{ {
COGL_PIPELINE_LAYER_STATE_UNIT = COGL_PIPELINE_LAYER_STATE_UNIT =
1L<<COGL_PIPELINE_LAYER_STATE_UNIT_INDEX, 1L<<COGL_PIPELINE_LAYER_STATE_UNIT_INDEX,
COGL_PIPELINE_LAYER_STATE_TEXTURE = COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET =
1L<<COGL_PIPELINE_LAYER_STATE_TEXTURE_INDEX, 1L<<COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX,
COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA =
1L<<COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX,
COGL_PIPELINE_LAYER_STATE_FILTERS = COGL_PIPELINE_LAYER_STATE_FILTERS =
1L<<COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX, 1L<<COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX,
COGL_PIPELINE_LAYER_STATE_WRAP_MODES = COGL_PIPELINE_LAYER_STATE_WRAP_MODES =
@ -190,13 +193,13 @@ typedef enum
* when point sprite coords are enabled */ * when point sprite coords are enabled */
#define COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN \ #define COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN \
(COGL_PIPELINE_LAYER_STATE_COMBINE | \ (COGL_PIPELINE_LAYER_STATE_COMBINE | \
COGL_PIPELINE_LAYER_STATE_TEXTURE | \ COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET | \
COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS | \ COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS | \
COGL_PIPELINE_LAYER_STATE_UNIT) COGL_PIPELINE_LAYER_STATE_UNIT)
#else #else
#define COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN \ #define COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN \
(COGL_PIPELINE_LAYER_STATE_COMBINE | \ (COGL_PIPELINE_LAYER_STATE_COMBINE | \
COGL_PIPELINE_LAYER_STATE_TEXTURE | \ COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET | \
COGL_PIPELINE_LAYER_STATE_UNIT) COGL_PIPELINE_LAYER_STATE_UNIT)
#endif #endif
@ -370,6 +373,7 @@ struct _CoglPipelineLayer
/* The texture for this layer, or COGL_INVALID_HANDLE for an empty /* The texture for this layer, or COGL_INVALID_HANDLE for an empty
* layer */ * layer */
CoglHandle texture; CoglHandle texture;
GLenum target;
CoglPipelineFilter mag_filter; CoglPipelineFilter mag_filter;
CoglPipelineFilter min_filter; CoglPipelineFilter min_filter;
@ -600,12 +604,6 @@ typedef struct
CoglPipelineLayer *layer; CoglPipelineLayer *layer;
} CoglPipelineLayerCacheEntry; } CoglPipelineLayerCacheEntry;
/* Flags used for _cogl_pipeline_find_equivalent_parent */
typedef enum
{
COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET = 1L<<0
} CoglPipelineFindEquivalentFlags;
/* /*
* CoglPipelineDestroyCallback * CoglPipelineDestroyCallback
* @pipeline: The #CoglPipeline that has been destroyed * @pipeline: The #CoglPipeline that has been destroyed
@ -1092,10 +1090,7 @@ _cogl_pipeline_compare_differences (CoglPipeline *pipeline0,
* semantics */ * semantics */
typedef enum _CoglPipelineEvalFlags typedef enum _CoglPipelineEvalFlags
{ {
/* When evaluating a pipeline-layer with associated textures then COGL_PIPELINE_EVAL_FLAG_NONE = 0
* evaluate the texture target, but don't consider the texture data
* itself. */
COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA = 1L<<0
} CoglPipelineEvalFlags; } CoglPipelineEvalFlags;
gboolean gboolean
@ -1160,8 +1155,7 @@ _cogl_pipeline_get_authority (CoglPipeline *pipeline,
CoglPipeline * CoglPipeline *
_cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline, _cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline,
CoglPipelineState pipeline_state, CoglPipelineState pipeline_state,
CoglPipelineLayerState layer_state, CoglPipelineLayerState layer_state);
CoglPipelineFindEquivalentFlags flags);
CoglHandle CoglHandle
_cogl_pipeline_get_layer_texture (CoglPipeline *pipeline, _cogl_pipeline_get_layer_texture (CoglPipeline *pipeline,

View File

@ -525,8 +525,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN) & COGL_PIPELINE_STATE_AFFECTS_FRAGMENT_CODEGEN) &
~COGL_PIPELINE_STATE_LAYERS, ~COGL_PIPELINE_STATE_LAYERS,
COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN | COGL_PIPELINE_LAYER_STATE_AFFECTS_FRAGMENT_CODEGEN |
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN, COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);
COGL_PIPELINE_FIND_EQUIVALENT_COMPARE_TEXTURE_TARGET);
priv = get_glsl_priv (authority); priv = get_glsl_priv (authority);

View File

@ -157,8 +157,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
(pipeline, (pipeline,
COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN & COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN &
~COGL_PIPELINE_STATE_LAYERS, ~COGL_PIPELINE_STATE_LAYERS,
COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN, COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);
0);
priv = get_glsl_priv (authority); priv = get_glsl_priv (authority);

View File

@ -799,7 +799,7 @@ layer_has_alpha_cb (CoglPipelineLayer *layer, void *data)
*/ */
tex_authority = tex_authority =
_cogl_pipeline_layer_get_authority (layer, _cogl_pipeline_layer_get_authority (layer,
COGL_PIPELINE_LAYER_STATE_TEXTURE); COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
if (tex_authority->texture && if (tex_authority->texture &&
cogl_texture_get_format (tex_authority->texture) & COGL_A_BIT) cogl_texture_get_format (tex_authority->texture) & COGL_A_BIT)
{ {
@ -1716,7 +1716,8 @@ _cogl_pipeline_layer_init_multi_property_sparse_state (
/* XXX: avoid using a default: label so we get a warning if we /* XXX: avoid using a default: label so we get a warning if we
* don't explicitly handle a newly defined state-group here. */ * don't explicitly handle a newly defined state-group here. */
case COGL_PIPELINE_LAYER_STATE_UNIT: case COGL_PIPELINE_LAYER_STATE_UNIT:
case COGL_PIPELINE_LAYER_STATE_TEXTURE: case COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET:
case COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA:
case COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS: case COGL_PIPELINE_LAYER_STATE_POINT_SPRITE_COORDS:
case COGL_PIPELINE_LAYER_STATE_USER_MATRIX: case COGL_PIPELINE_LAYER_STATE_USER_MATRIX:
case COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT: case COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT:
@ -2153,7 +2154,7 @@ _cogl_pipeline_layer_get_texture_real (CoglPipelineLayer *layer)
{ {
CoglPipelineLayer *authority = CoglPipelineLayer *authority =
_cogl_pipeline_layer_get_authority (layer, _cogl_pipeline_layer_get_authority (layer,
COGL_PIPELINE_LAYER_STATE_TEXTURE); COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
return authority->texture; return authority->texture;
} }
@ -2242,12 +2243,83 @@ _cogl_pipeline_prune_empty_layer_difference (CoglPipeline *layers_authority,
} }
} }
void static void
cogl_pipeline_set_layer_texture (CoglPipeline *pipeline, _cogl_pipeline_set_layer_texture_target (CoglPipeline *pipeline,
int layer_index,
GLenum target)
{
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET;
CoglPipelineLayer *layer;
CoglPipelineLayer *authority;
CoglPipelineLayer *new;
/* Note: this will ensure that the layer exists, creating one if it
* doesn't already.
*
* Note: If the layer already existed it's possibly owned by another
* pipeline. If the layer is created then it will be owned by
* pipeline. */
layer = _cogl_pipeline_get_layer (pipeline, layer_index);
/* Now find the ancestor of the layer that is the authority for the
* state we want to change */
authority = _cogl_pipeline_layer_get_authority (layer, change);
if (target == authority->target)
return;
new = _cogl_pipeline_layer_pre_change_notify (pipeline, layer, change);
if (new != layer)
layer = new;
else
{
/* If the original layer we found is currently the authority on
* the state we are changing see if we can revert to one of our
* ancestors being the authority. */
if (layer == authority &&
_cogl_pipeline_layer_get_parent (authority) != NULL)
{
CoglPipelineLayer *parent =
_cogl_pipeline_layer_get_parent (authority);
CoglPipelineLayer *old_authority =
_cogl_pipeline_layer_get_authority (parent, change);
if (old_authority->target == target)
{
layer->differences &= ~change;
g_assert (layer->owner == pipeline);
if (layer->differences == 0)
_cogl_pipeline_prune_empty_layer_difference (pipeline,
layer);
goto changed;
}
}
}
layer->target = target;
/* If we weren't previously the authority on this state then we need
* to extended our differences mask and so it's possible that some
* of our ancestry will now become redundant, so we aim to reparent
* ourselves if that's true... */
if (layer != authority)
{
layer->differences |= change;
_cogl_pipeline_layer_prune_redundant_ancestry (layer);
}
changed:
handle_automatic_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
}
static void
_cogl_pipeline_set_layer_texture_data (CoglPipeline *pipeline,
int layer_index, int layer_index,
CoglHandle texture) CoglHandle texture)
{ {
CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE; CoglPipelineLayerState change = COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA;
CoglPipelineLayer *layer; CoglPipelineLayer *layer;
CoglPipelineLayer *authority; CoglPipelineLayer *authority;
CoglPipelineLayer *new; CoglPipelineLayer *new;
@ -2321,6 +2393,48 @@ changed:
handle_automatic_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS); handle_automatic_blend_enable (pipeline, COGL_PIPELINE_STATE_LAYERS);
} }
/* A convenience for querying the target of a given texture that
* notably returns 0 for NULL textures - so we can say that a layer
* with no associated CoglTexture will have a texture target of 0.
*/
static GLenum
get_texture_target (CoglHandle texture)
{
GLuint ignore_handle;
GLenum gl_target;
if (texture)
cogl_texture_get_gl_texture (texture, &ignore_handle, &gl_target);
else
return 0;/* XXX: An invalid GL target enum */
return gl_target;
}
void
cogl_pipeline_set_layer_texture (CoglPipeline *pipeline,
int layer_index,
CoglHandle texture)
{
/* For the convenience of fragend code we separate texture state
* into the "target" and the "data", and setting a layer texture
* updates both of these properties.
*
* One example for why this is helpful is that the fragends may
* cache programs they generate and want to re-use those programs
* with all pipelines having equivalent fragment processing state.
* For the sake of determining if pipelines have equivalent fragment
* processing state we don't need to compare that the same
* underlying texture objects are referenced by the pipelines but we
* do need to see if they use the same texture targets. Making this
* distinction is much simpler if they are in different state
* groups.
*/
_cogl_pipeline_set_layer_texture_target (pipeline, layer_index,
get_texture_target (texture));
_cogl_pipeline_set_layer_texture_data (pipeline, layer_index, texture);
}
typedef struct typedef struct
{ {
int i; int i;
@ -2897,20 +3011,24 @@ _cogl_pipeline_apply_overrides (CoglPipeline *pipeline,
} }
static gboolean static gboolean
_cogl_pipeline_layer_texture_equal (CoglPipelineLayer *authority0, _cogl_pipeline_layer_texture_target_equal (CoglPipelineLayer *authority0,
CoglPipelineLayer *authority1,
CoglPipelineEvalFlags flags)
{
return authority0->target == authority1->target;
}
static gboolean
_cogl_pipeline_layer_texture_data_equal (CoglPipelineLayer *authority0,
CoglPipelineLayer *authority1, CoglPipelineLayer *authority1,
CoglPipelineEvalFlags flags) CoglPipelineEvalFlags flags)
{ {
GLuint gl_handle0, gl_handle1; GLuint gl_handle0, gl_handle1;
GLenum gl_target0, gl_target1;
cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, &gl_target0); cogl_texture_get_gl_texture (authority0->texture, &gl_handle0, NULL);
cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, &gl_target1); cogl_texture_get_gl_texture (authority1->texture, &gl_handle1, NULL);
if (flags & COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA) return gl_handle0 == gl_handle1;
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.
@ -3177,11 +3295,21 @@ _cogl_pipeline_layer_equal (CoglPipelineLayer *layer0,
layers_difference, layers_difference,
authorities1); authorities1);
if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE) if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET)
{ {
CoglPipelineLayerStateIndex state_index = CoglPipelineLayerStateIndex state_index =
COGL_PIPELINE_LAYER_STATE_TEXTURE_INDEX; COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX;
if (!_cogl_pipeline_layer_texture_equal (authorities0[state_index], if (!_cogl_pipeline_layer_texture_target_equal (authorities0[state_index],
authorities1[state_index],
flags))
return FALSE;
}
if (layers_difference & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
{
CoglPipelineLayerStateIndex state_index =
COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX;
if (!_cogl_pipeline_layer_texture_data_equal (authorities0[state_index],
authorities1[state_index], authorities1[state_index],
flags)) flags))
return FALSE; return FALSE;
@ -4794,7 +4922,7 @@ _cogl_pipeline_layer_free (CoglPipelineLayer *layer)
{ {
_cogl_pipeline_layer_unparent (COGL_PIPELINE_NODE (layer)); _cogl_pipeline_layer_unparent (COGL_PIPELINE_NODE (layer));
if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE && if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA &&
layer->texture != COGL_INVALID_HANDLE) layer->texture != COGL_INVALID_HANDLE)
cogl_handle_unref (layer->texture); cogl_handle_unref (layer->texture);
@ -4851,6 +4979,7 @@ _cogl_pipeline_init_default_layers (void)
layer->unit_index = 0; layer->unit_index = 0;
layer->texture = COGL_INVALID_HANDLE; layer->texture = COGL_INVALID_HANDLE;
layer->target = 0;
layer->mag_filter = COGL_PIPELINE_FILTER_LINEAR; layer->mag_filter = COGL_PIPELINE_FILTER_LINEAR;
layer->min_filter = COGL_PIPELINE_FILTER_LINEAR; layer->min_filter = COGL_PIPELINE_FILTER_LINEAR;
@ -5511,7 +5640,7 @@ _cogl_pipeline_layer_pre_paint (CoglPipelineLayer *layer)
texture_authority = texture_authority =
_cogl_pipeline_layer_get_authority (layer, _cogl_pipeline_layer_get_authority (layer,
COGL_PIPELINE_LAYER_STATE_TEXTURE); COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA);
if (texture_authority->texture != COGL_INVALID_HANDLE) if (texture_authority->texture != COGL_INVALID_HANDLE)
{ {
@ -5750,22 +5879,27 @@ _cogl_pipeline_layer_hash_unit_state (CoglPipelineLayer *authority,
} }
static void static void
_cogl_pipeline_layer_hash_texture_state (CoglPipelineLayer *authority, _cogl_pipeline_layer_hash_texture_target_state (CoglPipelineLayer *authority,
CoglPipelineLayer **authorities,
HashState *state)
{
GLenum gl_target = authority->target;
state->hash =
_cogl_util_one_at_a_time_hash (state->hash, &gl_target, sizeof (gl_target));
}
static void
_cogl_pipeline_layer_hash_texture_data_state (CoglPipelineLayer *authority,
CoglPipelineLayer **authorities, CoglPipelineLayer **authorities,
HashState *state) HashState *state)
{ {
GLuint gl_handle; GLuint gl_handle;
GLenum gl_target;
unsigned long hash = state->hash;
cogl_texture_get_gl_texture (authority->texture, &gl_handle, &gl_target); cogl_texture_get_gl_texture (authority->texture, &gl_handle, NULL);
hash = _cogl_util_one_at_a_time_hash (hash, &gl_target, sizeof (gl_target)); state->hash =
_cogl_util_one_at_a_time_hash (state->hash, &gl_handle, sizeof (gl_handle));
if (!(state->flags & COGL_PIPELINE_EVAL_FLAG_IGNORE_TEXTURE_DATA))
hash = _cogl_util_one_at_a_time_hash (hash, &gl_handle, sizeof (gl_handle));
state->hash = hash;
} }
static void static void
@ -5922,8 +6056,10 @@ _cogl_pipeline_init_layer_state_hash_functions (void)
CoglPipelineLayerStateIndex _index; CoglPipelineLayerStateIndex _index;
layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_UNIT_INDEX] = layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_UNIT_INDEX] =
_cogl_pipeline_layer_hash_unit_state; _cogl_pipeline_layer_hash_unit_state;
layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_TEXTURE_INDEX] = layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_TEXTURE_TARGET_INDEX] =
_cogl_pipeline_layer_hash_texture_state; _cogl_pipeline_layer_hash_texture_target_state;
layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA_INDEX] =
_cogl_pipeline_layer_hash_texture_data_state;
layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX] = layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_FILTERS_INDEX] =
_cogl_pipeline_layer_hash_filters_state; _cogl_pipeline_layer_hash_filters_state;
layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX] = layer_state_hash_functions[COGL_PIPELINE_LAYER_STATE_WRAP_MODES_INDEX] =
@ -5939,7 +6075,7 @@ _cogl_pipeline_init_layer_state_hash_functions (void)
_cogl_pipeline_layer_hash_point_sprite_state; _cogl_pipeline_layer_hash_point_sprite_state;
/* So we get a big error if we forget to update this code! */ /* So we get a big error if we forget to update this code! */
g_assert (COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT == 8); g_assert (COGL_PIPELINE_LAYER_STATE_SPARSE_COUNT == 9);
} }
static gboolean static gboolean
@ -6300,7 +6436,7 @@ dump_layer_cb (CoglPipelineNode *node, void *user_data)
layer->unit_index); layer->unit_index);
} }
if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE) if (layer->differences & COGL_PIPELINE_LAYER_STATE_TEXTURE_DATA)
{ {
changes = TRUE; changes = TRUE;
g_string_append_printf (changes_label, g_string_append_printf (changes_label,
@ -6585,43 +6721,6 @@ _cogl_pipeline_need_texture_combine_separate
return FALSE; return FALSE;
} }
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 /* This tries to find the oldest ancestor whose pipeline and layer
state matches the given flags. This is mostly used to detect code state matches the given flags. This is mostly used to detect code
gen authorities so that we can reduce the numer of programs gen authorities so that we can reduce the numer of programs
@ -6629,8 +6728,7 @@ layers_differ_for_find_equivalent (CoglPipelineLayerState layer_state,
CoglPipeline * CoglPipeline *
_cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline, _cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline,
CoglPipelineState pipeline_state, CoglPipelineState pipeline_state,
CoglPipelineLayerState layer_state, CoglPipelineLayerState layer_state)
CoglPipelineFindEquivalentFlags flags)
{ {
CoglPipeline *authority0; CoglPipeline *authority0;
CoglPipeline *authority1; CoglPipeline *authority1;
@ -6690,10 +6788,19 @@ _cogl_pipeline_find_equivalent_parent (CoglPipeline *pipeline,
&state); &state);
for (i = 0; i < n_layers; i++) for (i = 0; i < n_layers; i++)
if (layers_differ_for_find_equivalent (layer_state, flags, {
authority0_layers[i], unsigned long layer_differences;
authority1_layers[i]))
if (authority0_layers[i] == authority1_layers[i])
continue;
layer_differences =
_cogl_pipeline_layer_compare_differences (authority0_layers[i],
authority1_layers[i]);
if (layer_differences & layer_state)
return authority0; return authority0;
}
/* Find the next ancestor after that, that also modifies state /* Find the next ancestor after that, that also modifies state
* affecting codegen... */ * affecting codegen... */