[Cogl] [PATCH] Clearly define 3 progends that own the frag+vertends

Robert Bragg robert at sixbynine.org
Wed Sep 26 05:56:50 PDT 2012


From: Robert Bragg <robert at linux.intel.com>

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.
---
 cogl/Makefile.am                                   |    2 +
 cogl/cogl-pipeline-private.h                       |   49 +++---
 cogl/cogl-pipeline.c                               |  128 +++++++-------
 cogl/driver/gl/cogl-pipeline-fragend-fixed.c       |   16 +--
 cogl/driver/gl/cogl-pipeline-fragend-glsl.c        |   11 +-
 cogl/driver/gl/cogl-pipeline-opengl.c              |  195 ++++++++------------
 cogl/driver/gl/cogl-pipeline-progend-fixed.c       |   29 +++-
 cogl/driver/gl/cogl-pipeline-progend-glsl.c        |   35 ++--
 cogl/driver/gl/cogl-pipeline-vertend-fixed.c       |   16 +--
 cogl/driver/gl/cogl-pipeline-vertend-glsl.c        |   11 +-
 cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c    |   20 +--
 .../gl/cogl-pipeline-progend-fixed-arbfp-private.h |   36 ++++
 .../gl/gl/cogl-pipeline-progend-fixed-arbfp.c      |  102 ++++++++++
 13 files changed, 369 insertions(+), 281 deletions(-)
 create mode 100644 cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp-private.h
 create mode 100644 cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c

diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 21ce227..4536a1c 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -156,6 +156,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 3fc4e51..9dfd0b1 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... ?
@@ -426,20 +424,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);
@@ -458,10 +455,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,
@@ -479,6 +476,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);
@@ -764,10 +764,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.c b/cogl/cogl-pipeline.c
index 4328a70..6fa9820 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
@@ -125,6 +128,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
@@ -146,8 +153,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;
@@ -258,12 +264,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);
     }
 }
 
@@ -340,9 +351,7 @@ _cogl_pipeline_copy (CoglPipeline *src, CoglBool is_weak)
 
   pipeline->layers_cache_dirty = TRUE;
 
-  pipeline->fragend = src->fragend;
-
-  pipeline->vertend = src->vertend;
+  pipeline->progend = src->progend;
 
   pipeline->has_static_breadcrumb = FALSE;
 
@@ -760,15 +769,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
@@ -1082,46 +1085,41 @@ _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);
+      /* XXX: we used to loop all progends here so check if we used to
+       * free resources in the progend->pipeline_pre_change_notify
+       * code. */
+#warning "FIXME"
+      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;
@@ -1437,12 +1435,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);
     }
 }
 
@@ -1452,12 +1453,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);
     }
 }
 
@@ -1466,15 +1470,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 a7c0ca7..40c028d 100644
--- a/cogl/driver/gl/cogl-pipeline-fragend-fixed.c
+++ b/cogl/driver/gl/cogl-pipeline-fragend-fixed.c
@@ -88,26 +88,14 @@ 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)
 {
-  _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;
-
   _cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED);
-  return TRUE;
+  return;
 }
 
 static void
diff --git a/cogl/driver/gl/cogl-pipeline-fragend-glsl.c b/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
index d4e5a29..c406149 100644
--- a/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
+++ b/cogl/driver/gl/cogl-pipeline-fragend-glsl.c
@@ -206,7 +206,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,
@@ -217,10 +217,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
   CoglPipeline *template_pipeline = NULL;
   int i;
 
-  _COGL_GET_CONTEXT (ctx, FALSE);
-
-  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
-    return FALSE;
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   /* Now lookup our glsl backend private state */
   shader_state = get_shader_state (pipeline);
@@ -292,7 +289,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
          shader with a different boiler plate */
       if ((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) );
@@ -327,7 +324,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
       shader_state->unit_state[i].combine_constant_used = FALSE;
     }
 
-  return TRUE;
+  return;
 }
 
 static void
