x11: implement pixmap rendering with RENDER extension.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Mon, 22 Jul 2013 07:00:38 +0000 (09:00 +0200)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Mon, 22 Jul 2013 13:45:10 +0000 (15:45 +0200)
Use hardware accelerated XRenderComposite() function, from the RENDER
extension, to blit a pixmap to screen. Besides, this can also support
cropping and scaling.

configure.ac
gst-libs/gst/vaapi/Makefile.am
gst-libs/gst/vaapi/gstvaapidisplay_x11.c
gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h
gst-libs/gst/vaapi/gstvaapiwindow_x11.c
gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h

index 6e033e8..837ea10 100644 (file)
@@ -470,6 +470,23 @@ if test $HAVE_XRANDR -eq 1; then
         [Defined to 1 if the XRandR extension exists.])
 fi
 
+dnl Check for XRender
+HAVE_XRENDER=0
+if test $USE_X11 -eq 1; then
+    HAVE_XRENDER=1
+    PKG_CHECK_MODULES([XRENDER], [xrender], [:], [HAVE_XRENDER=0])
+    if test $HAVE_XRENDER -eq 1; then
+        saved_CPPFLAGS="$CPPFLAGS"
+        CPPFLAGS="$CPPFLAGS $XRENDER_CFLAGS"
+        AC_CHECK_HEADERS([X11/extensions/Xrender.h], [:], [HAVE_XRENDER=0])
+        CPPFLAGS="$saved_CPPFLAGS"
+    fi
+fi
+if test $HAVE_XRENDER -eq 1; then
+    AC_DEFINE_UNQUOTED([HAVE_XRENDER], [1],
+        [Defined to 1 if the XRender extension exists.])
+fi
+
 dnl OpenGL
 enable_opengl="no"
 if test "$enable_glx" = "yes"; then
index b2a5df5..d4fa248 100644 (file)
@@ -289,6 +289,7 @@ libgstvaapi_x11_@GST_API_VERSION@_la_CFLAGS =       \
        $(GST_BASE_CFLAGS)                      \
        $(X11_CFLAGS)                           \
        $(XRANDR_CFLAGS)                        \
+       $(XRENDER_CFLAGS)                       \
        $(LIBVA_X11_CFLAGS)                     \
        $(NULL)
 
@@ -296,6 +297,7 @@ libgstvaapi_x11_@GST_API_VERSION@_la_LIBADD =       \
        $(GLIB_LIBS)                            \
        $(X11_LIBS)                             \
        $(XRANDR_LIBS)                          \
+       $(XRENDER_LIBS)                         \
        $(LIBVA_X11_LIBS)                       \
        libgstvaapi-$(GST_API_VERSION).la       \
        $(NULL)
index 5fb0cba..b633b1a 100644 (file)
 # include <X11/extensions/Xrandr.h>
 #endif
 
+#ifdef HAVE_XRENDER
+# include <X11/extensions/Xrender.h>
+#endif
+
 #define DEBUG 1
 #include "gstvaapidebug.h"
 
@@ -130,18 +134,22 @@ set_synchronous(GstVaapiDisplayX11 *display, gboolean synchronous)
     }
 }
 
-/* Check whether XRANDR extension is available */
+/* Check for display server extensions */
 static void
-check_xrandr(GstVaapiDisplayX11 *display)
+check_extensions(GstVaapiDisplayX11 *display)
 {
-#ifdef HAVE_XRANDR
     GstVaapiDisplayX11Private * const priv =
         GST_VAAPI_DISPLAY_X11_PRIVATE(display);
     int evt_base, err_base;
 
+#ifdef HAVE_XRANDR
     priv->use_xrandr = XRRQueryExtension(priv->x11_display,
         &evt_base, &err_base);
 #endif
+#ifdef HAVE_XRENDER
+    priv->has_xrender = XRenderQueryExtension(priv->x11_display,
+        &evt_base, &err_base);
+#endif
 }
 
 static gboolean
@@ -156,7 +164,7 @@ gst_vaapi_display_x11_bind_display(GstVaapiDisplay *base_display,
     priv->x11_screen = DefaultScreen(native_display);
     priv->use_foreign_display = TRUE;
 
-    check_xrandr(display);
+    check_extensions(display);
 
     if (!set_display_name(display, XDisplayString(priv->x11_display)))
         return FALSE;
@@ -193,7 +201,7 @@ gst_vaapi_display_x11_open_display(GstVaapiDisplay *base_display,
     }
     priv->x11_screen = DefaultScreen(priv->x11_display);
 
-    check_xrandr(display);
+    check_extensions(display);
     return TRUE;
 }
 
