glcontext: add support for influencing the backing configuration
authorMatthew Waters <matthew@centricular.com>
Tue, 8 Sep 2020 06:27:03 +0000 (16:27 +1000)
committerMatthew Waters <matthew@centricular.com>
Thu, 13 May 2021 06:44:28 +0000 (16:44 +1000)
New API:
- gst_gl_context_get_config()
- gst_gl_context_request_config()

A GL context configuration is a GstStructure that has some well-known
names for common values that can also be extended in platform-specific
ways if necessary.

Wrapped OpenGL contexts may be able to retrieve the GL context
configuration depending on the platform.  If that information is
available, GstGLContext will attempt to create an context that matches
the shared OpenGL context config unless gst_gl_context_request_config()
has been called.

A new environment variable 'GST_GL_CONFIG' will be read to influence the
configuration chosen.  The environment variable will only be used as a
fallback if gst_gl_context_request_config() has not been called.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/809>

14 files changed:
gst-libs/gst/gl/cocoa/gstglcontext_cocoa.m
gst-libs/gst/gl/eagl/gstglcontext_eagl.m
gst-libs/gst/gl/egl/gstglcontext_egl.c
gst-libs/gst/gl/egl/gstglcontext_egl.h
gst-libs/gst/gl/gl.h
gst-libs/gst/gl/gstglcontext.c
gst-libs/gst/gl/gstglcontext.h
gst-libs/gst/gl/gstglcontext_private.h
gst-libs/gst/gl/gstglcontextconfig.c [new file with mode: 0644]
gst-libs/gst/gl/gstglcontextconfig.h [new file with mode: 0644]
gst-libs/gst/gl/meson.build
gst-libs/gst/gl/wgl/gstglcontext_wgl.c
gst-libs/gst/gl/x11/gstglcontext_glx.c
gst-libs/gst/gl/x11/gstglcontext_glx.h

index 595ddc6..3adb0cd 100644 (file)
@@ -39,6 +39,7 @@ static gboolean gst_gl_context_cocoa_activate (GstGLContext * context, gboolean
 static GstGLAPI gst_gl_context_cocoa_get_gl_api (GstGLContext * context);
 static GstGLPlatform gst_gl_context_cocoa_get_gl_platform (GstGLContext * context);
 static void gst_gl_context_cocoa_swap_buffers (GstGLContext * context);
+static GstStructure * gst_gl_context_cocoa_get_config (GstGLContext * context);
 
 GST_DEBUG_CATEGORY_STATIC (gst_gl_context_cocoa_debug);
 #define GST_CAT_DEFAULT gst_gl_context_cocoa_debug
@@ -66,6 +67,8 @@ gst_gl_context_cocoa_class_init (GstGLContextCocoaClass * klass)
       GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_get_gl_api);
   context_class->get_gl_platform =
       GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_get_gl_platform);
+  context_class->get_config =
+      GST_DEBUG_FUNCPTR (gst_gl_context_cocoa_get_config);
 }
 
 static void
@@ -170,6 +173,57 @@ gst_gl_context_cocoa_get_pixel_format (GstGLContextCocoa *context)
   return context->priv->pixel_format;
 }
 
+static GstStructure *
+cgl_pixel_format_to_structure (CGLPixelFormatObj fmt)
+{
+  GstStructure *ret;
+  int val, alpha;
+
+  ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME,
+      GST_GL_CONFIG_STRUCTURE_SET_ARGS(PLATFORM, GstGLPlatform, GST_GL_PLATFORM_CGL),
+      NULL);
+
+  if (CGLDescribePixelFormat (fmt, 0, kCGLPFAAlphaSize, &alpha) != kCGLNoError)
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(ALPHA_SIZE, int, alpha), NULL);
+
+  if (CGLDescribePixelFormat (fmt, 0, kCGLPFADepthSize, &val) != kCGLNoError)
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(DEPTH_SIZE, int, val), NULL);
+
+  if (CGLDescribePixelFormat (fmt, 0, kCGLPFAStencilSize, &val) != kCGLNoError)
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(STENCIL_SIZE, int, val), NULL);
+
+  if (CGLDescribePixelFormat (fmt, 0, kCGLPFAColorSize, &val) != kCGLNoError)
+    goto failure;
+  val -= alpha;
+  if (val % 3 == 0) {
+    /* XXX: assumes that bits are evenly distributed */
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(RED_SIZE, int, val / 3), NULL);
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(GREEN_SIZE, int, val / 3), NULL);
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(BLUE_SIZE, int, val / 3), NULL);
+  } else {
+    GST_WARNING ("Don't know how to split a color size of %u into R,G,B values",
+        val);
+    goto failure;
+  }
+
+  if (CGLDescribePixelFormat (fmt, 0, kCGLPFASamples, &val) != kCGLNoError)
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(SAMPLES, int, val), NULL);
+
+  if (CGLDescribePixelFormat (fmt, 0, kCGLPFASampleBuffers, &val) != kCGLNoError)
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(SAMPLE_BUFFERS, int, val), NULL);
+
+  return ret;
+
+failure:
+  gst_structure_free (ret);
+  return NULL;
+}
+
 static gboolean
 gst_gl_context_cocoa_create_context (GstGLContext *context, GstGLAPI gl_api,
     GstGLContext *other_context, GError **error)
@@ -338,3 +392,13 @@ gst_gl_context_cocoa_get_current_context (void)
 {
   return (guintptr) CGLGetCurrentContext ();
 }
+
+static GstStructure *
+gst_gl_context_cocoa_get_config (GstGLContext * context)
+{
+  GstGLContextCocoa *cocoa = GST_GL_CONTEXT_COCOA (context);
+
+  g_return_val_if_fail (cocoa->priv->pixel_format, NULL);
+
+  return cgl_pixel_format_to_structure (cocoa->priv->pixel_format);
+}
index fe9bba9..b869030 100644 (file)
@@ -50,6 +50,7 @@ static void gst_gl_context_eagl_swap_buffers (GstGLContext * context);
 static GstGLAPI gst_gl_context_eagl_get_gl_api (GstGLContext * context);
 static GstGLPlatform gst_gl_context_eagl_get_gl_platform (GstGLContext *
     context);
+GstStructure *gst_gl_context_eagl_get_config (GstGLContext * context);
 
 struct _GstGLContextEaglPrivate
 {
@@ -87,6 +88,7 @@ gst_gl_context_eagl_class_init (GstGLContextEaglClass * klass)
       GST_DEBUG_FUNCPTR (gst_gl_context_eagl_get_gl_api);
   context_class->get_gl_platform =
       GST_DEBUG_FUNCPTR (gst_gl_context_eagl_get_gl_platform);
+  context_class->get_config = GST_DEBUG_FUNCPTR (gst_gl_context_eagl_get_config);
 }
 
 static void
@@ -108,6 +110,71 @@ gst_gl_context_eagl_new (GstGLDisplay * display)
   return context;
 }
 
+enum EAGLFormat
+{
+  FORMAT_RGBA8 = 1,
+  FORMAT_RGB565,
+};
+
+static GstStructure *
+layer_config_to_structure (GstGLContextEagl *eagl, CAEAGLLayer * layer)
+{
+  GstStructure *ret;
+  NSDictionary *drawableProps = [layer drawableProperties];
+  NSString *color_format;
+  enum EAGLFormat eagl_format = FORMAT_RGBA8;
+
+  ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME,
+      GST_GL_CONFIG_STRUCTURE_SET_ARGS(PLATFORM, GstGLPlatform, GST_GL_PLATFORM_EAGL),
+      NULL);
+
+  color_format = [drawableProps objectForKey:kEAGLDrawablePropertyColorFormat];
+  if (!color_format)
+    color_format = [layer contentsFormat];
+
+  if (!color_format) {
+    GST_WARNING_OBJECT (eagl, "Could not retrieve color format from layer %p", layer);
+    goto failure;
+  }
+
+  if (color_format == kEAGLColorFormatRGBA8 || color_format == kCAContentsFormatRGBA8Uint) {
+    eagl_format = FORMAT_RGBA8;
+  } else if (color_format == kEAGLColorFormatRGB565) {
+    eagl_format = FORMAT_RGB565;
+  } else {
+    GST_WARNING_OBJECT (eagl, "unknown drawable format: %s", [color_format UTF8String]);
+    goto failure;
+  }
+
+  /* XXX: defaults chosen by _update_layer() */
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(DEPTH_SIZE, int, 16), NULL);
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(STENCIL_SIZE, int, 0), NULL);
+
+  switch (eagl_format) {
+    case FORMAT_RGBA8:
+      gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(RED_SIZE, int, 8), NULL);
+      gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(GREEN_SIZE, int, 8), NULL);
+      gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(BLUE_SIZE, int, 8), NULL);
+      gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(ALPHA_SIZE, int, 8), NULL);
+      break;
+    case FORMAT_RGB565:
+      gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(RED_SIZE, int, 5), NULL);
+      gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(GREEN_SIZE, int, 6), NULL);
+      gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(BLUE_SIZE, int, 5), NULL);
+      gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS(ALPHA_SIZE, int, 0), NULL);
+      break;
+    default:
+      GST_WARNING_OBJECT (eagl, "Unhandled format!");
+      goto failure;
+  }
+
+  return ret;
+
+failure:
+  gst_structure_free (ret);
+  return NULL;
+}
+
 void
 gst_gl_context_eagl_resize (GstGLContextEagl * eagl_context)
 {
@@ -167,6 +234,7 @@ gst_gl_context_eagl_update_layer (GstGLContext * context, gpointer layer)
   GstGLContextEagl *context_eagl = GST_GL_CONTEXT_EAGL (context);
   GstGLContextEaglPrivate *priv = context_eagl->priv;
   GstGLWindow *window = gst_gl_context_get_window (context);
+  GstStructure *fmt;
 
   if (!layer || !gst_gl_window_get_window_handle (window)) {
     GST_INFO_OBJECT (context, "window handle not set yet, not updating layer");
@@ -215,6 +283,12 @@ gst_gl_context_eagl_update_layer (GstGLContext * context, gpointer layer)
   priv->color_renderbuffer = color_renderbuffer;
   priv->depth_renderbuffer = depth_renderbuffer;
 
+  fmt = layer_config_to_structure (context_eagl, eagl_layer);
+  if (fmt) {
+    GST_DEBUG_OBJECT (context_eagl, "chosen config %" GST_PTR_FORMAT, fmt);
+    gst_structure_free (fmt);
+  }
+
 out:
   if (window)
     gst_object_unref (window);
@@ -384,3 +458,14 @@ gst_gl_context_eagl_get_current_context (void)
 {
   return (guintptr) [EAGLContext currentContext];
 }
+
+GstStructure *
+gst_gl_context_eagl_get_config (GstGLContext * context)
+{
+  GstGLContextEagl *eagl = GST_GL_CONTEXT_EAGL (context);
+
+  if (!eagl->priv->eagl_layer)
+    return NULL;
+
+  return layer_config_to_structure (eagl, (__bridge CAEAGLLayer *) eagl->priv->eagl_layer);
+}
index 147b7e9..1254fdd 100644 (file)
@@ -30,9 +30,8 @@
 
 #include "gstglcontext_egl.h"
 
+#include <gst/gl/gl.h>
 #include <gst/gl/gstglcontext_private.h>
-#include <gst/gl/gstglfeature.h>
-#include <gst/gl/gstglwindow.h>
 
 #include "gstegl.h"
 #include "../utils/opengl_versions.h"
@@ -74,6 +73,9 @@ static gboolean gst_gl_context_egl_check_feature (GstGLContext * context,
     const gchar * feature);
 static void gst_gl_context_egl_get_gl_platform_version (GstGLContext * context,
     gint * major, gint * minor);
+static GstStructure *gst_gl_context_egl_get_config (GstGLContext * context);
+static gboolean gst_gl_context_egl_request_config (GstGLContext * context,
+    GstStructure * config);
 
 G_DEFINE_TYPE (GstGLContextEGL, gst_gl_context_egl, GST_TYPE_GL_CONTEXT);
 
@@ -105,6 +107,9 @@ gst_gl_context_egl_class_init (GstGLContextEGLClass * klass)
       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_current_context);
   context_class->get_gl_platform_version =
       GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_gl_platform_version);
