On Wed, 2008-11-05 at 13:03 -0500, Owen Taylor wrote:
> On Wed, 2008-11-05 at 16:36 +0000, Matthew Allum wrote:
> > On Wed, 2008-11-05 at 10:22 -0500, Owen Taylor wrote:
> 
> > > I see two basic routes I could take:
> > > 
> > > 1) I could add support for ARB_texture_rectangle into cogl_texture.
> > >    Presumably this would look like cogl_texture_new_rectangle()
> > >    or something ... you'd have to explicitly ask to get a rectangular
> > >    texture, since they do behave significantly different.
[...]
> [...]
> > 
> > I think making it usage explicit and contained like this is really the
> > only way to go in we do bring back in support for ARB_texture_rectangle
> > without a lot of complexity and other pain elsewhere. 
> > 
> > Re devel branch - I dont see why this could not end up in the stable
> > branch of which we are already having to track pretty much with mutter.
> 
> My initial expectation was that there would be significant code churn
> and API changes, but looking at it, the "remove texture_rectangle
> support" patch is a lot smaller than I expected and doesn't look to hard
> or intrusive to reintroduce. 
> 
> I'll do some more experimentation with that and see if it I can get it
> to work and see if it fixes some of the other issues people are having.

OK, here's a stab at this. The first two patches (one for clutter, one
for metacity-clutter) basically simply revert the removal of
ARB_texture_rectangle support from clutter.

However, that leaves two problems:

 - texture_rectangle might unexpectedly be used in places that
   clutter-0.8 code won't expect, breaking compatibility.

 - for texture_from_pixmap, I want a way to actually force
   texture_rectangle to be used, to deal with driver bugs.
   (The current proprietary NVIDIA drivers are buggy this way;
   and I think also older Intel drivers.)

So, the second two patches add:

 cogl_texture_new_with_size_and_options()
 cogl_texture_new_from_data_and_options()
 cogl_texture_new_from_file_and_options() // for completeness 

