[cogl/wip/cogl-1.14: 46/50] Clearly define 3 progends that own the frag+vertends



commit 8023f6f3a2533d566db09173c0613f44a8ebcb43
Author: Robert Bragg <robert linux intel com>
Date:   Tue Sep 25 21:08:10 2012 +0100

    Clearly define 3 progends that own the frag+vertends
    
    This adds a new "fixed-arbfp" progend so we now have 3 distinct ways of
    setting up the state of a pipeline:
    
      Â fixed; where the vertex and fragment processing are implemented
        using fixed function opengl apis.
      Â fixed-arbfp; where vertex processing is implemented using fixed
        function opengl apis but fragment processing is implemented
        using the ARB Fragment Processing language.
      Â glsl; there vertex and fragment processing are both implemented
        using glsl.
    
    This means we avoid unusual, combinations such as glsl for vertex
    processing and arbfp for fragment processing, and also avoid pairing
    fixed-function vertex processing with glsl fragment processing which we
    happen to know hits some awkward code paths in Mesa that lead to poor
    performance.
    
    As part of this change, the progend now implies specific vertend and
    fragend choices so instead of associating a vertend and fragend with a
    pipeline we now just associate a progend choice.
    
    When flushing a pipeline and choosing what progend to use, we now call a
    progend->start() method that is able to determine if the vertend and
    fragend together will be able to handle the given pipeline so the
    vertend and fragend ->start() methods no longer need to return a boolean
    status.
    
    Since we now don't need to support glsl used in conjunction with fixed
    function this will allow us to avoid ever using OpenGL builtin attribute
    names, though this patch doesn't change that yet.
    
    Reviewed-by: Neil Roberts <neil linux intel com>
    
    (cherry picked from commit cec381f50c7a2f2186bd4a8c5f38fecd5f099075)

 cogl/Makefile.am                                   |    2 +
 cogl/cogl-pipeline-private.h                       |   49 +++---
 cogl/cogl-pipeline-state.c                         |    5 +-
 cogl/cogl-pipeline.c                               |  124 ++++++-------
 cogl/driver/gl/cogl-pipeline-fragend-fixed.c       |   26 +---
 cogl/driver/gl/cogl-pipeline-fragend-glsl.c        |   24 +--
 cogl/driver/gl/cogl-pipeline-opengl.c              |  195 ++++++++------------
 cogl/driver/gl/cogl-pipeline-progend-fixed.c       |   34 +++-
 cogl/driver/gl/cogl-pipeline-progend-glsl.c        |   42 +++--
 cogl/driver/gl/cogl-pipeline-vertend-fixed.c       |   27 +---
 cogl/driver/gl/cogl-pipeline-vertend-glsl.c        |   24 +--
 cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c    |   41 +----
 .../gl/cogl-pipeline-progend-fixed-arbfp-private.h |   36 ++++
 .../gl/gl/cogl-pipeline-progend-fixed-arbfp.c      |  110 +++++++++++
 14 files changed, 386 insertions(+), 353 deletions(-)
---
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 7aef9b4..abf7fc2 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -175,6 +175,8 @@ cogl_driver_sources += \
 	$(srcdir)/driver/gl/cogl-pipeline-fragend-glsl-private.h \
 	$(srcdir)/driver/gl/gl/cogl-pipeline-fragend-arbfp.c \
 	$(srcdir)/driver/gl/gl/cogl-pipeline-fragend-arbfp-private.h \
+	$(srcdir)/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c \
+	$(srcdir)/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h \
 	$(srcdir)/driver/gl/cogl-pipeline-fragend-fixed.c \
 	$(srcdir)/driver/gl/cogl-pipeline-fragend-fixed-private.h \
 	$(srcdir)/driver/gl/cogl-pipeline-vertend-glsl.c \
diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h
index 31a84c0..64c853b 100644
--- a/cogl/cogl-pipeline-private.h
+++ b/cogl/cogl-pipeline-private.h
@@ -45,9 +45,10 @@
 
 #ifdef HAVE_COGL_GL
 
-#define COGL_PIPELINE_PROGEND_FIXED       0
-#define COGL_PIPELINE_PROGEND_GLSL        1
-#define COGL_PIPELINE_N_PROGENDS          2
+#define COGL_PIPELINE_PROGEND_FIXED_ARBFP 0
+#define COGL_PIPELINE_PROGEND_FIXED       1
+#define COGL_PIPELINE_PROGEND_GLSL        2
+#define COGL_PIPELINE_N_PROGENDS          3
 
 #define COGL_PIPELINE_VERTEND_FIXED 0
 #define COGL_PIPELINE_VERTEND_GLSL  1
@@ -97,11 +98,8 @@
 
 #endif /* HAVE_COGL_GL */
 
-#define COGL_PIPELINE_FRAGEND_DEFAULT    0
-#define COGL_PIPELINE_FRAGEND_UNDEFINED  3
-
-#define COGL_PIPELINE_VERTEND_DEFAULT    0
-#define COGL_PIPELINE_VERTEND_UNDEFINED  3
+#define COGL_PIPELINE_PROGEND_DEFAULT    0
+#define COGL_PIPELINE_PROGEND_UNDEFINED  3
 
 /* XXX: should I rename these as
  * COGL_PIPELINE_STATE_INDEX_XYZ... ?
@@ -480,20 +478,19 @@ struct _CoglPipeline
    * where the pipeline originates from */
   unsigned int          has_static_breadcrumb:1;
 