+  context_class->get_config = GST_DEBUG_FUNCPTR (gst_gl_context_egl_get_config);
+  context_class->request_config =
+      GST_DEBUG_FUNCPTR (gst_gl_context_egl_request_config);
 }
 
 static void
@@ -152,6 +157,226 @@ gst_gl_context_egl_choose_format (GstGLContext * context, GError ** error)
   return TRUE;
 }
 
+static GstGLAPI
+egl_conformant_to_gst (int conformant)
+{
+  GstGLAPI ret = GST_GL_API_NONE;
+
+  if (conformant & EGL_OPENGL_BIT)
+    ret |= GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
+  if (conformant & EGL_OPENGL_ES_BIT)
+    ret |= GST_GL_API_GLES1;
+  if (conformant & EGL_OPENGL_ES2_BIT)
+    ret |= GST_GL_API_GLES2;
+#if defined(EGL_KHR_create_context)
+  if (conformant & EGL_OPENGL_ES3_BIT_KHR)
+    /* FIXME: need another gles3 value? */
+    ret |= GST_GL_API_GLES2;
+#endif
+#if 0
+  if (conformant & EGL_OPENVG_BIT)
+    conformant_values[i++] = "OpenVG";
+#endif
+
+  return ret;
+}
+
+static GstGLConfigSurfaceType
+egl_surface_type_to_gst (int surface)
+{
+  GstGLConfigSurfaceType ret = GST_GL_CONFIG_SURFACE_TYPE_NONE;
+
+  if (surface & EGL_WINDOW_BIT)
+    ret |= GST_GL_CONFIG_SURFACE_TYPE_WINDOW;
+  if (surface & EGL_PBUFFER_BIT)
+    ret |= GST_GL_CONFIG_SURFACE_TYPE_PBUFFER;
+#if 0
+  if (surface & EGL_MULTISAMPLE_RESOLVE_BOX_BIT)
+    surface_values[i++] = "multisample-resolve-box";
+  if (surface & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)
+    surface_values[i++] = "swap-behaviour-preserved";
+  if (surface & EGL_VG_ALPHA_FORMAT_PRE_BIT)
+    surface_values[i++] = "vg-alpha-format-pre";
+  if (surface & EGL_VG_COLORSPACE_LINEAR_BIT)
+    surface_values[i++] = "vg-colorspace-linear";
+#endif
+  return ret;
+}
+
+static GstGLConfigCaveat
+egl_caveat_to_gst (int caveat)
+{
+  switch (caveat) {
+    case EGL_NONE:
+      return GST_GL_CONFIG_CAVEAT_NONE;
+    case EGL_SLOW_CONFIG:
+      return GST_GL_CONFIG_CAVEAT_SLOW;
+    case EGL_NON_CONFORMANT_CONFIG:
+      return GST_GL_CONFIG_CAVEAT_NON_CONFORMANT;
+    default:
+      GST_WARNING ("unknown EGL caveat value %u (0x%x)", caveat, caveat);
+      return GST_GL_CONFIG_CAVEAT_NON_CONFORMANT;
+  }
+}
+
+static GstStructure *
+egl_config_to_structure (EGLDisplay egl_display, EGLConfig config)
+{
+  GstStructure *ret;
+  int val;
+  int buffer_type;
+
+  if (!egl_display)
+    return NULL;
+
+  ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME,
+      GST_GL_CONFIG_STRUCTURE_SET_ARGS (PLATFORM, GstGLPlatform,
+          GST_GL_PLATFORM_EGL), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_CONFIG_ID, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CONFIG_ID, int,
+          val), NULL);
+
+#if 0
+  {
+    /* Don't know how to translate this value, it's platform and implementation
+     * dependant
+     */
+    int native_visual_type;
+    if (!eglGetConfigAttrib (egl_display, config, EGL_NATIVE_VISUAL_TYPE,
+            &native_visual_type))
+      goto failure;
+  }
+#endif
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_NATIVE_VISUAL_ID, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_VISUAL_ID,
+          guint, val), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_NATIVE_RENDERABLE, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_RENDERABLE,
+          gboolean, val), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_CONFORMANT, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CONFORMANT_API,
+          GstGLAPI, egl_conformant_to_gst (val)), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_RENDERABLE_TYPE, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (RENDERABLE_API,
+          GstGLAPI, egl_conformant_to_gst (val)), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_SURFACE_TYPE, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (SURFACE_TYPE,
+          GstGLConfigSurfaceType, egl_surface_type_to_gst (val)), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_CONFIG_CAVEAT, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CAVEAT,
+          GstGLConfigCaveat, egl_caveat_to_gst (val)), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_LEVEL, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (LEVEL, int, val),
+      NULL);
+
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_COLOR_BUFFER_TYPE,
+          &buffer_type))
+    goto failure;
+
+  if (buffer_type == EGL_RGB_BUFFER) {
+    if (!eglGetConfigAttrib (egl_display, config, EGL_RED_SIZE, &val))
+      goto failure;
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (RED_SIZE, int,
+            val), NULL);
+
+    if (!eglGetConfigAttrib (egl_display, config, EGL_GREEN_SIZE, &val))
+      goto failure;
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (GREEN_SIZE, int,
+            val), NULL);
+
+    if (!eglGetConfigAttrib (egl_display, config, EGL_BLUE_SIZE, &val))
+      goto failure;
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (BLUE_SIZE, int,
+            val), NULL);
+
+    if (!eglGetConfigAttrib (egl_display, config, EGL_ALPHA_SIZE, &val))
+      goto failure;
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (ALPHA_SIZE, int,
+            val), NULL);
+  } else if (buffer_type == EGL_LUMINANCE_BUFFER) {
+    if (!eglGetConfigAttrib (egl_display, config, EGL_LUMINANCE_SIZE, &val))
+      goto failure;
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (LUMINANCE_SIZE,
+            int, val), NULL);
+
+    if (!eglGetConfigAttrib (egl_display, config, EGL_ALPHA_SIZE, &val))
+      goto failure;
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (ALPHA_SIZE, int,
+            val), NULL);
+  } else {
+    GST_WARNING ("unknown EGL_COLOR_BUFFER_TYPE value %x", buffer_type);
+    goto failure;
+  }
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_DEPTH_SIZE, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (DEPTH_SIZE, int,
+          val), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_STENCIL_SIZE, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (STENCIL_SIZE, int,
+          val), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_MIN_SWAP_INTERVAL, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MIN_SWAP_INTERVAL,
+          int, val), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_MAX_SWAP_INTERVAL, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_SWAP_INTERVAL,
+          int, val), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_MAX_PBUFFER_WIDTH, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_WIDTH,
+          int, val), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_MAX_PBUFFER_HEIGHT, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_HEIGHT,
+          int, val), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_MAX_PBUFFER_PIXELS, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_PIXELS,
+          int, val), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_SAMPLE_BUFFERS, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (SAMPLE_BUFFERS, int,
+          val), NULL);
+
+  if (!eglGetConfigAttrib (egl_display, config, EGL_SAMPLES, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (SAMPLES, int, val),
+      NULL);
+
+  return ret;
+
+failure:
+  gst_structure_free (ret);
+  return NULL;
+}
+
 static void
 gst_gl_context_egl_dump_config (GstGLContextEGL * egl, EGLConfig config)
 {
@@ -405,7 +630,7 @@ gst_gl_context_egl_choose_config (GstGLContextEGL * egl, GstGLAPI gl_api,
 {
   gboolean create_context;
   EGLint numConfigs;
-  gint i;
+  gint i, n;
   EGLint config_attrib[20];
   EGLint egl_api = 0;
   EGLBoolean ret = EGL_FALSE;
@@ -446,25 +671,57 @@ gst_gl_context_egl_choose_config (GstGLContextEGL * egl, GstGLAPI gl_api,
 
 try_again:
   i = 0;
+  n = G_N_ELEMENTS (config_attrib);
   config_attrib[i++] = EGL_SURFACE_TYPE;
   config_attrib[i++] = surface_type;
   config_attrib[i++] = EGL_RENDERABLE_TYPE;
   config_attrib[i++] = egl_api;
+
+  if (egl->requested_config) {
+#define TRANSFORM_VALUE(GL_CONF_NAME,EGL_ATTR_NAME) \
+  G_STMT_START { \
+    if (gst_structure_has_field_typed (egl->requested_config, \
+          GST_GL_CONFIG_ATTRIB_NAME(GL_CONF_NAME), \
+          GST_GL_CONFIG_ATTRIB_GTYPE(GL_CONF_NAME))) { \
+      int val; \
+      if (gst_structure_get (egl->requested_config, \
+          GST_GL_CONFIG_ATTRIB_NAME(GL_CONF_NAME), \
+          GST_GL_CONFIG_ATTRIB_GTYPE(GL_CONF_NAME), &val, NULL)) { \
+        config_attrib[i++] = EGL_ATTR_NAME; \
+        config_attrib[i++] = (int) val; \
+        g_assert (i <= n); \
+      } \
+    } \
+  } G_STMT_END
+
+    TRANSFORM_VALUE (CONFIG_ID, EGL_CONFIG_ID);
+    TRANSFORM_VALUE (RED_SIZE, EGL_RED_SIZE);
+    TRANSFORM_VALUE (GREEN_SIZE, EGL_GREEN_SIZE);
+    TRANSFORM_VALUE (BLUE_SIZE, EGL_BLUE_SIZE);
+    TRANSFORM_VALUE (ALPHA_SIZE, EGL_ALPHA_SIZE);
+    TRANSFORM_VALUE (DEPTH_SIZE, EGL_DEPTH_SIZE);
+    TRANSFORM_VALUE (STENCIL_SIZE, EGL_STENCIL_SIZE);
+    /* TODO: more values */
+#undef TRANSFORM_VALUE
+  } else {
 #if defined(USE_EGL_RPI) && GST_GL_HAVE_WINDOW_WAYLAND
-  /* The configurations with a=0 seems to be buggy whereas
-   * it works when using dispmanx directly */
-  config_attrib[i++] = EGL_ALPHA_SIZE;
-  config_attrib[i++] = 1;
+    /* The configurations with a=0 seems to be buggy whereas
+     * it works when using dispmanx directly */
+    config_attrib[i++] = EGL_ALPHA_SIZE;
+    config_attrib[i++] = 1;
 #endif
-  config_attrib[i++] = EGL_DEPTH_SIZE;
-  config_attrib[i++] = 16;
-  config_attrib[i++] = EGL_RED_SIZE;
-  config_attrib[i++] = 1;
-  config_attrib[i++] = EGL_GREEN_SIZE;
-  config_attrib[i++] = 1;
-  config_attrib[i++] = EGL_BLUE_SIZE;
-  config_attrib[i++] = 1;
+    config_attrib[i++] = EGL_DEPTH_SIZE;
+    config_attrib[i++] = 16;
+    config_attrib[i++] = EGL_RED_SIZE;
+    config_attrib[i++] = 1;
+    config_attrib[i++] = EGL_GREEN_SIZE;
+    config_attrib[i++] = 1;
+    config_attrib[i++] = EGL_BLUE_SIZE;
+    config_attrib[i++] = 1;
+  }
+
   config_attrib[i++] = EGL_NONE;
+  g_assert (i <= n);
 
   ret = eglChooseConfig (egl->egl_display, config_attrib,
       &egl->egl_config, 1, &numConfigs);
@@ -921,6 +1178,10 @@ gst_gl_context_egl_destroy_context (GstGLContext * context)
     gst_object_unref (egl->display_egl);
     egl->display_egl = NULL;
   }
+
+  if (egl->requested_config)
+    gst_structure_free (egl->requested_config);
+  egl->requested_config = NULL;
 }
 
 static gboolean
@@ -1117,3 +1378,87 @@ gst_gl_context_egl_get_gl_platform_version (GstGLContext * context,
   *major = context_egl->egl_major;
   *minor = context_egl->egl_minor;
 }
+
+static GstStructure *
+gst_gl_context_egl_get_config (GstGLContext * context)
+{
+  GstGLContextEGL *egl = GST_GL_CONTEXT_EGL (context);
+
+  g_return_val_if_fail (egl->egl_config, NULL);
+
+  return egl_config_to_structure (egl->egl_display, egl->egl_config);
+}
+
+static gboolean
+gst_gl_context_egl_request_config (GstGLContext * context,
+    GstStructure * config)
+{
+  GstGLContextEGL *egl = GST_GL_CONTEXT_EGL (context);
+
+  if (egl->requested_config)
+    gst_structure_free (egl->requested_config);
+  egl->requested_config = config;
+
+  return TRUE;
+}
+
+gboolean
+gst_gl_context_egl_fill_info (GstGLContext * context)
+{
+  EGLContext egl_context = (EGLContext) gst_gl_context_get_gl_context (context);
+  GstGLDisplay *display_egl;
+  GstStructure *config;
+  EGLDisplay *egl_display;
+  EGLConfig egl_config;
+  int config_id, n_configs;
+  int attrs[3];
+
+  if (!egl_context) {
+    GST_ERROR_OBJECT (context, "no GLX context");
+    return FALSE;
+  }
+
+  display_egl =
+      GST_GL_DISPLAY (gst_gl_display_egl_from_gl_display (context->display));
+  egl_display = (EGLDisplay) gst_gl_display_get_handle (display_egl);
+
+  if (EGL_TRUE != eglQueryContext (egl_display, egl_context, EGL_CONFIG_ID,
+          &config_id)) {
+    GST_WARNING_OBJECT (context,
+        "could not retrieve egl config id from egl context: %s",
+        gst_egl_get_error_string (eglGetError ()));
+    goto failure;
+  }
+
+  attrs[0] = EGL_CONFIG_ID;
+  attrs[1] = config_id;
+  attrs[2] = EGL_NONE;
+
+  if (EGL_TRUE != eglChooseConfig (egl_display, attrs, &egl_config, 1,
+          &n_configs) || n_configs <= 0) {
+    GST_WARNING_OBJECT (context,
+        "could not retrieve egl config from its ID 0x%x. "
+        "Wrong EGLDisplay or context?", config_id);
+    goto failure;
+  }
+
+  config = egl_config_to_structure (egl_display, egl_config);
+  if (!config) {
+    GST_WARNING_OBJECT (context, "could not transform config id 0x%x into "
+        "GstStructure", config_id);
+    goto failure;
+  }
+
+  GST_INFO_OBJECT (context, "found config %" GST_PTR_FORMAT, config);
+
+  g_object_set_data_full (G_OBJECT (context),
+      GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME, config,
+      (GDestroyNotify) gst_structure_free);
+
+  gst_object_unref (display_egl);
+  return TRUE;
+
+failure:
+  gst_object_unref (display_egl);
+  return FALSE;
+}
index 5dec857..6d9a8a7 100644 (file)
@@ -67,6 +67,8 @@ struct _GstGLContextEGL
 
   /* Cached handle */
   guintptr window_handle;
+
+  GstStructure *requested_config;
 };
 
 /**
@@ -89,6 +91,9 @@ guintptr            gst_gl_context_egl_get_current_context  (void);
 G_GNUC_INTERNAL
 gpointer            gst_gl_context_egl_get_proc_address     (GstGLAPI gl_api, const gchar * name);
 
+G_GNUC_INTERNAL
+gboolean            gst_gl_context_egl_fill_info            (GstGLContext * context);
+
 G_END_DECLS
 
 #endif /* __GST_GL_CONTEXT_EGL_H__ */
index 5246abb..6c7a37f 100644 (file)
@@ -26,6 +26,7 @@
 #include <gst/gl/gstglapi.h>
 #include <gst/gl/gstglconfig.h>
 #include <gst/gl/gstglcontext.h>
+#include <gst/gl/gstglcontextconfig.h>
 #include <gst/gl/gstgldebug.h>
 #include <gst/gl/gstgldisplay.h>
 #include <gst/gl/gstglfeature.h>
index 4278d0b..115bbd0 100644 (file)
  * #GstGLContext wraps an OpenGL context object in a uniform API.  As a result
  * of the limitation on OpenGL context, this object is not thread safe unless
  * specified and must only be activated in a single thread.
+ *
+ * Environment variables:
+ * - `GST_GL_API`: select which OpenGL API to create and OpenGL context for.
+ *                 Depending on the platform, the available values are
+ *                 'opengl', 'opengl3' (core profile), and 'gles2'.  See the
+ *                 the #GstGLAPI enumeration for more details.
+ * - `GST_GL_PLATFORM`: select which OpenGL platform to create an OpenGL
+ *                      context with.  Depending on the platform and the
+ *                      dependencies available build-time, the available values
+ *                      are, 'glx', 'egl', 'cgl', 'wgl', and 'eagl'
+ * - `GST_GL_CONFIG`: select the configuration used for creating the OpenGL
+ *                    context and OpenGL surface.  Written out as a GstStructure
+ *                    that has been serialized to string.  e.g.
+ *                    `GST_GL_CONFIG="gst-gl-context-config,red-size=8,green-size=8,blue-size=8,alpha-size=8,depth-size=16"`.
+ *                    Not all platforms will support the same level of
+ *                    functionality.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -215,6 +231,7 @@ struct _GstGLContextPrivate
   gint gl_minor;
 
   gchar *gl_exts;
+  GstStructure *requested_config;
 };
 
 typedef struct
