glcontext/wgl: implement gl3 core profile context selection
authorMatthew Waters <matthew@centricular.com>
Mon, 10 Aug 2015 13:44:54 +0000 (15:44 +0200)
committerMatthew Waters <matthew@centricular.com>
Mon, 10 Aug 2015 13:46:13 +0000 (15:46 +0200)
gst-libs/gst/gl/utils/opengl_versions.h [new file with mode: 0644]
gst-libs/gst/gl/win32/gstglcontext_wgl.c
gst-libs/gst/gl/win32/gstglcontext_wgl.h
gst-libs/gst/gl/x11/gstglcontext_glx.c

diff --git a/gst-libs/gst/gl/utils/opengl_versions.h b/gst-libs/gst/gl/utils/opengl_versions.h
new file mode 100644 (file)
index 0000000..beeeab6
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * GStreamer
+ * Copyright (C) 2015 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 _OPENGL_VERSIONS_H_
+#define _OPENGL_VERSIONS_H_
+
+/* list of known OpenGL versions */
+/* *INDENT-OFF* */
+static const struct { int major, minor; } opengl_versions[] = {
+   {4, 5},
+   {4, 4},
+   {4, 3},
+   {4, 2},
+   {4, 1},
+   {4, 0},
+
+   {3, 3},
+   {3, 2},
+   {3, 1},
+   {3, 0},
+
+   {2, 1},
+   {2, 0},
+
+   {1, 5},
+   {1, 4},
+   {1, 3},
+   {1, 2},
+   {1, 1},
+   {1, 0},
+
+   {0, 0} /* end of list */
+};
+/* *INDENT-ON* */
+
+#endif /* _OPENGL_VERSIONS_H_ */
index d950f252b9a6988d4351e6bff5091715d0785528..3c2f34a1a4894e8cefb13a15beb51e5b83b5aea6 100644 (file)
 #include "gstglcontext_wgl.h"
 #include <GL/wglext.h>
 
+#include "../utils/opengl_versions.h"
+
+struct _GstGLContextWGLPrivate
+{
+  PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
+
+  GstGLAPI context_api;
+};
+
 #define gst_gl_context_wgl_parent_class parent_class
 G_DEFINE_TYPE (GstGLContextWGL, gst_gl_context_wgl, GST_GL_TYPE_CONTEXT);
+#define GST_GL_CONTEXT_WGL_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE((o), GST_GL_TYPE_CONTEXT_WGL, GstGLContextWGLPrivate))
 
 static guintptr gst_gl_context_wgl_get_gl_context (GstGLContext * context);
 static void gst_gl_context_wgl_swap_buffers (GstGLContext * context);
@@ -52,6 +63,8 @@ gst_gl_context_wgl_class_init (GstGLContextWGLClass * klass)
 {
   GstGLContextClass *context_class = (GstGLContextClass *) klass;
 
+  g_type_class_add_private (klass, sizeof (GstGLContextWGLPrivate));
+
   context_class->get_gl_context =
       GST_DEBUG_FUNCPTR (gst_gl_context_wgl_get_gl_context);
   context_class->choose_format =
@@ -74,6 +87,9 @@ gst_gl_context_wgl_class_init (GstGLContextWGLClass * klass)
 static void
 gst_gl_context_wgl_init (GstGLContextWGL * context_wgl)
 {
+  context_wgl->priv = GST_GL_CONTEXT_WGL_GET_PRIVATE (context_wgl);
+
+  context_wgl->priv->context_api = GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
 }
 
 /* Must be called in the gl thread */
@@ -88,6 +104,44 @@ gst_gl_context_wgl_new (GstGLDisplay * display)
   return g_object_new (GST_GL_TYPE_CONTEXT_WGL, NULL);
 }
 
