diff options
Diffstat (limited to 'src/cairo-xlib-surface.c')
-rw-r--r-- | src/cairo-xlib-surface.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c index 20ba21cb..6a768112 100644 --- a/src/cairo-xlib-surface.c +++ b/src/cairo-xlib-surface.c @@ -55,6 +55,9 @@ #include <X11/Xutil.h> /* for XDestroyImage */ +#include <X11/extensions/Xv.h> +#include <X11/extensions/Xvlib.h> + #define XLIB_COORD_MAX 32767 #define DEBUG 0 @@ -998,6 +1001,101 @@ _cairo_xlib_surface_put_gc (cairo_xlib_surface_t *surface, GC gc) gc); } +static const struct { + pixman_format_code_t pixman_format; + int xv_id; +} xv_format_map[] = { + { PIXMAN_i420, 0x30323449 } +}; + +static cairo_status_t +_draw_image_surface_xv (cairo_xlib_surface_t *surface, + cairo_image_surface_t *image, + int src_x, + int src_y, + int width, + int height, + int dst_x, + int dst_y) +{ + XvImage *xvimage; + int res, j, n_formats; + unsigned int i, n_adaptors, format_id; + cairo_status_t status; + XvImageFormatValues *formats; + XvAdaptorInfo *adaptors; + XvPortID port; + GC gc; + + res = XvQueryAdaptors (surface->dpy, + RootWindowOfScreen (surface->screen->screen), + &n_adaptors, + &adaptors); + if (res != Success) + return res == XvBadAlloc ? _cairo_error (CAIRO_STATUS_NO_MEMORY) : CAIRO_INT_STATUS_UNSUPPORTED; + + for (format_id = 0; format_id < ARRAY_LENGTH (xv_format_map); format_id++) + { + if (xv_format_map[format_id].pixman_format == image->pixman_format) + break; + } + if (format_id == ARRAY_LENGTH (xv_format_map)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + for (i = 0; i < n_adaptors; i++) + { + if ((adaptors[i].type & (XvInputMask | XvImageMask)) != (XvInputMask | XvImageMask)) + continue; + + port = adaptors[i].base_id; + + formats = XvListImageFormats (surface->dpy, port, &n_formats); + for (j = 0; j < n_formats; j++) + { + if (formats[j].type != XvYUV) + continue; + + if (formats[j].id == xv_format_map[format_id].xv_id) + break; + } + XFree (formats); + if (j < n_formats) + break; + } + XFree (adaptors); + + if (i == n_adaptors) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* FIXME: check strides here */ + + xvimage = XvCreateImage (surface->dpy, port, + xv_format_map[format_id].xv_id, + (char *) pixman_image_get_data (image->pixman_image), + pixman_image_get_width (image->pixman_image), + pixman_image_get_height (image->pixman_image)); + if (xvimage == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_xlib_surface_get_gc (surface, &gc); + if (unlikely (status)) + { + XFree (xvimage); + return status; + } + + XvPutImage (surface->dpy, port, + surface->drawable, gc, + xvimage, + src_x, src_y, width, height, + dst_x, dst_y, width, height); + + _cairo_xlib_surface_put_gc (surface, gc); + XFree (xvimage); + + return CAIRO_STATUS_SUCCESS; +} + static cairo_status_t _draw_image_surface (cairo_xlib_surface_t *surface, cairo_image_surface_t *image, @@ -1016,6 +1114,14 @@ _draw_image_surface (cairo_xlib_surface_t *surface, cairo_bool_t own_data; GC gc; + status = _draw_image_surface_xv (surface, + image, + src_x, src_y, + width, height, + dst_x, dst_y); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + ximage.width = image->width; ximage.height = image->height; ximage.format = ZPixmap; |