[cogl/wip/glsl-cache: 1/3] pipeline: Unify how the backends store private data



commit 0766b491d88043c3ade67d61272bad88fa335fdf
Author: Neil Roberts <neil linux intel com>
Date:   Thu Jun 30 13:39:48 2011 +0100

    pipeline: Unify how the backends store private data
    
    Previously the fragends had a separate private data pointer which was
    used by the GLSL and ARBfp fragends to store a tiny struct containing
    a single pointer to the ref-counted shader state. The space for the
    private data pointer is reserved in all of the pipelines for all of
    the potential backends. The vertends and progends however did this
    differently by directly storing the pointer to the ref counted data
    using cogl_object_set_user_data. This patch unifies the different
    methods so that they all use cogl_object_set_user_data and the
    fragends don't bother with the separate tiny allocation for the
    private data. The private data pointer array has been removed from
    CoglPipeline and the corresponding fragend virtual to free the private
    data has also been removed because this can instead be done with the
    destroy notify from the object user data.
    
    The variable names used have been unified so that all of the vertends
    and fragends name their data struct CoglPipelineShaderState and use a
    variable called shader_state to refer to it. The progend uses
    CoglPipelineProgramState and a variable called program_state.
    
    This should also fix two potential bugs. the ARBfp fragend was
    apprently leaking a reference to the private state when it creates the
    private data because it was adding a reference before stroring the
    pointer to the newly allocated data but the ref count is already set
    to 1 on creation. The other potential bug is that the free function
    for CoglPipeline was only calling the free_priv virtual for the
    currently used fragend of the pipeline. The design of the fragends is
    meant to allow a pipeline to have multiple fragend priv datas because
    a child pipeline could be attaching its fragend data to the ancestor
    and its allowed to pick a different fragend.

 cogl/cogl-pipeline-fragend-arbfp.c |  376 ++++++++++++++--------------------
 cogl/cogl-pipeline-fragend-fixed.c |    1 -
 cogl/cogl-pipeline-fragend-glsl.c  |  331 ++++++++++++------------------
 cogl/cogl-pipeline-private.h       |   17 --
 cogl/cogl-pipeline-progend-glsl.c  |  391 +++++++++++++++++++-----------------
 cogl/cogl-pipeline-vertend-glsl.c  |  133 +++++++------
 cogl/cogl-pipeline.c               |   16 --
 7 files changed, 567 insertions(+), 698 deletions(-)
---
diff --git a/cogl/cogl-pipeline-fragend-arbfp.c b/cogl/cogl-pipeline-fragend-arbfp.c
index 3f24edb..da0907f 100644
--- a/cogl/cogl-pipeline-fragend-arbfp.c
+++ b/cogl/cogl-pipeline-fragend-arbfp.c
@@ -55,6 +55,8 @@
 #define GL_TEXTURE_3D                           0x806F
 #endif
 
+const CoglPipelineFragend _cogl_pipeline_arbfp_fragend;
+
 typedef struct _UnitState
 {
   int constant_id; /* The program.local[] index */
@@ -63,7 +65,7 @@ typedef struct _UnitState
   unsigned int sampled:1;
 } UnitState;
 
-typedef struct _ArbfpProgramState
+typedef struct
 {
   int ref_count;
 
@@ -84,82 +86,65 @@ typedef struct _ArbfpProgramState
   /* We need to track the last pipeline that an ARBfp program was used
    * with so know if we need to update any program.local parameters. */
   CoglPipeline *last_used_for_pipeline;
-} ArbfpProgramState;
+} CoglPipelineShaderState;
 
-typedef struct _CoglPipelineFragendARBfpPrivate
-{
-  ArbfpProgramState *arbfp_program_state;
-} CoglPipelineFragendARBfpPrivate;
+static CoglUserDataKey shader_state_key;
 
-const CoglPipelineFragend _cogl_pipeline_arbfp_fragend;
+static CoglPipelineShaderState *
+shader_state_new (int n_layers)
+{
+  CoglPipelineShaderState *shader_state;
 
+  shader_state = g_slice_new0 (CoglPipelineShaderState);
+  shader_state->ref_count = 1;
+  shader_state->unit_state = g_new0 (UnitState, n_layers);
 
-static ArbfpProgramState *
-arbfp_program_state_new (int n_layers)
-{
-  ArbfpProgramState *state = g_slice_new0 (ArbfpProgramState);
-  state->ref_count = 1;
-  state->unit_state = g_new0 (UnitState, n_layers);
-  return state;
+  return shader_state;
 }
 
-static ArbfpProgramState *
-arbfp_program_state_ref (ArbfpProgramState *state)
+static CoglPipelineShaderState *
+get_shader_state (CoglPipeline *pipeline)
 {
-  state->ref_count++;
-  return state;
+  return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key);
 }
 
-void
-arbfp_program_state_unref (ArbfpProgramState *state)
+static void
+destroy_shader_state (void *user_data)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+  CoglPipelineShaderState *shader_state = user_data;
 
-  g_return_if_fail (state->ref_count > 0);
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  state->ref_count--;
-  if (state->ref_count == 0)
+  if (--shader_state->ref_count == 0)
     {
-      if (state->gl_program)
+      if (shader_state->gl_program)
         {
-          GE (ctx, glDeletePrograms (1, &state->gl_program));
-          state->gl_program = 0;
+          GE (ctx, glDeletePrograms (1, &shader_state->gl_program));
+          shader_state->gl_program = 0;
         }
 
-      g_free (state->unit_state);
+      g_free (shader_state->unit_state);
 
-      g_slice_free (ArbfpProgramState, state);
+      g_slice_free (CoglPipelineShaderState, shader_state);
     }
 }
 
-static CoglPipelineFragendARBfpPrivate *
-get_arbfp_priv (CoglPipeline *pipeline)
-{
-  if (!(pipeline->fragend_priv_set_mask & COGL_PIPELINE_FRAGEND_ARBFP_MASK))
-    return NULL;
-
-  return pipeline->fragend_privs[COGL_PIPELINE_FRAGEND_ARBFP];
-}
-
 static void
-set_arbfp_priv (CoglPipeline *pipeline, CoglPipelineFragendARBfpPrivate *priv)
+set_shader_state (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state)
 {
-  if (priv)
-    {
-      pipeline->fragend_privs[COGL_PIPELINE_FRAGEND_ARBFP] = priv;
-      pipeline->fragend_priv_set_mask |= COGL_PIPELINE_FRAGEND_ARBFP_MASK;
-    }
-  else
-    pipeline->fragend_priv_set_mask &= ~COGL_PIPELINE_FRAGEND_ARBFP_MASK;
+  cogl_object_set_user_data (COGL_OBJECT (pipeline),
+                             &shader_state_key,
+                             shader_state,
+                             destroy_shader_state);
 }
 
-static ArbfpProgramState *
-get_arbfp_program_state (CoglPipeline *pipeline)
+static void
+dirty_shader_state (CoglPipeline *pipeline)
 {
-  CoglPipelineFragendARBfpPrivate *priv = get_arbfp_priv (pipeline);
-  if (!priv)
-    return NULL;
-  return priv->arbfp_program_state;
+  cogl_object_set_user_data (COGL_OBJECT (pipeline),
+                             &shader_state_key,
+                             NULL,
+                             NULL);
 }
 
 static gboolean
@@ -168,10 +153,8 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
                                     unsigned long pipelines_difference,
                                     int n_tex_coord_attribs)
 {
-  CoglPipelineFragendARBfpPrivate *priv;
+  CoglPipelineShaderState *shader_state;
   CoglPipeline *authority;
-  CoglPipelineFragendARBfpPrivate *authority_priv;
-  ArbfpProgramState *arbfp_program_state;
   CoglHandle user_program;
 
   _COGL_GET_CONTEXT (ctx, FALSE);
@@ -203,16 +186,11 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
 
   /* Now lookup our ARBfp backend private state (allocating if
    * necessary) */
-  priv = get_arbfp_priv (pipeline);
-  if (!priv)
-    {
-      priv = g_slice_new0 (CoglPipelineFragendARBfpPrivate);
-      set_arbfp_priv (pipeline, priv);
-    }
+  shader_state = get_shader_state (pipeline);
 
-  /* If we have a valid arbfp_program_state pointer then we are all
-   * set and don't need to generate a new program. */
-  if (priv->arbfp_program_state)
+  /* 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;
 
   /* If we don't have an associated arbfp program yet then find the
@@ -228,41 +206,36 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
      _cogl_pipeline_get_state_for_fragment_codegen (ctx) &
      ~COGL_PIPELINE_STATE_LAYERS,
      _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx));
-  authority_priv = get_arbfp_priv (authority);
-  if (authority_priv &&
-      authority_priv->arbfp_program_state)
+  shader_state = get_shader_state (authority);
+  if (shader_state)
     {
       /* If we are going to share our program state with an arbfp-authority
-       * then steal a reference to the program state associated with that
+       * then add a reference to the program state associated with that
        * arbfp-authority... */
-      priv->arbfp_program_state =
-        arbfp_program_state_ref (authority_priv->arbfp_program_state);
+      shader_state->ref_count++;
+      set_shader_state (pipeline, shader_state);
       return TRUE;
     }
 
-  if (!authority_priv)
-    {
-      authority_priv = g_slice_new0 (CoglPipelineFragendARBfpPrivate);
-      set_arbfp_priv (authority, authority_priv);
-    }
-
   /* If we haven't yet found an existing program then before we resort to
    * generating a new arbfp program we see if we can find a suitable
    * program in the arbfp_cache. */
   if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
     {
-      arbfp_program_state = g_hash_table_lookup (ctx->arbfp_cache, authority);
-      if (arbfp_program_state)
+      shader_state = g_hash_table_lookup (ctx->arbfp_cache, authority);
+      if (shader_state)
         {
-          priv->arbfp_program_state =
-            arbfp_program_state_ref (arbfp_program_state);
+          shader_state->ref_count++;
+          set_shader_state (pipeline, shader_state);
 
           /* Since we have already resolved the arbfp-authority at this point
            * we might as well also associate any program we find from the cache
            * with the authority too... */
-          if (authority_priv != priv)
-            authority_priv->arbfp_program_state =
-              arbfp_program_state_ref (arbfp_program_state);
+          if (authority != pipeline)
+            {
+              shader_state->ref_count++;
+              set_shader_state (authority, shader_state);
+            }
           return TRUE;
         }
     }
@@ -271,26 +244,27 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
    * generating code for a new program...
    */
 
-  arbfp_program_state = arbfp_program_state_new (n_layers);
-
-  priv->arbfp_program_state = arbfp_program_state_ref (arbfp_program_state);
+  shader_state = shader_state_new (n_layers);
+  set_shader_state (pipeline, shader_state);
 
   /* Since we have already resolved the arbfp-authority at this point we might
    * as well also associate any program we generate with the authority too...
    */
-  if (authority_priv != priv)
-    authority_priv->arbfp_program_state =
-      arbfp_program_state_ref (arbfp_program_state);
+  if (authority != pipeline)
+    {
+      shader_state->ref_count++;
+      set_shader_state (authority, shader_state);
+    }
 
