material: Avoid redundant glBindTexture calls
authorRobert Bragg <robert@linux.intel.com>
Mon, 26 Apr 2010 09:01:43 +0000 (10:01 +0100)
committerRobert Bragg <robert@linux.intel.com>
Wed, 9 Jun 2010 16:26:15 +0000 (17:26 +0100)
This adds a _cogl_bind_gl_texture_transient function that should be used
instead of glBindTexture so we can have a consistent cache of the
textures bound to each texture unit so we can avoid some redundant
binding.

12 files changed:
clutter/cogl/cogl/cogl-atlas-texture.c
clutter/cogl/cogl/cogl-material-private.h
clutter/cogl/cogl/cogl-material.c
clutter/cogl/cogl/cogl-sub-texture.c
clutter/cogl/cogl/cogl-texture-2d-sliced.c
clutter/cogl/cogl/cogl-texture-2d.c
clutter/cogl/cogl/cogl-texture-driver.h
clutter/cogl/cogl/cogl-texture-private.h
clutter/cogl/cogl/cogl-texture.c
clutter/cogl/cogl/driver/gl/cogl-texture-driver.c
clutter/cogl/cogl/driver/gles/cogl-texture-driver.c
clutter/glx/clutter-glx-texture-pixmap.c

index b15a85c..b414b46 100644 (file)
@@ -146,7 +146,9 @@ _cogl_atlas_texture_blit_begin (CoglAtlasTextureBlitData *data,
           data->fbo = 0;
         }
 
-      GE( glBindTexture (data->dst_gl_target, dst_gl_texture) );
+      _cogl_bind_gl_texture_transient (data->dst_gl_target,
+                                       dst_gl_texture,
+                                       FALSE);
     }
 
   if (data->fbo)
@@ -274,7 +276,8 @@ _cogl_atlas_texture_free (CoglAtlasTexture *atlas_tex)
 
   cogl_handle_unref (atlas_tex->sub_texture);
 
-  g_free (atlas_tex);
+  /* Chain up */
+  _cogl_texture_free (COGL_TEXTURE (atlas_tex));
 }
 
 static int
@@ -1074,5 +1077,6 @@ cogl_atlas_texture_vtable =
     _cogl_atlas_texture_get_format,
     _cogl_atlas_texture_get_gl_format,
     _cogl_atlas_texture_get_width,
-    _cogl_atlas_texture_get_height
+    _cogl_atlas_texture_get_height,
+    NULL /* is_foreign */
   };
index ed98393..08ea013 100644 (file)
@@ -70,6 +70,26 @@ typedef struct _CoglTextureUnit
    * with a layer may represent more than one GL texture) */
   GLuint             gl_texture;
 
+  /* Foreign textures are those not created or deleted by Cogl. If we ever
+   * call glBindTexture for a foreign texture then the next time we are
+   * asked to glBindTexture we can't try and optimize a redundant state
+   * change because we don't know if the original texture name was deleted
+   * and now we are being asked to bind a recycled name. */
+  gboolean           is_foreign;
+
+  /* We have many components in Cogl that need to temporarily bind arbitrary
+   * textures e.g. to query texture object parameters and since we don't
+   * want that to result in too much redundant reflushing of layer state
+   * when all that's needed is to re-bind the layers gl_texture we use this
+   * to track when the .layer_gl_texture state is invalid.
+   *
+   * XXX: as a further optimization cogl-material.c uses a convention
+   * of always leaving texture unit 1 active when not dealing with the
+   * flushing of layer state, so we can assume this is only ever TRUE
+   * for unit 1.
+   */
+  gboolean           dirty_gl_texture;
+
   /* A matrix stack giving us the means to associate a texture
    * transform matrix with the texture unit. */
   CoglMatrixStack   *matrix_stack;
@@ -123,6 +143,11 @@ _cogl_get_texture_unit (int index_);
 void
 _cogl_destroy_texture_units (void);
 