@@ -235,17 +252,9 @@ typedef struct
 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstGLContext, gst_gl_context,
     GST_TYPE_OBJECT);
 
-#define GST_TYPE_GL_WRAPPED_CONTEXT (gst_gl_wrapped_context_get_type())
-static GType gst_gl_wrapped_context_get_type (void);
 G_DEFINE_TYPE (GstGLWrappedContext, gst_gl_wrapped_context,
     GST_TYPE_GL_CONTEXT);
 
-#define GST_GL_WRAPPED_CONTEXT(o)           (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_GL_WRAPPED_CONTEXT, GstGLWrappedContext))
-#define GST_GL_WRAPPED_CONTEXT_CLASS(k)     (G_TYPE_CHECK_CLASS((k), GST_TYPE_GL_CONTEXT, GstGLContextClass))
-#define GST_IS_GL_WRAPPED_CONTEXT(o)        (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_GL_WRAPPED_CONTEXT))
-#define GST_IS_GL_WRAPPED_CONTEXT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_GL_WRAPPED_CONTEXT))
-#define GST_GL_WRAPPED_CONTEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_GL_WRAPPED_CONTEXT, GstGLWrappedContextClass))
-
 /**
  * gst_gl_context_error_quark:
  *
@@ -727,6 +736,10 @@ gst_gl_context_finalize (GObject * object)
     context->gl_vtable = NULL;
   }
 
+  if (context->priv->requested_config)
+    gst_structure_free (context->priv->requested_config);
+  context->priv->requested_config = NULL;
+
   g_mutex_clear (&context->priv->render_lock);
 
   g_cond_clear (&context->priv->create_cond);
@@ -1018,8 +1031,19 @@ gst_gl_context_can_share (GstGLContext * context, GstGLContext * other_context)
  * to share shareable OpenGL objects with.  See the OpenGL specification for
  * what is shared between OpenGL contexts.
  *
- * If an error occurs, and @error is not %NULL, then error will contain details
- * of the error and %FALSE will be returned.
+ * Since 1.20, the configuration can be overriden with the environment variable
+ * `GST_GL_CONFIG` which is a stringified #GstStructure as would be returned
+ * from gst_gl_context_get_config().  If `GST_GL_CONFIG` is not set, then the
+ * config will be chosen from @other_context by calling
+ * gst_gl_context_get_config() on @other_context.  Otherwise, a default
+ * configuration is used.
+ *
+ * Calling gst_gl_context_request_config()) before calling
+ * gst_gl_context_create() will override the config from @other_context but
+ * will not override the `GST_GL_CONFIG` environment variable.
+ *
+ * If an error occurs, and @error is not %NULL, then @error will contain
+ * details of the error and %FALSE will be returned.
  *
  * Should only be called once.
  *
@@ -1190,6 +1214,7 @@ gst_gl_context_create_thread (GstGLContext * context)
   const gchar *user_choice;
   GError **error;
   GstGLContext *other_context;
+  GstStructure *config;
 
   g_mutex_lock (&context->priv->render_lock);
 
@@ -1237,6 +1262,44 @@ gst_gl_context_create_thread (GstGLContext * context)
     goto failure;
   }
 
+  {
+    const gchar *config_str = g_getenv ("GST_GL_CONFIG");
+    if (config_str) {
+      GstStructure *config = gst_structure_from_string (config_str, NULL);
+      if (!config) {
+        g_set_error (error, GST_GL_CONTEXT_ERROR,
+            GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
+            "could not construct OpenGL config from the \'GST_GL_CONFIG\' "
+            "environment variable");
+        g_free (compiled_api_s);
+        g_free (user_api_s);
+        g_free (display_api_s);
+        goto failure;
+      }
+      if (!gst_gl_context_request_config (context, gst_structure_copy (config))) {
+        GST_WARNING_OBJECT (context,
+            "failed to request config %" GST_PTR_FORMAT, config);
+      } else {
+        GST_INFO_OBJECT (context, "requesting config from environment %"
+            GST_PTR_FORMAT, config);
+      }
+      gst_structure_free (config);
+    } else if (other_context && !context->priv->requested_config) {
+      GstStructure *config = gst_gl_context_get_config (other_context);
+      if (config) {
+        if (!gst_gl_context_request_config (context,
+                gst_structure_copy (config))) {
+          GST_WARNING_OBJECT (context,
+              "failed to request config %" GST_PTR_FORMAT, config);
+        } else {
+          GST_INFO_OBJECT (context, "requesting config from other context %"
+              GST_PTR_FORMAT " %" GST_PTR_FORMAT, other_context, config);
+        }
+        gst_structure_free (config);
+      }
+    }
+  }
+
   if (context_class->choose_format &&
       !context_class->choose_format (context, error)) {
     GST_WARNING_OBJECT (context, "Failed to choose format");
@@ -1279,6 +1342,11 @@ gst_gl_context_create_thread (GstGLContext * context)
   api_string = gst_gl_api_to_string (gl_api);
   GST_INFO_OBJECT (context, "available GL APIs: %s", api_string);
 
+  if ((config = gst_gl_context_get_config (context))) {
+    GST_DEBUG_OBJECT (context, "Chosen config %" GST_PTR_FORMAT, config);
+    gst_structure_free (config);
+  }
+
   if (((compiled_api & gl_api & display_api) & user_api) == GST_GL_API_NONE) {
     g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API,
         "failed to create context, context "
@@ -1472,6 +1540,20 @@ gst_gl_context_fill_info (GstGLContext * context, GError ** error)
     gl->IsVertexArray = NULL;
   }
 
+  if (GST_IS_GL_WRAPPED_CONTEXT (context)) {
+    /* XXX: vfunc? */
+#if GST_GL_HAVE_PLATFORM_GLX
+    if (gst_gl_context_get_gl_platform (context) == GST_GL_PLATFORM_GLX
+        && !gst_gl_context_glx_fill_info (context))
+      goto failure;
+#endif
+#if GST_GL_HAVE_PLATFORM_EGL
+    if (gst_gl_context_get_gl_platform (context) == GST_GL_PLATFORM_EGL
+        && !gst_gl_context_egl_fill_info (context))
+      goto failure;
+#endif
+  }
+
   return TRUE;
 
 failure:
@@ -1807,6 +1889,85 @@ gst_gl_context_swap_buffers (GstGLContext * context)
   context_class->swap_buffers (context);
 }
 
+/**
+ * gst_gl_context_get_config:
+ * @context: the #GstGLContext
+ *
+ * Retrieve the OpenGL configuration for this context.  The context must
+ * have been successfully created for this function to return a valid value.
+ *
+ * Not all implementations currently support retrieving the config and will
+ * return %NULL when not supported.
+ *
+ * Returns: (transfer full) (nullable): the configuration chosen for this OpenGL context.
+ *
+ * Since: 1.20
+ */
+GstStructure *
+gst_gl_context_get_config (GstGLContext * context)
+{
+  GstGLContextClass *context_class;
+
+  g_return_val_if_fail (GST_IS_GL_CONTEXT (context), NULL);
+  context_class = GST_GL_CONTEXT_GET_CLASS (context);
+  if (!context_class->get_config) {
+    GST_FIXME_OBJECT (context, "does not support retrieving a config");
+    return NULL;
+  }
+
+  return context_class->get_config (context);
+}
+
+/**
+ * gst_gl_context_request_config:
+ * @context: the #GstGLContext
+ * @gl_config: (nullable) (transfer full): a configuration structure for
+ *             configuring the OpenGL context
+ *
+ * Set the OpenGL configuration for this context.  The context must not
+ * have been created for this function to succeed.  Setting a %NULL
+ * @config has the affect of removing any specific configuration request.
+ *
+ * Not all implementations currently support retrieving the config and this
+ * function will return FALSE when not supported.
+ *
+ * Note that calling this function may cause a subsequent
+ * gst_gl_context_create() to fail if @config could not be matched with
+ * the platform-specific configuration.
+ *
+ * Note that the actual config used may be differ from the requested values.
+ *
+ * Returns: whether @gl_config could be successfully set on @context
+ *
+ * Since: 1.20
+ */
+gboolean
+gst_gl_context_request_config (GstGLContext * context, GstStructure * gl_config)
+{
+  GstGLContextClass *context_class;
+  gboolean ret;
+
+  g_return_val_if_fail (GST_IS_GL_CONTEXT (context), FALSE);
+  g_return_val_if_fail (context->priv->created == FALSE, FALSE);
+  context_class = GST_GL_CONTEXT_GET_CLASS (context);
+  if (!context_class->request_config) {
+    gst_structure_free (gl_config);
+    GST_FIXME_OBJECT (context, "does not support requesting a config");
+    return FALSE;
+  }
+
+  ret = context_class->request_config (context, gst_structure_copy (gl_config));
+  if (ret) {
+    if (context->priv->requested_config)
+      gst_structure_free (context->priv->requested_config);
+    context->priv->requested_config = gl_config;
+  } else {
+    gst_structure_free (gl_config);
+  }
+
+  return ret;
+}
+
 static GstGLAPI
 gst_gl_wrapped_context_get_gl_api (GstGLContext * context)
 {
@@ -1850,6 +2011,37 @@ gst_gl_wrapped_context_activate (GstGLContext * context, gboolean activate)
   return TRUE;
 }
 
+static gpointer
+_structure_copy_if_set (gpointer data, gpointer user_data)
+{
+  GstStructure *ret = NULL;
+
+  if (data)
+    ret = gst_structure_copy (data);
+  return ret;
+}
+
+static GstStructure *
+gst_gl_wrapped_context_get_config (GstGLContext * context)
+{
+  GstStructure *ret;
+
+  ret = g_object_dup_data (G_OBJECT (context),
+      GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME,
+      (GDuplicateFunc) _structure_copy_if_set, NULL);
+  if (ret) {
+    GST_DEBUG_OBJECT (context, "wrapped context found config %" GST_PTR_FORMAT,
+        ret);
+    return ret;
+  } else {
+    GST_FIXME_OBJECT (context, "wrapped context could not retrieve config. "
+        "The application may be missing a call to gst_gl_context_fill_info() "
+        "or the specific platform implemention is not implemented for "
+        "retrieving the config from a wrapped OpenGL context.");
+    return NULL;
+  }
+}
+
 static void
 gst_gl_wrapped_context_class_init (GstGLWrappedContextClass * klass)
 {
@@ -1862,6 +2054,8 @@ gst_gl_wrapped_context_class_init (GstGLWrappedContextClass * klass)
   context_class->get_gl_platform =
       GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_gl_platform);
   context_class->activate = GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_activate);
+  context_class->get_config =
+      GST_DEBUG_FUNCPTR (gst_gl_wrapped_context_get_config);
 }
 
 static void
