I was doing some profiling on Mutter in one particular case: alt-Tabbing
with the classic "draw border around window" alt-tab indication. This is
implemented by creating a big window and shaping it to a narrow
rectangle.

This a pathological way of doing alt-tab indication in the Clutter
universe, but a pretty good test case for the speed of window creation.

(Running with indirect GL, as normally is done to get the 
texture_from_pixmap extension to work via AIGLX.)

When I looked at the profile, it was very heavily dominated by
glTexImage2D() ... the server was spending > 20% of CPU doing that, and 
the client another 11%. (Plus some undetermined amount of kernel time
for wire transport and texture handling.)

When I investigated *what* glTexImage2D was taking most of the time, it
was a bit funny - the domination was by the calls to glTexImage2D
with a NULL pixels parameter that cogl_texture makes when initializing
a texture. Turns out that Mesa isn't too smart, and even though the 
resulting pixmap content is undefined, all the undefined bits get 
shipped over the wire and then stored in video memory.

This is pointless:

- If we are immediately going to fill the texture with data
- If we were creating the texture to use with texture_from_pixmap

So, the patch attached makes the initialization with glTexImage2D lazy
so it can either be combined with filling the texture with data or
avoided altogether.

These changes drop the server time related to glTexImage2D to 7% and the
client time to 6% in a similar test. The result feels much snappier as
well.

Caveats on the patch:

 - There's a lot of refactoring to consolidate glTexSubImage2D calls
   so that it feasible to do the actual change which is pretty trivial.

 - It's not all that well tested - in particular I haven't tested it
   in situations where I'm sure texture slicing is happening. It's a 
   pretty mechanical refactoring of the current code, but there's 
   obviously potential for introduced error.

 - If someone is calling glTexSubImage2D on the results of
   cogl_texture_get_gl_texture() instead of using
   cogl_texture_set_region() they'll run into problems, because 
   the initialization code path will be bypassed.

 - You could obviously make the claim that the proper fix lies in
   Mesa ... the glTexImage2D(..., NULL) should just be made fast.
   I don't know if that would require GLX wire protocol changes.

- Owen

>From a2b497ae3d2a41c34ce0f9296d2089af4b1b1917 Mon Sep 17 00:00:00 2001
From: Owen W. Taylor <[EMAIL PROTECTED]>
Date: Thu, 6 Nov 2008 19:05:50 -0500
Subject: [PATCH] Lazily initalize slices on first data store

Calling glTexImage2D(..., NULL) can be expensive despite the fact
that the pixels are undefined afterwards. Instead of initializing
each slice up front, track initialization in an array, and when
we first store data in the slice, see if we can use glTexImage2D()
to store the data. If not, call glTexImage2D(..., NULL) at that
point before calling glTexSubImage2D().

Also, refactor so that _cogl_texture_upload_to_gl() and
_cogl_texture_upload_subregion_to_gl() share most of their code
via a common _cogl_upload_slice(). This in particular combines
the code to pad the texture contents into the waste space.
---
 clutter/cogl/gl/cogl-texture.c |  496 ++++++++++++++++++++++------------------
 clutter/cogl/gl/cogl-texture.h |    1 +
 2 files changed, 273 insertions(+), 224 deletions(-)

diff --git a/clutter/cogl/gl/cogl-texture.c b/clutter/cogl/gl/cogl-texture.c
index fc60553..5d6fd2e 100644
--- a/clutter/cogl/gl/cogl-texture.c
+++ b/clutter/cogl/gl/cogl-texture.c
@@ -51,6 +51,27 @@
 
 static void _cogl_texture_free (CoglTexture *tex);
 
+/* A slice is "initialized" when we have called glTexImage2D on it
+ * to set up its size and internal format. Even when we pass NULL
+ * for pixels, glTexImage2D can be slow (this happens especially
+ * with indirect rendering via GLX, so we avoid calling  glTexImage2D
+ * until we actually have the data we want to send, in hopes we can
+ * send the data in the initial glTexImage2D call.
+ *
+ * tex->slice_initialized is an array that keeps track of whether
+ * each slice has been initalized.
+ */
+static GLuint _cogl_texture_get_initialized_handle (CoglTexture *tex,
+						    gint         x,
+						    gint         y);
+
+#define SLICE_GL_HANDLE(tex, x_index, y_index)				\
+  g_array_index ((tex)->slice_gl_handles, GLuint,			\
+		 (y_index) * (tex)->slice_x_spans->len + (x_index))
+
+#define SLICE_INITIALIZED(tex, x_index, y_index)			\
+  (tex)->slice_initialized->data[(y_index) * (tex)->slice_x_spans->len + (x_index)]
+
 COGL_HANDLE_DEFINE (Texture, texture, texture_handles);
 
 struct _CoglSpanIter