+void
+_cogl_bind_gl_texture_transient (GLenum gl_target,
+                                 GLuint gl_texture,
+                                 gboolean is_foreign);
+
 typedef enum _CoglMaterialEqualFlags
 {
   /* Return FALSE if any component of either material isn't set to its
@@ -441,6 +466,9 @@ _cogl_material_set_user_program (CoglHandle handle,
                                  CoglHandle program);
 
 void
+_cogl_delete_gl_texture (GLuint gl_texture);
+
+void
 _cogl_material_apply_legacy_state (CoglHandle handle);
 
 void
index fd08dd9..fce8543 100644 (file)
@@ -962,6 +962,8 @@ texture_unit_init (CoglTextureUnit *unit, int index_)
   unit->enabled = FALSE;
   unit->enabled_gl_target = 0;
   unit->gl_texture = 0;
+  unit->is_foreign = FALSE;
+  unit->dirty_gl_texture = FALSE;
   unit->matrix_stack = _cogl_matrix_stack_new ();
 
   unit->layer = NULL;
@@ -1027,6 +1029,71 @@ set_active_texture_unit (int unit_index)
     }
 }
 
+/* Note: this conceptually has slightly different semantics to
+ * OpenGL's glBindTexture because Cogl never cares about tracking
+ * multiple textures bound to different targets on the same texture
+ * unit.
+ *
+ * glBindTexture lets you bind multiple textures to a single texture
+ * unit if they are bound to different targets. So it does something
+ * like:
+ *   unit->current_texture[target] = texture;
+ *
+ * Cogl only lets you associate one texture with the currently active
+ * texture unit, so the target is basically a redundant parameter
+ * that's implicitly set on that texture.
+ *
+ * Technically this is just a thin wrapper around glBindTexture so
+ * actually it does have the GL semantics but it seems worth
+ * mentioning the conceptual difference in case anyone wonders why we
+ * don't associate the gl_texture with a gl_target in the
+ * CoglTextureUnit.
+ */
+void
+_cogl_bind_gl_texture_transient (GLenum gl_target,
+                                 GLuint gl_texture,
+                                 gboolean is_foreign)
+{
+  CoglTextureUnit *unit;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  unit = _cogl_get_texture_unit (ctx->active_texture_unit);
+
+  /* NB: If we have previously bound a foreign texture to this texture
+   * unit we don't know if that texture has since been deleted and we
+   * are seeing the texture name recycled */
+  if (unit->gl_texture == gl_texture &&
+      !unit->dirty_gl_texture &&
+      !unit->is_foreign)
+    return;
+
+  GE (glBindTexture (gl_target, gl_texture));
+
+  unit->dirty_gl_texture = TRUE;
+  unit->is_foreign = is_foreign;
+}
+
+void
+_cogl_delete_gl_texture (GLuint gl_texture)
+{
+  int i;
+
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  for (i = 0; i < ctx->texture_units->len; i++)
+    {
+      CoglTextureUnit *unit =
+        &g_array_index (ctx->texture_units, CoglTextureUnit, i);
+
+      if (unit->gl_texture == gl_texture)
+        {
+          unit->gl_texture = 0;
+          unit->dirty_gl_texture = FALSE;
+        }
+    }
+}
+
 /* Asserts that a layer corresponding to the given index exists. If no
  * match is found, then a new empty layer is added.
  */
@@ -2926,14 +2993,42 @@ _cogl_material_flush_common_gl_state (CoglMaterial *material,
       unit->layer0_overridden = layer0_override_texture ? TRUE : FALSE;
       unit->fallback = fallback;
 
-      /* FIXME: We could be more clever here and only bind the texture
-         if it is different from gl_layer_info->gl_texture to avoid
-         redundant GL calls. However a few other places in Cogl and
-         Clutter call glBindTexture such as ClutterGLXTexturePixmap so
-         we'd need to ensure they affect the cache. Also deleting a
-         texture should clear it from the cache in case a new texture
-         is generated with the same number */
+      /* NB: There are several Cogl components and some code in
+       * Clutter that will temporarily bind arbitrary GL textures to
+       * query and modify texture object parameters. If you look at
+       * the end of _cogl_material_flush_gl_state() you can see we
+       * make sure that such code always binds to texture unit 1 by
+       * always leaving texture unit 1 active. This means we can't
+       * rely on the unit->gl_texture state if unit->index == 1.
+       * Because texture unit 1 is a bit special we actually defer any
+       * necessary glBindTexture for it until the end of
+       * _cogl_material_flush_gl_state().
+       *
+       * NB: we get notified whenever glDeleteTextures is used (see
+       * _cogl_delete_gl_texture()) where we invalidate
+       * unit->gl_texture references to deleted textures so it's safe
+       * to compare unit->gl_texture with gl_texture.  (Without the
+       * hook it would be possible to delete a GL texture and create a
+       * new one with the same name and comparing unit->gl_texture and
+       * gl_texture wouldn't detect that.)
+       *
+       * NB: for foreign textures we don't know how the deletion of
+       * the GL texture objects correspond to the deletion of the
+       * CoglTextures so if there was previously a foreign texture
+       * associated with the texture unit then we can't assume that we
+       * aren't seeing a recycled texture name so we have to bind.
+       */
+#ifndef DISABLE_MATERIAL_CACHE
+      if (unit->gl_texture != gl_texture || unit->is_foreign)
+        {
+          if (unit->index != 1)
+            GE (glBindTexture (gl_target, gl_texture));
+          unit->gl_texture = gl_texture;
+        }
+#else
       GE (glBindTexture (gl_target, gl_texture));
+#endif
+      unit->is_foreign = _cogl_texture_is_foreign (texture);
 
       /* Disable the previous target if it was different and it's
        * still enabled */
@@ -3275,10 +3370,11 @@ done: /* well, almost... */
    * unless multitexturing is being used.
    */
   unit1 = _cogl_get_texture_unit (1);
-  if (unit1->enabled)
+  if (unit1->enabled && unit1->dirty_gl_texture)
     {
       set_active_texture_unit (1);
       GE (glBindTexture (unit1->enabled_gl_target, unit1->gl_texture));
+      unit1->dirty_gl_texture = FALSE;
     }
 
   /* Since there are several places where Cogl will temporarily bind a
index 2af29f5..22a1c88 100644 (file)
@@ -243,7 +243,8 @@ _cogl_sub_texture_free (CoglSubTexture *sub_tex)
   cogl_handle_unref (sub_tex->next_texture);
   cogl_handle_unref (sub_tex->full_texture);
 
-  g_free (sub_tex);
+  /* Chain up */
+  _cogl_texture_free (COGL_TEXTURE (sub_tex));
 }
 
 CoglHandle
@@ -556,5 +557,6 @@ cogl_sub_texture_vtable =
     _cogl_sub_texture_get_format,
     _cogl_sub_texture_get_gl_format,
     _cogl_sub_texture_get_width,
-    _cogl_sub_texture_get_height
+    _cogl_sub_texture_get_height,
+    NULL /* is_foreign */
   };
