[cogl-gles2-wrapper] Convert texture unit settings to be a static sized array
authorNeil Roberts <neil@linux.intel.com>
Fri, 20 Feb 2009 15:56:57 +0000 (15:56 +0000)
committerNeil Roberts <neil@linux.intel.com>
Fri, 20 Feb 2009 15:59:13 +0000 (15:59 +0000)
Previously the texture unit settings were stored in growable GArrays
and every time a new texture unit was encountered it would expand the
arrays. However the array wasn't copied when stored in a
CoglGles2WrapperSettings struct so all settings had the same
array. This meant that it wouldn't detect that a different program is
needed if a texture unit is disabled or enabled.

The texture unit settings arrays are all now a fixed size and the
enabledness of each unit is stored in a bit mask. Therefore the
settings can just be copied around by assignment as before.

This puts a limit on the number of texture units accessible by Cogl
but I think it is worth it to make the code simpler and more
efficient. The material API already poses a limit on the number of
texture units it can use.

clutter/cogl/gles/cogl-gles2-wrapper.c
clutter/cogl/gles/cogl-gles2-wrapper.h

index 5551ceb..e7a4619 100644 (file)
@@ -107,6 +107,40 @@ cogl_gles2_wrapper_create_shader (GLenum type, const char *source)
   return shader;
 }
 
+static void
+initialize_texture_units (CoglGles2Wrapper *w)
+{
+  /* We save the active texture unit since we may need to temporarily
+   * change this to initialise each new texture unit and we want to
+   * restore the active unit afterwards */
+  int initial_active_unit = w->active_texture_unit;
+  GLint prev_mode;
+  int i;
+
+  /* We will need to set the matrix mode to GL_TEXTURE to
+   * initialise any new texture units, so we save the current
+   * mode for restoring afterwards */
+  GE( cogl_wrap_glGetIntegerv (CGL_MATRIX_MODE, &prev_mode));
+
+  for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
+    {
+      CoglGles2WrapperTextureUnit *new_unit;
+
+      new_unit = w->texture_units + i;
+      memset (new_unit, 0, sizeof (CoglGles2WrapperTextureUnit));
+
+      w->active_texture_unit = i;
+      GE( cogl_wrap_glMatrixMode (GL_TEXTURE));
+      GE( cogl_wrap_glLoadIdentity ());
+    }
+
+  GE( cogl_wrap_glMatrixMode ((GLenum) prev_mode));
+
+  w->settings.texture_units = 0;
+
+  w->active_texture_unit = initial_active_unit;
+}
+
 void
 cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper)
 {
@@ -120,9 +154,6 @@ cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper)
   cogl_wrap_glMatrixMode (GL_MODELVIEW);
   cogl_wrap_glLoadIdentity ();
 
-  wrapper->texture_units =
-    g_array_new (FALSE, FALSE, sizeof (CoglGles2WrapperTextureUnit *));
-
   /* The gl*ActiveTexture wrappers will initialise the texture
    * stack for the texture unit when it's first activated */
   cogl_wrap_glActiveTexture (GL_TEXTURE0);
@@ -139,6 +170,8 @@ cogl_gles2_wrapper_init (CoglGles2Wrapper *wrapper)
   /* Initialize alpha testing */
   cogl_wrap_glDisable (GL_ALPHA_TEST);
   cogl_wrap_glAlphaFunc (GL_ALWAYS, 0.0f);
+
+  initialize_texture_units (wrapper);
 }
 
 static gboolean