-  /* There are multiple fragment processing backends for CoglPipeline,
-   * glsl, arbfp and fixed. This identifies the backend being used for
-   * the pipeline and any private state the backend has associated
-   * with the pipeline. */
-  unsigned int          fragend:3;
-  unsigned int          vertend:3;
+  /* There are multiple fragment and vertex processing backends for
+   * CoglPipeline, glsl, arbfp and fixed that are bundled under a
+   * "progend". This identifies the backend being used for the
+   * pipeline. */
+  unsigned int          progend:3;
 };
 
 typedef struct _CoglPipelineFragend
 {
-  CoglBool (*start) (CoglPipeline *pipeline,
-                     int n_layers,
-                     unsigned long pipelines_difference,
-                     int n_tex_coord_attribs);
+  void (*start) (CoglPipeline *pipeline,
+                 int n_layers,
+                 unsigned long pipelines_difference,
+                 int n_tex_coord_attribs);
   CoglBool (*add_layer) (CoglPipeline *pipeline,
                          CoglPipelineLayer *layer,
                          unsigned long layers_difference);
@@ -512,10 +509,10 @@ typedef struct _CoglPipelineFragend
 
 typedef struct _CoglPipelineVertend
 {
-  CoglBool (*start) (CoglPipeline *pipeline,
-                     int n_layers,
-                     unsigned long pipelines_difference,
-                     int n_tex_coord_attribs);
+  void (*start) (CoglPipeline *pipeline,
+                 int n_layers,
+                 unsigned long pipelines_difference,
+                 int n_tex_coord_attribs);
   CoglBool (*add_layer) (CoglPipeline *pipeline,
                          CoglPipelineLayer *layer,
                          unsigned long layers_difference,
@@ -533,6 +530,9 @@ typedef struct _CoglPipelineVertend
 
 typedef struct
 {
+  int vertend;
+  int fragend;
+  CoglBool (*start) (CoglPipeline *pipeline);
   void (*end) (CoglPipeline *pipeline,
                unsigned long pipelines_difference,
                int n_tex_coord_attribs);
@@ -818,10 +818,7 @@ _cogl_pipeline_weak_copy (CoglPipeline *pipeline,
                           void *user_data);
 
 void
-_cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend);
-
-void
-_cogl_pipeline_set_vertend (CoglPipeline *pipeline, int vertend);
+_cogl_pipeline_set_progend (CoglPipeline *pipeline, int progend);
 
 CoglPipeline *
 _cogl_pipeline_get_parent (CoglPipeline *pipeline);
diff --git a/cogl/cogl-pipeline-state.c b/cogl/cogl-pipeline-state.c
index 96a72e2..c7f3bde 100644
--- a/cogl/cogl-pipeline-state.c
+++ b/cogl/cogl-pipeline-state.c
@@ -1111,10 +1111,7 @@ cogl_pipeline_set_user_program (CoglPipeline *pipeline,
   _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
 
   if (program != COGL_INVALID_HANDLE)
-    {
-      _cogl_pipeline_set_fragend (pipeline, COGL_PIPELINE_FRAGEND_DEFAULT);
-      _cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_DEFAULT);
-    }
+    _cogl_pipeline_set_progend (pipeline, COGL_PIPELINE_PROGEND_UNDEFINED);
 
   /* If we are the current authority see if we can revert to one of our
    * ancestors being the authority */
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c
index 1a8036f..8a7d841 100644
--- a/cogl/cogl-pipeline.c
+++ b/cogl/cogl-pipeline.c
@@ -79,6 +79,9 @@ _cogl_pipeline_progends[MAX (COGL_PIPELINE_N_PROGENDS, 1)];
 #include "cogl-pipeline-vertend-fixed-private.h"
 #endif
 
+#ifdef COGL_PIPELINE_PROGEND_FIXED_ARBFP
+#include "cogl-pipeline-progend-fixed-arbfp-private.h"
+#endif
 #ifdef COGL_PIPELINE_PROGEND_FIXED
 #include "cogl-pipeline-progend-fixed-private.h"
 #endif
@@ -126,6 +129,10 @@ _cogl_pipeline_init_default_pipeline (void)
     &_cogl_pipeline_fixed_fragend;
 #endif
 #ifdef COGL_PIPELINE_PROGEND_FIXED
+  _cogl_pipeline_progends[COGL_PIPELINE_PROGEND_FIXED_ARBFP] =
+    &_cogl_pipeline_fixed_arbfp_progend;
+#endif
+#ifdef COGL_PIPELINE_PROGEND_FIXED
   _cogl_pipeline_progends[COGL_PIPELINE_PROGEND_FIXED] =
     &_cogl_pipeline_fixed_progend;
 #endif
@@ -147,8 +154,7 @@ _cogl_pipeline_init_default_pipeline (void)
 
   pipeline->is_weak = FALSE;
   pipeline->journal_ref_count = 0;
-  pipeline->fragend = COGL_PIPELINE_FRAGEND_UNDEFINED;
-  pipeline->vertend = COGL_PIPELINE_VERTEND_UNDEFINED;
+  pipeline->progend = COGL_PIPELINE_PROGEND_UNDEFINED;
   pipeline->differences = COGL_PIPELINE_STATE_ALL_SPARSE;
 
   pipeline->real_blend_enable = FALSE;
@@ -284,12 +290,17 @@ _cogl_pipeline_set_parent (CoglPipeline *pipeline,
    * that depends on the pipeline's ancestry then it may be notified
    * here...
    */
-  if (pipeline->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
-      _cogl_pipeline_fragends[pipeline->fragend]->pipeline_set_parent_notify)
+  if (pipeline->progend != COGL_PIPELINE_PROGEND_UNDEFINED)
     {
+      const CoglPipelineProgend *progend =
+        _cogl_pipeline_progends[pipeline->progend];
       const CoglPipelineFragend *fragend =
-        _cogl_pipeline_fragends[pipeline->fragend];
-      fragend->pipeline_set_parent_notify (pipeline);
+        _cogl_pipeline_fragends[progend->fragend];
+
+      /* Currently only the fragends ever care about reparenting of
+       * pipelines... */
+      if (fragend->pipeline_set_parent_notify)
+        fragend->pipeline_set_parent_notify (pipeline);
     }
 }
 
@@ -368,9 +379,7 @@ _cogl_pipeline_copy (CoglPipeline *src, CoglBool is_weak)
   pipeline->deprecated_get_layers_list = NULL;
   pipeline->deprecated_get_layers_list_dirty = TRUE;
 
-  pipeline->fragend = src->fragend;
-
-  pipeline->vertend = src->vertend;
+  pipeline->progend = src->progend;
 
   pipeline->has_static_breadcrumb = FALSE;
 
@@ -831,15 +840,9 @@ _cogl_pipeline_needs_blending_enabled (CoglPipeline    *pipeline,
 }
 
 void
-_cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend)
+_cogl_pipeline_set_progend (CoglPipeline *pipeline, int progend)
 {
-  pipeline->fragend = fragend;
-}
-
-void
-_cogl_pipeline_set_vertend (CoglPipeline *pipeline, int vertend)
-{
-  pipeline->vertend = vertend;
+  pipeline->progend = progend;
 }
 
 static void
@@ -1191,46 +1194,37 @@ _cogl_pipeline_pre_change_notify (CoglPipeline     *pipeline,
    *
    * 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.
+   * 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.
    *
    * 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 (!from_layer_change)
+  if (!from_layer_change &&
+      pipeline->progend != COGL_PIPELINE_PROGEND_UNDEFINED)
     {
-      int i;
+      const CoglPipelineProgend *progend =
+        _cogl_pipeline_progends[pipeline->progend];
+      const CoglPipelineVertend *vertend =
+        _cogl_pipeline_vertends[progend->vertend];
+      const CoglPipelineFragend *fragend =
+        _cogl_pipeline_fragends[progend->fragend];
 
-      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 (vertend->pipeline_pre_change_notify)
+        vertend->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];
-          vertend->pipeline_pre_change_notify (pipeline, change, new_color);
-        }
+      if (fragend->pipeline_pre_change_notify)
+        fragend->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);
+      if (progend->pipeline_pre_change_notify)
+        progend->pipeline_pre_change_notify (pipeline, change, new_color);
     }
 
   /* There may be an arbitrary tree of descendants of this pipeline;
@@ -1546,12 +1540,15 @@ _cogl_pipeline_fragend_layer_change_notify (CoglPipeline *owner,
    * have a single owner and can only be associated with a single
    * backend that needs to be notified of the layer change...
    */
