[cogl] pipeline: fix layer change notify mutex rule
- From: Robert Bragg <rbragg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [cogl] pipeline: fix layer change notify mutex rule
- Date: Thu, 30 Jun 2011 13:37:26 +0000 (UTC)
commit 256274bfcc7d41721ea343e8215a8ac5a5a6ea37
Author: Robert Bragg <robert linux intel com>
Date: Mon Jun 27 11:50:48 2011 +0100
pipeline: fix layer change notify mutex rule
There is a documented rule that layer changes should only be notified to
the fragend once; either as a pipeline change or as a layer change. When
the number of layers associated with a material changes then that should
get notified against the pipeline. All other layer changes get notified
against the layer.
There was a mistake in the _cogl_pipeline_add/remove_layer_difference
functions, in that we weren't using the 'inc/dec_n_layers' boolean to
determine if the fragend should be notified of the change.
It was also noticed that the logic of _cogl_pipeline_prune_to_n_layers
would also break this rule, by failing to notify some changes at all.
Signed-off-by: Neil Roberts <neil linux intel com>
cogl/cogl-pipeline.c | 159 ++++++++++++++++++++-----------------------------
1 files changed, 65 insertions(+), 94 deletions(-)
---
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c
index 0955d95..45fc077 100644
--- a/cogl/cogl-pipeline.c
+++ b/cogl/cogl-pipeline.c
@@ -1213,8 +1213,6 @@ _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline,
const CoglColor *new_color,
gboolean from_layer_change)
{
- int i;
-
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* If primitives have been logged in the journal referencing the
@@ -1267,70 +1265,54 @@ _cogl_pipeline_pre_change_notify (CoglPipeline *pipeline,
_cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_UNDEFINED);
#endif
- /* To simplify things for the backends we are careful about how
- * we report STATE_LAYERS changes.
+ /* XXX:
+ * To simplify things for the vertex, fragment and program backends
+ * we are careful about how we report STATE_LAYERS changes.
*
- * All STATE_LAYERS changes with the exception of ->n_layers
- * will also result in layer_pre_change_notifications. For
- * backends that perform code generation for fragment processing
- * they typically need to understand the details of how layers
- * get changed to determine if they need to repeat codegen. It
- * doesn't help them to report a pipeline STATE_LAYERS change
- * for all layer changes since it's so broad, they really need
- * to wait for the layer change to be notified. What does help
- * though is to report a STATE_LAYERS change for a change in
- * ->n_layers because they typically do need to repeat codegen
- * in that case.
+ * All STATE_LAYERS change notification with the exception of
+ * ->n_layers will also result in layer_pre_change_notifications.
+ * For backends that perform code generation for fragment
+ * processing they typically need to understand the details of how
+ * layers get changed to determine if they need to repeat codegen.
+ * It doesn't help them to
+ * report a pipeline STATE_LAYERS change for all layer changes since
+ * it's so broad, they really need to wait for the specific layer
+ * change to be notified. What does help though is to report a
+ * STATE_LAYERS change for a change in
+ * ->n_layers because they typically do need to repeat codegen in
+ * that case.
*
- * This just ensures backends only get a single pipeline or
- * layer pre-change notification for any particular change.
+ * Here we ensure that change notifications against a pipeline or
+ * against a layer are mutually exclusive as far as fragment, vertex
+ * and program backends are concerned.
*/
- if (pipeline->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
- _cogl_pipeline_fragends[pipeline->fragend]->pipeline_pre_change_notify)
+ if (!from_layer_change)
{
- const CoglPipelineFragend *fragend =
- _cogl_pipeline_fragends[pipeline->fragend];
+ int i;
- if (!from_layer_change)
- fragend->pipeline_pre_change_notify (pipeline, change, new_color);
- }
+ if (pipeline->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
+ _cogl_pipeline_fragends[pipeline->fragend]->pipeline_pre_change_notify)
+ {
+ const CoglPipelineFragend *fragend =
+ _cogl_pipeline_fragends[pipeline->fragend];
+ fragend->pipeline_pre_change_notify (pipeline, change, new_color);
+ }
- if (pipeline->vertend != COGL_PIPELINE_VERTEND_UNDEFINED &&
- _cogl_pipeline_vertends[pipeline->vertend]->pipeline_pre_change_notify)
- {
- const CoglPipelineVertend *vertend =
- _cogl_pipeline_vertends[pipeline->vertend];
+ if (pipeline->vertend != COGL_PIPELINE_VERTEND_UNDEFINED &&
+ _cogl_pipeline_vertends[pipeline->vertend]->pipeline_pre_change_notify)
+ {
+ const CoglPipelineVertend *vertend =
+ _cogl_pipeline_vertends[pipeline->vertend];
+ vertend->pipeline_pre_change_notify (pipeline, change, new_color);
+ }
- /* To simplify things for the backends we are careful about how
- * we report STATE_LAYERS changes.
- *
- * All STATE_LAYERS changes with the exception of ->n_layers
- * will also result in layer_pre_change_notifications. For
- * backends that perform code generation for fragment processing
- * they typically need to understand the details of how layers
- * get changed to determine if they need to repeat codegen. It
- * doesn't help them to report a pipeline STATE_LAYERS change
- * for all layer changes since it's so broad, they really need
- * to wait for the layer change to be notified. What does help
- * though is to report a STATE_LAYERS change for a change in
- * ->n_layers because they typically do need to repeat codegen
- * in that case.
- *
- * This just ensures backends only get a single pipeline or
- * layer pre-change notification for any particular change.
- */
- if (!from_layer_change)
- vertend->pipeline_pre_change_notify (pipeline, change, new_color);
+ for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
+ if (_cogl_pipeline_progends[i]->pipeline_pre_change_notify)
+ _cogl_pipeline_progends[i]->pipeline_pre_change_notify (pipeline,
+ change,
+ new_color);
}
- /* Notify all of the progends */
- if (!from_layer_change)
- for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
- if (_cogl_pipeline_progends[i]->pipeline_pre_change_notify)
- _cogl_pipeline_progends[i]->pipeline_pre_change_notify (pipeline,
- change,
- new_color);
-
/* There may be an arbitrary tree of descendants of this pipeline;
* any of which may indirectly depend on this pipeline as the
* authority for some set of properties. (Meaning for example that
@@ -1460,10 +1442,15 @@ _cogl_pipeline_add_layer_difference (CoglPipeline *pipeline,
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
+ /* Note: the last argument to _cogl_pipeline_pre_change_notify is
+ * needed to differentiate STATE_LAYER changes which don't affect
+ * the number of layers from those that do. NB: Layer change
+ * notifications that don't change the number of layers don't get
+ * forwarded to the fragend. */
_cogl_pipeline_pre_change_notify (pipeline,
COGL_PIPELINE_STATE_LAYERS,
NULL,
- FALSE);
+ !inc_n_layers);
pipeline->differences |= COGL_PIPELINE_STATE_LAYERS;
@@ -1474,10 +1461,6 @@ _cogl_pipeline_add_layer_difference (CoglPipeline *pipeline,
pipeline->n_layers++;
}
-/* NB: If you are calling this it's your responsibility to have
- * already called:
- * _cogl_pipeline_pre_change_notify (m, _CHANGE_LAYERS, NULL);
- */
static void
_cogl_pipeline_remove_layer_difference (CoglPipeline *pipeline,
CoglPipelineLayer *layer,
@@ -1490,10 +1473,15 @@ _cogl_pipeline_remove_layer_difference (CoglPipeline *pipeline,
* - If the pipeline isn't currently an authority for the state being
* changed, then initialize that state from the current authority.
*/
+ /* Note: the last argument to _cogl_pipeline_pre_change_notify is
+ * needed to differentiate STATE_LAYER changes which don't affect
+ * the number of layers from those that do. NB: Layer change
+ * notifications that don't change the number of layers don't get
+ * forwarded to the fragend. */
_cogl_pipeline_pre_change_notify (pipeline,
COGL_PIPELINE_STATE_LAYERS,
NULL,
- FALSE);
+ !dec_n_layers);
layer->owner = NULL;
cogl_object_unref (layer);
@@ -1558,7 +1546,6 @@ typedef struct
{
int keep_n;
int current_pos;
- gboolean needs_pruning;
int first_index_to_prune;
} CoglPipelinePruneLayersInfo;
@@ -1569,7 +1556,6 @@ update_prune_layers_info_cb (CoglPipelineLayer *layer, void *user_data)
if (state->current_pos == state->keep_n)
{
- state->needs_pruning = TRUE;
state->first_index_to_prune = layer->index;
return FALSE;
}
@@ -1580,26 +1566,29 @@ update_prune_layers_info_cb (CoglPipelineLayer *layer, void *user_data)
void
_cogl_pipeline_prune_to_n_layers (CoglPipeline *pipeline, int n)
{
+ CoglPipeline *authority =
+ _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LAYERS);
CoglPipelinePruneLayersInfo state;
- gboolean notified_change = TRUE;
GList *l;
GList *next;
+ if (authority->n_layers <= n)
+ return;
+
+ _cogl_pipeline_pre_change_notify (pipeline,
+ COGL_PIPELINE_STATE_LAYERS,
+ NULL,
+ FALSE);
+
state.keep_n = n;
state.current_pos = 0;
- state.needs_pruning = FALSE;
_cogl_pipeline_foreach_layer_internal (pipeline,
update_prune_layers_info_cb,
&state);
+ pipeline->differences |= COGL_PIPELINE_STATE_LAYERS;
pipeline->n_layers = n;
- if (!state.needs_pruning)
- return;
-
- if (!(pipeline->differences & COGL_PIPELINE_STATE_LAYERS))
- return;
-
/* It's possible that this pipeline owns some of the layers being
* discarded, so we'll need to unlink them... */
for (l = pipeline->layer_differences; l; l = next)
@@ -1608,28 +1597,10 @@ _cogl_pipeline_prune_to_n_layers (CoglPipeline *pipeline, int n)
next = l->next; /* we're modifying the list we're iterating */
if (layer->index > state.first_index_to_prune)
- {
- if (!notified_change)
- {
- /* - Flush journal primitives referencing the current
- * state.
- * - Make sure the pipeline has no dependants so it may
- * be modified.
- * - If the pipeline isn't currently an authority for
- * the state being changed, then initialize that state
- * from the current authority.
- */
- _cogl_pipeline_pre_change_notify (pipeline,
- COGL_PIPELINE_STATE_LAYERS,
- NULL,
- FALSE);
- notified_change = TRUE;
- }
-
- pipeline->layer_differences =
- g_list_delete_link (pipeline->layer_differences, l);
- }
+ _cogl_pipeline_remove_layer_difference (pipeline, layer, FALSE);
}
+
+ pipeline->differences |= COGL_PIPELINE_STATE_LAYERS;
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]