@@ -147,17 +180,11 @@ cogl_gles2_settings_equal (const CoglGles2WrapperSettings *a,
                           gboolean vertex_tests,
                           gboolean fragment_tests)
 {
+  if (a->texture_units != b->texture_units)
+    return FALSE;
+
   if (fragment_tests)
     {
-      int i;
-      for (i = 0; i < a->n_texture_units; i++)
-       {
-         if (a->texture_units[i].enabled != b->texture_units[i].enabled)
-           return FALSE;
-         if (a->texture_units[i].alpha_only != b->texture_units[i].alpha_only)
-           return FALSE;
-       }
-
       if (a->alpha_test_enabled != b->alpha_test_enabled)
        return FALSE;
       if (a->alpha_test_enabled && a->alpha_test_func != b->alpha_test_func)
@@ -181,6 +208,7 @@ cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings)
   CoglGles2WrapperShader *shader;
   GSList *node;
   int i;
+  int n_texture_units = 0;
 
   _COGL_GET_GLES2_WRAPPER (w, NULL);
 
@@ -195,44 +223,48 @@ cogl_gles2_get_vertex_shader (const CoglGles2WrapperSettings *settings)
   /* Otherwise create a new shader */
   shader_source = g_string_new (cogl_fixed_vertex_shader_per_vertex_attribs);
 
-  for (i = 0; i < settings->n_texture_units; i++)
-    {
-      if (!settings->texture_units[i].enabled)
-       continue;
+  for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
+    if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i))
       g_string_append_printf (shader_source,
                              "attribute vec4 multi_tex_coord_attrib%d;\n",
                              i);
-    }
 
-  g_string_append (shader_source, cogl_fixed_vertex_shader_transform_matrices);
-  g_string_append_printf (shader_source,
-                         "uniform mat4       texture_matrix[%d];\n",
-                         settings->n_texture_units);
+  /* Find the biggest enabled texture unit index */
+  for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
+    if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i))
+      n_texture_units = i + 1;
 
+  g_string_append (shader_source, cogl_fixed_vertex_shader_transform_matrices);
   g_string_append (shader_source, cogl_fixed_vertex_shader_output_variables);
-  g_string_append_printf (shader_source,
-                         "varying vec2       tex_coord[%d];",
-                         settings->n_texture_units);
 
-  g_string_append (shader_source, cogl_fixed_vertex_shader_fogging_options);
-  g_string_append (shader_source, cogl_fixed_vertex_shader_main_start);
-
-  for (i = 0; i < settings->n_texture_units; i++)
+  if (n_texture_units > 0)
     {
-      if (!settings->texture_units[i].enabled)
-       continue;
-
       g_string_append_printf (shader_source,
-                             "transformed_tex_coord = "
-                             "texture_matrix[%d] "
-                             " * multi_tex_coord_attrib%d;\n",
-                             i, i);
+                              "uniform mat4          texture_matrix[%d];\n",
+                              n_texture_units);
+
       g_string_append_printf (shader_source,
-                             "tex_coord[%d] = transformed_tex_coord.st "
-                             " / transformed_tex_coord.q;\n",
-                             i);
+                              "varying vec2       tex_coord[%d];",
+                              n_texture_units);
     }
 
+  g_string_append (shader_source, cogl_fixed_vertex_shader_fogging_options);
+  g_string_append (shader_source, cogl_fixed_vertex_shader_main_start);
+
+  for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
+    if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i))
+      {
+        g_string_append_printf (shader_source,
+                                "transformed_tex_coord = "
+                                "texture_matrix[%d] "
+                                " * multi_tex_coord_attrib%d;\n",
+                                i, i);
+        g_string_append_printf (shader_source,
+                                "tex_coord[%d] = transformed_tex_coord.st "
+                                " / transformed_tex_coord.q;\n",
+                                i);
+      }
+
   g_string_append (shader_source, cogl_fixed_vertex_shader_frag_color_start);
 
   if (settings->fog_enabled)
@@ -285,6 +317,7 @@ cogl_gles2_get_fragment_shader (const CoglGles2WrapperSettings *settings)
   CoglGles2WrapperShader *shader;
   GSList *node;
   int i;
+  int n_texture_units = 0;
 
   _COGL_GET_GLES2_WRAPPER (w, NULL);
 
@@ -299,15 +332,24 @@ cogl_gles2_get_fragment_shader (const CoglGles2WrapperSettings *settings)
   /* Otherwise create a new shader */
   shader_source = g_string_new (cogl_fixed_fragment_shader_variables_start);
 
