[cogl/wip/virtual-framebuffer: 21/22] rework enabling of attributes, removing _cogl_enable()



commit 2469065904b76de2519b2709f1211fb0177fcce3
Author: Robert Bragg <robert linux intel com>
Date:   Thu Nov 24 18:09:53 2011 +0000

    rework enabling of attributes, removing _cogl_enable()

 cogl/cogl-attribute-private.h             |   23 +-
 cogl/cogl-attribute.c                     |  709 +++++++++++++----------------
 cogl/cogl-context-private.h               |   27 +-
 cogl/cogl-context.c                       |   37 ++-
 cogl/cogl-pipeline-opengl.c               |    4 +-
 cogl/cogl-pipeline-progend-glsl-private.h |   17 +-
 cogl/cogl-pipeline-progend-glsl.c         |  162 ++-----
 cogl/cogl.c                               |   66 ---
 8 files changed, 435 insertions(+), 610 deletions(-)
---
diff --git a/cogl/cogl-attribute-private.h b/cogl/cogl-attribute-private.h
index 040784e..68ed52d 100644
--- a/cogl/cogl-attribute-private.h
+++ b/cogl/cogl-attribute-private.h
@@ -40,19 +40,26 @@ typedef enum
   COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY
 } CoglAttributeNameID;
 
+typedef struct _CoglAttributeNameState
+{
+  char *name;
+  CoglAttributeNameID name_id;
+  int name_index;
+  gboolean normalized_default;
+  int texture_unit;
+} CoglAttributeNameState;
+
 struct _CoglAttribute
 {
   CoglObject _parent;
 
   CoglAttributeBuffer *attribute_buffer;
-  const char *name;
-  CoglAttributeNameID name_id;
+  const CoglAttributeNameState *name_state;
   gsize stride;
   gsize offset;
   int n_components;
   CoglAttributeType type;
   gboolean normalized;
-  unsigned int texture_unit;
 
   int immutable_ref;
 };
@@ -71,6 +78,16 @@ typedef enum
   COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE = 1 << 3
 } CoglDrawFlags;
 
+/* During CoglContext initialization we register the "cogl_color_in"
+ * attribute name so it gets a global name_index of 0. We need to know
+ * the name_index for "cogl_color_in" in
+ * _cogl_pipeline_flush_gl_state() */
+#define COGL_ATTRIBUTE_COLOR_NAME_INDEX 0
+
+CoglAttributeNameState *
+_cogl_attribute_register_attribute_name (CoglContext *context,
+                                         const char *name);
+
 CoglAttribute *
 _cogl_attribute_immutable_ref (CoglAttribute *attribute);
 
diff --git a/cogl/cogl-attribute.c b/cogl/cogl-attribute.c
index ad525f6..755cea7 100644
--- a/cogl/cogl-attribute.c
+++ b/cogl/cogl-attribute.c
@@ -59,80 +59,11 @@ static void _cogl_attribute_free (CoglAttribute *attribute);
 
 COGL_OBJECT_DEFINE (Attribute, attribute);
 
