x11: implement pixmap rendering with RENDER extension.

Use hardware accelerated XRenderComposite() function, from the RENDER
extension, to blit a pixmap to screen. Besides, this can also support
cropping and scaling.
This commit is contained in:
Gwenole Beauchesne 2013-07-22 09:00:38 +02:00
parent 373329e6ff
commit 0af0849a92
6 changed files with 176 additions and 5 deletions

View 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

View 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)

View file

@ -36,6 +36,10 @@
# 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;
}

View 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;
};

View 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 \

View file

@ -25,6 +25,10 @@
#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;
};
/**