index 007a6fb..9c1b5d8 100644 (file)
@@ -117,6 +117,34 @@ struct _GstGLContext {
  * @destroy_context: destroy the OpenGL context
  * @swap_buffers: swap the default framebuffer's front/back buffers
  */
+/**
+ * GstGLContextClass::get_config:
+ * @context: the #GstGLContext
+ *
+ * Retrieve the configuration in use by this context.  See also
+ * gst_gl_context_get_config().
+ *
+ * Returns: (transfer full) (nullable): the configuration chosen for this
+ *          #GstGLContext
+ *
+ * Since: 1.20
+ */
+/**
+ * GstGLContextClass::request_config:
+ * @context: the #GstGLContext
+ * @gl_config: (nullable) (transfer full): a configuration structure for
+ *             configuring on @context
+ *
+ * Request a configuration for this @context to use.
+ *
+ * Unknown fields within @gl_config should be ignored by subclasses.
+ *
+ * See also gst_gl_context_request_config().
+ *
+ * Returns: Whether @gl_config could be successfull set on @context.
+ *
+ * Since: 1.20
+ */
 struct _GstGLContextClass {
   GstObjectClass parent_class;
 
@@ -133,9 +161,11 @@ struct _GstGLContextClass {
   void          (*swap_buffers)       (GstGLContext *context);
   gboolean      (*check_feature)      (GstGLContext *context, const gchar *feature);
   void          (*get_gl_platform_version) (GstGLContext *context, gint *major, gint *minor);
+  GstStructure *(*get_config)         (GstGLContext * context);
+  gboolean      (*request_config)     (GstGLContext * context, GstStructure * gl_config);
 
   /*< private >*/
-  gpointer _reserved[GST_PADDING];
+  gpointer _reserved[GST_PADDING-2];
 };
 
 /* methods */
@@ -149,6 +179,11 @@ GstGLContext * gst_gl_context_new_wrapped (GstGLDisplay *display,
                                            GstGLAPI available_apis);
 
 GST_GL_API
+GstStructure * gst_gl_context_get_config      (GstGLContext * context);
+GST_GL_API
+gboolean      gst_gl_context_request_config   (GstGLContext * context, GstStructure * gl_config);
+
+GST_GL_API
 gboolean      gst_gl_context_activate         (GstGLContext *context, gboolean activate);
 GST_GL_API
 GThread *     gst_gl_context_get_thread       (GstGLContext *context);
index 6926375..2fa8cfd 100644 (file)
@@ -29,6 +29,18 @@ G_GNUC_INTERNAL extern GstDebugCategory *gst_gl_context_debug;
 G_GNUC_INTERNAL
 gboolean            _gst_gl_context_debug_is_enabled            (GstGLContext * context);
 
+#define GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME "gst.gl.context.wrapped.config"
+
+#define GST_TYPE_GL_WRAPPED_CONTEXT (gst_gl_wrapped_context_get_type())
+G_GNUC_INTERNAL
+GType gst_gl_wrapped_context_get_type (void);
+
+#define GST_GL_WRAPPED_CONTEXT(o)           (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_GL_WRAPPED_CONTEXT, GstGLWrappedContext))
+#define GST_GL_WRAPPED_CONTEXT_CLASS(k)     (G_TYPE_CHECK_CLASS((k), GST_TYPE_GL_CONTEXT, GstGLContextClass))
+#define GST_IS_GL_WRAPPED_CONTEXT(o)        (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_GL_WRAPPED_CONTEXT))
+#define GST_IS_GL_WRAPPED_CONTEXT_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_GL_WRAPPED_CONTEXT))
+#define GST_GL_WRAPPED_CONTEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_GL_WRAPPED_CONTEXT, GstGLWrappedContextClass))
+
 G_END_DECLS
 
 #endif /* __GST_GL_CONTEXT_PRIVATE_H__ */
diff --git a/gst-libs/gst/gl/gstglcontextconfig.c b/gst-libs/gst/gl/gstglcontextconfig.c
new file mode 100644 (file)
index 0000000..1a9948b
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * GStreamer
+ * Copyright (C) 2020 Matthew Waters <matthew@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:gstglcontextconfig
+ * @short_description: OpenGL context configuration values
+ * @title: GstGLContext
+ * @see_also: #GstGLContext, #GstGLWindow
+ *
+ * A common list of well-known values for what a config retrievable from or set
+ * on a `GstGLContext` may contain.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gstglcontextconfig.h"
+#include <gst/gl/gl.h>
+
+/**
+ * GST_GL_CONFIG_ATTRIB_CONFIG_ID_NAME:
+ *
+ * The platform-specific config-id.  This value is not stable across different
+ * machines or even different versions of the same underlying OpenGL
+ * implementation.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_CONFIG_ID_GTYPE:
+ *
+ * The #GType of the config-id field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_CONFIG_ID_NAME = "config-id";
+/**
+ * GST_GL_CONFIG_ATTRIB_PLATFORM_NAME:
+ *
+ * The #GstGLPlatform this config was made for.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_PLATFORM_GTYPE:
+ *
+ * The #GType of the 'platform' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_PLATFORM_NAME = "platform";
+/**
+ * GST_GL_CONFIG_ATTRIB_CAVEAT_NAME:
+ *
+ * Any #GstGLConfigCaveat's applied to this configuration.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_CAVEAT_GTYPE:
+ *
+ * The #GType of the 'caveat' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_CAVEAT_NAME = "caveat";
+/**
+ * GST_GL_CONFIG_ATTRIB_SURFACE_TYPE_NAME:
+ *
+ * Flags of #GstGLConfigSurfaceType's that can apply to this configuration.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_SURFACE_TYPE_GTYPE:
+ *
+ * The #GType of the 'surface-type' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_SURFACE_TYPE_NAME = "surface-type";
+/**
+ * GST_GL_CONFIG_ATTRIB_CONFORMANT_API_NAME:
+ *
+ * The #GstGLAPI's that this configuration meets the conformance requirements
+ * for.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_CONFORMANT_API_GTYPE:
+ *
+ * The #GType of the 'conformant-api' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_CONFORMANT_API_NAME = "conformant-api";
+/**
+ * GST_GL_CONFIG_ATTRIB_RENDERABLE_API_NAME:
+ *
+ * The #GstGLAPI's that this configuration can be rendered with.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_RENDERABLE_API_GTYPE:
+ *
+ * The #GType of the 'renderable-api' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_RENDERABLE_API_NAME = "renderable-api";
+/**
+ * GST_GL_CONFIG_ATTRIB_RED_SIZE_NAME:
+ *
+ * The size of the red buffer with a colour backing buffer.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_RED_SIZE_GTYPE:
+ *
+ * The #GType of the 'red-size' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_RED_SIZE_NAME = "red-size";
+/**
+ * GST_GL_CONFIG_ATTRIB_GREEN_SIZE_NAME:
+ *
+ * The size of the green buffer with a colour backing buffer.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_GREEN_SIZE_GTYPE:
+ *
+ * The #GType of the 'green-size' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_GREEN_SIZE_NAME = "green-size";
+/**
+ * GST_GL_CONFIG_ATTRIB_BLUE_SIZE_NAME:
+ *
+ * The size of the blue buffer with a colour backing buffer.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_BLUE_SIZE_GTYPE:
+ *
+ * The #GType of the 'blue-size' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_BLUE_SIZE_NAME = "blue-size";
+/**
+ * GST_GL_CONFIG_ATTRIB_ALPHA_SIZE_NAME:
+ *
+ * The size of the alpha buffer with a colour backing buffer.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_ALPHA_SIZE_GTYPE:
+ *
+ * The #GType of the 'alpha-size' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_ALPHA_SIZE_NAME = "alpha-size";
+/**
+ * GST_GL_CONFIG_ATTRIB_LUMINANCE_SIZE_NAME:
+ *
+ * The size of the backing luminance buffer.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_LUMINANCE_SIZE_GTYPE:
+ *
+ * The #GType of the 'luminance-size' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_LUMINANCE_SIZE_NAME = "luminance-size";
+/**
+ * GST_GL_CONFIG_ATTRIB_DEPTH_SIZE_NAME:
+ *
+ * The size of the backing depth buffer.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_DEPTH_SIZE_GTYPE:
+ *
+ * The #GType of the 'depth-size' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_DEPTH_SIZE_NAME = "depth-size";
+/**
+ * GST_GL_CONFIG_ATTRIB_STENCIL_SIZE_NAME:
+ *
+ * The size of the backing stencil buffer.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_STENCIL_SIZE_GTYPE:
+ *
+ * The #GType of the 'stencil-size' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_STENCIL_SIZE_NAME = "stencil-size";
+/**
+ * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_WIDTH_NAME:
+ *
+ * The maximum width of a pbuffer created with this config.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_WIDTH_GTYPE:
+ *
+ * The #GType of the 'max-pbuffer-width' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_WIDTH_NAME = "max-pbuffer-width";
+/**
+ * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_HEIGHT_NAME:
+ *
+ * The maximum height of a pbuffer created with this config.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_HEIGHT_GTYPE:
+ *
+ * The #GType of the 'max-pbuffer-height' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_HEIGHT_NAME =
+    "max-pbuffer-height";
+/**
+ * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_PIXELS_NAME:
+ *
+ * The maximum number of pixels that a pbuffer can be created with this config.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_PIXELS_GTYPE:
+ *
+ * The #GType of the 'max-pbuffer-pixels' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_PIXELS_NAME =
+    "max-pbuffer-pixels";
+/**
+ * GST_GL_CONFIG_ATTRIB_SAMPLE_BUFFERS_NAME:
+ *
+ * The number of sample buffers for this config.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_SAMPLE_BUFFERS_GTYPE:
+ *
+ * The #GType of the 'sample-buffers' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_SAMPLE_BUFFERS_NAME = "sample-buffers";
+/**
+ * GST_GL_CONFIG_ATTRIB_SAMPLES_NAME:
+ *
+ * The number of samples per pixel for this config.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_SAMPLES_GTYPE:
+ *
+ * The #GType of the 'samples' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_SAMPLES_NAME = "samples";
+/**
+ * GST_GL_CONFIG_ATTRIB_NATIVE_RENDERABLE_NAME:
+ *
+ * Whether this configuration is renderable to by the native drawing API.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_NATIVE_RENDERABLE_GTYPE:
+ *
+ * The #GType of the 'native-renderable' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_NATIVE_RENDERABLE_NAME = "native-renderable";
+/**
+ * GST_GL_CONFIG_ATTRIB_NATIVE_VISUAL_ID_NAME:
+ *
+ * The native visual ID of this config.  This value may not be consistent
+ * across machines or even dependency versions.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_NATIVE_VISUAL_ID_GTYPE:
+ *
+ * The #GType of the 'native-visual-id' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_NATIVE_VISUAL_ID_NAME = "native-visual-id";
+/**
+ * GST_GL_CONFIG_ATTRIB_LEVEL_NAME:
+ *
+ * Level of the under/overlay of this config.  Positive values correspond to
+ * overlay, negative values are underlay.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_LEVEL_GTYPE:
+ *
+ * The #GType of the 'level' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_LEVEL_NAME = "level";
+/**
+ * GST_GL_CONFIG_ATTRIB_MIN_SWAP_INTERVAL_NAME:
+ *
+ * The minimum value available for vsync synchronisation.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_MIN_SWAP_INTERVAL_GTYPE:
+ *
+ * The #GType of the 'min-swap-interval' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_MIN_SWAP_INTERVAL_NAME = "min-swap-interval";
+/**
+ * GST_GL_CONFIG_ATTRIB_MAX_SWAP_INTERVAL_NAME:
+ *
+ * The maximum value available for vsync synchronisation.
+ *
+ * Since: 1.20
+ */
+/**
+ * GST_GL_CONFIG_ATTRIB_MAX_SWAP_INTERVAL_GTYPE:
+ *
+ * The #GType of the 'max-swap-interval' field.
+ *
+ * Since: 1.20
+ */
+const gchar *GST_GL_CONFIG_ATTRIB_MAX_SWAP_INTERVAL_NAME = "max-swap-interval";
+
+static const gchar *
+gst_gl_enum_value_to_const_string (GType type, guint value)
+{
+  GEnumClass *enum_class;
+  GEnumValue *enum_value;
+  const gchar *str = NULL;
+
+  enum_class = g_type_class_ref (type);
+  enum_value = g_enum_get_value (enum_class, value);
+
+  if (enum_value)
+    str = enum_value->value_nick;
+
+  g_type_class_unref (enum_class);
+
+  return str;
+}
+
+/**
+ * gst_gl_config_caveat_to_string:
+ * @caveat: the #GstGLConfigCaveat
+ *
+ * Returns: (nullable): a string version of @caveat or %NULL if @caveat does not
+ *                      exist.
+ *
+ * Since: 1.20
+ */
+const gchar *
+gst_gl_config_caveat_to_string (GstGLConfigCaveat caveat)
+{
+  return gst_gl_enum_value_to_const_string (GST_TYPE_GL_CONFIG_CAVEAT, caveat);
+}
+
+/**
+ * gst_gl_config_surface_type_to_string:
+ * @surface_type: the #GstGLConfigSurfaceType
+ *
+ * Returns: (nullable): a string version of @caveat or %NULL if @surface_type does not
+ *                      exist.
+ *
+ * Since: 1.20
+ */
+const gchar *
+gst_gl_config_surface_type_to_string (GstGLConfigSurfaceType surface_type)
+{
+  return gst_gl_enum_value_to_const_string (GST_TYPE_GL_CONFIG_SURFACE_TYPE,
+      surface_type);
+}
diff --git a/gst-libs/gst/gl/gstglcontextconfig.h b/gst-libs/gst/gl/gstglcontextconfig.h
new file mode 100644 (file)
index 0000000..af33013
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * GStreamer
+ * Copyright (C) 2020 Matthew Waters <matthew@centricular.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_GL_CONTEXT_CONFIG_H__
+#define __GST_GL_CONTEXT_CONFIG_H__
+
+#include <gst/gst.h>
+
+#include <gst/gl/gstgl_fwd.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GST_GL_CONFIG_STRUCTURE_NAME:
+ *
+ * The canonical name of a #GstStructure that contains a configuration for a
+ * #GstGLContext.
+ *
+ * Since: 1.20
+ */
+#define GST_GL_CONFIG_STRUCTURE_NAME "gst-gl-context-config"
+
+/**
+ * GST_GL_CONFIG_ATTRIB_NAME:
+ *
+ * Get a reference to the variable name of a particular configuration field.
+ *
+ * e.g. for `CONFIG_ID`: `GST_GL_CONFIG_ATTRIB_NAME (CONFIG_ID)`
+ *
+ * Since: 1.20
+ */
+#define GST_GL_CONFIG_ATTRIB_NAME(UPPER_NAME) \
+  G_PASTE(G_PASTE(GST_GL_CONFIG_ATTRIB_,UPPER_NAME),_NAME)
+/**
+ * GST_GL_CONFIG_ATTRIB_GTYPE:
+ *
+ * Get a reference to the #GType of a particular configuration field.
+ *
+ * e.g. for `CONFIG_ID`: `GST_GL_CONFIG_ATTRIB_GTYPE (CONFIG_ID)`
+ *
+ * Since: 1.20
+ */
+#define GST_GL_CONFIG_ATTRIB_GTYPE(UPPER_NAME) \
+  G_PASTE(G_PASTE(GST_GL_CONFIG_ATTRIB_,UPPER_NAME),_GTYPE)
+
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_CONFIG_ID_NAME;
+#define GST_GL_CONFIG_ATTRIB_CONFIG_ID_GTYPE G_TYPE_UINT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_PLATFORM_NAME;
+#define GST_GL_CONFIG_ATTRIB_PLATFORM_GTYPE GST_TYPE_GL_PLATFORM
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_CAVEAT_NAME;
+#define GST_GL_CONFIG_ATTRIB_CAVEAT_GTYPE GST_TYPE_GL_CONFIG_CAVEAT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_SURFACE_TYPE_NAME;
+#define GST_GL_CONFIG_ATTRIB_SURFACE_TYPE_GTYPE GST_TYPE_GL_CONFIG_SURFACE_TYPE
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_CONFORMANT_API_NAME;
+#define GST_GL_CONFIG_ATTRIB_CONFORMANT_API_GTYPE GST_TYPE_GL_API
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_RENDERABLE_API_NAME;
+#define GST_GL_CONFIG_ATTRIB_RENDERABLE_API_GTYPE GST_TYPE_GL_API
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_RED_SIZE_NAME;
+#define GST_GL_CONFIG_ATTRIB_RED_SIZE_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_GREEN_SIZE_NAME;
+#define GST_GL_CONFIG_ATTRIB_GREEN_SIZE_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_BLUE_SIZE_NAME;
+#define GST_GL_CONFIG_ATTRIB_BLUE_SIZE_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_ALPHA_SIZE_NAME;
+#define GST_GL_CONFIG_ATTRIB_ALPHA_SIZE_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_LUMINANCE_SIZE_NAME;
+#define GST_GL_CONFIG_ATTRIB_LUMINANCE_SIZE_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_DEPTH_SIZE_NAME;
+#define GST_GL_CONFIG_ATTRIB_DEPTH_SIZE_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_STENCIL_SIZE_NAME;
+#define GST_GL_CONFIG_ATTRIB_STENCIL_SIZE_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_WIDTH_NAME;
+#define GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_WIDTH_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_HEIGHT_NAME;
+#define GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_HEIGHT_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_PIXELS_NAME;
+#define GST_GL_CONFIG_ATTRIB_MAX_PBUFFER_PIXELS_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_SAMPLE_BUFFERS_NAME;
+#define GST_GL_CONFIG_ATTRIB_SAMPLE_BUFFERS_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_SAMPLES_NAME;
+#define GST_GL_CONFIG_ATTRIB_SAMPLES_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_NATIVE_RENDERABLE_NAME;
+#define GST_GL_CONFIG_ATTRIB_NATIVE_RENDERABLE_GTYPE G_TYPE_BOOLEAN
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_NATIVE_VISUAL_ID_NAME;
+#define GST_GL_CONFIG_ATTRIB_NATIVE_VISUAL_ID_GTYPE G_TYPE_UINT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_LEVEL_NAME;
+#define GST_GL_CONFIG_ATTRIB_LEVEL_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_MIN_SWAP_INTERVAL_NAME;
+#define GST_GL_CONFIG_ATTRIB_MIN_SWAP_INTERVAL_GTYPE G_TYPE_INT
+GST_GL_API const char * GST_GL_CONFIG_ATTRIB_MAX_SWAP_INTERVAL_NAME;
+#define GST_GL_CONFIG_ATTRIB_MAX_SWAP_INTERVAL_GTYPE G_TYPE_INT
+
+/**
+ * GST_GL_CONFIG_STRUCTURE_SET_ARGS:
+ *
+ * Since: 1.20
+ */
+#define GST_GL_CONFIG_STRUCTURE_SET_ARGS(def_name,ctype,val) \
+    GST_GL_CONFIG_ATTRIB_NAME(def_name), \
+    GST_GL_CONFIG_ATTRIB_GTYPE(def_name), \
+    (ctype) (val)
+
+/**
+ * GstGLConfigCaveat:
+ * @GST_GL_CONFIG_CAVEAT_NONE: none
+ * @GST_GL_CONFIG_CAVEAT_SLOW: slow
+ * @GST_GL_CONFIG_CAVEAT_NON_CONFORMANT: non-conformant
+ *
+ * Since: 1.20
+ */
+typedef enum
+{
+  GST_GL_CONFIG_CAVEAT_NONE,
+  GST_GL_CONFIG_CAVEAT_SLOW,
+  GST_GL_CONFIG_CAVEAT_NON_CONFORMANT,
+} GstGLConfigCaveat;
+
+GST_GL_API
+const gchar * gst_gl_config_caveat_to_string (GstGLConfigCaveat caveat);
+
+/**
+ * GstGLConfigSurfaceType:
+ * @GST_GL_CONFIG_SURFACE_TYPE_NONE: none
+ * @GST_GL_CONFIG_SURFACE_TYPE_WINDOW: window
+ * @GST_GL_CONFIG_SURFACE_TYPE_PBUFFER: pbuffer
+ * @GST_GL_CONFIG_SURFACE_TYPE_PIXMAP: pixmap
+ *
+ * Since: 1.20
+ */
+typedef enum
+{
+  GST_GL_CONFIG_SURFACE_TYPE_NONE = 0,
+  GST_GL_CONFIG_SURFACE_TYPE_WINDOW = (1 << 0),
+  GST_GL_CONFIG_SURFACE_TYPE_PBUFFER = (1 << 1),
+  GST_GL_CONFIG_SURFACE_TYPE_PIXMAP = (1 << 2),
+} GstGLConfigSurfaceType;
+
+GST_GL_API
+const gchar * gst_gl_config_surface_type_to_string (GstGLConfigSurfaceType surface_type);
+
+G_END_DECLS
+
+#endif /* __GST_GL_CONTEXT_CONFIG_H__ */
index 80278d3..67399f2 100644 (file)
@@ -14,6 +14,7 @@ gl_sources = [
   'gstglbuffer.c',
   'gstglbufferpool.c',
   'gstglcontext.c',
+  'gstglcontextconfig.c',
   'gstgldebug.c',
   'gstgldisplay.c',
   'gstglfeature.c',
@@ -51,6 +52,7 @@ gir_gl_headers = [
   'gstglbufferpool.h',
   'gstglcolorconvert.h',
   'gstglcontext.h',
+  'gstglcontextconfig.h',
   'gstgldebug.h',
   'gstgldisplay.h',
   'gstglfeature.h',
index b13dec4..d75dc32 100644 (file)
@@ -63,6 +63,7 @@ static GstGLPlatform gst_gl_context_wgl_get_gl_platform (GstGLContext *
     context);
 static gboolean gst_gl_context_wgl_check_feature (GstGLContext * context,
     const gchar * feature);
+GstStructure *gst_gl_context_wgl_get_config (GstGLContext * context);
 
 static void
 gst_gl_context_wgl_class_init (GstGLContextWGLClass * klass)
@@ -88,6 +89,7 @@ gst_gl_context_wgl_class_init (GstGLContextWGLClass * klass)
       GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_platform);
   context_class->check_feature =
       GST_DEBUG_FUNCPTR (gst_gl_context_wgl_check_feature);
+  context_class->get_config = GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_config);
 }
 
 static void
@@ -302,6 +304,47 @@ gst_gl_context_wgl_destroy_context (GstGLContext * context)
   context_wgl->wgl_context = NULL;
 }
 