-  if (owner->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
-      _cogl_pipeline_fragends[owner->fragend]->layer_pre_change_notify)
+  if (owner->progend != COGL_PIPELINE_PROGEND_UNDEFINED)
     {
+      const CoglPipelineProgend *progend =
+        _cogl_pipeline_progends[owner->progend];
       const CoglPipelineFragend *fragend =
-        _cogl_pipeline_fragends[owner->fragend];
-      fragend->layer_pre_change_notify (owner, layer, change);
+        _cogl_pipeline_fragends[progend->fragend];
+
+      if (fragend->layer_pre_change_notify)
+        fragend->layer_pre_change_notify (owner, layer, change);
     }
 }
 
@@ -1561,12 +1558,15 @@ _cogl_pipeline_vertend_layer_change_notify (CoglPipeline *owner,
                                             CoglPipelineLayerState change)
 {
   /* NB: The comment in fragend_layer_change_notify applies here too */
-  if (owner->vertend != COGL_PIPELINE_VERTEND_UNDEFINED &&
-      _cogl_pipeline_vertends[owner->vertend]->layer_pre_change_notify)
+  if (owner->progend != COGL_PIPELINE_PROGEND_UNDEFINED)
     {
+      const CoglPipelineProgend *progend =
+        _cogl_pipeline_progends[owner->progend];
       const CoglPipelineVertend *vertend =
-        _cogl_pipeline_vertends[owner->vertend];
-      vertend->layer_pre_change_notify (owner, layer, change);
+        _cogl_pipeline_vertends[progend->vertend];
+
+      if (vertend->layer_pre_change_notify)
+        vertend->layer_pre_change_notify (owner, layer, change);
     }
 }
 
@@ -1575,15 +1575,11 @@ _cogl_pipeline_progend_layer_change_notify (CoglPipeline *owner,
                                             CoglPipelineLayer *layer,
                                             CoglPipelineLayerState change)
 {
-  int i;
+  const CoglPipelineProgend *progend =
+    _cogl_pipeline_progends[owner->progend];
 
-  /* Give all of the progends a chance to notice that the layer has
-     changed */
-  for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
-    if (_cogl_pipeline_progends[i]->layer_pre_change_notify)
-      _cogl_pipeline_progends[i]->layer_pre_change_notify (owner,
-                                                           layer,
-                                                           change);
+  if (progend->layer_pre_change_notify)
+    progend->layer_pre_change_notify (owner, layer, change);
 }
 
 typedef struct
diff --git a/cogl/driver/gl/cogl-pipeline-fragend-fixed.c b/cogl/driver/gl/cogl-pipeline-fragend-fixed.c
index bc2a4b4..253c1ff 100644
--- a/cogl/driver/gl/cogl-pipeline-fragend-fixed.c
+++ b/cogl/driver/gl/cogl-pipeline-fragend-fixed.c
@@ -89,37 +89,13 @@ get_max_texture_units (void)
   return ctx->max_texture_units;
 }
 
-static CoglBool
+static void
 _cogl_pipeline_fragend_fixed_start (CoglPipeline *pipeline,
                                     int n_layers,
                                     unsigned long pipelines_difference,
                                     int n_tex_coord_attribs)
 {
-  CoglHandle user_program;
-
-  _COGL_GET_CONTEXT (ctx, FALSE);
-
-  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
-    return FALSE;
-
-  if (ctx->driver == COGL_DRIVER_GLES2)
-    return FALSE;
-
-  /* Fragment snippets are only supported in the GLSL fragend */
-  if (_cogl_pipeline_has_fragment_snippets (pipeline))
-    return FALSE;
-
-  /* If there is a user program with a fragment shader then the
-     appropriate backend for that language should handle it. We can
-     still use the fixed fragment backend if the program only contains
-     a vertex shader */
-  user_program = cogl_pipeline_get_user_program (pipeline);
-  if (user_program != COGL_INVALID_HANDLE &&
-      _cogl_program_has_fragment_shader (user_program))
-    return FALSE;
-
   _cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED);
