summaryrefslogtreecommitdiff
path: root/src/cairo-xlib-surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-xlib-surface.c')
-rw-r--r--src/cairo-xlib-surface.c106
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;