diff --git a/ChangeLog b/ChangeLog index 925a9612d..0563db919 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2008-04-29 Matthew Allum + + * 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 Removed COGLhandle and changed shader and program functions to be diff --git a/clutter/glx/Makefile.am b/clutter/glx/Makefile.am index 182825a17..7bdefd070 100644 --- a/clutter/glx/Makefile.am +++ b/clutter/glx/Makefile.am @@ -1,10 +1,11 @@ -libclutterincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter -libclutterinclude_HEADERS = clutter-glx.h clutter-glx-texture-pixmap.h +libclutter_glx_includedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter/glx +libclutter_glx_include_HEADERS = clutter-glx.h clutter-glx-texture-pixmap.h INCLUDES = \ -DG_LOG_DOMAIN=\"ClutterGLX\" \ -I$(top_srcdir) \ -I$(top_srcdir)/clutter \ + -I$(top_srcdir)/clutter/x11 \ -I$(top_builddir)/clutter \ $(CLUTTER_CFLAGS) \ $(CLUTTER_DEBUG_CFLAGS) \ diff --git a/clutter/glx/clutter-glx-texture-pixmap.c b/clutter/glx/clutter-glx-texture-pixmap.c index a5c3b43af..f2420f11f 100644 --- a/clutter/glx/clutter-glx-texture-pixmap.c +++ b/clutter/glx/clutter-glx-texture-pixmap.c @@ -4,6 +4,8 @@ * An OpenGL based 'interactive canvas' library. * * Authored By Johan Bilien + * Matthew Allum + * Robert Bragg * * 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 clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, gint x, @@ -102,51 +82,29 @@ clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, 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 -clutter_glx_texture_pixmap_class_init (ClutterGLXTexturePixmapClass *klass) +static gboolean +texture_bind (ClutterGLXTexturePixmap *tex) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); - ClutterX11TexturePixmapClass *x11_texture_class = - CLUTTER_X11_TEXTURE_PIXMAP_CLASS (klass); + GLuint handle = 0; + GLenum target = 0; + CoglHandle cogl_tex; + 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; - object_class->notify = clutter_glx_texture_pixmap_notify; + glEnable(target); - actor_class->realize = clutter_glx_texture_pixmap_realize; - actor_class->unrealize = clutter_glx_texture_pixmap_unrealize; - actor_class->paint = clutter_glx_texture_pixmap_paint; + /* FIXME: fire off an error here? */ + glBindTexture (target, handle); - 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 ()); - - /* 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; - } + return TRUE; } static void @@ -159,11 +117,6 @@ clutter_glx_texture_pixmap_init (ClutterGLXTexturePixmap *self) CLUTTER_GLX_TYPE_TEXTURE_PIXMAP, 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 @@ -195,55 +148,75 @@ clutter_glx_texture_pixmap_notify (GObject *object, GParamSpec *pspec) if (g_str_equal (pspec->name, "pixmap")) { ClutterGLXTexturePixmap *texture = CLUTTER_GLX_TEXTURE_PIXMAP (object); + printf("notify\n"); + 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 clutter_glx_texture_pixmap_realize (ClutterActor *actor) { ClutterGLXTexturePixmapPrivate *priv; - COGLenum pixel_type, pixel_format,filter_quality; - gboolean repeat_x, repeat_y; - guint width, height; + Pixmap pixmap; + guint pixmap_width, pixmap_height; + printf("realise\n"); 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)-> realize (actor); return; } g_object_get (actor, - "pixel-type", &pixel_type, - "pixel-format", &pixel_format, - "repeat-x", &repeat_x, - "repeat-y", &repeat_y, - "filter-quality", &filter_quality, - "pixmap-width", &width, - "pixmap-height", &height, + "pixmap", &pixmap, + "pixmap-width", &pixmap_width, + "pixmap-height", &pixmap_height, NULL); - /* FIXME: Obsolete. Move to new cogl api - cogl_textures_create (1, &priv->texture_id); - */ - 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, - filter_quality ? CGL_LINEAR : CGL_NEAREST, - filter_quality ? CGL_LINEAR : CGL_NEAREST); + if (!pixmap) + return; - 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); + create_cogl_texture (CLUTTER_TEXTURE (actor), pixmap_width, pixmap_height); } static void @@ -252,6 +225,8 @@ clutter_glx_texture_pixmap_unrealize (ClutterActor *actor) ClutterGLXTexturePixmapPrivate *priv; Display *dpy; + printf("unrealise\n"); + priv = CLUTTER_GLX_TEXTURE_PIXMAP (actor)->priv; dpy = clutter_x11_get_default_display(); @@ -277,104 +252,9 @@ clutter_glx_texture_pixmap_unrealize (ClutterActor *actor) 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); } -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 * get_fbconfig_for_depth (guint depth) { @@ -482,6 +362,41 @@ get_fbconfig_for_depth (guint depth) 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 clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture) { @@ -492,16 +407,23 @@ clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture) Display *dpy; guint depth; Pixmap pixmap; + guint pixmap_width, pixmap_height; ClutterBackendGLX *backend_glx; + printf("create\n"); + backend_glx = CLUTTER_BACKEND_GLX(clutter_get_default_backend ()); dpy = clutter_x11_get_default_display (); g_object_get (texture, + "pixmap-width", &pixmap_width, + "pixmap-height", &pixmap_height, "pixmap-depth", &depth, "pixmap", &pixmap, NULL); + if (!pixmap) + return; fbconfig = get_fbconfig_for_depth (depth); @@ -516,10 +438,12 @@ clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture) if (depth == 24) { attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT; + printf("depth: %i\n", 24); } else if (depth == 32) { attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT; + printf("depth: %i\n", 32); } else { @@ -531,58 +455,38 @@ clutter_glx_texture_pixmap_create_glx_pixmap (ClutterGLXTexturePixmap *texture) attribs[i++] = 0; 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; - else - attribs[i++] = GLX_TEXTURE_2D_EXT; */ attribs[i++] = None; - clutter_x11_trap_x_errors (); glx_pixmap = glXCreatePixmap (dpy, *fbconfig, pixmap, attribs); XSync (dpy, FALSE); - clutter_x11_untrap_x_errors (); + if (clutter_x11_untrap_x_errors ()) + g_warning ("glx pixmap creation failed"); g_free (fbconfig); if (glx_pixmap != None) { if (priv->glx_pixmap) - { - 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 (); - } + clutter_glx_texture_pixmap_free_glx_pixmap (texture); 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 @@ -595,26 +499,41 @@ clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, ClutterGLXTexturePixmapPrivate *priv; Display *dpy; + printf("update area\n"); + priv = CLUTTER_GLX_TEXTURE_PIXMAP (texture)->priv; 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)) return; - /* FIXME: Obsolete. - cogl_texture_bind (priv->target_type, priv->texture_id); */ + if (!_have_tex_from_pixmap_ext) + { + 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) { + 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 (); (_gl_bind_tex_image) (dpy, @@ -629,8 +548,61 @@ clutter_glx_texture_pixmap_update_area (ClutterX11TexturePixmap *texture, 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: * @pixmap: the X Pixmap to which this texture should be bound diff --git a/clutter/glx/clutter-glx-texture-pixmap.h b/clutter/glx/clutter-glx-texture-pixmap.h index f77f17f86..963820df5 100644 --- a/clutter/glx/clutter-glx-texture-pixmap.h +++ b/clutter/glx/clutter-glx-texture-pixmap.h @@ -28,6 +28,7 @@ #include #include +#include #include diff --git a/clutter/x11/Makefile.am b/clutter/x11/Makefile.am index d3632d7d1..193971a51 100644 --- a/clutter/x11/Makefile.am +++ b/clutter/x11/Makefile.am @@ -1,5 +1,5 @@ -libclutterincludedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter -libclutterinclude_HEADERS = clutter-x11.h \ +libclutter_x11_includedir = $(includedir)/clutter-@CLUTTER_API_VERSION@/clutter/x11 +libclutter_x11_include_HEADERS = clutter-x11.h \ clutter-x11-texture-pixmap.h clutter-x11-$(CLUTTER_API_VERSION).pc: clutter-x11.pc diff --git a/clutter/x11/clutter-x11-texture-pixmap.c b/clutter/x11/clutter-x11-texture-pixmap.c index 55ebbc830..a0d58a5ba 100644 --- a/clutter/x11/clutter-x11-texture-pixmap.c +++ b/clutter/x11/clutter-x11-texture-pixmap.c @@ -51,6 +51,11 @@ #include #include +#include +#include +#include +#include + enum { PROP_PIXMAP = 1, @@ -86,10 +91,12 @@ struct _ClutterX11TexturePixmapPrivate guint depth; XImage *image; + XShmSegmentInfo shminfo; gboolean automatic_updates; Damage damage; + gboolean have_shm; }; static int _damage_event_base = 0; @@ -130,6 +137,108 @@ check_extensions (ClutterX11TexturePixmap *texture) 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 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 ? */ } -} -static GObject * -clutter_x11_texture_pixmap_constructor (GType type, - guint n_props, - GObjectConstructParam *props) -{ - 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; + self->priv->image = NULL; + self->priv->automatic_updates = FALSE; + self->priv->damage = None; + self->priv->pixmap = None; + self->priv->shminfo.shmid = -1; } static void @@ -254,6 +354,8 @@ clutter_x11_texture_pixmap_dispose (GObject *object) priv->image = NULL; } + free_shm_resources (texture); + 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)); - object_class->constructor = clutter_x11_texture_pixmap_constructor; object_class->dispose = clutter_x11_texture_pixmap_dispose; object_class->set_property = clutter_x11_texture_pixmap_set_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; Display *dpy; XImage *image; - guint *pixel, *l; + char *first_pixel; GError *error = NULL; guint bytes_per_line; - guint8 *data; + char *data; gboolean data_allocated = FALSE; int err_code; @@ -459,23 +560,51 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, clutter_x11_trap_x_errors (); - /* FIXME: Use XSHM here! */ - if (!priv->image) - priv->image = XGetImage (dpy, - priv->pixmap, - 0, 0, - priv->pixmap_width, priv->pixmap_height, - AllPlanes, - ZPixmap); + 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 - XGetSubImage (dpy, - priv->pixmap, - x, y, - width, height, - AllPlanes, - ZPixmap, - priv->image, - x, y); + { + if (!priv->image) + { + priv->image = XGetImage (dpy, + priv->pixmap, + 0, 0, + priv->pixmap_width, priv->pixmap_height, + AllPlanes, + ZPixmap); + first_pixel = priv->image->data + priv->image->bytes_per_line * y + + x * priv->image->bits_per_pixel/8; + } + else + { + XGetSubImage (dpy, + priv->pixmap, + x, y, + width, height, + AllPlanes, + ZPixmap, + priv->image, + 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); @@ -488,53 +617,47 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, return; } - image = priv->image; - if (priv->depth == 24) { - guint *first_line = (guint *)image->data + y * image->bytes_per_line / 4; + guint xpos, ypos; - for (l = first_line; - l != (first_line + height * image->bytes_per_line / 4); - l = l + image->bytes_per_line / 4) - { - for (pixel = l + x; pixel != l + x + width; pixel ++) + for (ypos=0; yposbytes_per_line*ypos + + xpos * 4; + p[3] = 0xFF; } - data = (guint8 *)first_line + x * 4; + data = first_pixel; bytes_per_line = image->bytes_per_line; } - else if (priv->depth == 16) { - guint16 *p, *lp; - + guint xpos, ypos; data = g_malloc (height * width * 4); data_allocated = TRUE; - bytes_per_line = priv->pixmap_width * 4; + bytes_per_line = width * 4; - for (l = (guint *)data, - lp = (guint16 *)image->data + y * image->bytes_per_line / 2; - 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++) + for (ypos=0; yposbytes_per_line * ypos + + xpos * 2; + guint16 *src_pixel = (guint16 *)src_p; + char *dst_p = data + bytes_per_line * ypos + xpos * 4; + guint32 *dst_pixel = (guint32 *)dst_p; + *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) { bytes_per_line = image->bytes_per_line; - data = (guint8 *)image->data + y * bytes_per_line + x * 4; + data = first_pixel; } else return; @@ -542,7 +665,7 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, if (x != 0 || y != 0 || width != priv->pixmap_width || height != priv->pixmap_height) clutter_texture_set_area_from_rgb_data (CLUTTER_TEXTURE (texture), - data, + (guint8 *)data, TRUE, x, y, width, height, @@ -552,7 +675,7 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, &error); else clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (texture), - data, + (guint8 *)data, TRUE, width, height, bytes_per_line, @@ -571,6 +694,9 @@ clutter_x11_texture_pixmap_update_area_real (ClutterX11TexturePixmap *texture, if (data_allocated) g_free (data); + + if (priv->have_shm) + XFree (image); } /** @@ -633,6 +759,8 @@ clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture, int x, y; unsigned int width, height, border_width, depth; Status status = 0; + gboolean new_pixmap = FALSE, new_pixmap_width = FALSE; + gboolean new_pixmap_height = FALSE, new_pixmap_depth = FALSE; ClutterX11TexturePixmapPrivate *priv; @@ -642,6 +770,7 @@ clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture, clutter_x11_trap_x_errors (); + if (pixmap != None) status = XGetGeometry (clutter_x11_get_default_display(), (Drawable)pixmap, &root, @@ -666,34 +795,48 @@ clutter_x11_texture_pixmap_set_pixmap (ClutterX11TexturePixmap *texture, priv->image = NULL; } - g_object_ref (texture); - if (priv->pixmap != pixmap) { priv->pixmap = pixmap; - g_object_notify (G_OBJECT (texture), "pixmap"); + new_pixmap = TRUE; } if (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) { priv->pixmap_height = height; - g_object_notify (G_OBJECT (texture), "pixmap-height"); + new_pixmap_height = TRUE; } if (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); + free_shm_resources (texture); + if (pixmap != None) + try_alloc_shm (texture); + if (priv->depth != 0 && priv->pixmap != None && priv->pixmap_width != 0 && diff --git a/configure.ac b/configure.ac index 2e5ed4bdd..73e5614c3 100644 --- a/configure.ac +++ b/configure.ac @@ -333,6 +333,7 @@ case $clutterbackend in ;; fruity) + CLUTTER_FLAVOUR="fruity" CLUTTER_STAGE_TYPE="CLUTTER_TYPE_STAGE_FRUITY" AC_DEFINE([HAVE_CLUTTER_FRUITY], 1, [We're building a fruity version of the eglnative backend]) diff --git a/tests/test-pixmap.c b/tests/test-pixmap.c index a3f789e26..894ec1013 100644 --- a/tests/test-pixmap.c +++ b/tests/test-pixmap.c @@ -1,7 +1,8 @@ +#include #if HAVE_CLUTTER_GLX -#include + #include #include #include @@ -159,13 +160,11 @@ main (int argc, char **argv) pixmap = win_remote; + /* XCompositeRedirectWindow(clutter_x11_get_default_display(), win_remote, CompositeRedirectAutomatic); - - pixmap = XCompositeNameWindowPixmap (clutter_x11_get_default_display(), - win_remote); */ tex = clutter_x11_texture_pixmap_new_with_pixmap (pixmap); @@ -176,8 +175,21 @@ main (int argc, char **argv) TRUE); #ifdef HAVE_CLUTTER_GLX + 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); clutter_actor_set_position (tex, @@ -186,7 +198,7 @@ main (int argc, char **argv) 0); clutter_x11_texture_pixmap_set_automatic (CLUTTER_X11_TEXTURE_PIXMAP (tex), - FALSE); + TRUE); clutter_container_add_actor (CLUTTER_CONTAINER (stage), tex);