-  return TRUE;
 }
 
 static void
diff --git a/cogl/driver/gl/cogl-pipeline-fragend-glsl.c b/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
index 6093673..e66bf47 100644
--- a/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
+++ b/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
@@ -213,7 +213,7 @@ has_replace_hook (CoglPipelineLayer *layer,
   return FALSE;
 }
 
-static CoglBool
+static void
 _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
                                    int n_layers,
                                    unsigned long pipelines_difference,
@@ -222,22 +222,10 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
   CoglPipelineShaderState *shader_state;
   CoglPipeline *authority;
   CoglPipeline *template_pipeline = NULL;
-  CoglProgram *user_program;
+  CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline);
   int i;
 
-  _COGL_GET_CONTEXT (ctx, FALSE);
-
-  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
-    return FALSE;
-
-  user_program = cogl_pipeline_get_user_program (pipeline);
-
-  /* If the user fragment shader isn't GLSL then we should let
-     another backend handle it */
-  if (user_program &&
-      _cogl_program_has_fragment_shader (user_program) &&
-      _cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
-    return FALSE;
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   /* Now lookup our glsl backend private state */
   shader_state = get_shader_state (pipeline);
@@ -313,7 +301,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
            shader_state->user_program_age == user_program->age)
           && (ctx->driver != COGL_DRIVER_GLES2 ||
               shader_state->n_tex_coord_attribs == n_tex_coord_attribs))
-        return TRUE;
+        return;
 
       /* We need to recreate the shader so destroy the existing one */
       GE( ctx, glDeleteShader (shader_state->gl_shader) );
@@ -333,7 +321,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
      to generate one */
   if (user_program &&
       _cogl_program_has_fragment_shader (user_program))
-    return TRUE;
+    return;
 
   /* We reuse two grow-only GStrings for code-gen. One string
      contains the uniform and attribute declarations while the
@@ -356,8 +344,6 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
       shader_state->unit_state[i].sampled = FALSE;
       shader_state->unit_state[i].combine_constant_used = FALSE;
     }
-
-  return TRUE;
 }
 
 static void
diff --git a/cogl/driver/gl/cogl-pipeline-opengl.c b/cogl/driver/gl/cogl-pipeline-opengl.c
index 4ccfdcd..7d0b162 100644
--- a/cogl/driver/gl/cogl-pipeline-opengl.c
+++ b/cogl/driver/gl/cogl-pipeline-opengl.c
@@ -1035,28 +1035,30 @@ compare_layer_differences_cb (CoglPipelineLayer *layer, void *user_data)
 
 typedef struct
 {
+  CoglFramebuffer *framebuffer;
+  const CoglPipelineVertend *vertend;
   const CoglPipelineFragend *fragend;
   CoglPipeline *pipeline;
   unsigned long *layer_differences;
   CoglBool error_adding_layer;
   CoglBool added_layer;
-} CoglPipelineFragendAddLayerState;
-
+} CoglPipelineAddLayerState;
 
 static CoglBool
-fragend_add_layer_cb (CoglPipelineLayer *layer,
+vertend_add_layer_cb (CoglPipelineLayer *layer,
                       void *user_data)
 {
-  CoglPipelineFragendAddLayerState *state = user_data;
-  const CoglPipelineFragend *fragend = state->fragend;
+  CoglPipelineAddLayerState *state = user_data;
+  const CoglPipelineVertend *vertend = state->vertend;
   CoglPipeline *pipeline = state->pipeline;
   int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
 
   /* Either generate per layer code snippets or setup the
    * fixed function glTexEnv for each layer... */
