Private function to tell if we have RENDER extension.
Thu Jan 3 22:18:15 2002 Owen Taylor <otaylor@redhat.com> * gdk/x11/gdkdrawable-x11.c gdk/x11/gdkprivate-x11.h (_gdk_x11_have_render): Private function to tell if we have RENDER extension. * gdk/x11/gdkgc-x11.c (_gdk_x11_gc_get_fg_picture): Return None if we don't have RENDER extension. * gdk/x11/gdkpango-x11.c (gdk_pango_context_get): Don't use Xft unless we have render extension. * gdk/x11/gdkdrawable-x11.c (gdk_x11_drawable_get_picture): Handle missing render extension. * gdk/gdkdraw.c gdk/gdkdrawable.h gdk/gdkpixmap.c gdk/gdkwindow.c gdk/gdkinternals.h: Add a private copy_to_image() virtual function to the GdkDrawable vtable that extends get_image() to allow copying onto existing images. Make the default implementation of get_image() use this so that backends don't have to implement both. Add private wrapper _gdk_drawable_copy_to_image(). * gdk/x11/gdkimage-x11.c gdk/x11/gdkprivate-x11.c gdk/x11/gdkdrawable-x11.c (_gdk_x11_copy_to_image): Implement copy_to_image() semantics, speed up by using ShmPixmaps and XCopyArea when possible, XFlush() after ungrabbing the server, generally redo the logic once again. * gdk/gdkinternals.h gdk/x11/gdkimage-x11.c _gdk_windowing_bits_per_depth(): Function to convert from depth to bits-per-pixel. (We assume only one bpp per depth - X requires this.) * gdk/gdkinternals.h gdk/gdkrgb.c gdk/gdkimage.c: Move the GdkRGB scratch image code into a generic _gdk_image_get_scratch() chunk of code that we can use other places we need scratch images. * gdk/gdkimage.c gdk/x11/gdkimage.c gdk/gdkinternals.h: Add _gdk_image_new_for_depth() as the backend to _gdk_image_new() to allowing creating images with a depth and no visual. * gdk/gdkpixbuf-drawable.c: Fix so that getting parts of images not at 0,0 actually works. * gdk/gdkdrawable.h gdk/gdkinternals.h gdk/gdkdraw.c gdk/gdkwindow.c gdk/gdkpixmap.c gdk/gdkpixbuf-render.c: - Add a new GdkDrawableClass vfunc _draw_pixbuf, and _gdk_draw_pixbuf() [ will be made public later ], to allow backends to accelerate drawing pixbufs. - Move the implementation of gdk_pixbuf_render_to_drawable_alpha() to be the default implementation. - Update docs for gdk_pixbuf_render_to_drawable_alpha(). - Optimize the default implementation by using _gdk_image_copy_to_pixmap() and scratch shared images, and special casing the compositing. * gdk/x11/gdkdrawable-x11.c: Accelerate _gdk_draw_pixbuf() with alpha using the RENDER extension. * gdk/gdkpixbuf-drawable.c (gdk_pixbuf_get_from_drawable): Optimize by _gdk_image_copy_to_pixmap() and scratch images. * tests/testrgb.c: Add test for speed of alpha composition, reduce the number of iterations since alpha composition can be a bit slow. * gdk/x11/gdkimage-x11.c gdk/gdkprivate-x11.h (_gdk_x11_image_get_shm_pixmap): Private function to get a ShmPixmap for an image, if possible.
This commit is contained in:
@ -59,10 +59,12 @@ struct _GdkImagePrivateX11
|
||||
XImage *ximage;
|
||||
Display *xdisplay;
|
||||
gpointer x_shm_info;
|
||||
Pixmap shm_pixmap;
|
||||
};
|
||||
|
||||
static GList *image_list = NULL;
|
||||
static gpointer parent_class = NULL;
|
||||
static gboolean have_shm_pixmaps;
|
||||
|
||||
static void gdk_x11_image_destroy (GdkImage *image);
|
||||
static void gdk_image_init (GdkImage *image);
|
||||
@ -198,33 +200,42 @@ _gdk_windowing_image_init (void)
|
||||
{
|
||||
if (_gdk_use_xshm)
|
||||
{
|
||||
if (!gdk_image_check_xshm (gdk_display))
|
||||
{
|
||||
_gdk_use_xshm = False;
|
||||
}
|
||||
gint res = gdk_image_check_xshm (gdk_display);
|
||||
|
||||
if (!res)
|
||||
_gdk_use_xshm = FALSE;
|
||||
else
|
||||
have_shm_pixmaps = (res == 2);
|
||||
}
|
||||
}
|
||||
|
||||
GdkImage*
|
||||
gdk_image_new (GdkImageType type,
|
||||
GdkVisual *visual,
|
||||
gint width,
|
||||
gint height)
|
||||
_gdk_image_new_for_depth (GdkImageType type,
|
||||
GdkVisual *visual,
|
||||
gint width,
|
||||
gint height,
|
||||
gint depth)
|
||||
{
|
||||
GdkImage *image;
|
||||
GdkImagePrivateX11 *private;
|
||||
#ifdef USE_SHM
|
||||
XShmSegmentInfo *x_shm_info;
|
||||
#endif /* USE_SHM */
|
||||
Visual *xvisual;
|
||||
Visual *xvisual = NULL;
|
||||
|
||||
g_return_val_if_fail (!visual || GDK_IS_VISUAL (visual), NULL);
|
||||
g_return_val_if_fail (visual || depth != -1, NULL);
|
||||
|
||||
if (visual)
|
||||
depth = visual->depth;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case GDK_IMAGE_FASTEST:
|
||||
image = gdk_image_new (GDK_IMAGE_SHARED, visual, width, height);
|
||||
image = _gdk_image_new_for_depth (GDK_IMAGE_SHARED, visual, width, height, depth);
|
||||
|
||||
if (!image)
|
||||
image = gdk_image_new (GDK_IMAGE_NORMAL, visual, width, height);
|
||||
image = _gdk_image_new_for_depth (GDK_IMAGE_NORMAL, visual, width, height, depth);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -238,9 +249,10 @@ gdk_image_new (GdkImageType type,
|
||||
image->visual = visual;
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
image->depth = visual->depth;
|
||||
image->depth = depth;
|
||||
|
||||
xvisual = ((GdkVisualPrivate*) visual)->xvisual;
|
||||
if (visual)
|
||||
xvisual = ((GdkVisualPrivate*) visual)->xvisual;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@ -253,7 +265,7 @@ gdk_image_new (GdkImageType type,
|
||||
x_shm_info->shmid = -1;
|
||||
x_shm_info->shmaddr = (char*) -1;
|
||||
|
||||
private->ximage = XShmCreateImage (private->xdisplay, xvisual, visual->depth,
|
||||
private->ximage = XShmCreateImage (private->xdisplay, xvisual, depth,
|
||||
ZPixmap, NULL, x_shm_info, width, height);
|
||||
if (private->ximage == NULL)
|
||||
{
|
||||
@ -326,7 +338,7 @@ gdk_image_new (GdkImageType type,
|
||||
goto error;
|
||||
break;
|
||||
case GDK_IMAGE_NORMAL:
|
||||
private->ximage = XCreateImage (private->xdisplay, xvisual, visual->depth,
|
||||
private->ximage = XCreateImage (private->xdisplay, xvisual, depth,
|
||||
ZPixmap, 0, 0, width, height, 32, 0);
|
||||
|
||||
/* Use malloc, not g_malloc here, because X will call free()
|
||||
@ -344,7 +356,7 @@ gdk_image_new (GdkImageType type,
|
||||
|
||||
if (image)
|
||||
{
|
||||
image->byte_order = private->ximage->byte_order;
|
||||
image->byte_order = (private->ximage->byte_order == LSBFirst) ? GDK_LSB_FIRST : GDK_MSB_FIRST;
|
||||
image->mem = private->ximage->data;
|
||||
image->bpl = private->ximage->bytes_per_line;
|
||||
image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
|
||||
@ -379,39 +391,144 @@ gdk_image_new (GdkImageType type,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Pixmap
|
||||
_gdk_x11_image_get_shm_pixmap (GdkImage *image)
|
||||
{
|
||||
GdkImagePrivateX11 *private = PRIVATE_DATA (image);
|
||||
|
||||
#ifdef USE_SHM
|
||||
/* Future: do we need one of these per-screen per-image? ShmPixmaps
|
||||
* are the same for every screen, but can they be shared?
|
||||
*/
|
||||
if (!private->shm_pixmap && image->type == GDK_IMAGE_SHARED && have_shm_pixmaps)
|
||||
private->shm_pixmap = XShmCreatePixmap (private->xdisplay, _gdk_root_window,
|
||||
image->mem, private->x_shm_info,
|
||||
image->width, image->height, image->depth);
|
||||
|
||||
return private->shm_pixmap;
|
||||
#else
|
||||
return None;
|
||||
#endif
|
||||
}
|
||||
|
||||
GdkImage*
|
||||
_gdk_x11_get_image (GdkDrawable *drawable,
|
||||
gint x,
|
||||
gint y,
|
||||
gint width,
|
||||
gint height)
|
||||
gdk_image_new (GdkImageType type,
|
||||
GdkVisual *visual,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
return _gdk_image_new_for_depth (type, visual, width, height, -1);
|
||||
}
|
||||
|
||||
GdkImage*
|
||||
get_full_image (GdkDrawable *drawable,
|
||||
gint src_x,
|
||||
gint src_y,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
GdkImage *image;
|
||||
GdkImagePrivateX11 *private;
|
||||
GdkDrawableImplX11 *impl;
|
||||
XImage *ximage;
|
||||
|
||||
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
||||
|
||||
ximage = XGetImage (impl->xdisplay,
|
||||
impl->xid,
|
||||
src_x, src_y, width, height,
|
||||
AllPlanes, ZPixmap);
|
||||
|
||||
if (!ximage)
|
||||
return NULL;
|
||||
|
||||
image = g_object_new (gdk_image_get_type (), NULL);
|
||||
|
||||
private = PRIVATE_DATA (image);
|
||||
|
||||
private->xdisplay = gdk_display;
|
||||
private->ximage = ximage;
|
||||
|
||||
image->type = GDK_IMAGE_NORMAL;
|
||||
image->visual = gdk_drawable_get_visual (drawable); /* could be NULL */
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
image->depth = gdk_drawable_get_depth (drawable);
|
||||
|
||||
image->mem = private->ximage->data;
|
||||
image->bpl = private->ximage->bytes_per_line;
|
||||
image->bits_per_pixel = private->ximage->bits_per_pixel;
|
||||
image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
|
||||
image->byte_order = (private->ximage->byte_order == LSBFirst) ? GDK_LSB_FIRST : GDK_MSB_FIRST;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
GdkImage*
|
||||
_gdk_x11_copy_to_image (GdkDrawable *drawable,
|
||||
GdkImage *image,
|
||||
gint src_x,
|
||||
gint src_y,
|
||||
gint dest_x,
|
||||
gint dest_y,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
GdkImagePrivateX11 *private;
|
||||
GdkDrawableImplX11 *impl;
|
||||
GdkVisual *visual;
|
||||
gboolean have_grab;
|
||||
GdkRectangle req;
|
||||
GdkRectangle window_rect;
|
||||
XImage *ximage;
|
||||
Pixmap shm_pixmap = None;
|
||||
gboolean success = TRUE;
|
||||
|
||||
g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_X11 (drawable), NULL);
|
||||
g_return_val_if_fail (image != NULL || (dest_x == 0 && dest_y == 0), NULL);
|
||||
|
||||
visual = gdk_drawable_get_visual (drawable);
|
||||
|
||||
g_assert (visual || !GDK_IS_WINDOW_IMPL_X11 (drawable));
|
||||
|
||||
impl = GDK_DRAWABLE_IMPL_X11 (drawable);
|
||||
|
||||
have_grab = FALSE;
|
||||
|
||||
#define UNGRAB() G_STMT_START { \
|
||||
if (have_grab) { \
|
||||
gdk_x11_ungrab_server (); \
|
||||
XFlush (impl->xdisplay); \
|
||||
have_grab = FALSE; } \
|
||||
} G_STMT_END
|
||||
|
||||
if (!image && !GDK_IS_WINDOW_IMPL_X11 (drawable))
|
||||
return get_full_image (drawable, src_x, src_y, width, height);
|
||||
|
||||
if (image && image->type == GDK_IMAGE_SHARED)
|
||||
{
|
||||
shm_pixmap = _gdk_x11_image_get_shm_pixmap (image);
|
||||
if (shm_pixmap)
|
||||
{
|
||||
/* Again easy, we can just XCopyArea, and don't have to worry about clipping
|
||||
*/
|
||||
GC xgc = XCreateGC (impl->xdisplay, impl->xid, 0, NULL);
|
||||
|
||||
XCopyArea (impl->xdisplay, impl->xid, shm_pixmap, xgc,
|
||||
src_x, src_y, width, height, dest_x, dest_y);
|
||||
XSync (impl->xdisplay, FALSE);
|
||||
|
||||
XFreeGC (impl->xdisplay, xgc);
|
||||
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now the general case - we may have to worry about clipping to the screen
|
||||
* bounds, in which case we'll have to grab the server and only get a piece
|
||||
* of the window.
|
||||
*/
|
||||
if (GDK_IS_WINDOW_IMPL_X11 (drawable))
|
||||
{
|
||||
GdkRectangle screen_rect;
|
||||
Window child;
|
||||
|
||||
g_assert (visual);
|
||||
|
||||
have_grab = TRUE;
|
||||
gdk_x11_grab_server ();
|
||||
|
||||
@ -443,13 +560,7 @@ _gdk_x11_get_image (GdkDrawable *drawable,
|
||||
if (gdk_error_trap_pop () ||
|
||||
!gdk_rectangle_intersect (&window_rect, &screen_rect,
|
||||
&window_rect))
|
||||
{
|
||||
if (have_grab)
|
||||
gdk_x11_ungrab_server ();
|
||||
return image = gdk_image_new (GDK_IMAGE_FASTEST,
|
||||
visual,
|
||||
width, height);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -460,8 +571,8 @@ _gdk_x11_get_image (GdkDrawable *drawable,
|
||||
&window_rect.height);
|
||||
}
|
||||
|
||||
req.x = x;
|
||||
req.y = y;
|
||||
req.x = src_x;
|
||||
req.y = src_y;
|
||||
req.width = width;
|
||||
req.height = height;
|
||||
|
||||
@ -470,97 +581,66 @@ _gdk_x11_get_image (GdkDrawable *drawable,
|
||||
* For pixmaps this is all of the pixmap, for windows it is just
|
||||
* the onscreen part.
|
||||
*/
|
||||
if (!gdk_rectangle_intersect (&req, &window_rect, &req) && visual)
|
||||
{
|
||||
if (have_grab)
|
||||
gdk_x11_ungrab_server ();
|
||||
return image = gdk_image_new (GDK_IMAGE_FASTEST,
|
||||
visual,
|
||||
width, height);
|
||||
}
|
||||
if (!gdk_rectangle_intersect (&req, &window_rect, &req))
|
||||
goto out;
|
||||
|
||||
if (req.x != x || req.y != y)
|
||||
private = PRIVATE_DATA (image);
|
||||
|
||||
gdk_error_trap_push ();
|
||||
|
||||
if (!image &&
|
||||
req.x == src_x && req.y == src_y && req.width == width && req.height == height)
|
||||
{
|
||||
g_assert (GDK_IS_WINDOW (drawable));
|
||||
g_assert (visual);
|
||||
|
||||
image = gdk_image_new (GDK_IMAGE_FASTEST,
|
||||
visual,
|
||||
width, height);
|
||||
if (image == NULL)
|
||||
{
|
||||
if (have_grab)
|
||||
gdk_x11_ungrab_server ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private = PRIVATE_DATA (image);
|
||||
|
||||
gdk_error_trap_push ();
|
||||
|
||||
ximage = XGetSubImage (impl->xdisplay,
|
||||
impl->xid,
|
||||
req.x, req.y, req.width, req.height,
|
||||
AllPlanes, ZPixmap,
|
||||
private->ximage,
|
||||
req.x - x, req.y - y);
|
||||
|
||||
if (have_grab)
|
||||
{
|
||||
gdk_x11_ungrab_server ();
|
||||
have_grab = FALSE;
|
||||
}
|
||||
|
||||
if (gdk_error_trap_pop () || ximage == NULL)
|
||||
{
|
||||
g_object_unref (G_OBJECT (image));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_assert (ximage == private->ximage);
|
||||
image = get_full_image (drawable, src_x, src_y, width, height);
|
||||
if (!image)
|
||||
success = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Here we ignore the req.width, req.height -
|
||||
* XGetImage() will do the right thing without
|
||||
* them.
|
||||
gboolean created_image = FALSE;
|
||||
|
||||
if (!image)
|
||||
{
|
||||
image = _gdk_image_new_for_depth (GDK_IMAGE_NORMAL, visual, width, height,
|
||||
gdk_drawable_get_depth (drawable));
|
||||
created_image = TRUE;
|
||||
}
|
||||
|
||||
/* In the ShmImage but no ShmPixmap case, we could use XShmGetImage when
|
||||
* we are getting the entire image.
|
||||
*/
|
||||
ximage = XGetImage (impl->xdisplay,
|
||||
impl->xid,
|
||||
x, y, width, height,
|
||||
AllPlanes, ZPixmap);
|
||||
|
||||
if (have_grab)
|
||||
{
|
||||
gdk_x11_ungrab_server ();
|
||||
have_grab = FALSE;
|
||||
}
|
||||
|
||||
if (!ximage)
|
||||
return NULL;
|
||||
|
||||
image = g_object_new (gdk_image_get_type (), NULL);
|
||||
|
||||
private = PRIVATE_DATA (image);
|
||||
|
||||
private->xdisplay = gdk_display;
|
||||
private->ximage = ximage;
|
||||
|
||||
image->type = GDK_IMAGE_NORMAL;
|
||||
image->visual = visual; /* May be NULL */
|
||||
image->width = width;
|
||||
image->height = height;
|
||||
image->depth = gdk_drawable_get_depth (drawable);
|
||||
|
||||
image->mem = private->ximage->data;
|
||||
image->bpl = private->ximage->bytes_per_line;
|
||||
image->bits_per_pixel = private->ximage->bits_per_pixel;
|
||||
image->bpp = (private->ximage->bits_per_pixel + 7) / 8;
|
||||
image->byte_order = private->ximage->byte_order;
|
||||
if (XGetSubImage (impl->xdisplay,
|
||||
impl->xid,
|
||||
req.x, req.y, req.width, req.height,
|
||||
AllPlanes, ZPixmap,
|
||||
private->ximage,
|
||||
dest_x + req.x - src_x, dest_y + req.y - src_y) == None)
|
||||
{
|
||||
if (created_image)
|
||||
g_object_unref (image);
|
||||
image = NULL;
|
||||
success = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert (!have_grab);
|
||||
out:
|
||||
|
||||
if (have_grab)
|
||||
{
|
||||
gdk_x11_ungrab_server ();
|
||||
XFlush (impl->xdisplay);
|
||||
have_grab = FALSE;
|
||||
}
|
||||
|
||||
gdk_error_trap_pop ();
|
||||
|
||||
if (success && !image)
|
||||
{
|
||||
/* We "succeeded", but could get no content for the image so return junk */
|
||||
image = _gdk_image_new_for_depth (GDK_IMAGE_NORMAL, visual, width, height,
|
||||
gdk_drawable_get_depth (drawable));
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
@ -625,7 +705,11 @@ gdk_x11_image_destroy (GdkImage *image)
|
||||
case GDK_IMAGE_SHARED:
|
||||
#ifdef USE_SHM
|
||||
gdk_flush();
|
||||
|
||||
|
||||
if (private->shm_pixmap)
|
||||
XFreePixmap (private->xdisplay, private->shm_pixmap);
|
||||
|
||||
image_list = g_list_remove (image_list, image);
|
||||
XShmDetach (private->xdisplay, private->x_shm_info);
|
||||
XDestroyImage (private->ximage);
|
||||
|
||||
@ -634,8 +718,7 @@ gdk_x11_image_destroy (GdkImage *image)
|
||||
|
||||
g_free (private->x_shm_info);
|
||||
private->x_shm_info = NULL;
|
||||
|
||||
image_list = g_list_remove (image_list, image);
|
||||
|
||||
#else /* USE_SHM */
|
||||
g_error ("trying to destroy shared memory image when gdk was compiled without shared memory support");
|
||||
#endif /* USE_SHM */
|
||||
@ -673,3 +756,23 @@ gdk_x11_image_get_ximage (GdkImage *image)
|
||||
|
||||
return private->ximage;
|
||||
}
|
||||
|
||||
gint
|
||||
_gdk_windowing_get_bits_for_depth (gint depth)
|
||||
{
|
||||
XPixmapFormatValues *formats;
|
||||
gint count, i;
|
||||
|
||||
formats = XListPixmapFormats (gdk_display, &count);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (formats[i].depth == depth)
|
||||
{
|
||||
gint result = formats[i].bits_per_pixel;
|
||||
XFree (formats);
|
||||
return result;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user