cogl-pipeline: Make find codegen authority more general
authorNeil Roberts <neil@linux.intel.com>
Wed, 1 Dec 2010 17:06:18 +0000 (17:06 +0000)
committerNeil Roberts <neil@linux.intel.com>
Mon, 13 Dec 2010 17:22:57 +0000 (17:22 +0000)
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.

clutter/cogl/cogl/cogl-pipeline-fragend-arbfp.c
clutter/cogl/cogl/cogl-pipeline-fragend-glsl.c
clutter/cogl/cogl/cogl-pipeline-private.h
clutter/cogl/cogl/cogl-pipeline.c

index b5c8b52..61767a8 100644 (file)
 #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;
index 69a7df3..dd50ddf 100644 (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)
         {
index 9f05e4d..13354c5 100644 (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);
 
index 2d98796..d829e82 100644 (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;
     }