Bug 1297 - Bring back support for GL_ARB_texture_rectangle

* clutter/cogl/gl/cogl-texture.c (cogl_texture_new_from_foreign,
	(_cogl_texture_quad_hw, cogl_texture_polygon),
	(_cogl_texture_quad_sw): Support GL_ARB_texture_rectangle textures

	* clutter/glx/clutter-glx-texture-pixmap.c: Use rectangle textures
	when NPOTs are not available or it is forced by the
	CLUTTER_PIXMAP_TEXTURE_RECTANGLE environment variable.

	* clutter/cogl/gl/cogl.c (cogl_enable): Allow enabling
	GL_TEXTURE_RECTANGLE_ARB.
This commit is contained in:
Neil Roberts 2008-12-04 17:24:33 +00:00
parent 89e7552ca3
commit 98035e4d8a
4 changed files with 229 additions and 46 deletions

View File

@ -1,3 +1,18 @@
2008-12-04 Neil Roberts <neil@linux.intel.com>
Bug 1297 - Bring back support for GL_ARB_texture_rectangle
* clutter/cogl/gl/cogl-texture.c (cogl_texture_new_from_foreign,
(_cogl_texture_quad_hw, cogl_texture_polygon),
(_cogl_texture_quad_sw): Support GL_ARB_texture_rectangle textures
* clutter/glx/clutter-glx-texture-pixmap.c: Use rectangle textures
when NPOTs are not available or it is forced by the
CLUTTER_PIXMAP_TEXTURE_RECTANGLE environment variable.
* clutter/cogl/gl/cogl.c (cogl_enable): Allow enabling
GL_TEXTURE_RECTANGLE_ARB.
2008-12-04 Neil Roberts <neil@linux.intel.com> 2008-12-04 Neil Roberts <neil@linux.intel.com>
Bug 1172 - Disjoint paths and clip to path Bug 1172 - Disjoint paths and clip to path

View File

@ -1428,8 +1428,14 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
CoglTexSliceSpan x_span; CoglTexSliceSpan x_span;
CoglTexSliceSpan y_span; CoglTexSliceSpan y_span;
/* Allow 2-dimensional textures only */ /* GL_ARB_texture_rectangle textures are supported if they are
if (gl_target != GL_TEXTURE_2D) created from foreign because some chipsets have trouble with
GL_ARB_texture_non_power_of_two. There is no Cogl call to create
them directly to emphasize the fact that they don't work fully
(for example, no mipmapping and complicated shader support) */
/* Allow 2-dimensional or rectangle textures only */
if (gl_target != GL_TEXTURE_2D && gl_target != CGL_TEXTURE_RECTANGLE_ARB)
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
/* Make sure it is a valid GL texture object */ /* Make sure it is a valid GL texture object */
@ -1928,8 +1934,7 @@ _cogl_texture_quad_sw (CoglTexture *tex,
GLfloat tex_coords[8]; GLfloat tex_coords[8];
GLfloat quad_coords[8]; GLfloat quad_coords[8];
GLuint gl_handle; GLuint gl_handle;
gulong enable_flags = (COGL_ENABLE_TEXTURE_2D gulong enable_flags = (COGL_ENABLE_VERTEX_ARRAY
| COGL_ENABLE_VERTEX_ARRAY
| COGL_ENABLE_TEXCOORD_ARRAY); | COGL_ENABLE_TEXCOORD_ARRAY);
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -1938,8 +1943,12 @@ _cogl_texture_quad_sw (CoglTexture *tex,
printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n"); printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n");
#endif #endif
/* Prepare GL state */ /* Prepare GL state */
if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
enable_flags |= COGL_ENABLE_TEXTURE_RECT;
else
enable_flags |= COGL_ENABLE_TEXTURE_2D;
if (ctx->color_alpha < 255 if (ctx->color_alpha < 255
|| tex->bitmap.format & COGL_A_BIT) || tex->bitmap.format & COGL_A_BIT)
{ {
@ -2027,9 +2036,11 @@ _cogl_texture_quad_sw (CoglTexture *tex,
/* Normalize texture coordinates to current slice /* Normalize texture coordinates to current slice
(rectangle texture targets take denormalized) */ (rectangle texture targets take denormalized) */
if (tex->gl_target != CGL_TEXTURE_RECTANGLE_ARB)
{
slice_ty1 /= iter_y.span->size; slice_ty1 /= iter_y.span->size;
slice_ty2 /= iter_y.span->size; slice_ty2 /= iter_y.span->size;
}
/* Iterate until whole quad width covered */ /* Iterate until whole quad width covered */
for (_cogl_span_iter_begin (&iter_x, tex->slice_x_spans, for (_cogl_span_iter_begin (&iter_x, tex->slice_x_spans,
@ -2053,8 +2064,11 @@ _cogl_texture_quad_sw (CoglTexture *tex,
/* Normalize texture coordinates to current slice /* Normalize texture coordinates to current slice
(rectangle texture targets take denormalized) */ (rectangle texture targets take denormalized) */
if (tex->gl_target != CGL_TEXTURE_RECTANGLE_ARB)
{
slice_tx1 /= iter_x.span->size; slice_tx1 /= iter_x.span->size;
slice_tx2 /= iter_x.span->size; slice_tx2 /= iter_x.span->size;
}
#if COGL_DEBUG #if COGL_DEBUG
printf("~~~~~ slice (%d,%d)\n", iter_x.index, iter_y.index); printf("~~~~~ slice (%d,%d)\n", iter_x.index, iter_y.index);
@ -2111,8 +2125,7 @@ _cogl_texture_quad_hw (CoglTexture *tex,
GLuint gl_handle; GLuint gl_handle;
CoglTexSliceSpan *x_span; CoglTexSliceSpan *x_span;
CoglTexSliceSpan *y_span; CoglTexSliceSpan *y_span;
gulong enable_flags = (COGL_ENABLE_TEXTURE_2D gulong enable_flags = (COGL_ENABLE_VERTEX_ARRAY
| COGL_ENABLE_VERTEX_ARRAY
| COGL_ENABLE_TEXCOORD_ARRAY); | COGL_ENABLE_TEXCOORD_ARRAY);
#if COGL_DEBUG #if COGL_DEBUG
@ -2122,6 +2135,11 @@ _cogl_texture_quad_hw (CoglTexture *tex,
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Prepare GL state */ /* Prepare GL state */
if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
enable_flags |= COGL_ENABLE_TEXTURE_RECT;
else
enable_flags |= COGL_ENABLE_TEXTURE_2D;
if (ctx->color_alpha < 255 if (ctx->color_alpha < 255
|| tex->bitmap.format & COGL_A_BIT) || tex->bitmap.format & COGL_A_BIT)
{ {
@ -2162,6 +2180,15 @@ _cogl_texture_quad_hw (CoglTexture *tex,
ty1 = ty1 * (y_span->size - y_span->waste) / y_span->size; ty1 = ty1 * (y_span->size - y_span->waste) / y_span->size;
ty2 = ty2 * (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) COGL_FIXED_TO_FLOAT(x) #define CFX_F(x) COGL_FIXED_TO_FLOAT(x)
/* Draw textured quad */ /* Draw textured quad */
@ -2215,7 +2242,8 @@ cogl_texture_rectangle (CoglHandle handle,
(no waste) or all of the coordinates are in the range [0,1] then (no waste) or all of the coordinates are in the range [0,1] then
we can use hardware tiling */ we can use hardware tiling */
if (tex->slice_gl_handles->len == 1 if (tex->slice_gl_handles->len == 1
&& (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT) && ((cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
&& tex->gl_target == GL_TEXTURE_2D)
|| (tx1 >= 0 && tx1 <= COGL_FIXED_1 || (tx1 >= 0 && tx1 <= COGL_FIXED_1
&& tx2 >= 0 && tx2 <= COGL_FIXED_1 && tx2 >= 0 && tx2 <= COGL_FIXED_1
&& ty1 >= 0 && ty1 <= COGL_FIXED_1 && ty1 >= 0 && ty1 <= COGL_FIXED_1
@ -2289,11 +2317,14 @@ cogl_texture_polygon (CoglHandle handle,
} }
/* Prepare GL state */ /* Prepare GL state */
enable_flags = (COGL_ENABLE_TEXTURE_2D enable_flags = (COGL_ENABLE_VERTEX_ARRAY
| COGL_ENABLE_VERTEX_ARRAY
| COGL_ENABLE_TEXCOORD_ARRAY | COGL_ENABLE_TEXCOORD_ARRAY
| COGL_ENABLE_BLEND); | COGL_ENABLE_BLEND);
if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
enable_flags |= COGL_ENABLE_TEXTURE_RECT;
else
enable_flags |= COGL_ENABLE_TEXTURE_2D;
if (ctx->enable_backface_culling) if (ctx->enable_backface_culling)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING; enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
@ -2335,19 +2366,31 @@ cogl_texture_polygon (CoglHandle handle,
OpenGL */ OpenGL */
for (i = 0, p = ctx->texture_vertices; i < n_vertices; i++, p++) for (i = 0, p = ctx->texture_vertices; i < n_vertices; i++, p++)
{ {
CoglFixed tx, ty;
#define CFX_F COGL_FIXED_TO_FLOAT #define CFX_F COGL_FIXED_TO_FLOAT
tx = ((vertices[i].tx
- (COGL_FIXED_FROM_INT (x_span->start)
/ tex->bitmap.width))
* tex->bitmap.width / x_span->size);
ty = ((vertices[i].ty
- (COGL_FIXED_FROM_INT (y_span->start)
/ tex->bitmap.height))
* tex->bitmap.height / y_span->size);
/* Scale the coordinates up for rectangle textures */
if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
{
tx *= x_span->size;
ty *= y_span->size;
}
p->v[0] = CFX_F(vertices[i].x); p->v[0] = CFX_F(vertices[i].x);
p->v[1] = CFX_F(vertices[i].y); p->v[1] = CFX_F(vertices[i].y);
p->v[2] = CFX_F(vertices[i].z); p->v[2] = CFX_F(vertices[i].z);
p->t[0] = CFX_F((vertices[i].tx p->t[0] = CFX_F(tx);
- (COGL_FIXED_FROM_INT (x_span->start) p->t[1] = CFX_F(ty);
/ tex->bitmap.width))
* tex->bitmap.width / x_span->size);
p->t[1] = CFX_F((vertices[i].ty
- (COGL_FIXED_FROM_INT (y_span->start)
/ tex->bitmap.height))
* tex->bitmap.height / y_span->size);
p->c[0] = cogl_color_get_red_byte(&vertices[i].color); p->c[0] = cogl_color_get_red_byte(&vertices[i].color);
p->c[1] = cogl_color_get_green_byte(&vertices[i].color); p->c[1] = cogl_color_get_green_byte(&vertices[i].color);
p->c[2] = cogl_color_get_blue_byte(&vertices[i].color); p->c[2] = cogl_color_get_blue_byte(&vertices[i].color);

View File

@ -319,6 +319,12 @@ cogl_enable (gulong flags)
COGL_ENABLE_BACKFACE_CULLING, COGL_ENABLE_BACKFACE_CULLING,
GL_CULL_FACE); GL_CULL_FACE);
#ifdef GL_TEXTURE_RECTANGLE_ARB
cogl_toggle_flag (ctx, flags,
COGL_ENABLE_TEXTURE_RECT,
GL_TEXTURE_RECTANGLE_ARB);
#endif
cogl_toggle_client_flag (ctx, flags, cogl_toggle_client_flag (ctx, flags,
COGL_ENABLE_VERTEX_ARRAY, COGL_ENABLE_VERTEX_ARRAY,
GL_VERTEX_ARRAY); GL_VERTEX_ARRAY);

View File

@ -40,6 +40,13 @@
* *
* The class requires the GLX_EXT_texture_from_pixmap OpenGL extension * The class requires the GLX_EXT_texture_from_pixmap OpenGL extension
* (http://people.freedesktop.org/~davidr/GLX_EXT_texture_from_pixmap.txt) * (http://people.freedesktop.org/~davidr/GLX_EXT_texture_from_pixmap.txt)
*
* The GL_ARB_texture_non_power_of_two extension will be used if it is
* available. Otherwise it will try to use the
* GL_ARB_texture_rectangle extension. If both are available you can
* force it to prefer the rectangle extension by setting the
* CLUTTER_PIXMAP_TEXTURE_RECTANGLE to 'force'. To prevent it ever
* using the rectangle extension you can set it to 'disable'.
*/ */
@ -48,6 +55,8 @@
#include "config.h" #include "config.h"
#endif #endif
#include <string.h>
#include "../x11/clutter-x11-texture-pixmap.h" #include "../x11/clutter-x11-texture-pixmap.h"
#include "clutter-glx-texture-pixmap.h" #include "clutter-glx-texture-pixmap.h"
#include "clutter-glx.h" #include "clutter-glx.h"
@ -68,12 +77,20 @@ typedef void (*ReleaseTexImage) (Display *display,
typedef void (*GenerateMipmap) (GLenum target); typedef void (*GenerateMipmap) (GLenum target);
typedef enum
{
CLUTTER_GLX_RECTANGLE_DISALLOW,
CLUTTER_GLX_RECTANGLE_ALLOW,
CLUTTER_GLX_RECTANGLE_FORCE
} RectangleState;
static BindTexImage _gl_bind_tex_image = NULL; static BindTexImage _gl_bind_tex_image = NULL;
static ReleaseTexImage _gl_release_tex_image = NULL; static ReleaseTexImage _gl_release_tex_image = NULL;
static GenerateMipmap _gl_generate_mipmap = NULL; static GenerateMipmap _gl_generate_mipmap = NULL;
static gboolean _have_tex_from_pixmap_ext = FALSE; static gboolean _have_tex_from_pixmap_ext = FALSE;
static gboolean _ext_check_done = FALSE; static gboolean _ext_check_done = FALSE;
static gboolean _have_tex_rectangle = FALSE;
static RectangleState _rectangle_state = CLUTTER_GLX_RECTANGLE_ALLOW;
struct _ClutterGLXTexturePixmapPrivate struct _ClutterGLXTexturePixmapPrivate
{ {
@ -86,6 +103,8 @@ struct _ClutterGLXTexturePixmapPrivate
gboolean bound; gboolean bound;
gint can_mipmap; gint can_mipmap;
gint mipmap_generate_queued; gint mipmap_generate_queued;
gboolean using_rectangle;
}; };
static void static void
@ -170,7 +189,9 @@ clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self)
if (_ext_check_done == FALSE) if (_ext_check_done == FALSE)
{ {
const char *gl_extensions = NULL;
const gchar *glx_extensions = NULL; const gchar *glx_extensions = NULL;
const char *rect_env;
glx_extensions = glx_extensions =
glXQueryExtensionsString (clutter_x11_get_default_display (), glXQueryExtensionsString (clutter_x11_get_default_display (),
@ -191,16 +212,59 @@ clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self)
_gl_generate_mipmap = _gl_generate_mipmap =
(GenerateMipmap)cogl_get_proc_address ("glGenerateMipmapEXT"); (GenerateMipmap)cogl_get_proc_address ("glGenerateMipmapEXT");
gl_extensions = (char *) glGetString (GL_EXTENSIONS);
_have_tex_rectangle = cogl_check_extension ("GL_ARB_texture_rectangle",
gl_extensions);
if ((rect_env = g_getenv ("CLUTTER_PIXMAP_TEXTURE_RECTANGLE")))
{
if (strcasecmp (rect_env, "force") == 0)
_rectangle_state = CLUTTER_GLX_RECTANGLE_FORCE;
else if (strcasecmp (rect_env, "disable") == 0)
_rectangle_state = CLUTTER_GLX_RECTANGLE_DISALLOW;
else if (rect_env[0])
g_warning ("Unknown value for CLUTTER_PIXMAP_TEXTURE_RECTANGLE, "
"should be 'force' or 'disable'");
}
_ext_check_done = TRUE; _ext_check_done = TRUE;
} }
} }
static void
clutter_glx_texture_pixmap_free_rectangle (ClutterGLXTexturePixmap *texture)
{
ClutterGLXTexturePixmapPrivate *priv = texture->priv;
CoglHandle cogl_tex;
/* Cogl won't free the GL texture resource if it was created with
new_from_foreign so we need to free it manually */
if (priv->using_rectangle)
{
cogl_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (texture));
if (cogl_tex != COGL_INVALID_HANDLE)
{
GLuint gl_handle;
GLenum gl_target;
cogl_texture_get_gl_texture (cogl_tex, &gl_handle, &gl_target);
if (gl_target == CGL_TEXTURE_RECTANGLE_ARB)
glDeleteTextures (1, &gl_handle);
}
priv->using_rectangle = FALSE;
}
}
static void static void
clutter_glx_texture_pixmap_dispose (GObject *object) clutter_glx_texture_pixmap_dispose (GObject *object)
{ {
ClutterGLXTexturePixmapPrivate *priv; ClutterGLXTexturePixmap *texture = CLUTTER_GLX_TEXTURE_PIXMAP (object);
ClutterGLXTexturePixmapPrivate *priv = texture->priv;
priv = CLUTTER_GLX_TEXTURE_PIXMAP (object)->priv; clutter_glx_texture_pixmap_free_rectangle (texture);
if (priv->glx_pixmap != None) if (priv->glx_pixmap != None)
{ {
@ -228,20 +292,70 @@ clutter_glx_texture_pixmap_notify (GObject *object, GParamSpec *pspec)
} }
} }
static gboolean
should_use_rectangle (void)
{
/* Use the rectangle only if it is available and either:
the CLUTTER_PIXMAP_TEXTURE_RECTANGLE environment variable is
set to 'force'
*or*
the env var is set to 'allow' (which is the default) and NPOTs
textures are not available */
return _have_tex_rectangle
&& ((_rectangle_state == CLUTTER_GLX_RECTANGLE_ALLOW
&& !clutter_feature_available (CLUTTER_FEATURE_TEXTURE_NPOT))
|| _rectangle_state == CLUTTER_GLX_RECTANGLE_FORCE);
}
static gboolean static gboolean
create_cogl_texture (ClutterTexture *texture, create_cogl_texture (ClutterTexture *texture,
guint width, guint width,
guint height) guint height)
{ {
ClutterGLXTexturePixmap *texture_glx = CLUTTER_GLX_TEXTURE_PIXMAP (texture);
ClutterGLXTexturePixmapPrivate *priv = texture_glx->priv;
CoglHandle handle; CoglHandle handle;
gboolean using_rectangle;
/* We want to use the GL_ARB_texture_rectangle extension on some
chipsets because GL_ARB_texture_non_power_of_two is not always
supported or might be buggy */
if (should_use_rectangle ())
{
GLuint tex = 0;
using_rectangle = TRUE;
glGenTextures (1, &tex);
glBindTexture (CGL_TEXTURE_RECTANGLE_ARB, tex);
glTexImage2D (CGL_TEXTURE_RECTANGLE_ARB, 0,
GL_RGBA, width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
handle = cogl_texture_new_from_foreign (tex, CGL_TEXTURE_RECTANGLE_ARB,
width, height,
0, 0,
COGL_PIXEL_FORMAT_RGBA_8888
| COGL_BGR_BIT);
}
else
{
handle handle
= cogl_texture_new_with_size (width, height, = cogl_texture_new_with_size (width, height,
-1, FALSE, -1, FALSE,
COGL_PIXEL_FORMAT_RGBA_8888|COGL_BGR_BIT); COGL_PIXEL_FORMAT_RGBA_8888|COGL_BGR_BIT);
using_rectangle = FALSE;
}
if (handle) if (handle)
{ {
clutter_glx_texture_pixmap_free_rectangle (texture_glx);
priv->using_rectangle = using_rectangle;
clutter_texture_set_cogl_texture (texture, handle); clutter_texture_set_cogl_texture (texture, handle);
CLUTTER_ACTOR_SET_FLAGS (texture, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_SET_FLAGS (texture, CLUTTER_ACTOR_REALIZED);
@ -301,12 +415,14 @@ clutter_glx_texture_pixmap_realize (ClutterActor *actor)
static void static void
clutter_glx_texture_pixmap_unrealize (ClutterActor *actor) clutter_glx_texture_pixmap_unrealize (ClutterActor *actor)
{ {
ClutterGLXTexturePixmapPrivate *priv; ClutterGLXTexturePixmap *texture = CLUTTER_GLX_TEXTURE_PIXMAP (actor);
ClutterGLXTexturePixmapPrivate *priv = texture->priv;
Display *dpy; Display *dpy;
priv = CLUTTER_GLX_TEXTURE_PIXMAP (actor)->priv;
dpy = clutter_x11_get_default_display(); dpy = clutter_x11_get_default_display();
clutter_glx_texture_pixmap_free_rectangle (texture);
if (!_have_tex_from_pixmap_ext) if (!_have_tex_from_pixmap_ext)
{ {
CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)-> CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)->
@ -575,7 +691,8 @@ clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture)
attribs[i++] = GLX_TEXTURE_TARGET_EXT; attribs[i++] = GLX_TEXTURE_TARGET_EXT;
attribs[i++] = GLX_TEXTURE_2D_EXT; attribs[i++] = (should_use_rectangle ()
? GLX_TEXTURE_RECTANGLE_EXT : GLX_TEXTURE_2D_EXT);
attribs[i++] = None; attribs[i++] = None;
@ -637,13 +754,12 @@ clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture,
gint width, gint width,
gint height) gint height)
{ {
ClutterGLXTexturePixmapPrivate *priv; ClutterGLXTexturePixmap *texture_glx = CLUTTER_GLX_TEXTURE_PIXMAP (texture);
ClutterGLXTexturePixmapPrivate *priv = texture_glx->priv;
Display *dpy; Display *dpy;
CLUTTER_NOTE (TEXTURE, "Updating texture pixmap"); CLUTTER_NOTE (TEXTURE, "Updating texture pixmap");
priv = CLUTTER_GLX_TEXTURE_PIXMAP (texture)->priv;
dpy = clutter_x11_get_default_display(); dpy = clutter_x11_get_default_display();
if (!CLUTTER_ACTOR_IS_REALIZED (texture)) if (!CLUTTER_ACTOR_IS_REALIZED (texture))
@ -652,6 +768,9 @@ clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture,
if (priv->use_fallback) if (priv->use_fallback)
{ {
CLUTTER_NOTE (TEXTURE, "Falling back to X11"); CLUTTER_NOTE (TEXTURE, "Falling back to X11");
clutter_glx_texture_pixmap_free_rectangle (texture_glx);
parent_class->update_area (texture, parent_class->update_area (texture,
x, y, x, y,
width, height); width, height);