@@ -241,20 +262,206 @@ _cogl_texture_allocate_waste_buffer (CoglTexture *tex)
   return waste_buf;
 }
 
-static gboolean
-_cogl_texture_upload_to_gl (CoglTexture *tex)
+/* An "upload" is a series of glTexSubImage2D calls to different
+ * slices from the same source. By sticking the common parameters
+ * in a structure we keep the parameter list to _cogl_upload_slice()
+ * almost within reason.
+ */
+
+typedef struct _CoglUpload CoglUpload;
+
+struct _CoglUpload
+{
+  CoglTexture *tex;
+  CoglBitmap *source_bmp;
+  GLenum format;
+  GLenum type;
+  guchar *waste_buf;
+};
+
+static void
+_cogl_upload_init (CoglUpload  *upload,
+		   CoglTexture *tex,
+		   CoglBitmap  *source_bmp,
+		   GLenum       format,
+		   GLenum       type)
+{
+  upload->tex = tex;
+  upload->source_bmp = source_bmp;
+  upload->format = format;
+  upload->type = type;
+  upload->waste_buf = _cogl_texture_allocate_waste_buffer (tex);
+}
+
+static void
+_cogl_upload_finish (CoglUpload  *upload)
+{
+  if (upload->waste_buf)
+    g_free (upload->waste_buf);
+}
+
+/* x_index, y_index:   indices for the slice we are uploading
+ * source_x, source_y: source relative to source_bmp (0,0)
+ * local_x, local_x:   destinination relative to the slice
+ * width, height:      size of the rect to upload to this slice
+ */
+static void
+_cogl_upload_slice (CoglUpload *upload,
+		    gint        x_index,
+		    gint        y_index,
+		    gint        source_x,
+		    gint        source_y,
+		    gint        local_x,
+		    gint        local_y,
+		    gint        width,
+		    gint        height)
 {
+  CoglTexture       *tex = upload->tex;
+  CoglBitmap        *source_bmp = upload->source_bmp;
   CoglTexSliceSpan  *x_span;
   CoglTexSliceSpan  *y_span;
   GLuint             gl_handle;
   gint               bpp;
-  gint               x,y;
-  guchar            *waste_buf;
-  
-  bpp = _cogl_get_format_bpp (tex->bitmap.format);
 
-  waste_buf = _cogl_texture_allocate_waste_buffer (tex);
+  bpp = _cogl_get_format_bpp (source_bmp->format);
+
+  x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x_index);
+  y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y_index);
+
+  /* Setup gl alignment to match rowstride and top-left corner */
+  _cogl_subregion_gl_store_rules (source_bmp->rowstride,
+				  source_bmp->width,
+				  bpp,
+				  source_x,
+				  source_y,
+				  FALSE);
+
+  /* If the slice is not yet initialized and we are filling the
+   * entire slice with data (no waste) then we can use glTexImage2D
+   * directly here and skip the general path where we first
+   * initialize with glTexImage2D and then upload with
+   * glTexSubImage2D.
+   */
+  if (!SLICE_INITIALIZED (tex, x_index, y_index) &&
+      local_x == 0 && local_y == 0 &&
+      x_span->size == width && x_span->waste == 0 &&
+      y_span->size == height && y_span->waste == 0)
+    {
+      gl_handle = SLICE_GL_HANDLE (tex, x_index, y_index);
+
+      GE( glBindTexture (tex->gl_target, gl_handle) );
+
+      GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat,
+			x_span->size, y_span->size, 0,
+			upload->format, upload->type, source_bmp->data) );
+
+      SLICE_INITIALIZED (tex, x_index, y_index) = TRUE;
+
+      return;
+    }
+
+  gl_handle = _cogl_texture_get_initialized_handle (tex, x_index, y_index);
+
+  GE( glBindTexture (tex->gl_target, gl_handle) );
+
+  /* Upload new image data */
+  GE( glTexSubImage2D (tex->gl_target, 0,
+		       local_x, local_y,
+		       width, height,
+		       upload->format, upload->type, source_bmp->data) );
+
+  /* If the x_span is sliced and the upload touches the
+     rightmost pixels then fill the waste with copies of the
+     pixels */
+  if (x_span->waste > 0
+      && local_x < x_span->size - x_span->waste
+      && local_x + width >= x_span->size - x_span->waste)
+    {
+      const guchar *src = source_bmp->data
+	+ (source_y - local_y) * source_bmp->rowstride
+	+ (source_x - local_x + x_span->size - x_span->waste - 1) * bpp;
+      guchar *dst = upload->waste_buf;
+      guint wx, wy;
+
+      for (wy = 0; wy < height; wy++)
+	{
+	  for (wx = 0; wx < x_span->waste; wx++)
+	    {
+	      memcpy (dst, src, bpp);
+	      dst += bpp;
+	    }
+	  src += source_bmp->rowstride;
+	}
+
+      _cogl_subregion_gl_store_rules (x_span->waste * bpp,
+				      x_span->waste,
+				      bpp,
+				      0, 0, FALSE);
+
+      GE (glTexSubImage2D (tex->gl_target, 0,
+			   x_span->size - x_span->waste, local_y,
+			   x_span->waste,
+			   height,
+			   upload->format,
+			   upload->type,
+			   upload->waste_buf) );
+    }
+
+  /* same for the bottom-most pixels */
+  if (y_span->waste > 0
+      && local_y < y_span->size - y_span->waste
+      && local_y + height >= y_span->size - y_span->waste)
+    {
+      const guchar *src = upload->source_bmp->data
+	+ (source_x - local_x) * bpp
+	+ (source_y - local_y + y_span->size - y_span->waste - 1) * upload->source_bmp->rowstride;
+      guchar *dst = upload->waste_buf;
+      guint wy, wx;
+      guint copy_width;
+
+      if (local_x + width >= x_span->size - x_span->waste)
+	copy_width = x_span->size - local_x;
+      else
+	copy_width = width;
+
+      for (wy = 0; wy < y_span->waste; wy++)
+	{
+	  memcpy (dst, src, width * bpp);
+	  dst += width * bpp;
+
+	  for (wx = width; wx < copy_width; wx++)
+	    {
+	      memcpy (dst, dst - bpp, bpp);
+	      dst += bpp;
+	    }
+	}
+
+      _cogl_subregion_gl_store_rules (copy_width * bpp,
+				      copy_width,
+				      bpp,
+				      0, 0, FALSE);
+
+      GE( glTexSubImage2D (tex->gl_target, 0,
+			   local_x, y_span->size - y_span->waste,
+			   copy_width,
+			   y_span->waste,
+			   upload->format,
+			   upload->type,
+			   upload->waste_buf) );
+    }
+}
+
+static gboolean
+_cogl_texture_upload_to_gl (CoglTexture *tex)
+{
+  CoglUpload         upload;
+  CoglTexSliceSpan  *x_span;
+  CoglTexSliceSpan  *y_span;
+  gint               x,y;
 
+  _cogl_upload_init (&upload, tex, &tex->bitmap,
+		     tex->gl_format, tex->gl_type);
+  
   /* Iterate vertical slices */
   for (y = 0; y < tex->slice_y_spans->len; ++y)
     {
@@ -265,97 +472,16 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
 	{
 	  x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
 	  
-	  /* Pick the gl texture object handle */
-	  gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
-				     y * tex->slice_x_spans->len + x);
-	  
-	  /* Setup gl alignment to match rowstride and top-left corner */
-	  _cogl_subregion_gl_store_rules (tex->bitmap.rowstride,
-					  tex->bitmap.width,
-					  bpp,
-					  x_span->start,
-					  y_span->start,
-					  FALSE);
-	  
-	  /* Upload new image data */
-	  GE( glBindTexture (tex->gl_target, gl_handle) );
-	  
-	  GE( glTexSubImage2D (tex->gl_target, 0, 0, 0,
-			       x_span->size - x_span->waste,
-			       y_span->size - y_span->waste,
-			       tex->gl_format, tex->gl_type,
-			       tex->bitmap.data) );
-
-          /* Fill the waste with a copies of the rightmost pixels */
-          if (x_span->waste > 0)
-            {
-              const guchar *src = tex->bitmap.data
-                + y_span->start * tex->bitmap.rowstride
-                + (x_span->start + x_span->size - x_span->waste - 1) * bpp;
-              guchar *dst = waste_buf;
-              guint wx, wy;
-
-              for (wy = 0; wy < y_span->size - y_span->waste; wy++)
-                {
-                  for (wx = 0; wx < x_span->waste; wx++)
-                    {
-                      memcpy (dst, src, bpp);
-                      dst += bpp;
-                    }
-                  src += tex->bitmap.rowstride;
-                }
-
-              _cogl_subregion_gl_store_rules (x_span->waste * bpp,
-                                              x_span->waste,
-                                              bpp,
-                                              0, 0, FALSE);
-
-              GE( glTexSubImage2D (tex->gl_target, 0,
-                                   x_span->size - x_span->waste, 0,
-                                   x_span->waste,
-                                   y_span->size - y_span->waste,
-                                   tex->gl_format, tex->gl_type,
-                                   waste_buf) );
-            }
-
-          if (y_span->waste > 0)
-            {
-              const guchar *src = tex->bitmap.data
-                + ((y_span->start + y_span->size - y_span->waste - 1)
-                   * tex->bitmap.rowstride)
-                + x_span->start * bpp;
-              guchar *dst = waste_buf;
-              guint wy, wx;
-
-              for (wy = 0; wy < y_span->waste; wy++)
-                {
-                  memcpy (dst, src, (x_span->size - x_span->waste) * bpp);
-                  dst += (x_span->size - x_span->waste) * bpp;
-
-                  for (wx = 0; wx < x_span->waste; wx++)
-                    {
-                      memcpy (dst, dst - bpp, bpp);
-                      dst += bpp;
-                    }
-                }
-
-              _cogl_subregion_gl_store_rules (x_span->size * bpp,
-                                              x_span->size,
-                                              bpp,
-                                              0, 0, FALSE);
-
-              GE( glTexSubImage2D (tex->gl_target, 0,
-                                   0, y_span->size - y_span->waste,
-                                   x_span->size,
-                                   y_span->waste,
-                                   tex->gl_format, tex->gl_type,
-                                   waste_buf) );
-            }
+	  _cogl_upload_slice (&upload,
+			      x, y,
+			      x_span->start, y_span->start,
+			      0, 0,
+			      x_span->size - x_span->waste,
+			      y_span->size - y_span->waste);
 	}
     }
 