-  arbfp_program_state->user_program = user_program;
+  shader_state->user_program = user_program;
   if (user_program == COGL_INVALID_HANDLE)
     {
       int i;
 
       /* We reuse a single grow-only GString for code-gen */
       g_string_set_size (ctx->codegen_source_buffer, 0);
-      arbfp_program_state->source = ctx->codegen_source_buffer;
-      g_string_append (arbfp_program_state->source,
+      shader_state->source = ctx->codegen_source_buffer;
+      g_string_append (shader_state->source,
                        "!!ARBfp1.0\n"
                        "TEMP output;\n"
                        "TEMP tmp0, tmp1, tmp2, tmp3, tmp4;\n"
@@ -302,14 +276,14 @@ _cogl_pipeline_fragend_arbfp_start (CoglPipeline *pipeline,
       /* At the end of code-gen we'll add the program to a cache and
        * we'll use the authority pipeline as the basis for key into
        * that cache... */
-      arbfp_program_state->arbfp_authority = authority;
+      shader_state->arbfp_authority = authority;
 
       for (i = 0; i < n_layers; i++)
         {
-          arbfp_program_state->unit_state[i].sampled = FALSE;
-          arbfp_program_state->unit_state[i].dirty_combine_constant = FALSE;
+          shader_state->unit_state[i].sampled = FALSE;
+          shader_state->unit_state[i].dirty_combine_constant = FALSE;
         }
-      arbfp_program_state->next_constant_id = 0;
+      shader_state->next_constant_id = 0;
     }
 
   return TRUE;
@@ -370,20 +344,20 @@ gl_target_to_arbfp_string (GLenum gl_target)
 }
 
 static void
-setup_texture_source (ArbfpProgramState *arbfp_program_state,
+setup_texture_source (CoglPipelineShaderState *shader_state,
                       int unit_index,
                       GLenum gl_target)
 {
-  if (!arbfp_program_state->unit_state[unit_index].sampled)
+  if (!shader_state->unit_state[unit_index].sampled)
     {
       if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)))
-        g_string_append_printf (arbfp_program_state->source,
+        g_string_append_printf (shader_state->source,
                                 "TEMP texel%d;\n"
                                 "MOV texel%d, one;\n",
                                 unit_index,
                                 unit_index);
       else
-        g_string_append_printf (arbfp_program_state->source,
+        g_string_append_printf (shader_state->source,
                                 "TEMP texel%d;\n"
                                 "TEX texel%d,fragment.texcoord[%d],"
                                 "texture[%d],%s;\n",
@@ -392,7 +366,7 @@ setup_texture_source (ArbfpProgramState *arbfp_program_state,
                                 unit_index,
                                 unit_index,
                                 gl_target_to_arbfp_string (gl_target));
-      arbfp_program_state->unit_state[unit_index].sampled = TRUE;
+      shader_state->unit_state[unit_index].sampled = TRUE;
     }
 }
 
@@ -452,7 +426,7 @@ setup_arg (CoglPipeline *pipeline,
            GLint op,
            CoglPipelineFragendARBfpArg *arg)
 {
-  ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
+  CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
   static const char *tmp_name[3] = { "tmp0", "tmp1", "tmp2" };
   GLenum gl_target;
   CoglHandle texture;
@@ -465,14 +439,14 @@ setup_arg (CoglPipeline *pipeline,
       arg->texture_unit = _cogl_pipeline_layer_get_unit_index (layer);
       texture = _cogl_pipeline_layer_get_texture (layer);
       cogl_texture_get_gl_texture (texture, NULL, &gl_target);
-      setup_texture_source (arbfp_program_state, arg->texture_unit, gl_target);
+      setup_texture_source (shader_state, arg->texture_unit, gl_target);
       break;
     case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT:
       {
         int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
-        UnitState *unit_state = &arbfp_program_state->unit_state[unit_index];
+        UnitState *unit_state = &shader_state->unit_state[unit_index];
 
-        unit_state->constant_id = arbfp_program_state->next_constant_id++;
+        unit_state->constant_id = shader_state->next_constant_id++;
         unit_state->dirty_combine_constant = TRUE;
 
         arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_CONSTANT;
@@ -497,7 +471,7 @@ setup_arg (CoglPipeline *pipeline,
       arg->texture_unit = src - GL_TEXTURE0;
       texture = _cogl_pipeline_layer_get_texture (layer);
       cogl_texture_get_gl_texture (texture, NULL, &gl_target);
-      setup_texture_source (arbfp_program_state, arg->texture_unit, gl_target);
+      setup_texture_source (shader_state, arg->texture_unit, gl_target);
     }
 
   arg->swizzle = "";
@@ -507,11 +481,11 @@ setup_arg (CoglPipeline *pipeline,
     case COGL_PIPELINE_COMBINE_OP_SRC_COLOR:
       break;
     case COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_COLOR:
-      g_string_append_printf (arbfp_program_state->source,
+      g_string_append_printf (shader_state->source,
                               "SUB tmp%d, one, ",
                               arg_index);
-      append_arg (arbfp_program_state->source, arg);
-      g_string_append_printf (arbfp_program_state->source, ";\n");
+      append_arg (shader_state->source, arg);
+      g_string_append_printf (shader_state->source, ";\n");
       arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE;
       arg->name = tmp_name[arg_index];
       arg->swizzle = "";
@@ -523,16 +497,16 @@ setup_arg (CoglPipeline *pipeline,
         arg->swizzle = ".a";
       break;
     case COGL_PIPELINE_COMBINE_OP_ONE_MINUS_SRC_ALPHA:
-      g_string_append_printf (arbfp_program_state->source,
+      g_string_append_printf (shader_state->source,
                               "SUB tmp%d, one, ",
                               arg_index);
-      append_arg (arbfp_program_state->source, arg);
+      append_arg (shader_state->source, arg);
       /* avoid a swizzle if we know RGB are going to be masked
        * in the end anyway */
       if (mask != COGL_BLEND_STRING_CHANNEL_MASK_ALPHA)
-        g_string_append_printf (arbfp_program_state->source, ".a;\n");
+        g_string_append_printf (shader_state->source, ".a;\n");
       else
-        g_string_append_printf (arbfp_program_state->source, ";\n");
+        g_string_append_printf (shader_state->source, ";\n");
       arg->type = COGL_PIPELINE_FRAGEND_ARBFP_ARG_TYPE_SIMPLE;
       arg->name = tmp_name[arg_index];
       break;
@@ -577,7 +551,7 @@ append_function (CoglPipeline *pipeline,
                  CoglPipelineFragendARBfpArg *args,
                  int n_args)
 {
-  ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
+  CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
   const char *mask_name;
 
   switch (mask)
@@ -599,35 +573,35 @@ append_function (CoglPipeline *pipeline,
   switch (function)
     {
     case COGL_PIPELINE_COMBINE_FUNC_ADD:
-      g_string_append_printf (arbfp_program_state->source,
+      g_string_append_printf (shader_state->source,
                               "ADD_SAT output%s, ",
                               mask_name);
       break;
     case COGL_PIPELINE_COMBINE_FUNC_MODULATE:
       /* Note: no need to saturate since we can assume operands
        * have values in the range [0,1] */
-      g_string_append_printf (arbfp_program_state->source, "MUL output%s, ",
+      g_string_append_printf (shader_state->source, "MUL output%s, ",
                               mask_name);
       break;
     case COGL_PIPELINE_COMBINE_FUNC_REPLACE:
       /* Note: no need to saturate since we can assume operand
        * has a value in the range [0,1] */
-      g_string_append_printf (arbfp_program_state->source, "MOV output%s, ",
+      g_string_append_printf (shader_state->source, "MOV output%s, ",
                               mask_name);
       break;
     case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT:
-      g_string_append_printf (arbfp_program_state->source,
+      g_string_append_printf (shader_state->source,
                               "SUB_SAT output%s, ",
                               mask_name);
       break;
     case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED:
-      g_string_append_printf (arbfp_program_state->source, "ADD tmp3%s, ",
+      g_string_append_printf (shader_state->source, "ADD tmp3%s, ",
                               mask_name);
-      append_arg (arbfp_program_state->source, &args[0]);
-      g_string_append (arbfp_program_state->source, ", ");
-      append_arg (arbfp_program_state->source, &args[1]);
-      g_string_append (arbfp_program_state->source, ";\n");
-      g_string_append_printf (arbfp_program_state->source,
+      append_arg (shader_state->source, &args[0]);
+      g_string_append (shader_state->source, ", ");
+      append_arg (shader_state->source, &args[1]);
+      g_string_append (shader_state->source, ";\n");
+      g_string_append_printf (shader_state->source,
                               "SUB_SAT output%s, tmp3, half",
                               mask_name);
       n_args = 0;
@@ -656,20 +630,20 @@ append_function (CoglPipeline *pipeline,
          * output = 4 * DP3 (src0 - 0.5, src1 - 0.5)
          */
 
-        g_string_append (arbfp_program_state->source, "MAD tmp3, two, ");
-        append_arg (arbfp_program_state->source, &args[0]);
-        g_string_append (arbfp_program_state->source, ", minus_one;\n");
+        g_string_append (shader_state->source, "MAD tmp3, two, ");
+        append_arg (shader_state->source, &args[0]);
+        g_string_append (shader_state->source, ", minus_one;\n");
 
         if (!fragend_arbfp_args_equal (&args[0], &args[1]))
           {
-            g_string_append (arbfp_program_state->source, "MAD tmp4, two, ");
-            append_arg (arbfp_program_state->source, &args[1]);
-            g_string_append (arbfp_program_state->source, ", minus_one;\n");
+            g_string_append (shader_state->source, "MAD tmp4, two, ");
+            append_arg (shader_state->source, &args[1]);
+            g_string_append (shader_state->source, ", minus_one;\n");
           }
         else
           tmp4 = "tmp3";
 
-        g_string_append_printf (arbfp_program_state->source,
+        g_string_append_printf (shader_state->source,
                                 "DP3_SAT output%s, tmp3, %s",
                                 mask_name, tmp4);
         n_args = 0;
@@ -681,31 +655,31 @@ append_function (CoglPipeline *pipeline,
 
       /* NB: GL_INTERPOLATE = arg0*arg2 + arg1*(1-arg2)
        * but LRP dst, a, b, c = b*a + c*(1-a) */
-      g_string_append_printf (arbfp_program_state->source, "LRP output%s, ",
+      g_string_append_printf (shader_state->source, "LRP output%s, ",
                               mask_name);
-      append_arg (arbfp_program_state->source, &args[2]);
-      g_string_append (arbfp_program_state->source, ", ");
-      append_arg (arbfp_program_state->source, &args[0]);
-      g_string_append (arbfp_program_state->source, ", ");
-      append_arg (arbfp_program_state->source, &args[1]);
+      append_arg (shader_state->source, &args[2]);
+      g_string_append (shader_state->source, ", ");
+      append_arg (shader_state->source, &args[0]);
+      g_string_append (shader_state->source, ", ");
+      append_arg (shader_state->source, &args[1]);
       n_args = 0;
       break;
     default:
       g_error ("Unknown texture combine function %d", function);
-      g_string_append_printf (arbfp_program_state->source, "MUL_SAT output%s, ",
+      g_string_append_printf (shader_state->source, "MUL_SAT output%s, ",
                               mask_name);
       n_args = 2;
       break;
     }
 
   if (n_args > 0)
-    append_arg (arbfp_program_state->source, &args[0]);
+    append_arg (shader_state->source, &args[0]);
   if (n_args > 1)
     {
-      g_string_append (arbfp_program_state->source, ", ");
-      append_arg (arbfp_program_state->source, &args[1]);
+      g_string_append (shader_state->source, ", ");
+      append_arg (shader_state->source, &args[1]);
     }
-  g_string_append (arbfp_program_state->source, ";\n");
+  g_string_append (shader_state->source, ";\n");
 }
 
 static void
@@ -745,7 +719,7 @@ _cogl_pipeline_fragend_arbfp_add_layer (CoglPipeline *pipeline,
                                         CoglPipelineLayer *layer,
                                         unsigned long layers_difference)
 {
-  ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
+  CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
   CoglPipelineLayer *combine_authority =
     _cogl_pipeline_layer_get_authority (layer,
                                         COGL_PIPELINE_LAYER_STATE_COMBINE);
@@ -780,7 +754,7 @@ _cogl_pipeline_fragend_arbfp_add_layer (CoglPipeline *pipeline,
    * We are careful to only saturate when writing to output.
    */
 
-  if (!arbfp_program_state->source)
+  if (!shader_state->source)
     return TRUE;
 
   if (!_cogl_pipeline_need_texture_combine_separate (combine_authority))
@@ -827,12 +801,12 @@ _cogl_pipeline_fragend_arbfp_add_layer (CoglPipeline *pipeline,
 gboolean
 _cogl_pipeline_fragend_arbfp_passthrough (CoglPipeline *pipeline)
 {
-  ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
+  CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
 
-  if (!arbfp_program_state->source)
+  if (!shader_state->source)
     return TRUE;
 
-  g_string_append (arbfp_program_state->source,
+  g_string_append (shader_state->source,
                    "MOV output, fragment.color.primary;\n");
   return TRUE;
 }
@@ -841,7 +815,7 @@ typedef struct _UpdateConstantsState
 {
   int unit;
   gboolean update_all;
-  ArbfpProgramState *arbfp_program_state;
+  CoglPipelineShaderState *shader_state;
 } UpdateConstantsState;
 
 static gboolean
@@ -850,8 +824,8 @@ update_constants_cb (CoglPipeline *pipeline,
                      void *user_data)
 {
   UpdateConstantsState *state = user_data;
-  ArbfpProgramState *arbfp_program_state = state->arbfp_program_state;
-  UnitState *unit_state = &arbfp_program_state->unit_state[state->unit++];
+  CoglPipelineShaderState *shader_state = state->shader_state;
+  UnitState *unit_state = &shader_state->unit_state[state->unit++];
 
   _COGL_GET_CONTEXT (ctx, FALSE);
 
@@ -873,12 +847,12 @@ static gboolean
 _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
                                   unsigned long pipelines_difference)
 {
-  ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (pipeline);
+  CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
   GLuint gl_program;
 
   _COGL_GET_CONTEXT (ctx, FALSE);
 
-  if (arbfp_program_state->source)
+  if (shader_state->source)
     {
       GLenum gl_error;
       COGL_STATIC_COUNTER (fragend_arbfp_compile_counter,
@@ -889,32 +863,32 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
 
       COGL_COUNTER_INC (_cogl_uprof_context, fragend_arbfp_compile_counter);
 
-      g_string_append (arbfp_program_state->source,
+      g_string_append (shader_state->source,
                        "MOV result.color,output;\n");
-      g_string_append (arbfp_program_state->source, "END\n");
+      g_string_append (shader_state->source, "END\n");
 
       if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
-        g_message ("pipeline program:\n%s", arbfp_program_state->source->str);
+        g_message ("pipeline program:\n%s", shader_state->source->str);
 
-      GE (ctx, glGenPrograms (1, &arbfp_program_state->gl_program));
+      GE (ctx, glGenPrograms (1, &shader_state->gl_program));
 
       GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB,
-                         arbfp_program_state->gl_program));
+                              shader_state->gl_program));
 
       while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
         ;
       ctx->glProgramString (GL_FRAGMENT_PROGRAM_ARB,
                             GL_PROGRAM_FORMAT_ASCII_ARB,
-                            arbfp_program_state->source->len,
-                            arbfp_program_state->source->str);
+                            shader_state->source->len,
+                            shader_state->source->str);
       if (ctx->glGetError () != GL_NO_ERROR)
         {
           g_warning ("\n%s\n%s",
-                     arbfp_program_state->source->str,
+                     shader_state->source->str,
                      ctx->glGetString (GL_PROGRAM_ERROR_STRING_ARB));
         }
 
-      arbfp_program_state->source = NULL;
+      shader_state->source = NULL;
 
       if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_PROGRAM_CACHES))))
         {
@@ -942,9 +916,9 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
            * other pipelines) and only takes a copy of the state that
            * relates to the arbfp program and references small dummy
            * textures instead of potentially large user textures. */
-          key = cogl_pipeline_copy (arbfp_program_state->arbfp_authority);
-          arbfp_program_state_ref (arbfp_program_state);
-          g_hash_table_insert (ctx->arbfp_cache, key, arbfp_program_state);
+          key = cogl_pipeline_copy (shader_state->arbfp_authority);
+          shader_state->ref_count++;
+          g_hash_table_insert (ctx->arbfp_cache, key, shader_state);
           if (G_UNLIKELY (g_hash_table_size (ctx->arbfp_cache) > 50))
             {
               static gboolean seen = FALSE;
@@ -959,78 +933,60 @@ _cogl_pipeline_fragend_arbfp_end (CoglPipeline *pipeline,
       /* The authority is only valid during codegen since the program
        * state may have a longer lifetime than the original authority
        * it is created for. */
-      arbfp_program_state->arbfp_authority = NULL;
+      shader_state->arbfp_authority = NULL;
     }
 
-  if (arbfp_program_state->user_program != COGL_INVALID_HANDLE)
+  if (shader_state->user_program != COGL_INVALID_HANDLE)
     {
       /* An arbfp program should contain exactly one shader which we
          can use directly */
-      CoglProgram *program = arbfp_program_state->user_program;
+      CoglProgram *program = shader_state->user_program;
       CoglShader *shader = program->attached_shaders->data;
 
       gl_program = shader->gl_handle;
     }
   else
-    gl_program = arbfp_program_state->gl_program;
+    gl_program = shader_state->gl_program;
 
   GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB, gl_program));
   _cogl_use_fragment_program (0, COGL_PIPELINE_PROGRAM_TYPE_ARBFP);
 
-  if (arbfp_program_state->user_program == COGL_INVALID_HANDLE)
+  if (shader_state->user_program == COGL_INVALID_HANDLE)
     {
       UpdateConstantsState state;
       state.unit = 0;
-      state.arbfp_program_state = arbfp_program_state;
+      state.shader_state = shader_state;
       /* If this arbfp program was last used with a different pipeline
        * then we need to ensure we update all program.local params */
       state.update_all =
-        pipeline != arbfp_program_state->last_used_for_pipeline;
+        pipeline != shader_state->last_used_for_pipeline;
       cogl_pipeline_foreach_layer (pipeline,
                                    update_constants_cb,
                                    &state);
     }
   else
     {
-      CoglProgram *program = arbfp_program_state->user_program;
+      CoglProgram *program = shader_state->user_program;
       gboolean program_changed;
 
       /* If the shader has changed since it was last flushed then we
          need to update all uniforms */
-      program_changed = program->age != arbfp_program_state->user_program_age;
+      program_changed = program->age != shader_state->user_program_age;
 
       _cogl_program_flush_uniforms (program, gl_program, program_changed);
 
-      arbfp_program_state->user_program_age = program->age;
+      shader_state->user_program_age = program->age;
     }
 
   /* We need to track what pipeline used this arbfp program last since
    * we will need to update program.local params when switching
    * between different pipelines. */
-  arbfp_program_state->last_used_for_pipeline = pipeline;
+  shader_state->last_used_for_pipeline = pipeline;
 
   return TRUE;
 }
 
 static void
-dirty_arbfp_program_state (CoglPipeline *pipeline)
-{
-  CoglPipelineFragendARBfpPrivate *priv;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  priv = get_arbfp_priv (pipeline);
-  if (!priv)
-    return;
-
-  if (priv->arbfp_program_state)
-    {
-      arbfp_program_state_unref (priv->arbfp_program_state);
-      priv->arbfp_program_state = NULL;
-    }
-}
-
-static void
 _cogl_pipeline_fragend_arbfp_pipeline_pre_change_notify (
                                                    CoglPipeline *pipeline,
                                                    CoglPipelineState change,
@@ -1039,7 +995,7 @@ _cogl_pipeline_fragend_arbfp_pipeline_pre_change_notify (
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
-    dirty_arbfp_program_state (pipeline);
+    dirty_shader_state (pipeline);
 }
 
 /* NB: layers are considered immutable once they have any dependants
@@ -1056,29 +1012,23 @@ _cogl_pipeline_fragend_arbfp_layer_pre_change_notify (
                                                 CoglPipelineLayer *layer,
                                                 CoglPipelineLayerState change)
 {
-  CoglPipelineFragendARBfpPrivate *priv = get_arbfp_priv (owner);
+  CoglPipelineShaderState *shader_state = get_shader_state (owner);
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  if (!priv)
+  if (!shader_state)
     return;
 
   if ((change & _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx)))
     {
-      dirty_arbfp_program_state (owner);
+      dirty_shader_state (owner);
       return;
     }
 
   if (change & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT)
     {
-      ArbfpProgramState *arbfp_program_state = get_arbfp_program_state (owner);
-
-      if (arbfp_program_state)
-        {
-          int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
-          arbfp_program_state->unit_state[unit_index].dirty_combine_constant =
-            TRUE;
-        }
+      int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
+      shader_state->unit_state[unit_index].dirty_combine_constant = TRUE;
     }
 
   /* TODO: we could be saving snippets of texture combine code along
@@ -1087,19 +1037,6 @@ _cogl_pipeline_fragend_arbfp_layer_pre_change_notify (
   return;
 }
 
-static void
-_cogl_pipeline_fragend_arbfp_free_priv (CoglPipeline *pipeline)
-{
-  CoglPipelineFragendARBfpPrivate *priv = get_arbfp_priv (pipeline);
-  if (priv)
-    {
-      if (priv->arbfp_program_state)
-        arbfp_program_state_unref (priv->arbfp_program_state);
-      g_slice_free (CoglPipelineFragendARBfpPrivate, priv);
-      set_arbfp_priv (pipeline, NULL);
-    }
-}
-
 const CoglPipelineFragend _cogl_pipeline_arbfp_fragend =
 {
   _cogl_pipeline_fragend_arbfp_start,
@@ -1108,8 +1045,7 @@ const CoglPipelineFragend _cogl_pipeline_arbfp_fragend =
   _cogl_pipeline_fragend_arbfp_end,
   _cogl_pipeline_fragend_arbfp_pipeline_pre_change_notify,
   NULL,
-  _cogl_pipeline_fragend_arbfp_layer_pre_change_notify,
-  _cogl_pipeline_fragend_arbfp_free_priv
+  _cogl_pipeline_fragend_arbfp_layer_pre_change_notify
 };
 
 #endif /* COGL_PIPELINE_FRAGEND_ARBFP */
diff --git a/cogl/cogl-pipeline-fragend-fixed.c b/cogl/cogl-pipeline-fragend-fixed.c
index 97fe043..93627e4 100644
--- a/cogl/cogl-pipeline-fragend-fixed.c
+++ b/cogl/cogl-pipeline-fragend-fixed.c
@@ -363,7 +363,6 @@ const CoglPipelineFragend _cogl_pipeline_fixed_fragend =
   NULL, /* pipeline_change_notify */
   NULL, /* pipeline_set_parent_notify */
   NULL, /* layer_change_notify */
-  NULL /* free_priv */
 };
 
 #endif /* COGL_PIPELINE_FRAGEND_FIXED */
diff --git a/cogl/cogl-pipeline-fragend-glsl.c b/cogl/cogl-pipeline-fragend-glsl.c
index 32b355d..35e43e9 100644
--- a/cogl/cogl-pipeline-fragend-glsl.c
+++ b/cogl/cogl-pipeline-fragend-glsl.c
@@ -56,13 +56,15 @@
 #define GL_TEXTURE_3D                           0x806F
 #endif
 
+const CoglPipelineFragend _cogl_pipeline_glsl_backend;
+
 typedef struct _UnitState
 {
   unsigned int sampled:1;
   unsigned int combine_constant_used:1;
 } UnitState;
 
-typedef struct _GlslShaderState
+typedef struct
 {
   int ref_count;
 
@@ -75,120 +77,83 @@ typedef struct _GlslShaderState
      program changes then we may need to redecide whether to generate
      a shader at all */
   unsigned int user_program_age;
-} GlslShaderState;
+} CoglPipelineShaderState;
 
-typedef struct _CoglPipelineFragendGlslPrivate
-{
-  GlslShaderState *glsl_shader_state;
-} CoglPipelineFragendGlslPrivate;
-
-const CoglPipelineFragend _cogl_pipeline_glsl_backend;
+static CoglUserDataKey shader_state_key;
 
-static GlslShaderState *
-glsl_shader_state_new (int n_layers)
+static CoglPipelineShaderState *
+shader_state_new (int n_layers)
 {
-  GlslShaderState *state = g_slice_new0 (GlslShaderState);
+  CoglPipelineShaderState *shader_state;
 
-  state->ref_count = 1;
-  state->unit_state = g_new0 (UnitState, n_layers);
+  shader_state = g_slice_new0 (CoglPipelineShaderState);
+  shader_state->ref_count = 1;
+  shader_state->unit_state = g_new0 (UnitState, n_layers);
 
-  return state;
+  return shader_state;
 }
 
-static GlslShaderState *
-glsl_shader_state_ref (GlslShaderState *state)
+static CoglPipelineShaderState *
+get_shader_state (CoglPipeline *pipeline)
 {
-  state->ref_count++;
-  return state;
+  return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key);
 }
 
-void
-glsl_shader_state_unref (GlslShaderState *state)
+static void
+destroy_shader_state (void *user_data)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+  CoglPipelineShaderState *shader_state = user_data;
 
-  g_return_if_fail (state->ref_count > 0);
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  state->ref_count--;
-  if (state->ref_count == 0)
+  if (--shader_state->ref_count == 0)
     {
-      if (state->gl_shader)
-        GE( ctx, glDeleteShader (state->gl_shader) );
+      if (shader_state->gl_shader)
+        GE( ctx, glDeleteShader (shader_state->gl_shader) );
 
-      g_free (state->unit_state);
+      g_free (shader_state->unit_state);
 
-      g_slice_free (GlslShaderState, state);
+      g_slice_free (CoglPipelineShaderState, shader_state);
     }
 }
 
-static CoglPipelineFragendGlslPrivate *
-get_glsl_priv (CoglPipeline *pipeline)
-{
-  if (!(pipeline->fragend_priv_set_mask & COGL_PIPELINE_FRAGEND_GLSL_MASK))
-    return NULL;
-
-  return pipeline->fragend_privs[COGL_PIPELINE_FRAGEND_GLSL];
-}
-
 static void
-set_glsl_priv (CoglPipeline *pipeline, CoglPipelineFragendGlslPrivate *priv)
+set_shader_state (CoglPipeline *pipeline, CoglPipelineShaderState *shader_state)
 {
-  if (priv)
-    {
-      pipeline->fragend_privs[COGL_PIPELINE_FRAGEND_GLSL] = priv;
-      pipeline->fragend_priv_set_mask |= COGL_PIPELINE_FRAGEND_GLSL_MASK;
-    }
-  else
-    pipeline->fragend_priv_set_mask &= ~COGL_PIPELINE_FRAGEND_GLSL_MASK;
+  cogl_object_set_user_data (COGL_OBJECT (pipeline),
+                             &shader_state_key,
+                             shader_state,
+                             destroy_shader_state);
 }
 
-static GlslShaderState *
-get_glsl_shader_state (CoglPipeline *pipeline)
+static void
+dirty_shader_state (CoglPipeline *pipeline)
 {
-  CoglPipelineFragendGlslPrivate *priv = get_glsl_priv (pipeline);
-  if (!priv)
-    return NULL;
-  return priv->glsl_shader_state;
+  cogl_object_set_user_data (COGL_OBJECT (pipeline),
+                             &shader_state_key,
+                             NULL,
+                             NULL);
 }
 
 GLuint
 _cogl_pipeline_fragend_glsl_get_shader (CoglPipeline *pipeline)
 {
-  GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
+  CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
 
-  if (glsl_shader_state)
-    return glsl_shader_state->gl_shader;
+  if (shader_state)
+    return shader_state->gl_shader;
   else
     return 0;
 }
 
-static void
-dirty_glsl_shader_state (CoglPipeline *pipeline)
-{
-  CoglPipelineFragendGlslPrivate *priv;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  priv = get_glsl_priv (pipeline);
-  if (!priv)
-    return;
-
-  if (priv->glsl_shader_state)
-    {
-      glsl_shader_state_unref (priv->glsl_shader_state);
-      priv->glsl_shader_state = NULL;
-    }
-}
-
 static gboolean
 _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
                                    int n_layers,
                                    unsigned long pipelines_difference,
                                    int n_tex_coord_attribs)
 {
-  CoglPipelineFragendGlslPrivate *priv;
+  CoglPipelineShaderState *shader_state;
   CoglPipeline *authority;
-  CoglPipelineFragendGlslPrivate *authority_priv;
   CoglProgram *user_program;
   int i;
 
@@ -206,16 +171,10 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
       _cogl_program_get_language (user_program) != COGL_SHADER_LANGUAGE_GLSL)
     return FALSE;
 
-  /* Now lookup our glsl backend private state (allocating if
-   * necessary) */
-  priv = get_glsl_priv (pipeline);
-  if (!priv)
-    {
-      priv = g_slice_new0 (CoglPipelineFragendGlslPrivate);
-      set_glsl_priv (pipeline, priv);
-    }
+  /* Now lookup our glsl backend private state */
+  shader_state = get_shader_state (pipeline);
 
-  if (!priv->glsl_shader_state)
+  if (shader_state == NULL)
     {
       /* If we don't have an associated glsl shader yet then find the
        * glsl-authority (the oldest ancestor whose state will result in
@@ -231,43 +190,39 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
          ~COGL_PIPELINE_STATE_LAYERS,
          _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx));
 
-      authority_priv = get_glsl_priv (authority);
-      if (!authority_priv)
-        {
-          authority_priv = g_slice_new0 (CoglPipelineFragendGlslPrivate);
-          set_glsl_priv (authority, authority_priv);
-        }
+      shader_state = get_shader_state (authority);
 
       /* If we don't have an existing program associated with the
        * glsl-authority then start generating code for a new shader...
        */
-      if (!authority_priv->glsl_shader_state)
+      if (shader_state == NULL)
         {
-          GlslShaderState *glsl_shader_state =
-            glsl_shader_state_new (n_layers);
-          authority_priv->glsl_shader_state = glsl_shader_state;
+          shader_state = shader_state_new (n_layers);
+          set_shader_state (authority, shader_state);
         }
 
       /* If the pipeline isn't actually its own glsl-authority
        * then take a reference to the program state associated
        * with the glsl-authority... */
       if (authority != pipeline)
-        priv->glsl_shader_state =
-          glsl_shader_state_ref (authority_priv->glsl_shader_state);
+        {
+          shader_state->ref_count++;
+          set_shader_state (pipeline, shader_state);
+        }
     }
 
-  if (priv->glsl_shader_state->gl_shader)
+  if (shader_state->gl_shader)
     {
       /* If we already have a valid GLSL shader then we don't need to
          generate a new one. However if there's a user program and it
          has changed since the last link then we do need a new shader */
       if (user_program == NULL ||
-          (priv->glsl_shader_state->user_program_age == user_program->age))
+          shader_state->user_program_age == user_program->age)
         return TRUE;
 
       /* We need to recreate the shader so destroy the existing one */
-      GE( ctx, glDeleteShader (priv->glsl_shader_state->gl_shader) );
-      priv->glsl_shader_state->gl_shader = 0;
+      GE( ctx, glDeleteShader (shader_state->gl_shader) );
+      shader_state->gl_shader = 0;
     }
 
   /* If we make it here then we have a glsl_shader_state struct
@@ -275,7 +230,7 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
      encountered it or because the user program has changed */
 
   if (user_program)
-    priv->glsl_shader_state->user_program_age = user_program->age;
+    shader_state->user_program_age = user_program->age;
 
   /* If the user program contains a fragment shader then we don't need
      to generate one */
@@ -290,25 +245,25 @@ _cogl_pipeline_fragend_glsl_start (CoglPipeline *pipeline,
      add_layer callback is invoked */
   g_string_set_size (ctx->codegen_header_buffer, 0);
   g_string_set_size (ctx->codegen_source_buffer, 0);
-  priv->glsl_shader_state->header = ctx->codegen_header_buffer;
-  priv->glsl_shader_state->source = ctx->codegen_source_buffer;
+  shader_state->header = ctx->codegen_header_buffer;
+  shader_state->source = ctx->codegen_source_buffer;
 
-  g_string_append (priv->glsl_shader_state->source,
+  g_string_append (shader_state->source,
                    "void\n"
                    "main ()\n"
                    "{\n");
 
   for (i = 0; i < n_layers; i++)
     {
-      priv->glsl_shader_state->unit_state[i].sampled = FALSE;
-      priv->glsl_shader_state->unit_state[i].combine_constant_used = FALSE;
+      shader_state->unit_state[i].sampled = FALSE;
+      shader_state->unit_state[i].combine_constant_used = FALSE;
     }
 
   return TRUE;
 }
 
 static void
-add_constant_lookup (GlslShaderState *glsl_shader_state,
+add_constant_lookup (CoglPipelineShaderState *shader_state,
                      CoglPipeline *pipeline,
                      CoglPipelineLayer *layer,
                      const char *swizzle)
@@ -316,21 +271,21 @@ add_constant_lookup (GlslShaderState *glsl_shader_state,
   int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
 
   /* Create a sampler uniform for this layer if we haven't already */
-  if (!glsl_shader_state->unit_state[unit_index].combine_constant_used)
+  if (!shader_state->unit_state[unit_index].combine_constant_used)
     {
-      g_string_append_printf (glsl_shader_state->header,
+      g_string_append_printf (shader_state->header,
                               "uniform vec4 _cogl_layer_constant_%i;\n",
                               unit_index);
-      glsl_shader_state->unit_state[unit_index].combine_constant_used = TRUE;
+      shader_state->unit_state[unit_index].combine_constant_used = TRUE;
     }
 
-  g_string_append_printf (glsl_shader_state->source,
+  g_string_append_printf (shader_state->source,
                           "_cogl_layer_constant_%i.%s",
                           unit_index, swizzle);
 }
 
 static void
-add_texture_lookup (GlslShaderState *glsl_shader_state,
+add_texture_lookup (CoglPipelineShaderState *shader_state,
                     CoglPipeline *pipeline,
                     CoglPipelineLayer *layer,
                     const char *swizzle)
@@ -343,9 +298,9 @@ add_texture_lookup (GlslShaderState *glsl_shader_state,
 
   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_TEXTURING)))
     {
-      g_string_append (glsl_shader_state->source,
+      g_string_append (shader_state->source,
                        "vec4 (1.0, 1.0, 1.0, 1.0).");
-      g_string_append (glsl_shader_state->source, swizzle);
+      g_string_append (shader_state->source, swizzle);
 
       return;
     }
@@ -394,16 +349,16 @@ add_texture_lookup (GlslShaderState *glsl_shader_state,
     }
 
   /* Create a sampler uniform for this layer if we haven't already */
-  if (!glsl_shader_state->unit_state[unit_index].sampled)
+  if (!shader_state->unit_state[unit_index].sampled)
     {
-      g_string_append_printf (glsl_shader_state->header,
+      g_string_append_printf (shader_state->header,
                               "uniform sampler%s _cogl_sampler_%i;\n",
                               target_string,
                               unit_index);
-      glsl_shader_state->unit_state[unit_index].sampled = TRUE;
+      shader_state->unit_state[unit_index].sampled = TRUE;
     }
 
-  g_string_append_printf (glsl_shader_state->source,
+  g_string_append_printf (shader_state->source,
                           "texture%s (_cogl_sampler_%i, ",
                           target_string, unit_index);
 
@@ -418,15 +373,15 @@ add_texture_lookup (GlslShaderState *glsl_shader_state,
   if (ctx->driver == COGL_DRIVER_GLES2 &&
       cogl_pipeline_get_layer_point_sprite_coords_enabled (pipeline,
                                                            layer->index))
-    g_string_append_printf (glsl_shader_state->source,
+    g_string_append_printf (shader_state->source,
                             "gl_PointCoord.%s",
                             tex_coord_swizzle);
   else
-    g_string_append_printf (glsl_shader_state->source,
+    g_string_append_printf (shader_state->source,
                             "cogl_tex_coord_in[%d].%s",
                             unit_index, tex_coord_swizzle);
 
-  g_string_append_printf (glsl_shader_state->source, ").%s", swizzle);
+  g_string_append_printf (shader_state->source, ").%s", swizzle);
 }
 
 typedef struct
@@ -454,14 +409,14 @@ find_pipeline_layer_cb (CoglPipelineLayer *layer,
 }
 
 static void
-add_arg (GlslShaderState *glsl_shader_state,
+add_arg (CoglPipelineShaderState *shader_state,
          CoglPipeline *pipeline,
          CoglPipelineLayer *layer,
          CoglPipelineCombineSource src,
          CoglPipelineCombineOp operand,
          const char *swizzle)
 {
-  GString *shader_source = glsl_shader_state->source;
+  GString *shader_source = shader_state->source;
   char alpha_swizzle[5] = "aaaa";
 
   g_string_append_c (shader_source, '(');
@@ -484,14 +439,14 @@ add_arg (GlslShaderState *glsl_shader_state,
   switch (src)
     {
     case COGL_PIPELINE_COMBINE_SOURCE_TEXTURE:
-      add_texture_lookup (glsl_shader_state,
+      add_texture_lookup (shader_state,
                           pipeline,
                           layer,
                           swizzle);
       break;
 
     case COGL_PIPELINE_COMBINE_SOURCE_CONSTANT:
-      add_constant_lookup (glsl_shader_state,
+      add_constant_lookup (shader_state,
                            pipeline,
                            layer,
                            swizzle);
@@ -521,7 +476,7 @@ add_arg (GlslShaderState *glsl_shader_state,
                                                  find_pipeline_layer_cb,
                                                  &data);
 
-          add_texture_lookup (glsl_shader_state,
+          add_texture_lookup (shader_state,
                               pipeline,
                               data.layer,
                               swizzle);
@@ -540,40 +495,40 @@ append_masked_combine (CoglPipeline *pipeline,
                        CoglPipelineCombineSource *src,
                        CoglPipelineCombineOp *op)
 {
-  GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
-  GString *shader_source = glsl_shader_state->source;
+  CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
+  GString *shader_source = shader_state->source;
 
-  g_string_append_printf (glsl_shader_state->source,
+  g_string_append_printf (shader_state->source,
                           "  cogl_color_out.%s = ", swizzle);
 
   switch (function)
     {
     case COGL_PIPELINE_COMBINE_FUNC_REPLACE:
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[0], op[0], swizzle);
       break;
 
     case COGL_PIPELINE_COMBINE_FUNC_MODULATE:
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[0], op[0], swizzle);
       g_string_append (shader_source, " * ");
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[1], op[1], swizzle);
       break;
 
     case COGL_PIPELINE_COMBINE_FUNC_ADD:
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[0], op[0], swizzle);
       g_string_append (shader_source, " + ");
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[1], op[1], swizzle);
       break;
 
     case COGL_PIPELINE_COMBINE_FUNC_ADD_SIGNED:
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[0], op[0], swizzle);
       g_string_append (shader_source, " + ");
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[1], op[1], swizzle);
       g_string_append_printf (shader_source,
                               " - vec4(0.5, 0.5, 0.5, 0.5).%s",
@@ -581,26 +536,26 @@ append_masked_combine (CoglPipeline *pipeline,
       break;
 
     case COGL_PIPELINE_COMBINE_FUNC_SUBTRACT:
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[0], op[0], swizzle);
       g_string_append (shader_source, " - ");
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[1], op[1], swizzle);
       break;
 
     case COGL_PIPELINE_COMBINE_FUNC_INTERPOLATE:
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[0], op[0], swizzle);
       g_string_append (shader_source, " * ");
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[2], op[2], swizzle);
       g_string_append (shader_source, " + ");
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[1], op[1], swizzle);
       g_string_append_printf (shader_source,
                               " * (vec4(1.0, 1.0, 1.0, 1.0).%s - ",
                               swizzle);
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[2], op[2], swizzle);
       g_string_append_c (shader_source, ')');
       break;
@@ -608,22 +563,22 @@ append_masked_combine (CoglPipeline *pipeline,
     case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGB:
     case COGL_PIPELINE_COMBINE_FUNC_DOT3_RGBA:
       g_string_append (shader_source, "vec4(4.0 * ((");
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[0], op[0], "r");
       g_string_append (shader_source, " - 0.5) * (");
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[1], op[1], "r");
       g_string_append (shader_source, " - 0.5) + (");
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[0], op[0], "g");
       g_string_append (shader_source, " - 0.5) * (");
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[1], op[1], "g");
       g_string_append (shader_source, " - 0.5) + (");
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[0], op[0], "b");
       g_string_append (shader_source, " - 0.5) * (");
-      add_arg (glsl_shader_state, pipeline, layer,
+      add_arg (shader_state, pipeline, layer,
                src[1], op[1], "b");
       g_string_append_printf (shader_source, " - 0.5))).%s", swizzle);
       break;
@@ -637,13 +592,13 @@ _cogl_pipeline_fragend_glsl_add_layer (CoglPipeline *pipeline,
                                         CoglPipelineLayer *layer,
                                         unsigned long layers_difference)
 {
-  GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
+  CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
   CoglPipelineLayer *combine_authority =
     _cogl_pipeline_layer_get_authority (layer,
                                         COGL_PIPELINE_LAYER_STATE_COMBINE);
   CoglPipelineLayerBigState *big_state = combine_authority->big_state;
 
-  if (!glsl_shader_state->source)
+  if (!shader_state->source)
     return TRUE;
 
   if (!_cogl_pipeline_need_texture_combine_separate (combine_authority) ||
@@ -680,12 +635,12 @@ _cogl_pipeline_fragend_glsl_add_layer (CoglPipeline *pipeline,
 gboolean
 _cogl_pipeline_fragend_glsl_passthrough (CoglPipeline *pipeline)
 {
-  GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
+  CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
 
-  if (!glsl_shader_state->source)
+  if (!shader_state->source)
     return TRUE;
 
-  g_string_append (glsl_shader_state->source,
+  g_string_append (shader_state->source,
                    "  cogl_color_out = cogl_color_in;\n");
 
   return TRUE;
@@ -698,7 +653,7 @@ _cogl_pipeline_fragend_glsl_passthrough (CoglPipeline *pipeline)
 
 static void
 add_alpha_test_snippet (CoglPipeline *pipeline,
-                        GlslShaderState *glsl_shader_state)
+                        CoglPipelineShaderState *shader_state)
 {
   CoglPipelineAlphaFunc alpha_func;
 
@@ -711,7 +666,7 @@ add_alpha_test_snippet (CoglPipeline *pipeline,
   if (alpha_func == COGL_PIPELINE_ALPHA_FUNC_NEVER)
     {
       /* Always discard the fragment */
-      g_string_append (glsl_shader_state->source,
+      g_string_append (shader_state->source,
                        "  discard;\n");
       return;
     }
@@ -719,31 +674,31 @@ add_alpha_test_snippet (CoglPipeline *pipeline,
   /* For all of the other alpha functions we need a uniform for the
      reference */
 
-  g_string_append (glsl_shader_state->header,
+  g_string_append (shader_state->header,
                    "uniform float _cogl_alpha_test_ref;\n");
 
-  g_string_append (glsl_shader_state->source,
+  g_string_append (shader_state->source,
                    "  if (cogl_color_out.a ");
 
   switch (alpha_func)
     {
     case COGL_PIPELINE_ALPHA_FUNC_LESS:
-      g_string_append (glsl_shader_state->source, ">=");
+      g_string_append (shader_state->source, ">=");
       break;
     case COGL_PIPELINE_ALPHA_FUNC_EQUAL:
-      g_string_append (glsl_shader_state->source, "!=");
+      g_string_append (shader_state->source, "!=");
       break;
     case COGL_PIPELINE_ALPHA_FUNC_LEQUAL:
-      g_string_append (glsl_shader_state->source, ">");
+      g_string_append (shader_state->source, ">");
       break;
     case COGL_PIPELINE_ALPHA_FUNC_GREATER:
-      g_string_append (glsl_shader_state->source, "<=");
+      g_string_append (shader_state->source, "<=");
       break;
     case COGL_PIPELINE_ALPHA_FUNC_NOTEQUAL:
-      g_string_append (glsl_shader_state->source, "==");
+      g_string_append (shader_state->source, "==");
       break;
     case COGL_PIPELINE_ALPHA_FUNC_GEQUAL:
-      g_string_append (glsl_shader_state->source, "< ");
+      g_string_append (shader_state->source, "< ");
       break;
 
     case COGL_PIPELINE_ALPHA_FUNC_ALWAYS:
@@ -752,7 +707,7 @@ add_alpha_test_snippet (CoglPipeline *pipeline,
       break;
     }
 
-  g_string_append (glsl_shader_state->source,
+  g_string_append (shader_state->source,
                    " _cogl_alpha_test_ref)\n    discard;\n");
 }
 
@@ -762,11 +717,11 @@ gboolean
 _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
                                  unsigned long pipelines_difference)
 {
-  GlslShaderState *glsl_shader_state = get_glsl_shader_state (pipeline);
+  CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
 
   _COGL_GET_CONTEXT (ctx, FALSE);
 
-  if (glsl_shader_state->source)
+  if (shader_state->source)
     {
       const char *source_strings[2];
       GLint lengths[2];
@@ -784,23 +739,23 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
 
 #ifdef HAVE_COGL_GLES2
       if (ctx->driver == COGL_DRIVER_GLES2)
-        add_alpha_test_snippet (pipeline, glsl_shader_state);
+        add_alpha_test_snippet (pipeline, shader_state);
 #endif
 
-      g_string_append (glsl_shader_state->source, "}\n");
+      g_string_append (shader_state->source, "}\n");
 
       GE_RET( shader, ctx, glCreateShader (GL_FRAGMENT_SHADER) );
 
-      lengths[0] = glsl_shader_state->header->len;
-      source_strings[0] = glsl_shader_state->header->str;
-      lengths[1] = glsl_shader_state->source->len;
-      source_strings[1] = glsl_shader_state->source->str;
+      lengths[0] = shader_state->header->len;
+      source_strings[0] = shader_state->header->str;
+      lengths[1] = shader_state->source->len;
+      source_strings[1] = shader_state->source->str;
 
       /* Find the highest texture unit that is sampled to pass as the
          number of texture coordinate attributes */
       n_layers = cogl_pipeline_get_n_layers (pipeline);
       for (i = 0; i < n_layers; i++)
-        if (glsl_shader_state->unit_state[i].sampled)
+        if (shader_state->unit_state[i].sampled)
           n_tex_coord_attribs = i + 1;
 
       _cogl_shader_set_source_with_boilerplate (shader, GL_FRAGMENT_SHADER,
@@ -822,9 +777,9 @@ _cogl_pipeline_fragend_glsl_end (CoglPipeline *pipeline,
           g_warning ("Shader compilation failed:\n%s", shader_log);
         }
 
-      glsl_shader_state->header = NULL;
-      glsl_shader_state->source = NULL;
-      glsl_shader_state->gl_shader = shader;
+      shader_state->header = NULL;
+      shader_state->source = NULL;
+      shader_state->gl_shader = shader;
     }
 
   return TRUE;
@@ -838,7 +793,7 @@ _cogl_pipeline_fragend_glsl_pre_change_notify (CoglPipeline *pipeline,
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
-    dirty_glsl_shader_state (pipeline);
+    dirty_shader_state (pipeline);
 }
 
 /* NB: layers are considered immutable once they have any dependants
@@ -855,17 +810,11 @@ _cogl_pipeline_fragend_glsl_layer_pre_change_notify (
                                                 CoglPipelineLayer *layer,
                                                 CoglPipelineLayerState change)
 {
-  CoglPipelineFragendGlslPrivate *priv;
-
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  priv = get_glsl_priv (owner);
-  if (!priv)
-    return;
-
   if ((change & _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx)))
     {
-      dirty_glsl_shader_state (owner);
+      dirty_shader_state (owner);
       return;
     }
 
@@ -874,19 +823,6 @@ _cogl_pipeline_fragend_glsl_layer_pre_change_notify (
    * the snippet. */
 }
 
-static void
-_cogl_pipeline_fragend_glsl_free_priv (CoglPipeline *pipeline)
-{
-  CoglPipelineFragendGlslPrivate *priv = get_glsl_priv (pipeline);
-  if (priv)
-    {
-      if (priv->glsl_shader_state)
-        glsl_shader_state_unref (priv->glsl_shader_state);
-      g_slice_free (CoglPipelineFragendGlslPrivate, priv);
-      set_glsl_priv (pipeline, NULL);
-    }
-}
-
 const CoglPipelineFragend _cogl_pipeline_glsl_fragend =
 {
   _cogl_pipeline_fragend_glsl_start,
@@ -895,8 +831,7 @@ const CoglPipelineFragend _cogl_pipeline_glsl_fragend =
   _cogl_pipeline_fragend_glsl_end,
   _cogl_pipeline_fragend_glsl_pre_change_notify,
   NULL, /* pipeline_set_parent_notify */
-  _cogl_pipeline_fragend_glsl_layer_pre_change_notify,
-  _cogl_pipeline_fragend_glsl_free_priv,
+  _cogl_pipeline_fragend_glsl_layer_pre_change_notify
 };
 
 #endif /* COGL_PIPELINE_FRAGEND_GLSL */
diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h
index ba0fabf..35d05e7 100644
--- a/cogl/cogl-pipeline-private.h
+++ b/cogl/cogl-pipeline-private.h
@@ -649,10 +649,6 @@ struct _CoglPipeline
    * pipeline in comparison to its parent. */
   unsigned long    differences;
 
-  /* The fragment processing backends can associate private data with a
-   * pipeline. */
-  void		  *fragend_privs[COGL_PIPELINE_N_FRAGENDS];
-
   /* Whenever a pipeline is modified we increment the age. There's no
    * guarantee that it won't wrap but it can nevertheless be a
    * convenient mechanism to determine when a pipeline has been
@@ -704,17 +700,6 @@ struct _CoglPipeline
 
   /* bitfields */
 
-  /* A pipeline can have private data associated with it for multiple
-   * fragment processing backends. Although only one backend is
-   * associated with a pipeline the backends may want to cache private
-   * state with the ancestors of other pipelines and those ancestors
-   * could currently be associated with different backends.
-   *
-   * Each set bit indicates if the corresponding ->fragend_privs[]
-   * entry is valid.
-   */
-  unsigned int          fragend_priv_set_mask:COGL_PIPELINE_N_FRAGENDS;
-
   /* Weak pipelines don't count as dependants on their parents which
    * means that the parent pipeline can be modified without
    * considering how the modifications may affect the weak pipeline.
@@ -771,8 +756,6 @@ typedef struct _CoglPipelineFragend
   void (*layer_pre_change_notify) (CoglPipeline *owner,
                                    CoglPipelineLayer *layer,
                                    CoglPipelineLayerState change);
-
-  void (*free_priv) (CoglPipeline *pipeline);
 } CoglPipelineFragend;
 
 typedef struct _CoglPipelineVertend
diff --git a/cogl/cogl-pipeline-progend-glsl.c b/cogl/cogl-pipeline-progend-glsl.c
index ae8e0af..9eb1d7c 100644
--- a/cogl/cogl-pipeline-progend-glsl.c
+++ b/cogl/cogl-pipeline-progend-glsl.c
@@ -138,14 +138,14 @@ typedef struct
   CoglPipeline *last_used_for_pipeline;
 
   UnitState *unit_state;
-} CoglPipelineProgendPrivate;
+} CoglPipelineProgramState;
 
-static CoglUserDataKey glsl_priv_key;
+static CoglUserDataKey program_state_key;
 
-static CoglPipelineProgendPrivate *
-get_glsl_priv (CoglPipeline *pipeline)
+static CoglPipelineProgramState *
+get_program_state (CoglPipeline *pipeline)
 {
-  return cogl_object_get_user_data (COGL_OBJECT (pipeline), &glsl_priv_key);
+  return cogl_object_get_user_data (COGL_OBJECT (pipeline), &program_state_key);
 }
 
 #ifdef HAVE_COGL_GLES2
@@ -162,96 +162,101 @@ get_glsl_priv (CoglPipeline *pipeline)
 int
 _cogl_pipeline_progend_glsl_get_position_attribute (CoglPipeline *pipeline)
 {
-  CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
+  CoglPipelineProgramState *program_state = get_program_state (pipeline);
 
   _COGL_GET_CONTEXT (ctx, -1);
 
-  g_return_val_if_fail (priv != NULL, -1);
-  g_return_val_if_fail (priv->program != 0, -1);
+  g_return_val_if_fail (program_state != NULL, -1);
+  g_return_val_if_fail (program_state->program != 0, -1);
 
-  if (priv->position_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
-    GE_RET( priv->position_attribute_location,
-            ctx, glGetAttribLocation (priv->program, "cogl_position_in") );
+  if (program_state->position_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
+    GE_RET( program_state->position_attribute_location,
+            ctx, glGetAttribLocation (program_state->program,
+                                      "cogl_position_in") );
 
-  return priv->position_attribute_location;
+  return program_state->position_attribute_location;
 }
 
 int
 _cogl_pipeline_progend_glsl_get_color_attribute (CoglPipeline *pipeline)
 {
-  CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
+  CoglPipelineProgramState *program_state = get_program_state (pipeline);
 
   _COGL_GET_CONTEXT (ctx, -1);
 
-  g_return_val_if_fail (priv != NULL, -1);
-  g_return_val_if_fail (priv->program != 0, -1);
+  g_return_val_if_fail (program_state != NULL, -1);
+  g_return_val_if_fail (program_state->program != 0, -1);
 
-  if (priv->color_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
-    GE_RET( priv->color_attribute_location,
-            ctx, glGetAttribLocation (priv->program, "cogl_color_in") );
+  if (program_state->color_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
+    GE_RET( program_state->color_attribute_location,
+            ctx, glGetAttribLocation (program_state->program,
+                                      "cogl_color_in") );
 
-  return priv->color_attribute_location;
+  return program_state->color_attribute_location;
 }
 
 int
 _cogl_pipeline_progend_glsl_get_normal_attribute (CoglPipeline *pipeline)
 {
-  CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
+  CoglPipelineProgramState *program_state = get_program_state (pipeline);
 
   _COGL_GET_CONTEXT (ctx, -1);
 
-  g_return_val_if_fail (priv != NULL, -1);
-  g_return_val_if_fail (priv->program != 0, -1);
+  g_return_val_if_fail (program_state != NULL, -1);
+  g_return_val_if_fail (program_state->program != 0, -1);
 
-  if (priv->normal_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
-    GE_RET( priv->normal_attribute_location,
-            ctx, glGetAttribLocation (priv->program, "cogl_normal_in") );
+  if (program_state->normal_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
+    GE_RET( program_state->normal_attribute_location,
+            ctx, glGetAttribLocation (program_state->program,
+                                      "cogl_normal_in") );
 
-  return priv->normal_attribute_location;
+  return program_state->normal_attribute_location;
 }
 
 int
 _cogl_pipeline_progend_glsl_get_tex_coord_attribute (CoglPipeline *pipeline,
                                                      int unit)
 {
-  CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
+  CoglPipelineProgramState *program_state = get_program_state (pipeline);
 
   _COGL_GET_CONTEXT (ctx, -1);
 
-  g_return_val_if_fail (priv != NULL, -1);
-  g_return_val_if_fail (priv->program != 0, -1);
+  g_return_val_if_fail (program_state != NULL, -1);
+  g_return_val_if_fail (program_state->program != 0, -1);
 
   if (unit == 0)
     {
-      if (priv->tex_coord0_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
-        GE_RET( priv->tex_coord0_attribute_location,
-                ctx, glGetAttribLocation (priv->program,
+      if (program_state->tex_coord0_attribute_location ==
+          ATTRIBUTE_LOCATION_UNKNOWN)
+        GE_RET( program_state->tex_coord0_attribute_location,
+                ctx, glGetAttribLocation (program_state->program,
                                           "cogl_tex_coord0_in") );
 
-      return priv->tex_coord0_attribute_location;
+      return program_state->tex_coord0_attribute_location;
     }
   else
     {
       char *name = g_strdup_printf ("cogl_tex_coord%i_in", unit);
       int *locations;
 
-      if (priv->tex_coord_attribute_locations == NULL)
-        priv->tex_coord_attribute_locations = g_array_new (FALSE, FALSE,
-                                                           sizeof (int));
-      if (priv->tex_coord_attribute_locations->len <= unit - 1)
+      if (program_state->tex_coord_attribute_locations == NULL)
+        program_state->tex_coord_attribute_locations =
+          g_array_new (FALSE, FALSE, sizeof (int));
+      if (program_state->tex_coord_attribute_locations->len <= unit - 1)
         {
-          int i = priv->tex_coord_attribute_locations->len;
-          g_array_set_size (priv->tex_coord_attribute_locations, unit);
+          int i = program_state->tex_coord_attribute_locations->len;
+          g_array_set_size (program_state->tex_coord_attribute_locations, unit);
           for (; i < unit; i++)
-            g_array_index (priv->tex_coord_attribute_locations, int, i) =
-              ATTRIBUTE_LOCATION_UNKNOWN;
+            g_array_index (program_state->tex_coord_attribute_locations, int, i)
+              = ATTRIBUTE_LOCATION_UNKNOWN;
         }
 
-      locations = &g_array_index (priv->tex_coord_attribute_locations, int, 0);
+      locations = &g_array_index (program_state->tex_coord_attribute_locations,
+                                  int, 0);
 
       if (locations[unit - 1] == ATTRIBUTE_LOCATION_UNKNOWN)
         GE_RET( locations[unit - 1],
-                ctx, glGetAttribLocation (priv->program, name) );
+                ctx, glGetAttribLocation (program_state->program, name) );
 
       g_free (name);
 
@@ -260,79 +265,100 @@ _cogl_pipeline_progend_glsl_get_tex_coord_attribute (CoglPipeline *pipeline,
 }
 
 static void
-clear_attribute_cache (CoglPipelineProgendPrivate *priv)
+clear_attribute_cache (CoglPipelineProgramState *program_state)
 {
-  priv->position_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
-  priv->color_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
-  priv->normal_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
-  priv->tex_coord0_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
-  if (priv->tex_coord_attribute_locations)
+  program_state->position_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
+  program_state->color_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
+  program_state->normal_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
+  program_state->tex_coord0_attribute_location = ATTRIBUTE_LOCATION_UNKNOWN;
+  if (program_state->tex_coord_attribute_locations)
     {
-      g_array_free (priv->tex_coord_attribute_locations, TRUE);
-      priv->tex_coord_attribute_locations = NULL;
+      g_array_free (program_state->tex_coord_attribute_locations, TRUE);
+      program_state->tex_coord_attribute_locations = NULL;
     }
 }
 
 static void
-clear_flushed_matrix_stacks (CoglPipelineProgendPrivate *priv)
+clear_flushed_matrix_stacks (CoglPipelineProgramState *program_state)
 {
-  if (priv->flushed_modelview_stack)
+  if (program_state->flushed_modelview_stack)
     {
-      cogl_object_unref (priv->flushed_modelview_stack);
-      priv->flushed_modelview_stack = NULL;
+      cogl_object_unref (program_state->flushed_modelview_stack);
+      program_state->flushed_modelview_stack = NULL;
     }
-  if (priv->flushed_projection_stack)
+  if (program_state->flushed_projection_stack)
     {
-      cogl_object_unref (priv->flushed_projection_stack);
-      priv->flushed_projection_stack = NULL;
+      cogl_object_unref (program_state->flushed_projection_stack);
+      program_state->flushed_projection_stack = NULL;
     }
-  priv->flushed_modelview_is_identity = FALSE;
+  program_state->flushed_modelview_is_identity = FALSE;
 }
 
 #endif /* HAVE_COGL_GLES2 */
 
+static CoglPipelineProgramState *
+program_state_new (int n_layers)
+{
+  CoglPipelineProgramState *program_state;
+
+  program_state = g_slice_new (CoglPipelineProgramState);
+  program_state->ref_count = 1;
+  program_state->program = 0;
+  program_state->n_tex_coord_attribs = 0;
+  program_state->unit_state = g_new (UnitState, n_layers);
+#ifdef HAVE_COGL_GLES2
+  program_state->tex_coord_attribute_locations = NULL;
+  program_state->flushed_modelview_stack = NULL;
+  program_state->flushed_modelview_is_identity = FALSE;
+  program_state->flushed_projection_stack = NULL;
+#endif
+
+  return program_state;
+}
+
 static void
-destroy_glsl_priv (void *user_data)
+destroy_program_state (void *user_data)
 {
-  CoglPipelineProgendPrivate *priv = user_data;
+  CoglPipelineProgramState *program_state = user_data;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  if (--priv->ref_count == 0)
+  if (--program_state->ref_count == 0)
     {
 #ifdef HAVE_COGL_GLES2
       if (ctx->driver == COGL_DRIVER_GLES2)
         {
-          clear_attribute_cache (priv);
-          clear_flushed_matrix_stacks (priv);
+          clear_attribute_cache (program_state);
+          clear_flushed_matrix_stacks (program_state);
         }
 #endif
 
-      if (priv->program)
-        GE( ctx, glDeleteProgram (priv->program) );
+      if (program_state->program)
+        GE( ctx, glDeleteProgram (program_state->program) );
 
-      g_free (priv->unit_state);
+      g_free (program_state->unit_state);
 
-      g_slice_free (CoglPipelineProgendPrivate, priv);
+      g_slice_free (CoglPipelineProgramState, program_state);
     }
 }
 
 static void
-set_glsl_priv (CoglPipeline *pipeline, CoglPipelineProgendPrivate *priv)
+set_program_state (CoglPipeline *pipeline,
+                  CoglPipelineProgramState *program_state)
 {
   cogl_object_set_user_data (COGL_OBJECT (pipeline),
-                             &glsl_priv_key,
-                             priv,
-                             destroy_glsl_priv);
+                             &program_state_key,
+                             program_state,
+                             destroy_program_state);
 }
 
 static void
-dirty_glsl_program_state (CoglPipeline *pipeline)
+dirty_program_state (CoglPipeline *pipeline)
 {
   cogl_object_set_user_data (COGL_OBJECT (pipeline),
-                             &glsl_priv_key,
+                             &program_state_key,
                              NULL,
-                             destroy_glsl_priv);
+                             NULL);
 }
 
 static void
@@ -371,7 +397,7 @@ typedef struct
   int unit;
   GLuint gl_program;
   gboolean update_all;
-  CoglPipelineProgendPrivate *priv;
+  CoglPipelineProgramState *program_state;
 } UpdateUniformsState;
 
 static gboolean
@@ -380,8 +406,8 @@ get_uniform_cb (CoglPipeline *pipeline,
                 void *user_data)
 {
   UpdateUniformsState *state = user_data;
-  CoglPipelineProgendPrivate *priv = state->priv;
-  UnitState *unit_state = &priv->unit_state[state->unit];
+  CoglPipelineProgramState *program_state = state->program_state;
+  UnitState *unit_state = &program_state->unit_state[state->unit];
   GLint uniform_location;
 
   _COGL_GET_CONTEXT (ctx, FALSE);
@@ -439,8 +465,8 @@ update_constants_cb (CoglPipeline *pipeline,
                      void *user_data)
 {
   UpdateUniformsState *state = user_data;
-  CoglPipelineProgendPrivate *priv = state->priv;
-  UnitState *unit_state = &priv->unit_state[state->unit++];
+  CoglPipelineProgramState *program_state = state->program_state;
+  UnitState *unit_state = &program_state->unit_state[state->unit++];
 
   _COGL_GET_CONTEXT (ctx, FALSE);
 
@@ -482,21 +508,22 @@ update_constants_cb (CoglPipeline *pipeline,
 static void
 update_builtin_uniforms (CoglPipeline *pipeline,
                          GLuint gl_program,
-                         CoglPipelineProgendPrivate *priv)
+                         CoglPipelineProgramState *program_state)
 {
   int i;
 
-  if (priv->dirty_builtin_uniforms == 0)
+  if (program_state->dirty_builtin_uniforms == 0)
     return;
 
   for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
-    if ((priv->dirty_builtin_uniforms & (1 << i)) &&
-        priv->builtin_uniform_locations[i] != -1)
+    if ((program_state->dirty_builtin_uniforms & (1 << i)) &&
+        program_state->builtin_uniform_locations[i] != -1)
       builtin_uniforms[i].update_func (pipeline,
-                                       priv->builtin_uniform_locations[i],
+                                       program_state
+                                       ->builtin_uniform_locations[i],
                                        builtin_uniforms[i].getter_func);
 
-  priv->dirty_builtin_uniforms = 0;
+  program_state->dirty_builtin_uniforms = 0;
 }
 
 #endif /* HAVE_COGL_GLES2 */
@@ -506,7 +533,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
                                  unsigned long pipelines_difference,
                                  int n_tex_coord_attribs)
 {
-  CoglPipelineProgendPrivate *priv;
+  CoglPipelineProgramState *program_state;
   GLuint gl_program;
   gboolean program_changed = FALSE;
   UpdateUniformsState state;
@@ -520,11 +547,11 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
       pipeline->vertend != COGL_PIPELINE_VERTEND_GLSL)
     return;
 
-  priv = get_glsl_priv (pipeline);
+  program_state = get_program_state (pipeline);
 
   user_program = cogl_pipeline_get_user_program (pipeline);
 
-  if (priv == NULL)
+  if (program_state == NULL)
     {
       CoglPipeline *authority;
 
@@ -539,29 +566,19 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
          _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx) |
          COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);
 
-      priv = get_glsl_priv (authority);
+      program_state = get_program_state (authority);
 
-      if (priv == NULL)
+      if (program_state == NULL)
         {
-          priv = g_slice_new (CoglPipelineProgendPrivate);
-          priv->ref_count = 1;
-          priv->program = 0;
-          priv->n_tex_coord_attribs = 0;
-          priv->unit_state = g_new (UnitState,
-                                    cogl_pipeline_get_n_layers (pipeline));
-#ifdef HAVE_COGL_GLES2
-          priv->tex_coord_attribute_locations = NULL;
-          priv->flushed_modelview_stack = NULL;
-          priv->flushed_modelview_is_identity = FALSE;
-          priv->flushed_projection_stack = NULL;
-#endif
-          set_glsl_priv (authority, priv);
+          program_state
+            = program_state_new (cogl_pipeline_get_n_layers (pipeline));
+          set_program_state (authority, program_state);
         }
 
       if (authority != pipeline)
         {
-          priv->ref_count++;
-          set_glsl_priv (pipeline, priv);
+          program_state->ref_count++;
+          set_program_state (pipeline, program_state);
         }
     }
 
@@ -571,26 +588,26 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
    * Also if the number of texture coordinate attributes in use has
    * increased, then delete the program so we can prepend a new
    * _cogl_tex_coord[] varying array declaration. */
-  if (priv->program && user_program &&
-      (user_program->age != priv->user_program_age ||
-       n_tex_coord_attribs > priv->n_tex_coord_attribs))
+  if (program_state->program && user_program &&
+      (user_program->age != program_state->user_program_age ||
+       n_tex_coord_attribs > program_state->n_tex_coord_attribs))
     {
-      GE( ctx, glDeleteProgram (priv->program) );
-      priv->program = 0;
+      GE( ctx, glDeleteProgram (program_state->program) );
+      program_state->program = 0;
     }
 
-  if (priv->program == 0)
+  if (program_state->program == 0)
     {
       GLuint backend_shader;
       GSList *l;
 
-      GE_RET( priv->program, ctx, glCreateProgram () );
+      GE_RET( program_state->program, ctx, glCreateProgram () );
 
       /* Attach all of the shader from the user program */
       if (user_program)
         {
-          if (priv->n_tex_coord_attribs > n_tex_coord_attribs)
-            n_tex_coord_attribs = priv->n_tex_coord_attribs;
+          if (program_state->n_tex_coord_attribs > n_tex_coord_attribs)
+            n_tex_coord_attribs = program_state->n_tex_coord_attribs;
 
 #ifdef HAVE_COGL_GLES2
           /* Find the largest count of texture coordinate attributes
@@ -614,29 +631,29 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
 
               g_assert (shader->language == COGL_SHADER_LANGUAGE_GLSL);
 
-              GE( ctx, glAttachShader (priv->program,
+              GE( ctx, glAttachShader (program_state->program,
                                        shader->gl_handle) );
             }
 
-          priv->user_program_age = user_program->age;
+          program_state->user_program_age = user_program->age;
         }
 
       /* Attach any shaders from the GLSL backends */
       if (pipeline->fragend == COGL_PIPELINE_FRAGEND_GLSL &&
           (backend_shader = _cogl_pipeline_fragend_glsl_get_shader (pipeline)))
-        GE( ctx, glAttachShader (priv->program, backend_shader) );
+        GE( ctx, glAttachShader (program_state->program, backend_shader) );
       if (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL &&
           (backend_shader = _cogl_pipeline_vertend_glsl_get_shader (pipeline)))
-        GE( ctx, glAttachShader (priv->program, backend_shader) );
+        GE( ctx, glAttachShader (program_state->program, backend_shader) );
 
-      link_program (priv->program);
+      link_program (program_state->program);
 
       program_changed = TRUE;
 
-      priv->n_tex_coord_attribs = n_tex_coord_attribs;
+      program_state->n_tex_coord_attribs = n_tex_coord_attribs;
     }
 
-  gl_program = priv->program;
+  gl_program = program_state->program;
 
   if (pipeline->fragend == COGL_PIPELINE_FRAGEND_GLSL)
     _cogl_use_fragment_program (gl_program, COGL_PIPELINE_PROGRAM_TYPE_GLSL);
@@ -645,7 +662,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
 
   state.unit = 0;
   state.gl_program = gl_program;
-  state.priv = priv;
+  state.program_state = program_state;
 
   if (program_changed)
     cogl_pipeline_foreach_layer (pipeline,
@@ -654,7 +671,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
 
   state.unit = 0;
   state.update_all = (program_changed ||
-                      priv->last_used_for_pipeline != pipeline);
+                      program_state->last_used_for_pipeline != pipeline);
 
   cogl_pipeline_foreach_layer (pipeline,
                                update_constants_cb,
@@ -667,33 +684,31 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
         {
           int i;
 
-          clear_attribute_cache (priv);
-          clear_flushed_matrix_stacks (priv);
+          clear_attribute_cache (program_state);
+          clear_flushed_matrix_stacks (program_state);
 
           for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
-            GE_RET( priv->builtin_uniform_locations[i],
-                    ctx,
+            GE_RET( program_state->builtin_uniform_locations[i], ctx,
                     glGetUniformLocation (gl_program,
                                           builtin_uniforms[i].uniform_name) );
 
-          GE_RET( priv->modelview_uniform,
-                  ctx, glGetUniformLocation (gl_program,
-                                             "cogl_modelview_matrix") );
+          GE_RET( program_state->modelview_uniform, ctx,
+                  glGetUniformLocation (gl_program,
+                                        "cogl_modelview_matrix") );
 
-          GE_RET( priv->projection_uniform,
-                  ctx, glGetUniformLocation (gl_program,
-                                             "cogl_projection_matrix") );
+          GE_RET( program_state->projection_uniform, ctx,
+                  glGetUniformLocation (gl_program,
+                                        "cogl_projection_matrix") );
 
-          GE_RET( priv->mvp_uniform,
-                  ctx,
+          GE_RET( program_state->mvp_uniform, ctx,
                   glGetUniformLocation (gl_program,
                                         "cogl_modelview_projection_matrix") );
         }
       if (program_changed ||
-          priv->last_used_for_pipeline != pipeline)
-        priv->dirty_builtin_uniforms = ~(unsigned long) 0;
+          program_state->last_used_for_pipeline != pipeline)
+        program_state->dirty_builtin_uniforms = ~(unsigned long) 0;
 
-      update_builtin_uniforms (pipeline, gl_program, priv);
+      update_builtin_uniforms (pipeline, gl_program, program_state);
     }
 #endif
 
@@ -704,7 +719,7 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
 
   /* We need to track the last pipeline that the program was used with
    * so know if we need to update all of the uniforms */
-  priv->last_used_for_pipeline = pipeline;
+  program_state->last_used_for_pipeline = pipeline;
 }
 
 static void
@@ -715,7 +730,8 @@ _cogl_pipeline_progend_glsl_pre_change_notify (CoglPipeline *pipeline,
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
   if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
-    dirty_glsl_program_state (pipeline);
+    dirty_program_state (pipeline);
+
 #ifdef HAVE_COGL_GLES2
   else if (ctx->driver == COGL_DRIVER_GLES2)
     {
@@ -724,9 +740,10 @@ _cogl_pipeline_progend_glsl_pre_change_notify (CoglPipeline *pipeline,
       for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
         if ((change & builtin_uniforms[i].change))
           {
-            CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
-            if (priv)
-              priv->dirty_builtin_uniforms |= 1 << i;
+            CoglPipelineProgramState *program_state
+              = get_program_state (pipeline);
+            if (program_state)
+              program_state->dirty_builtin_uniforms |= 1 << i;
             return;
           }
     }
@@ -751,27 +768,27 @@ _cogl_pipeline_progend_glsl_layer_pre_change_notify (
 
   if ((change & _cogl_pipeline_get_state_for_fragment_codegen (ctx)))
     {
-      dirty_glsl_program_state (owner);
+      dirty_program_state (owner);
       return;
     }
 
   if (change & COGL_PIPELINE_LAYER_STATE_COMBINE_CONSTANT)
     {
-      CoglPipelineProgendPrivate *priv = get_glsl_priv (owner);
-      if (priv)
+      CoglPipelineProgramState *program_state = get_program_state (owner);
+      if (program_state)
         {
           int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
-          priv->unit_state[unit_index].dirty_combine_constant = TRUE;
+          program_state->unit_state[unit_index].dirty_combine_constant = TRUE;
         }
     }
 
   if (change & COGL_PIPELINE_LAYER_STATE_USER_MATRIX)
     {
-      CoglPipelineProgendPrivate *priv = get_glsl_priv (owner);
-      if (priv)
+      CoglPipelineProgramState *program_state = get_program_state (owner);
+      if (program_state)
         {
           int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
-          priv->unit_state[unit_index].dirty_texture_matrix = TRUE;
+          program_state->unit_state[unit_index].dirty_texture_matrix = TRUE;
         }
     }
 }
@@ -783,11 +800,11 @@ flush_modelview_cb (gboolean is_identity,
                     const CoglMatrix *matrix,
                     void *user_data)
 {
-  CoglPipelineProgendPrivate *priv = user_data;
+  CoglPipelineProgramState *program_state = user_data;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  GE( ctx, glUniformMatrix4fv (priv->modelview_uniform, 1, FALSE,
+  GE( ctx, glUniformMatrix4fv (program_state->modelview_uniform, 1, FALSE,
                                cogl_matrix_get_array (matrix)) );
 }
 
@@ -796,17 +813,17 @@ flush_projection_cb (gboolean is_identity,
                     const CoglMatrix *matrix,
                     void *user_data)
 {
-  CoglPipelineProgendPrivate *priv = user_data;
+  CoglPipelineProgramState *program_state = user_data;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  GE( ctx, glUniformMatrix4fv (priv->projection_uniform, 1, FALSE,
+  GE( ctx, glUniformMatrix4fv (program_state->projection_uniform, 1, FALSE,
                                cogl_matrix_get_array (matrix)) );
 }
 
 typedef struct
 {
-  CoglPipelineProgendPrivate *priv;
+  CoglPipelineProgramState *program_state;
   const CoglMatrix *projection_matrix;
 } FlushCombinedData;
 
@@ -825,7 +842,8 @@ flush_combined_step_two_cb (gboolean is_identity,
   if (is_identity)
     {
       const float *array = cogl_matrix_get_array (data->projection_matrix);
-      GE( ctx, glUniformMatrix4fv (data->priv->mvp_uniform, 1, FALSE, array ) );
+      GE( ctx, glUniformMatrix4fv (data->program_state->mvp_uniform,
+                                   1, FALSE, array ) );
     }
   else
     {
@@ -833,7 +851,7 @@ flush_combined_step_two_cb (gboolean is_identity,
                             data->projection_matrix,
                             matrix);
 
-      GE( ctx, glUniformMatrix4fv (data->priv->mvp_uniform, 1, FALSE,
+      GE( ctx, glUniformMatrix4fv (data->program_state->mvp_uniform, 1, FALSE,
                                    cogl_matrix_get_array (&mvp_matrix)) );
     }
 }
@@ -847,7 +865,7 @@ flush_combined_step_one_cb (gboolean is_identity,
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  data.priv = user_data;
+  data.program_state = user_data;
   data.projection_matrix = matrix;
 
   _cogl_matrix_stack_prepare_for_flush (ctx->flushed_modelview_stack,
@@ -859,7 +877,7 @@ flush_combined_step_one_cb (gboolean is_identity,
 static void
 _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
 {
-  CoglPipelineProgendPrivate *priv = get_glsl_priv (pipeline);
+  CoglPipelineProgramState *program_state = get_program_state (pipeline);
   gboolean modelview_changed;
   gboolean projection_changed;
 
@@ -872,7 +890,7 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
      vertend, but this is a requirement on GLES2 anyway */
   g_return_if_fail (pipeline->vertend == COGL_PIPELINE_VERTEND_GLSL);
 
-  priv = get_glsl_priv (pipeline);
+  program_state = get_program_state (pipeline);
 
   /* An initial pipeline is flushed while creating the context. At
      this point there are no matrices flushed so we can't do
@@ -885,59 +903,62 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
      the identity matrix so it makes sense to optimise this case by
      specifically checking whether we already have the identity matrix
      which will catch a lot of common cases of redundant flushing */
-  if (priv->flushed_modelview_is_identity &&
+  if (program_state->flushed_modelview_is_identity &&
       _cogl_matrix_stack_has_identity_flag (ctx->flushed_modelview_stack))
     modelview_changed = FALSE;
   else
     modelview_changed =
-      priv->flushed_modelview_stack != ctx->flushed_modelview_stack ||
-      priv->flushed_modelview_stack_age !=
-      _cogl_matrix_stack_get_age (priv->flushed_modelview_stack);
+      program_state->flushed_modelview_stack != ctx->flushed_modelview_stack ||
+      program_state->flushed_modelview_stack_age !=
+      _cogl_matrix_stack_get_age (program_state->flushed_modelview_stack);
 
   projection_changed =
-    priv->flushed_projection_stack != ctx->flushed_projection_stack ||
-    priv->flushed_projection_stack_age !=
-    _cogl_matrix_stack_get_age (priv->flushed_projection_stack);
+    program_state->flushed_projection_stack != ctx->flushed_projection_stack ||
+    program_state->flushed_projection_stack_age !=
+    _cogl_matrix_stack_get_age (program_state->flushed_projection_stack);
 
   if (modelview_changed)
     {
       cogl_object_ref (ctx->flushed_modelview_stack);
-      if (priv->flushed_modelview_stack)
-        cogl_object_unref (priv->flushed_modelview_stack);
-      priv->flushed_modelview_stack = ctx->flushed_modelview_stack;
-      priv->flushed_modelview_stack_age =
+      if (program_state->flushed_modelview_stack)
+        cogl_object_unref (program_state->flushed_modelview_stack);
+      program_state->flushed_modelview_stack = ctx->flushed_modelview_stack;
+      program_state->flushed_modelview_stack_age =
         _cogl_matrix_stack_get_age (ctx->flushed_modelview_stack);
-      priv->flushed_modelview_is_identity =
+      program_state->flushed_modelview_is_identity =
         _cogl_matrix_stack_has_identity_flag (ctx->flushed_modelview_stack);
 
-      if (priv->modelview_uniform != -1)
-        _cogl_matrix_stack_prepare_for_flush (priv->flushed_modelview_stack,
+      if (program_state->modelview_uniform != -1)
+        _cogl_matrix_stack_prepare_for_flush (program_state
+                                              ->flushed_modelview_stack,
                                               COGL_MATRIX_MODELVIEW,
                                               flush_modelview_cb,
-                                              priv);
+                                              program_state);
     }
 
   if (projection_changed)
     {
       cogl_object_ref (ctx->flushed_projection_stack);
-      if (priv->flushed_projection_stack)
-        cogl_object_unref (priv->flushed_projection_stack);
-      priv->flushed_projection_stack = ctx->flushed_projection_stack;
-      priv->flushed_projection_stack_age =
+      if (program_state->flushed_projection_stack)
+        cogl_object_unref (program_state->flushed_projection_stack);
+      program_state->flushed_projection_stack = ctx->flushed_projection_stack;
+      program_state->flushed_projection_stack_age =
         _cogl_matrix_stack_get_age (ctx->flushed_projection_stack);
 
-      if (priv->projection_uniform != -1)
-        _cogl_matrix_stack_prepare_for_flush (priv->flushed_projection_stack,
+      if (program_state->projection_uniform != -1)
+        _cogl_matrix_stack_prepare_for_flush (program_state
+                                              ->flushed_projection_stack,
                                               COGL_MATRIX_PROJECTION,
                                               flush_projection_cb,
-                                              priv);
+                                              program_state);
     }
 
-  if (priv->mvp_uniform != -1 && (modelview_changed || projection_changed))
+  if (program_state->mvp_uniform != -1 &&
+      (modelview_changed || projection_changed))
     _cogl_matrix_stack_prepare_for_flush (ctx->flushed_projection_stack,
                                           COGL_MATRIX_PROJECTION,
                                           flush_combined_step_one_cb,
-                                          priv);
+                                          program_state);
 }
 
 static void
diff --git a/cogl/cogl-pipeline-vertend-glsl.c b/cogl/cogl-pipeline-vertend-glsl.c
index f13eceb..74fc9a8 100644
--- a/cogl/cogl-pipeline-vertend-glsl.c
+++ b/cogl/cogl-pipeline-vertend-glsl.c
@@ -55,57 +55,69 @@ typedef struct
      program changes then we may need to redecide whether to generate
      a shader at all */
   unsigned int user_program_age;
-} CoglPipelineVertendPrivate;
+} CoglPipelineShaderState;
 
-static CoglUserDataKey glsl_priv_key;
+static CoglUserDataKey shader_state_key;
 
-static CoglPipelineVertendPrivate *
-get_glsl_priv (CoglPipeline *pipeline)
+static CoglPipelineShaderState *
+shader_state_new (void)
 {
-  return cogl_object_get_user_data (COGL_OBJECT (pipeline), &glsl_priv_key);
+  CoglPipelineShaderState *shader_state;
+
+  shader_state = g_slice_new0 (CoglPipelineShaderState);
+  shader_state->ref_count = 1;
+
+  return shader_state;
+}
+
+static CoglPipelineShaderState *
+get_shader_state (CoglPipeline *pipeline)
+{
+  return cogl_object_get_user_data (COGL_OBJECT (pipeline), &shader_state_key);
 }
 
 static void
-destroy_glsl_priv (void *user_data)
+destroy_shader_state (void *user_data)
 {
-  CoglPipelineVertendPrivate *priv = user_data;
+  CoglPipelineShaderState *shader_state = user_data;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  if (--priv->ref_count == 0)
+  if (--shader_state->ref_count == 0)
     {
-      if (priv->gl_shader)
-        GE( ctx, glDeleteShader (priv->gl_shader) );
+      if (shader_state->gl_shader)
+        GE( ctx, glDeleteShader (shader_state->gl_shader) );
 
-      g_slice_free (CoglPipelineVertendPrivate, priv);
+      g_slice_free (CoglPipelineShaderState, shader_state);
     }
 }
 
 static void
-set_glsl_priv (CoglPipeline *pipeline, CoglPipelineVertendPrivate *priv)
+set_shader_state (CoglPipeline *pipeline,
+                  CoglPipelineShaderState *shader_state)
 {
   cogl_object_set_user_data (COGL_OBJECT (pipeline),
-                             &glsl_priv_key,
-                             priv,
-                             destroy_glsl_priv);
+                             &shader_state_key,
+                             shader_state,
+                             destroy_shader_state);
 }
 
 static void
-dirty_glsl_shader_state (CoglPipeline *pipeline)
+dirty_shader_state (CoglPipeline *pipeline)
 {
   cogl_object_set_user_data (COGL_OBJECT (pipeline),
-                             &glsl_priv_key,
+                             &shader_state_key,
                              NULL,
-                             destroy_glsl_priv);
+                             NULL);
 }
 
 GLuint
 _cogl_pipeline_vertend_glsl_get_shader (CoglPipeline *pipeline)
 {
-  CoglPipelineVertendPrivate *priv = get_glsl_priv (pipeline);
+  CoglPipelineShaderState *shader_state = get_shader_state (pipeline);
 
-  if (priv)
-    return priv->gl_shader;
+  if (shader_state)
+    return shader_state->gl_shader;
   else
     return 0;
 }
@@ -115,7 +127,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
                                    int n_layers,
                                    unsigned long pipelines_difference)
 {
-  CoglPipelineVertendPrivate *priv;
+  CoglPipelineShaderState *shader_state;
   CoglProgram *user_program;
 
   _COGL_GET_CONTEXT (ctx, FALSE);
@@ -134,9 +146,9 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
 
   /* Now lookup our glsl backend private state (allocating if
    * necessary) */
-  priv = get_glsl_priv (pipeline);
+  shader_state = get_shader_state (pipeline);
 
-  if (priv == NULL)
+  if (shader_state == NULL)
     {
       CoglPipeline *authority;
 
@@ -148,42 +160,41 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
          ~COGL_PIPELINE_STATE_LAYERS,
          COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN);
 
-      priv = get_glsl_priv (authority);
+      shader_state = get_shader_state (authority);
 
-      if (priv == NULL)
+      if (shader_state == NULL)
         {
-          priv = g_slice_new0 (CoglPipelineVertendPrivate);
-          priv->ref_count = 1;
-          set_glsl_priv (authority, priv);
+          shader_state = shader_state_new ();
+          set_shader_state (authority, shader_state);
         }
 
       if (authority != pipeline)
         {
-          priv->ref_count++;
-          set_glsl_priv (pipeline, priv);
+          shader_state->ref_count++;
+          set_shader_state (pipeline, shader_state);
         }
     }
 
-  if (priv->gl_shader)
+  if (shader_state->gl_shader)
     {
       /* If we already have a valid GLSL shader then we don't need to
          generate a new one. However if there's a user program and it
          has changed since the last link then we do need a new shader */
       if (user_program == NULL ||
-          priv->user_program_age == user_program->age)
+          shader_state->user_program_age == user_program->age)
         return TRUE;
 
       /* We need to recreate the shader so destroy the existing one */
-      GE( ctx, glDeleteShader (priv->gl_shader) );
-      priv->gl_shader = 0;
+      GE( ctx, glDeleteShader (shader_state->gl_shader) );
+      shader_state->gl_shader = 0;
     }
 
-  /* If we make it here then we have a priv struct without a gl_shader
+  /* If we make it here then we have a shader_state struct without a gl_shader
      either because this is the first time we've encountered it or
      because the user program has changed */
 
   if (user_program)
-    priv->user_program_age = user_program->age;
+    shader_state->user_program_age = user_program->age;
 
   /* If the user program contains a vertex shader then we don't need
      to generate one */
@@ -198,10 +209,10 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
      add_layer callback is invoked */
   g_string_set_size (ctx->codegen_header_buffer, 0);
   g_string_set_size (ctx->codegen_source_buffer, 0);
-  priv->header = ctx->codegen_header_buffer;
-  priv->source = ctx->codegen_source_buffer;
+  shader_state->header = ctx->codegen_header_buffer;
+  shader_state->source = ctx->codegen_source_buffer;
 
-  g_string_append (priv->source,
+  g_string_append (shader_state->source,
                    "void\n"
                    "main ()\n"
                    "{\n");
@@ -209,7 +220,7 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
   if (ctx->driver == COGL_DRIVER_GLES2)
     /* There is no builtin uniform for the pointsize on GLES2 so we need
        to copy it from the custom uniform in the vertex shader */
-    g_string_append (priv->source,
+    g_string_append (shader_state->source,
                      "  cogl_point_size_out = cogl_point_size_in;\n");
   /* On regular OpenGL we'll just flush the point size builtin */
   else if (pipelines_difference & COGL_PIPELINE_STATE_POINT_SIZE)
@@ -232,12 +243,12 @@ _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
                                        CoglPipelineLayer *layer,
                                        unsigned long layers_difference)
 {
-  CoglPipelineVertendPrivate *priv;
+  CoglPipelineShaderState *shader_state;
   int unit_index;
 
   _COGL_GET_CONTEXT (ctx, FALSE);
 
-  priv = get_glsl_priv (pipeline);
+  shader_state = get_shader_state (pipeline);
 
   unit_index = _cogl_pipeline_layer_get_unit_index (layer);
 
@@ -263,7 +274,7 @@ _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
         }
     }
 
-  if (priv->source == NULL)
+  if (shader_state->source == NULL)
     return TRUE;
 
   /* Transform the texture coordinates by the layer's user matrix.
@@ -277,7 +288,7 @@ _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
    * avoid setting them if not
    */
 
-  g_string_append_printf (priv->source,
+  g_string_append_printf (shader_state->source,
                           "  cogl_tex_coord_out[%i] = "
                           "cogl_texture_matrix[%i] * cogl_tex_coord%i_in;\n",
                           unit_index, unit_index, unit_index);
@@ -289,13 +300,13 @@ static gboolean
 _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
                                  unsigned long pipelines_difference)
 {
-  CoglPipelineVertendPrivate *priv;
+  CoglPipelineShaderState *shader_state;
 
   _COGL_GET_CONTEXT (ctx, FALSE);
 
-  priv = get_glsl_priv (pipeline);
+  shader_state = get_shader_state (pipeline);
 
-  if (priv->source)
+  if (shader_state->source)
     {
       const char *source_strings[2];
       GLint lengths[2];
@@ -310,7 +321,7 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
                            0 /* no application private data */);
       COGL_COUNTER_INC (_cogl_uprof_context, vertend_glsl_compile_counter);
 
-      g_string_append (priv->source,
+      g_string_append (shader_state->source,
                        "  cogl_position_out = "
                        "cogl_modelview_projection_matrix * "
                        "cogl_position_in;\n"
@@ -319,10 +330,10 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
 
       GE_RET( shader, ctx, glCreateShader (GL_VERTEX_SHADER) );
 
-      lengths[0] = priv->header->len;
-      source_strings[0] = priv->header->str;
-      lengths[1] = priv->source->len;
-      source_strings[1] = priv->source->str;
+      lengths[0] = shader_state->header->len;
+      source_strings[0] = shader_state->header->str;
+      lengths[1] = shader_state->source->len;
+      source_strings[1] = shader_state->source->str;
 
       n_layers = cogl_pipeline_get_n_layers (pipeline);
 
@@ -345,9 +356,9 @@ _cogl_pipeline_vertend_glsl_end (CoglPipeline *pipeline,
           g_warning ("Shader compilation failed:\n%s", shader_log);
         }
 
-      priv->header = NULL;
-      priv->source = NULL;
-      priv->gl_shader = shader;
+      shader_state->header = NULL;
+      shader_state->source = NULL;
+      shader_state->gl_shader = shader;
     }
 
   return TRUE;
@@ -359,7 +370,7 @@ _cogl_pipeline_vertend_glsl_pre_change_notify (CoglPipeline *pipeline,
                                                const CoglColor *new_color)
 {
   if ((change & COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN))
-    dirty_glsl_shader_state (pipeline);
+    dirty_shader_state (pipeline);
 }
 
 /* NB: layers are considered immutable once they have any dependants
@@ -376,15 +387,15 @@ _cogl_pipeline_vertend_glsl_layer_pre_change_notify (
                                                 CoglPipelineLayer *layer,
                                                 CoglPipelineLayerState change)
 {
-  CoglPipelineVertendPrivate *priv;
+  CoglPipelineShaderState *shader_state;
 
-  priv = get_glsl_priv (owner);
-  if (!priv)
+  shader_state = get_shader_state (owner);
+  if (!shader_state)
     return;
 
   if ((change & COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN))
     {
-      dirty_glsl_shader_state (owner);
+      dirty_shader_state (owner);
       return;
     }
 
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c
index 739036b..f84c2ac 100644
--- a/cogl/cogl-pipeline.c
+++ b/cogl/cogl-pipeline.c
@@ -447,7 +447,6 @@ _cogl_pipeline_copy (CoglPipeline *src, gboolean is_weak)
   pipeline->deprecated_get_layers_list_dirty = TRUE;
 
   pipeline->fragend = src->fragend;
-  pipeline->fragend_priv_set_mask = 0;
 
   pipeline->vertend = src->vertend;
 
@@ -500,18 +499,6 @@ cogl_pipeline_new (void)
   return new;
 }
 
-static void
-_cogl_pipeline_fragend_free_priv (CoglPipeline *pipeline)
-{
-  if (pipeline->fragend != COGL_PIPELINE_FRAGEND_UNDEFINED &&
-      _cogl_pipeline_fragends[pipeline->fragend]->free_priv)
-    {
-      const CoglPipelineFragend *fragend =
-        _cogl_pipeline_fragends[pipeline->fragend];
-      fragend->free_priv (pipeline);
-    }
-}
-
 static gboolean
 destroy_weak_children_cb (CoglPipelineNode *node,
                           void *user_data)
@@ -544,8 +531,6 @@ _cogl_pipeline_free (CoglPipeline *pipeline)
 
   g_assert (COGL_LIST_EMPTY (&COGL_PIPELINE_NODE (pipeline)->children));
 
-  _cogl_pipeline_fragend_free_priv (pipeline);
-
   _cogl_pipeline_unparent (COGL_PIPELINE_NODE (pipeline));
 
   if (pipeline->differences & COGL_PIPELINE_STATE_USER_SHADER &&
@@ -967,7 +952,6 @@ _cogl_pipeline_needs_blending_enabled (CoglPipeline    *pipeline,
 void
 _cogl_pipeline_set_fragend (CoglPipeline *pipeline, int fragend)
 {
-  _cogl_pipeline_fragend_free_priv (pipeline);
   pipeline->fragend = fragend;
 }
 



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