+  /* Find the biggest enabled texture unit index */
+  for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
+    if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i))
+      n_texture_units = i + 1;
+
   g_string_append (shader_source, cogl_fixed_fragment_shader_inputs);
-  g_string_append_printf (shader_source,
-                         "varying vec2       tex_coord[%d];\n",
-                         settings->n_texture_units);
 
-  g_string_append (shader_source, cogl_fixed_fragment_shader_texturing_options);
-  g_string_append_printf (shader_source,
-                         "uniform sampler2D  texture_unit[%d];\n",
-                         settings->n_texture_units);
+  if (n_texture_units > 0)
+    {
+      g_string_append_printf (shader_source,
+                              "varying vec2       tex_coord[%d];\n",
+                              n_texture_units);
+
+      g_string_append (shader_source, cogl_fixed_fragment_shader_texturing_options);
+      g_string_append_printf (shader_source,
+                              "uniform sampler2D  texture_unit[%d];\n",
+                              n_texture_units);
+    }
 
   g_string_append (shader_source, cogl_fixed_fragment_shader_fogging_options);
 
@@ -318,37 +360,30 @@ cogl_gles2_get_fragment_shader (const CoglGles2WrapperSettings *settings)
   /* This pointless extra variable is needed to work around an
      apparent bug in the PowerVR drivers. Without it the alpha
      blending seems to stop working */
-  /* g_string_append (shader_source, "gl_FragColor = frag_color;\n");
-   */
   g_string_append (shader_source,
                   "vec4 frag_color_copy = frag_color;\n");
   g_string_append (shader_source, "gl_FragColor = frag_color;\n");
 
-  for (i = 0; i < settings->n_texture_units; i++)
-    {
-      if (settings->texture_units[i].alpha_only)
-       {
-         /* If the texture only has an alpha channel (eg, with the textures
-            from the pango renderer) then the RGB components will be
-            black. We want to use the RGB from the current color in that
-            case */
-         g_string_append_printf (
-             shader_source,
-             "gl_FragColor.a *= "
-                 "texture2D (texture_unit[%d], tex_coord[%d]).a;\n",
-                 i, i);
-       }
-      else
-       {
-         g_string_append_printf (
-             shader_source,
-             "gl_FragColor *= "
-                 "texture2D (texture_unit[%d], tex_coord[%d]);\n",
-                 i, i);
-       }
-    }
-  if (i == 0)
-    g_string_append (shader_source, "gl_FragColor = frag_color;\n");
+  for (i = 0; i < n_texture_units; i++)
+    if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i))
+      {
+        if (COGL_GLES2_TEXTURE_UNIT_IS_ALPHA_ONLY (settings->texture_units, i))
+          /* If the texture only has an alpha channel (eg, with the textures
+             from the pango renderer) then the RGB components will be
+             black. We want to use the RGB from the current color in that
+             case */
+          g_string_append_printf (shader_source,
+                                  "gl_FragColor.a *= "
+                                  "texture2D (texture_unit[%d], "
+                                  "tex_coord[%d]).a;\n",
+                                  i, i);
+        else
+          g_string_append_printf (shader_source,
+                                  "gl_FragColor *= "
+                                  "texture2D (texture_unit[%d], "
+                                  "tex_coord[%d]);\n",
+                                  i, i);
+      }
 
   if (settings->fog_enabled)
     g_string_append (shader_source, cogl_fixed_fragment_shader_fog);