Where auto_mipmap is replaced with a flags field. (If breaking cogl
compat, you'd just want to change existing functions.) texture_rectangle
is not used by default, but you can pass:

 COGL_TEXTURE_ALLOW_RECTANGLE: allow it to be used
 COGL_TEXTURE_FORCE_RECTANGLE: use in preference to NPOT textures

And ClutterGLXPixmapTexture supports an environment variable 
CLUTTER_PIXMAP_TEXTURE_RECTANGLE=[force|disable].

The default is to allow - there's a good argument that it should default
to 'force' instead, considering the widespread presence of such buggy
drivers.

- Owen

>From 5b97816731c039a7cf6fbdb23f0d6716554bdbc0 Mon Sep 17 00:00:00 2001
From: Owen W. Taylor <[EMAIL PROTECTED]>
Date: Wed, 5 Nov 2008 16:17:57 -0500
Subject: [PATCH] Add back support for GL_ARB_texture_rectangle

Revert most of:

    2008-06-06  Matthew Allum  <[EMAIL PROTECTED]>

            Bug #948 - Remove texture rectangle support

GL_EXT_texture_for_pixmap only works with GL_ARGB_texture_rectangle on
many systems, either because of HW limitations (General NPOT textures
are not supported on older ATI cards), or because of driver bugs.

Changes to clutter_texture_new_from_actor() are not reverted; setting
disable-slicing there is pretty much orthogonal to texture_rectangle
and works fine with the rest of the revert.
---
 clutter/clutter-feature.c                |    3 +
 clutter/clutter-feature.h                |    1 +
 clutter/cogl/gl/cogl-texture.c           |   69 ++++++++++++++++++++++++++----
 clutter/cogl/gl/cogl.c                   |   15 ++++++-
 clutter/glx/clutter-glx-texture-pixmap.c |   13 +++---
 5 files changed, 85 insertions(+), 16 deletions(-)

diff --git a/clutter/clutter-feature.c b/clutter/clutter-feature.c
index 54ac41e..10edfe9 100644
--- a/clutter/clutter-feature.c
+++ b/clutter/clutter-feature.c
@@ -58,6 +58,9 @@ _clutter_features_from_cogl (guint cogl_flags)
 {
   ClutterFeatureFlags clutter_flags = 0;
   
+  if (cogl_flags & COGL_FEATURE_TEXTURE_RECTANGLE)
+    clutter_flags |= CLUTTER_FEATURE_TEXTURE_RECTANGLE;
+  
   if (cogl_flags & COGL_FEATURE_TEXTURE_NPOT)
     clutter_flags |= CLUTTER_FEATURE_TEXTURE_NPOT;
 
diff --git a/clutter/clutter-feature.h b/clutter/clutter-feature.h
index 89be737..0276fcf 100644
--- a/clutter/clutter-feature.h
+++ b/clutter/clutter-feature.h
@@ -57,6 +57,7 @@ G_BEGIN_DECLS
  */
 typedef enum 
 {
+  CLUTTER_FEATURE_TEXTURE_RECTANGLE      = (1 << 1),
   CLUTTER_FEATURE_TEXTURE_NPOT           = (1 << 2),
   CLUTTER_FEATURE_SYNC_TO_VBLANK         = (1 << 3),
   CLUTTER_FEATURE_TEXTURE_YUV            = (1 << 4),
diff --git a/clutter/cogl/gl/cogl-texture.c b/clutter/cogl/gl/cogl-texture.c
index 3bdf3bd..7cae747 100644
--- a/clutter/cogl/gl/cogl-texture.c
+++ b/clutter/cogl/gl/cogl-texture.c
@@ -752,7 +752,20 @@ _cogl_texture_size_supported (GLenum gl_target,
 			      int    width,
 			      int    height)
 {
-if (gl_target ==  GL_TEXTURE_2D)
+  if (gl_target == GL_TEXTURE_RECTANGLE_ARB)
+    {
+      /* There is no proxy rectangle texture target so best we can
+       * do is to check against the safest value (although depending
+       * on our specific format and type the size could be supported
+       * when it seems it is not) */
+      
+      GLint max_size = 0;
+
+      GE( glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &max_size) );
+
+      return (max_size && width <= max_size && height <= max_size);
+    }
+  else if (gl_target ==  GL_TEXTURE_2D)
     {
       /* Proxy texture allows for a quick check for supported size */
       
@@ -801,6 +814,13 @@ _cogl_texture_slices_create (CoglTexture *tex)
       tex->gl_target  = GL_TEXTURE_2D;
       slices_for_size = _cogl_rect_slices_for_size;
     }
+  else if (cogl_features_available (COGL_FEATURE_TEXTURE_RECTANGLE))
+    {
+      max_width = tex->bitmap.width;
+      max_height = tex->bitmap.height;
+      tex->gl_target = GL_TEXTURE_RECTANGLE_ARB;
+      slices_for_size = _cogl_rect_slices_for_size;
+    }
   else
     {
       max_width = cogl_util_next_p2 (tex->bitmap.width);
@@ -1423,7 +1443,8 @@ cogl_texture_new_from_foreign (GLuint           gl_handle,
   CoglTexSliceSpan y_span;
   
   /* Allow 2-dimensional textures only */
-  if (gl_target != GL_TEXTURE_2D)
+  if (gl_target != GL_TEXTURE_2D &&
+      gl_target != GL_TEXTURE_RECTANGLE_ARB)
     return COGL_INVALID_HANDLE;
   
   /* Make sure it is a valid GL texture object */
@@ -1942,7 +1963,10 @@ _cogl_texture_quad_sw (CoglTexture *tex,
 #endif
   
   /* Prepare GL state */
-  enable_flags |= COGL_ENABLE_TEXTURE_2D;
+  if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB)
+    enable_flags |= COGL_ENABLE_TEXTURE_RECT;
+  else
+    enable_flags |= COGL_ENABLE_TEXTURE_2D;
   
   if (ctx->color_alpha < 255
       || tex->bitmap.format & COGL_A_BIT)
@@ -1998,8 +2022,11 @@ _cogl_texture_quad_sw (CoglTexture *tex,
       
       /* Normalize texture coordinates to current slice
          (rectangle texture targets take denormalized) */
-      slice_ty1 /= iter_y.span->size;
-      slice_ty2 /= iter_y.span->size;
+      if (tex->gl_target != GL_TEXTURE_RECTANGLE_ARB)
+	{
+	  slice_ty1 /= iter_y.span->size;
+	  slice_ty2 /= iter_y.span->size;
+	}
       
       
       /* Iterate until whole quad width covered */
@@ -2024,8 +2051,11 @@ _cogl_texture_quad_sw (CoglTexture *tex,
 	  
 	  /* Normalize texture coordinates to current slice
              (rectangle texture targets take denormalized) */
-          slice_tx1 /= iter_x.span->size;
-          slice_tx2 /= iter_x.span->size;
+	  if (tex->gl_target != GL_TEXTURE_RECTANGLE_ARB)
+	    {
+	      slice_tx1 /= iter_x.span->size;
+	      slice_tx2 /= iter_x.span->size;
+	    }
 	  
 #if COGL_DEBUG
 	  printf("~~~~~ slice (%d,%d)\n", iter_x.index, iter_y.index);
@@ -2093,7 +2123,10 @@ _cogl_texture_quad_hw (CoglTexture *tex,
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
   
   /* Prepare GL state */
-  enable_flags |= COGL_ENABLE_TEXTURE_2D;
+  if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB)
+    enable_flags |= COGL_ENABLE_TEXTURE_RECT;
+  else
+    enable_flags |= COGL_ENABLE_TEXTURE_2D;
   
   if (ctx->color_alpha < 255
       || tex->bitmap.format & COGL_A_BIT)
@@ -2116,6 +2149,15 @@ _cogl_texture_quad_hw (CoglTexture *tex,
   ty1 = ty1 * (y_span->size - y_span->waste) / y_span->size;
   ty2 = ty2 * (y_span->size - y_span->waste) / y_span->size;
 
+  /* Denormalize texture coordinates for rectangle textures */
+  if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB)
+    {
+      tx1 *= x_span->size;
+      tx2 *= x_span->size;
+      ty1 *= y_span->size;
+      ty2 *= y_span->size;
+    }
+  
 #define CFX_F(x) CLUTTER_FIXED_TO_FLOAT(x)
   
   /* Draw textured quad */
@@ -2261,7 +2303,10 @@ cogl_texture_polygon (CoglHandle         handle,
   tex = _cogl_texture_pointer_from_handle (handle);
   
   /* Prepare GL state */
-  cogl_enable (COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_BLEND);
+  if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB)
+    cogl_enable (COGL_ENABLE_TEXTURE_RECT | COGL_ENABLE_BLEND);
+  else
+    cogl_enable (COGL_ENABLE_TEXTURE_2D | COGL_ENABLE_BLEND);
 
   /* Temporarily change the wrapping mode on all of the slices to use
      a transparent border */
@@ -2310,6 +2355,12 @@ cogl_texture_polygon (CoglHandle         handle,
 		    - y_span->start / (GLfloat) tex->bitmap.height)
 		* tex->bitmap.height / y_span->size;
 
+	      if (tex->gl_target == GL_TEXTURE_RECTANGLE_ARB)
+		{
+		  tx *= x_span->size;
+		  ty *= y_span->size;
+		}
+
 	      glTexCoord2f (tx, ty);
 
 	      glVertex3f (CLUTTER_FIXED_TO_FLOAT (vertices[vnum].x),
diff --git a/clutter/cogl/gl/cogl.c b/clutter/cogl/gl/cogl.c
index 6906927..d56c306 100644
--- a/clutter/cogl/gl/cogl.c
+++ b/clutter/cogl/gl/cogl.c
@@ -323,6 +323,11 @@ cogl_enable (gulong flags)
 			   COGL_ENABLE_TEXCOORD_ARRAY,
 			   GL_TEXTURE_COORD_ARRAY);
   
+#ifdef GL_TEXTURE_RECTANGLE_ARB
+  cogl_toggle_flag (ctx, flags,
+		    COGL_ENABLE_TEXTURE_RECT,
+		    GL_TEXTURE_RECTANGLE_ARB);
+#endif
 }
 
 gulong
@@ -934,7 +939,15 @@ _cogl_features_init ()
 
   gl_extensions = (const gchar*) glGetString (GL_EXTENSIONS);
 
-  if (cogl_check_extension ("GL_ARB_texture_non_power_of_two", gl_extensions))
+#if defined(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB) && defined(GL_TEXTURE_RECTANGLE_ARB)
+  if (cogl_check_extension ("GL_ARB_texture_rectangle", gl_extensions) ||
+      cogl_check_extension ("GL_EXT_texture_rectangle", gl_extensions))
+    {
+      flags |= COGL_FEATURE_TEXTURE_RECTANGLE;
+    }
+#endif
+  
+  if (0 && cogl_check_extension ("GL_ARB_texture_non_power_of_two", gl_extensions))
     {
 #ifdef HAVE_CLUTTER_OSX
       if (really_enable_npot ())
diff --git a/clutter/glx/clutter-glx-texture-pixmap.c b/clutter/glx/clutter-glx-texture-pixmap.c
index 3ae6f54..0083fbf 100644
--- a/clutter/glx/clutter-glx-texture-pixmap.c
+++ b/clutter/glx/clutter-glx-texture-pixmap.c
@@ -548,7 +548,10 @@ clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture)
 
   attribs[i++] = GLX_TEXTURE_TARGET_EXT;
 
-  attribs[i++] = GLX_TEXTURE_2D_EXT;
+  if (clutter_feature_available (COGL_FEATURE_TEXTURE_NPOT))
+    attribs[i++] = GLX_TEXTURE_2D_EXT;
+  else
+    attribs[i++] = GLX_TEXTURE_RECTANGLE_EXT;
 
   attribs[i++] = None;
 
@@ -715,11 +718,9 @@ clutter_glx_texture_pixmap_using_extension (ClutterGLXTexturePixmap *texture)
 
   priv = CLUTTER_GLX_TEXTURE_PIXMAP (texture)->priv;
 
-  return (_have_tex_from_pixmap_ext); 
-  /* Assume NPOT TFP's are supported even if regular NPOT isn't advertised 
-   * but tfp is. Seemingly some Intel drivers do this ?
-  */
-  /* && clutter_feature_available (COGL_FEATURE_TEXTURE_NPOT)); */
+  return (_have_tex_from_pixmap_ext
+	  && (clutter_feature_available (COGL_FEATURE_TEXTURE_NPOT)
+	      || clutter_feature_available (COGL_FEATURE_TEXTURE_RECTANGLE)));
 }
 
 /**
-- 
1.6.0.3

>From f681d6dd400f342a54fa692dc29872f8a7deb74b Mon Sep 17 00:00:00 2001
From: Owen W. Taylor <[EMAIL PROTECTED]>
Date: Wed, 5 Nov 2008 17:45:00 -0500
Subject: [PATCH] Support GL_ARB_texture_rectangle in MutterShapedTexture

mutter-shaped-texture.c: Retrieve the target from the cogl_texture
  and use it, instead of hardcoding GL_TEXTURE_2D.
---
 src/compositor/mutter/mutter-shaped-texture.c |   36 +++++++++++++++---------
 1 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/src/compositor/mutter/mutter-shaped-texture.c b/src/compositor/mutter/mutter-shaped-texture.c
index 19e850e..c237870 100644
--- a/src/compositor/mutter/mutter-shaped-texture.c
+++ b/src/compositor/mutter/mutter-shaped-texture.c
@@ -233,6 +233,7 @@ mutter_shaped_texture_ensure_mask (MutterShapedTexture *stex)
   CoglHandle paint_tex;
   guint tex_width, tex_height;
   GLuint mask_gl_tex;
+  GLenum mask_target;
 
   paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex));
 
@@ -291,14 +292,17 @@ mutter_shaped_texture_ensure_mask (MutterShapedTexture *stex)
       priv->mask_width = tex_width;
       priv->mask_height = tex_height;
 
-      cogl_texture_get_gl_texture (priv->mask_texture, &mask_gl_tex, NULL);
+      cogl_texture_get_gl_texture (priv->mask_texture, &mask_gl_tex, &mask_target);
 
       mutter_shaped_texture_get_gl_size (priv->mask_texture,
 					 &priv->mask_gl_width,
 					 &priv->mask_gl_height);
 
-      if ((guint) priv->mask_gl_width == tex_width
-          && (guint) priv->mask_gl_height == tex_height)
+      if (mask_target == GL_TEXTURE_RECTANGLE_ARB)
+	mutter_shaped_texture_set_coord_array (0.0f, 0.0f, tex_width, tex_height,
+					       priv->mask_tex_coords);
+      else if ((guint) priv->mask_gl_width == tex_width
+	       && (guint) priv->mask_gl_height == tex_height)
         mutter_shaped_texture_set_coord_array (0.0f, 0.0f, 1.0f, 1.0f,
 					       priv->mask_tex_coords);
       else
@@ -322,6 +326,7 @@ mutter_shaped_texture_paint (ClutterActor *actor)
   GLboolean vertex_array_was_enabled, tex_coord_array_was_enabled;
   GLboolean color_array_was_enabled;
   GLuint paint_gl_tex, mask_gl_tex;
+  GLenum paint_target, mask_target;
   guint paint_gl_width, paint_gl_height;
   GLfloat vertex_coords[8], paint_tex_coords[8];
   ClutterActorBox alloc;
@@ -358,18 +363,18 @@ mutter_shaped_texture_paint (ClutterActor *actor)
 
   mutter_shaped_texture_ensure_mask (stex);
 
-  cogl_texture_get_gl_texture (paint_tex, &paint_gl_tex, NULL);
-  cogl_texture_get_gl_texture (priv->mask_texture, &mask_gl_tex, NULL);
+  cogl_texture_get_gl_texture (paint_tex, &paint_gl_tex, &paint_target);
+  cogl_texture_get_gl_texture (priv->mask_texture, &mask_gl_tex, &mask_target);
 
   /* We need to keep track of the some of the old state so that we
      don't confuse Cogl */
-  texture_was_enabled = glIsEnabled (GL_TEXTURE_2D);
+  texture_was_enabled = glIsEnabled (paint_target);
   blend_was_enabled = glIsEnabled (GL_BLEND);
   vertex_array_was_enabled = glIsEnabled (GL_VERTEX_ARRAY);
   tex_coord_array_was_enabled = glIsEnabled (GL_TEXTURE_COORD_ARRAY);
   color_array_was_enabled = glIsEnabled (GL_COLOR_ARRAY);
 
-  glEnable (GL_TEXTURE_2D);
+  glEnable (paint_target);
   glEnable (GL_BLEND);
   glEnableClientState (GL_VERTEX_ARRAY);
   glEnableClientState (GL_TEXTURE_COORD_ARRAY);
@@ -379,7 +384,7 @@ mutter_shaped_texture_paint (ClutterActor *actor)
   cogl_color (&white);
 
   /* Put the main painting texture in the first texture unit */
-  glBindTexture (GL_TEXTURE_2D, paint_gl_tex);
+  glBindTexture (paint_target, paint_gl_tex);
 
   /* We need the actual size of the texture so that we can calculate
      the right texture coordinates if NPOTs textures are not supported
@@ -391,9 +396,9 @@ mutter_shaped_texture_paint (ClutterActor *actor)
   /* Put the mask texture in the second texture unit */
   tst_active_texture (GL_TEXTURE1);
   tst_client_active_texture (GL_TEXTURE1);
-  glBindTexture (GL_TEXTURE_2D, mask_gl_tex);
+  glBindTexture (mask_target, mask_gl_tex);
 
-  glEnable (GL_TEXTURE_2D);
+  glEnable (mask_target);
 
   glEnableClientState (GL_TEXTURE_COORD_ARRAY);
   glTexCoordPointer (2, GL_FLOAT, 0, priv->mask_tex_coords);
@@ -419,8 +424,11 @@ mutter_shaped_texture_paint (ClutterActor *actor)
 					                         - alloc.y1),
 					 vertex_coords);
 
-  if ((guint) paint_gl_width == tex_width
-      && (guint) paint_gl_height == tex_height)
+  if (paint_target == GL_TEXTURE_RECTANGLE_ARB)
+    mutter_shaped_texture_set_coord_array (0.0f, 0.0f, tex_width, tex_height,
+					   paint_tex_coords);
+  else if ((guint) paint_gl_width == tex_width
+	&& (guint) paint_gl_height == tex_height)
     mutter_shaped_texture_set_coord_array (0.0f, 0.0f, 1.0f, 1.0f,
                                          paint_tex_coords);
   else
@@ -434,7 +442,7 @@ mutter_shaped_texture_paint (ClutterActor *actor)
   glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
 
   /* Disable the second texture unit and coord array */
-  glDisable (GL_TEXTURE_2D);
+  glDisable (mask_target);
   glDisableClientState (GL_TEXTURE_COORD_ARRAY);
 
   /* Go back to operating on the first texture unit */
@@ -443,7 +451,7 @@ mutter_shaped_texture_paint (ClutterActor *actor)
 
   /* Restore the old state */
   if (!texture_was_enabled)
-    glDisable (GL_TEXTURE_2D);
+    glDisable (paint_target);
   if (!blend_was_enabled)
     glDisable (GL_BLEND);
   if (!vertex_array_was_enabled)
-- 
1.6.0.3

>From 4ac3e3ec460338d0f3f086b11e891552cd05453c Mon Sep 17 00:00:00 2001
From: Owen W. Taylor <[EMAIL PROTECTED]>
Date: Wed, 5 Nov 2008 18:27:30 -0500
Subject: [PATCH] Allow controlling the user of GL_ARB_texture_rectangle

cogl/cogl.h.in: Add cogl_texture_new_{with_size,from_data,from_file}_and_options()
  These functions allow passing in a set of CoglTextureOptions flags.
  Flags replace the auto_mipmap option and additionally control whether
  GL_ARB_texture_rectangle is used at all, and is used in preference
  to NPOT_textures.

cogl/gl/cogle-texture.c cogl/gles/cogle-texture.c: Implement the
  _and_options() variants of the cogl_texture constructors.

glx/clutter-glx-texture-pixmap.c: By default enable GL_ARB_texture_rectangle
  for our pixmap textures. Add environment variable
  CLUTTER_PIXMAP_TEXTURE_RECTANGLE=[force,disable] to control.
---
 clutter/cogl/cogl.h.in                   |   87 ++++++++++++++++++++++++++++++
 clutter/cogl/gl/cogl-texture.c           |   64 +++++++++++++++++++---
 clutter/cogl/gles/cogl-texture.c         |   45 ++++++++++++++-
 clutter/glx/clutter-glx-texture-pixmap.c |   59 ++++++++++++++++++---
 4 files changed, 236 insertions(+), 19 deletions(-)

diff --git a/clutter/cogl/cogl.h.in b/clutter/cogl/cogl.h.in
index 814ca33..ab3d482 100644
--- a/clutter/cogl/cogl.h.in
+++ b/clutter/cogl/cogl.h.in
@@ -197,6 +197,24 @@ typedef enum
 } CoglBufferTarget;
 
 /**
+ * CoglTextureOptions:
+ * @COGL_TEXTURE_ALLOW_RECTANGLE: Use GL_ARB_texture_rectangle if
+ *   it's available and GL_ARB_texture_non_power_of_two isn't.
+ * @COGL_TEXTURE_FORCE_RECTANGLE:Use  GL_ARB_texture_rectangle
+ *   even if GL_ARB_texture_non_power_of_two is available.
+ * @COGL_TEXTURE_AUTO_MIPMAP: enable generation of mipmap pyramid
+ *   from the base level image whenever it is updated.
+ *
+ */
+typedef enum
+{
+  COGL_TEXTURE_ALLOW_RECTANGLE      = (1 << 1),
+  COGL_TEXTURE_FORCE_RECTANGLE      = (1 << 2),
+  COGL_TEXTURE_AUTO_MIPMAP          = (1 << 3)
+
+} CoglTextureOptions;
+
+/**
  * CoglTextureVertex:
  * @x: Model x-coordinate
  * @y: Model y-coordinate
@@ -654,6 +672,27 @@ CoglHandle      cogl_texture_new_with_size    (guint           width,
                                                CoglPixelFormat internal_format);
 
 /**
+ * cogl_texture_new_with_size_and_options:
+ * @width: width of texture in pixels.
+ * @height: height of texture in pixels.
+ * @max_waste: maximum extra horizontal and|or vertical margin pixels to make
+ * texture fit GPU limitations.
+ * @options: a set of bit flags that affect how the texture is created
+ * @internal_format: the #CoglPixelFormat to use for the GPU storage of the
+ * texture.
+ *
+ * Create a new texture with specified dimensions, options, and pixel format.
+ *
+ * Returns: a #CoglHandle to the newly created texture or COGL_INVALID_HANDLE
+ * if texture creation failed.
+ */
+CoglHandle      cogl_texture_new_with_size_and_options (guint              width,
+							guint              height,
+							gint               max_waste,
+							CoglTextureOptions options,
+							CoglPixelFormat    internal_format);
+
+/**
  * cogl_texture_new_from_file:
  * @filename: the file to load
  * @max_waste: maximum extra horizontal and|or vertical margin pixels to make
@@ -676,6 +715,27 @@ CoglHandle      cogl_texture_new_from_file    (const gchar    *filename,
                                                GError        **error);
 
 /**
+ * cogl_texture_new_from_file_and_options:
+ * @filename: the file to load
+ * @max_waste: maximum extra horizontal and|or vertical margin pixels to make
+ * texture fit GPU limitations.
+ * @options: a set of bit flags that affect how the texture is created
+ * @internal_format: the #CoglPixelFormat to use for the GPU storage of the
+ * texture.
+ * @error: a #GError or NULL.
+ *
+ * Load an image file from disk with specified options.
+ *
+ * Returns: a #CoglHandle to the newly created texture or COGL_INVALID_HANDLE
+ * if creating the texture failed.
+ */
+CoglHandle      cogl_texture_new_from_file_and_options    (const gchar        *filename,
+							   gint               max_waste,
+							   CoglTextureOptions options,
+							   CoglPixelFormat    internal_format,
+							   GError           **error);
+
+/**
  * cogl_texture_new_from_data:
  * @width: width of texture in pixels.
  * @height: height of texture in pixels.
@@ -704,6 +764,33 @@ CoglHandle      cogl_texture_new_from_data    (guint            width,
                                                const guchar    *data);
 
 /**
+ * cogl_texture_new_from_data_and_options:
+ * @width: width of texture in pixels.
+ * @height: height of texture in pixels.
+ * @max_waste: maximum extra horizontal and|or vertical margin pixels to make
+ * @options: a set of bit flags that affect how the texture is created.
+ * @format: the #CoglPixelFormat the buffer is stored in in RAM
+ * @internal_format: the #CoglPixelFormat that will be used for storing the
+ * buffer on the GPU.
+ * @rowstride: the memory offset in bytes between the starts of scanlines in
+ * @data.
+ * @data: pointer the memory region where the source buffer resides.
+ *
+ * Create a new cogl texture based on data residing in memory with specified options
+ *
+ * Returns: a #CoglHandle to the newly created texture or COGL_INVALID_HANDLE
+ * if creating the texture failed.
+ */
+CoglHandle      cogl_texture_new_from_data_and_options    (guint              width,
+							   guint              height,
+							   gint               max_waste,
+							   CoglTextureOptions options,
+							   CoglPixelFormat    format,
+							   CoglPixelFormat    internal_format,
+							   guint              rowstride,
+							   const guchar      *data);
+
+/**
  * cogl_texture_new_from_foreign:
  * @gl_handle: opengl target type of foreign texture
  * @gl_target: opengl handle of foreign texture.
diff --git a/clutter/cogl/gl/cogl-texture.c b/clutter/cogl/gl/cogl-texture.c
index 7cae747..f5b37a2 100644
--- a/clutter/cogl/gl/cogl-texture.c
+++ b/clutter/cogl/gl/cogl-texture.c
@@ -788,7 +788,8 @@ _cogl_texture_size_supported (GLenum gl_target,
 }
 
 static gboolean
-_cogl_texture_slices_create (CoglTexture *tex)
+_cogl_texture_slices_create (CoglTexture       *tex,
+			     CoglTextureOptions options)
 {  
   gint              bpp;
   gint              max_width;
@@ -807,15 +808,20 @@ _cogl_texture_slices_create (CoglTexture *tex)
   bpp = _cogl_get_format_bpp (tex->bitmap.format);
   
   /* Initialize size of largest slice according to supported features*/
-  if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT))
+  if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) &&
+      ((options & COGL_TEXTURE_FORCE_RECTANGLE) == 0 ||
+       !cogl_features_available (COGL_FEATURE_TEXTURE_RECTANGLE)))
     {
+      g_printerr("NPOT!\n");
       max_width = tex->bitmap.width;
       max_height = tex->bitmap.height;
       tex->gl_target  = GL_TEXTURE_2D;
       slices_for_size = _cogl_rect_slices_for_size;
     }
