2008-04-29 Matthew Allum <mallum@openedhand.com>

* clutter/glx/Makefile.am:
        * clutter/glx/clutter-glx-texture-pixmap.c:
        * clutter/glx/clutter-glx-texture-pixmap.h:
        * clutter/x11/Makefile.am:
        * clutter/x11/clutter-x11-texture-pixmap.c:
        * tests/test-pixmap.c:
        Commit newer x11 texture pixmap stuff (optionally using SHM).
        Also seemingly still broken overhauled glx-texture-pixmap
        (code by Robert and myself)

* configure.ac:
        Minor formatting change.
This commit is contained in:
Matthew Allum 2008-04-29 16:30:47 +00:00
parent 19058afe82
commit ca3074f772
8 changed files with 453 additions and 308 deletions

View File

@ -1,3 +1,18 @@
2008-04-29 Matthew Allum <mallum@openedhand.com>
* clutter/glx/Makefile.am:
* clutter/glx/clutter-glx-texture-pixmap.c:
* clutter/glx/clutter-glx-texture-pixmap.h:
* clutter/x11/Makefile.am:
* clutter/x11/clutter-x11-texture-pixmap.c:
* tests/test-pixmap.c:
Commit newer x11 texture pixmap stuff (optionally using SHM).
Also seemingly still broken overhauled glx-texture-pixmap
(code by Robert and myself)
* configure.ac:
Minor formatting change.
2008-04-29 Neil Roberts <neil@o-hand.com> 2008-04-29 Neil Roberts <neil@o-hand.com>
Removed COGLhandle and changed shader and program functions to be Removed COGLhandle and changed shader and program functions to be

View File

@ -1,10 +1,11 @@
libclutterincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter libclutter_glx_includedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter/glx
libclutterinclude_HEADERS = clutter-glx.h clutter-glx-texture-pixmap.h libclutter_glx_include_HEADERS = clutter-glx.h clutter-glx-texture-pixmap.h
INCLUDES = \ INCLUDES = \
-DG_LOG_DOMAIN=\"ClutterGLX\" \ -DG_LOG_DOMAIN=\"ClutterGLX\" \
-I$(top_srcdir) \ -I$(top_srcdir) \
-I$(top_srcdir)/clutter \ -I$(top_srcdir)/clutter \
-I$(top_srcdir)/clutter/x11 \
-I$(top_builddir)/clutter \ -I$(top_builddir)/clutter \
$(CLUTTER_CFLAGS) \ $(CLUTTER_CFLAGS) \
$(CLUTTER_DEBUG_CFLAGS) \ $(CLUTTER_DEBUG_CFLAGS) \

View File