@@ -418,31 +453,31 @@ cogl_gles2_wrapper_get_locations (GLuint program,
   uniforms->modelview_matrix_uniform
     = glGetUniformLocation (program, "modelview_matrix");
 
-  uniforms->texture_matrix_uniforms =
-    g_array_new (FALSE, FALSE, sizeof (GLint));
-  uniforms->texture_sampler_uniforms =
-    g_array_new (FALSE, FALSE, sizeof (GLint));
-  attribs->multi_texture_coords =
-    g_array_new (FALSE, FALSE, sizeof (GLint));
-  for (i = 0; i < settings->n_texture_units; i++)
-    {
-      char *matrix_var_name = g_strdup_printf ("texture_matrix[%d]", i);
-      char *sampler_var_name = g_strdup_printf ("texture_unit[%d]", i);
-      char *tex_coord_var_name =
-       g_strdup_printf ("multi_tex_coord_attrib%d", i);
-      GLint location;
-
-      location = glGetUniformLocation (program, matrix_var_name);
-      g_array_append_val (uniforms->texture_matrix_uniforms, location);
-      location = glGetUniformLocation (program, sampler_var_name);
-      g_array_append_val (uniforms->texture_sampler_uniforms, location);
-      location = glGetAttribLocation (program, tex_coord_var_name);
-      g_array_append_val (attribs->multi_texture_coords, location);
-
-      g_free (tex_coord_var_name);
-      g_free (sampler_var_name);
-      g_free (matrix_var_name);
-    }
+  for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
+    if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (settings->texture_units, i))
+      {
+        char *matrix_var_name = g_strdup_printf ("texture_matrix[%d]", i);
+        char *sampler_var_name = g_strdup_printf ("texture_unit[%d]", i);
+        char *tex_coord_var_name =
+          g_strdup_printf ("multi_tex_coord_attrib%d", i);
+
+        uniforms->texture_matrix_uniforms[i]
+          = glGetUniformLocation (program, matrix_var_name);
+        uniforms->texture_sampler_uniforms[i]
+          = glGetUniformLocation (program, sampler_var_name);
+        attribs->multi_texture_coords[i]
+          = glGetAttribLocation (program, tex_coord_var_name);
+
+        g_free (tex_coord_var_name);
+        g_free (sampler_var_name);
+        g_free (matrix_var_name);
+      }
+    else
+      {
+        uniforms->texture_matrix_uniforms[i] = -1;
+        uniforms->texture_sampler_uniforms[i] = -1;
+        attribs->multi_texture_coords[i] = -1;
+      }
 
   uniforms->fog_density_uniform
     = glGetUniformLocation (program, "fog_density");
@@ -633,9 +668,7 @@ cogl_gles2_wrapper_update_matrix (CoglGles2Wrapper *wrapper, GLenum matrix_num)
 
     case GL_TEXTURE:
       wrapper->dirty_uniforms |= COGL_GLES2_DIRTY_TEXTURE_MATRICES;
-      texture_unit = g_array_index (wrapper->texture_units,
-                                   CoglGles2WrapperTextureUnit *,
-                                   wrapper->active_texture_unit);
+      texture_unit = wrapper->texture_units + wrapper->active_texture_unit;
       texture_unit->dirty_matrix = 1;
       break;
     }
@@ -671,9 +704,7 @@ cogl_wrap_glPushMatrix ()
     case GL_TEXTURE:
       {
        CoglGles2WrapperTextureUnit *texture_unit;
-       texture_unit = g_array_index (w->texture_units,
-                                     CoglGles2WrapperTextureUnit *,
-                                     w->active_texture_unit);
+       texture_unit = w->texture_units + w->active_texture_unit;
        src = texture_unit->texture_stack
              + texture_unit->texture_stack_pos * 16;
        texture_unit->texture_stack_pos = (texture_unit->texture_stack_pos + 1)
@@ -709,9 +740,7 @@ cogl_wrap_glPopMatrix ()
       break;
 
     case GL_TEXTURE:
-      texture_unit = g_array_index (w->texture_units,
-                                   CoglGles2WrapperTextureUnit *,
-                                   w->active_texture_unit);
+      texture_unit = w->texture_units + w->active_texture_unit;
       texture_unit->texture_stack_pos = (texture_unit->texture_stack_pos - 1)
        & (COGL_GLES2_TEXTURE_STACK_SIZE - 1);
       break;
@@ -744,10 +773,7 @@ cogl_gles2_get_matrix_stack_top (CoglGles2Wrapper *wrapper)
       return wrapper->projection_stack + wrapper->projection_stack_pos * 16;
 
     case GL_TEXTURE:
-
-      texture_unit = g_array_index (wrapper->texture_units,
-                                   CoglGles2WrapperTextureUnit *,
-                                   wrapper->active_texture_unit);
+      texture_unit = wrapper->texture_units + wrapper->active_texture_unit;
       return texture_unit->texture_stack
        + texture_unit->texture_stack_pos * 16;
     }