+static GstGLConfigSurfaceType
+pfd_flags_to_surface_type (int flags)
+{
+  GstGLConfigSurfaceType ret = GST_GL_CONFIG_SURFACE_TYPE_NONE;
+
+  if (flags & PFD_DRAW_TO_WINDOW)
+    ret |= GST_GL_CONFIG_SURFACE_TYPE_WINDOW;
+  if (flags & PFD_DRAW_TO_BITMAP)
+    ret |= GST_GL_CONFIG_SURFACE_TYPE_PIXMAP;
+
+  return ret;
+}
+
+static GstStructure *
+pixel_format_to_structure (HDC hdc, int pixfmt)
+{
+  GstStructure *ret;
+  PIXELFORMATDESCRIPTOR pfd;
+
+  if (pixfmt == 0)
+    return NULL;
+
+  if (DescribePixelFormat (hdc, pixfmt, sizeof (pfd), &pfd) == 0)
+    return NULL;
+
+  ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME,
+      GST_GL_CONFIG_STRUCTURE_SET_ARGS (PLATFORM, GstGLPlatform,
+          GST_GL_PLATFORM_WGL), GST_GL_CONFIG_STRUCTURE_SET_ARGS (RED_SIZE, int,
+          pfd.cRedBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (BLUE_SIZE, int,
+          pfd.cBlueBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (GREEN_SIZE, int,
+          pfd.cGreenBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (ALPHA_SIZE, int,
+          pfd.cAlphaBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (DEPTH_SIZE, int,
+          pfd.cDepthBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (STENCIL_SIZE, int,
+          pfd.cStencilBits), GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_VISUAL_ID,
+          guint, pixfmt), GST_GL_CONFIG_STRUCTURE_SET_ARGS (SURFACE_TYPE,
+          GstGLConfigSurfaceType, pfd_flags_to_surface_type (pfd.dwFlags)),
+      NULL);
+
+  return ret;
+}
+
 static gboolean
 gst_gl_context_wgl_choose_format (GstGLContext * context, GError ** error)
 {
@@ -310,6 +353,7 @@ gst_gl_context_wgl_choose_format (GstGLContext * context, GError ** error)
   gint pixelformat = 0;
   gboolean res = FALSE;
   HDC device;
+  GstStructure *config;
 
   window = gst_gl_context_get_window (context);
   gst_gl_window_win32_create_window (GST_GL_WINDOW_WIN32 (window), error);
@@ -353,6 +397,10 @@ gst_gl_context_wgl_choose_format (GstGLContext * context, GError ** error)
     return FALSE;
   }
 
+  config = pixel_format_to_structure (device, pixelformat);
+  GST_INFO_OBJECT (context, "chosen config %" GST_PTR_FORMAT, config);
+  gst_structure_free (config);
+
   res = SetPixelFormat (device, pixelformat, &pfd);
 
   return res;
@@ -437,3 +485,18 @@ gst_gl_context_wgl_get_current_context (void)
 {
   return (guintptr) wglGetCurrentContext ();
 }
+
+GstStructure *
+gst_gl_context_wgl_get_config (GstGLContext * context)
+{
+  GstGLWindow *window;
+  int pixfmt;
+  HDC hdc;
+
+  window = gst_gl_context_get_window (context);
+  hdc = (HDC) gst_gl_window_get_display (window);
+
+  pixfmt = GetPixelFormat (hdc);
+
+  return pixel_format_to_structure (hdc, pixfmt);
+}
index cb74d47..e581a7d 100644 (file)
@@ -55,6 +55,9 @@ static GstGLPlatform gst_gl_context_glx_get_gl_platform (GstGLContext *
     context);
 static void gst_gl_context_glx_get_gl_platform_version (GstGLContext * context,
     gint * major, gint * minor);
+static GstStructure *gst_gl_context_glx_get_config (GstGLContext * context);
+static gboolean gst_gl_context_glx_request_config (GstGLContext * context,
+    GstStructure * config);
 
 struct _GstGLContextGLXPrivate
 {
@@ -66,6 +69,8 @@ struct _GstGLContextGLXPrivate
   GLXFBConfig *fbconfigs;
     GLXContext (*glXCreateContextAttribsARB) (Display *, GLXFBConfig,
       GLXContext, Bool, const int *);
+
+  GstStructure *requested_config;
 };
 
 #define gst_gl_context_glx_parent_class parent_class
@@ -98,6 +103,9 @@ gst_gl_context_glx_class_init (GstGLContextGLXClass * klass)
       GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_current_context);
   context_class->get_gl_platform_version =
       GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_gl_platform_version);
+  context_class->get_config = GST_DEBUG_FUNCPTR (gst_gl_context_glx_get_config);
+  context_class->request_config =
+      GST_DEBUG_FUNCPTR (gst_gl_context_glx_request_config);
 }
 
 static void