index c2268df..8a56970 100644 (file)
@@ -42,6 +42,7 @@
 #include "cogl-handle.h"
 #include "cogl-spans.h"
 #include "cogl-journal-private.h"
+#include "cogl-material-private.h"
 
 #include <string.h>
 #include <stdlib.h>
@@ -253,6 +254,7 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
           _cogl_texture_driver_upload_subregion_to_gl (
                                      tex_2ds->gl_target,
                                      gl_handle,
+                                     tex_2ds->is_foreign,
                                      x_span->start, /* src x */
                                      y_span->start, /* src y */
                                      0, /* dst x */
@@ -441,6 +443,7 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
 
           _cogl_texture_driver_upload_subregion_to_gl (tex_2ds->gl_target,
                                                        gl_handle,
+                                                       tex_2ds->is_foreign,
                                                        source_x,
                                                        source_y,
                                                        local_x, /* dst x */
@@ -680,7 +683,9 @@ _cogl_texture_2d_sliced_set_wrap_mode_parameters (CoglTexture *tex,
         {
           GLuint texnum = g_array_index (tex_2ds->slice_gl_handles, GLuint, i);
 
-          GE( glBindTexture (tex_2ds->gl_target, texnum) );
+          _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
+                                           texnum,
+                                           tex_2ds->is_foreign);
           GE( glTexParameteri (tex_2ds->gl_target,
                                GL_TEXTURE_WRAP_S, wrap_mode_s) );
           GE( glTexParameteri (tex_2ds->gl_target,
@@ -855,8 +860,9 @@ _cogl_texture_2d_sliced_slices_create (CoglTexture2DSliced *tex_2ds,
                      y_span->size - y_span->waste);
 
           /* Setup texture parameters */
-          GE( glBindTexture (tex_2ds->gl_target,
-                             gl_handles[y * n_x_slices + x] ) );
+          _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
+                                           gl_handles[y * n_x_slices + x],
+                                           FALSE);
 
           _cogl_texture_driver_try_setting_gl_border_color (tex_2ds->gl_target,
                                                             transparent_color);
@@ -882,11 +888,14 @@ _cogl_texture_2d_sliced_slices_free (CoglTexture2DSliced *tex_2ds)
 
   if (tex_2ds->slice_gl_handles != NULL)
     {
+      int i;
       if (tex_2ds->is_foreign == FALSE)
-        {
-          GE( glDeleteTextures (tex_2ds->slice_gl_handles->len,
-                                (GLuint*) tex_2ds->slice_gl_handles->data) );
-        }
+        for (i = 0; i < tex_2ds->slice_gl_handles->len; i++)
+          {
+            GLuint texture =
+              g_array_index (tex_2ds->slice_gl_handles, GLuint, i);
+            _cogl_delete_gl_texture (texture);
+          }
 
       g_array_free (tex_2ds->slice_gl_handles, TRUE);
     }
@@ -899,7 +908,9 @@ static void
 _cogl_texture_2d_sliced_free (CoglTexture2DSliced *tex_2ds)
 {
   _cogl_texture_2d_sliced_slices_free (tex_2ds);
-  g_free (tex_2ds);
+
+  /* Chain up */
+  _cogl_texture_free (COGL_TEXTURE (tex_2ds));
 }
 
 static gboolean
@@ -1121,7 +1132,8 @@ _cogl_texture_2d_sliced_new_from_foreign (GLuint           gl_handle,
   /* Make sure binding succeeds */
   while ((gl_error = glGetError ()) != GL_NO_ERROR)
     ;
-  glBindTexture (gl_target, gl_handle);
+
+  _cogl_bind_gl_texture_transient (gl_target, gl_handle, TRUE);
   if (glGetError () != GL_NO_ERROR)
     return COGL_INVALID_HANDLE;
 
@@ -1226,6 +1238,12 @@ _cogl_texture_2d_sliced_new_from_foreign (GLuint           gl_handle,
   return _cogl_texture_2d_sliced_handle_new (tex_2ds);
 }
 
+static gboolean
+_cogl_texture_2d_sliced_is_foreign (CoglTexture *tex)
+{
+  return COGL_TEXTURE_2D_SLICED (tex)->is_foreign;
+}
+
 static int
 _cogl_texture_2d_sliced_get_max_waste (CoglTexture *tex)
 {
@@ -1371,7 +1389,9 @@ _cogl_texture_2d_sliced_set_filters (CoglTexture *tex,
   for (i=0; i<tex_2ds->slice_gl_handles->len; ++i)
     {
       gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint, i);
-      GE( glBindTexture (tex_2ds->gl_target, gl_handle) );
+      _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
+                                       gl_handle,
+                                       tex_2ds->is_foreign);
       GE( glTexParameteri (tex_2ds->gl_target, GL_TEXTURE_MAG_FILTER,
                            tex_2ds->mag_filter) );
       GE( glTexParameteri (tex_2ds->gl_target, GL_TEXTURE_MIN_FILTER,
@@ -1399,7 +1419,9 @@ _cogl_texture_2d_sliced_ensure_mipmaps (CoglTexture *tex)
   for (i = 0; i < tex_2ds->slice_gl_handles->len; i++)
     {
       GLuint gl_handle = g_array_index (tex_2ds->slice_gl_handles, GLuint, i);
-      GE( glBindTexture (tex_2ds->gl_target, gl_handle) );
+      _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
+                                       gl_handle,
+                                       tex_2ds->is_foreign);
 
       /* glGenerateMipmap is defined in the FBO extension */
       if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
@@ -1544,7 +1566,9 @@ _cogl_texture_2d_sliced_download_from_gl (
                                                           bpp);
 
              /* Download slice image data into temp bmp */
-             GE( glBindTexture (tex_2ds->gl_target, gl_handle) );
+              _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
+                                               gl_handle,
+                                               tex_2ds->is_foreign);
 
               if (!_cogl_texture_driver_gl_get_tex_image (tex_2ds->gl_target,
                                                           target_gl_format,
@@ -1578,7 +1602,9 @@ _cogl_texture_2d_sliced_download_from_gl (
                                                         bpp);
 
              /* Download slice image data */
-             GE( glBindTexture (tex_2ds->gl_target, gl_handle) );
+              _cogl_bind_gl_texture_transient (tex_2ds->gl_target,
+                                               gl_handle,
+                                               tex_2ds->is_foreign);
 
               if (!_cogl_texture_driver_gl_get_tex_image (tex_2ds->gl_target,
                                                           target_gl_format,
@@ -1737,5 +1763,6 @@ cogl_texture_2d_sliced_vtable =
     _cogl_texture_2d_sliced_get_format,
     _cogl_texture_2d_sliced_get_gl_format,
     _cogl_texture_2d_sliced_get_width,
-    _cogl_texture_2d_sliced_get_height
+    _cogl_texture_2d_sliced_get_height,
+    _cogl_texture_2d_sliced_is_foreign
   };
index 793c5cd..a7bcbf3 100644 (file)
@@ -37,6 +37,7 @@
 #include "cogl-context.h"
 #include "cogl-handle.h"
 #include "cogl-journal-private.h"
+#include "cogl-material-private.h"
 
 #include <string.h>
 #include <math.h>
@@ -137,7 +138,9 @@ _cogl_texture_2d_set_wrap_mode_parameters (CoglTexture *tex,
   if (tex_2d->wrap_mode_s != wrap_mode_s ||
       tex_2d->wrap_mode_t != wrap_mode_t)
     {
-      GE( glBindTexture (GL_TEXTURE_2D, tex_2d->gl_texture) );
+      _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                       tex_2d->gl_texture,
+                                       FALSE);
       GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode_s) );
       GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode_t) );
 
@@ -149,8 +152,10 @@ _cogl_texture_2d_set_wrap_mode_parameters (CoglTexture *tex,
 static void
 _cogl_texture_2d_free (CoglTexture2D *tex_2d)
 {
-  GE( glDeleteTextures (1, &tex_2d->gl_texture) );
-  g_free (tex_2d);
+  _cogl_delete_gl_texture (tex_2d->gl_texture);
+
+  /* Chain up */
+  _cogl_texture_free (COGL_TEXTURE (tex_2d));
 }
 
 static gboolean
@@ -253,7 +258,9 @@ _cogl_texture_2d_new_with_size (unsigned int     width,
   tex_2d = _cogl_texture_2d_create_base (width, height, flags, internal_format);
 
   _cogl_texture_driver_gen (GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
-  GE( glBindTexture (GL_TEXTURE_2D, tex_2d->gl_texture) );
+  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                   tex_2d->gl_texture,
+                                   FALSE);
   GE( glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat,
                     width, height, 0, gl_format, gl_type, NULL) );
 
@@ -299,6 +306,7 @@ _cogl_texture_2d_new_from_bitmap (CoglHandle       bmp_handle,
   _cogl_texture_driver_gen (GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
   _cogl_texture_driver_upload_to_gl (GL_TEXTURE_2D,
                                      tex_2d->gl_texture,
+                                     FALSE,
                                      &dst_bmp,
                                      gl_intformat,
                                      gl_format,
@@ -389,7 +397,9 @@ _cogl_texture_2d_set_filters (CoglTexture *tex,
   tex_2d->mag_filter = mag_filter;
 
   /* Apply new filters to the texture */
-  GE( glBindTexture (GL_TEXTURE_2D, tex_2d->gl_texture) );
+  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                   tex_2d->gl_texture,
+                                   FALSE);
   GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter) );
   GE( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter) );
 }
@@ -405,7 +415,9 @@ _cogl_texture_2d_ensure_mipmaps (CoglTexture *tex)
   if (!tex_2d->auto_mipmap || !tex_2d->mipmaps_dirty)
     return;
 
-  GE( glBindTexture (GL_TEXTURE_2D, tex_2d->gl_texture) );
+  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                   tex_2d->gl_texture,
+                                   FALSE);
   /* glGenerateMipmap is defined in the FBO extension. We only allow
      CoglTexture2D instances to be created if this feature is
      available so we don't need to check for the extension */
@@ -474,6 +486,7 @@ _cogl_texture_2d_set_region (CoglTexture    *tex,
   /* Send data to GL */
   _cogl_texture_driver_upload_subregion_to_gl (GL_TEXTURE_2D,
                                                tex_2d->gl_texture,
+                                               FALSE,
                                                src_x, src_y,
                                                dst_x, dst_y,
                                                dst_width, dst_height,
@@ -552,7 +565,9 @@ _cogl_texture_2d_get_data (CoglTexture     *tex,
   _cogl_texture_driver_prep_gl_for_pixels_download (target_bmp.rowstride,
                                                     closest_bpp);
 
-  GE( glBindTexture (GL_TEXTURE_2D, tex_2d->gl_texture) );
+  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                   tex_2d->gl_texture,
+                                   FALSE);
   if (!_cogl_texture_driver_gl_get_tex_image (GL_TEXTURE_2D,
                                               closest_gl_format,
                                               closest_gl_type,
@@ -638,5 +653,6 @@ cogl_texture_2d_vtable =
     _cogl_texture_2d_get_format,
     _cogl_texture_2d_get_gl_format,
     _cogl_texture_2d_get_width,
-    _cogl_texture_2d_get_height
+    _cogl_texture_2d_get_height,
+    NULL /* is_foreign */
   };
index 1728ee1..725629b 100644 (file)
@@ -61,6 +61,7 @@ _cogl_texture_driver_prep_gl_for_pixels_upload (int pixels_rowstride,
 void
 _cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
                                              GLuint       gl_handle,
+                                             gboolean     is_foreign,
                                              int          src_x,
                                              int          src_y,
                                              int          dst_x,
@@ -80,6 +81,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
 void
 _cogl_texture_driver_upload_to_gl (GLenum       gl_target,
                                    GLuint       gl_handle,
+                                   gboolean     is_foreign,
                                    CoglBitmap  *source_bmp,
                                    GLint        internal_gl_format,
                                    GLuint       source_gl_format,
index 0f97233..74ffe03 100644 (file)
@@ -118,6 +118,8 @@ struct _CoglTextureVtable
   GLenum (* get_gl_format) (CoglTexture *tex);
   int (* get_width) (CoglTexture *tex);
   int (* get_height) (CoglTexture *tex);
+
+  gboolean (* is_foreign) (CoglTexture *tex);
 };
 
 struct _CoglTexture
@@ -126,6 +128,20 @@ struct _CoglTexture
   const CoglTextureVtable *vtable;
 };
 
+typedef enum _CoglTextureChangeFlags
+{
+  /* Whenever the internals of a texture are changed such that the
+   * underlying GL textures that represent the CoglTexture change then
+   * we notify cogl-material.c via
+   * _cogl_material_texture_pre_change_notify
+   */
+  COGL_TEXTURE_CHANGE_GL_TEXTURES
+
+} CoglTextureChangeFlags;
+
+void
+_cogl_texture_free (CoglTexture *texture);
+
 void
 _cogl_texture_foreach_sub_texture_in_region (CoglHandle handle,
                                              float virtual_tx_1,
@@ -215,4 +231,7 @@ _cogl_texture_draw_and_read (CoglHandle   handle,
                              GLuint       target_gl_format,
                              GLuint       target_gl_type);
 
+gboolean
+_cogl_texture_is_foreign (CoglHandle handle);
+
 #endif /* __COGL_TEXTURE_PRIVATE_H */
index b192a8a..1dbcbbf 100644 (file)
@@ -102,6 +102,12 @@ cogl_texture_unref (CoglHandle handle)
   cogl_handle_unref (handle);
 }
 
+void
+_cogl_texture_free (CoglTexture *texture)
+{
+  g_free (texture);
+}
+
 static gboolean
 _cogl_texture_needs_premult_conversion (CoglPixelFormat src_format,
                                         CoglPixelFormat dst_format)
@@ -471,6 +477,8 @@ cogl_texture_new_from_foreign (GLuint           gl_handle,
                               GLuint           y_pot_waste,
                               CoglPixelFormat  format)
 {
+  /* FIXME: only create a sliced texture if x or y waste was specified
+   */
   return _cogl_texture_2d_sliced_new_from_foreign (gl_handle,
                                                    gl_target,
                                                    width,
@@ -480,6 +488,21 @@ cogl_texture_new_from_foreign (GLuint           gl_handle,
                                                    format);
 }
 
+gboolean
+_cogl_texture_is_foreign (CoglHandle handle)
+{
+  CoglTexture *tex;
+
+  g_return_val_if_fail (cogl_is_texture (handle), FALSE);
+
+  tex = COGL_TEXTURE (handle);
+
+  if (tex->vtable->is_foreign)
+    return tex->vtable->is_foreign (tex);
+  else
+    return FALSE;
+}
+
 CoglHandle
 cogl_texture_new_from_sub_texture (CoglHandle full_texture,
                                    int        sub_x,
index 01eedc7..2726104 100644 (file)
@@ -40,6 +40,7 @@
 #include "cogl-context.h"
 #include "cogl-handle.h"
 #include "cogl-primitives.h"
+#include "cogl-material-private.h"
 
 #include <string.h>
 #include <stdlib.h>
@@ -58,7 +59,9 @@ _cogl_texture_driver_gen (GLenum   gl_target,
 
   for (i = 0; i < n; i++)
     {
-      GE (glBindTexture (gl_target, textures[i]));
+      _cogl_bind_gl_texture_transient (gl_target,
+                                       textures[i],
+                                       FALSE);
 
       switch (gl_target)
         {
@@ -123,6 +126,7 @@ _cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride,
 void
 _cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
                                              GLuint       gl_handle,
+                                             gboolean     is_foreign,
                                              int          src_x,
                                              int          src_y,
                                              int          dst_x,
@@ -141,7 +145,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
                                   src_y,
                                   bpp);
 
-  GE( glBindTexture (gl_target, gl_handle) );
+  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
 
   GE( glTexSubImage2D (gl_target, 0,
                        dst_x, dst_y,
@@ -154,6 +158,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
 void
 _cogl_texture_driver_upload_to_gl (GLenum       gl_target,
                                    GLuint       gl_handle,
+                                   gboolean     is_foreign,
                                    CoglBitmap  *source_bmp,
                                    GLint        internal_gl_format,
                                    GLuint       source_gl_format,
@@ -164,7 +169,7 @@ _cogl_texture_driver_upload_to_gl (GLenum       gl_target,
   /* Setup gl alignment to match rowstride and top-left corner */
   prep_gl_for_pixels_upload_full (source_bmp->rowstride, 0, 0, bpp);
 
-  GE( glBindTexture (gl_target, gl_handle) );
+  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
 
   GE( glTexImage2D (gl_target, 0,
                     internal_gl_format,
index ac55c87..af03ef9 100644 (file)
@@ -37,6 +37,7 @@
 #include "cogl-bitmap-private.h"
 #include "cogl-texture-private.h"
 #include "cogl-material.h"
+#include "cogl-material-private.h"
 #include "cogl-context.h"
 #include "cogl-handle.h"
 #include "cogl-primitives.h"
@@ -58,7 +59,7 @@ _cogl_texture_driver_gen (GLenum   gl_target,
 
   for (i = 0; i < n; i++)
     {
-      GE (glBindTexture (gl_target, textures[i]));
+      _cogl_bind_gl_texture_transient (gl_target, textures[i], FALSE);
 
       switch (gl_target)
         {
@@ -91,6 +92,7 @@ _cogl_texture_driver_prep_gl_for_pixels_download (int pixels_rowstride,
 void
 _cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
                                              GLuint       gl_handle,
+                                             gboolean     is_foreign,
                                              int          src_x,
                                              int          src_y,
                                              int          dst_x,
@@ -131,7 +133,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
                                slice_bmp.width,
                                slice_bmp.height);
 
-  GE( glBindTexture (gl_target, gl_handle) );
+  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
 
   GE( glTexSubImage2D (gl_target, 0,
                        dst_x, dst_y,
@@ -147,6 +149,7 @@ _cogl_texture_driver_upload_subregion_to_gl (GLenum       gl_target,
 void
 _cogl_texture_driver_upload_to_gl (GLenum       gl_target,
                                    GLuint       gl_handle,
+                                   gboolean     is_foreign,
                                    CoglBitmap  *source_bmp,
                                    GLint        internal_gl_format,
                                    GLuint       source_gl_format,
@@ -175,7 +178,7 @@ _cogl_texture_driver_upload_to_gl (GLenum       gl_target,
   _cogl_texture_driver_prep_gl_for_pixels_upload (bmp.rowstride,
                                                   bpp);
 
-  GE( glBindTexture (gl_target, gl_handle) );
+  _cogl_bind_gl_texture_transient (gl_target, gl_handle, is_foreign);
 
   GE( glTexImage2D (gl_target, 0,
                     internal_gl_format,
index 3e4cf2d..3bd58a6 100644 (file)
@@ -67,6 +67,7 @@
 #include "../clutter-private.h"
 
 #include "cogl/cogl.h"
+#include "cogl/cogl-material-private.h"
 
 typedef void    (*BindTexImage) (Display     *display,
                                  GLXDrawable  drawable,
@@ -141,7 +142,10 @@ bind_texture (ClutterGLXTexturePixmap *tex)
   if (!cogl_texture_get_gl_texture (cogl_tex, &handle, &target))
     g_warning ("Failed to pluck out GL handle from cogl texture to bind");
 
-  glBindTexture (target, handle);
+  if (tex->priv->using_rectangle)
+    _cogl_bind_gl_texture_transient (target, handle, TRUE);
+  else
+    _cogl_bind_gl_texture_transient (target, handle, FALSE);
 }
 
 static void
@@ -426,7 +430,7 @@ create_cogl_texture (ClutterTexture *texture,
       using_rectangle = TRUE;
 
       glGenTextures (1, &tex);
-      glBindTexture (GL_TEXTURE_RECTANGLE_ARB, tex);
+      _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, tex, TRUE);
       glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0,
                     gl_format, width, height,
                     0, GL_RGB, GL_UNSIGNED_BYTE, NULL);