@@ -951,9 +977,7 @@ cogl_wrap_glTexCoordPointer (GLint size, GLenum type, GLsizei stride,
 
   active_unit = w->active_client_texture_unit;
 
-  texture_unit = g_array_index (w->texture_units,
-                               CoglGles2WrapperTextureUnit *,
-                               active_unit);
+  texture_unit = w->texture_units + active_unit;
   texture_unit->texture_coords_size = size;
   texture_unit->texture_coords_type = type;
   texture_unit->texture_coords_stride = stride;
@@ -1109,16 +1133,12 @@ cogl_wrap_prepare_for_draw (void)
 
          /* TODO - we should probably have a per unit dirty flag too */
 
-         for (i = 0; i < program->uniforms.texture_matrix_uniforms->len; i++)
+         for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
            {
              CoglGles2WrapperTextureUnit *texture_unit;
-             GLint uniform =
-               g_array_index (program->uniforms.texture_matrix_uniforms,
-                              GLint, i);
+             GLint uniform = program->uniforms.texture_matrix_uniforms[i];
 
-             texture_unit = g_array_index (w->texture_units,
-                                           CoglGles2WrapperTextureUnit *,
-                                           i);
+              texture_unit = w->texture_units + i;
              if (uniform != -1)
                glUniformMatrix4fv (uniform, 1, GL_FALSE,
                                    texture_unit->texture_stack
@@ -1147,11 +1167,9 @@ cogl_wrap_prepare_for_draw (void)
 
           /* TODO - we should probably have a per unit dirty flag too */
 
-          for (i = 0; i < program->uniforms.texture_sampler_uniforms->len; i++)
+          for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
             {
-              GLint uniform =
-                g_array_index (program->uniforms.texture_sampler_uniforms,
-                               GLint, i);
+              GLint uniform = program->uniforms.texture_sampler_uniforms[i];
 
               if (uniform != -1)
                 glUniform1i (uniform, i);
@@ -1194,33 +1212,27 @@ cogl_wrap_prepare_for_draw (void)
       int i;
 
       /* TODO - coverage test */
-      for (i = 0; i < w->settings.n_texture_units; i++)
-       {
-         GLint tex_coord_var_index;
-         CoglGles2WrapperTextureUnit *texture_unit;
-
-         if (!w->settings.texture_units[i].enabled)
-           continue;
-
-         texture_unit = g_array_index (w->texture_units,
-                                       CoglGles2WrapperTextureUnit *,
-                                       w->active_texture_unit);
-         if (!texture_unit->texture_coords_enabled)
-           continue;
-
-         /* TODO - we should probably have a per unit dirty flag too */
-
-         /* TODO - coverage test */
-         tex_coord_var_index =
-           g_array_index (program->attributes.multi_texture_coords,
-                          GLint, i);
-         glVertexAttribPointer (tex_coord_var_index,
-                                texture_unit->texture_coords_size,
-                                texture_unit->texture_coords_type,
-                                GL_FALSE,
-                                texture_unit->texture_coords_stride,
-                                texture_unit->texture_coords_pointer);
-       }
+      for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
+        if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (w->settings.texture_units, i))
+          {
+            GLint tex_coord_var_index;
+            CoglGles2WrapperTextureUnit *texture_unit;
+
+            texture_unit = w->texture_units + w->active_texture_unit;
+            if (!texture_unit->texture_coords_enabled)
+              continue;
+
+            /* TODO - we should probably have a per unit dirty flag too */
+
+            /* TODO - coverage test */
+            tex_coord_var_index = program->attributes.multi_texture_coords[i];
+            glVertexAttribPointer (tex_coord_var_index,
+                                   texture_unit->texture_coords_size,
+                                   texture_unit->texture_coords_type,
+                                   GL_FALSE,
+                                   texture_unit->texture_coords_stride,
+                                   texture_unit->texture_coords_pointer);
+          }
     }
 
   if (w->dirty_vertex_attrib_enables)
@@ -1231,22 +1243,22 @@ cogl_wrap_prepare_for_draw (void)
 
       /* TODO - we should probably have a per unit dirty flag too */
 
-      for (i = 0; i < w->texture_units->len; i++)
+      for (i = 0; i < COGL_GLES2_MAX_TEXTURE_UNITS; i++)
        {
-         CoglGles2WrapperTextureUnit *texture_unit =
-             g_array_index (w->texture_units,
-                            CoglGles2WrapperTextureUnit *,
-                            w->active_texture_unit);
-         if (texture_unit->texture_coords_enabled)
-           glEnableVertexAttribArray (
-             g_array_index (program->attributes.multi_texture_coords,
-                            GLint, i));
-         else
-           glDisableVertexAttribArray (
-             g_array_index (program->attributes.multi_texture_coords,
-                            GLint, i));
-         w->dirty_vertex_attrib_enables = 0;
+         CoglGles2WrapperTextureUnit *texture_unit
+            = w->texture_units + w->active_texture_unit;
+          GLint attrib = program->attributes.multi_texture_coords[i];
+
+          if (attrib != -1)
+            {
+              if (texture_unit->texture_coords_enabled)
+                glEnableVertexAttribArray (attrib);
+              else
+                glDisableVertexAttribArray (attrib);
+            }
        }
+
+      w->dirty_vertex_attrib_enables = 0;
     }
 }
 
