From c4cc90d570d029a39eff55624be2b4584eff764c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 5 Oct 2009 16:03:37 +0200 Subject: Add very hacky support for uploading I420 as YUV. This patch requires the X server supporting XvPutImage to work on pixmaps. It also fails to properly check abort conditions. Consider this a proof of concept more than anything else. --- boilerplate/Makefile.win32.features | 10 ++++ build/Makefile.win32.features | 1 + build/Makefile.win32.features-h | 3 + configure.ac | 14 +++++ src/Makefile.win32.features | 14 +++++ src/cairo-image-surface.c | 14 +++++ src/cairo-xlib-surface.c | 106 ++++++++++++++++++++++++++++++++++++ 7 files changed, 162 insertions(+) diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features index 5c1e0119..647b9b1a 100644 --- a/boilerplate/Makefile.win32.features +++ b/boilerplate/Makefile.win32.features @@ -39,6 +39,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xrender_private) enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xrender_sources) endif +supported_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xv_headers) +all_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xv_headers) +all_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xv_private) +all_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xv_sources) +ifeq ($(CAIRO_HAS_XLIB_XV_SURFACE),1) +enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xv_headers) +enabled_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xv_private) +enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xv_sources) +endif + unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_headers) all_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_headers) all_cairo_boilerplate_private += $(cairo_boilerplate_xcb_private) diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features index bd314e9f..1cd72adb 100644 --- a/build/Makefile.win32.features +++ b/build/Makefile.win32.features @@ -2,6 +2,7 @@ CAIRO_HAS_XLIB_SURFACE=0 CAIRO_HAS_XLIB_XRENDER_SURFACE=0 +CAIRO_HAS_XLIB_XV_SURFACE=0 CAIRO_HAS_XCB_SURFACE=0 CAIRO_HAS_QT_SURFACE=0 CAIRO_HAS_QUARTZ_SURFACE=0 diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h index 7e49cd63..bfd2c3c4 100644 --- a/build/Makefile.win32.features-h +++ b/build/Makefile.win32.features-h @@ -11,6 +11,9 @@ endif ifeq ($(CAIRO_HAS_XLIB_XRENDER_SURFACE),1) @echo "#define CAIRO_HAS_XLIB_XRENDER_SURFACE 1" >> src/cairo-features.h endif +ifeq ($(CAIRO_HAS_XLIB_XV_SURFACE),1) + @echo "#define CAIRO_HAS_XLIB_XV_SURFACE 1" >> src/cairo-features.h +endif ifeq ($(CAIRO_HAS_XCB_SURFACE),1) @echo "#define CAIRO_HAS_XCB_SURFACE 1" >> src/cairo-features.h endif diff --git a/configure.ac b/configure.ac index ba3cbc06..6a1c8683 100644 --- a/configure.ac +++ b/configure.ac @@ -103,6 +103,20 @@ CAIRO_ENABLE_SURFACE_BACKEND(xlib_xrender, Xlib Xrender, auto, [ fi ]) +CAIRO_ENABLE_SURFACE_BACKEND(xlib_xv, Xlib Xv, auto, [ + if test "x$use_xlib" != "xyes"; then + use_xlib_xv="no (requires --enable-xlib)" + else + xlib_xv_BASE=cairo-xlib + xlib_xv_REQUIRES="xv" + PKG_CHECK_MODULES(xlib_xv, $xlib_xv_REQUIRES, + [AC_DEFINE([CAIRO_HAS_XV], 1, [Define to 1 if xv support is available])], + [AC_MSG_RESULT(no) + use_xlib_xrender="no (requires $xlib_xrender_REQUIRES http://freedesktop.org/Software/xlibs)" + ]) + fi +]) + dnl =========================================================================== CAIRO_ENABLE_SURFACE_BACKEND(xcb, XCB, no, [ diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features index 048c9211..207b84c2 100644 --- a/src/Makefile.win32.features +++ b/src/Makefile.win32.features @@ -49,6 +49,20 @@ ifeq ($(CAIRO_HAS_XLIB_XRENDER_SURFACE),1) enabled_cairo_pkgconf += cairo-xlib-xrender.pc endif +supported_cairo_headers += $(cairo_xlib_xv_headers) +all_cairo_headers += $(cairo_xlib_xv_headers) +all_cairo_private += $(cairo_xlib_xv_private) +all_cairo_sources += $(cairo_xlib_xv_sources) +ifeq ($(CAIRO_HAS_XLIB_XV_SURFACE),1) +enabled_cairo_headers += $(cairo_xlib_xv_headers) +enabled_cairo_private += $(cairo_xlib_xv_private) +enabled_cairo_sources += $(cairo_xlib_xv_sources) +endif +all_cairo_pkgconf += cairo-xlib-xv.pc +ifeq ($(CAIRO_HAS_XLIB_XV_SURFACE),1) +enabled_cairo_pkgconf += cairo-xlib-xv.pc +endif + unsupported_cairo_headers += $(cairo_xcb_headers) all_cairo_headers += $(cairo_xcb_headers) all_cairo_private += $(cairo_xcb_private) diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c index ebf6c39f..d057c559 100644 --- a/src/cairo-image-surface.c +++ b/src/cairo-image-surface.c @@ -115,6 +115,9 @@ _cairo_content_from_pixman_format (pixman_format_code_t pixman_format) #endif #if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16) case PIXMAN_a2r10g10b10: +#endif +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,17,0) + case PIXMAN_ayuv: #endif return CAIRO_CONTENT_COLOR_ALPHA; case PIXMAN_x8r8g8b8: @@ -144,6 +147,17 @@ _cairo_content_from_pixman_format (pixman_format_code_t pixman_format) #endif #if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,15,16) case PIXMAN_x2r10g10b10: +#endif +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0,17,0) + case PIXMAN_i420: + case PIXMAN_nv12: + case PIXMAN_nv21: + case PIXMAN_y41b: + case PIXMAN_y42b: + case PIXMAN_y444: + case PIXMAN_yuy2: + case PIXMAN_uyvy: + case PIXMAN_yvyu: #endif return CAIRO_CONTENT_COLOR; case PIXMAN_a8: 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 /* for XDestroyImage */ +#include +#include + #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; -- cgit v1.2.3