-#if 0
-gboolean
-validate_gl_attribute (const char *name,
-                       int n_components,
-                       CoglAttributeNameID *name_id,
-                       gboolean *normalized,
-                       unsigned int *texture_unit)
-{
-  name = name + 3; /* skip past "gl_" */
-
-  *normalized = FALSE;
-  *texture_unit = 0;
-
-  if (strcmp (name, "Vertex") == 0)
-    {
-      if (G_UNLIKELY (n_components == 1))
-        {
-          g_critical ("glVertexPointer doesn't allow 1 component vertex "
-                      "positions so we currently only support \"gl_Vertex\" "
-                      "attributes where n_components == 2, 3 or 4");
-          return FALSE;
-        }
-      *name_id = COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY;
-    }
-  else if (strcmp (name, "Color") == 0)
-    {
-      if (G_UNLIKELY (n_components != 3 && n_components != 4))
-        {
-          g_critical ("glColorPointer expects 3 or 4 component colors so we "
-                      "currently only support \"gl_Color\" attributes where "
-                      "n_components == 3 or 4");
-          return FALSE;
-        }
-      *name_id = COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY;
-      *normalized = TRUE;
-    }
-  else if (strncmp (name, "MultiTexCoord", strlen ("MultiTexCoord")) == 0)
-    {
-      if (sscanf (gl_attribute, "MultiTexCoord%u", texture_unit) != 1)
-	{
-	  g_warning ("gl_MultiTexCoord attributes should include a\n"
-		     "texture unit number, E.g. gl_MultiTexCoord0\n");
-	  unit = 0;
-	}
-      *name_id = COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY;
-    }
-  else if (strncmp (name, "Normal") == 0)
-    {
-      if (G_UNLIKELY (n_components != 3))
-        {
-          g_critical ("glNormalPointer expects 3 component normals so we "
-                      "currently only support \"gl_Normal\" attributes where "
-                      "n_components == 3");
-          return FALSE;
-        }
-      *name_id = COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY;
-      *normalized = TRUE;
-    }
-  else
-    {
-      g_warning ("Unknown gl_* attribute name gl_%s\n", name);
-      return FALSE;
-    }
-
-  return TRUE;
-}
-#endif
-
-gboolean
-validate_cogl_attribute (const char *name,
-                         int n_components,
-                         CoglAttributeNameID *name_id,
-                         gboolean *normalized,
-                         unsigned int *texture_unit)
+static gboolean
+validate_cogl_attribute_name (const char *name,
+                              CoglAttributeNameID *name_id,
+                              gboolean *normalized,
+                              int *texture_unit)
 {
   name = name + 5; /* skip "cogl_" */
 
@@ -140,27 +71,9 @@ validate_cogl_attribute (const char *name,
   *texture_unit = 0;
 
   if (strcmp (name, "position_in") == 0)
-    {
-      if (G_UNLIKELY (n_components == 1))
-        {
-          g_critical ("glVertexPointer doesn't allow 1 component vertex "
-                      "positions so we currently only support \"cogl_vertex\" "
-                      "attributes where n_components == 2, 3 or 4");
-          return FALSE;
-        }
-      *name_id = COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY;
-    }
+    *name_id = COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY;
   else if (strcmp (name, "color_in") == 0)
-    {
-      if (G_UNLIKELY (n_components != 3 && n_components != 4))
-        {
-          g_critical ("glColorPointer expects 3 or 4 component colors so we "
-                      "currently only support \"cogl_color\" attributes where "
-                      "n_components == 3 or 4");
-          return FALSE;
-        }
-      *name_id = COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY;
-    }
+    *name_id = COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY;
   else if (strcmp (name, "tex_coord_in") == 0)
     *name_id = COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY;
   else if (strncmp (name, "tex_coord", strlen ("tex_coord")) == 0)
@@ -178,13 +91,6 @@ validate_cogl_attribute (const char *name,
     }
   else if (strcmp (name, "normal_in") == 0)
     {
-      if (G_UNLIKELY (n_components != 3))
-        {
-          g_critical ("glNormalPointer expects 3 component normals so we "
-                      "currently only support \"cogl_normal\" attributes "
-                      "where n_components == 3");
-          return FALSE;
-        }
       *name_id = COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY;
       *normalized = TRUE;
     }
@@ -197,6 +103,49 @@ validate_cogl_attribute (const char *name,
   return TRUE;
 }
 
+CoglAttributeNameState *
+_cogl_attribute_register_attribute_name (CoglContext *context,
+                                         const char *name)
+{
+  CoglAttributeNameState *name_state = g_new (CoglAttributeNameState, 1);
+  int name_index = context->n_attribute_names++;
+
+  name_state->name = g_strdup (name);
+  name_state->name_index = name_index;
+  if (strncmp (name, "cogl_", 5) == 0)
+    {
+      if (!validate_cogl_attribute_name (name,
+                                         &name_state->name_id,
+                                         &name_state->normalized_default,
+                                         &name_state->texture_unit))
+      goto error;
+    }
+  else
+    {
+      name_state->name_id = COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY;
+      name_state->normalized_default = FALSE;
+      name_state->texture_unit = 0;
+    }
+
+  g_hash_table_insert (context->attribute_name_states_hash,
+                       name_state->name, name_state);
+
+  if (G_UNLIKELY (context->attribute_name_index_map == NULL))
+    context->attribute_name_index_map =
+      g_array_new (FALSE, FALSE, sizeof (void *));
+
+  g_array_set_size (context->attribute_name_index_map, name_index + 1);
+
+  g_array_index (context->attribute_name_index_map,
+                 CoglAttributeNameState *, name_index) = name_state;
+
+  return name_state;
+
+error:
+  g_free (name_state);
+  return NULL;
+}
+
 CoglAttribute *
 cogl_attribute_new (CoglAttributeBuffer *attribute_buffer,
                     const char *name,
@@ -206,8 +155,20 @@ cogl_attribute_new (CoglAttributeBuffer *attribute_buffer,
                     CoglAttributeType type)
 {
   CoglAttribute *attribute = g_slice_new (CoglAttribute);
-  gboolean status;
 
+  /* FIXME: retrieve the context from the buffer */
+  _COGL_GET_CONTEXT (ctx, NULL);
+
+  attribute->name_state =
+    g_hash_table_lookup (ctx->attribute_name_states_hash, name);
+  if (!attribute->name_state)
+    {
+      CoglAttributeNameState *name_state =
+        _cogl_attribute_register_attribute_name (ctx, name);
+      if (!name_state)
+        goto error;
+      attribute->name_state = name_state;
+    }
   attribute->attribute_buffer = cogl_object_ref (attribute_buffer);
   attribute->stride = stride;
   attribute->offset = offset;
@@ -215,71 +176,52 @@ cogl_attribute_new (CoglAttributeBuffer *attribute_buffer,
   attribute->type = type;
   attribute->immutable_ref = 0;
 
-  if (strncmp (name, "cogl_", 5) == 0)
+  if (attribute->name_state->name_id != COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY)
     {
-      const char *common_tex_coord_names[8] = {
-          "cogl_tex_coord0_in",
-          "cogl_tex_coord1_in",
-          "cogl_tex_coord2_in",
-          "cogl_tex_coord3_in",
-          "cogl_tex_coord4_in",
-          "cogl_tex_coord5_in",
-          "cogl_tex_coord6_in",
-          "cogl_tex_coord7_in"
-      };
-      status = validate_cogl_attribute (name,
-                                        n_components,
-                                        &attribute->name_id,
-                                        &attribute->normalized,
-                                        &attribute->texture_unit);
-
-      /* Avoid even the cost of g_intern_string() for the very common case
-       * attribute names...*/
-      switch (attribute->name_id)
+      switch (attribute->name_state->name_id)
         {
         case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
-          attribute->name = "cogl_position_in";
+          if (G_UNLIKELY (n_components == 1))
+            {
+              g_critical ("glVertexPointer doesn't allow 1 component vertex "
+                          "positions so we currently only support \"cogl_vertex\" "
+                          "attributes where n_components == 2, 3 or 4");
+              return FALSE;
+            }
           break;
         case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
-          attribute->name = "cogl_color_in";
+          if (G_UNLIKELY (n_components != 3 && n_components != 4))
+            {
+              g_critical ("glColorPointer expects 3 or 4 component colors so we "
+                          "currently only support \"cogl_color\" attributes where "
+                          "n_components == 3 or 4");
+              return FALSE;
+            }
           break;
         case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
-          if (attribute->texture_unit < 8)
-            attribute->name = common_tex_coord_names[attribute->texture_unit];
-          else
-            attribute->name = g_intern_string (name);
           break;
         case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
-          attribute->name = "cogl_normal_in";
+          if (G_UNLIKELY (n_components != 3))
+            {
+              g_critical ("glNormalPointer expects 3 component normals so we "
+                          "currently only support \"cogl_normal\" attributes "
+                          "where n_components == 3");
+              return FALSE;
+            }
           break;
         default:
           g_warn_if_reached ();
         }
+      attribute->normalized = attribute->name_state->normalized_default;
     }
-#if 0
-  else if (strncmp (name, "gl_", 3) == 0)
-    status = validate_gl_attribute (attribute->name,
-                                    n_components,
-                                    &attribute->name_id,
-                                    &attribute->normalized,
-                                    &attribute->texture_unit);
-#endif
   else
-    {
-      attribute->name = g_intern_string (name);
-      attribute->name_id = COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY;
-      attribute->normalized = FALSE;
-      attribute->texture_unit = 0;
-      status = TRUE;
-    }
-
-  if (!status)
-    {
-      _cogl_attribute_free (attribute);
-      return NULL;
-    }
+    attribute->normalized = FALSE;
 
   return _cogl_attribute_object_new (attribute);
+
+error:
+  _cogl_attribute_free (attribute);
+  return NULL;
 }
 
 gboolean
@@ -428,87 +370,238 @@ validated:
   return status;
 }
 
+typedef struct _ForeachChangedBitState
+{
+  CoglContext *context;
+  const CoglBitmask *new_bits;
+  CoglPipeline *pipeline;
+} ForeachChangedBitState;
+
 static gboolean
-toggle_enabled_cb (int bit_num, void *user_data)
+toggle_builtin_attribute_enabled_cb (int bit_num, void *user_data)
 {
-  const CoglBitmask *new_values = user_data;
-  gboolean enabled = _cogl_bitmask_get (new_values, bit_num);
+  ForeachChangedBitState *state = user_data;
+  gboolean enabled = _cogl_bitmask_get (state->new_bits, bit_num);
+  CoglContext *context = state->context;
+  GLenum cap;
 
-  _COGL_GET_CONTEXT (ctx, FALSE);
+  switch (bit_num)
+    {
+    case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
+      cap = GL_COLOR_ARRAY;
+      break;
+    case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
+      cap = GL_VERTEX_ARRAY;
+      break;
+    case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
+      cap = GL_NORMAL_ARRAY;
+      break;
+    }
+  if (enabled)
+    GE (context, glEnableClientState (cap));
+  else
+    GE (context, glDisableClientState (cap));
+
+  return TRUE;
+}
+
+static gboolean
+toggle_texcood_attribute_enabled_cb (int bit_num, void *user_data)
+{
+  ForeachChangedBitState *state = user_data;
+  gboolean enabled = _cogl_bitmask_get (state->new_bits, bit_num);
+  CoglContext *context = state->context;
+
+  GE( context, glClientActiveTexture (GL_TEXTURE0 + bit_num) );
+
+  if (enabled)
+    GE( context, glEnableClientState (GL_TEXTURE_COORD_ARRAY) );
+  else
+    GE( context, glDisableClientState (GL_TEXTURE_COORD_ARRAY) );
+
+  return TRUE;
+}
 
-  if (ctx->driver == COGL_DRIVER_GLES2)
+static gboolean
+toggle_custom_attribute_enabled_cb (int bit_num, void *user_data)
+{
+  ForeachChangedBitState *state = user_data;
+  gboolean enabled = _cogl_bitmask_get (state->new_bits, bit_num);
+  CoglContext *context = state->context;
+  int enable_location;
+  int disable_location;
+
+  if (enabled)
     {
-      if (enabled)
-        GE( ctx, glEnableVertexAttribArray (bit_num) );
-      else
-        GE( ctx, glDisableVertexAttribArray (bit_num) );
+      CoglPipeline *pipeline = state->pipeline;
+      CoglPipeline *prev_pipeline = context->current_pipeline;
+
+      enable_location =
+        _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, bit_num);
+
+      if (G_LIKELY (prev_pipeline))
+        {
+          disable_location =
+            _cogl_pipeline_progend_glsl_get_attrib_location (prev_pipeline,
+                                                             bit_num);
+
+          if (enable_location != disable_location)
+            GE( context, glDisableVertexAttribArray (disable_location) );
+        }
+
+      GE( context, glEnableVertexAttribArray (enable_location) );
     }
-#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
   else
     {
-      GE( ctx, glClientActiveTexture (GL_TEXTURE0 + bit_num) );
+      CoglPipeline *prev_pipeline = context->current_pipeline;
 
-      if (enabled)
-        GE( ctx, glEnableClientState (GL_TEXTURE_COORD_ARRAY) );
-      else
-        GE( ctx, glDisableClientState (GL_TEXTURE_COORD_ARRAY) );
+      /* XXX: we only expect ctx->current_pipeline to be NULL the
+       * first time we are flushing a pipeline so we should never need
+       * to be disabling anything in that case.
+       *
+       * If we later change things so ctx->current_pipeline can be
+       * NULL at other times then this code will be affected because
+       * we need a way of mapping a name_index to a GLSL program
+       * attribute location which is currently only possible via the
+       * CoglPipelineProgramState associated with the currently
+       * flushed pipeline. */
+      _COGL_RETURN_VAL_IF_FAIL (prev_pipeline != NULL, TRUE);
+
+      disable_location =
+        _cogl_pipeline_progend_glsl_get_attrib_location (prev_pipeline,
+                                                         bit_num);
+
+      GE( context, glDisableVertexAttribArray (disable_location) );
     }
-#endif
 
   return TRUE;
 }
 
 static void
-set_enabled_arrays (CoglBitmask *value_cache,
-                    const CoglBitmask *new_values)
+foreach_changed_bit_and_save (CoglContext *context,
+                              CoglBitmask *current_bits,
+                              const CoglBitmask *new_bits,
+                              CoglBitmaskForeachFunc callback,
+                              ForeachChangedBitState *state)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
   /* Get the list of bits that are different */
-  _cogl_bitmask_clear_all (&ctx->arrays_to_change);
-  _cogl_bitmask_set_bits (&ctx->arrays_to_change, value_cache);
-  _cogl_bitmask_xor_bits (&ctx->arrays_to_change, new_values);
+  _cogl_bitmask_clear_all (&context->changed_bits_tmp);
+  _cogl_bitmask_set_bits (&context->changed_bits_tmp, current_bits);
+  _cogl_bitmask_xor_bits (&context->changed_bits_tmp, new_bits);
 
   /* Iterate over each bit to change */
-  _cogl_bitmask_foreach (&ctx->arrays_to_change,
-                         toggle_enabled_cb,
-                         (void *) new_values);
+  state->new_bits = new_bits;
+  _cogl_bitmask_foreach (&context->changed_bits_tmp,
+                         callback,
+                         state);
 
   /* Store the new values */
-  _cogl_bitmask_clear_all (value_cache);
-  _cogl_bitmask_set_bits (value_cache, new_values);
+  _cogl_bitmask_clear_all (current_bits);
+  _cogl_bitmask_set_bits (current_bits, new_bits);
 }
 
-static CoglHandle
-enable_gl_state (CoglDrawFlags flags,
-                 CoglAttribute **attributes,
-                 int n_attributes,
-                 ValidateLayerState *state)
+static void
+setup_generic_attribute (CoglContext *context,
+                         CoglPipeline *pipeline,
+                         CoglAttribute *attribute,
+                         guint8 *base)
+{
+  int name_index = attribute->name_state->name_index;
+  int attrib_location =
+    _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, name_index);
+  if (attrib_location != -1)
+    {
+      GE( context, glVertexAttribPointer (attrib_location,
+                                          attribute->n_components,
+                                          attribute->type,
+                                          attribute->normalized,
+                                          attribute->stride,
+                                          base + attribute->offset) );
+      _cogl_bitmask_set (&context->enabled_custom_attributes,
+                         attrib_location, TRUE);
+    }
+}
+
+static void
+apply_attribute_enable_updates (CoglContext *context,
+                                CoglPipeline *pipeline)
+{
+  ForeachChangedBitState changed_bits_state;
+
+  changed_bits_state.context = context;
+  changed_bits_state.new_bits = &context->enable_builtin_attributes_tmp;
+  changed_bits_state.pipeline = pipeline;
+
+  foreach_changed_bit_and_save (context,
+                                &context->enabled_builtin_attributes,
+                                &context->enable_builtin_attributes_tmp,
+                                toggle_builtin_attribute_enabled_cb,
+                                &changed_bits_state);
+
+  changed_bits_state.new_bits = &context->enable_texcoord_attributes_tmp;
+  foreach_changed_bit_and_save (context,
+                                &context->enabled_texcoord_attributes,
+                                &context->enable_texcoord_attributes_tmp,
+                                toggle_texcood_attribute_enabled_cb,
+                                &changed_bits_state);
+
+  changed_bits_state.new_bits = &context->enable_custom_attributes_tmp;
+  foreach_changed_bit_and_save (context,
+                                &context->enabled_custom_attributes,
+                                &context->enable_custom_attributes_tmp,
+                                toggle_custom_attribute_enabled_cb,
+                                &changed_bits_state);
+}
+
+static CoglPipeline *
+flush_state (CoglDrawFlags flags,
+             CoglAttribute **attributes,
+             int n_attributes,
+             ValidateLayerState *state)
 {
   CoglFramebuffer *framebuffer = cogl_get_draw_framebuffer ();
   int i;
-  GLuint generic_index = 0;
-  unsigned long enable_flags = 0;
   gboolean skip_gl_color = FALSE;
-  CoglPipeline *source;
+  CoglPipeline *source = cogl_get_source ();
   CoglPipeline *copy = NULL;
   int n_tex_coord_attribs = 0;
 
   _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
 
+  if (!(flags & COGL_DRAW_SKIP_JOURNAL_FLUSH))
+    _cogl_journal_flush (framebuffer->journal, framebuffer);
+
+  state->unit = 0;
+  state->options.flags = 0;
+  state->fallback_layers = 0;
+
+  if (!(flags & COGL_DRAW_SKIP_PIPELINE_VALIDATION))
+    cogl_pipeline_foreach_layer (cogl_get_source (),
+                                 validate_layer_cb,
+                                 state);
+
+  /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
+   * as the pipeline state) when flushing the clip stack, so should
+   * always be done first when preparing to draw. We need to do this
+   * before setting up the array pointers because setting up the clip
+   * stack can cause some drawing which would change the array
+   * pointers. */
+  if (!(flags & COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH))
+    _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (),
+                                   _cogl_get_read_framebuffer (),
+                                   COGL_FRAMEBUFFER_STATE_ALL);
+
   /* In cogl_read_pixels we have a fast-path when reading a single
    * pixel and the scene is just comprised of simple rectangles still
    * in the journal. For this optimization to work we need to track
    * when the framebuffer really does get drawn to. */
   _cogl_framebuffer_dirty (framebuffer);
 