@@ -1278,10 +1290,15 @@ cogl_gles2_wrapper_bind_texture (GLenum target, GLuint texture,
   /* We need to keep track of whether the texture is alpha-only
      because the emulation of GL_MODULATE needs to work differently in
      that case */
-  _COGL_GLES2_CHANGE_SETTING (
-      w, texture_units[w->active_texture_unit].alpha_only,
-      internal_format == GL_ALPHA);
-
+  if (COGL_GLES2_TEXTURE_UNIT_IS_ALPHA_ONLY (w->settings.texture_units,
+                                             w->active_texture_unit)
+      != (internal_format == GL_ALPHA))
+    {
+      COGL_GLES2_TEXTURE_UNIT_SET_ALPHA_ONLY (w->settings.texture_units,
+                                              w->active_texture_unit,
+                                              internal_format == GL_ALPHA);
+      w->settings_dirty = TRUE;
+    }
 }
 
 void
@@ -1292,66 +1309,14 @@ cogl_wrap_glTexEnvi (GLenum target, GLenum pname, GLfloat param)
      nothing needs to be done here. */
 }
 
-static void
-realize_texture_units (CoglGles2Wrapper *w, int texture_unit_index)
-{
-  /* We save the active texture unit since we may need to temporarily
-   * change this to initialise each new texture unit and we want to
-   * restore the active unit afterwards */
-  int initial_active_unit = w->active_texture_unit;
-
-  if (texture_unit_index >= w->settings.n_texture_units)
-    {
-      int n_new_texture_units =
-       texture_unit_index + 1 - w->settings.n_texture_units;
-      GLint prev_mode;
-      int i;
-
-      w->settings.texture_units =
-       g_realloc (w->settings.texture_units,
-                  texture_unit_index + 1
-                   * sizeof (CoglGles2WrapperTextureUnitSettings));
-
-      /* We will need to set the matrix mode to GL_TEXTURE to
-       * initialise any new texture units, so we save the current
-       * mode for restoring afterwards */
-      GE( cogl_wrap_glGetIntegerv (CGL_MATRIX_MODE, &prev_mode));
-
-      for (i = 0; i < n_new_texture_units; i++)
-       {
-         CoglGles2WrapperTextureUnit *new_unit;
-         CoglGles2WrapperTextureUnitSettings *new_unit_settings;
-
-         new_unit = g_new0 (CoglGles2WrapperTextureUnit, 1);
-         g_array_append_val (w->texture_units, new_unit);
-
-         w->active_texture_unit = i;
-         GE( cogl_wrap_glMatrixMode (GL_TEXTURE));
-         GE( cogl_wrap_glLoadIdentity ());
-
-         new_unit_settings =
-           &w->settings.texture_units[w->settings.n_texture_units + i];
-         new_unit_settings->enabled = FALSE;
-         new_unit_settings->alpha_only = FALSE;
-       }
-
-      GE( cogl_wrap_glMatrixMode ((GLenum)prev_mode));
-
-      w->settings.n_texture_units = w->texture_units->len;
-    }
-
-  w->active_texture_unit = initial_active_unit;
-}
-
 void
 cogl_wrap_glClientActiveTexture (GLenum texture)
 {
   int texture_unit_index = texture - GL_TEXTURE0;
   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
 
-  w->active_client_texture_unit = texture_unit_index;
-
-  realize_texture_units (w, texture_unit_index);
+  if (texture_unit_index < COGL_GLES2_MAX_TEXTURE_UNITS)
+    w->active_client_texture_unit = texture_unit_index;
 }
 
 void
