[cogl/wip/neil/pipeline-uniforms: 16/17] Stash



commit 3e51b248a4554d16b6940ee93b5607f61a4953ce
Author: Neil Roberts <neil linux intel com>
Date:   Wed Nov 2 12:43:53 2011 +0000

    Stash

 cogl/cogl-pipeline-progend-glsl.c |  196 +++++++++++++++++++++---------------
 cogl/cogl-pipeline.c              |    6 +
 2 files changed, 120 insertions(+), 82 deletions(-)
---
diff --git a/cogl/cogl-pipeline-progend-glsl.c b/cogl/cogl-pipeline-progend-glsl.c
index 4ec6f37..84a516c 100644
--- a/cogl/cogl-pipeline-progend-glsl.c
+++ b/cogl/cogl-pipeline-progend-glsl.c
@@ -142,12 +142,6 @@ typedef struct
    * so know if we need to update all of the uniforms */
   CoglPipeline *last_used_for_pipeline;
 
-  /* TRUE if any of the uniforms on this pipeline have been modified
-     since it was last flushed. If so then we'll flush all of the
-     uniforms that this pipeline overrides (but not necessarily those
-     that the parent overrides if we've already flushed them) */
-  gboolean uniforms_changed;
-
   /* Array of GL uniform locations indexed by Cogl's uniform
      location. We are careful only to allocated this array if a custom
      uniform is actually set */
@@ -323,7 +317,6 @@ program_state_new (int n_layers)
   program_state->program = 0;
   program_state->n_tex_coord_attribs = 0;
   program_state->unit_state = g_new (UnitState, n_layers);
-  program_state->uniforms_changed = TRUE;
   program_state->uniform_locations = NULL;
 #ifdef HAVE_COGL_GLES2
   program_state->tex_coord_attribute_locations = NULL;
