display: use VA display cache for X11 and GLX winsys.

This commit is contained in:
Gwenole Beauchesne 2012-01-12 15:03:04 +01:00
parent 773272475f
commit 9516f00f8e
5 changed files with 188 additions and 27 deletions

View file

@ -25,6 +25,7 @@
*/
#include "config.h"
#include <string.h>
#include "gstvaapiutils.h"
#include "gstvaapidisplay.h"
#include "gstvaapidisplay_priv.h"
@ -50,6 +51,22 @@ enum {
PROP_HEIGHT
};
static inline GstVaapiDisplayCache *
get_display_cache(void)
{
static GstVaapiDisplayCache *g_display_cache = NULL;
if (!g_display_cache)
g_display_cache = gst_vaapi_display_cache_new();
return g_display_cache;
}
GstVaapiDisplayCache *
gst_vaapi_display_get_cache(void)
{
return get_display_cache();
}
/* Append GstVaapiImageFormat to formats array */
static inline void
append_format(GArray *formats, GstVaapiImageFormat format)
@ -281,7 +298,8 @@ gst_vaapi_display_destroy(GstVaapiDisplay *display)
}
if (priv->display) {
vaTerminate(priv->display);
if (!priv->parent)
vaTerminate(priv->display);
priv->display = NULL;
}
@ -290,12 +308,20 @@ gst_vaapi_display_destroy(GstVaapiDisplay *display)
if (klass->close_display)
klass->close_display(display);
}
if (priv->parent) {
g_object_unref(priv->parent);
priv->parent = NULL;
}
gst_vaapi_display_cache_remove(get_display_cache(), display);
}
static gboolean
gst_vaapi_display_create(GstVaapiDisplay *display)
{
GstVaapiDisplayPrivate * const priv = display->priv;
GstVaapiDisplayCache *cache;
gboolean has_errors = TRUE;
VAProfile *profiles = NULL;
VAEntrypoint *entrypoints = NULL;
@ -303,16 +329,21 @@ gst_vaapi_display_create(GstVaapiDisplay *display)
unsigned int *flags = NULL;
gint i, j, n, num_entrypoints, major_version, minor_version;
VAStatus status;
GstVaapiDisplayInfo info;
const GstVaapiDisplayInfo *cached_info = NULL;
if (!priv->display && priv->create_display) {
memset(&info, 0, sizeof(info));
info.display = display;
if (priv->display)
info.va_display = priv->display;
else if (priv->create_display) {
GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS(display);
if (klass->open_display && !klass->open_display(display))
return FALSE;
if (klass->get_display) {
priv->display = klass->get_display(display);
if (!priv->display)
return FALSE;
}
if (!klass->get_display || !klass->get_display(display, &info))
return FALSE;
priv->display = info.va_display;
if (klass->get_size)
klass->get_size(display, &priv->width, &priv->height);
if (klass->get_size_mm)
@ -322,10 +353,25 @@ gst_vaapi_display_create(GstVaapiDisplay *display)
if (!priv->display)
return FALSE;
status = vaInitialize(priv->display, &major_version, &minor_version);
if (!vaapi_check_status(status, "vaInitialize()"))
goto end;
GST_DEBUG("VA-API version %d.%d", major_version, minor_version);
cache = get_display_cache();
if (!cache)
return FALSE;
cached_info = gst_vaapi_display_cache_lookup_by_va_display(
cache,
info.va_display
);
if (cached_info) {
if (priv->parent)
g_object_unref(priv->parent);
priv->parent = g_object_ref(cached_info->display);
}
if (!priv->parent) {
status = vaInitialize(priv->display, &major_version, &minor_version);
if (!vaapi_check_status(status, "vaInitialize()"))
goto end;
GST_DEBUG("VA-API version %d.%d", major_version, minor_version);
}
/* VA profiles */
profiles = g_new(VAProfile, vaMaxNumProfiles(priv->display));
@ -419,6 +465,11 @@ gst_vaapi_display_create(GstVaapiDisplay *display)
append_formats(priv->subpicture_formats, formats, n);
g_array_sort(priv->subpicture_formats, compare_rgb_formats);
if (!cached_info) {
if (!gst_vaapi_display_cache_add(cache, &info))
goto end;
}
has_errors = FALSE;
end:
g_free(profiles);
@ -431,13 +482,21 @@ end:
static void
gst_vaapi_display_lock_default(GstVaapiDisplay *display)
{
g_static_rec_mutex_lock(&display->priv->mutex);
GstVaapiDisplayPrivate *priv = display->priv;
if (priv->parent)
priv = priv->parent->priv;
g_static_rec_mutex_lock(&priv->mutex);
}
static void
gst_vaapi_display_unlock_default(GstVaapiDisplay *display)
{
g_static_rec_mutex_unlock(&display->priv->mutex);
GstVaapiDisplayPrivate *priv = display->priv;
if (priv->parent)
priv = priv->parent->priv;
g_static_rec_mutex_unlock(&priv->mutex);
}
static void
@ -562,6 +621,7 @@ gst_vaapi_display_init(GstVaapiDisplay *display)
GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE(display);
display->priv = priv;
priv->parent = NULL;
priv->display = NULL;
priv->width = 0;
priv->height = 0;
@ -590,6 +650,16 @@ gst_vaapi_display_init(GstVaapiDisplay *display)
GstVaapiDisplay *
gst_vaapi_display_new_with_display(VADisplay va_display)
{
GstVaapiDisplayCache * const cache = get_display_cache();
const GstVaapiDisplayInfo *info;
g_return_val_if_fail(va_display != NULL, NULL);
g_return_val_if_fail(cache != NULL, NULL);
info = gst_vaapi_display_cache_lookup_by_va_display(cache, va_display);
if (info)
return g_object_ref(info->display);
return g_object_new(GST_VAAPI_TYPE_DISPLAY,
"display", va_display,
NULL);

View file

@ -95,7 +95,7 @@ struct _GstVaapiDisplay {
* @unlock: (optional) virtual function to unlock a display
* @sync: (optional) virtual function to sync a display
* @flush: (optional) virtual function to flush pending requests of a display
* @get_display: virtual function to retrieve the #VADisplay
* @get_display: virtual function to retrieve the #GstVaapiDisplayInfo
* @get_size: virtual function to retrieve the display dimensions, in pixels
* @get_size_mm: virtual function to retrieve the display dimensions, in millimeters
*
@ -112,7 +112,8 @@ struct _GstVaapiDisplayClass {
void (*unlock) (GstVaapiDisplay *display);
void (*sync) (GstVaapiDisplay *display);
void (*flush) (GstVaapiDisplay *display);
VADisplay (*get_display) (GstVaapiDisplay *display);
gboolean (*get_display) (GstVaapiDisplay *display,
GstVaapiDisplayInfo *info);
void (*get_size) (GstVaapiDisplay *display,
guint *pwidth, guint *pheight);
void (*get_size_mm) (GstVaapiDisplay *display,

View file

@ -46,10 +46,19 @@ gst_vaapi_display_glx_finalize(GObject *object)
G_OBJECT_CLASS(gst_vaapi_display_glx_parent_class)->finalize(object);
}
static VADisplay
gst_vaapi_display_glx_get_va_display(GstVaapiDisplay *display)
static gboolean
gst_vaapi_display_glx_get_display_info(
GstVaapiDisplay *display,
GstVaapiDisplayInfo *info
)
{
return vaGetDisplayGLX(GST_VAAPI_DISPLAY_XDISPLAY(display));
GstVaapiDisplayClass * const dpy_class =
GST_VAAPI_DISPLAY_CLASS(gst_vaapi_display_glx_parent_class);
info->va_display = vaGetDisplayGLX(GST_VAAPI_DISPLAY_XDISPLAY(display));
if (!info->va_display)
return FALSE;
return dpy_class->get_display(display, info);
}
static void
@ -59,7 +68,7 @@ gst_vaapi_display_glx_class_init(GstVaapiDisplayGLXClass *klass)
GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
object_class->finalize = gst_vaapi_display_glx_finalize;
dpy_class->get_display = gst_vaapi_display_glx_get_va_display;
dpy_class->get_display = gst_vaapi_display_glx_get_display_info;
}
static void

View file

@ -23,6 +23,7 @@
#define GST_VAAPI_DISPLAY_PRIV_H
#include <gst/vaapi/gstvaapidisplay.h>
#include <gst/vaapi/gstvaapidisplaycache.h>
G_BEGIN_DECLS
@ -70,6 +71,7 @@ G_BEGIN_DECLS
* Base class for VA displays.
*/
struct _GstVaapiDisplayPrivate {
GstVaapiDisplay *parent;
GStaticRecMutex mutex;
VADisplay display;
guint width;
@ -85,6 +87,9 @@ struct _GstVaapiDisplayPrivate {
guint create_display : 1;
};
GstVaapiDisplayCache *
gst_vaapi_display_get_cache(void);
G_END_DECLS
#endif /* GST_VAAPI_DISPLAY_PRIV_H */

View file

@ -25,6 +25,7 @@
*/
#include "config.h"
#include <string.h>
#include "gstvaapiutils.h"
#include "gstvaapidisplay_priv.h"
#include "gstvaapidisplay_x11.h"
@ -46,6 +47,40 @@ enum {
PROP_X11_SCREEN
};
static inline const gchar *
get_default_display_name(void)
{
static const gchar *g_display_name;
if (!g_display_name)
g_display_name = getenv("DISPLAY");
return g_display_name;
}
static gboolean
compare_display_name(gconstpointer a, gconstpointer b, gpointer user_data)
{
const gchar *display_name;
/* XXX: handle screen number? */
if (a && b)
return strcmp(a, b) == 0;
/* Match "" or default display name */
if (a)
display_name = a;
else if (b)
display_name = b;
else
return TRUE;
if (*display_name == '\0')
return TRUE;
if (strcmp(display_name, get_default_display_name()) == 0)
return TRUE;
return FALSE;
}
static void
gst_vaapi_display_x11_finalize(GObject *object)
{
@ -139,13 +174,29 @@ static void
gst_vaapi_display_x11_constructed(GObject *object)
{
GstVaapiDisplayX11 * const display = GST_VAAPI_DISPLAY_X11(object);
GstVaapiDisplayX11Private * const priv = display->priv;
GstVaapiDisplayCache * const cache = gst_vaapi_display_get_cache();
const GstVaapiDisplayInfo *info;
GObjectClass *parent_class;
display->priv->create_display = display->priv->x11_display == NULL;
priv->create_display = priv->x11_display == NULL;
/* Don't create X11 display if there is one in the cache already */
if (priv->create_display) {
info = gst_vaapi_display_cache_lookup_by_name(
cache,
priv->display_name,
compare_display_name, NULL
);
if (info) {
priv->x11_display = info->native_display;
priv->create_display = FALSE;
}
}
/* Reset display-name if the user provided his own X11 display */
if (!display->priv->create_display)
set_display_name(display, XDisplayString(display->priv->x11_display));
if (!priv->create_display)
set_display_name(display, XDisplayString(priv->x11_display));
parent_class = G_OBJECT_CLASS(gst_vaapi_display_x11_parent_class);
if (parent_class->constructed)
@ -158,7 +209,6 @@ gst_vaapi_display_x11_open_display(GstVaapiDisplay *display)
GstVaapiDisplayX11Private * const priv =
GST_VAAPI_DISPLAY_X11(display)->priv;
/* XXX: maintain an X11 display cache */
if (priv->create_display) {
priv->x11_display = XOpenDisplay(priv->display_name);
if (!priv->x11_display)
@ -217,10 +267,36 @@ gst_vaapi_display_x11_flush(GstVaapiDisplay *display)
}
}
static VADisplay
gst_vaapi_display_x11_get_va_display(GstVaapiDisplay *display)
static gboolean
gst_vaapi_display_x11_get_display_info(
GstVaapiDisplay *display,
GstVaapiDisplayInfo *info
)
{
return vaGetDisplay(GST_VAAPI_DISPLAY_XDISPLAY(display));
GstVaapiDisplayX11Private * const priv =
GST_VAAPI_DISPLAY_X11(display)->priv;
GstVaapiDisplayCache *cache;
const GstVaapiDisplayInfo *cached_info;
/* Return any cached info even if child has its own VA display */
cache = gst_vaapi_display_get_cache();
if (!cache)
return FALSE;
cached_info = gst_vaapi_display_cache_lookup_by_native_display(cache, priv->x11_display);
if (cached_info) {
*info = *cached_info;
return TRUE;
}
/* Otherwise, create VA display if there is none already */
info->native_display = priv->x11_display;
info->display_name = priv->display_name;
if (!info->va_display) {
info->va_display = vaGetDisplay(priv->x11_display);
if (!info->va_display)
return FALSE;
}
return TRUE;
}
static void
@ -280,7 +356,7 @@ gst_vaapi_display_x11_class_init(GstVaapiDisplayX11Class *klass)
dpy_class->close_display = gst_vaapi_display_x11_close_display;
dpy_class->sync = gst_vaapi_display_x11_sync;
dpy_class->flush = gst_vaapi_display_x11_flush;
dpy_class->get_display = gst_vaapi_display_x11_get_va_display;
dpy_class->get_display = gst_vaapi_display_x11_get_display_info;
dpy_class->get_size = gst_vaapi_display_x11_get_size;
dpy_class->get_size_mm = gst_vaapi_display_x11_get_size_mm;