@@ -1360,9 +1325,8 @@ cogl_wrap_glActiveTexture (GLenum texture)
   int texture_unit_index = texture - GL_TEXTURE0;
   _COGL_GET_GLES2_WRAPPER (w, NO_RETVAL);
 
-  w->active_texture_unit = texture_unit_index;
-
-  realize_texture_units (w, texture_unit_index);
+  if (texture_unit_index < COGL_GLES2_MAX_TEXTURE_UNITS)
+    w->active_texture_unit = texture_unit_index;
 }
 
 void
@@ -1373,8 +1337,14 @@ cogl_wrap_glEnable (GLenum cap)
   switch (cap)
     {
     case GL_TEXTURE_2D:
-      _COGL_GLES2_CHANGE_SETTING (
-         w, texture_units[w->active_texture_unit].enabled, TRUE);
+      if (!COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (w->settings.texture_units,
+                                               w->active_texture_unit))
+        {
+          COGL_GLES2_TEXTURE_UNIT_SET_ENABLED (w->settings.texture_units,
+                                               w->active_texture_unit,
+                                               TRUE);
+          w->settings_dirty = TRUE;
+        }
       break;
 
     case GL_FOG:
@@ -1398,8 +1368,14 @@ cogl_wrap_glDisable (GLenum cap)
   switch (cap)
     {
     case GL_TEXTURE_2D:
-      _COGL_GLES2_CHANGE_SETTING (
-         w, texture_units[w->active_texture_unit].enabled, FALSE);
+      if (COGL_GLES2_TEXTURE_UNIT_IS_ENABLED (w->settings.texture_units,
+                                              w->active_texture_unit))
+        {
+          COGL_GLES2_TEXTURE_UNIT_SET_ENABLED (w->settings.texture_units,
+                                               w->active_texture_unit,
+                                               FALSE);
+          w->settings_dirty = TRUE;
+        }
       break;
 
     case GL_FOG:
@@ -1429,9 +1405,7 @@ cogl_wrap_glEnableClientState (GLenum array)
     case GL_TEXTURE_COORD_ARRAY:
       /* TODO - review if this should be in w->settings? */
 
-      texture_unit = g_array_index (w->texture_units,
-                                   CoglGles2WrapperTextureUnit *,
-                                   w->active_texture_unit);
+      texture_unit = w->texture_units + w->active_texture_unit;
       if (texture_unit->texture_coords_enabled != 1)
        {
          texture_unit->texture_coords_enabled = 1;
@@ -1461,9 +1435,7 @@ cogl_wrap_glDisableClientState (GLenum array)
       break;
     case GL_TEXTURE_COORD_ARRAY:
 
-      texture_unit = g_array_index (w->texture_units,
-                                   CoglGles2WrapperTextureUnit *,
-                                   w->active_texture_unit);
+      texture_unit = w->texture_units + w->active_texture_unit;
       /* TODO - review if this should be in w->settings? */
       if (texture_unit->texture_coords_enabled != 0)
        {
index 4ae3370..ec6860b 100644 (file)
@@ -52,6 +52,20 @@ typedef struct _CoglGles2WrapperShader         CoglGles2WrapperShader;
 #define COGL_GLES2_PROJECTION_STACK_SIZE  2
 #define COGL_GLES2_TEXTURE_STACK_SIZE     2
 
+/* Accessors for the texture unit bit mask */
+#define COGL_GLES2_TEXTURE_UNIT_IS_ENABLED(mask, unit)  \
+  (((mask) & (1 << ((unit) * 2))) ? TRUE : FALSE)
+#define COGL_GLES2_TEXTURE_UNIT_IS_ALPHA_ONLY(mask, unit)       \
+  (((mask) & (1 << ((unit) * 2 + 1))) ? TRUE : FALSE)
+#define COGL_GLES2_SET_BIT(mask, bit, val)                              \
+  ((val) ? ((mask) |= (1 << (bit))) : ((mask) &= ~(1 << (bit))))
+#define COGL_GLES2_TEXTURE_UNIT_SET_ENABLED(mask, unit, val)    \
+  COGL_GLES2_SET_BIT ((mask), (unit) * 2, (val))
+#define COGL_GLES2_TEXTURE_UNIT_SET_ALPHA_ONLY(mask, unit, val) \
+  COGL_GLES2_SET_BIT ((mask), (unit) * 2 + 1, (val))
+
+#define COGL_GLES2_MAX_TEXTURE_UNITS (sizeof (guint32) * 8 / 2)
+
 /* Dirty flags for shader uniforms */
 enum
   {
@@ -82,16 +96,15 @@ enum
 
 struct _CoglGles2WrapperAttributes
 {
-  GArray    *multi_texture_coords;
+  GLint      multi_texture_coords[COGL_GLES2_MAX_TEXTURE_UNITS];
 };
 
 struct _CoglGles2WrapperUniforms
 {
   GLint      mvp_matrix_uniform;
   GLint      modelview_matrix_uniform;
-  GArray    *texture_matrix_uniforms;
-
-  GArray    *texture_sampler_uniforms;
+  GLint      texture_matrix_uniforms[COGL_GLES2_MAX_TEXTURE_UNITS];
+  GLint      texture_sampler_uniforms[COGL_GLES2_MAX_TEXTURE_UNITS];
 
   GLint      fog_density_uniform;
   GLint      fog_start_uniform;
@@ -100,14 +113,7 @@ struct _CoglGles2WrapperUniforms
 
   GLint      alpha_test_ref_uniform;
 
-  GLint     texture_unit_uniform;
-};
-
-struct _CoglGles2WrapperTextureUnitSettings
-{
-  guint        enabled:1;
-  guint alpha_only:1;
-  /* TODO: blending state */
+  GLint      texture_unit_uniform;
 };
 
 /* NB: We get a copy of this for each fragment/vertex
@@ -115,8 +121,7 @@ struct _CoglGles2WrapperTextureUnitSettings
  * fairly lean */
 struct _CoglGles2WrapperSettings
 {
-  CoglGles2WrapperTextureUnitSettings *texture_units;
-  guint           n_texture_units;
+  guint32  texture_units;
 
   GLint    alpha_test_func;
   GLint    fog_mode;
@@ -149,10 +154,11 @@ struct _CoglGles2Wrapper
   GLuint     modelview_stack_pos;
   GLfloat    projection_stack[COGL_GLES2_PROJECTION_STACK_SIZE * 16];
   GLuint     projection_stack_pos;
-  GArray    *texture_units;
   guint             active_texture_unit;
   guint             active_client_texture_unit;
 
+  CoglGles2WrapperTextureUnit texture_units[COGL_GLES2_MAX_TEXTURE_UNITS];
+
   /* The combined modelview and projection matrix is only updated at
      the last minute in glDrawArrays to avoid recalculating it for
      every change to the modelview matrix */