diff --git a/cogl/driver/gl/cogl-pipeline-opengl.c b/cogl/driver/gl/cogl-pipeline-opengl.c
index 5d9ce3b..50a338d 100644
--- a/cogl/driver/gl/cogl-pipeline-opengl.c
+++ b/cogl/driver/gl/cogl-pipeline-opengl.c
@@ -1013,28 +1013,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
     {
@@ -1045,32 +1047,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
     {
@@ -1137,11 +1127,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 */
@@ -1220,120 +1211,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
@@ -1352,6 +1318,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
@@ -1376,12 +1344,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..ee0d699 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,34 @@
 #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;
+
+  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 +84,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 2a23857..a2aaffd 100644
--- a/cogl/driver/gl/cogl-pipeline-progend-glsl.c
+++ b/cogl/driver/gl/cogl-pipeline-progend-glsl.c
@@ -640,6 +640,17 @@ _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)
+{
+  _COGL_GET_CONTEXT (ctx, FALSE);
+
+  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
+    return FALSE;
+
+  return TRUE;
+}
+
 static void
 _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
                                  unsigned long pipelines_difference,
@@ -653,12 +664,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);
 
   if (program_state == NULL)
@@ -731,11 +736,9 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
       GE_RET( program_state->program, ctx, glCreateProgram () );
 
       /* 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);
@@ -747,10 +750,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;
@@ -902,9 +903,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;
@@ -1062,6 +1060,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 499f545..f26d322 100644
--- a/cogl/driver/gl/cogl-pipeline-vertend-fixed.c
+++ b/cogl/driver/gl/cogl-pipeline-vertend-fixed.c
@@ -43,27 +43,15 @@
 
 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)
 {
-  _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;
-
   _cogl_use_vertex_program (0, COGL_PIPELINE_PROGRAM_TYPE_FIXED);
 
-  return TRUE;
+  return;
 }
 
 static CoglBool
diff --git a/cogl/driver/gl/cogl-pipeline-vertend-glsl.c b/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
index ff6d942..e7a0fe1 100644
--- a/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
+++ b/cogl/driver/gl/cogl-pipeline-vertend-glsl.c
@@ -143,7 +143,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,
@@ -152,10 +152,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
   CoglPipelineShaderState *shader_state;
   CoglPipeline *template_pipeline = NULL;
 
-  _COGL_GET_CONTEXT (ctx, FALSE);
-
-  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_GLSL))
-    return FALSE;
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   /* Now lookup our glsl backend private state (allocating if
    * necessary) */
@@ -218,7 +215,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
          shader with a different boiler plate */
       if (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) );
@@ -251,7 +248,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
     g_string_append (shader_state->source,
                      "  cogl_point_size_out = cogl_point_size_in;\n");
 
-  return TRUE;
+  return;
 }
 
 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 04bfbc2..562e92d 100644
--- a/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c
+++ b/cogl/driver/gl/gl/cogl-pipeline-fragend-arbfp.c
@@ -149,7 +149,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,
@@ -159,17 +159,7 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
   CoglPipeline *authority;
   CoglPipeline *template_pipeline = NULL;
 
-  _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;
-
-  /* Fragment snippets are only supported in the GLSL fragend */
-  if (_cogl_pipeline_has_fragment_snippets (pipeline))
-    return FALSE;
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   /* Now lookup our ARBfp backend private state */
   shader_state = get_shader_state (pipeline);
@@ -177,7 +167,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
@@ -200,7 +190,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
@@ -256,7 +246,7 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
       set_shader_state (template_pipeline, shader_state);
     }
 
-  return TRUE;
+  return;
 }
 
 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 at 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..24782e7
--- /dev/null
+++ b/cogl/driver/gl/gl/cogl-pipeline-progend-fixed-arbfp.c
@@ -0,0 +1,102 @@
+/*
+ * 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 at 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"
+
+static CoglBool
+_cogl_pipeline_progend_fixed_arbfp_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;
+
+  /* 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;
+
+  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 */
-- 
1.7.7.6



More information about the Cogl mailing list