index 0593317..45494bc 100644 (file)
@@ -63,6 +63,17 @@ typedef struct _GstVaapiDisplayX11Class         GstVaapiDisplayX11Class;
 #define GST_VAAPI_DISPLAY_XSCREEN(display) \
     GST_VAAPI_DISPLAY_X11_PRIVATE(display)->x11_screen
 
+/**
+ * GST_VAAPI_DISPLAY_HAS_XRENDER:
+ * @display: a #GstVaapiDisplay
+ *
+ * Macro that evaluates to the existence of the XRender extension on
+ * @display server.
+ */
+#undef  GST_VAAPI_DISPLAY_HAS_XRENDER
+#define GST_VAAPI_DISPLAY_HAS_XRENDER(display) \
+    (GST_VAAPI_DISPLAY_X11_PRIVATE(display)->has_xrender)
+
 struct _GstVaapiDisplayX11Private {
     gchar              *display_name;
     Display            *x11_display;
@@ -70,6 +81,7 @@ struct _GstVaapiDisplayX11Private {
     GArray             *pixmap_formats;
     guint               use_foreign_display     : 1; // Foreign native_display?
     guint               use_xrandr              : 1;
+    guint               has_xrender             : 1; // Has XRender extension?
     guint               synchronous             : 1;
 };
 
index a5ea277..df58ef2 100644 (file)
@@ -31,6 +31,8 @@
 #include "gstvaapicompat.h"
 #include "gstvaapiwindow_x11.h"
 #include "gstvaapiwindow_x11_priv.h"
+#include "gstvaapipixmap_x11.h"
+#include "gstvaapipixmap_priv.h"
 #include "gstvaapidisplay_x11.h"
 #include "gstvaapidisplay_x11_priv.h"
 #include "gstvaapiutils.h"
@@ -223,6 +225,9 @@ gst_vaapi_window_x11_create(GstVaapiWindow *window, guint *width, guint *height)
         "_NET_WM_STATE_FULLSCREEN",
     };
 