-  if (waste_buf)
-    g_free (waste_buf);
+  _cogl_upload_finish (&upload);
 
   return TRUE;
 }
@@ -387,8 +513,7 @@ _cogl_texture_download_from_gl (CoglTexture *tex,
 	  x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
 	  
 	  /* Pick the gl texture object handle */
-	  gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
-				     y * tex->slice_x_spans->len + x);
+	  gl_handle = _cogl_texture_get_initialized_handle (tex, x, y);
 	  
 	  /* If there's any waste we need to copy manually
              (no glGetTexSubImage) */
@@ -475,20 +600,17 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
 				      GLuint       source_gl_format,
 				      GLuint       source_gl_type)
 {
+  CoglUpload        upload;
   CoglTexSliceSpan *x_span;
   CoglTexSliceSpan *y_span;
-  gint              bpp;
   CoglSpanIter      x_iter;
   CoglSpanIter      y_iter;
-  GLuint            gl_handle;
   gint              source_x = 0, source_y = 0;
   gint              inter_w = 0, inter_h = 0;
   gint              local_x = 0, local_y = 0;
-  guchar           *waste_buf;
   
-  bpp = _cogl_get_format_bpp (source_bmp->format);
-  
-  waste_buf = _cogl_texture_allocate_waste_buffer (tex);
+  _cogl_upload_init (&upload, tex, source_bmp,
+		     source_gl_format, source_gl_type);
 
   /* Iterate vertical spans */
   for (source_y = src_y,
@@ -544,118 +666,15 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
 	  local_y = CLUTTER_FIXED_TO_INT (y_iter.intersect_start -
 					  y_iter.pos);
 	  
-	  /* Pick slice GL handle */
-	  gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
-				     y_iter.index * tex->slice_x_spans->len +
-				     x_iter.index);
-	  
-	  /* Setup gl alignment to match rowstride and top-left corner */
-	  
-	  _cogl_subregion_gl_store_rules (source_bmp->rowstride,
-					  source_bmp->width,
-					  bpp,
-					  source_x,
-					  source_y,
-					  FALSE);
-	  
-	  /* Upload new image data */
-	  GE( glBindTexture (tex->gl_target, gl_handle) );
-	  
-	  GE( glTexSubImage2D (tex->gl_target, 0,
-			       local_x, local_y,
-			       inter_w, inter_h,
-			       source_gl_format,
-			       source_gl_type,
-			       source_bmp->data) );
-
-          /* If the x_span is sliced and the upload touches the
-             rightmost pixels then fill the waste with copies of the
-             pixels */
-          if (x_span->waste > 0
-              && local_x < x_span->size - x_span->waste
-              && local_x + inter_w >= x_span->size - x_span->waste)
-            {
-              const guchar *src = source_bmp->data
-                + (src_y + CLUTTER_FIXED_TO_INT (y_iter.intersect_start)
-                   - dst_y) * source_bmp->rowstride
-                + (src_x + x_span->start + x_span->size - x_span->waste
-                   - dst_x - 1) * bpp;
-              guchar *dst = waste_buf;
-              guint wx, wy;
-
-              for (wy = 0; wy < inter_h; wy++)
-                {
-                  for (wx = 0; wx < x_span->waste; wx++)
-                    {
-                      memcpy (dst, src, bpp);
-                      dst += bpp;
-                    }
-                  src += source_bmp->rowstride;
-                }
-
-              _cogl_subregion_gl_store_rules (x_span->waste * bpp,
-                                              x_span->waste,
-                                              bpp,
-                                              0, 0, FALSE);
-
-              GE( glTexSubImage2D (tex->gl_target, 0,
-                                   x_span->size - x_span->waste, local_y,
-                                   x_span->waste,
-                                   inter_h,
-                                   source_gl_format,
-                                   source_gl_type,
-                                   waste_buf) );
-            }
-
-          /* same for the bottom-most pixels */
-          if (y_span->waste > 0
-              && local_y < y_span->size - y_span->waste
-              && local_y + inter_h >= y_span->size - y_span->waste)
-            {
-              const guchar *src = source_bmp->data
-                + (src_x + CLUTTER_FIXED_TO_INT (x_iter.intersect_start)
-                   - dst_x) * bpp
-                + (src_y + y_span->start + y_span->size - y_span->waste
-                   - dst_y - 1) * source_bmp->rowstride;
-              guchar *dst = waste_buf;
-              guint wy, wx;
-              guint copy_width;
-
-              if (local_x + inter_w >= x_span->size - x_span->waste)
-                copy_width = x_span->size - local_x;
-              else
-                copy_width = inter_w;
-
-              for (wy = 0; wy < y_span->waste; wy++)
-                {
-                  memcpy (dst, src, inter_w * bpp);
-                  dst += inter_w * bpp;
-
-                  for (wx = inter_w; wx < copy_width; wx++)
-                    {
-                      memcpy (dst, dst - bpp, bpp);
-                      dst += bpp;
-                    }
-                }
-
-              _cogl_subregion_gl_store_rules (copy_width * bpp,
-                                              copy_width,
-                                              bpp,
-                                              0, 0, FALSE);
-
-              GE( glTexSubImage2D (tex->gl_target, 0,
-                                   local_x, y_span->size - y_span->waste,
-                                   copy_width,
-                                   y_span->waste,
-                                   source_gl_format,
-                                   source_gl_type,
-                                   waste_buf) );
-            }
+	  _cogl_upload_slice (&upload,
+			      x_iter.index, y_iter.index,
+			      source_x, source_y,
+			      local_x, local_y,
+			      inter_w, inter_h);
 	}
     }
 