@@ -558,17 +551,6 @@ update_builtin_uniforms (CoglPipeline *pipeline,
 
 #endif /* HAVE_COGL_GLES2 */
 
-static GSList *
-get_ancestors (CoglPipeline *pipeline)
-{
-  GSList *ancestors = NULL;
-
-  while (pipeline)
-    ancestors = g_slist_prepend (ancestors, pipeline);
-
-  return ancestors;
-}
-
 static void
 flush_uniform_boxed_value (CoglContext *ctx,
                            GLint uniform_location,
@@ -622,23 +604,96 @@ flush_uniform_boxed_value (CoglContext *ctx,
 typedef struct
 {
   CoglPipelineProgramState *program_state;
-  CoglPipeline *flushed_ancestor;
-  unsigned long *force_flush_uniforms;
-  unsigned long *flushed_uniforms;
+  unsigned long *uniform_differences;
+  int n_differences;
   CoglPipelineUniformsState *uniforms_state;
-  gboolean found_ancestor;
   CoglContext *ctx;
   CoglPipelineUniformOverride *override;
 } FlushUniformsClosure;
 
+static void
+compare_uniform_differences (FlushUniformsClosure *data,
+                             CoglPipeline *pipeline0,
+                             CoglPipeline *pipeline1)
+{
+  GSList *head0 = NULL;
+  GSList *head1 = NULL;
+  CoglPipeline *node0;
+  CoglPipeline *node1;
+  int len0 = 0;
+  int len1 = 0;
+  int count;
+  GSList *common_ancestor0;
+  GSList *common_ancestor1;
+
+  /* This algorithm is copied from
+     _cogl_pipeline_compare_differences(). It might be nice to share
+     the code more */
+
+  for (node0 = pipeline0; node0; node0 = _cogl_pipeline_get_parent (node0))
+    {
+      GSList *link = alloca (sizeof (GSList));
+      link->next = head0;
+      link->data = node0;
+      head0 = link;
+      len0++;
+    }
+  for (node1 = pipeline1; node1; node1 = _cogl_pipeline_get_parent (node1))
+    {
+      GSList *link = alloca (sizeof (GSList));
+      link->next = head1;
+      link->data = node1;
+      head1 = link;
+      len1++;
+    }
+
+  /* NB: There's no point looking at the head entries since we know both
+   * pipelines must have the same default pipeline as their root node. */
+  common_ancestor0 = head0;
+  common_ancestor1 = head1;
+  head0 = head0->next;
+  head1 = head1->next;
+  count = MIN (len0, len1) - 1;
+  while (count--)
+    {
+      if (head0->data != head1->data)
+        break;
+      common_ancestor0 = head0;
+      common_ancestor1 = head1;
+      head0 = head0->next;
+      head1 = head1->next;
+    }
+
+  for (head0 = common_ancestor0->next; head0; head0 = head0->next)
+    {
+      node0 = head0->data;
+      if ((node0->differences & COGL_PIPELINE_STATE_UNIFORMS))
+        {
+          const CoglPipelineUniformsState *uniforms_state =
+            &node0->big_state->uniforms_state;
+          _cogl_bitmask_set_flags (&uniforms_state->override_mask,
+                                   data->uniform_differences);
+        }
+    }
+  for (head1 = common_ancestor1->next; head1; head1 = head1->next)
+    {
+      node1 = head1->data;
+      if ((node1->differences & COGL_PIPELINE_STATE_UNIFORMS))
+        {
+          const CoglPipelineUniformsState *uniforms_state =
+            &node1->big_state->uniforms_state;
+          _cogl_bitmask_set_flags (&uniforms_state->override_mask,
+                                   data->uniform_differences);
+        }
+    }
+}
+
 static gboolean
 flush_uniform_cb (int uniform_num, void *user_data)
 {
   FlushUniformsClosure *data = user_data;
 
-  if (!COGL_FLAGS_GET (data->flushed_uniforms, uniform_num) &&
-      (!data->found_ancestor ||
-       COGL_FLAGS_GET (data->force_flush_uniforms, uniform_num)))
+  if (COGL_FLAGS_GET (data->uniform_differences, uniform_num))
     {
       GArray *uniform_locations;
       GLint uniform_location;
@@ -682,12 +737,13 @@ flush_uniform_cb (int uniform_num, void *user_data)
                                    uniform_location,
                                    &data->override->value);
 
-      COGL_FLAGS_SET (data->flushed_uniforms, uniform_num, TRUE);
+      data->n_differences--;
+      COGL_FLAGS_SET (data->uniform_differences, uniform_num, FALSE);
     }
 
   data->override = COGL_SLIST_NEXT (data->override, list_node);
 
-  return TRUE;
+  return data->n_differences > 0;
 }
 
 static void
@@ -702,83 +758,65 @@ _cogl_pipeline_progend_glsl_flush_uniforms (CoglPipeline *pipeline,
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  _cogl_bitmask_init (&data.force_flush_uniforms);
-
   if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS)
     data.uniforms_state = &pipeline->big_state->uniforms_state;
   else
     data.uniforms_state = NULL;
 
-  data.flushed_ancestor = NULL;
   data.program_state = program_state;
   data.ctx = ctx;
 
   n_uniform_longs = COGL_FLAGS_N_LONGS_FOR_SIZE (ctx->n_uniform_names);
 
-  data.force_flush_uniforms = g_newa (unsigned long, n_uniform_longs);
-  memset (data.force_flush_uniforms, 0,
-          n_uniform_longs * sizeof (unsigned long));
-  data.flushed_uniforms = g_newa (unsigned long, n_uniform_longs);
-  memset (data.flushed_uniforms, 0,
-          n_uniform_longs * sizeof (unsigned long));
+  data.uniform_differences = g_newa (unsigned long, n_uniform_longs);
 
   /* Try to find a common ancestor for the values that were already
      flushed on the pipeline that this program state was last used for
      so we can avoid flushing those */
 
-  if (program_changed)
+  if (program_changed || program_state->last_used_for_pipeline == NULL)
     {
-      /* The program has changed so we have no common ancestor and we
-         need to flush everything. All of the uniform locations are
-         invalid */
-      if (program_state->uniform_locations)
-        g_array_set_size (program_state->uniform_locations, 0);
+      if (program_changed)
+        {
+          /* The program has changed so all of the uniform locations
+             are invalid */
+          if (program_state->uniform_locations)
+            g_array_set_size (program_state->uniform_locations, 0);
+        }
+
+      /* We need to flush everything so mark all of the uniforms as
+         dirty */
+      memset (data.uniform_differences, 0xff,
+              n_uniform_longs * sizeof (unsigned long));
+      data.n_differences = G_MAXINT;
     }
-  else
+  else if (program_state->last_used_for_pipeline)
     {
-      GSList *flushed_ancestors =
-        get_ancestors (program_state->last_used_for_pipeline);
-      GSList *new_ancestors =
-        get_ancestors (pipeline);
-      GSList *a, *b;
-
-      for (a = flushed_ancestors, b = new_ancestors;
-           a && b && a->data == b->data;
-           a = a->next, b = b->next)
-        data.flushed_ancestor = a->data;
+      int i;
 
-      g_slist_free (flushed_ancestors);
-      g_slist_free (new_ancestors);
+      memset (data.uniform_differences, 0,
+              n_uniform_longs * sizeof (unsigned long));
+      compare_uniform_differences (&data,
+                                   program_state->last_used_for_pipeline,
+                                   pipeline);
 
       /* We need to be sure to flush any uniforms that have changed
          since the last flush */
       if (data.uniforms_state)
         _cogl_bitmask_set_flags (&data.uniforms_state->changed_mask,
-                                 data.force_flush_uniforms);
+                                 data.uniform_differences);
 
-      /* We need to flush any uniforms that are children of the common
-         ancestor up to the last used pipeline */
-      while (a)
-        {
-          CoglPipeline *child_pipeline = a->data;
-          if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS)
-            {
-              const CoglPipelineUniformsState *uniforms_state =
-                &child_pipeline->big_state->uniforms_state;
-              _cogl_bitmask_set_flags (&uniforms_state->override_mask,
-                                       data.force_flush_uniforms);
-            }
-          a = a->next;
-        }
-    }
+      /* Count the number of differences. This is so we can stop early
+         when we've flushed all of them */
+      data.n_differences = 0;
 