-  source = cogl_get_source ();
-
   /* Iterate the attributes to work out whether blending needs to be
      enabled and how many texture coords there are. We need to do this
      before flushing the pipeline. */
   for (i = 0; i < n_attributes; i++)
-    switch (attributes[i]->name_id)
+    switch (attributes[i]->name_state->name_id)
       {
       case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
         if ((flags & COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE) == 0 &&
@@ -589,11 +682,13 @@ enable_gl_state (CoglDrawFlags flags,
 
   _cogl_pipeline_flush_gl_state (source, skip_gl_color, n_tex_coord_attribs);
 
-  _cogl_bitmask_clear_all (&ctx->temp_bitmask);
+  _cogl_bitmask_clear_all (&ctx->enable_builtin_attributes_tmp);
+  _cogl_bitmask_clear_all (&ctx->enable_texcoord_attributes_tmp);
+  _cogl_bitmask_clear_all (&ctx->enable_custom_attributes_tmp);
 
   /* Bind the attribute pointers. We need to do this after the
-     pipeline is flushed because on GLES2 that is the only point when
-     we can determine the attribute locations */
+   * pipeline is flushed because when using GLSL that is the only
+   * point when we can determine the attribute locations */
 
   for (i = 0; i < n_attributes; i++)
     {
@@ -601,156 +696,77 @@ enable_gl_state (CoglDrawFlags flags,
       CoglAttributeBuffer *attribute_buffer;
       CoglBuffer *buffer;
       guint8 *base;
-#ifdef HAVE_COGL_GLES2
-      int attrib_location;
-#endif
 
       attribute_buffer = cogl_attribute_get_buffer (attribute);
       buffer = COGL_BUFFER (attribute_buffer);
       base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_ATTRIBUTE_BUFFER);
 
-      switch (attribute->name_id)
+      switch (attribute->name_state->name_id)
         {
         case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
 #ifdef HAVE_COGL_GLES2
           if (ctx->driver == COGL_DRIVER_GLES2)
-            {
-              attrib_location =
-                _cogl_pipeline_progend_glsl_get_color_attribute (source);
-              if (attrib_location != -1)
-                {
-                  GE( ctx,
-                      glVertexAttribPointer (attrib_location,
-                                             attribute->n_components,
-                                             attribute->type,
-                                             TRUE, /* normalize */
-                                             attribute->stride,
-                                             base + attribute->offset) );
-
-                  _cogl_bitmask_set (&ctx->temp_bitmask, attrib_location, TRUE);
-                }
-            }
+            setup_generic_attribute (ctx, source, attribute, base);
           else
 #endif
             {
-              enable_flags |= COGL_ENABLE_COLOR_ARRAY;
-              /* GE (ctx, glEnableClientState (GL_COLOR_ARRAY)); */
+              _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp,
+                                 COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY, TRUE);
               GE (ctx, glColorPointer (attribute->n_components,
                                        attribute->type,
                                        attribute->stride,
                                        base + attribute->offset));
-
             }
-
           break;
         case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
 #ifdef HAVE_COGL_GLES2
           if (ctx->driver == COGL_DRIVER_GLES2)
-            {
-              attrib_location =
-                _cogl_pipeline_progend_glsl_get_normal_attribute (source);
-              if (attrib_location != -1)
-                {
-                  GE( ctx,
-                      glVertexAttribPointer (attrib_location,
-                                             attribute->n_components,
-                                             attribute->type,
-                                             TRUE, /* normalize */
-                                             attribute->stride,
-                                             base + attribute->offset) );
-                  _cogl_bitmask_set (&ctx->temp_bitmask, attrib_location, TRUE);
-                }
-            }
+            setup_generic_attribute (ctx, source, attribute, base);
 #endif
-#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
-          if (ctx->driver != COGL_DRIVER_GLES2)
             {
-              /* FIXME: go through cogl cache to enable normal array */
-              GE (ctx, glEnableClientState (GL_NORMAL_ARRAY));
+              _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp,
+                                 COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY, TRUE);
               GE (ctx, glNormalPointer (attribute->type,
                                         attribute->stride,
                                         base + attribute->offset));
-
             }
-#endif
           break;
         case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
 #ifdef HAVE_COGL_GLES2
           if (ctx->driver == COGL_DRIVER_GLES2)
-            {
-              attrib_location =
-                _cogl_pipeline_progend_glsl_get_tex_coord_attribute
-                (source, attribute->texture_unit);
-              if (attrib_location != -1)
-                {
-                  GE( ctx,
-                      glVertexAttribPointer (attrib_location,
-                                             attribute->n_components,
-                                             attribute->type,
-                                             FALSE, /* normalize */
-                                             attribute->stride,
-                                             base + attribute->offset) );
-                  _cogl_bitmask_set (&ctx->temp_bitmask, attrib_location, TRUE);
-                }
-            }
+            setup_generic_attribute (ctx, source, attribute, base);
           else
 #endif
             {
-              GE (ctx, glClientActiveTexture (GL_TEXTURE0 +
-                                              attribute->texture_unit));
+              _cogl_bitmask_set (&ctx->enable_texcoord_attributes_tmp,
+                                 attribute->name_state->texture_unit, TRUE);
+              GE (ctx,
+                  glClientActiveTexture (GL_TEXTURE0 +
+                                         attribute->name_state->texture_unit));
               GE (ctx, glTexCoordPointer (attribute->n_components,
                                           attribute->type,
                                           attribute->stride,
                                           base + attribute->offset));
-              _cogl_bitmask_set (&ctx->temp_bitmask,
-                                 attribute->texture_unit, TRUE);
-
             }
           break;
         case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
 #ifdef HAVE_COGL_GLES2
           if (ctx->driver == COGL_DRIVER_GLES2)
-            {
-              attrib_location =
-                _cogl_pipeline_progend_glsl_get_position_attribute (source);
-              if (attrib_location != -1)
-                {
-                  GE( ctx,
-                      glVertexAttribPointer (attrib_location,
-                                             attribute->n_components,
-                                             attribute->type,
-                                             FALSE, /* normalize */
-                                             attribute->stride,
-                                             base + attribute->offset) );
-                  _cogl_bitmask_set (&ctx->temp_bitmask, attrib_location, TRUE);
-                }
-            }
+            setup_generic_attribute (ctx, source, attribute, base);
           else
 #endif
             {
-              enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
-              /* GE (ctx, glEnableClientState (GL_VERTEX_ARRAY)); */
+              _cogl_bitmask_set (&ctx->enable_builtin_attributes_tmp,
+                                 COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY, TRUE);
               GE (ctx, glVertexPointer (attribute->n_components,
                                         attribute->type,
                                         attribute->stride,
                                         base + attribute->offset));
-
             }
           break;
         case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
           if (ctx->driver != COGL_DRIVER_GLES1)
-            {
-              /* FIXME: go through cogl cache to enable generic array. */
-              /* FIXME: this is going to end up just using the builtins
-                 on GLES 2 */
-              GE (ctx, glEnableVertexAttribArray (generic_index++));
-              GE (ctx, glVertexAttribPointer (generic_index,
-                                              attribute->n_components,
-                                              attribute->type,
-                                              attribute->normalized,
-                                              attribute->stride,
-                                              base + attribute->offset));
-            }
+            setup_generic_attribute (ctx, source, attribute, base);
           break;
         default:
           g_warning ("Unrecognised attribute type 0x%08x", attribute->type);
@@ -759,10 +775,7 @@ enable_gl_state (CoglDrawFlags flags,
       _cogl_buffer_unbind (buffer);
     }
 
-  /* Flush the state of the attribute arrays */
-  set_enabled_arrays (&ctx->arrays_enabled, &ctx->temp_bitmask);
-
-  _cogl_enable (enable_flags);
+  apply_attribute_enable_updates (ctx, source);
 
   return source;
 }
@@ -772,60 +785,14 @@ _cogl_attribute_disable_cached_arrays (void)
 {
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  _cogl_bitmask_clear_all (&ctx->temp_bitmask);
-  set_enabled_arrays (&ctx->arrays_enabled, &ctx->temp_bitmask);
-}
+  _cogl_bitmask_clear_all (&ctx->enable_builtin_attributes_tmp);
+  _cogl_bitmask_clear_all (&ctx->enable_texcoord_attributes_tmp);
+  _cogl_bitmask_clear_all (&ctx->enable_custom_attributes_tmp);
 
-/* FIXME: we shouldn't be disabling state after drawing we should
- * just disable the things not needed after enabling state. */
-static void
-disable_gl_state (CoglAttribute **attributes,
-                  int n_attributes,
-                  CoglPipeline *source)
-{
-  GLuint generic_index = 0;
-  int i;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  if (G_UNLIKELY (source != cogl_get_source ()))
-    cogl_object_unref (source);
-
-  for (i = 0; i < n_attributes; i++)
-    {
-      CoglAttribute *attribute = attributes[i];
-
-      switch (attribute->name_id)
-        {
-        case COGL_ATTRIBUTE_NAME_ID_COLOR_ARRAY:
-          /* GE (ctx, glDisableClientState (GL_COLOR_ARRAY)); */
-          break;
-        case COGL_ATTRIBUTE_NAME_ID_NORMAL_ARRAY:
-          /* FIXME: go through cogl cache to enable normal array */
-#if defined(HAVE_COGL_GLES) || defined(HAVE_COGL_GL)
-          if (ctx->driver != COGL_DRIVER_GLES2)
-            GE (ctx, glDisableClientState (GL_NORMAL_ARRAY));
-#endif
-          break;
-        case COGL_ATTRIBUTE_NAME_ID_TEXTURE_COORD_ARRAY:
-          /* The enabled state of the texture coord arrays is
-             cached in ctx->enabled_texcoord_arrays so we don't
-             need to do anything here. The array will be disabled
-             by the next drawing primitive if it is not
-             required */
-          break;
-        case COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY:
-          /* GE (ctx, glDisableClientState (GL_VERTEX_ARRAY)); */
-          break;
-        case COGL_ATTRIBUTE_NAME_ID_CUSTOM_ARRAY:
-          if (ctx->driver != COGL_DRIVER_GLES1)
-            /* FIXME: go through cogl cache to enable generic array */
-            GE (ctx, glDisableVertexAttribArray (generic_index++));
-          break;
-        default:
-          g_warning ("Unrecognised attribute type 0x%08x", attribute->type);
-        }
-    }
+  /* XXX: we can pass a NULL source pipeline here because we know a
+   * source pipeline only needs to be referenced when enabling
+   * attributes. */
+  apply_attribute_enable_updates (ctx, NULL);
 }
 
 #ifdef COGL_ENABLE_DEBUG
@@ -1020,7 +987,8 @@ draw_wireframe (CoglVerticesMode mode,
 
   for (i = 0; i < n_attributes; i++)
     {
-      if (strcmp (attributes[i]->name, "cogl_position_in") == 0)
+      if (attributes[i]->name_state->name_id ==
+          COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY)
         {
           position = attributes[i];
           break;
@@ -1073,37 +1041,6 @@ draw_wireframe (CoglVerticesMode mode,
 }
 #endif
 
-static void
-flush_state (CoglDrawFlags flags,
-             ValidateLayerState *state)
-{
-  if (!(flags & COGL_DRAW_SKIP_JOURNAL_FLUSH))
-    {
-      CoglFramebuffer *framebuffer = cogl_get_draw_framebuffer ();
-      _cogl_journal_flush (framebuffer->journal, framebuffer);
-    }
-
-  state->unit = 0;
-  state->options.flags = 0;
-  state->fallback_layers = 0;
-
-  if (!(flags & COGL_DRAW_SKIP_PIPELINE_VALIDATION))
-    cogl_pipeline_foreach_layer (cogl_get_source (),
-                                 validate_layer_cb,
-                                 state);
-
-  /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
-   * as the pipeline state) when flushing the clip stack, so should
-   * always be done first when preparing to draw. We need to do this
-   * before setting up the array pointers because setting up the clip
-   * stack can cause some drawing which would change the array
-   * pointers. */
-  if (!(flags & COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH))
-    _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (),
-                                   _cogl_get_read_framebuffer (),
-                                   COGL_FRAMEBUFFER_STATE_ALL);
-}
-
 /* This can be called directly by the CoglJournal to draw attributes
  * skipping the implicit journal flush, the framebuffer flush and
  * pipeline validation. */
@@ -1120,15 +1057,12 @@ _cogl_draw_attributes (CoglVerticesMode mode,
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  flush_state (flags, &state);
-
-  source = enable_gl_state (flags, attributes, n_attributes, &state);
+  source = flush_state (flags, attributes, n_attributes, &state);
 
   GE (ctx, glDrawArrays ((GLenum)mode, first_vertex, n_vertices));
 
-  /* FIXME: we shouldn't be disabling state after drawing we should
-   * just disable the things not needed after enabling state. */
-  disable_gl_state (attributes, n_attributes, source);
+  if (G_UNLIKELY (source != cogl_get_source ()))
+    cogl_object_unref (source);
 
 #ifdef COGL_ENABLE_DEBUG
   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME)))
@@ -1212,9 +1146,7 @@ _cogl_draw_indexed_attributes (CoglVerticesMode mode,
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  flush_state (flags, &state);
-
-  source = enable_gl_state (flags, attributes, n_attributes, &state);
+  source = flush_state (flags, attributes, n_attributes, &state);
 
   buffer = COGL_BUFFER (cogl_indices_get_buffer (indices));
   base = _cogl_buffer_bind (buffer, COGL_BUFFER_BIND_TARGET_INDEX_BUFFER);
@@ -1241,9 +1173,8 @@ _cogl_draw_indexed_attributes (CoglVerticesMode mode,
 
   _cogl_buffer_unbind (buffer);
 
-  /* FIXME: we shouldn't be disabling state after drawing we should
-   * just disable the things not needed after enabling state. */
-  disable_gl_state (attributes, n_attributes, source);
+  if (G_UNLIKELY (source != cogl_get_source ()))
+    cogl_object_unref (source);
 
 #ifdef COGL_ENABLE_DEBUG
   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME)))
diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index 9f2e178..f8b9cf0 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -72,8 +72,21 @@ struct _CoglContext
   CoglHandle        default_layer_n;
   CoglHandle        dummy_layer_dependant;
 
-  /* Enable cache */
-  unsigned long     enable_flags;
+  GHashTable *attribute_name_states_hash;
+  GArray *attribute_name_index_map;
+  int n_attribute_names;
+
+  CoglBitmask       enabled_builtin_attributes;
+  CoglBitmask       enabled_texcoord_attributes;
+  CoglBitmask       enabled_custom_attributes;
+
+  /* These are temporary bitmasks that are used when disabling
+   * builtin,texcoord and custom attribute arrays. They are here just
+   * to avoid allocating new ones each time */
+  CoglBitmask       enable_builtin_attributes_tmp;
+  CoglBitmask       enable_texcoord_attributes_tmp;
+  CoglBitmask       enable_custom_attributes_tmp;
+  CoglBitmask       changed_bits_tmp;
 
   gboolean          legacy_backface_culling_enabled;
 
@@ -129,16 +142,6 @@ struct _CoglContext
   gboolean          current_pipeline_skip_gl_color;
   unsigned long     current_pipeline_age;
 
-  /* Bitmask of attributes enabled. On GLES2 these are the vertex
-     attribute numbers and on regular GL these are only used for the
-     texture coordinate arrays */
-  CoglBitmask       arrays_enabled;
-  /* These are temporary bitmasks that are used when disabling
-     texcoord arrays. They are here just to avoid allocating new ones
-     each time */
-  CoglBitmask       arrays_to_change;
-  CoglBitmask       temp_bitmask;
-
   gboolean          gl_blend_enable_cache;
 
   gboolean              depth_test_enabled_cache;
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index f474538..08b527e 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -43,6 +43,7 @@
 #include "cogl-framebuffer-private.h"
 #include "cogl-onscreen-private.h"
 #include "cogl2-path.h"
