[waffle] [PATCH 12/18] wgl: fully support ARB_create_context and EXT_create_context_es_profile.

Emil Velikov emil.l.velikov at gmail.com
Tue Jul 22 20:31:38 PDT 2014


Follow the specs and return correct error values when invalid context
attributes are provided.

Both extensions are virtually identical to their GLX counterparts,
as such copy the relevant implementation from waffle's GLX backend.

Signed-off-by: Emil Velikov <emil.l.velikov at gmail.com>
---
 src/waffle/wgl/wgl_config.c  |  99 +++++++++++++++++++++++++++++++-
 src/waffle/wgl/wgl_config.h  |   2 +
 src/waffle/wgl/wgl_context.c | 134 ++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 231 insertions(+), 4 deletions(-)

diff --git a/src/waffle/wgl/wgl_config.c b/src/waffle/wgl/wgl_config.c
index 1051153..9dea991 100644
--- a/src/waffle/wgl/wgl_config.c
+++ b/src/waffle/wgl/wgl_config.c
@@ -27,9 +27,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <windows.h>
-// XXX: Do we want to include these two, or should we redefine the WGL* consts ?
-#include <GL/gl.h>
-#include <GL/wglext.h>
 
 #include "wcore_config_attrs.h"
 #include "wcore_error.h"
@@ -57,6 +54,98 @@ wgl_config_destroy(struct wcore_config *wc_self)
     return ok;
 }
 
+/// @brief Check the values of `attrs->context_*`.
+static bool
+wgl_config_check_context_attrs(struct wgl_display *dpy,
+                               const struct wcore_config_attrs *attrs)
+{
+    if (attrs->context_forward_compatible) {
+        assert(attrs->context_api == WAFFLE_CONTEXT_OPENGL);
+        assert(wcore_config_attrs_version_ge(attrs, 30));
+    }
+
+    if (attrs->context_debug && !dpy->ARB_create_context) {
+        wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+                     "WGL_ARB_create_context is required in order to "
+                     "request a debug context");
+        return false;
+    }
+
+    switch (attrs->context_api) {
+        case WAFFLE_CONTEXT_OPENGL:
+            if (!wcore_config_attrs_version_eq(attrs, 10) && !dpy->ARB_create_context) {
+                wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+                             "WGL_ARB_create_context is required in order to "
+                             "request an OpenGL version not equal to the default "
+                             "value 1.0");
+                return false;
+            }
+            else if (wcore_config_attrs_version_ge(attrs, 32) && !dpy->ARB_create_context_profile) {
+                wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+                             "WGL_ARB_create_context_profile is required "
+                             "to create a context with version >= 3.2");
+                return false;
+            }
+            else if (wcore_config_attrs_version_ge(attrs, 32)) {
+                assert(attrs->context_profile == WAFFLE_CONTEXT_CORE_PROFILE ||
+                       attrs->context_profile == WAFFLE_CONTEXT_COMPATIBILITY_PROFILE);
+            }
+
+            if (attrs->context_forward_compatible && !dpy->ARB_create_context) {
+                wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+                             "WGL_ARB_create_context is required in order to "
+                             "request a forward-compatible context");
+                return false;
+            }
+
+            return true;
+
+        case WAFFLE_CONTEXT_OPENGL_ES1:
+            assert(wcore_config_attrs_version_eq(attrs, 10) ||
+                   wcore_config_attrs_version_eq(attrs, 11));
+            assert(!attrs->context_forward_compatible);
+
+            if (!dpy->EXT_create_context_es_profile) {
+                wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+                             "WGL_EXT_create_context_es_profile is required "
+                             "to create an OpenGL ES1 context");
+                return false;
+            }
+
+            return true;
+
+        case WAFFLE_CONTEXT_OPENGL_ES2:
+            assert(attrs->context_major_version == 2);
+            assert(!attrs->context_forward_compatible);
+
+            if (!dpy->EXT_create_context_es2_profile) {
+                wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+                             "WGL_EXT_create_context_es2_profile is required "
+                             "to create an OpenGL ES2 context");
+                return false;
+            }
+
+            return true;
+
+        case WAFFLE_CONTEXT_OPENGL_ES3:
+            assert(attrs->context_major_version == 3);
+
+            if (!dpy->EXT_create_context_es_profile) {
+                wcore_errorf(WAFFLE_ERROR_UNSUPPORTED_ON_PLATFORM,
+                             "WGL_EXT_create_context_es_profile is required "
+                             "to create an OpenGL ES3 context");
+                return false;
+            }
+
+            return true;
+
+        default:
+            wcore_error_internal("context_api has bad value %#x",
+                                 attrs->context_api);
+            return false;
+    }
+}
+
 static void
 wgl_config_set_pixeldescriptor(struct wgl_config *config,
                                const struct wcore_config_attrs *attrs)