@ -4,6 +4,8 @@
* An OpenGL based 'interactive canvas' library. * An OpenGL based 'interactive canvas' library.
* *
* Authored By Johan Bilien <johan.bilien@nokia.com> * Authored By Johan Bilien <johan.bilien@nokia.com>
* Matthew Allum <mallum@o-hand.com>
* Robert Bragg <bob@o-hand.com>
* *
* Copyright (C) 2007 OpenedHand * Copyright (C) 2007 OpenedHand
* *
@ -70,28 +72,6 @@ struct _ClutterGLXTexturePixmapPrivate
}; };
static void
clutter_glx_texture_pixmap_class_init (ClutterGLXTexturePixmapClass *klass);
static void
clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self);
static void
clutter_glx_texture_pixmap_dispose (GObject *object);
static void
clutter_glx_texture_pixmap_notify (GObject *object,
GParamSpec *pspec);
static void
clutter_glx_texture_pixmap_realize (ClutterActor *actor);
static void
clutter_glx_texture_pixmap_unrealize (ClutterActor *actor);
static void
clutter_glx_texture_pixmap_paint (ClutterActor *actor);
static void static void
clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture,
gint x, gint x,
@ -102,51 +82,29 @@ clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture,
static void static void
clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *tex); clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *tex);
static ClutterX11TexturePixmapClass *parent_class = NULL;
G_DEFINE_TYPE (ClutterGLXTexturePixmap, \ G_DEFINE_TYPE (ClutterGLXTexturePixmap, \
clutter_glx_texture_pixmap, \ clutter_glx_texture_pixmap, \
CLUTTER_X11_TYPE_TEXTURE_PIXMAP); CLUTTER_X11_TYPE_TEXTURE_PIXMAP);
static void static gboolean
clutter_glx_texture_pixmap_class_init (ClutterGLXTexturePixmapClass *klass) texture_bind (ClutterGLXTexturePixmap *tex)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (klass); GLuint handle = 0;
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); GLenum target = 0;
ClutterX11TexturePixmapClass *x11_texture_class = CoglHandle cogl_tex;
CLUTTER_X11_TEXTURE_PIXMAP_CLASS (klass); cogl_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE(tex));
g_type_class_add_private (klass, sizeof (ClutterGLXTexturePixmapPrivate)); if (!cogl_texture_get_gl_texture (cogl_tex, &handle, &target))
return FALSE;
object_class->dispose = clutter_glx_texture_pixmap_dispose; glEnable(target);
object_class->notify = clutter_glx_texture_pixmap_notify;
actor_class->realize = clutter_glx_texture_pixmap_realize; /* FIXME: fire off an error here? */
actor_class->unrealize = clutter_glx_texture_pixmap_unrealize; glBindTexture (target, handle);
actor_class->paint = clutter_glx_texture_pixmap_paint;
x11_texture_class->update_area = clutter_glx_texture_pixmap_update_area; return TRUE;
if (_ext_check_done == FALSE)
{
const gchar *glx_extensions = NULL;
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;
}
_ext_check_done = TRUE;
}
} }
static void static void
@ -159,11 +117,6 @@ clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self)
CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, CLUTTER_GLX_TYPE_TEXTURE_PIXMAP,
ClutterGLXTexturePixmapPrivate); ClutterGLXTexturePixmapPrivate);
/* FIXME: Obsolete. Move to new cogl api.
if (clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE))
priv->target_type = CGL_TEXTURE_RECTANGLE_ARB;
else
priv->target_type = CGL_TEXTURE_2D; */
} }
static void static void
@ -195,55 +148,75 @@ clutter_glx_texture_pixmap_notify (GObject *object, GParamSpec *pspec)
if (g_str_equal (pspec->name, "pixmap")) if (g_str_equal (pspec->name, "pixmap"))
{ {
ClutterGLXTexturePixmap *texture = CLUTTER_GLX_TEXTURE_PIXMAP (object); ClutterGLXTexturePixmap *texture = CLUTTER_GLX_TEXTURE_PIXMAP (object);
printf("notify\n");
clutter_glx_texture_pixmap_create_glx_pixmap (texture); clutter_glx_texture_pixmap_create_glx_pixmap (texture);
} }
} }
static void
create_cogl_texture (ClutterTexture *texture,
guint width,
guint height)
{
CoglHandle handle;
handle = cogl_texture_new_with_size (width, height,
64,
COGL_PIXEL_FORMAT_RGBA_8888|COGL_BGR_BIT);
printf("handle: %i, width: %i, height: %i\n",
(int)handle, width, height);
if (handle)
{
clutter_texture_set_cogl_texture (texture, handle);
CLUTTER_ACTOR_SET_FLAGS (texture, CLUTTER_ACTOR_REALIZED);
printf("realised, updating\n");
clutter_glx_texture_pixmap_update_area
(CLUTTER_X11_TEXTURE_PIXMAP (texture),
0, 0,
width, height);
}
else
g_warning ("unable to realize");
}
static void static void
clutter_glx_texture_pixmap_realize (ClutterActor *actor) clutter_glx_texture_pixmap_realize (ClutterActor *actor)
{ {
ClutterGLXTexturePixmapPrivate *priv; ClutterGLXTexturePixmapPrivate *priv;
COGLenum pixel_type, pixel_format,filter_quality; Pixmap pixmap;
gboolean repeat_x, repeat_y; guint pixmap_width, pixmap_height;
guint width, height; printf("realise\n");
priv = CLUTTER_GLX_TEXTURE_PIXMAP (actor)->priv; priv = CLUTTER_GLX_TEXTURE_PIXMAP (actor)->priv;
if (!_have_tex_from_pixmap_ext) if (!_have_tex_from_pixmap_ext
|| !clutter_feature_available (CLUTTER_FEATURE_TEXTURE_RECTANGLE))
{ {
/* Fall back */
/* FIXME: Also check for sliced npots ? */
g_warning("Falling back....");
CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)-> CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)->
realize (actor); realize (actor);
return; return;
} }
g_object_get (actor, g_object_get (actor,
"pixel-type", &pixel_type, "pixmap", &pixmap,
"pixel-format", &pixel_format, "pixmap-width", &pixmap_width,
"repeat-x", &repeat_x, "pixmap-height", &pixmap_height,
"repeat-y", &repeat_y,
"filter-quality", &filter_quality,
"pixmap-width", &width,
"pixmap-height", &height,
NULL); NULL);
/* FIXME: Obsolete. Move to new cogl api if (!pixmap)
cogl_textures_create (1, &priv->texture_id); return;
*/
clutter_glx_texture_pixmap_update_area (CLUTTER_X11_TEXTURE_PIXMAP (actor),
0, 0,
width, height);
/*
cogl_texture_set_alignment (priv->target_type, 4, width);
cogl_texture_set_filters (priv->target_type, create_cogl_texture (CLUTTER_TEXTURE (actor), pixmap_width, pixmap_height);
filter_quality ? CGL_LINEAR : CGL_NEAREST,
filter_quality ? CGL_LINEAR : CGL_NEAREST);
cogl_texture_set_wrap (priv->target_type,
repeat_x ? CGL_REPEAT : CGL_CLAMP_TO_EDGE,
repeat_y ? CGL_REPEAT : CGL_CLAMP_TO_EDGE);
*/
CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
} }
static void static void
@ -252,6 +225,8 @@ clutter_glx_texture_pixmap_unrealize (ClutterActor *actor)
ClutterGLXTexturePixmapPrivate *priv; ClutterGLXTexturePixmapPrivate *priv;
Display *dpy; Display *dpy;
printf("unrealise\n");
priv = CLUTTER_GLX_TEXTURE_PIXMAP (actor)->priv; priv = CLUTTER_GLX_TEXTURE_PIXMAP (actor)->priv;
dpy = clutter_x11_get_default_display(); dpy = clutter_x11_get_default_display();
@ -277,104 +252,9 @@ clutter_glx_texture_pixmap_unrealize (ClutterActor *actor)
clutter_x11_untrap_x_errors (); clutter_x11_untrap_x_errors ();
} }
/* FIXME: Obsolete. Move to new cogl api.
cogl_textures_destroy (1, &priv->texture_id);
*/
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
} }
static void
texture_render_to_gl_quad (ClutterGLXTexturePixmap *texture,
int x_1,
int y_1,
int x_2,
int y_2)
{
/* FIXME: Obsolete. Move to new cogl api
ClutterGLXTexturePixmapPrivate *priv = texture->priv;
int qx1 = 0, qx2 = 0, qy1 = 0, qy2 = 0;
int qwidth = 0, qheight = 0;
float tx, ty;
guint width, height;
g_object_get (texture,
"pixmap-width", &width,
"pixmap-height", &height,
NULL);
qwidth = x_2 - x_1;
qheight = y_2 - y_1;
cogl_texture_bind (priv->target_type, priv->texture_id);
if (priv->target_type == CGL_TEXTURE_2D)
{
tx = (float) width / clutter_util_next_p2 (width);
ty = (float) height / clutter_util_next_p2 (height);
}
else
{
tx = (float) width;
ty = (float) height;
}
qx1 = x_1; qx2 = x_2;
qy1 = y_1; qy2 = y_2;
cogl_texture_quad (x_1, x_2, y_1, y_2,
0,
0,
CLUTTER_FLOAT_TO_FIXED (tx),
CLUTTER_FLOAT_TO_FIXED (ty)); */
}
static void
clutter_glx_texture_pixmap_paint (ClutterActor *actor)
{
ClutterGLXTexturePixmap *texture = CLUTTER_GLX_TEXTURE_PIXMAP (actor);
ClutterGLXTexturePixmapPrivate *priv = texture->priv;
gint x_1, y_1, x_2, y_2;
ClutterColor col = { 0xff, 0xff, 0xff, 0xff };
if (!_have_tex_from_pixmap_ext)
{
CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)->
paint (actor);
return;
}
if (!CLUTTER_ACTOR_IS_REALIZED (actor))
clutter_actor_realize (actor);
cogl_push_matrix ();
/* FIXME: Obsolete. Move to new cogl api.
switch (priv->target_type)
{
case CGL_TEXTURE_2D:
cogl_enable (CGL_ENABLE_TEXTURE_2D|CGL_ENABLE_BLEND);
break;
case CGL_TEXTURE_RECTANGLE_ARB:
cogl_enable (CGL_ENABLE_TEXTURE_RECT|CGL_ENABLE_BLEND);
break;
default:
break;
} */
col.alpha = clutter_actor_get_opacity (actor);
cogl_color (&col);
clutter_actor_get_coords (actor, &x_1, &y_1, &x_2, &y_2);
texture_render_to_gl_quad (texture, 0, 0, x_2 - x_1, y_2 - y_1);
cogl_pop_matrix ();
}
static GLXFBConfig * static GLXFBConfig *
get_fbconfig_for_depth (guint depth) get_fbconfig_for_depth (guint depth)
{ {
@ -482,6 +362,41 @@ get_fbconfig_for_depth (guint depth)
return ret; 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 ();
if (_have_tex_from_pixmap_ext &&
CLUTTER_ACTOR_IS_REALIZED (texture) &&
priv->bound)
{
texture_bind (texture);
clutter_x11_trap_x_errors ();
(_gl_release_tex_image) (dpy,
priv->glx_pixmap,
GLX_FRONT_LEFT_EXT);
XSync (clutter_x11_get_default_display(), FALSE);
if (clutter_x11_untrap_x_errors ())
g_warning ("Failed to unbind texture pixmap");
printf("Destroyed pxm: %li\n", priv->glx_pixmap);
}
clutter_x11_trap_x_errors ();
glXDestroyGLXPixmap (dpy, priv->glx_pixmap);
XSync (dpy, FALSE);
clutter_x11_untrap_x_errors ();
}
static void static void
clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture) clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture)
{ {
@ -492,16 +407,23 @@ clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture)
Display *dpy; Display *dpy;
guint depth; guint depth;
Pixmap pixmap; Pixmap pixmap;
guint pixmap_width, pixmap_height;
ClutterBackendGLX *backend_glx; ClutterBackendGLX *backend_glx;
printf("create\n");
backend_glx = CLUTTER_BACKEND_GLX(clutter_get_default_backend ()); backend_glx = CLUTTER_BACKEND_GLX(clutter_get_default_backend ());
dpy = clutter_x11_get_default_display (); dpy = clutter_x11_get_default_display ();
g_object_get (texture, g_object_get (texture,
"pixmap-width", &pixmap_width,
"pixmap-height", &pixmap_height,
"pixmap-depth", &depth, "pixmap-depth", &depth,
"pixmap", &pixmap, "pixmap", &pixmap,
NULL); NULL);
if (!pixmap)
return;
fbconfig = get_fbconfig_for_depth (depth); fbconfig = get_fbconfig_for_depth (depth);
@ -516,10 +438,12 @@ clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture)
if (depth == 24) if (depth == 24)
{ {
attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT; attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT;
printf("depth: %i\n", 24);
} }
else if (depth == 32) else if (depth == 32)
{ {
attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT; attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
printf("depth: %i\n", 32);
} }
else else
{ {
@ -531,58 +455,38 @@ clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture)
attribs[i++] = 0; attribs[i++] = 0;
attribs[i++] = GLX_TEXTURE_TARGET_EXT; attribs[i++] = GLX_TEXTURE_TARGET_EXT;
/* FIXME: Obsolete. Move to new cogl api
if (priv->target_type == CGL_TEXTURE_RECTANGLE_ARB)
attribs[i++] = GLX_TEXTURE_RECTANGLE_EXT; attribs[i++] = GLX_TEXTURE_RECTANGLE_EXT;
else
attribs[i++] = GLX_TEXTURE_2D_EXT; */
attribs[i++] = None; attribs[i++] = None;
clutter_x11_trap_x_errors (); clutter_x11_trap_x_errors ();
glx_pixmap = glXCreatePixmap (dpy, glx_pixmap = glXCreatePixmap (dpy,
*fbconfig, *fbconfig,
pixmap, pixmap,
attribs); attribs);
XSync (dpy, FALSE); XSync (dpy, FALSE);
clutter_x11_untrap_x_errors (); if (clutter_x11_untrap_x_errors ())
g_warning ("glx pixmap creation failed");
g_free (fbconfig); g_free (fbconfig);
if (glx_pixmap != None) if (glx_pixmap != None)
{ {
if (priv->glx_pixmap) if (priv->glx_pixmap)
{ clutter_glx_texture_pixmap_free_glx_pixmap (texture);
if (_have_tex_from_pixmap_ext &&
CLUTTER_ACTOR_IS_REALIZED (texture) &&
priv->bound)
{
/*
cogl_texture_bind (priv->target_type, priv->texture_id); */
clutter_x11_trap_x_errors ();
(_gl_release_tex_image) (dpy,
priv->glx_pixmap,
GLX_FRONT_LEFT_EXT);
XSync (clutter_x11_get_default_display(), FALSE);
if (clutter_x11_untrap_x_errors ())
g_warning ("Failed to bind texture pixmap");
}
clutter_x11_trap_x_errors ();
glXDestroyGLXPixmap (dpy, priv->glx_pixmap);
XSync (dpy, FALSE);
clutter_x11_untrap_x_errors ();
}
priv->glx_pixmap = glx_pixmap; priv->glx_pixmap = glx_pixmap;
if (!clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (texture)))
{
create_cogl_texture (texture,
pixmap_width,
pixmap_height);
} }
}
printf("Created pxm: %li\n", priv->glx_pixmap);
} }
static void static void
@ -595,26 +499,41 @@ clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture,
ClutterGLXTexturePixmapPrivate *priv; ClutterGLXTexturePixmapPrivate *priv;
Display *dpy; Display *dpy;
printf("update area\n");
priv = CLUTTER_GLX_TEXTURE_PIXMAP (texture)->priv; priv = CLUTTER_GLX_TEXTURE_PIXMAP (texture)->priv;
dpy = clutter_x11_get_default_display(); dpy = clutter_x11_get_default_display();
if (!_have_tex_from_pixmap_ext)
{
CLUTTER_X11_TEXTURE_PIXMAP_CLASS
(texture)->update_area (texture,
x, y,
width, height);
return;
}
if (!CLUTTER_ACTOR_IS_REALIZED (texture)) if (!CLUTTER_ACTOR_IS_REALIZED (texture))
return; return;
/* FIXME: Obsolete. if (!_have_tex_from_pixmap_ext)
cogl_texture_bind (priv->target_type, priv->texture_id); */ {
parent_class->update_area (texture,
x, y,
width, height);
return;
}
}
static void
clutter_glx_texture_pixmap_paint (ClutterActor *self)
{
ClutterGLXTexturePixmapPrivate *priv;
priv = CLUTTER_GLX_TEXTURE_PIXMAP (self)->priv;
if (_have_tex_from_pixmap_ext) if (_have_tex_from_pixmap_ext)
{ {
Display *dpy;
dpy = clutter_x11_get_default_display();
if (texture_bind (CLUTTER_GLX_TEXTURE_PIXMAP(self)))
{
printf("no fallback pxm: %li\n", priv->glx_pixmap);
clutter_x11_trap_x_errors (); clutter_x11_trap_x_errors ();
(_gl_bind_tex_image) (dpy, (_gl_bind_tex_image) (dpy,
@ -629,8 +548,61 @@ clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture,
priv->bound = TRUE; priv->bound = TRUE;
} }
else
g_warning ("Failed to bind initial tex");
}
CLUTTER_ACTOR_CLASS (clutter_glx_texture_pixmap_parent_class)->paint(self);
} }
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;
actor_class->paint = clutter_glx_texture_pixmap_paint;
x11_texture_class->update_area = clutter_glx_texture_pixmap_update_area;
if (_ext_check_done == FALSE)
{
const gchar *glx_extensions = NULL;
glx_extensions =
glXQueryExtensionsString (clutter_x11_get_default_display (),
clutter_x11_get_default_screen ());
printf("GLX extension string:%s\n", glx_extensions);
/* 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;
}
_ext_check_done = TRUE;
}
}
/** /**
* clutter_glx_texture_pixmap_new_with_pixmap: * clutter_glx_texture_pixmap_new_with_pixmap:
* @pixmap: the X Pixmap to which this texture should be bound * @pixmap: the X Pixmap to which this texture should be bound

View File

@ -28,6 +28,7 @@
#include <glib.h> #include <glib.h>
#include <glib-object.h> #include <glib-object.h>
#include <clutter/x11/clutter-x11-texture-pixmap.h>
#include <GL/glx.h> #include <GL/glx.h>

View File

@ -1,5 +1,5 @@
libclutterincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter libclutter_x11_includedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter/x11
libclutterinclude_HEADERS = clutter-x11.h \ libclutter_x11_include_HEADERS = clutter-x11.h \
clutter-x11-texture-pixmap.h clutter-x11-texture-pixmap.h
clutter-x11-$(CLUTTER_API_VERSION).pc: clutter-x11.pc clutter-x11-$(CLUTTER_API_VERSION).pc: clutter-x11.pc

View File

@ -51,6 +51,11 @@
#include <X11/extensions/Xdamage.h> #include <X11/extensions/Xdamage.h>
#include <X11/extensions/Xcomposite.h> #include <X11/extensions/Xcomposite.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <X11/extensions/XShm.h>
enum enum
{ {
PROP_PIXMAP = 1, PROP_PIXMAP = 1,
@ -86,10 +91,12 @@ struct _ClutterX11TexturePixmapPrivate
guint depth; guint depth;
XImage *image; XImage *image;
XShmSegmentInfo shminfo;
gboolean automatic_updates; gboolean automatic_updates;
Damage damage; Damage damage;
gboolean have_shm;
}; };
static int _damage_event_base = 0; static int _damage_event_base = 0;
@ -130,6 +137,108 @@ check_extensions (ClutterX11TexturePixmap *texture)
return TRUE; return TRUE;
} }
static void
free_shm_resources (ClutterX11TexturePixmap *texture)
{
ClutterX11TexturePixmapPrivate *priv;
priv = texture->priv;
if (priv->shminfo.shmid != -1)
{
XShmDetach(clutter_x11_get_default_display(),
&priv->shminfo);
shmdt(priv->shminfo.shmaddr);
shmctl(priv->shminfo.shmid, IPC_RMID, 0);
priv->shminfo.shmid = -1;
}
}
/* Tries to allocate enough shared mem to handle a full size
* update size of the X Pixmap. */
static gboolean
try_alloc_shm (ClutterX11TexturePixmap *texture)
{
ClutterX11TexturePixmapPrivate *priv;
XImage *dummy_image;
Display *dpy;
priv = texture->priv;
dpy = clutter_x11_get_default_display();
g_return_val_if_fail (priv->pixmap, FALSE);
if (!XShmQueryExtension(dpy) || g_getenv("CLUTTER_X11_NO_SHM"))
{
priv->have_shm = FALSE;
return FALSE;
}
clutter_x11_trap_x_errors ();
/* We are creating a dummy_image so we can have Xlib calculate
* image->bytes_per_line - including any magic padding it may
* want - for the largest possible ximage we might need to use
* when handling updates to the texture.
*
* Note: we pass a NULL shminfo here, but that has no bearing
* on the setup of the XImage, except that ximage->obdata will
* == NULL.
*/
dummy_image =
XShmCreateImage(dpy,
DefaultVisual(dpy,
clutter_x11_get_default_screen()),
priv->depth,
ZPixmap,
NULL,
NULL, /* shminfo, */
priv->pixmap_width,
priv->pixmap_height);
if (!dummy_image)
goto failed_image_create;
priv->shminfo.shmid = shmget (IPC_PRIVATE,
dummy_image->bytes_per_line
* dummy_image->height,
IPC_CREAT|0777);
if (priv->shminfo.shmid == -1)
goto failed_shmget;
priv->shminfo.shmaddr =
shmat (priv->shminfo.shmid, 0, 0);
if (priv->shminfo.shmaddr == (void *)-1)
goto failed_shmat;
priv->shminfo.readOnly = False;
if (XShmAttach(dpy, &priv->shminfo) == 0)
goto failed_xshmattach;
if (clutter_x11_untrap_x_errors ())
g_warning ("X Error: Failed to setup XShm.");
priv->have_shm = TRUE;
return TRUE;
failed_xshmattach:
g_warning ("XShmAttach failed");
shmdt(priv->shminfo.shmaddr);
failed_shmat:
g_warning ("shmat failed");
shmctl(priv->shminfo.shmid, IPC_RMID, 0);
failed_shmget:
g_warning ("shmget failed");
XDestroyImage(dummy_image);
failed_image_create:
if (clutter_x11_untrap_x_errors ())
g_warning ("X Error: Failed to setup XShm.");
priv->have_shm = FALSE;
return FALSE;
}
static ClutterX11FilterReturn static ClutterX11FilterReturn
on_x_event_filter (XEvent *xev, ClutterEvent *cev, gpointer data) on_x_event_filter (XEvent *xev, ClutterEvent *cev, gpointer data)
{ {
@ -223,21 +332,12 @@ clutter_x11_texture_pixmap_init (ClutterX11TexturePixmap *self)
* - a _can_autoupdate() method ? * - a _can_autoupdate() method ?
*/ */
} }
}
static GObject * self->priv->image = NULL;
clutter_x11_texture_pixmap_constructor (GType type, self->priv->automatic_updates = FALSE;
guint n_props, self->priv->damage = None;
GObjectConstructParam *props) self->priv->pixmap = None;
{ self->priv->shminfo.shmid = -1;
GObject *object = G_OBJECT_CLASS (clutter_x11_texture_pixmap_parent_class)->
constructor (type, n_props, props);
g_object_set (object,
"sync-size", FALSE,
NULL);
return object;
} }
static void static void
@ -254,6 +354,8 @@ clutter_x11_texture_pixmap_dispose (GObject *object)
priv->image = NULL; priv->image = NULL;
} }
free_shm_resources (texture);
G_OBJECT_CLASS (clutter_x11_texture_pixmap_parent_class)->dispose (object); G_OBJECT_CLASS (clutter_x11_texture_pixmap_parent_class)->dispose (object);
} }
@ -340,7 +442,6 @@ clutter_x11_texture_pixmap_class_init (ClutterX11TexturePixmapClass *klass)
g_type_class_add_private (klass, sizeof (ClutterX11TexturePixmapPrivate)); g_type_class_add_private (klass, sizeof (ClutterX11TexturePixmapPrivate));
object_class->constructor = clutter_x11_texture_pixmap_constructor;
object_class->dispose = clutter_x11_texture_pixmap_dispose; object_class->dispose = clutter_x11_texture_pixmap_dispose;
object_class->set_property = clutter_x11_texture_pixmap_set_property; object_class->set_property = clutter_x11_texture_pixmap_set_property;
object_class->get_property = clutter_x11_texture_pixmap_get_property; object_class->get_property = clutter_x11_texture_pixmap_get_property;
@ -441,10 +542,10 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture,
ClutterX11TexturePixmapPrivate *priv; ClutterX11TexturePixmapPrivate *priv;
Display *dpy; Display *dpy;
XImage *image; XImage *image;
guint *pixel, *l; char *first_pixel;
GError *error = NULL; GError *error = NULL;
guint bytes_per_line; guint bytes_per_line;
guint8 *data; char *data;
gboolean data_allocated = FALSE; gboolean data_allocated = FALSE;
int err_code; int err_code;
@ -459,15 +560,38 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture,
clutter_x11_trap_x_errors (); clutter_x11_trap_x_errors ();
/* FIXME: Use XSHM here! */ if (priv->have_shm)
{
image =
XShmCreateImage(dpy,
DefaultVisual(dpy,
clutter_x11_get_default_screen()),
priv->depth,
ZPixmap,
NULL,
&priv->shminfo,
width,
height);
image->data = priv->shminfo.shmaddr;
XShmGetImage (dpy, priv->pixmap, image, x, y, AllPlanes);
first_pixel = image->data;
}
else
{
if (!priv->image) if (!priv->image)
{
priv->image = XGetImage (dpy, priv->image = XGetImage (dpy,
priv->pixmap, priv->pixmap,
0, 0, 0, 0,
priv->pixmap_width, priv->pixmap_height, priv->pixmap_width, priv->pixmap_height,
AllPlanes, AllPlanes,
ZPixmap); ZPixmap);
first_pixel = priv->image->data + priv->image->bytes_per_line * y
+ x * priv->image->bits_per_pixel/8;
}
else else
{
XGetSubImage (dpy, XGetSubImage (dpy,
priv->pixmap, priv->pixmap,
x, y, x, y,
@ -476,6 +600,11 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture,
ZPixmap, ZPixmap,
priv->image, priv->image,
x, y); x, y);
first_pixel = priv->image->data + priv->image->bytes_per_line * y
+ x * priv->image->bits_per_pixel/8;
}
image = priv->image;
}
XSync (dpy, FALSE); XSync (dpy, FALSE);
@ -488,53 +617,47 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture,
return; return;
} }
image = priv->image;
if (priv->depth == 24) if (priv->depth == 24)
{ {
guint *first_line = (guint *)image->data + y * image->bytes_per_line / 4; guint xpos, ypos;
for (l = first_line; for (ypos=0; ypos<height; ypos++)
l != (first_line + height * image->bytes_per_line / 4); for (xpos=0; xpos<width; xpos++)
l = l + image->bytes_per_line / 4)
{ {
for (pixel = l + x; pixel != l + x + width; pixel ++) char *p = first_pixel + image->bytes_per_line*ypos
{ + xpos * 4;
((guint8 *)pixel)[3] = 0xFF; p[3] = 0xFF;
}
} }
data = (guint8 *)first_line + x * 4; data = first_pixel;
bytes_per_line = image->bytes_per_line; bytes_per_line = image->bytes_per_line;
} }
else if (priv->depth == 16) else if (priv->depth == 16)
{ {
guint16 *p, *lp; guint xpos, ypos;
data = g_malloc (height * width * 4); data = g_malloc (height * width * 4);
data_allocated = TRUE; data_allocated = TRUE;
bytes_per_line = priv->pixmap_width * 4; bytes_per_line = width * 4;
for (l = (guint *)data, for (ypos=0; ypos<height; ypos++)
lp = (guint16 *)image->data + y * image->bytes_per_line / 2; for (xpos=0; xpos<width; xpos++)
l != ((guint *)data + height * width);
l = l + width, lp = lp + image->bytes_per_line / 2)
{ {
for (pixel = l, p = lp + x; pixel != l + width; pixel ++, p++) char *src_p = first_pixel + image->bytes_per_line * ypos
{ + xpos * 2;
*pixel = 0xFF000000 | guint16 *src_pixel = (guint16 *)src_p;
(guint)((*p) & 0xf800) << 8 | char *dst_p = data + bytes_per_line * ypos + xpos * 4;
(guint)((*p) & 0x07e0) << 5 | guint32 *dst_pixel = (guint32 *)dst_p;
(guint)((*p) & 0x001f) << 3;
}
}
*dst_pixel =
((((*src_pixel << 3) & 0xf8) | ((*src_pixel >> 2) & 0x7)) | \
(((*src_pixel << 5) & 0xfc00) | ((*src_pixel >> 1) & 0x300)) | \
(((*src_pixel << 8) & 0xf80000) | ((*src_pixel << 3) & 0x70000)));
}
} }
else if (priv->depth == 32) else if (priv->depth == 32)
{ {
bytes_per_line = image->bytes_per_line; bytes_per_line = image->bytes_per_line;
data = (guint8 *)image->data + y * bytes_per_line + x * 4; data = first_pixel;
} }
else else
return; return;
@ -542,7 +665,7 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture,
if (x != 0 || y != 0 || if (x != 0 || y != 0 ||
width != priv->pixmap_width || height != priv->pixmap_height) width != priv->pixmap_width || height != priv->pixmap_height)
clutter_texture_set_area_from_rgb_data (CLUTTER_TEXTURE (texture), clutter_texture_set_area_from_rgb_data (CLUTTER_TEXTURE (texture),
data, (guint8 *)data,
TRUE, TRUE,
x, y, x, y,
width, height, width, height,
@ -552,7 +675,7 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture,
&error); &error);
else else
clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (texture), clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (texture),
data, (guint8 *)data,
TRUE, TRUE,
width, height, width, height,
bytes_per_line, bytes_per_line,
@ -571,6 +694,9 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture,
if (data_allocated) if (data_allocated)
g_free (data); g_free (data);
if (priv->have_shm)
XFree (image);
} }
/** /**
@ -633,6 +759,8 @@ clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture,
int x, y; int x, y;
unsigned int width, height, border_width, depth; unsigned int width, height, border_width, depth;
Status status = 0; Status status = 0;
gboolean new_pixmap = FALSE, new_pixmap_width = FALSE;
gboolean new_pixmap_height = FALSE, new_pixmap_depth = FALSE;
ClutterX11TexturePixmapPrivate *priv; ClutterX11TexturePixmapPrivate *priv;
@ -642,6 +770,7 @@ clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture,
clutter_x11_trap_x_errors (); clutter_x11_trap_x_errors ();
if (pixmap != None)
status = XGetGeometry (clutter_x11_get_default_display(), status = XGetGeometry (clutter_x11_get_default_display(),
(Drawable)pixmap, (Drawable)pixmap,
&root, &root,
@ -666,34 +795,48 @@ clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture,
priv->image = NULL; priv->image = NULL;
} }
g_object_ref (texture);
if (priv->pixmap != pixmap) if (priv->pixmap != pixmap)
{ {
priv->pixmap = pixmap; priv->pixmap = pixmap;
g_object_notify (G_OBJECT (texture), "pixmap"); new_pixmap = TRUE;
} }
if (priv->pixmap_width != width) if (priv->pixmap_width != width)
{ {
priv->pixmap_width = width; priv->pixmap_width = width;
g_object_notify (G_OBJECT (texture), "pixmap-width"); new_pixmap_width = TRUE;
} }
if (priv->pixmap_height != height) if (priv->pixmap_height != height)
{ {
priv->pixmap_height = height; priv->pixmap_height = height;
g_object_notify (G_OBJECT (texture), "pixmap-height"); new_pixmap_height = TRUE;
} }
if (priv->depth != depth) if (priv->depth != depth)
{ {
priv->depth = depth; priv->depth = depth;
g_object_notify (G_OBJECT (texture), "pixmap-depth"); new_pixmap_depth = TRUE;
} }
/* NB: We defer sending the signals until updating all the
* above members so the values are all available to the
* signal handlers. */
g_object_ref (texture);
if (new_pixmap)
g_object_notify (G_OBJECT (texture), "pixmap");
if (new_pixmap_width)
g_object_notify (G_OBJECT (texture), "pixmap-width");
if (new_pixmap_height)
g_object_notify (G_OBJECT (texture), "pixmap-height");
if (new_pixmap_depth)
g_object_notify (G_OBJECT (texture), "pixmap-depth");
g_object_unref (texture); g_object_unref (texture);
free_shm_resources (texture);
if (pixmap != None)
try_alloc_shm (texture);
if (priv->depth != 0 && if (priv->depth != 0 &&
priv->pixmap != None && priv->pixmap != None &&
priv->pixmap_width != 0 && priv->pixmap_width != 0 &&

View File

@ -333,6 +333,7 @@ case $clutterbackend in
;; ;;
fruity) fruity)
CLUTTER_FLAVOUR="fruity" CLUTTER_FLAVOUR="fruity"
CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_FRUITY" CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_FRUITY"
AC_DEFINE([HAVE_CLUTTER_FRUITY], 1, [We're building a fruity version of the eglnative backend]) AC_DEFINE([HAVE_CLUTTER_FRUITY], 1, [We're building a fruity version of the eglnative backend])