-  if (G_LIKELY (fragend->add_layer (pipeline,
+  if (G_LIKELY (vertend->add_layer (pipeline,
                                     layer,
-                                    state->layer_differences[unit_index])))
+                                    state->layer_differences[unit_index],
+                                    state->framebuffer)))
     state->added_layer = TRUE;
   else
     {
@@ -1067,32 +1069,20 @@ fragend_add_layer_cb (CoglPipelineLayer *layer,
   return TRUE;
 }
 
-typedef struct
-{
-  CoglFramebuffer *framebuffer;
-  const CoglPipelineVertend *vertend;
-  CoglPipeline *pipeline;
-  unsigned long *layer_differences;
-  CoglBool error_adding_layer;
-  CoglBool added_layer;
-} CoglPipelineVertendAddLayerState;
-
-
 static CoglBool
-vertend_add_layer_cb (CoglPipelineLayer *layer,
+fragend_add_layer_cb (CoglPipelineLayer *layer,
                       void *user_data)
 {
-  CoglPipelineVertendAddLayerState *state = user_data;
-  const CoglPipelineVertend *vertend = state->vertend;
+  CoglPipelineAddLayerState *state = user_data;
+  const CoglPipelineFragend *fragend = state->fragend;
   CoglPipeline *pipeline = state->pipeline;
   int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
 
-  /* Either enerate per layer code snippets or setup the
-   * fixed function matrix uniforms for each layer... */
-  if (G_LIKELY (vertend->add_layer (pipeline,
+  /* Either generate per layer code snippets or setup the
+   * fixed function glTexEnv for each layer... */
+  if (G_LIKELY (fragend->add_layer (pipeline,
                                     layer,
-                                    state->layer_differences[unit_index],
-                                    state->framebuffer)))
+                                    state->layer_differences[unit_index])))
     state->added_layer = TRUE;
   else
     {
@@ -1159,11 +1149,12 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
                                CoglBool skip_gl_color,
                                int n_tex_coord_attribs)
 {
-  unsigned long    pipelines_difference;
-  int              n_layers;
-  unsigned long   *layer_differences;
-  int              i;
+  unsigned long pipelines_difference;
+  int n_layers;
+  unsigned long *layer_differences;
+  int i;
   CoglTextureUnit *unit1;
+  const CoglPipelineProgend *progend;
 
   COGL_STATIC_TIMER (pipeline_flush_timer,
                      "Mainloop", /* parent */
@@ -1242,120 +1233,95 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
                                         layer_differences,
                                         skip_gl_color);
 
-  /* Now flush the fragment processing state according to the current
-   * fragment processing backend.
+  /* Now flush the fragment, vertex and program state according to the
+   * current progend backend.
    *
-   * Note: Some of the backends may not support the current pipeline
-   * configuration and in that case it will report an error and we
-   * will fallback to a different backend.
+   * Note: Some backends may not support the current pipeline
+   * configuration and in that case it will report and error and we
+   * will look for a different backend.
    *
-   * NB: if pipeline->backend != COGL_PIPELINE_FRAGEND_UNDEFINED then
+   * NB: if pipeline->progend != COGL_PIPELINE_PROGEND_UNDEFINED then
    * we have previously managed to successfully flush this pipeline
-   * with the given backend so we will simply use that to avoid
+   * with the given progend so we will simply use that to avoid
    * fallback code paths.
    */
+  if (pipeline->progend == COGL_PIPELINE_PROGEND_UNDEFINED)
+    _cogl_pipeline_set_progend (pipeline, COGL_PIPELINE_PROGEND_DEFAULT);
 
-  if (pipeline->fragend == COGL_PIPELINE_FRAGEND_UNDEFINED)
-    _cogl_pipeline_set_fragend (pipeline, COGL_PIPELINE_FRAGEND_DEFAULT);
-
-  for (i = pipeline->fragend;
-       i < G_N_ELEMENTS (_cogl_pipeline_fragends);
-       i++, _cogl_pipeline_set_fragend (pipeline, i))
+  for (i = pipeline->progend;
+       i < COGL_PIPELINE_N_PROGENDS;
+       i++, _cogl_pipeline_set_progend (pipeline, i))
     {
-      const CoglPipelineFragend *fragend = _cogl_pipeline_fragends[i];
-      CoglPipelineFragendAddLayerState state;
-
-      /* E.g. For fragends generating code they can setup their
-       * scratch buffers here... */
-      if (G_UNLIKELY (!fragend->start (pipeline,
-                                       n_layers,
-                                       pipelines_difference,
-                                       n_tex_coord_attribs)))
+      const CoglPipelineVertend *vertend;
+      const CoglPipelineFragend *fragend;
+      CoglPipelineAddLayerState state;
+
+      progend = _cogl_pipeline_progends[i];
+
+      if (G_UNLIKELY (!progend->start (pipeline)))
         continue;
 
-      state.fragend = fragend;
+      vertend = _cogl_pipeline_vertends[progend->vertend];
+
+      vertend->start (pipeline,
+                      n_layers,
+                      pipelines_difference,
+                      n_tex_coord_attribs);
+
+      state.framebuffer = framebuffer;
+      state.vertend = vertend;
       state.pipeline = pipeline;
       state.layer_differences = layer_differences;
       state.error_adding_layer = FALSE;
       state.added_layer = FALSE;
+
       _cogl_pipeline_foreach_layer_internal (pipeline,
-                                             fragend_add_layer_cb,
+                                             vertend_add_layer_cb,
                                              &state);
 
       if (G_UNLIKELY (state.error_adding_layer))
         continue;
 
-      if (!state.added_layer &&
-          fragend->passthrough &&
-          G_UNLIKELY (!fragend->passthrough (pipeline)))
+      if (G_UNLIKELY (!vertend->end (pipeline, pipelines_difference)))
         continue;
 
-      /* For fragends generating code they may compile and link their
-       * programs here, update any uniforms and tell OpenGL to use
-       * that program.
+      /* Now prepare the fragment processing state (fragend)
+       *
+       * NB: We can't combine the setup of the vertend and fragend
+       * since the backends that do code generation share
+       * ctx->codegen_source_buffer as a scratch buffer.
        */
-      if (G_UNLIKELY (!fragend->end (pipeline, pipelines_difference)))
-        continue;
-
-      break;
-    }
 
-  if (G_UNLIKELY (i >= G_N_ELEMENTS (_cogl_pipeline_fragends)))
-    g_warning ("No usable pipeline fragment backend was found!");
-
-  /* Now flush the vertex processing state according to the current
-   * vertex processing backend.
-   */
-
-  if (pipeline->vertend == COGL_PIPELINE_VERTEND_UNDEFINED)
-    _cogl_pipeline_set_vertend (pipeline, COGL_PIPELINE_VERTEND_DEFAULT);
+      fragend = _cogl_pipeline_fragends[progend->fragend];
+      state.fragend = fragend;
 
-  for (i = pipeline->vertend;
-       i < G_N_ELEMENTS (_cogl_pipeline_vertends);
-       i++, _cogl_pipeline_set_vertend (pipeline, i))
-    {
-      const CoglPipelineVertend *vertend = _cogl_pipeline_vertends[i];
-      CoglPipelineVertendAddLayerState state;
-
-      /* E.g. For vertends generating code they can setup their
-       * scratch buffers here... */
-      if (G_UNLIKELY (!vertend->start (pipeline,
-                                       n_layers,
-                                       pipelines_difference,
-                                       n_tex_coord_attribs)))
-        continue;
+      fragend->start (pipeline,
+                      n_layers,
+                      pipelines_difference,
+                      n_tex_coord_attribs);
 
-      state.framebuffer = framebuffer;
-      state.vertend = vertend;
-      state.pipeline = pipeline;
-      state.layer_differences = layer_differences;
-      state.error_adding_layer = FALSE;
-      state.added_layer = FALSE;
       _cogl_pipeline_foreach_layer_internal (pipeline,
-                                             vertend_add_layer_cb,
+                                             fragend_add_layer_cb,
                                              &state);
 
       if (G_UNLIKELY (state.error_adding_layer))
         continue;
 
-      /* For vertends generating code they may compile and link their
-       * programs here, update any uniforms and tell OpenGL to use
-       * that program.
-       */
-      if (G_UNLIKELY (!vertend->end (pipeline, pipelines_difference)))
+      if (!state.added_layer)
+        {
+          if (fragend->passthrough &&
+              G_UNLIKELY (!fragend->passthrough (pipeline)))
+            continue;
+        }
+
+      if (G_UNLIKELY (!fragend->end (pipeline, pipelines_difference)))
         continue;
 
+      if (progend->end)
+        progend->end (pipeline, pipelines_difference, n_tex_coord_attribs);
       break;
     }
 
-  if (G_UNLIKELY (i >= G_N_ELEMENTS (_cogl_pipeline_vertends)))
-    g_warning ("No usable pipeline vertex backend was found!");
-
-  for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
-    if (_cogl_pipeline_progends[i]->end)
-      _cogl_pipeline_progends[i]->end (pipeline, pipelines_difference,
-                                       n_tex_coord_attribs);
-
   /* FIXME: This reference is actually resulting in lots of
    * copy-on-write reparenting because one-shot pipelines end up
    * living for longer than necessary and so any later modification of
@@ -1374,6 +1340,8 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
 
 done:
 
+  progend = _cogl_pipeline_progends[pipeline->progend];
+
   /* We can't assume the color will be retained between flushes on
      GLES2 because the generic attribute values are not stored as part
      of the program object so they could be overridden by any
@@ -1398,12 +1366,11 @@ done:
     }
 #endif
 
-  /* Give any progends a chance to update any uniforms that might not
-     depend on the material state. This is used on GLES2 to update the
-     matrices */
-  for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
-    if (_cogl_pipeline_progends[i]->pre_paint)
-      _cogl_pipeline_progends[i]->pre_paint (pipeline, framebuffer);
+  /* Give the progend a chance to update any uniforms that might not
+   * depend on the material state. This is used on GLES2 to update the
+   * matrices */
+  if (progend->pre_paint)
+    progend->pre_paint (pipeline, framebuffer);
 
   /* Handle the fact that OpenGL associates texture filter and wrap
    * modes with the texture objects not the texture units... */
diff --git a/cogl/driver/gl/cogl-pipeline-progend-fixed.c b/cogl/driver/gl/cogl-pipeline-progend-fixed.c
index c1051fa..b096bab 100644
--- a/cogl/driver/gl/cogl-pipeline-progend-fixed.c
+++ b/cogl/driver/gl/cogl-pipeline-progend-fixed.c
@@ -32,6 +32,7 @@
 #include <string.h>
 
 #include "cogl-pipeline-private.h"
+#include "cogl-pipeline-state-private.h"
 
 #ifdef COGL_PIPELINE_PROGEND_FIXED
 
@@ -39,15 +40,39 @@
 #include "cogl-context-private.h"
 #include "cogl-framebuffer-private.h"
 
+static CoglBool
+_cogl_pipeline_progend_fixed_start (CoglPipeline *pipeline)
+{
+  _COGL_GET_CONTEXT (ctx, FALSE);
+
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
+    return FALSE;
+
+  if (ctx->driver == COGL_DRIVER_GLES2)
+    return FALSE;
+
+  /* Vertex snippets are only supported in the GLSL fragend */
+  if (_cogl_pipeline_has_vertex_snippets (pipeline))
+    return FALSE;
+
+  /* Fragment snippets are only supported in the GLSL fragend */
+  if (_cogl_pipeline_has_fragment_snippets (pipeline))
+    return FALSE;
+
+  /* If there is a user program then the appropriate backend for that
+   * language should handle it. */
+  if (cogl_pipeline_get_user_program (pipeline))
+    return FALSE;
+
+  return TRUE;
+}
+
 static void
 _cogl_pipeline_progend_fixed_pre_paint (CoglPipeline *pipeline,
                                         CoglFramebuffer *framebuffer)
 {
   CoglContext *ctx = framebuffer->context;
 
-  if (pipeline->vertend != COGL_PIPELINE_VERTEND_FIXED)
-    return;
-
   if (ctx->current_projection_entry)
     _cogl_matrix_entry_flush_to_gl_builtins (ctx,
                                              ctx->current_projection_entry,
@@ -64,6 +89,9 @@ _cogl_pipeline_progend_fixed_pre_paint (CoglPipeline *pipeline,
 
 const CoglPipelineProgend _cogl_pipeline_fixed_progend =
   {
+    COGL_PIPELINE_VERTEND_FIXED,
+    COGL_PIPELINE_FRAGEND_FIXED,
+    _cogl_pipeline_progend_fixed_start,
     NULL, /* end */
     NULL, /* pre_change_notify */
     NULL, /* layer_pre_change_notify */
diff --git a/cogl/driver/gl/cogl-pipeline-progend-glsl.c b/cogl/driver/gl/cogl-pipeline-progend-glsl.c
index fdecb7b..989da41 100644
--- a/cogl/driver/gl/cogl-pipeline-progend-glsl.c
+++ b/cogl/driver/gl/cogl-pipeline-progend-glsl.c
@@ -645,6 +645,24 @@ _cogl_pipeline_progend_glsl_flush_uniforms (CoglPipeline *pipeline,
     _cogl_bitmask_clear_all (&uniforms_state->changed_mask);
 }
 
+static CoglBool
+_cogl_pipeline_progend_glsl_start (CoglPipeline *pipeline)
+{
+  CoglHandle user_program;
+
+  _COGL_GET_CONTEXT (ctx, FALSE);
+
+  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
+    return FALSE;
+
+  user_program = cogl_pipeline_get_user_program (pipeline);
+  if (user_program &&
+      _cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
+    return FALSE;
+
+  return TRUE;
+}
+
 static void
 _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
                                  unsigned long pipelines_difference,
@@ -659,12 +677,6 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  /* If neither of the glsl fragend or vertends are used then we don't
-     need to do anything */
-  if (pipeline->fragend != COGL_PIPELINE_FRAGEND_GLSL &&
-      pipeline->vertend != COGL_PIPELINE_VERTEND_GLSL)
-    return;
-
   program_state = get_program_state (pipeline);
 
   user_program = cogl_pipeline_get_user_program (pipeline);
@@ -763,11 +775,9 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
         }
 
       /* Attach any shaders from the GLSL backends */
-      if (pipeline->fragend == COGL_PIPELINE_FRAGEND_GLSL &&
-          (backend_shader = _cogl_pipeline_fragend_glsl_get_shader (pipeline)))
+      if ((backend_shader = _cogl_pipeline_fragend_glsl_get_shader (pipeline)))
         GE( ctx, glAttachShader (program_state->program, backend_shader) );
-      if (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL &&
-          (backend_shader = _cogl_pipeline_vertend_glsl_get_shader (pipeline)))
+      if ((backend_shader = _cogl_pipeline_vertend_glsl_get_shader (pipeline)))
         GE( ctx, glAttachShader (program_state->program, backend_shader) );
 
       link_program (program_state->program);
@@ -779,10 +789,8 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
 
   gl_program = program_state->program;
 
-  if (pipeline->fragend == COGL_PIPELINE_FRAGEND_GLSL)
-    _cogl_use_fragment_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
-  if (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL)
-    _cogl_use_vertex_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
+  _cogl_use_fragment_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
+  _cogl_use_vertex_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
 
   state.unit = 0;
   state.gl_program = gl_program;
@@ -939,9 +947,6 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline,
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  if (pipeline->vertend != COGL_PIPELINE_VERTEND_GLSL)
-    return;
-
   program_state = get_program_state (pipeline);
 
   projection_entry = ctx->current_projection_entry;
@@ -1099,6 +1104,9 @@ update_float_uniform (CoglPipeline *pipeline,
 
 const CoglPipelineProgend _cogl_pipeline_glsl_progend =
   {
+    COGL_PIPELINE_VERTEND_GLSL,
+    COGL_PIPELINE_FRAGEND_GLSL,
+    _cogl_pipeline_progend_glsl_start,
     _cogl_pipeline_progend_glsl_end,
     _cogl_pipeline_progend_glsl_pre_change_notify,
     _cogl_pipeline_progend_glsl_layer_pre_change_notify,
diff --git a/cogl/driver/gl/cogl-pipeline-vertend-fixed.c b/cogl/driver/gl/cogl-pipeline-vertend-fixed.c
index 219090e..adb2ab0 100644
--- a/cogl/driver/gl/cogl-pipeline-vertend-fixed.c
+++ b/cogl/driver/gl/cogl-pipeline-vertend-fixed.c
@@ -44,38 +44,13 @@
 
 const CoglPipelineVertend _cogl_pipeline_fixed_vertend;
 
-static CoglBool
+static void
 _cogl_pipeline_vertend_fixed_start (CoglPipeline *pipeline,
                                     int n_layers,
                                     unsigned long pipelines_difference,
                                     int n_tex_coord_attribs)
 {
-  CoglProgram *user_program;
-
-  _COGL_GET_CONTEXT (ctx, FALSE);
-
-  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
-    return FALSE;
-
-  if (ctx->driver == COGL_DRIVER_GLES2)
-    return FALSE;
-
-  /* Vertex snippets are only supported in the GLSL fragend */
-  if (_cogl_pipeline_has_vertex_snippets (pipeline))
-    return FALSE;
-
-  /* If there is a user program with a vertex shader then the
-     appropriate backend for that language should handle it. We can
-     still use the fixed vertex backend if the program only contains
-     a fragment shader */
-  user_program = cogl_pipeline_get_user_program (pipeline);
-  if (user_program != COGL_INVALID_HANDLE &&
-      _cogl_program_has_vertex_shader (user_program))
-    return FALSE;
-
   _cogl_use_vertex_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED);
-
-  return TRUE;
 }
 
 static CoglBool
diff --git a/cogl/driver/gl/cogl-pipeline-vertend-glsl.c b/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
index d8b7e6d..16f037c 100644
--- a/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
+++ b/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
@@ -149,7 +149,7 @@ get_layer_vertex_snippets (CoglPipelineLayer *layer)
   return &layer->big_state->vertex_snippets;
 }
 
-static CoglBool
+static void
 _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
                                    int n_layers,
                                    unsigned long pipelines_difference,
@@ -157,21 +157,9 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
 {
   CoglPipelineShaderState *shader_state;
   CoglPipeline *template_pipeline = NULL;
-  CoglProgram *user_program;
-
-  _COGL_GET_CONTEXT (ctx, FALSE);
-
-  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
-    return FALSE;
-
-  user_program = cogl_pipeline_get_user_program (pipeline);
+  CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline);
 
-  /* If the user program has a vertex shader that isn't GLSL then the
-     appropriate vertend for that language should handle it */
-  if (user_program &&
-      _cogl_program_has_vertex_shader (user_program) &&
-      _cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
-    return FALSE;
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   /* Now lookup our glsl backend private state (allocating if
    * necessary) */
@@ -238,7 +226,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
            shader_state->user_program_age == user_program->age)
           && (ctx->driver != COGL_DRIVER_GLES2 ||
               shader_state->n_tex_coord_attribs == n_tex_coord_attribs))
-        return TRUE;
+        return;
 
       /* We need to recreate the shader so destroy the existing one */
       GE( ctx, glDeleteShader (shader_state->gl_shader) );
@@ -258,7 +246,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
      to generate one */
   if (user_program &&
       _cogl_program_has_vertex_shader (user_program))
-    return TRUE;
+    return;
 
   /* We reuse two grow-only GStrings for code-gen. One string
      contains the uniform and attribute declarations while the
@@ -280,8 +268,6 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
        to copy it from the custom uniform in the vertex shader */
     g_string_append (shader_state->source,
                      "  cogl_point_size_out = cogl_point_size_in;\n");
-
-  return TRUE;
 }
 
 static CoglBool
diff --git a/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c b/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c
index 7b27a01..52f3dcc 100644
--- a/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c
+++ b/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c
@@ -155,7 +155,7 @@ dirty_shader_state (CoglPipeline *pipeline)
                              NULL);
 }
 
-static CoglBool
+static void
 _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
                                     int n_layers,
                                     unsigned long pipelines_difference,
@@ -164,38 +164,9 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
   CoglPipelineShaderState *shader_state;
   CoglPipeline *authority;
   CoglPipeline *template_pipeline = NULL;
-  CoglHandle user_program;
-
-  _COGL_GET_CONTEXT (ctx, FALSE);
-
-  /* First validate that we can handle the current state using ARBfp
-   */
-
-  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP))
-    return FALSE;
-
-  /* TODO: support fog */
-  if (_cogl_pipeline_get_fog_enabled (pipeline))
-    return FALSE;
+  CoglProgram *user_program = cogl_pipeline_get_user_program (pipeline);
 
-  /* Fragment snippets are only supported in the GLSL fragend */
-  if (_cogl_pipeline_has_fragment_snippets (pipeline))
-    return FALSE;
-
-  user_program = cogl_pipeline_get_user_program (pipeline);
-  if (user_program != COGL_INVALID_HANDLE)
-    {
-      /* If the program doesn't have a fragment shader then some other
-         vertend will handle the vertex shader state and we still need
-         to generate a fragment program */
-      if (!_cogl_program_has_fragment_shader (user_program))
-        user_program = COGL_INVALID_HANDLE;
-      /* If the user program does have a fragment shader then we can
-         only handle it if it's in ARBfp */
-      else if (_cogl_program_get_language (user_program) !=
-               COGL_SHADER_LANGUAGE_ARBFP)
-        return FALSE;
-    }
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   /* Now lookup our ARBfp backend private state */
   shader_state = get_shader_state (pipeline);
@@ -203,7 +174,7 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
   /* If we have a valid shader_state then we are all set and don't
    * need to generate a new program. */
   if (shader_state)
-    return TRUE;
+    return;
 
   /* If we don't have an associated arbfp program yet then find the
    * arbfp-authority (the oldest ancestor whose state will result in
@@ -226,7 +197,7 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
        * arbfp-authority... */
       shader_state->ref_count++;
       set_shader_state (pipeline, shader_state);
-      return TRUE;
+      return;
     }
 
   /* If we haven't yet found an existing program then before we resort to
@@ -285,8 +256,6 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
       shader_state->ref_count++;
       set_shader_state (template_pipeline, shader_state);
     }
-
-  return TRUE;
 }
 
 static const char *
diff --git a/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h b/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h
new file mode 100644
index 0000000..ff71801
--- /dev/null
+++ b/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h
@@ -0,0 +1,36 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Neil Roberts <neil linux intel com>
+ */
+
+#ifndef __COGL_PIPELINE_PROGEND_FIXED_ARBFP_PRIVATE_H
+#define __COGL_PIPELINE_PROGEND_FIXED_ARBFP_PRIVATE_H
+
+#include "cogl-pipeline-private.h"
+
+extern const CoglPipelineProgend _cogl_pipeline_fixed_arbfp_progend;
+
+#endif /* __COGL_PIPELINE_PROGEND_FIXED_ARBFP_PRIVATE_H */
+
diff --git a/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c b/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
new file mode 100644
index 0000000..b105fa2
--- /dev/null
+++ b/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
@@ -0,0 +1,110 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "cogl-pipeline-private.h"
+#include "cogl-pipeline-state-private.h"
+
+#ifdef COGL_PIPELINE_PROGEND_FIXED_ARBFP
+
+#include "cogl-context.h"
+#include "cogl-context-private.h"
+#include "cogl-framebuffer-private.h"
+#include "cogl-program-private.h"
+
+static CoglBool
+_cogl_pipeline_progend_fixed_arbfp_start (CoglPipeline *pipeline)
+{
+  CoglHandle user_program;
+
+  _COGL_GET_CONTEXT (ctx, FALSE);
+
+  if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_FIXED)))
+    return FALSE;
+
+  if (ctx->driver == COGL_DRIVER_GLES2)
+    return FALSE;
+
+  /* Vertex snippets are only supported in the GLSL fragend */
+  if (_cogl_pipeline_has_vertex_snippets (pipeline))
+    return FALSE;
+
+  /* Validate that we can handle the fragment state using ARBfp
+   */
+
+  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_ARBFP))
+    return FALSE;
+
+  /* Fragment snippets are only supported in the GLSL fragend */
+  if (_cogl_pipeline_has_fragment_snippets (pipeline))
+    return FALSE;
+
+  user_program = cogl_pipeline_get_user_program (pipeline);
+  if (user_program &&
+      _cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_ARBFP)
+    return FALSE;
+
+  return TRUE;
+}
+
+static void
+_cogl_pipeline_progend_fixed_arbfp_pre_paint (CoglPipeline *pipeline,
+                                              CoglFramebuffer *framebuffer)
+{
+  CoglContext *ctx = framebuffer->context;
+
+  if (ctx->current_projection_entry)
+    _cogl_matrix_entry_flush_to_gl_builtins (ctx,
+                                             ctx->current_projection_entry,
+                                             COGL_MATRIX_PROJECTION,
+                                             framebuffer,
+                                             FALSE /* enable flip */);
+  if (ctx->current_modelview_entry)
+    _cogl_matrix_entry_flush_to_gl_builtins (ctx,
+                                             ctx->current_modelview_entry,
+                                             COGL_MATRIX_MODELVIEW,
+                                             framebuffer,
+                                             FALSE /* enable flip */);
+}
+
+const CoglPipelineProgend _cogl_pipeline_fixed_arbfp_progend =
+  {
+    COGL_PIPELINE_VERTEND_FIXED,
+    COGL_PIPELINE_FRAGEND_ARBFP,
+    _cogl_pipeline_progend_fixed_arbfp_start,
+    NULL, /* end */
+    NULL, /* pre_change_notify */
+    NULL, /* layer_pre_change_notify */
+    _cogl_pipeline_progend_fixed_arbfp_pre_paint
+  };
+
+#endif /* COGL_PIPELINE_PROGEND_FIXED_ARBFP */



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