@@ -171,6 +260,10 @@ wgl_config_choose(struct wcore_platform *wc_plat,
     struct wcore_window *wc_window;
     bool ok;
 
+    ok = wgl_config_check_context_attrs(dpy, attrs);
+    if (!ok)
+        return NULL;
+
     self = wcore_calloc(sizeof(*self));
     if (!self)
         return NULL;
diff --git a/src/waffle/wgl/wgl_config.h b/src/waffle/wgl/wgl_config.h
index 822cc85..6722398 100644
--- a/src/waffle/wgl/wgl_config.h
+++ b/src/waffle/wgl/wgl_config.h
@@ -27,6 +27,8 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <GL/gl.h>
+#include <GL/wglext.h>
 
 #include "wcore_config.h"
 #include "wcore_util.h"
diff --git a/src/waffle/wgl/wgl_context.c b/src/waffle/wgl/wgl_context.c
index ce4ff11..da783ad 100644
--- a/src/waffle/wgl/wgl_context.c
+++ b/src/waffle/wgl/wgl_context.c
@@ -31,6 +31,7 @@
 
 #include "wgl_config.h"
 #include "wgl_context.h"
+#include "wgl_display.h"
 #include "wgl_error.h"
 #include "wgl_window.h"
 
@@ -51,12 +52,143 @@ wgl_context_destroy(struct wcore_context *wc_self)
     return ok;
 }
 