-  if (waste_buf)
-    g_free (waste_buf);
+  _cogl_upload_finish (&upload);
 
   return TRUE;
 }
@@ -926,6 +945,12 @@ _cogl_texture_slices_create (CoglTexture       *tex,
   
   g_array_set_size (tex->slice_gl_handles, n_slices);
   
+  tex->slice_initialized = g_byte_array_sized_new (n_slices);
+
+  g_byte_array_set_size (tex->slice_initialized, n_slices);
+
+  memset(tex->slice_initialized->data, 0, n_slices);
+  
   
   /* Hardware repeated tiling if supported, else tile in software*/
   if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
@@ -975,17 +1000,41 @@ _cogl_texture_slices_create (CoglTexture       *tex,
 	     outside of the texture */
 	  GE( glTexParameterfv (tex->gl_target, GL_TEXTURE_BORDER_COLOR,
 				transparent_color) );
-
-	  /* Pass NULL data to init size and internal format */
-	  GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat,
-			    x_span->size, y_span->size, 0,
-			    tex->gl_format, tex->gl_type, 0) );
 	}
     }
   
   return TRUE;
 }
 
+static GLuint
+_cogl_texture_get_initialized_handle (CoglTexture       *tex,
+				      gint               x,
+				      gint               y)
+{
+  if (!SLICE_INITIALIZED (tex, x, y))
+    {
+      CoglTexSliceSpan  *x_span;
+      CoglTexSliceSpan  *y_span;
+      GLuint             gl_handle;
+
+      x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
+      y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y);
+
+      gl_handle = SLICE_GL_HANDLE (tex, x, y);
+
+      GE( glBindTexture (tex->gl_target, gl_handle) );
+      /* Pass NULL data to init size and internal format */
+
+      GE( glTexImage2D (tex->gl_target, 0, tex->gl_intformat,
+			x_span->size, y_span->size, 0,
+			tex->gl_format, tex->gl_type, 0) );
+
+      SLICE_INITIALIZED (tex, x, y) = TRUE;
+    }
+
+  return SLICE_GL_HANDLE (tex, x, y);
+}
+
 static void
 _cogl_texture_slices_free (CoglTexture *tex)
 { 
@@ -1005,6 +1054,9 @@ _cogl_texture_slices_free (CoglTexture *tex)
       
       g_array_free (tex->slice_gl_handles, TRUE);
     }