+static HGLRC
+_create_context_with_flags (GstGLContextWGL * context_wgl, HDC dpy,
+    HGLRC share_context, gint major, gint minor, gint contextFlags,
+    gint profileMask)
+{
+  HGLRC ret;
+#define N_ATTRIBS 20
+  gint attribs[N_ATTRIBS];
+  gint n = 0;
+
+  if (major) {
+    attribs[n++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
+    attribs[n++] = major;
+  }
+  if (minor) {
+    attribs[n++] = WGL_CONTEXT_MINOR_VERSION_ARB;
+    attribs[n++] = minor;
+  }
+  if (contextFlags) {
+    attribs[n++] = WGL_CONTEXT_FLAGS_ARB;
+    attribs[n++] = contextFlags;
+  }
+  if (profileMask) {
+    attribs[n++] = WGL_CONTEXT_PROFILE_MASK_ARB;
+    attribs[n++] = profileMask;
+  }
+  attribs[n++] = 0;
+
+  g_assert (n < N_ATTRIBS);
+#undef N_ATTRIBS
+
+  ret =
+      context_wgl->priv->wglCreateContextAttribsARB (dpy, share_context,
+      attribs);
+
+  return ret;
+}
+
 static gboolean
 gst_gl_context_wgl_create_context (GstGLContext * context,
     GstGLAPI gl_api, GstGLContext * other_context, GError ** error)
@@ -95,7 +149,7 @@ gst_gl_context_wgl_create_context (GstGLContext * context,
   GstGLWindow *window;
   GstGLContextWGL *context_wgl;
   HGLRC external_gl_context = NULL;
-  PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
+  HGLRC trampoline;
   HDC device;
 
   context_wgl = GST_GL_CONTEXT_WGL (context);
@@ -112,45 +166,81 @@ gst_gl_context_wgl_create_context (GstGLContext * context,
     external_gl_context = (HGLRC) gst_gl_context_get_gl_context (other_context);
   }
 
-  context_wgl->wgl_context = wglCreateContext (device);
-  if (context_wgl->wgl_context)
+  trampoline = wglCreateContext (device);
+  if (trampoline)
     GST_DEBUG ("gl context created: %" G_GUINTPTR_FORMAT,
-        (guintptr) context_wgl->wgl_context);
+        (guintptr) trampoline);
   else {
     g_set_error (error, GST_GL_CONTEXT_ERROR,
         GST_GL_CONTEXT_ERROR_CREATE_CONTEXT, "failed to create glcontext:0x%x",
         (unsigned int) GetLastError ());
     goto failure;
   }
-  g_assert (context_wgl->wgl_context);
+  g_assert (trampoline);
+
+  /* get extension functions */
+  wglMakeCurrent (device, trampoline);
+
+  context_wgl->priv->wglCreateContextAttribsARB =
+      (PFNWGLCREATECONTEXTATTRIBSARBPROC)
+      wglGetProcAddress ("wglCreateContextAttribsARB");
+
+  wglMakeCurrent (device, 0);
+  wglDeleteContext (trampoline);
+  trampoline = NULL;
+
+  if (context_wgl->priv->wglCreateContextAttribsARB != NULL
+      && gl_api & GST_GL_API_OPENGL3) {
+    gint i;
+
+    for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) {
+      gint profileMask = 0;
+      gint contextFlags = 0;
+
+      if ((opengl_versions[i].major > 3
+              || (opengl_versions[i].major == 3
+                  && opengl_versions[i].minor >= 2))) {
+        profileMask |= WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
+        contextFlags |= WGL_CONTEXT_DEBUG_BIT_ARB;
+      } else {
+        break;
+      }
 
+      GST_DEBUG_OBJECT (context, "trying to create a GL %d.%d context",
+          opengl_versions[i].major, opengl_versions[i].minor);
 
-  if (external_gl_context) {
+      context_wgl->wgl_context = _create_context_with_flags (context_wgl,
+          device, external_gl_context, opengl_versions[i].major,
+          opengl_versions[i].minor, contextFlags, profileMask);
 
-    wglMakeCurrent (device, context_wgl->wgl_context);
+      if (context_wgl->wgl_context) {
+        context_wgl->priv->context_api = GST_GL_API_OPENGL3;
+        break;
+      }
+    }
+  }
 
-    wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
-        wglGetProcAddress ("wglCreateContextAttribsARB");
+  if (!context_wgl->wgl_context) {
+    context_wgl->wgl_context = wglCreateContext (device);
 
-    if (wglCreateContextAttribsARB != NULL) {
-      wglMakeCurrent (device, 0);
-      wglDeleteContext (context_wgl->wgl_context);
-      context_wgl->wgl_context =
-          wglCreateContextAttribsARB (device, external_gl_context, 0);
-      if (context_wgl->wgl_context == NULL) {
+    if (!context_wgl->wgl_context) {
+      g_set_error (error, GST_GL_CONTEXT_ERROR,
+          GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
+          "Failed to create WGL context 0x%x", (unsigned int) GetLastError ());
+      goto failure;
+    }
+
+    if (external_gl_context) {
+      if (!wglShareLists (external_gl_context, context_wgl->wgl_context)) {
         g_set_error (error, GST_GL_CONTEXT_ERROR,
             GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
-            "failed to share context through wglCreateContextAttribsARB 0x%x",
+            "failed to share contexts through wglShareLists 0x%x",
             (unsigned int) GetLastError ());
         goto failure;
       }
-    } else if (!wglShareLists (external_gl_context, context_wgl->wgl_context)) {
-      g_set_error (error, GST_GL_CONTEXT_ERROR,
-          GST_GL_CONTEXT_ERROR_CREATE_CONTEXT,
-          "failed to share contexts through wglShareLists 0x%x",
-          (unsigned int) GetLastError ());
-      goto failure;
     }
+
+    context_wgl->priv->context_api = GST_GL_API_OPENGL;
   }
 
   GST_LOG ("gl context id: %" G_GUINTPTR_FORMAT,
@@ -277,7 +367,9 @@ gst_gl_context_wgl_activate (GstGLContext * context, gboolean activate)
 GstGLAPI
 gst_gl_context_wgl_get_gl_api (GstGLContext * context)
 {
-  return GST_GL_API_OPENGL;
+  GstGLContextWGL *context_wgl = GST_GL_CONTEXT_WGL (context);
+
+  return context_wgl->priv->context_api;
 }
 
 static GstGLPlatform
index 0a3e0670eb25361eaa76059dedbc0e87aafe96ed..64bf14178ee8a531876572a62a141eb020261eaf 100644 (file)
@@ -34,6 +34,7 @@ G_BEGIN_DECLS
 
 typedef struct _GstGLContextWGL        GstGLContextWGL;
 typedef struct _GstGLContextWGLClass   GstGLContextWGLClass;
+typedef struct _GstGLContextWGLPrivate GstGLContextWGLPrivate;
 
 struct _GstGLContextWGL {
   /*< private >*/
@@ -42,6 +43,8 @@ struct _GstGLContextWGL {
   HGLRC wgl_context;
   HGLRC external_gl_context;
 
+  GstGLContextWGLPrivate *priv;
+
   gpointer _reserved[GST_PADDING];
 };
 
index e1e9fbbc2354b28c60116521e4447627fe179fe0..bc83230a8438f68e855006528d0f3f8cffd972a6 100644 (file)
@@ -36,6 +36,7 @@
 
 #include <gst/gl/gl.h>
 #include "gstglcontext_glx.h"
+#include "../utils/opengl_versions.h"
 
 #define GST_CAT_DEFAULT gst_gl_context_debug
 
@@ -137,35 +138,6 @@ _describe_fbconfig (Display * display, GLXFBConfig config)
   GST_DEBUG ("stencil: %d", val);
 }
 
-/* list of known OpenGL versions */
-/* *INDENT-OFF* */
-static const struct { int major, minor; } gl_versions[] = {
-   {4, 5},
-   {4, 4},
-   {4, 3},
-   {4, 2},
-   {4, 1},
-   {4, 0},
-
-   {3, 3},
-   {3, 2},
-   {3, 1},
-   {3, 0},
-
-   {2, 1},
-   {2, 0},
-
-   {1, 5},
-   {1, 4},
-   {1, 3},
-   {1, 2},
-   {1, 1},
-   {1, 0},
-
-   {0, 0} /* end of list */
-};
-/* *INDENT-ON* */
-
 static GLXContext
 _create_context_with_flags (GstGLContextGLX * context_glx, Display * dpy,
     GLXFBConfig fbconfig, GLXContext share_context, gint major, gint minor,
@@ -252,12 +224,13 @@ gst_gl_context_glx_create_context (GstGLContext * context,
       && context_glx->priv->glXCreateContextAttribsARB) {
     gint i;
 
-    for (i = 0; i < G_N_ELEMENTS (gl_versions); i++) {
+    for (i = 0; i < G_N_ELEMENTS (opengl_versions); i++) {
       gint profileMask = 0;
       gint contextFlags = 0;
 
-      if ((gl_versions[i].major > 3
-              || (gl_versions[i].major == 3 && gl_versions[i].minor >= 2))) {
+      if ((opengl_versions[i].major > 3
+              || (opengl_versions[i].major == 3
+                  && opengl_versions[i].minor >= 2))) {
         profileMask |= GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
         contextFlags |= GLX_CONTEXT_DEBUG_BIT_ARB;
       } else {
@@ -265,12 +238,12 @@ gst_gl_context_glx_create_context (GstGLContext * context,
       }
 
       GST_DEBUG_OBJECT (context, "trying to create a GL %d.%d context",
-          gl_versions[i].major, gl_versions[i].minor);
+          opengl_versions[i].major, opengl_versions[i].minor);
 
       context_glx->glx_context = _create_context_with_flags (context_glx,
           device, context_glx->priv->fbconfigs[0],
-          (GLXContext) external_gl_context, gl_versions[i].major,
-          gl_versions[i].minor, contextFlags, profileMask);
+          (GLXContext) external_gl_context, opengl_versions[i].major,
+          opengl_versions[i].minor, contextFlags, profileMask);
 
       if (context_glx->glx_context) {
         context_glx->priv->context_api = GST_GL_API_OPENGL3;