View File

@ -1,7 +1,8 @@
#include <config.h>
#if HAVE_CLUTTER_GLX #if HAVE_CLUTTER_GLX
#include <config.h>
#include <clutter/clutter.h> #include <clutter/clutter.h>
#include <clutter/x11/clutter-x11.h> #include <clutter/x11/clutter-x11.h>
#include <clutter/x11/clutter-x11-texture-pixmap.h> #include <clutter/x11/clutter-x11-texture-pixmap.h>
@ -159,13 +160,11 @@ main (int argc, char **argv)
pixmap = win_remote; pixmap = win_remote;
/* /*
XCompositeRedirectWindow(clutter_x11_get_default_display(), XCompositeRedirectWindow(clutter_x11_get_default_display(),
win_remote, win_remote,
CompositeRedirectAutomatic); CompositeRedirectAutomatic);
pixmap = XCompositeNameWindowPixmap (clutter_x11_get_default_display(),
win_remote);
*/ */
tex = clutter_x11_texture_pixmap_new_with_pixmap (pixmap); tex = clutter_x11_texture_pixmap_new_with_pixmap (pixmap);
@ -176,8 +175,21 @@ main (int argc, char **argv)
TRUE); TRUE);
#ifdef HAVE_CLUTTER_GLX #ifdef HAVE_CLUTTER_GLX
pixmap = create_pixmap (&w, &h, &d); pixmap = create_pixmap (&w, &h, &d);
#if 0
// pixmap = win_remote;
XCompositeRedirectWindow(clutter_x11_get_default_display(),
win_remote,
CompositeRedirectAutomatic);
pixmap = XCompositeNameWindowPixmap (clutter_x11_get_default_display(),
win_remote);
#endif
tex = clutter_glx_texture_pixmap_new_with_pixmap (pixmap); tex = clutter_glx_texture_pixmap_new_with_pixmap (pixmap);
clutter_actor_set_position (tex, clutter_actor_set_position (tex,
@ -186,7 +198,7 @@ main (int argc, char **argv)
0); 0);
clutter_x11_texture_pixmap_set_automatic (CLUTTER_X11_TEXTURE_PIXMAP (tex), clutter_x11_texture_pixmap_set_automatic (CLUTTER_X11_TEXTURE_PIXMAP (tex),
FALSE); TRUE);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), clutter_container_add_actor (CLUTTER_CONTAINER (stage),
tex); tex);