@@ -121,6 +129,140 @@ gst_gl_context_glx_new (GstGLDisplay * display)
   return context;
 }
 
+static GstGLConfigSurfaceType
+glx_drawable_type_to_gst (int drawable_type)
+{
+  GstGLConfigSurfaceType ret = GST_GL_CONFIG_SURFACE_TYPE_NONE;
+
+  if (drawable_type & GLX_WINDOW_BIT)
+    ret |= GST_GL_CONFIG_SURFACE_TYPE_WINDOW;
+  if (drawable_type & GLX_PIXMAP_BIT)
+    ret |= GST_GL_CONFIG_SURFACE_TYPE_PIXMAP;
+  if (drawable_type & GLX_PBUFFER_BIT)
+    ret |= GST_GL_CONFIG_SURFACE_TYPE_PBUFFER;
+
+  return ret;
+}
+
+static GstGLConfigCaveat
+glx_caveat_to_gst (int caveat)
+{
+  switch (caveat) {
+    case GLX_NONE:
+      return GST_GL_CONFIG_CAVEAT_NONE;
+    case GLX_SLOW_CONFIG:
+      return GST_GL_CONFIG_CAVEAT_SLOW;
+    case GLX_NON_CONFORMANT_CONFIG:
+      return GST_GL_CONFIG_CAVEAT_NON_CONFORMANT;
+    default:
+      GST_WARNING ("unknown GLX caveat value %u (0x%x)", caveat, caveat);
+      return GST_GL_CONFIG_CAVEAT_NON_CONFORMANT;
+  }
+}
+
+static GstStructure *
+fb_config_to_structure (GstGLContext * context,
+    Display * dpy, GLXFBConfig fbconfig)
+{
+  GstStructure *ret;
+  int val, render_type;
+
+  ret = gst_structure_new (GST_GL_CONFIG_STRUCTURE_NAME,
+      GST_GL_CONFIG_STRUCTURE_SET_ARGS (PLATFORM, GstGLPlatform,
+          GST_GL_PLATFORM_GLX), "platform-sub-type", G_TYPE_STRING, "fbconfig",
+      NULL);
+
+  if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_FBCONFIG_ID, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CONFIG_ID, int,
+          val), NULL);
+
+  if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_VISUAL_ID, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_VISUAL_ID,
+          guint, val), NULL);
+
+  if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_CONFIG_CAVEAT, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (CAVEAT,
+          GstGLConfigCaveat, glx_caveat_to_gst (val)), NULL);
+
+  if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_DRAWABLE_TYPE, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (SURFACE_TYPE,
+          GstGLConfigSurfaceType, glx_drawable_type_to_gst (val)), NULL);
+
+  if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_X_RENDERABLE, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (NATIVE_RENDERABLE,
+          gboolean, val), NULL);
+
+  if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_LEVEL, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (LEVEL, int, val),
+      NULL);
+
+  if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_RENDER_TYPE,
+          &render_type))
+    goto failure;
+
+  if (render_type & GLX_RGBA_BIT) {
+    if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_RED_SIZE, &val))
+      goto failure;
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (RED_SIZE, int,
+            val), NULL);
+
+    if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_GREEN_SIZE, &val))
+      goto failure;
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (GREEN_SIZE, int,
+            val), NULL);
+
+    if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_BLUE_SIZE, &val))
+      goto failure;
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (BLUE_SIZE, int,
+            val), NULL);
+
+    if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_ALPHA_SIZE, &val))
+      goto failure;
+    gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (ALPHA_SIZE, int,
+            val), NULL);
+  }
+
+  if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_DEPTH_SIZE, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (DEPTH_SIZE, int,
+          val), NULL);
+
+  if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_STENCIL_SIZE, &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (STENCIL_SIZE, int,
+          val), NULL);
+
+  if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_MAX_PBUFFER_WIDTH,
+          &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_WIDTH,
+          int, val), NULL);
+
+  if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_MAX_PBUFFER_HEIGHT,
+          &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_HEIGHT,
+          int, val), NULL);
+
+  if (Success != glXGetFBConfigAttrib (dpy, fbconfig, GLX_MAX_PBUFFER_PIXELS,
+          &val))
+    goto failure;
+  gst_structure_set (ret, GST_GL_CONFIG_STRUCTURE_SET_ARGS (MAX_PBUFFER_PIXELS,
+          int, val), NULL);
+
+  return ret;
+
+failure:
+  gst_structure_free (ret);
+  return NULL;
+}
+
 static void
 gst_gl_context_glx_dump_fb_config (GstGLContextGLX * glx,
     Display * dpy, GLXFBConfig fbconfig)