+
+/// @brief Fill @a attrib_list, which will be given to wglCreateContextAttribsARB().
+///
+/// This does not validate the `config->context_*` attributes. That validation
+/// occurred during waffle_config_choose().
+static bool
+wgl_context_fill_attrib_list(struct wgl_config *config,
+                             int attrib_list[])
+{
+    struct wcore_config_attrs *attrs = &config->wcore.attrs;
+    int i = 0;
+    int context_flags = 0;
+
+    // XXX: Check if the following workaround is relevant under Windows.
+
+    // As a workaround for NVidia, do not specify
+    // WGL_CONTEXT_MAJOR_VERSION_ARB and WGL_CONTEXT_MINOR_VERSION_ARB in the
+    // call to wglCreateContextAttribsARB if the user requested an OpenGL
+    // context of unspecified version or if the user explicitly requested an
+    // OpenGL 1.0 context.
+    //
+    // Calling wglCreateContextAttribARB with MAJOR=1 and MINOR=0, according
+    // to the spec, is equivalent to calling it with MAJOR and MINOR
+    // unspecified.  From the WGL_ARB_create_context spec:
+    //
+    //     If an attribute is not specified in <attrib_list>,
+    //     then the default value specified below is used instead.
+    //
+    //     The default values for WGL_CONTEXT_MAJOR_VERSION_ARB and
+    //     WGL_CONTEXT_MINOR_VERSION_ARB are 1 and 0 respectively. In this
+    //     case, implementations will typically return the most recent version
+    //     of OpenGL they support which is backwards compatible with OpenGL 1.0
+    //     (e.g. 3.0, 3.1 + GL_ARB_compatibility, or 3.2 compatibility profile)
+    //
+    // However, NVidia's libGL, circa 2012-12-19, is not compliant. Calling
+    // wglCreateContextAttribsARB with MAJOR=1 and MINOR=0 returns an OpenGL
+    // 2.1 context. Calling it with MAJOR and MINOR unspecified returns
+    // a context of the latest supported OpenGL version.
+    if (!(wcore_config_attrs_version_eq(attrs, 10) &&
+          attrs->context_api == WAFFLE_CONTEXT_OPENGL))
+    {
+        attrib_list[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
+        attrib_list[i++] = attrs->context_major_version;
+
+        attrib_list[i++] = WGL_CONTEXT_MINOR_VERSION_ARB;
+        attrib_list[i++] = attrs->context_minor_version;
+    }
+
+    switch (attrs->context_api) {
+        case WAFFLE_CONTEXT_OPENGL:
+            if (wcore_config_attrs_version_ge(attrs, 32)) {
+                switch (attrs->context_profile) {
+                    case WAFFLE_CONTEXT_CORE_PROFILE:
+                        attrib_list[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
+                        attrib_list[i++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
+                        break;
+                    case WAFFLE_CONTEXT_COMPATIBILITY_PROFILE:
+                        attrib_list[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
+                        attrib_list[i++] = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
+                        break;
+                    default:
+                        assert(false);
+                        break;
+                }
+            }
+
+            if (attrs->context_forward_compatible) {
+                context_flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
+            }
+
+            break;
+        case WAFFLE_CONTEXT_OPENGL_ES1:
+        case WAFFLE_CONTEXT_OPENGL_ES2:
+        case WAFFLE_CONTEXT_OPENGL_ES3:
+            attrib_list[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
+            attrib_list[i++] = WGL_CONTEXT_ES_PROFILE_BIT_EXT;
+            break;
+    }
+
+    if (attrs->context_debug) {
+        context_flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
+    }
+
+    if (context_flags != 0) {
+        attrib_list[i++] = WGL_CONTEXT_FLAGS_ARB;
+        attrib_list[i++] = context_flags;
+    }
+
+    attrib_list[i++] = 0;
+    return true;
+}
+
+static HGLRC
+wgl_context_create_native(struct wgl_config *config,
+                          struct wgl_context *share_ctx)
+{
+    struct wgl_display *dpy = wgl_display(config->wcore.display);
+    HGLRC real_share_ctx = share_ctx ? share_ctx->hglrc : NULL;
+    HGLRC hglrc;
+
+    if (dpy->ARB_create_context) {
+        bool ok;
+
+        // Choose a large size to prevent accidental overflow.
+        int attrib_list[64];
+
+        ok = wgl_context_fill_attrib_list(config, attrib_list);
+        if (!ok)
+            return NULL;
+
+        hglrc = dpy->wglCreateContextAttribsARB(config->window->hDC,
+                                                real_share_ctx,
+                                                attrib_list);
+        if (!hglrc) {
+            wcore_errorf(WAFFLE_ERROR_UNKNOWN,
+                         "glXCreateContextAttribsARB failed");
+            return NULL;
+        }
+    }
+    else {
+        hglrc = wglCreateContext(config->window->hDC);
+        if (!hglrc) {
+            wcore_errorf(WAFFLE_ERROR_UNKNOWN, "wglCreateContext failed");
+            return NULL;
+        }
+    }
+
+    return hglrc;
+}
+
 struct wcore_context*
 wgl_context_create(struct wcore_platform *wc_plat,
                    struct wcore_config *wc_config,
                    struct wcore_context *wc_share_ctx)
 {
     struct wgl_config *config = wgl_config(wc_config);
+    struct wgl_context *share_ctx = wgl_context(wc_share_ctx);
     struct wgl_context *self;
     int error;
 
@@ -68,7 +200,7 @@ wgl_context_create(struct wcore_platform *wc_plat,
     if (error)
         goto fail;
 
-    self->hglrc = wglCreateContext(config->window->hDC);
+    self->hglrc = wgl_context_create_native(config, share_ctx);
     if (!self->hglrc)
         goto fail;
 
-- 
2.0.2



More information about the waffle mailing list