mutter/clutter/glx/clutter-glx-texture-pixmap.c
Robert Bragg b1f7d2fea8 material: Avoid redundant glBindTexture calls
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.
2010-06-09 17:26:15 +01:00

939 lines
26 KiB
C

/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Johan Bilien <johan.bilien@nokia.com>
* Matthew Allum <mallum@o-hand.com>
* Robert Bragg <bob@o-hand.com>
*
* Copyright (C) 2007 OpenedHand
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*
*/
/* TODO:
* - Automagically handle named pixmaps, and window resizes (i.e
* essentially handle window id's being passed in) ?
*/
/**
* SECTION:clutter-glx-texture-pixmap
* @short_description: A texture which displays the content of an X Pixmap.
*
* #ClutterGLXTexturePixmap is a class for displaying the content of an
* X Pixmap as a ClutterActor. Used together with the X Composite extension,
* it allows to display the content of X Windows inside Clutter.
*
* The class requires the GLX_EXT_texture_from_pixmap OpenGL extension
* (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'.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include "../x11/clutter-x11-texture-pixmap.h"
#include "clutter-glx-texture-pixmap.h"
#include "clutter-glx.h"
#include "clutter-backend-glx.h"
#include "../clutter-util.h"
#include "../clutter-debug.h"
#include "../clutter-private.h"
#include "cogl/cogl.h"
#include "cogl/cogl-material-private.h"
typedef void (*BindTexImage) (Display *display,
GLXDrawable drawable,
int buffer,
int *attribList);
typedef void (*ReleaseTexImage) (Display *display,
GLXDrawable drawable,
int buffer);
typedef void (*GenerateMipmap) (GLenum target);
typedef enum
{
CLUTTER_GLX_RECTANGLE_DISALLOW,
CLUTTER_GLX_RECTANGLE_ALLOW,
CLUTTER_GLX_RECTANGLE_FORCE
} RectangleState;
enum
{
PROP_0,
PROP_AUTO_REDRAW,
};
static BindTexImage _gl_bind_tex_image = NULL;
static ReleaseTexImage _gl_release_tex_image = NULL;
static GenerateMipmap _gl_generate_mipmap = NULL;
static gboolean _have_tex_from_pixmap_ext = FALSE;
static gboolean _ext_check_done = FALSE;
static gboolean _have_tex_rectangle = FALSE;
static RectangleState _rectangle_state = CLUTTER_GLX_RECTANGLE_ALLOW;
struct _ClutterGLXTexturePixmapPrivate
{
GLXPixmap glx_pixmap;
gboolean use_fallback;
gboolean bound;
gint can_mipmap;
gboolean mipmap_generate_queued;
gboolean bind_tex_image_queued;
gboolean using_rectangle;
};
static void
clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture,
gint x,
gint y,
gint width,
gint height);
static void
clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *tex);
static ClutterX11TexturePixmapClass *parent_class = NULL;
G_DEFINE_TYPE (ClutterGLXTexturePixmap, \
clutter_glx_texture_pixmap, \
CLUTTER_X11_TYPE_TEXTURE_PIXMAP);
static void
bind_texture (ClutterGLXTexturePixmap *tex)
{
GLuint handle = 0;
GLenum target = 0;
CoglHandle cogl_tex =
clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (tex));
if (!cogl_texture_get_gl_texture (cogl_tex, &handle, &target))
g_warning ("Failed to pluck out GL handle from cogl texture to bind");
if (tex->priv->using_rectangle)
_cogl_bind_gl_texture_transient (target, handle, TRUE);
else
_cogl_bind_gl_texture_transient (target, handle, FALSE);
}
static void
release_tex_image (ClutterGLXTexturePixmap *texture)
{
ClutterGLXTexturePixmapPrivate *priv = texture->priv;
Display *dpy;
if (!priv->glx_pixmap || !priv->bound)
return;
dpy = clutter_x11_get_default_display ();
bind_texture (texture);
clutter_x11_trap_x_errors ();
(_gl_release_tex_image) (dpy,
priv->glx_pixmap,
GLX_FRONT_LEFT_EXT);
XSync (dpy, FALSE);
if (clutter_x11_untrap_x_errors ())
CLUTTER_NOTE (TEXTURE, "Failed to release?");
CLUTTER_NOTE (TEXTURE, "Destroyed pxm: %li", priv->glx_pixmap);
priv->bound = FALSE;
}
static void
on_glx_texture_pixmap_pre_paint (ClutterGLXTexturePixmap *texture,
gpointer user_data)
{
ClutterGLXTexturePixmapPrivate *priv = texture->priv;
gboolean tex_bound = FALSE;
Display *dpy = clutter_x11_get_default_display();
if (priv->bind_tex_image_queued)
{
CLUTTER_NOTE (TEXTURE, "Really updating via GLX");
bind_texture (CLUTTER_GLX_TEXTURE_PIXMAP (texture));
tex_bound = TRUE;
clutter_x11_trap_x_errors ();
(_gl_bind_tex_image) (dpy,
priv->glx_pixmap,
GLX_FRONT_LEFT_EXT,
NULL);
XSync (dpy, FALSE);
/* Note above fires X error for non name pixmaps - but
* things still seem to work - i.e pixmap updated
*/
if (clutter_x11_untrap_x_errors ())
CLUTTER_NOTE (TEXTURE, "Update bind_tex_image failed");
priv->bound = TRUE;
if (clutter_texture_get_filter_quality (CLUTTER_TEXTURE (texture))
== CLUTTER_TEXTURE_QUALITY_HIGH)
{
priv->mipmap_generate_queued++;
}
priv->bind_tex_image_queued = FALSE;
}
if (_gl_generate_mipmap &&
priv->can_mipmap &&
priv->mipmap_generate_queued)
{
GLuint handle = 0;
GLenum target = 0;
CoglHandle cogl_tex;
cogl_tex = clutter_texture_get_cogl_texture
(CLUTTER_TEXTURE(texture));
bind_texture (texture);
tex_bound = TRUE;
cogl_texture_get_gl_texture (cogl_tex, &handle, &target);
_gl_generate_mipmap (target);
}
priv->mipmap_generate_queued = FALSE;
/* Disable mipmaps if we can't support them */
if (clutter_texture_get_filter_quality (CLUTTER_TEXTURE (texture))
== CLUTTER_TEXTURE_QUALITY_HIGH
&& !priv->can_mipmap)
{
CoglHandle material
= clutter_texture_get_cogl_material (CLUTTER_TEXTURE (texture));
cogl_material_set_layer_filters (material, 0,
COGL_MATERIAL_FILTER_LINEAR,
COGL_MATERIAL_FILTER_LINEAR);
}
}
static void
clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self)
{
ClutterGLXTexturePixmapPrivate *priv;
priv = self->priv =
G_TYPE_INSTANCE_GET_PRIVATE (self,
CLUTTER_GLX_TYPE_TEXTURE_PIXMAP,
ClutterGLXTexturePixmapPrivate);
g_signal_connect (CLUTTER_ACTOR(self),
"paint", G_CALLBACK (on_glx_texture_pixmap_pre_paint),
NULL);
if (_ext_check_done == FALSE)
{
const char *gl_extensions = NULL;
const gchar *glx_extensions = NULL;
const char *rect_env;
glx_extensions =
glXQueryExtensionsString (clutter_x11_get_default_display (),
clutter_x11_get_default_screen ());
/* Check for the texture from pixmap extension */
if (_cogl_check_extension ("GLX_EXT_texture_from_pixmap",
glx_extensions))
{
_gl_bind_tex_image =
(BindTexImage)cogl_get_proc_address ("glXBindTexImageEXT");
_gl_release_tex_image =
(ReleaseTexImage)cogl_get_proc_address ("glXReleaseTexImageEXT");
if (_gl_bind_tex_image && _gl_release_tex_image)
_have_tex_from_pixmap_ext = TRUE;
}
_gl_generate_mipmap =
(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 (g_ascii_strcasecmp (rect_env, "force") == 0)
_rectangle_state = CLUTTER_GLX_RECTANGLE_FORCE;
else if (g_ascii_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;
}
}
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 == GL_TEXTURE_RECTANGLE_ARB)
glDeleteTextures (1, &gl_handle);
}
priv->using_rectangle = FALSE;
}
}
static void
clutter_glx_texture_pixmap_dispose (GObject *object)
{
ClutterGLXTexturePixmap *texture = CLUTTER_GLX_TEXTURE_PIXMAP (object);
ClutterGLXTexturePixmapPrivate *priv = texture->priv;
clutter_glx_texture_pixmap_free_rectangle (texture);
if (priv->glx_pixmap != None)
{
clutter_x11_trap_x_errors ();
glXDestroyPixmap (clutter_x11_get_default_display(),
priv->glx_pixmap);
XSync (clutter_x11_get_default_display(), FALSE);
clutter_x11_untrap_x_errors ();
priv->glx_pixmap = None;
}
G_OBJECT_CLASS (clutter_glx_texture_pixmap_parent_class)->dispose (object);
}
static void
clutter_glx_texture_pixmap_notify (GObject *object, GParamSpec *pspec)
{
if (g_str_equal (pspec->name, "pixmap"))
{
ClutterGLXTexturePixmap *texture = CLUTTER_GLX_TEXTURE_PIXMAP (object);
if (CLUTTER_ACTOR_IS_REALIZED (texture))
clutter_glx_texture_pixmap_create_glx_pixmap (texture);
}
}
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
create_cogl_texture (ClutterTexture *texture,
guint width,
guint height)
{
ClutterGLXTexturePixmap *texture_glx = CLUTTER_GLX_TEXTURE_PIXMAP (texture);
ClutterGLXTexturePixmapPrivate *priv = texture_glx->priv;
CoglHandle handle;
gboolean using_rectangle;
GLint gl_format;
CoglPixelFormat cogl_format = COGL_PIXEL_FORMAT_RGBA_8888;
guint depth;
g_object_get (G_OBJECT (texture_glx), "pixmap-depth", &depth, NULL);
if (depth == 32)
{
gl_format = GL_RGBA;
cogl_format = COGL_PIXEL_FORMAT_RGBA_8888;
}
else if (depth == 24)
{
gl_format = GL_RGB;
cogl_format = COGL_PIXEL_FORMAT_RGB_888;
}
else
{
g_critical ("Can't create a TFP cogl texture for pixmap with depth < 24");
return FALSE;
}
/* 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);
_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);
handle = cogl_texture_new_from_foreign (tex, GL_TEXTURE_RECTANGLE_ARB,
width, height,
0, 0,
cogl_format | COGL_BGR_BIT |
COGL_PREMULT_BIT);
}
else
{
handle
= cogl_texture_new_with_size (width, height,
COGL_TEXTURE_NO_SLICING,
cogl_format | COGL_BGR_BIT |
COGL_PREMULT_BIT);
using_rectangle = FALSE;
}
if (handle)
{
clutter_glx_texture_pixmap_free_rectangle (texture_glx);
priv->using_rectangle = using_rectangle;
clutter_texture_set_cogl_texture (texture, handle);
cogl_handle_unref(handle);
return TRUE;
}
return FALSE;
}
static void
clutter_glx_texture_pixmap_realize (ClutterActor *actor)
{
ClutterGLXTexturePixmap *texture;
ClutterGLXTexturePixmapPrivate *priv;
texture = CLUTTER_GLX_TEXTURE_PIXMAP (actor);
priv = texture->priv;
clutter_glx_texture_pixmap_create_glx_pixmap (texture);
if (priv->use_fallback)
{
CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)->
realize (actor);
return;
}
CLUTTER_NOTE (TEXTURE, "texture pixmap realised");
}
static void
clutter_glx_texture_pixmap_unrealize (ClutterActor *actor)
{
ClutterGLXTexturePixmap *texture = CLUTTER_GLX_TEXTURE_PIXMAP (actor);
Display *dpy;
dpy = clutter_x11_get_default_display();
clutter_glx_texture_pixmap_free_rectangle (texture);
if (!_have_tex_from_pixmap_ext)
{
CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)->
unrealize (actor);
return;
}
if (!CLUTTER_ACTOR_IS_REALIZED (actor))
return;
release_tex_image (texture);
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
}
static GLXFBConfig *
get_fbconfig_for_depth (ClutterGLXTexturePixmap *texture, guint depth)
{
GLXFBConfig *fbconfigs, *ret = NULL;
int n_elements, i, found;
Display *dpy;
int db, stencil, alpha, mipmap, rgba, value;
static GLXFBConfig *cached_config = NULL;
static gboolean have_cached_config = FALSE;
static int cached_mipmap = 0;
if (have_cached_config)
{
texture->priv->can_mipmap = cached_mipmap;
return cached_config;
}
dpy = clutter_x11_get_default_display ();
fbconfigs = glXGetFBConfigs (dpy,
clutter_x11_get_default_screen (),
&n_elements);
db = G_MAXSHORT;
stencil = G_MAXSHORT;
mipmap = 0;
rgba = 0;
found = n_elements;
for (i = 0; i < n_elements; i++)
{
XVisualInfo *vi;
int visual_depth;
vi = glXGetVisualFromFBConfig (dpy,
fbconfigs[i]);
if (vi == NULL)
continue;
visual_depth = vi->depth;
XFree (vi);
if (visual_depth != depth)
continue;
glXGetFBConfigAttrib (dpy,
fbconfigs[i],
GLX_ALPHA_SIZE,
&alpha);
glXGetFBConfigAttrib (dpy,
fbconfigs[i],
GLX_BUFFER_SIZE,
&value);
if (value != depth && (value - alpha) != depth)
continue;
value = 0;
if (depth == 32)
{
glXGetFBConfigAttrib (dpy,
fbconfigs[i],
GLX_BIND_TO_TEXTURE_RGBA_EXT,
&value);
if (value)
rgba = 1;
}
if (!value)
{
if (rgba)
continue;
glXGetFBConfigAttrib (dpy,
fbconfigs[i],
GLX_BIND_TO_TEXTURE_RGB_EXT,
&value);
if (!value)
continue;
}
glXGetFBConfigAttrib (dpy,
fbconfigs[i],
GLX_DOUBLEBUFFER,
&value);
if (value > db)
continue;
db = value;
glXGetFBConfigAttrib (dpy,
fbconfigs[i],
GLX_STENCIL_SIZE,
&value);
if (value > stencil)
continue;
stencil = value;
if (_gl_generate_mipmap)
{
glXGetFBConfigAttrib (dpy,
fbconfigs[i],
GLX_BIND_TO_MIPMAP_TEXTURE_EXT,
&value);
if (value < mipmap)
continue;
mipmap = value;
}
found = i;
}
if (found != n_elements)
{
ret = g_malloc (sizeof (GLXFBConfig));
*ret = fbconfigs[found];
}
if (n_elements)
XFree (fbconfigs);
have_cached_config = TRUE;
cached_config = ret;
texture->priv->can_mipmap = cached_mipmap = mipmap;
return ret;
}
static void
clutter_glx_texture_pixmap_free_glx_pixmap (ClutterGLXTexturePixmap *texture)
{
ClutterGLXTexturePixmapPrivate *priv = texture->priv;
Display *dpy;
dpy = clutter_x11_get_default_display ();
release_tex_image (texture);
clutter_x11_trap_x_errors ();
if (priv->glx_pixmap)
glXDestroyPixmap (dpy, priv->glx_pixmap);
XSync (dpy, FALSE);
clutter_x11_untrap_x_errors ();
priv->glx_pixmap = None;
}
static void
clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture)
{
ClutterGLXTexturePixmapPrivate *priv = texture->priv;
GLXPixmap glx_pixmap = None;
int attribs[7], i = 0, mipmap = 0;
GLXFBConfig *fbconfig;
Display *dpy;
guint depth;
Pixmap pixmap = None;
guint pixmap_width = 0, pixmap_height = 0;
ClutterBackendGLX *backend_glx;
ClutterTextureQuality quality;
backend_glx = CLUTTER_BACKEND_GLX(clutter_get_default_backend ());
dpy = clutter_x11_get_default_display ();
if (!_have_tex_from_pixmap_ext)
goto cleanup;
g_object_get (texture,
"pixmap-width", &pixmap_width,
"pixmap-height", &pixmap_height,
"pixmap-depth", &depth,
"pixmap", &pixmap,
NULL);
if (!pixmap)
{
goto cleanup;
}
CLUTTER_NOTE (TEXTURE, "Creating GLXPixmap");
fbconfig = get_fbconfig_for_depth (texture, depth);
if (!fbconfig)
{
g_warning ("Could not find an FBConfig for selected pixmap");
goto cleanup;
}
attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
if (depth == 24)
{
attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT;
}
else if (depth == 32)
{
attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
}
else
{
g_warning ("Pixmap with depth below 24 are not supported");
goto cleanup;
}
quality = clutter_texture_get_filter_quality (CLUTTER_TEXTURE (texture));
if (quality == CLUTTER_TEXTURE_QUALITY_HIGH && priv->can_mipmap)
mipmap = priv->can_mipmap;
attribs[i++] = GLX_MIPMAP_TEXTURE_EXT;
attribs[i++] = mipmap;
attribs[i++] = GLX_TEXTURE_TARGET_EXT;
attribs[i++] = (should_use_rectangle ()
? GLX_TEXTURE_RECTANGLE_EXT : GLX_TEXTURE_2D_EXT);
attribs[i++] = None;
/* Note: some drivers (e.g. Nvidia) get upset if you effectivly create a glx
* pixmap for the same server side object, even though you might have unique
* client side names, we currently avoid hitting this problem by destroying
* the current glx pixmap first */
if (priv->glx_pixmap)
clutter_glx_texture_pixmap_free_glx_pixmap (texture);
clutter_x11_trap_x_errors ();
glx_pixmap = glXCreatePixmap (dpy,
*fbconfig,
pixmap,
attribs);
XSync (dpy, FALSE);
if (clutter_x11_untrap_x_errors ())
{
CLUTTER_NOTE (TEXTURE, "Failed to create GLXPixmap");
/* Make sure we don't think the call actually succeeded */
glx_pixmap = None;
}
if (!create_cogl_texture (CLUTTER_TEXTURE (texture),
pixmap_width, pixmap_height))
{
CLUTTER_NOTE (TEXTURE, "Unable to create texture for pixmap");
glXDestroyPixmap (dpy, glx_pixmap);
glx_pixmap = None;
goto cleanup;
}
cleanup:
if (priv->glx_pixmap)
clutter_glx_texture_pixmap_free_glx_pixmap (texture);
if (glx_pixmap != None)
{
priv->use_fallback = FALSE;
priv->glx_pixmap = glx_pixmap;
CLUTTER_NOTE (TEXTURE, "Created GLXPixmap");
clutter_glx_texture_pixmap_update_area (CLUTTER_X11_TEXTURE_PIXMAP (texture),
0, 0,
pixmap_width, pixmap_height);
/* Get ready to queue initial mipmap generation */
if (clutter_texture_get_filter_quality (CLUTTER_TEXTURE (texture))
== CLUTTER_TEXTURE_QUALITY_HIGH)
{
priv->mipmap_generate_queued = TRUE;
}
return;
}
else
{
if (pixmap)
CLUTTER_NOTE (TEXTURE, "Falling back to X11 manual mechansim");
priv->use_fallback = TRUE;
priv->glx_pixmap = None;
}
}
static void
clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture,
gint x,
gint y,
gint width,
gint height)
{
ClutterGLXTexturePixmap *texture_glx = CLUTTER_GLX_TEXTURE_PIXMAP (texture);
ClutterGLXTexturePixmapPrivate *priv = texture_glx->priv;
CLUTTER_NOTE (TEXTURE, "Updating texture pixmap");
if (!CLUTTER_ACTOR_IS_REALIZED (texture))
return;
if (priv->use_fallback)
{
CLUTTER_NOTE (TEXTURE, "Falling back to X11");
clutter_glx_texture_pixmap_free_rectangle (texture_glx);
parent_class->update_area (texture,
x, y,
width, height);
return;
}
if (priv->glx_pixmap == None)
return;
priv->bind_tex_image_queued = TRUE;
}
static void
clutter_glx_texture_pixmap_class_init (ClutterGLXTexturePixmapClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
ClutterX11TexturePixmapClass *x11_texture_class =
CLUTTER_X11_TEXTURE_PIXMAP_CLASS (klass);
g_type_class_add_private (klass, sizeof (ClutterGLXTexturePixmapPrivate));
parent_class = g_type_class_peek_parent(klass);
object_class->dispose = clutter_glx_texture_pixmap_dispose;
object_class->notify = clutter_glx_texture_pixmap_notify;
actor_class->realize = clutter_glx_texture_pixmap_realize;
actor_class->unrealize = clutter_glx_texture_pixmap_unrealize;
x11_texture_class->update_area = clutter_glx_texture_pixmap_update_area;
}
/**
* clutter_glx_texture_pixmap_using_extension:
* @texture: A #ClutterGLXTexturePixmap
*
* Checks whether @texture is using the GLX_EXT_texture_from_pixmap
* extension; this extension can be optionally (though it is strongly
* encouraged) implemented as a zero-copy between a GLX pixmap and
* a GL texture.
*
* Return value: %TRUE if the texture is using the
* GLX_EXT_texture_from_pixmap OpenGL extension or falling back to the
* slower software mechanism.
*
* Since: 0.8
*/
gboolean
clutter_glx_texture_pixmap_using_extension (ClutterGLXTexturePixmap *texture)
{
ClutterGLXTexturePixmapPrivate *priv;
priv = CLUTTER_GLX_TEXTURE_PIXMAP (texture)->priv;
return (_have_tex_from_pixmap_ext && !priv->use_fallback);
/* 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)); */
}
/**
* clutter_glx_texture_pixmap_new_with_pixmap:
* @pixmap: the X Pixmap to which this texture should be bound
*
* Creates a new #ClutterGLXTexturePixmap for @pixmap
*
* Return value: A new #ClutterGLXTexturePixmap bound to the given X Pixmap
*
* Since: 0.8
*/
ClutterActor *
clutter_glx_texture_pixmap_new_with_pixmap (Pixmap pixmap)
{
return g_object_new (CLUTTER_GLX_TYPE_TEXTURE_PIXMAP,
"pixmap", pixmap,
NULL);
}
/**
* clutter_glx_texture_pixmap_new_with_window:
* @window: the X window to which this texture should be bound
*
* Creates a new #ClutterGLXTexturePixmap for @window
*
* Return value: A new #ClutterGLXTexturePixmap bound to the given X window
*
* Since: 0.8
**/
ClutterActor *
clutter_glx_texture_pixmap_new_with_window (Window window)
{
return g_object_new (CLUTTER_GLX_TYPE_TEXTURE_PIXMAP,
"window", window,
NULL);
}
/**
* clutter_glx_texture_pixmap_new:
*
* Creates a new, empty #ClutterGLXTexturePixmap
*
* Return value: A new #ClutterGLXTexturePixmap
*
* Since: 0.8
*/
ClutterActor *
clutter_glx_texture_pixmap_new (void)
{
return g_object_new (CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, NULL);
}