-  else if (cogl_features_available (COGL_FEATURE_TEXTURE_RECTANGLE))
+  else if (cogl_features_available (COGL_FEATURE_TEXTURE_RECTANGLE) &&
+           ((options & (COGL_TEXTURE_ALLOW_RECTANGLE | COGL_TEXTURE_FORCE_RECTANGLE)) != 0))
     {
+      g_printerr("RECTANGLE!\n");
       max_width = tex->bitmap.width;
       max_height = tex->bitmap.height;
       tex->gl_target = GL_TEXTURE_RECTANGLE_ARB;
@@ -823,6 +829,7 @@ _cogl_texture_slices_create (CoglTexture *tex)
     }
   else
     {
+      g_printerr("SLICED!\n");
       max_width = cogl_util_next_p2 (tex->bitmap.width);
       max_height = cogl_util_next_p2 (tex->bitmap.height);
       tex->gl_target = GL_TEXTURE_2D;
@@ -1208,6 +1215,18 @@ cogl_texture_new_with_size (guint           width,
                             gboolean        auto_mipmap,
 			    CoglPixelFormat internal_format)
 {
+  return cogl_texture_new_with_size_and_options (width, height, max_waste,
+						 auto_mipmap ? COGL_TEXTURE_AUTO_MIPMAP : 0,
+						 internal_format);
+}
+
+CoglHandle
+cogl_texture_new_with_size_and_options (guint              width,
+					guint              height,
+					gint               max_waste,
+					CoglTextureOptions options,
+					CoglPixelFormat    internal_format)
+{
   CoglTexture *tex;
   gint         bpp;
   gint         rowstride;
@@ -1227,7 +1246,7 @@ cogl_texture_new_with_size (guint           width,
   COGL_HANDLE_DEBUG_NEW (texture, tex);
 
   tex->is_foreign = FALSE;
-  tex->auto_mipmap = auto_mipmap;
+  tex->auto_mipmap = (options & COGL_TEXTURE_AUTO_MIPMAP) != 0;
   
   tex->bitmap.width = width;
   tex->bitmap.height = height;
@@ -1252,7 +1271,7 @@ cogl_texture_new_with_size (guint           width,
 			      &tex->gl_type);
   
   /* Create slices for the given format and size */
-  if (!_cogl_texture_slices_create (tex))
+  if (!_cogl_texture_slices_create (tex, options))
     {
       _cogl_texture_free (tex);
       return COGL_INVALID_HANDLE;
@@ -1271,6 +1290,21 @@ cogl_texture_new_from_data (guint              width,
 			    guint              rowstride,
 			    const guchar      *data)
 {
+  return cogl_texture_new_from_data_and_options (width, height, max_waste,
+						 auto_mipmap ? COGL_TEXTURE_AUTO_MIPMAP : 0,
+						 format, internal_format, rowstride, data);
+}
+
+CoglHandle
+cogl_texture_new_from_data_and_options (guint              width,
+					guint              height,
+					gint               max_waste,
+					CoglTextureOptions options,
+					CoglPixelFormat    format,
+					CoglPixelFormat    internal_format,
+					guint              rowstride,
+					const guchar      *data)
+{
   CoglTexture *tex;
   gint         bpp;
   
@@ -1291,7 +1325,7 @@ cogl_texture_new_from_data (guint              width,
   COGL_HANDLE_DEBUG_NEW (texture, tex);
 
   tex->is_foreign = FALSE;
-  tex->auto_mipmap = auto_mipmap;
+  tex->auto_mipmap = (options & COGL_TEXTURE_AUTO_MIPMAP) != 0;
   
   tex->bitmap.width = width;
   tex->bitmap.height = height;
@@ -1319,7 +1353,7 @@ cogl_texture_new_from_data (guint              width,
       return COGL_INVALID_HANDLE;
     }
   
-  if (!_cogl_texture_slices_create (tex))
+  if (!_cogl_texture_slices_create (tex, options))
     {
       _cogl_texture_free (tex);
       return COGL_INVALID_HANDLE;
@@ -1343,6 +1377,18 @@ cogl_texture_new_from_file (const gchar     *filename,
 			    CoglPixelFormat  internal_format,
 			    GError         **error)
 {
+  return cogl_texture_new_from_file_and_options (filename, max_waste,
+						 auto_mipmap ? COGL_TEXTURE_AUTO_MIPMAP : 0,
+						 internal_format, error);
+}
+
+CoglHandle
+cogl_texture_new_from_file_and_options (const gchar       *filename,
+					gint               max_waste,
+					CoglTextureOptions options,
+					CoglPixelFormat    internal_format,
+					GError            **error)
+{
   CoglBitmap   bmp;
   CoglTexture *tex;
   
@@ -1368,7 +1414,7 @@ cogl_texture_new_from_file (const gchar     *filename,
   COGL_HANDLE_DEBUG_NEW (texture, tex);
   
   tex->is_foreign = FALSE;
-  tex->auto_mipmap = auto_mipmap;
+  tex->auto_mipmap = (options & COGL_TEXTURE_AUTO_MIPMAP) != 0;
   
   tex->bitmap = bmp;
   tex->bitmap_owner = TRUE;
@@ -1395,7 +1441,7 @@ cogl_texture_new_from_file (const gchar     *filename,
       return COGL_INVALID_HANDLE;
     }
   
-  if (!_cogl_texture_slices_create (tex))
+  if (!_cogl_texture_slices_create (tex, options))
     {
       _cogl_texture_free (tex);
       return COGL_INVALID_HANDLE;
diff --git a/clutter/cogl/gles/cogl-texture.c b/clutter/cogl/gles/cogl-texture.c
index 97cd258..bf0f004 100644
--- a/clutter/cogl/gles/cogl-texture.c
+++ b/clutter/cogl/gles/cogl-texture.c
@@ -1168,6 +1168,18 @@ cogl_texture_new_with_size (guint           width,
                             gboolean        auto_mipmap,
 			    CoglPixelFormat internal_format)
 {
+  return cogl_texture_new_with_size_and_options (width, height, max_waste,
+						 auto_mipmap ? COGL_TEXTURE_AUTO_MIPMAP : 0,
+						 internal_format);
+}
+
+CoglHandle
+cogl_texture_new_with_size_and_options (guint              width,
+					guint              height,
+					gint               max_waste,
+					CoglTextureOptions options,
+					CoglPixelFormat    internal_format)
+{
   CoglTexture *tex;
   gint         bpp;
   gint         rowstride;
@@ -1187,7 +1199,7 @@ cogl_texture_new_with_size (guint           width,
   COGL_HANDLE_DEBUG_NEW (texture, tex);
   
   tex->is_foreign = FALSE;
-  tex->auto_mipmap = auto_mipmap;
+  tex->auto_mipmap = (options & COGL_TEXTURE_AUTO_MIPMAP) != 0;
   
   tex->bitmap.width = width;
   tex->bitmap.height = height;
@@ -1230,6 +1242,21 @@ cogl_texture_new_from_data (guint              width,
 			    guint              rowstride,
 			    const guchar      *data)
 {
+  return cogl_texture_new_from_data_and_options (width, height, max_waste,
+						 auto_mipmap ? COGL_TEXTURE_AUTO_MIPMAP : 0,
+						 format, internal_format, rowstride, data);
+}
+
+CoglHandle
+cogl_texture_new_from_data_and_options (guint              width,
+					guint              height,
+					gint               max_waste,
+					CoglTextureOptions options,
+					CoglPixelFormat    format,
+					CoglPixelFormat    internal_format,
+					guint              rowstride,
+					const guchar      *data)
+{
   CoglTexture *tex;
   gint         bpp;
   
@@ -1250,7 +1277,7 @@ cogl_texture_new_from_data (guint              width,
   COGL_HANDLE_DEBUG_NEW (texture, tex);
   
   tex->is_foreign = FALSE;
-  tex->auto_mipmap = auto_mipmap;
+  tex->auto_mipmap = (options & COGL_TEXTURE_AUTO_MIPMAP) != 0;
 
   tex->bitmap.width = width;
   tex->bitmap.height = height;
@@ -1302,6 +1329,18 @@ cogl_texture_new_from_file (const gchar     *filename,
 			    CoglPixelFormat  internal_format,
 			    GError         **error)
 {
+  return cogl_texture_new_from_file_and_options (filename, max_waste,
+						 auto_mipmap ? COGL_TEXTURE_AUTO_MIPMAP : 0,
+						 internal_format, error);
+}
+
+CoglHandle
+cogl_texture_new_from_file_and_options (const gchar       *filename,
+					gint               max_waste,
+					CoglTextureOptions options,
+					CoglPixelFormat    internal_format,
+					GError            **error)
+{
   CoglBitmap   bmp;
   CoglTexture *tex;
   
@@ -1327,7 +1366,7 @@ cogl_texture_new_from_file (const gchar     *filename,
   COGL_HANDLE_DEBUG_NEW (texture, tex);
   
   tex->is_foreign = FALSE;
-  tex->auto_mipmap = auto_mipmap;
+  tex->auto_mipmap = (options & COGL_TEXTURE_AUTO_MIPMAP) != 0;
 
   tex->bitmap = bmp;
   tex->bitmap_owner = TRUE;  
diff --git a/clutter/glx/clutter-glx-texture-pixmap.c b/clutter/glx/clutter-glx-texture-pixmap.c
index 0083fbf..4a2f3fe 100644
--- a/clutter/glx/clutter-glx-texture-pixmap.c
+++ b/clutter/glx/clutter-glx-texture-pixmap.c
@@ -48,6 +48,8 @@
 #include "config.h"
 #endif
 
+#include <string.h>
+
 #include "../x11/clutter-x11-texture-pixmap.h"
 #include "clutter-glx-texture-pixmap.h"
 #include "clutter-glx.h"
@@ -200,6 +202,36 @@ clutter_glx_texture_pixmap_notify (GObject *object, GParamSpec *pspec)
     }
 }
 
+static CoglTextureOptions
+get_texture_options (void)
+{
+  static gboolean initialized = FALSE;
+  static CoglTextureOptions options;
+
+  if (!initialized)
+    {
+      const char *env_string;
+
+      initialized = TRUE;
+
+      options = COGL_TEXTURE_ALLOW_RECTANGLE;
+
+      env_string = g_getenv ("CLUTTER_PIXMAP_TEXTURE_RECTANGLE");
+      if (env_string)
+	{
+	  if (strcasecmp (env_string, "force") == 0)
+	    options |= COGL_TEXTURE_FORCE_RECTANGLE;
+	  else if (strcasecmp (env_string, "disable") == 0)
+	    options &= ~COGL_TEXTURE_ALLOW_RECTANGLE;
+	  else if (env_string[0])
+	    g_warning ("Unknown value for CLUTTER_PIXMAP_TEXTURE_RECTANGLE, "
+		       "should be 'force' or 'disable'");
+	}
+    }
+
+  return options;
+}
+
 static gboolean
 create_cogl_texture (ClutterTexture *texture,
 		     guint width,
@@ -207,10 +239,10 @@ create_cogl_texture (ClutterTexture *texture,
 {
   CoglHandle  handle;
 
-  handle 
-    = cogl_texture_new_with_size (width, height,
-                                  -1, FALSE,
-                                  COGL_PIXEL_FORMAT_RGBA_8888|COGL_BGR_BIT);
+  handle = cogl_texture_new_with_size_and_options (width, height,
+						   -1,
+						   get_texture_options(),
+						   COGL_PIXEL_FORMAT_RGBA_8888|COGL_BGR_BIT);
 
   if (handle)
     {
@@ -718,9 +750,22 @@ clutter_glx_texture_pixmap_using_extension (ClutterGLXTexturePixmap *texture)
 
   priv = CLUTTER_GLX_TEXTURE_PIXMAP (texture)->priv;
 
-  return (_have_tex_from_pixmap_ext
-	  && (clutter_feature_available (COGL_FEATURE_TEXTURE_NPOT)
-	      || clutter_feature_available (COGL_FEATURE_TEXTURE_RECTANGLE)));
+  if (!_have_tex_from_pixmap_ext)
+    return FALSE;
+
+  /* EXT_texture_from_pixmap is only useful if we have the
+   * ARGB_texture_non_power_of_two or ARB_texture_rectangle
+   */
+  if (clutter_feature_available (COGL_FEATURE_TEXTURE_NPOT))
+    return TRUE;
+
+  if (clutter_feature_available (COGL_FEATURE_TEXTURE_RECTANGLE))
+    {
+      CoglTextureOptions options = get_texture_options();
+      return (options & (COGL_TEXTURE_ALLOW_RECTANGLE | COGL_TEXTURE_FORCE_RECTANGLE)) != 0;
+    }
+
+  return FALSE;
 }
 
 /**
-- 
1.6.0.3

>From f3df37a11ccc159141d944bfe6f93a709263d0dc Mon Sep 17 00:00:00 2001
From: Owen W. Taylor <[EMAIL PROTECTED]>
Date: Wed, 5 Nov 2008 18:33:10 -0500
Subject: [PATCH] Use ARB_texture_rectangle for pixmap shape rectangle when appropriate

Use the newly added cogl_texture_new_from_data_and_options() to enable
use of ARB_texture_rectangle.

Support CLUTTER_PIXMAP_TEXTURE_RECTANGLE=[force|disable] in the same
way as Clutter now does.
---
 src/compositor/mutter/mutter-shaped-texture.c |   43 +++++++++++++++++++++---
 1 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/src/compositor/mutter/mutter-shaped-texture.c b/src/compositor/mutter/mutter-shaped-texture.c
index c237870..3bb88f3 100644
--- a/src/compositor/mutter/mutter-shaped-texture.c
+++ b/src/compositor/mutter/mutter-shaped-texture.c
@@ -226,6 +226,36 @@ mutter_shaped_texture_get_gl_size (CoglHandle tex,
     }
 }
 
+static CoglTextureOptions
+get_texture_options (void)
+{
+  static gboolean initialized = FALSE;
+  static CoglTextureOptions options;
+
+  if (!initialized)
+    {
+      const char *env_string;
+
+      initialized = TRUE;
+
+      options = COGL_TEXTURE_ALLOW_RECTANGLE;
+
+      env_string = g_getenv ("CLUTTER_PIXMAP_TEXTURE_RECTANGLE");
+      if (env_string)
+	{
+	  if (strcasecmp (env_string, "force") == 0)
+	    options |= COGL_TEXTURE_FORCE_RECTANGLE;
+	  else if (strcasecmp (env_string, "disable") == 0)
+	    options &= ~COGL_TEXTURE_ALLOW_RECTANGLE;
+	  else if (env_string[0])
+	    g_warning ("Unknown value for CLUTTER_PIXMAP_TEXTURE_RECTANGLE, "
+		       "should be 'force' or 'disable'");
+	}
+    }
+
+  return options;
+}
+
 static void
 mutter_shaped_texture_ensure_mask (MutterShapedTexture *stex)
 {
@@ -280,12 +310,13 @@ mutter_shaped_texture_ensure_mask (MutterShapedTexture *stex)
             memset (p, 255, x2 - x1);
         }
 
-      priv->mask_texture = cogl_texture_new_from_data (tex_width, tex_height,
-                                                       -1, FALSE,
-                                                       COGL_PIXEL_FORMAT_A_8,
-                                                       COGL_PIXEL_FORMAT_ANY,
-                                                       tex_width,
-                                                       mask_data);
+      priv->mask_texture = cogl_texture_new_from_data_and_options (tex_width, tex_height,
+								   -1,
+								   get_texture_options(),
+								   COGL_PIXEL_FORMAT_A_8,
+								   COGL_PIXEL_FORMAT_ANY,
+								   tex_width,
+								   mask_data);
 
       g_free (mask_data);
 
-- 
1.6.0.3

Reply via email to