@@ -353,6 +495,60 @@ gst_gl_context_glx_dump_all_fb_configs (GstGLContextGLX * glx,
   XFree (configs);
 }
 
+static int *
+fb_config_attributes_from_structure (GstStructure * config)
+{
+  guint i = 0, n;
+  int *ret;
+
+  if (!config) {
+    gint attribs[] = {
+      GLX_RENDER_TYPE, GLX_RGBA_BIT,
+      GLX_RED_SIZE, 1,
+      GLX_GREEN_SIZE, 1,
+      GLX_BLUE_SIZE, 1,
+      GLX_DEPTH_SIZE, 16,
+      GLX_DOUBLEBUFFER, True,
+      None
+    };
+
+    return g_memdup (attribs, sizeof (attribs));
+  }
+
+  n = gst_structure_n_fields (config) * 2 + 1;
+  ret = g_new0 (gint, n);
+
+#define TRANSFORM_VALUE(GL_CONF_NAME,GLX_ATTR_NAME) \
+  G_STMT_START { \
+    if (gst_structure_has_field_typed (config, \
+          GST_GL_CONFIG_ATTRIB_NAME(GL_CONF_NAME), \
+          GST_GL_CONFIG_ATTRIB_GTYPE(GL_CONF_NAME))) { \
+      int val; \
+      if (gst_structure_get (config, \
+          GST_GL_CONFIG_ATTRIB_NAME(GL_CONF_NAME), \
+          GST_GL_CONFIG_ATTRIB_GTYPE(GL_CONF_NAME), &val, NULL)) { \
+        ret[i++] = GLX_ATTR_NAME; \
+        ret[i++] = (int) val; \
+      } \
+    } \
+  } G_STMT_END
+
+  TRANSFORM_VALUE (CONFIG_ID, GLX_FBCONFIG_ID);
+  TRANSFORM_VALUE (RED_SIZE, GLX_RED_SIZE);
+  TRANSFORM_VALUE (GREEN_SIZE, GLX_GREEN_SIZE);
+  TRANSFORM_VALUE (BLUE_SIZE, GLX_BLUE_SIZE);
+  TRANSFORM_VALUE (ALPHA_SIZE, GLX_ALPHA_SIZE);
+  TRANSFORM_VALUE (DEPTH_SIZE, GLX_DEPTH_SIZE);
+  TRANSFORM_VALUE (STENCIL_SIZE, GLX_STENCIL_SIZE);
+  /* TODO: more values */
+
+#undef TRANSFORM_VALUE
+
+  ret[i++] = None;
+  g_assert (i <= n);
+  return ret;
+}
+
 static GLXContext
 _create_context_with_flags (GstGLContextGLX * context_glx, Display * dpy,
     GLXFBConfig fbconfig, GLXContext share_context, gint major, gint minor,
@@ -487,9 +683,6 @@ gst_gl_context_glx_create_context (GstGLContext * context,
     context_glx->priv->context_api = GST_GL_API_OPENGL;
   }
 
-  if (context_glx->priv->fbconfigs)
-    XFree (context_glx->priv->fbconfigs);
-
   if (!context_glx->glx_context) {
     g_set_error (error, GST_GL_CONTEXT_ERROR,
         GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "Failed to create opengl context");
@@ -523,10 +716,18 @@ gst_gl_context_glx_destroy_context (GstGLContext * context)
   window = gst_gl_context_get_window (context);
   device = (Display *) gst_gl_display_get_handle (window->display);
 
+  if (context_glx->priv->fbconfigs)
+    XFree (context_glx->priv->fbconfigs);
+  context_glx->priv->fbconfigs = NULL;
+
   glXDestroyContext (device, context_glx->glx_context);
 
   context_glx->glx_context = 0;
 
+  if (context_glx->priv->requested_config)
+    gst_structure_free (context_glx->priv->requested_config);
+  context_glx->priv->requested_config = NULL;
+
   gst_object_unref (window);
 }
 
@@ -598,16 +799,12 @@ gst_gl_context_glx_choose_format (GstGLContext * context, GError ** error)
       goto failure;
     }
   } else {
-    gint attribs[] = {
-      GLX_RENDER_TYPE, GLX_RGBA_BIT,
-      GLX_RED_SIZE, 1,
-      GLX_GREEN_SIZE, 1,
-      GLX_BLUE_SIZE, 1,
-      GLX_DEPTH_SIZE, 16,
-      GLX_DOUBLEBUFFER, True,
-      None
-    };
     int fbcount;
+    int *attribs;
+
+    attribs =
+        fb_config_attributes_from_structure (context_glx->
+        priv->requested_config);
 
     gst_gl_context_glx_dump_all_fb_configs (context_glx, device,
         DefaultScreen (device));
@@ -615,6 +812,8 @@ gst_gl_context_glx_choose_format (GstGLContext * context, GError ** error)
     context_glx->priv->fbconfigs = glXChooseFBConfig (device,
         DefaultScreen (device), attribs, &fbcount);
 
+    g_free (attribs);
+
     if (!context_glx->priv->fbconfigs) {
       g_set_error (error, GST_GL_CONTEXT_ERROR,
           GST_GL_CONTEXT_ERROR_WRONG_CONFIG,
@@ -730,3 +929,109 @@ gst_gl_context_glx_get_gl_platform_version (GstGLContext * context,
   *major = context_glx->priv->glx_major;
   *minor = context_glx->priv->glx_minor;
 }
+
+static GstStructure *
+gst_gl_context_glx_get_config (GstGLContext * context)
+{
+  GstGLContextGLX *glx = GST_GL_CONTEXT_GLX (context);
+  GstGLWindow *window;
+  GstGLWindowX11 *window_x11;
+  Display *device;
+  GstStructure *ret;
+
+  window = gst_gl_context_get_window (context);
+  device = (Display *) gst_gl_display_get_handle (window->display);
+  window_x11 = GST_GL_WINDOW_X11 (window);
+
+  g_return_val_if_fail (glx->priv->fbconfigs || window_x11->visual_info, NULL);
+
+  if (glx->priv->fbconfigs) {
+    ret = fb_config_to_structure (context, device, glx->priv->fbconfigs[0]);
+  } else {
+    /*TODO: XVisualInfo for really old GLX/X11 versions, */
+    ret = NULL;
+  }
+  gst_object_unref (window);
+  return ret;
+}
+
+static gboolean
+gst_gl_context_glx_request_config (GstGLContext * context,
+    GstStructure * config)
+{
+  GstGLContextGLX *glx = GST_GL_CONTEXT_GLX (context);
+
+  if (glx->priv->requested_config)
+    gst_structure_free (glx->priv->requested_config);
+  glx->priv->requested_config = config;
+
+  return TRUE;
+}
+
+gboolean
+gst_gl_context_glx_fill_info (GstGLContext * context)
+{
+  GLXContext glx_context = (GLXContext) gst_gl_context_get_gl_context (context);
+  GstStructure *config;
+  Display *device;
+  GLXFBConfig *fbconfigs;
+  int fbconfig_id, n_fbconfigs;
+  int glx_major, glx_minor;
+  int attrs[3];
+
+  if (!glx_context) {
+    GST_ERROR_OBJECT (context, "no GLX context");
+    return FALSE;
+  }
+
+  device = (Display *) gst_gl_display_get_handle (context->display);
+
+  if (!glXQueryVersion (device, &glx_major, &glx_minor)) {
+    GST_WARNING_OBJECT (context, "could not retrieve GLX version");
+    return FALSE;
+  }
+
+  if (!GST_GL_CHECK_GL_VERSION (glx_major, glx_minor, 1, 4)) {
+    GST_FIXME_OBJECT (context, "No support for retrieving the "
+        "GstGLContextConfig from GLX < 1.4, have %u.%u", glx_major, glx_minor);
+    return TRUE;
+  }
+
+  if (Success != glXQueryContext (device, glx_context, GLX_FBCONFIG_ID,
+          &fbconfig_id)) {
+    GST_WARNING_OBJECT (context,
+        "could not retrieve fbconfig id from glx context");
+    goto failure;
+  }
+
+  attrs[0] = GLX_FBCONFIG_ID;
+  attrs[1] = fbconfig_id;
+  attrs[2] = None;
+
+  fbconfigs = glXChooseFBConfig (device, DefaultScreen (device), attrs,
+      &n_fbconfigs);
+  if (!fbconfigs || n_fbconfigs <= 0) {
+    GST_WARNING_OBJECT (context,
+        "could not retrieve fbconfig from its ID 0x%x. "
+        "Wrong Display or Screen?", fbconfig_id);
+    goto failure;
+  }
+
+  config = fb_config_to_structure (context, device, fbconfigs[0]);
+  if (!config) {
+    GST_WARNING_OBJECT (context, "could not transform fbconfig id 0x%x into "
+        "GstStructure.", fbconfig_id);
+    goto failure;
+  }
+
+  GST_INFO_OBJECT (context, "found config %" GST_PTR_FORMAT, config);
+
+  g_object_set_data_full (G_OBJECT (context),
+      GST_GL_CONTEXT_WRAPPED_GL_CONFIG_NAME, config,
+      (GDestroyNotify) gst_structure_free);
+
+  return TRUE;
+
+failure:
+  return FALSE;
+}
index 40886ed..e084cb5 100644 (file)
@@ -68,6 +68,9 @@ guintptr            gst_gl_context_glx_get_current_context  (void);
 G_GNUC_INTERNAL
 gpointer            gst_gl_context_glx_get_proc_address     (GstGLAPI gl_api, const gchar * name);
 
+G_GNUC_INTERNAL
+gboolean            gst_gl_context_glx_fill_info            (GstGLContext * context);
+
 G_END_DECLS
 
 #endif /* __GST_GL_CONTEXT_H__ */