display: use VA display cache for X11 and GLX winsys.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Thu, 12 Jan 2012 14:03:04 +0000 (15:03 +0100)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Thu, 12 Jan 2012 15:09:08 +0000 (16:09 +0100)
gst-libs/gst/vaapi/gstvaapidisplay.c
gst-libs/gst/vaapi/gstvaapidisplay.h
gst-libs/gst/vaapi/gstvaapidisplay_glx.c
gst-libs/gst/vaapi/gstvaapidisplay_priv.h
gst-libs/gst/vaapi/gstvaapidisplay_x11.c

index b4da162..0d2cff0 100644 (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;
+
+    memset(&info, 0, sizeof(info));
+    info.display = display;
 
-    if (!priv->display && priv->create_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);
index 0517e42..616f743 100644 (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,
index 660d757..cd74789 100644 (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
index 5f2ff14..76b58a7 100644 (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 */
index de98a00..36b0a99 100644 (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;