Use a utility function to create GL_ARB_texture_rectangles

meta-texture-rectangle and meta-shaped-texture both create textures
with GL_TEXTURE_RECTANGLE_ARB as the target using direct GL
calls. This patch moves that code into a shared utility function in a
separate file instead. The function resolves the required GL symbols
dynamically instead of linking to them directly so that if Clutter
eventually stops linking to -lGL mutter will continue to build. The
function also splits the texture creation into a separate texture
creation and data upload stage so that it can use
cogl_texture_set_region to upload the data. That way it can avoid
clobbering the glPixelStore state and it can let Cogl do any necessary
format conversion. The code preserves the old value of the rectangle
texture binding instead of clobbering it because Cogl expects to be
able to cache this value to avoid redundant glBindTexture
calls. Finally, the function uses cogl_object_set_data to
automatically destroy the GL texture when the Cogl texture is
destroyed. This avoids having to have special code to destroy the cogl
texture.

https://bugzilla.gnome.org/show_bug.cgi?id=654569
This commit is contained in:
Neil Roberts 2011-07-13 15:47:10 +01:00
parent 5237b2aa65
commit fccd626604
5 changed files with 191 additions and 62 deletions

View File

@ -55,6 +55,8 @@ libmutter_la_SOURCES = \
compositor/meta-shadow-factory-private.h \ compositor/meta-shadow-factory-private.h \
compositor/meta-shaped-texture.c \ compositor/meta-shaped-texture.c \
compositor/meta-shaped-texture.h \ compositor/meta-shaped-texture.h \
compositor/meta-texture-rectangle.c \
compositor/meta-texture-rectangle.h \
compositor/meta-texture-tower.c \ compositor/meta-texture-tower.c \
compositor/meta-texture-tower.h \ compositor/meta-texture-tower.h \
compositor/meta-window-actor.c \ compositor/meta-window-actor.c \

View File

@ -27,6 +27,7 @@
#include "meta-shaped-texture.h" #include "meta-shaped-texture.h"
#include "meta-texture-tower.h" #include "meta-texture-tower.h"
#include "meta-texture-rectangle.h"
#include <clutter/clutter.h> #include <clutter/clutter.h>
#include <cogl/cogl.h> #include <cogl/cogl.h>
@ -181,17 +182,6 @@ meta_shaped_texture_dirty_mask (MetaShapedTexture *stex)
if (priv->mask_texture != COGL_INVALID_HANDLE) if (priv->mask_texture != COGL_INVALID_HANDLE)
{ {
GLuint mask_gl_tex;
GLenum mask_gl_target;
cogl_texture_get_gl_texture (priv->mask_texture,
&mask_gl_tex, &mask_gl_target);
#ifdef GL_TEXTURE_RECTANGLE_ARB
if (mask_gl_target == GL_TEXTURE_RECTANGLE_ARB)
glDeleteTextures (1, &mask_gl_tex);
#endif
cogl_handle_unref (priv->mask_texture); cogl_handle_unref (priv->mask_texture);
priv->mask_texture = COGL_INVALID_HANDLE; priv->mask_texture = COGL_INVALID_HANDLE;
@ -258,24 +248,18 @@ meta_shaped_texture_ensure_mask (MetaShapedTexture *stex)
#ifdef GL_TEXTURE_RECTANGLE_ARB #ifdef GL_TEXTURE_RECTANGLE_ARB
if (paint_gl_target == GL_TEXTURE_RECTANGLE_ARB) if (paint_gl_target == GL_TEXTURE_RECTANGLE_ARB)
{ {
GLuint tex;
glGenTextures (1, &tex);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, tex);
glPixelStorei (GL_UNPACK_ROW_LENGTH, tex_width);
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0,
GL_ALPHA, tex_width, tex_height,
0, GL_ALPHA, GL_UNSIGNED_BYTE, mask_data);
priv->mask_texture priv->mask_texture
= cogl_texture_new_from_foreign (tex, = meta_texture_rectangle_new (tex_width, tex_height,
GL_TEXTURE_RECTANGLE_ARB, 0, /* flags */
tex_width, tex_height, /* data format */
0, 0, COGL_PIXEL_FORMAT_A_8,
COGL_PIXEL_FORMAT_A_8); /* internal GL format */
GL_ALPHA,
/* internal cogl format */
COGL_PIXEL_FORMAT_A_8,
/* rowstride */
tex_width,
mask_data);
} }
else else
#endif /* GL_TEXTURE_RECTANGLE_ARB */ #endif /* GL_TEXTURE_RECTANGLE_ARB */