+#include "cogl-attribute-private.h"
 
 #include <string.h>
 
@@ -129,7 +130,6 @@ cogl_context_new (CoglDisplay *display,
 {
   CoglContext *context;
   GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
-  unsigned long enable_flags = 0;
   const CoglWinsysVtable *winsys;
   int i;
 
@@ -221,6 +221,16 @@ cogl_context_new (CoglDisplay *display,
       g_assert_not_reached ();
     }
 
+  context->attribute_name_states_hash =
+    g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+  context->attribute_name_index_map = NULL;
+  context->n_attribute_names = 0;
+
+  /* The "cogl_color_in" attribute needs a deterministic name_index
+   * so we make sure it's the first attribute name we register */
+  _cogl_attribute_register_attribute_name (context, "cogl_color_in");
+
+
   context->uniform_names =
     g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
   context->uniform_name_hash = g_hash_table_new (g_str_hash, g_str_equal);
@@ -234,7 +244,6 @@ cogl_context_new (CoglDisplay *display,
   _cogl_pipeline_init_state_hash_functions ();
   _cogl_pipeline_init_layer_state_hash_functions ();
 
-  context->enable_flags = 0;
   context->current_clip_stack_valid = FALSE;
   context->current_clip_stack = NULL;
 
@@ -284,9 +293,13 @@ cogl_context_new (CoglDisplay *display,
   context->current_pipeline_changes_since_flush = 0;
   context->current_pipeline_skip_gl_color = FALSE;
 
-  _cogl_bitmask_init (&context->arrays_enabled);
-  _cogl_bitmask_init (&context->temp_bitmask);
-  _cogl_bitmask_init (&context->arrays_to_change);
+  _cogl_bitmask_init (&context->enabled_builtin_attributes);
+  _cogl_bitmask_init (&context->enable_builtin_attributes_tmp);
+  _cogl_bitmask_init (&context->enabled_texcoord_attributes);
+  _cogl_bitmask_init (&context->enable_texcoord_attributes_tmp);
+  _cogl_bitmask_init (&context->enabled_custom_attributes);
+  _cogl_bitmask_init (&context->enable_custom_attributes_tmp);
+  _cogl_bitmask_init (&context->changed_bits_tmp);
 
   context->max_texture_units = -1;
   context->max_activateable_texture_units = -1;
@@ -385,7 +398,6 @@ cogl_context_new (CoglDisplay *display,
 
   cogl_push_source (context->opaque_color_pipeline);
   _cogl_pipeline_flush_gl_state (context->opaque_color_pipeline, FALSE, 0);
-  _cogl_enable (enable_flags);
 
   context->atlases = NULL;
   g_hook_list_init (&context->atlas_reorganize_callbacks, sizeof (GHook));
@@ -468,9 +480,13 @@ _cogl_context_free (CoglContext *context)
   g_slist_free (context->atlases);
   g_hook_list_clear (&context->atlas_reorganize_callbacks);
 
-  _cogl_bitmask_destroy (&context->arrays_enabled);
-  _cogl_bitmask_destroy (&context->temp_bitmask);
-  _cogl_bitmask_destroy (&context->arrays_to_change);
+  _cogl_bitmask_destroy (&context->enabled_builtin_attributes);
+  _cogl_bitmask_destroy (&context->enable_builtin_attributes_tmp);
+  _cogl_bitmask_destroy (&context->enabled_texcoord_attributes);
+  _cogl_bitmask_destroy (&context->enable_texcoord_attributes_tmp);
+  _cogl_bitmask_destroy (&context->enabled_custom_attributes);
+  _cogl_bitmask_destroy (&context->enable_custom_attributes_tmp);
+  _cogl_bitmask_destroy (&context->changed_bits_tmp);
 
   g_slist_free (context->texture_types);
   g_slist_free (context->buffer_types);
@@ -490,6 +506,9 @@ _cogl_context_free (CoglContext *context)
   g_ptr_array_free (context->uniform_names, TRUE);
   g_hash_table_destroy (context->uniform_name_hash);
 
+  g_hash_table_destroy (context->attribute_name_states_hash);
+  g_array_free (context->attribute_name_index_map, TRUE);
+
   g_byte_array_free (context->buffer_map_fallback_array, TRUE);
 
   cogl_object_unref (context->display);
diff --git a/cogl/cogl-pipeline-opengl.c b/cogl/cogl-pipeline-opengl.c
index 92d75ea..aaf5ea8 100644
--- a/cogl/cogl-pipeline-opengl.c
+++ b/cogl/cogl-pipeline-opengl.c
@@ -1372,8 +1372,10 @@ done:
       int attribute;
       CoglPipeline *authority =
         _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_COLOR);
+      int name_index = COGL_ATTRIBUTE_COLOR_NAME_INDEX;
 
-      attribute = _cogl_pipeline_progend_glsl_get_color_attribute (pipeline);
+      attribute =
+        _cogl_pipeline_progend_glsl_get_attrib_location (pipeline, name_index);
       if (attribute != -1)
         GE (ctx,
             glVertexAttrib4f (attribute,
diff --git a/cogl/cogl-pipeline-progend-glsl-private.h b/cogl/cogl-pipeline-progend-glsl-private.h
index c100269..a080204 100644
--- a/cogl/cogl-pipeline-progend-glsl-private.h
+++ b/cogl/cogl-pipeline-progend-glsl-private.h
@@ -33,22 +33,9 @@
 
 extern const CoglPipelineProgend _cogl_pipeline_glsl_progend;
 
-#ifdef HAVE_COGL_GLES2
-
-int
-_cogl_pipeline_progend_glsl_get_position_attribute (CoglPipeline *pipeline);
-
-int
-_cogl_pipeline_progend_glsl_get_color_attribute (CoglPipeline *pipeline);
-
-int
-_cogl_pipeline_progend_glsl_get_normal_attribute (CoglPipeline *pipeline);
-
 int
-_cogl_pipeline_progend_glsl_get_tex_coord_attribute (CoglPipeline *pipeline,
-                                                     int unit);
-
-#endif /* HAVE_COGL_GLES2 */
+_cogl_pipeline_progend_glsl_get_attrib_location (CoglPipeline *pipeline,
+                                                 int name_index);
 
 #endif /* __COGL_PIPELINE_PROGEND_GLSL_PRIVATE_H */
 
diff --git a/cogl/cogl-pipeline-progend-glsl.c b/cogl/cogl-pipeline-progend-glsl.c
index 703cbea..bc96cb8 100644
--- a/cogl/cogl-pipeline-progend-glsl.c
+++ b/cogl/cogl-pipeline-progend-glsl.c
@@ -47,6 +47,7 @@
 #include "cogl-pipeline-vertend-glsl-private.h"
 #include "cogl-pipeline-cache.h"
 #include "cogl-pipeline-state-private.h"
+#include "cogl-attribute-private.h"
 
 #ifdef HAVE_COGL_GLES2
 
@@ -116,18 +117,6 @@ typedef struct
   unsigned long dirty_builtin_uniforms;
   GLint builtin_uniform_locations[G_N_ELEMENTS (builtin_uniforms)];
 
-  /* Under GLES2 we can't use the builtin functions to set attribute
-     pointers such as the vertex position. Instead the vertex
-     attribute code needs to query the attribute numbers from the
-     progend backend */
-  int position_attribute_location;
-  int color_attribute_location;
-  int normal_attribute_location;
-  int tex_coord0_attribute_location;
-  /* We only allocate this array if more than one tex coord attribute
-     is requested because most pipelines will only use one layer */
-  GArray *tex_coord_attribute_locations;
-
   GLint modelview_uniform;
   GLint projection_uniform;
   GLint mvp_uniform;
@@ -148,6 +137,9 @@ typedef struct
      uniform is actually set */
   GArray *uniform_locations;
 
+  /* Array of attribute locations. */
+  GArray *attribute_locations;
+
   UnitState *unit_state;
 } CoglPipelineProgramState;
 
@@ -161,8 +153,6 @@ get_program_state (CoglPipeline *pipeline)
 
 #define UNIFORM_LOCATION_UNKNOWN -2
 
-#ifdef HAVE_COGL_GLES2
-
 #define ATTRIBUTE_LOCATION_UNKNOWN -2
 
 /* Under GLES2 the vertex attribute API needs to query the attribute
@@ -172,125 +162,66 @@ get_program_state (CoglPipeline *pipeline)
    cache. This should always be called after the pipeline is flushed
    so they can assert that the gl program is valid */
 
-int
-_cogl_pipeline_progend_glsl_get_position_attribute (CoglPipeline *pipeline)
-{
-  CoglPipelineProgramState *program_state = get_program_state (pipeline);
-
-  _COGL_GET_CONTEXT (ctx, -1);
-
-  _COGL_RETURN_VAL_IF_FAIL (program_state != NULL, -1);
-  _COGL_RETURN_VAL_IF_FAIL (program_state->program != 0, -1);
-
-  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 program_state->position_attribute_location;
-}
-
-int
-_cogl_pipeline_progend_glsl_get_color_attribute (CoglPipeline *pipeline)
-{
-  CoglPipelineProgramState *program_state = get_program_state (pipeline);
-
-  _COGL_GET_CONTEXT (ctx, -1);
-
-  _COGL_RETURN_VAL_IF_FAIL (program_state != NULL, -1);
-  _COGL_RETURN_VAL_IF_FAIL (program_state->program != 0, -1);
-
-  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 program_state->color_attribute_location;
-}
+/* All attributes names get internally mapped to a global set of
+ * sequential indices when they are setup which we need to need to
+ * then be able to map to a GL attribute location once we have
+ * a linked GLSL program */
 
 int
-_cogl_pipeline_progend_glsl_get_normal_attribute (CoglPipeline *pipeline)
+_cogl_pipeline_progend_glsl_get_attrib_location (CoglPipeline *pipeline,
+                                                 int name_index)
 {
   CoglPipelineProgramState *program_state = get_program_state (pipeline);
+  int *locations;
 
   _COGL_GET_CONTEXT (ctx, -1);
 
   _COGL_RETURN_VAL_IF_FAIL (program_state != NULL, -1);
   _COGL_RETURN_VAL_IF_FAIL (program_state->program != 0, -1);
 
-  if (program_state->normal_attribute_location == ATTRIBUTE_LOCATION_UNKNOWN)
-    GE_RET( program_state->normal_attribute_location,
-            ctx, glGetAttribLocation (program_state->program,
-                                      "cogl_normal_in") );
+  if (G_UNLIKELY (program_state->attribute_locations == NULL))
+    program_state->attribute_locations =
+      g_array_new (FALSE, FALSE, sizeof (int));
 
-  return program_state->normal_attribute_location;
-}
-
-int
-_cogl_pipeline_progend_glsl_get_tex_coord_attribute (CoglPipeline *pipeline,
-                                                     int unit)
-{
-  CoglPipelineProgramState *program_state = get_program_state (pipeline);
-
-  _COGL_GET_CONTEXT (ctx, -1);
-
-  _COGL_RETURN_VAL_IF_FAIL (program_state != NULL, -1);
-  _COGL_RETURN_VAL_IF_FAIL (program_state->program != 0, -1);
-
-  if (unit == 0)
+  if (G_UNLIKELY (program_state->attribute_locations->len <= name_index))
     {
-      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 program_state->tex_coord0_attribute_location;
+      int i = program_state->attribute_locations->len;
+      g_array_set_size (program_state->attribute_locations, name_index + 1);
+      for (; i < program_state->attribute_locations->len; i++)
+        g_array_index (program_state->attribute_locations, int, i)
+          = ATTRIBUTE_LOCATION_UNKNOWN;
     }
-  else
-    {
-      char *name = g_strdup_printf ("cogl_tex_coord%i_in", unit);
-      int *locations;
 
-      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 = 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 (program_state->tex_coord_attribute_locations, int, i)
-              = ATTRIBUTE_LOCATION_UNKNOWN;
-        }
+  locations = &g_array_index (program_state->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 (program_state->program, name) );
+  if (locations[name_index] == ATTRIBUTE_LOCATION_UNKNOWN)
+    {
+      CoglAttributeNameState *name_state =
+        g_array_index (ctx->attribute_name_index_map,
+                       CoglAttributeNameState *, name_index);
 
-      g_free (name);
+      _COGL_RETURN_VAL_IF_FAIL (name_state != NULL, 0);
 
-      return locations[unit - 1];
+      GE_RET( locations[name_index],
+              ctx, glGetAttribLocation (program_state->program,
+                                        name_state->name) );
     }
+
+  return locations[name_index];
 }
 
 static void
 clear_attribute_cache (CoglPipelineProgramState *program_state)
 {
-  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)
+  if (program_state->attribute_locations)
     {
-      g_array_free (program_state->tex_coord_attribute_locations, TRUE);
-      program_state->tex_coord_attribute_locations = NULL;
+      g_array_free (program_state->attribute_locations, TRUE);
+      program_state->attribute_locations = NULL;
     }
 }
 
+#ifdef HAVE_COGL_GLES2
+
 static void
 clear_flushed_matrix_stacks (CoglPipelineProgramState *program_state)
 {
@@ -320,8 +251,8 @@ program_state_new (int n_layers)
   program_state->n_tex_coord_attribs = 0;
   program_state->unit_state = g_new (UnitState, n_layers);
   program_state->uniform_locations = NULL;
+  program_state->attribute_locations = NULL;
 #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;
@@ -347,12 +278,11 @@ destroy_program_state (void *user_data,
 
   if (--program_state->ref_count == 0)
     {
+      clear_attribute_cache (program_state);
+
 #ifdef HAVE_COGL_GLES2
       if (ctx->driver == COGL_DRIVER_GLES2)
-        {
-          clear_attribute_cache (program_state);
-          clear_flushed_matrix_stacks (program_state);
-        }
+        clear_flushed_matrix_stacks (program_state);
 #endif
 
       if (program_state->program)
@@ -858,9 +788,12 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
   state.program_state = program_state;
 
   if (program_changed)
-    cogl_pipeline_foreach_layer (pipeline,
-                                 get_uniform_cb,
-                                 &state);
+    {
+      cogl_pipeline_foreach_layer (pipeline,
+                                   get_uniform_cb,
+                                   &state);
+      clear_attribute_cache (program_state);
+    }
 
   state.unit = 0;
   state.update_all = (program_changed ||
@@ -877,7 +810,6 @@ _cogl_pipeline_progend_glsl_end (CoglPipeline *pipeline,
         {
           int i;
 
-          clear_attribute_cache (program_state);
           clear_flushed_matrix_stacks (program_state);
 
           for (i = 0; i < G_N_ELEMENTS (builtin_uniforms); i++)
diff --git a/cogl/cogl.c b/cogl/cogl.c
index 46fd45e..cba3de7 100644
--- a/cogl/cogl.c
+++ b/cogl/cogl.c
@@ -141,69 +141,6 @@ cogl_clear (const CoglColor *color, unsigned long buffers)
   cogl_framebuffer_clear (cogl_get_draw_framebuffer (), buffers, color);
 }
 
-#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
-
-static gboolean
-toggle_client_flag (CoglContext *ctx,
-		    unsigned long new_flags,
-		    unsigned long flag,
-		    GLenum gl_flag)
-{
-  _COGL_RETURN_VAL_IF_FAIL (ctx->driver != COGL_DRIVER_GLES2, FALSE);
-
-  /* Toggles and caches a single client-side enable flag
-   * on or off by comparing to current state
-   */
-  if (new_flags & flag)
-    {
-      if (!(ctx->enable_flags & flag))
-	{
-	  GE( ctx, glEnableClientState (gl_flag) );
-	  ctx->enable_flags |= flag;
-	  return TRUE;
-	}
-    }
-  else if (ctx->enable_flags & flag)
-    {
-      GE( ctx, glDisableClientState (gl_flag) );
-      ctx->enable_flags &= ~flag;
-    }
-
-  return FALSE;
-}
-
-#endif
-
-void
-_cogl_enable (unsigned long flags)
-{
-  /* This function essentially caches glEnable state() in the
-   * hope of lessening number GL traffic.
-  */
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-#if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
-  if (ctx->driver != COGL_DRIVER_GLES2)
-    {
-      toggle_client_flag (ctx, flags,
-                          COGL_ENABLE_VERTEX_ARRAY,
-                          GL_VERTEX_ARRAY);
-
-      toggle_client_flag (ctx, flags,
-                          COGL_ENABLE_COLOR_ARRAY,
-                          GL_COLOR_ARRAY);
-    }
-#endif
-}
-
-unsigned long
-_cogl_get_enable (void)
-{
-  _COGL_GET_CONTEXT (ctx, 0);
-
-  return ctx->enable_flags;
-}
-
 /* XXX: This API has been deprecated */
 void
 cogl_set_depth_test_enabled (gboolean setting)
@@ -645,7 +582,6 @@ cogl_read_pixels (int x,
 void
 cogl_begin_gl (void)
 {
-  unsigned long enable_flags = 0;
   CoglPipeline *pipeline;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@@ -697,8 +633,6 @@ cogl_begin_gl (void)
                                  FALSE,
                                  cogl_pipeline_get_n_layers (pipeline));
 
-  _cogl_enable (enable_flags);
-
   /* Disable any cached vertex arrays */
   _cogl_attribute_disable_cached_arrays ();
 }



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