+
+  if (tex->slice_initialized != NULL)
+    g_byte_array_free (tex->slice_initialized, TRUE);
 }
 
 static gboolean
@@ -2113,9 +2165,7 @@ _cogl_texture_quad_sw (CoglTexture *tex,
 #endif
 	  
 	  /* Pick and bind opengl texture object */
-	  gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
-				     iter_y.index * iter_x.array->len +
-				     iter_x.index);
+	  gl_handle =_cogl_texture_get_initialized_handle (tex, iter_x.index, iter_y.index);
 	  
 	  GE( glBindTexture (tex->gl_target, gl_handle) );
 	  
@@ -2180,7 +2230,7 @@ _cogl_texture_quad_hw (CoglTexture *tex,
   cogl_enable (enable_flags);
   
   /* Pick and bind opengl texture object */
-  gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0);
+  gl_handle = _cogl_texture_get_initialized_handle (tex, 0, 0);
   GE( glBindTexture (tex->gl_target, gl_handle) );
   
   x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
@@ -2363,8 +2413,6 @@ cogl_texture_polygon (CoglHandle         handle,
 			   GL_CLAMP_TO_BORDER) );
     }
 
-  i = 0;
-
   /* Render all of the slices with the full geometry but use a
      transparent border color so that any part of the texture not
      covered by the slice will be ignored */
@@ -2376,7 +2424,7 @@ cogl_texture_polygon (CoglHandle         handle,
 	{
 	  x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
 
-	  gl_handle = g_array_index (tex->slice_gl_handles, GLuint, i++);
+	  gl_handle = _cogl_texture_get_initialized_handle (tex, x, y);
 
 	  GE( glBindTexture (tex->gl_target, gl_handle) );
 
diff --git a/clutter/cogl/gl/cogl-texture.h b/clutter/cogl/gl/cogl-texture.h
index 1174374..658c0c1 100644
--- a/clutter/cogl/gl/cogl-texture.h
+++ b/clutter/cogl/gl/cogl-texture.h
@@ -51,6 +51,7 @@ struct _CoglTexture
   GArray            *slice_x_spans;
   GArray            *slice_y_spans;
   GArray            *slice_gl_handles;
+  GByteArray        *slice_initialized;
   gint               max_waste;
   COGLenum           min_filter;
   COGLenum           mag_filter;
-- 
1.6.0.3

Reply via email to