View File

@ -0,0 +1,118 @@
/*
* texture rectangle
*
* A small utility function to help create a rectangle texture
*
* Authored By Neil Roberts <neil@linux.intel.com>
*
* Copyright (C) 2011 Intel Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <config.h>
#include "meta-texture-rectangle.h"
#ifdef GL_TEXTURE_RECTANGLE_ARB
static void (* pf_glGetIntegerv) (GLenum pname, GLint *params);
static void (* pf_glTexImage2D) (GLenum target, GLint level,
GLint internalFormat,
GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type,
const GLvoid *pixels);
static void (* pf_glGenTextures) (GLsizei n, GLuint *textures);
static void (* pf_glDeleteTextures) (GLsizei n, const GLuint *texture);
static void (* pf_glBindTexture) (GLenum target, GLuint texture);
static void
rectangle_texture_destroy_cb (void *user_data)
{
GLuint tex = GPOINTER_TO_UINT (user_data);
pf_glDeleteTextures (1, &tex);
}
#endif /* GL_TEXTURE_RECTANGLE_ARB */
CoglHandle
meta_texture_rectangle_new (unsigned int width,
unsigned int height,
CoglTextureFlags flags,
CoglPixelFormat format,
GLenum internal_gl_format,
GLenum internal_format,
unsigned int rowstride,
const guint8 *data)
{
CoglHandle cogl_tex = COGL_INVALID_HANDLE;
#ifdef GL_TEXTURE_RECTANGLE_ARB
static CoglUserDataKey user_data_key;
GLint old_binding;
GLuint tex;
if (pf_glGenTextures == NULL)
{
pf_glGetIntegerv = (void *) cogl_get_proc_address ("glGetIntegerv");
pf_glTexImage2D = (void *) cogl_get_proc_address ("glTexImage2D");
pf_glGenTextures = (void *) cogl_get_proc_address ("glGenTextures");
pf_glDeleteTextures = (void *) cogl_get_proc_address ("glDeleteTextures");
pf_glBindTexture = (void *) cogl_get_proc_address ("glBindTexture");
}
pf_glGenTextures (1, &tex);
pf_glGetIntegerv (GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
pf_glBindTexture (GL_TEXTURE_RECTANGLE_ARB, tex);
pf_glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0,
internal_gl_format, width, height,
0, internal_gl_format,
GL_UNSIGNED_BYTE, NULL);
pf_glBindTexture (GL_TEXTURE_RECTANGLE_ARB, old_binding);
cogl_tex = cogl_texture_new_from_foreign (tex,
GL_TEXTURE_RECTANGLE_ARB,
width, height,
0, 0, /* no waste */
internal_format);
/* Cogl won't destroy the GL texture when a foreign texture is used
so we need to destroy it manually. We can set a destroy
notification callback to do this transparently */
cogl_object_set_user_data (cogl_tex,
&user_data_key,
GUINT_TO_POINTER (tex),
rectangle_texture_destroy_cb);
/* Use cogl_texture_set_region instead of uploading the data
directly with GL calls so that we can let Cogl deal with setting
the pixel store parameters and handling format conversion */
if (data)
cogl_texture_set_region (cogl_tex,
0, 0, /* src x/y */
0, 0, /* dst x/y */
width, height, /* dst width/height */
width, height, /* src width/height */
format,
rowstride,
data);
#endif /* GL_TEXTURE_RECTANGLE_ARB */
return cogl_tex;
}

