Skip to content
Permalink
64c3f7a96d
Go to file
 
 
Cannot retrieve contributors at this time
848 lines (706 sloc) 25.6 KB
/*
* 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>
* Kimmo Hamalainen <kimmo.hamalainen@nokia.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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* TODO:
* - Automagically handle named pixmaps, and window resizes (i.e
* essentially handle window id's being passed in) ?
*/
/**
* SECTION:clutter-eglx-texture-pixmap
* @short_description: A texture which displays the content of an X Pixmap.
*
* #ClutterEGLXTexturePixmap 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 EGL_EXT_texture_from_pixmap OpenGL extension.
*/
/* Whether to draw a red-bordered window when there is no valid pixmap
* (If we don't, we just draw nothing) */
#define DEBUG_RED_RECT 0
/* We don't want to print configs in most cases, as this can take around 30ms or so */
#define DEBUG_PRINT_CONFIGS 0
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <X11/extensions/Xcomposite.h>
#include <string.h>
#include "../x11/clutter-x11-texture-pixmap.h"
#include "clutter-eglx-texture-pixmap.h"
#include "clutter-eglx.h"
#include "clutter-backend-egl.h"
#include "../clutter-util.h"
#include "../clutter-debug.h"
#include "../clutter-debug.h"
#include "cogl/cogl.h"
static gboolean _have_tex_from_pixmap_ext = FALSE;
static gboolean _have_egl_image_tfp_ext = FALSE;
static gboolean _ext_check_done = FALSE;
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
struct _ClutterEGLXTexturePixmapPrivate
{
EGLSurface egl_surface;
EGLImageKHR egl_image;
gboolean use_fallback;
guint current_pixmap;
guint current_pixmap_depth;
guint current_pixmap_width;
guint current_pixmap_height;
/* If the pixmap has changed, we'll want to try and recreate the surface */
gboolean pixmap_changed;
gboolean pixmap_bound;
gboolean dispose_called;
};
void
clutter_eglx_texture_pixmap_paint (ClutterActor *actor);
static void
clutter_eglx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture,
gint x,
gint y,
gint width,
gint height);
static EGLConfig
clutter_eglx_get_eglconfig (EGLDisplay *display,
EGLSurface *surface, Pixmap pixmap,
int depth);
static void
clutter_eglx_texture_pixmap_bind (ClutterActor *actor);
static void
clutter_eglx_texture_pixmap_unbind (ClutterActor *actor);
static void
clutter_eglx_texture_pixmap_freeing_pixmap (ClutterEGLXTexturePixmap *self);
static ClutterX11TexturePixmapClass *parent_class = NULL;
static ClutterActorClass *clutter_actor_class = NULL;
G_DEFINE_TYPE_WITH_CODE (ClutterEGLXTexturePixmap, \
clutter_eglx_texture_pixmap, \
CLUTTER_X11_TYPE_TEXTURE_PIXMAP,
G_ADD_PRIVATE (ClutterEGLXTexturePixmap));
static void
print_config_info (EGLConfig conf)
{
#if DEBUG_PRINT_CONFIGS
EGLint red = -1, green = -1, blue = -1, alpha = -1, stencil = -1;
EGLint rgba_bindable = -1, rgb_bindable = -1, tex_target = -1;
if (!conf) return;
eglGetConfigAttrib (clutter_eglx_display (),
conf,
EGL_RED_SIZE, &red);
eglGetConfigAttrib (clutter_eglx_display (),
conf,
EGL_GREEN_SIZE, &green);
eglGetConfigAttrib (clutter_eglx_display (),
conf,
EGL_BLUE_SIZE, &blue);
eglGetConfigAttrib (clutter_eglx_display (),
conf,
EGL_ALPHA_SIZE, &alpha);
eglGetConfigAttrib (clutter_eglx_display (),
conf,
EGL_STENCIL_SIZE, &stencil);
eglGetConfigAttrib (clutter_eglx_display (),
conf,
EGL_BIND_TO_TEXTURE_RGB, &rgb_bindable);
eglGetConfigAttrib (clutter_eglx_display (),
conf,
EGL_BIND_TO_TEXTURE_RGBA, &rgba_bindable);
eglGetConfigAttrib (clutter_eglx_display (),
conf,
EGL_TEXTURE_TARGET, &tex_target);
g_debug ("%s: R:%d G:%d B:%d A:%d S:%d RGB:%d RGBA:%d TEX:%d",
__FUNCTION__,
red, green, blue, alpha, stencil,
rgb_bindable, rgba_bindable, tex_target);
#endif
}
static void
clutter_eglx_texture_pixmap_init (ClutterEGLXTexturePixmap *self)
{
ClutterEGLXTexturePixmapPrivate *priv;
priv = self->priv = clutter_eglx_texture_pixmap_get_instance_private (self);
priv->egl_surface = EGL_NO_SURFACE;
priv->egl_image = EGL_NO_IMAGE_KHR;
priv->pixmap_bound = FALSE;
priv->current_pixmap = 0;
priv->current_pixmap_depth = 0;
priv->current_pixmap_width = 0;
priv->current_pixmap_height = 0;
priv->dispose_called = FALSE;
if (_ext_check_done == FALSE)
{
const char *eglx_extensions = NULL;
ClutterBackendEGL *backend;
backend = CLUTTER_BACKEND_EGL (clutter_get_default_backend ());
eglx_extensions = eglQueryString (backend->edpy,
EGL_EXTENSIONS);
g_debug("%s: checking for texture_from_pixmap", __FUNCTION__);
/* Check for a texture from pixmap extension.
* Note: vendor-specific since there is no TFP in EGL specification. */
if (cogl_check_extension ("EGL_NOKIA_texture_from_pixmap",
eglx_extensions))
{
g_debug("%s: found EGL_NOKIA_texture_from_pixmap", __FUNCTION__);
_have_tex_from_pixmap_ext = TRUE;
}
else
{
g_debug("%s: checking for EGLImage 'texture from pixmap' ability", __FUNCTION__);
if (cogl_check_extension ("EGL_KHR_image_pixmap", eglx_extensions) &&
cogl_features_available(COGL_FEATURE_TEXTURE_EGLIMAGE))
{
g_debug("%s: found EGL_KHR_image_pixmap & GL_OES_EGL_image", __FUNCTION__);
eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)
eglGetProcAddress ("eglCreateImageKHR");
eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC)
eglGetProcAddress ("eglDestroyImageKHR");
glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)
eglGetProcAddress ("glEGLImageTargetTexture2DOES");
_have_egl_image_tfp_ext = TRUE;
}
}
_ext_check_done = TRUE;
}
priv->use_fallback = !_have_tex_from_pixmap_ext && !_have_egl_image_tfp_ext;
/* We need to know when the pixmap is about to be freed, so we can
* eglDestroySurface before it's gone */
g_signal_connect (self, "pixmap-freeing",
G_CALLBACK (clutter_eglx_texture_pixmap_freeing_pixmap), 0);
}
static void
clutter_eglx_texture_pixmap_dispose (GObject *object)
{
ClutterEGLXTexturePixmapPrivate *priv;
priv = CLUTTER_EGLX_TEXTURE_PIXMAP (object)->priv;
/* this dispose handler is called twice because of how
* clutter_actor_destroy works */
if (priv->pixmap_bound)
clutter_eglx_texture_pixmap_unbind(CLUTTER_ACTOR(object));
/* Texture deletion is now handled by the CoglTexture */
G_OBJECT_CLASS (clutter_eglx_texture_pixmap_parent_class)->dispose (object);
}
static gboolean
create_cogl_texture (ClutterTexture *texture,
GLuint gl_handle,
GLuint width,
GLuint height,
CoglPixelFormat format)
{
CoglHandle handle;
handle = cogl_texture_new_from_foreign (gl_handle, GL_TEXTURE_2D,
width, height,
0, 0, format);
if (handle)
{
/* Force COGL to take ownership of this texture and destroy it
* when the CoglTexture is destroyed */
cogl_texture_set_foreign(handle, FALSE);
/*g_debug ("%s: created cogl handle %x", __FUNCTION__, (int)handle);*/
clutter_texture_set_cogl_texture (texture, handle);
/* unref because clutter_texture_set_cogl_texture ref'd the handle */
cogl_texture_unref (handle);
return TRUE;
}
else
g_debug ("%s: cogl_texture_new_from_foreign failed", __FUNCTION__);
return FALSE;
}
static void
clutter_eglx_texture_pixmap_bind (ClutterActor *actor)
{
ClutterEGLXTexturePixmapPrivate *priv;
Pixmap pixmap;
Window window;
guint pixmap_depth;
gboolean has_alpha;
CoglPixelFormat format;
ClutterBackendEGL *backend;
GLuint texture_id;
backend = CLUTTER_BACKEND_EGL (clutter_get_default_backend ());
priv = CLUTTER_EGLX_TEXTURE_PIXMAP (actor)->priv;
g_object_get (actor,
"pixmap", &priv->current_pixmap,
"pixmap-depth", &priv->current_pixmap_depth,
"pixmap-width", &priv->current_pixmap_width,
"pixmap-height", &priv->current_pixmap_height,
NULL);
if (priv->use_fallback)
{
g_debug ("%s: texture from pixmap appears unsupported", __FUNCTION__);
CLUTTER_NOTE (TEXTURE, "Falling back to X11 manual mechanism");
CLUTTER_ACTOR_CLASS (clutter_eglx_texture_pixmap_parent_class)->
realize (actor);
return;
}
g_object_get (actor,
"pixmap", &pixmap,
"window", &window,
"pixmap-depth", &pixmap_depth,
NULL);
if (!pixmap && !window)
{
g_warning ("%s: no Pixmap or Window to bind to", __FUNCTION__);
return;
}
has_alpha = pixmap_depth==32;
if (!clutter_x11_texture_pixmap_get_allow_alpha(
CLUTTER_X11_TEXTURE_PIXMAP(actor)))
has_alpha = FALSE;
if (_have_tex_from_pixmap_ext)
{
EGLConfig conf;
if (pixmap)
{
conf = clutter_eglx_get_eglconfig (backend->edpy, &priv->egl_surface,
pixmap, has_alpha);
print_config_info (conf);
}
else
{
clutter_x11_trap_x_errors ();
pixmap = XCompositeNameWindowPixmap (clutter_x11_get_default_display (),
window);
if (clutter_x11_untrap_x_errors ())
{
g_warning ("%s: XCompositeNameWindowPixmap failed for window %lx",
__FUNCTION__, window);
return;
}
conf = clutter_eglx_get_eglconfig (backend->edpy, &priv->egl_surface,
pixmap, has_alpha);
print_config_info (conf);
}
if (priv->egl_surface == EGL_NO_SURFACE)
{
g_warning ("%s: error %x, failed to create %s surface for %lx, "
"using X11 fallback.",
__FUNCTION__, eglGetError (),
pixmap ? "pixmap" : "window",
pixmap ? pixmap : window);
priv->use_fallback = TRUE;
CLUTTER_ACTOR_CLASS (clutter_eglx_texture_pixmap_parent_class)->
realize (actor);
return;
}
}
else /* _have_egl_image_tfp_ext */
{
const EGLint img_attribs[] = {
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_NONE
};
priv->egl_image = eglCreateImageKHR(backend->edpy,
EGL_NO_CONTEXT,
EGL_NATIVE_PIXMAP_KHR,
(EGLClientBuffer)pixmap,
img_attribs);
if (priv->egl_image == EGL_NO_IMAGE)
{
g_warning ("%s: error %x, failed to create %s EGLImageKHR for %lx, "
"using X11 fallback.",
__FUNCTION__, eglGetError (),
pixmap ? "pixmap" : "window",
pixmap ? pixmap : window);
priv->use_fallback = TRUE;
CLUTTER_ACTOR_CLASS (clutter_eglx_texture_pixmap_parent_class)->
realize (actor);
return;
}
}
/* If we got here, we should have priv->egl_surface or priv->egl_image
* set from pixmap */
priv->pixmap_bound = TRUE;
/* Bind to a GL texture */
glGenTextures (1, &texture_id);
glBindTexture (GL_TEXTURE_2D, texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
if (glIsTexture (texture_id) == GL_FALSE)
{
g_warning ("%s: failed to bind texture", __FUNCTION__);
return;
}
if (!has_alpha)
{
if (priv->current_pixmap_depth == 16)
format = COGL_PIXEL_FORMAT_RGB_565;
else
format = COGL_PIXEL_FORMAT_RGB_888;
}
else
{
g_debug ("%s: texture format is EGL_TEXTURE_RGBA", __FUNCTION__);
format = COGL_PIXEL_FORMAT_RGBA_8888;
}
if (!create_cogl_texture (CLUTTER_TEXTURE (actor), texture_id,
priv->current_pixmap_width, priv->current_pixmap_height, format))
{
g_debug ("%s: Unable to create cogl texture", __FUNCTION__);
glDeleteTextures (1, &texture_id);
CLUTTER_NOTE (TEXTURE, "Falling back to X11 manual mechanism");
priv->use_fallback = TRUE;
CLUTTER_ACTOR_CLASS (clutter_eglx_texture_pixmap_parent_class)->
realize (actor);
}
}
static void
clutter_eglx_texture_pixmap_unbind (ClutterActor *actor)
{
ClutterEGLXTexturePixmapPrivate *priv;
ClutterBackendEGL *backend;
Display *dpy;
priv = CLUTTER_EGLX_TEXTURE_PIXMAP (actor)->priv;
backend = CLUTTER_BACKEND_EGL (clutter_get_default_backend ());
dpy = clutter_x11_get_default_display ();
if (priv->egl_surface != EGL_NO_SURFACE)
{
/*
g_debug ("%s: doing eglDestroySurface(disp, %x)",
__FUNCTION__, (unsigned int)priv->egl_surface);
*/
clutter_x11_trap_x_errors ();
eglDestroySurface (backend->edpy, priv->egl_surface);
XSync (dpy, FALSE);
if (clutter_x11_untrap_x_errors ())
g_debug ("%s: X errors", __FUNCTION__);
priv->egl_surface = EGL_NO_SURFACE;
}
else if (priv->egl_image != EGL_NO_IMAGE_KHR)
{
eglDestroyImageKHR(backend->edpy, priv->egl_image);
priv->egl_image = EGL_NO_IMAGE_KHR;
}
priv->pixmap_bound = FALSE;
/* It looks like we can keep the old texture as clutter
* will free it anyway if we unrealise or set a new texture */
}
static void clutter_eglx_texture_pixmap_freeing_pixmap (ClutterEGLXTexturePixmap *self)
{
ClutterEGLXTexturePixmapPrivate *priv = self->priv;
/** We need to ensure that we get rid of the surface before the pixmap
* is XFreePixmap'd. The pixmap will be set to 0 or the new value right
* after, so we'll be notified to create a new surface if we need to. */
if (priv->pixmap_bound)
clutter_eglx_texture_pixmap_unbind(CLUTTER_ACTOR(self));
}
static const EGLint pixmap_creation_config_rgb[] = {
EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGB,
EGL_NONE
};
static const EGLint pixmap_creation_config_rgba[] = {
EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
EGL_NONE
};
static const EGLint pixmap_config[] = {
EGL_SURFACE_TYPE, EGL_PIXMAP_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_DEPTH_SIZE, 0,
EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE,
/*EGL_BUFFER_SIZE, 16,*/
EGL_NONE
};
static EGLConfig
clutter_eglx_get_eglconfig (EGLDisplay *display,
EGLSurface *surface, Pixmap pixmap,
gboolean has_alpha)
{
EGLConfig configs[20];
int i, nconfigs = 0;
EGLBoolean ret;
ret = eglChooseConfig (display, pixmap_config, configs,
G_N_ELEMENTS (configs), &nconfigs);
if (ret != EGL_TRUE)
{
g_debug ("%s: eglChooseConfig failed: %x", __FUNCTION__, eglGetError());
return NULL;
}
/*else
{
g_debug ("%s: got %d matching configs", __FUNCTION__, nconfigs);
}*/
for (i = 0; i < nconfigs; ++i)
{
if (has_alpha)
*surface = eglCreatePixmapSurface (display, configs[i],
(EGLNativePixmapType)pixmap,
pixmap_creation_config_rgba);
else
*surface = eglCreatePixmapSurface (display, configs[i],
(EGLNativePixmapType)pixmap,
pixmap_creation_config_rgb);
if (*surface != EGL_NO_SURFACE)
return configs[i];
g_debug ("%s: eglCreatePixmapSurface failed for config:",
__FUNCTION__);
print_config_info (configs[i]);
}
/* We failed to get any surface */
return NULL;
}
static void
clutter_eglx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture,
gint x,
gint y,
gint width,
gint height)
{
guint pixmap, pixmap_depth, pixmap_width, pixmap_height;
ClutterEGLXTexturePixmapPrivate *priv;
priv = CLUTTER_EGLX_TEXTURE_PIXMAP (texture)->priv;
if (priv->use_fallback)
{
g_debug ("%s: Falling back to X11", __FUNCTION__);
parent_class->update_area (texture, x, y, width, height);
return;
}
if (!CLUTTER_ACTOR_IS_REALIZED (texture))
{
g_debug ("%s: Not realised, returning", __FUNCTION__);
return;
}
/*g_debug ("%s: Updating texture pixmap %p, %d, %d, %d, %d",
__FUNCTION__, texture,
x, y, width, height);*/
g_object_get (texture,
"pixmap", &pixmap,
"pixmap-depth", &pixmap_depth,
"pixmap-width", &pixmap_width,
"pixmap-height", &pixmap_height,
NULL);
if (pixmap != priv->current_pixmap ||
pixmap_depth != priv->current_pixmap_depth ||
pixmap_width != priv->current_pixmap_width ||
pixmap_height != priv->current_pixmap_height ||
!priv->pixmap_bound)
{
priv->pixmap_changed = TRUE;
}
if (/*priv->pixmap_bound
&& */CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (texture)))
clutter_actor_queue_redraw (CLUTTER_ACTOR (texture));
}
static void
clutter_eglx_texture_pixmap_realize (ClutterActor *actor)
{
CLUTTER_ACTOR_CLASS (clutter_actor_class)->realize (actor);
CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
}
static void
clutter_eglx_texture_pixmap_class_init (ClutterEGLXTexturePixmapClass *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);
parent_class = g_type_class_peek_parent(klass);
clutter_actor_class = g_type_class_peek_parent(parent_class);
object_class->dispose = clutter_eglx_texture_pixmap_dispose;
actor_class->paint = clutter_eglx_texture_pixmap_paint;
actor_class->realize = clutter_eglx_texture_pixmap_realize;
x11_texture_class->update_area = clutter_eglx_texture_pixmap_update_area;
}
/**
* clutter_eglx_texture_pixmap_using_extension:
* @texture: A #ClutterEGLXTexturePixmap
*
* Return value: A boolean indicating if the texture is using the
* EGL_EXT_texture_from_pixmap OpenGL extension or falling back to
* slower software mechanism.
*
* Since: 0.8
**/
gboolean
clutter_eglx_texture_pixmap_using_extension (ClutterEGLXTexturePixmap *texture)
{
return _have_tex_from_pixmap_ext || _have_egl_image_tfp_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)); */
}
/**
* clutter_eglx_texture_pixmap_new_with_pixmap:
* @pixmap: the X Pixmap to which this texture should be bound
*
* Return value: A new #ClutterEGLXTexturePixmap bound to the given X Pixmap
*
* Since: 0.8
**/
ClutterActor*
clutter_eglx_texture_pixmap_new_with_pixmap (Pixmap pixmap)
{
ClutterActor *actor;
actor = g_object_new (CLUTTER_EGLX_TYPE_TEXTURE_PIXMAP,
"pixmap", pixmap,
NULL);
return actor;
}
/**
* clutter_eglx_texture_pixmap_new_with_window:
* @window: the X window to which this texture should be bound
*
* Return value: A new #ClutterEGLXTexturePixmap bound to the given X window
*
* Since: 0.8
**/
ClutterActor*
clutter_eglx_texture_pixmap_new_with_window (Window window)
{
ClutterActor *actor;
actor = g_object_new (CLUTTER_EGLX_TYPE_TEXTURE_PIXMAP,
"window", window,
NULL);
return actor;
}
/**
* clutter_eglx_texture_pixmap_new:
*
* Return value: A new #ClutterEGLXTexturePixmap
*
* Since: 0.8
**/
ClutterActor *
clutter_eglx_texture_pixmap_new (void)
{
ClutterActor *actor;
actor = g_object_new (CLUTTER_EGLX_TYPE_TEXTURE_PIXMAP, NULL);
return actor;
}
#if DEBUG_RED_RECT
static void
clutter_eglx_texture_pixmap_paint_fail (ClutterActor *actor)
{
ClutterGeometry geom;
ClutterColor col_black = {0,0,0,255};
ClutterColor col_red = {255,0,0,255};
guint w,h;
clutter_actor_get_allocation_geometry (actor, &geom);
w = geom.width;
h = geom.height;
col_black.alpha = col_red.alpha = clutter_actor_get_paint_opacity (actor);
/* red border on black rectangle */
cogl_color (&col_black);
cogl_rectangle (10, 10, w-10, h-10);
cogl_color (&col_red);
cogl_rectangle (0, 0, w, 10);
cogl_rectangle (0, h-10, w, 10);
cogl_rectangle (0, 10, 10, h-20);
cogl_rectangle (w-10, 10, 10, h-20);
}
#endif //DEBUG_RED_RECT
void
clutter_eglx_texture_pixmap_paint (ClutterActor *actor)
{
guint pixmap, pixmap_depth, pixmap_width, pixmap_height;
ClutterEGLXTexturePixmapPrivate *priv;
int do_release = 1;
GLuint texture_id;
CoglHandle handle;
priv = CLUTTER_EGLX_TEXTURE_PIXMAP (actor)->priv;
if (priv->pixmap_changed) {
priv->pixmap_changed = FALSE;
g_debug ("%s: Pixmap has changed, rebinding", __FUNCTION__);
clutter_eglx_texture_pixmap_unbind(actor);
clutter_eglx_texture_pixmap_bind(actor);
}
if (priv->use_fallback)
{
CLUTTER_ACTOR_CLASS(clutter_actor_class)->paint(actor);
return;
}
if (!CLUTTER_ACTOR_IS_REALIZED (actor))
{
g_debug ("%s: Not realised, returning", __FUNCTION__);
return;
}
g_object_get (actor,
"pixmap", &pixmap,
"pixmap-depth", &pixmap_depth,
"pixmap-width", &pixmap_width,
"pixmap-height", &pixmap_height,
NULL);
handle = clutter_texture_get_cogl_texture(CLUTTER_TEXTURE(actor));
if (!priv->pixmap_bound ||
handle == COGL_INVALID_HANDLE)
{
/*
guint window;
const gchar *name = clutter_actor_get_name(actor);
g_object_get (actor, "window", &window, NULL);
g_debug ("%s: Buffer not created "
"(name '%s', pixmap %d, window 0x%x, width %d, height %d, depth %d)",
__FUNCTION__,
name ? name : "null",
pixmap, window, pixmap_width, pixmap_height, pixmap_depth);*/
#if DEBUG_RED_RECT
clutter_eglx_texture_pixmap_paint_fail (actor);
#endif //DEBUG_RED_RECT
return;
}
if ((pixmap != priv->current_pixmap ||
pixmap_depth != priv->current_pixmap_depth ||
pixmap_width != priv->current_pixmap_width ||
pixmap_height != priv->current_pixmap_height) &&
priv->pixmap_bound)
{
g_warning ("%s: Pixmap has changed but update not called, returning",
__FUNCTION__);
return;
}
clutter_x11_trap_x_errors ();
XSync (clutter_x11_get_default_display (), FALSE);
if (!handle || !cogl_texture_get_gl_texture (handle, &texture_id, NULL))
return;
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, texture_id);
if (_have_tex_from_pixmap_ext)
{
if (eglBindTexImage (clutter_eglx_display (),
priv->egl_surface,
EGL_BACK_BUFFER) == EGL_FALSE)
{
g_debug ("%s: eglBindTexImage(disp, %x) failed (tex %x): %x",
__FUNCTION__, (unsigned int)priv->egl_surface,
texture_id, eglGetError ());
do_release = 0;
}
}
else /* _have_egl_image_tfp_ext */
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, priv->egl_image);
if (clutter_x11_untrap_x_errors ())
g_debug ("%s: X errors", __FUNCTION__);
CLUTTER_ACTOR_CLASS(clutter_actor_class)->paint(actor);
if (_have_tex_from_pixmap_ext && do_release &&
eglReleaseTexImage (clutter_eglx_display (), priv->egl_surface,
EGL_BACK_BUFFER) == EGL_FALSE)
{
g_debug ("%s: eglReleaseTexImage(disp, %x) failed: %x", __FUNCTION__,
(unsigned int)priv->egl_surface, eglGetError ());
}
}
You can’t perform that action at this time.