+    priv->has_xrender = GST_VAAPI_DISPLAY_HAS_XRENDER(
+        GST_VAAPI_OBJECT_DISPLAY(window));
+
     if (window->use_foreign_window && xid) {
         GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
         XGetWindowAttributes(dpy, xid, &wattr);
@@ -266,6 +271,17 @@ gst_vaapi_window_x11_destroy(GstVaapiWindow *window)
     Display * const                  dpy  = GST_VAAPI_OBJECT_XDISPLAY(window);
     const Window                     xid  = GST_VAAPI_OBJECT_ID(window);
 
+#ifdef HAVE_XRENDER
+    GstVaapiWindowX11Private * const priv =
+        GST_VAAPI_WINDOW_X11_GET_PRIVATE(window);
+    if (priv->picture) {
+        GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
+        XRenderFreePicture(dpy, priv->picture);
+        GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
+        priv->picture = None;
+    }
+#endif
+
     if (xid) {
         if (!window->use_foreign_window) {
             GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
@@ -434,6 +450,113 @@ gst_vaapi_window_x11_render(
     return TRUE;
 }
 
+static gboolean
+gst_vaapi_window_x11_render_pixmap_xrender(
+    GstVaapiWindow          *window,
+    GstVaapiPixmap          *pixmap,
+    const GstVaapiRectangle *src_rect,
+    const GstVaapiRectangle *dst_rect
+)
+{
+#ifdef HAVE_XRENDER
+    GstVaapiWindowX11Private * const priv =
+        GST_VAAPI_WINDOW_X11_GET_PRIVATE(window);
+    Display * const     dpy = GST_VAAPI_OBJECT_XDISPLAY(window);
+    const Window        win = GST_VAAPI_OBJECT_ID(window);
+    const Pixmap        pix = GST_VAAPI_OBJECT_ID(pixmap);
+    Picture picture;
+    XRenderPictFormat *pic_fmt;
+    XWindowAttributes wattr;
+    int fmt, op;
+    gboolean success = FALSE;
+
+    /* Ensure Picture for window is created */
+    if (!priv->picture) {
+        GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
+        XGetWindowAttributes(dpy, win, &wattr);
+        pic_fmt = XRenderFindVisualFormat(dpy, wattr.visual);
+        if (pic_fmt)
+            priv->picture = XRenderCreatePicture(dpy, win, pic_fmt, 0, NULL);
+        GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
+        if (!priv->picture)
+            return FALSE;
+    }
+
+    /* Check pixmap format */
+    switch (GST_VAAPI_PIXMAP_FORMAT(pixmap)) {
+    case GST_VIDEO_FORMAT_xRGB:
+        fmt = PictStandardRGB24;
+        op  = PictOpSrc;
+        goto get_pic_fmt;
+    case GST_VIDEO_FORMAT_ARGB:
+        fmt = PictStandardARGB32;
+        op  = PictOpOver;
+    get_pic_fmt:
+        GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
+        pic_fmt = XRenderFindStandardFormat(dpy, fmt);
+        GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
+        break;
+    default:
+        pic_fmt = NULL;
+        break;
+    }
+    if (!pic_fmt)
+        return FALSE;
+
+    GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
+    do {
+        const double sx = (double)src_rect->width / dst_rect->width;
+        const double sy = (double)src_rect->height / dst_rect->height;
+        XTransform xform;
+
+        picture = XRenderCreatePicture(dpy, pix, pic_fmt, 0, NULL);
+        if (!picture)
+            break;
+
+        xform.matrix[0][0] = XDoubleToFixed(sx);
+        xform.matrix[0][1] = XDoubleToFixed(0.0);
+        xform.matrix[0][2] = XDoubleToFixed(src_rect->x);
+        xform.matrix[1][0] = XDoubleToFixed(0.0);
+        xform.matrix[1][1] = XDoubleToFixed(sy);
+        xform.matrix[1][2] = XDoubleToFixed(src_rect->y);
+        xform.matrix[2][0] = XDoubleToFixed(0.0);
+        xform.matrix[2][1] = XDoubleToFixed(0.0);
+        xform.matrix[2][2] = XDoubleToFixed(1.0);
+        XRenderSetPictureTransform(dpy, picture, &xform);
+
+        XRenderComposite(dpy, op, picture, None, priv->picture,
+            0, 0, 0, 0, dst_rect->x, dst_rect->y,
+            dst_rect->width, dst_rect->height);
+        XSync(dpy, False);
+        success = TRUE;
+    } while (0);
+    if (picture)
+        XRenderFreePicture(dpy, picture);
+    GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
+    return success;
+#endif
+    return FALSE;
+}
+
+static gboolean
+gst_vaapi_window_x11_render_pixmap(
+    GstVaapiWindow          *window,
+    GstVaapiPixmap          *pixmap,
+    const GstVaapiRectangle *src_rect,
+    const GstVaapiRectangle *dst_rect
+)
+{
+    GstVaapiWindowX11Private * const priv =
+        GST_VAAPI_WINDOW_X11_GET_PRIVATE(window);
+
+    if (priv->has_xrender)
+        return gst_vaapi_window_x11_render_pixmap_xrender(window, pixmap,
+            src_rect, dst_rect);
+
+    /* XXX: only X RENDER extension is supported for now */
+    return FALSE;
+}
+
 void
 gst_vaapi_window_x11_class_init(GstVaapiWindowX11Class *klass)
 {
@@ -452,6 +575,7 @@ gst_vaapi_window_x11_class_init(GstVaapiWindowX11Class *klass)
     window_class->set_fullscreen = gst_vaapi_window_x11_set_fullscreen;
     window_class->resize         = gst_vaapi_window_x11_resize;
     window_class->render         = gst_vaapi_window_x11_render;
+    window_class->render_pixmap  = gst_vaapi_window_x11_render_pixmap;
 }
 
 #define gst_vaapi_window_x11_finalize \
index 2622ac8..c5bebb6 100644 (file)
 
 #include "gstvaapiwindow_priv.h"
 
+#ifdef HAVE_XRENDER
+# include <X11/extensions/Xrender.h>
+#endif
+
 G_BEGIN_DECLS
 
 #define GST_VAAPI_WINDOW_X11_GET_PRIVATE(obj) \
@@ -42,8 +46,12 @@ typedef struct _GstVaapiWindowX11Class          GstVaapiWindowX11Class;
 struct _GstVaapiWindowX11Private {
     Atom                atom_NET_WM_STATE;
     Atom                atom_NET_WM_STATE_FULLSCREEN;
+#ifdef HAVE_XRENDER
+    Picture             picture;
+#endif
     guint               is_mapped               : 1;
     guint               fullscreen_on_map       : 1;
+    guint               has_xrender             : 1;
 };
 
 /**