View File

@ -0,0 +1,45 @@
/*
* texture rectangle
*
* A small utility function to help create a rectangle texture
*
* Authored By Neil Roberts <neil@linux.intel.com>
*
* Copyright (C) 2011 Intel Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef __META_TEXTURE_RECTANGLE_H__
#define __META_TEXTURE_RECTANGLE_H__
#include <cogl/cogl.h>
G_BEGIN_DECLS
CoglHandle
meta_texture_rectangle_new (unsigned int width,
unsigned int height,
CoglTextureFlags flags,
CoglPixelFormat format,
GLenum internal_gl_format,
GLenum internal_format,
unsigned int rowstride,
const guint8 *data);
G_END_DECLS
#endif /* __META_TEXTURE_RECTANGLE_H__ */

View File

@ -26,6 +26,7 @@
#include <string.h> #include <string.h>
#include "meta-texture-tower.h" #include "meta-texture-tower.h"
#include "meta-texture-rectangle.h"
#ifndef M_LOG2E #ifndef M_LOG2E
#define M_LOG2E 1.4426950408889634074 #define M_LOG2E 1.4426950408889634074
@ -109,22 +110,6 @@ texture_is_rectangle (CoglHandle texture)
} }
#endif /* GL_TEXTURE_RECTANGLE_ARB */ #endif /* GL_TEXTURE_RECTANGLE_ARB */
static void
free_texture (CoglHandle texture)
{
#ifdef GL_TEXTURE_RECTANGLE_ARB
GLuint gl_tex;
GLenum gl_target;
cogl_texture_get_gl_texture (texture, &gl_tex, &gl_target);
if (gl_target == GL_TEXTURE_RECTANGLE_ARB)
glDeleteTextures (1, &gl_tex);
#endif /* GL_TEXTURE_RECTANGLE_ARB */
cogl_handle_unref (texture);
}
/** /**
* meta_texture_tower_update_area: * meta_texture_tower_update_area:
* @tower: a MetaTextureTower * @tower: a MetaTextureTower
@ -152,7 +137,7 @@ meta_texture_tower_set_base_texture (MetaTextureTower *tower,
{ {
if (tower->textures[i] != COGL_INVALID_HANDLE) if (tower->textures[i] != COGL_INVALID_HANDLE)
{ {
free_texture (tower->textures[i]); cogl_handle_unref (tower->textures[i]);
tower->textures[i] = COGL_INVALID_HANDLE; tower->textures[i] = COGL_INVALID_HANDLE;
} }
@ -384,23 +369,18 @@ texture_tower_create_texture (MetaTextureTower *tower,
if ((!is_power_of_two (width) || !is_power_of_two (height)) && if ((!is_power_of_two (width) || !is_power_of_two (height)) &&
texture_is_rectangle (tower->textures[level - 1])) texture_is_rectangle (tower->textures[level - 1]))
{ {
GLuint tex = 0; tower->textures[level] =
meta_texture_rectangle_new (width, height,
glGenTextures (1, &tex); 0, /* flags */
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, tex); /* data format */
glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, TEXTURE_FORMAT,
GL_RGBA, width,height, /* internal GL format */
#if TEXTURE_FORMAT == COGL_PIXEL_FORMAT_BGRA_8888_PRE GL_RGBA,
0, GL_BGRA, GL_UNSIGNED_BYTE, /* internal cogl format */
#else /* assume big endian */ TEXTURE_FORMAT,
0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, /* rowstride */
#endif width * 4,
NULL); NULL);
tower->textures[level] = cogl_texture_new_from_foreign (tex, GL_TEXTURE_RECTANGLE_ARB,
width, height,
0, 0,
TEXTURE_FORMAT);
} }
else else
#endif /* GL_TEXTURE_RECTANGLE_ARB */ #endif /* GL_TEXTURE_RECTANGLE_ARB */