|
|
@@ -68,11 +68,17 @@ |
|
|
#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; |
|
|
|
|
|
@@ -83,6 +89,7 @@ struct _ClutterEGLXTexturePixmapPrivate |
|
|
|
|
|
/* If the pixmap has changed, we'll want to try and recreate the surface */ |
|
|
gboolean pixmap_changed; |
|
|
gboolean pixmap_bound; |
|
|
|
|
|
gboolean dispose_called; |
|
|
}; |
|
|
@@ -103,10 +110,10 @@ clutter_eglx_get_eglconfig (EGLDisplay *display, |
|
|
int depth); |
|
|
|
|
|
static void |
|
|
clutter_eglx_texture_pixmap_surface_create (ClutterActor *actor); |
|
|
clutter_eglx_texture_pixmap_bind (ClutterActor *actor); |
|
|
|
|
|
static void |
|
|
clutter_eglx_texture_pixmap_surface_destroy (ClutterActor *actor); |
|
|
clutter_eglx_texture_pixmap_unbind (ClutterActor *actor); |
|
|
|
|
|
static void |
|
|
clutter_eglx_texture_pixmap_freeing_pixmap (ClutterEGLXTexturePixmap *self); |
|
|
@@ -166,6 +173,8 @@ clutter_eglx_texture_pixmap_init (ClutterEGLXTexturePixmap *self) |
|
|
|
|
|
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; |
|
|
@@ -190,11 +199,31 @@ clutter_eglx_texture_pixmap_init (ClutterEGLXTexturePixmap *self) |
|
|
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; |
|
|
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 */ |
|
|
@@ -212,8 +241,8 @@ clutter_eglx_texture_pixmap_dispose (GObject *object) |
|
|
/* this dispose handler is called twice because of how |
|
|
* clutter_actor_destroy works */ |
|
|
|
|
|
if (priv->egl_surface != EGL_NO_SURFACE) |
|
|
clutter_eglx_texture_pixmap_surface_destroy(CLUTTER_ACTOR(object)); |
|
|
if (priv->pixmap_bound) |
|
|
clutter_eglx_texture_pixmap_unbind(CLUTTER_ACTOR(object)); |
|
|
|
|
|
/* Texture deletion is now handled by the CoglTexture */ |
|
|
|
|
|
@@ -251,7 +280,7 @@ create_cogl_texture (ClutterTexture *texture, |
|
|
} |
|
|
|
|
|
static void |
|
|
clutter_eglx_texture_pixmap_surface_create (ClutterActor *actor) |
|
|
clutter_eglx_texture_pixmap_bind (ClutterActor *actor) |
|
|
{ |
|
|
ClutterEGLXTexturePixmapPrivate *priv; |
|
|
Pixmap pixmap; |
|
|
@@ -299,49 +328,83 @@ clutter_eglx_texture_pixmap_surface_create (ClutterActor *actor) |
|
|
CLUTTER_X11_TEXTURE_PIXMAP(actor))) |
|
|
has_alpha = FALSE; |
|
|
|
|
|
if (pixmap) |
|
|
{ |
|
|
EGLConfig conf = clutter_eglx_get_eglconfig ( |
|
|
backend->edpy, &priv->egl_surface, |
|
|
pixmap, has_alpha); |
|
|
print_config_info (conf); |
|
|
} |
|
|
else |
|
|
if (_have_tex_from_pixmap_ext) |
|
|
{ |
|
|
EGLConfig conf; |
|
|
|
|
|
clutter_x11_trap_x_errors (); |
|
|
pixmap = XCompositeNameWindowPixmap (clutter_x11_get_default_display (), |
|
|
window); |
|
|
if (clutter_x11_untrap_x_errors ()) |
|
|
if (pixmap) |
|
|
{ |
|
|
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); |
|
|
} |
|
|
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; |
|
|
|
|
|
if (priv->egl_surface == EGL_NO_SURFACE) |
|
|
CLUTTER_ACTOR_CLASS (clutter_eglx_texture_pixmap_parent_class)-> |
|
|
realize (actor); |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
else /* _have_egl_image_tfp_ext */ |
|
|
{ |
|
|
g_warning ("%s: error %x, failed to create %s surface for %lx, " |
|
|
"using X11 fallback.", |
|
|
__FUNCTION__, eglGetError (), |
|
|
pixmap ? "pixmap" : "window", |
|
|
pixmap ? pixmap : window); |
|
|
const EGLint img_attribs[] = { |
|
|
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, |
|
|
EGL_NONE |
|
|
}; |
|
|
|
|
|
priv->use_fallback = TRUE; |
|
|
priv->egl_image = eglCreateImageKHR(backend->edpy, |
|
|
EGL_NO_CONTEXT, |
|
|
EGL_NATIVE_PIXMAP_KHR, |
|
|
(EGLClientBuffer)pixmap, |
|
|
img_attribs); |
|
|
|
|
|
CLUTTER_ACTOR_CLASS (clutter_eglx_texture_pixmap_parent_class)-> |
|
|
realize (actor); |
|
|
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); |
|
|
|
|
|
return; |
|
|
priv->use_fallback = TRUE; |
|
|
|
|
|
CLUTTER_ACTOR_CLASS (clutter_eglx_texture_pixmap_parent_class)-> |
|
|
realize (actor); |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
/* bind the surface to a GL texture */ |
|
|
/* 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); |
|
|
|
|
|
@@ -363,7 +426,7 @@ clutter_eglx_texture_pixmap_surface_create (ClutterActor *actor) |
|
|
} |
|
|
else |
|
|
{ |
|
|
g_debug ("%s: surface format is EGL_TEXTURE_RGBA", __FUNCTION__); |
|
|
g_debug ("%s: texture format is EGL_TEXTURE_RGBA", __FUNCTION__); |
|
|
format = COGL_PIXEL_FORMAT_RGBA_8888; |
|
|
} |
|
|
|
|
|
@@ -383,7 +446,7 @@ clutter_eglx_texture_pixmap_surface_create (ClutterActor *actor) |
|
|
} |
|
|
|
|
|
static void |
|
|
clutter_eglx_texture_pixmap_surface_destroy (ClutterActor *actor) |
|
|
clutter_eglx_texture_pixmap_unbind (ClutterActor *actor) |
|
|
{ |
|
|
ClutterEGLXTexturePixmapPrivate *priv; |
|
|
ClutterBackendEGL *backend; |
|
|
@@ -406,6 +469,13 @@ clutter_eglx_texture_pixmap_surface_destroy (ClutterActor *actor) |
|
|
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 */ |
|
|
@@ -417,8 +487,8 @@ static void clutter_eglx_texture_pixmap_freeing_pixmap (ClutterEGLXTexturePixmap |
|
|
/** 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->egl_surface != EGL_NO_SURFACE) |
|
|
clutter_eglx_texture_pixmap_surface_destroy(CLUTTER_ACTOR(self)); |
|
|
if (priv->pixmap_bound) |
|
|
clutter_eglx_texture_pixmap_unbind(CLUTTER_ACTOR(self)); |
|
|
} |
|
|
|
|
|
static const EGLint pixmap_creation_config_rgb[] = { |
|
|
@@ -529,12 +599,12 @@ clutter_eglx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, |
|
|
pixmap_depth != priv->current_pixmap_depth || |
|
|
pixmap_width != priv->current_pixmap_width || |
|
|
pixmap_height != priv->current_pixmap_height || |
|
|
priv->egl_surface == EGL_NO_SURFACE) |
|
|
!priv->pixmap_bound) |
|
|
{ |
|
|
priv->pixmap_changed = TRUE; |
|
|
} |
|
|
|
|
|
if (/*priv->egl_surface != EGL_NO_SURFACE |
|
|
if (/*priv->pixmap_bound |
|
|
&& */CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (texture))) |
|
|
clutter_actor_queue_redraw (CLUTTER_ACTOR (texture)); |
|
|
} |
|
|
@@ -580,7 +650,7 @@ clutter_eglx_texture_pixmap_class_init (ClutterEGLXTexturePixmapClass *klass) |
|
|
gboolean |
|
|
clutter_eglx_texture_pixmap_using_extension (ClutterEGLXTexturePixmap *texture) |
|
|
{ |
|
|
return _have_tex_from_pixmap_ext; |
|
|
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 ? |
|
|
*/ |
|
|
@@ -683,9 +753,9 @@ clutter_eglx_texture_pixmap_paint (ClutterActor *actor) |
|
|
|
|
|
if (priv->pixmap_changed) { |
|
|
priv->pixmap_changed = FALSE; |
|
|
g_debug ("%s: Pixmap has changed, destroying surface", __FUNCTION__); |
|
|
clutter_eglx_texture_pixmap_surface_destroy(actor); |
|
|
clutter_eglx_texture_pixmap_surface_create(actor); |
|
|
g_debug ("%s: Pixmap has changed, rebinding", __FUNCTION__); |
|
|
clutter_eglx_texture_pixmap_unbind(actor); |
|
|
clutter_eglx_texture_pixmap_bind(actor); |
|
|
} |
|
|
|
|
|
if (priv->use_fallback) |
|
|
@@ -709,7 +779,7 @@ clutter_eglx_texture_pixmap_paint (ClutterActor *actor) |
|
|
|
|
|
handle = clutter_texture_get_cogl_texture(CLUTTER_TEXTURE(actor)); |
|
|
|
|
|
if (priv->egl_surface == EGL_NO_SURFACE || |
|
|
if (!priv->pixmap_bound || |
|
|
handle == COGL_INVALID_HANDLE) |
|
|
{ |
|
|
/* |
|
|
@@ -732,7 +802,7 @@ clutter_eglx_texture_pixmap_paint (ClutterActor *actor) |
|
|
pixmap_depth != priv->current_pixmap_depth || |
|
|
pixmap_width != priv->current_pixmap_width || |
|
|
pixmap_height != priv->current_pixmap_height) && |
|
|
priv->egl_surface != EGL_NO_SURFACE) |
|
|
priv->pixmap_bound) |
|
|
{ |
|
|
g_warning ("%s: Pixmap has changed but update not called, returning", |
|
|
__FUNCTION__); |
|
|
@@ -748,22 +818,27 @@ clutter_eglx_texture_pixmap_paint (ClutterActor *actor) |
|
|
glEnable (GL_TEXTURE_2D); |
|
|
glBindTexture (GL_TEXTURE_2D, texture_id); |
|
|
|
|
|
if (eglBindTexImage (clutter_eglx_display (), |
|
|
priv->egl_surface, |
|
|
EGL_BACK_BUFFER) == EGL_FALSE) |
|
|
if (_have_tex_from_pixmap_ext) |
|
|
{ |
|
|
g_debug ("%s: eglBindTexImage(disp, %x) failed (tex %x): %x", |
|
|
__FUNCTION__, (unsigned int)priv->egl_surface, |
|
|
texture_id, eglGetError ()); |
|
|
do_release = 0; |
|
|
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 (do_release && |
|
|
if (_have_tex_from_pixmap_ext && do_release && |
|
|
eglReleaseTexImage (clutter_eglx_display (), priv->egl_surface, |
|
|
EGL_BACK_BUFFER) == EGL_FALSE) |
|
|
{ |
|
|
|