-  data.found_ancestor = FALSE;
+      for (i = 0; i < n_uniform_longs; i++)
+        data.n_differences +=
+          _cogl_util_popcountl (data.uniform_differences[i]);
+    }
 
-  while (pipeline)
+  while (pipeline && data.n_differences > 0)
     {
-      if (pipeline == data.flushed_ancestor)
-        data.found_ancestor = TRUE;
-
       if (pipeline->differences & COGL_PIPELINE_STATE_UNIFORMS)
         {
           const CoglPipelineUniformsState *uniforms_state =
@@ -1029,12 +1067,6 @@ _cogl_pipeline_progend_glsl_pre_change_notify (CoglPipeline *pipeline,
 
   if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
     dirty_program_state (pipeline);
-  else if ((change & COGL_PIPELINE_STATE_UNIFORMS))
-    {
-      CoglPipelineProgramState *program_state = get_program_state (pipeline);
-      if (program_state)
-        program_state->uniforms_changed = TRUE;
-    }
 #ifdef HAVE_COGL_GLES2
   else if (ctx->driver == COGL_DRIVER_GLES2)
     {
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c
index 3d2bf3e..1e10a71 100644
--- a/cogl/cogl-pipeline.c
+++ b/cogl/cogl-pipeline.c
@@ -2231,6 +2231,12 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0,
                               _cogl_pipeline_user_shader_equal))
     goto done;
 
+  if (!simple_property_equal (authorities0, authorities1,
+                              pipelines_difference,
+                              COGL_PIPELINE_STATE_UNIFORMS_INDEX,
+                              _cogl_pipeline_uniforms_state_equal))
+    goto done;
+
   if (pipelines_difference & COGL_PIPELINE_STATE_LAYERS)
     {
       CoglPipelineStateIndex state_index = COGL_PIPELINE_STATE_LAYERS_INDEX;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]