[PATCH 4/5] wined3d: Add a setting for the maximum OpenGL version to use.

Matteo Bruni mbruni at codeweavers.com
Mon Jul 6 15:20:13 CDT 2015


---
sort-of-v2: Allow to set a maximum GL version instead of a core/legacy
profile switch, flag the context type with a WINED3D_GL_ "extension".
Drop the DEBUG_BIT part from wined3d_adapter_init() since
at that point the gl_info->supported[] flags aren't initialized yet.

A lot of stuff is still missing so 3.2 core profile doesn't work at the
moment (it's going to crash if you enable the option, actually). Still I
need something like this to avoid adding dead code moving forward.
---
 dlls/wined3d/context.c         |  25 ++++++--
 dlls/wined3d/directx.c         | 139 ++++++++++++++++++++++++++++++++++-------
 dlls/wined3d/wined3d_gl.h      |   1 +
 dlls/wined3d/wined3d_main.c    |  12 ++++
 dlls/wined3d/wined3d_private.h |   5 +-
 5 files changed, 151 insertions(+), 31 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 9cc7c11..faf8e82 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -1558,20 +1558,35 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
     if (gl_info->p_wglCreateContextAttribsARB)
     {
         unsigned int ctx_attrib_idx = 0;
-        GLint ctx_attribs[3];
+        GLint ctx_attribs[7], ctx_flags = 0;
 
         if (context_debug_output_enabled(gl_info))
+            ctx_flags = WGL_CONTEXT_DEBUG_BIT_ARB;
+        ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
+        ctx_attribs[ctx_attrib_idx++] = gl_info->selected_gl_version >> 16;
+        ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_MINOR_VERSION_ARB;
+        ctx_attribs[ctx_attrib_idx++] = gl_info->selected_gl_version & 0xffff;
+        if (gl_info->selected_gl_version >= MAKEDWORD_VERSION(3, 2))
+            ctx_flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
+        if (ctx_flags)
         {
             ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_FLAGS_ARB;
-            ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_DEBUG_BIT_ARB;
+            ctx_attribs[ctx_attrib_idx++] = ctx_flags;
         }
         ctx_attribs[ctx_attrib_idx] = 0;
 
         if (!(ctx = gl_info->p_wglCreateContextAttribsARB(hdc, share_ctx, ctx_attribs)))
         {
-            ERR("Failed to create a WGL context.\n");
-            context_release(ret);
-            goto out;
+            if (ctx_flags & WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB)
+            {
+                ctx_attribs[ctx_attrib_idx - 1] &= ~WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
+                if (!(ctx = gl_info->p_wglCreateContextAttribsARB(hdc, share_ctx, ctx_attribs)))
+                {
+                    ERR("Failed to create a WGL context.\n");
+                    context_release(ret);
+                    goto out;
+                }
+            }
         }
     }
     else
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 059332d..dafcc50 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -279,19 +279,19 @@ static void wined3d_caps_gl_ctx_destroy(const struct wined3d_caps_gl_ctx *ctx)
         ERR("Failed to restore previous GL context.\n");
 }
 
-static void wined3d_caps_gl_ctx_create_attribs(struct wined3d_caps_gl_ctx *caps_gl_ctx,
+static BOOL wined3d_caps_gl_ctx_create_attribs(struct wined3d_caps_gl_ctx *caps_gl_ctx,
         struct wined3d_gl_info *gl_info, const GLint *ctx_attribs)
 {
     HGLRC new_ctx;
 
     if (!(gl_info->p_wglCreateContextAttribsARB = (void *)wglGetProcAddress("wglCreateContextAttribsARB")))
-        return;
+        return TRUE;
 
     if (!(new_ctx = gl_info->p_wglCreateContextAttribsARB(caps_gl_ctx->dc, NULL, ctx_attribs)))
     {
         ERR("Failed to create a context using wglCreateContextAttribsARB(), last error %#x.\n", GetLastError());
         gl_info->p_wglCreateContextAttribsARB = NULL;
-        return;
+        return FALSE;
     }
 
     if (!wglMakeCurrent(caps_gl_ctx->dc, new_ctx))
@@ -300,12 +300,14 @@ static void wined3d_caps_gl_ctx_create_attribs(struct wined3d_caps_gl_ctx *caps_
         if (!wglDeleteContext(new_ctx))
             ERR("Failed to delete new context, last error %#x.\n", GetLastError());
         gl_info->p_wglCreateContextAttribsARB = NULL;
-        return;
+        return TRUE;
     }
 
     if (!wglDeleteContext(caps_gl_ctx->gl_ctx))
         ERR("Failed to delete old context, last error %#x.\n", GetLastError());
     caps_gl_ctx->gl_ctx = new_ctx;
+
+    return TRUE;
 }
 
 static BOOL wined3d_caps_gl_ctx_create(struct wined3d_caps_gl_ctx *ctx)
@@ -2420,6 +2422,30 @@ static void parse_extension_string(struct wined3d_gl_info *gl_info, const char *
     }
 }
 
+static void enumerate_gl_extensions(struct wined3d_gl_info *gl_info,
+        const struct wined3d_extension_map *map, unsigned int map_entries_count)
+{
+    const char *gl_extension_name;
+    unsigned int i, j;
+    GLint extensions_count;
+
+    glGetIntegerv(GL_NUM_EXTENSIONS, &extensions_count);
+    for (i = 0; i < extensions_count; ++i)
+    {
+        gl_extension_name = (const char *)GL_EXTCALL(glGetStringi(GL_EXTENSIONS, i));
+        TRACE("- %s.\n", debugstr_a(gl_extension_name));
+        for (j = 0; j < map_entries_count; ++j)
+        {
+            if (!strcmp(gl_extension_name, map[j].extension_string))
+            {
+                TRACE("FOUND: %s support.\n", map[j].extension_string);
+                gl_info->supported[map[j].extension] = TRUE;
+                break;
+            }
+        }
+    }
+}
+
 static void load_gl_funcs(struct wined3d_gl_info *gl_info)
 {
 #define USE_GL_FUNC(pfn) gl_info->gl_ops.ext.p_##pfn = (void *)wglGetProcAddress(#pfn);
@@ -2912,6 +2938,7 @@ static void load_gl_funcs(struct wined3d_gl_info *gl_info)
     USE_GL_FUNC(glGetShaderInfoLog)         /* OpenGL 2.0 */
     USE_GL_FUNC(glGetShaderiv)              /* OpenGL 2.0 */
     USE_GL_FUNC(glGetShaderSource)          /* OpenGL 2.0 */
+    USE_GL_FUNC(glGetStringi)               /* OpenGL 3.0 */
     USE_GL_FUNC(glGetUniformfv)             /* OpenGL 2.0 */
     USE_GL_FUNC(glGetUniformiv)             /* OpenGL 2.0 */
     USE_GL_FUNC(glGetUniformLocation)       /* OpenGL 2.0 */
@@ -3324,12 +3351,12 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter *adapter)
     struct fragment_caps fragment_caps;
     struct shader_caps shader_caps;
     const char *WGL_Extensions = NULL;
-    const char *GL_Extensions = NULL;
     enum wined3d_gl_vendor gl_vendor;
     enum wined3d_pci_device device;
     DWORD gl_version;
     HDC hdc;
     unsigned int i;
+    GLint context_profile;
 
     TRACE("adapter %p.\n", adapter);
 
@@ -3359,23 +3386,37 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter *adapter)
     }
     gl_version = wined3d_parse_gl_version(gl_version_str);
 
-    /* Parse the gl supported features, in theory enabling parts of our code appropriately. */
-    GL_Extensions = (const char *)gl_info->gl_ops.gl.p_glGetString(GL_EXTENSIONS);
-    if (!GL_Extensions)
-    {
-        ERR("Received a NULL GL_EXTENSIONS.\n");
-        return FALSE;
-    }
+    load_gl_funcs(gl_info);
 
     memset(gl_info->supported, 0, sizeof(gl_info->supported));
     gl_info->supported[WINED3D_GL_EXT_NONE] = TRUE;
 
+    glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &context_profile);
+    if (glGetError() != GL_NO_ERROR)
+        context_profile = 0;
+    if (context_profile & GL_CONTEXT_CORE_PROFILE_BIT)
+        TRACE("Got a core profile context.\n");
+    else
+        gl_info->supported[WINED3D_GL_LEGACY_CONTEXT] = TRUE;
+
     TRACE("GL extensions reported:\n");
-    parse_extension_string(gl_info, GL_Extensions, gl_extension_map,
-            sizeof(gl_extension_map) / sizeof(*gl_extension_map));
+    if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
+    {
+        const char *gl_extensions = (const char *)gl_info->gl_ops.gl.p_glGetString(GL_EXTENSIONS);
 
-    /* Now work out what GL support this card really has. */
-    load_gl_funcs( gl_info );
+        if (!gl_extensions)
+        {
+            ERR("Received a NULL GL_EXTENSIONS.\n");
+            return FALSE;
+        }
+        parse_extension_string(gl_info, gl_extensions, gl_extension_map,
+                sizeof(gl_extension_map) / sizeof(*gl_extension_map));
+    }
+    else
+    {
+        enumerate_gl_extensions(gl_info, gl_extension_map,
+                sizeof(gl_extension_map) / sizeof(*gl_extension_map));
+    }
 
     hdc = wglGetCurrentDC();
     /* Not all GL drivers might offer WGL extensions e.g. VirtualBox. */
@@ -5667,11 +5708,17 @@ static void wined3d_adapter_init_fb_cfgs(struct wined3d_adapter *adapter, HDC dc
 
 static BOOL wined3d_adapter_init(struct wined3d_adapter *adapter, UINT ordinal)
 {
+    static const DWORD supported_gl_versions[] =
+    {
+        MAKEDWORD_VERSION(3, 2),
+        MAKEDWORD_VERSION(1, 0),
+    };
     struct wined3d_gl_info *gl_info = &adapter->gl_info;
     struct wined3d_caps_gl_ctx caps_gl_ctx = {0};
-    unsigned int ctx_attrib_idx = 0;
+    unsigned int i, ctx_attrib_idx = 0;
     DISPLAY_DEVICEW display_device;
-    GLint ctx_attribs[3];
+    GLint ctx_attribs[7], ctx_flags = 0;
+    BOOL ret;
 
     TRACE("adapter %p, ordinal %u.\n", adapter, ordinal);
 
@@ -5717,13 +5764,59 @@ static BOOL wined3d_adapter_init(struct wined3d_adapter *adapter, UINT ordinal)
         return FALSE;
     }
 
-    if (context_debug_output_enabled(gl_info))
+    for (i = 0; i < ARRAY_SIZE(supported_gl_versions); ++i)
+    {
+        if (supported_gl_versions[i] <= wined3d_settings.max_gl_version)
+        {
+            if (supported_gl_versions[i] != wined3d_settings.max_gl_version)
+                ERR_(winediag)("Requested GL version %u.%u which is unsupported, trying version %u.%u instead.\n",
+                        wined3d_settings.max_gl_version >> 16, wined3d_settings.max_gl_version & 0xffff,
+                        supported_gl_versions[i] >> 16, supported_gl_versions[i] & 0xffff);
+            break;
+        }
+    }
+    if (i == ARRAY_SIZE(supported_gl_versions))
+    {
+        ERR_(winediag)("Requested invalid GL version %u.%u.\n",
+                wined3d_settings.max_gl_version >> 16, wined3d_settings.max_gl_version & 0xffff);
+        i = ARRAY_SIZE(supported_gl_versions) - 1;
+    }
+
+    for (; i < ARRAY_SIZE(supported_gl_versions); ++i)
     {
-        ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_FLAGS_ARB;
-        ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_DEBUG_BIT_ARB;
+        unsigned int major = supported_gl_versions[i] >> 16;
+        unsigned int minor = supported_gl_versions[i] & 0xffff;
+
+        gl_info->selected_gl_version = supported_gl_versions[i];
+
+        ctx_flags = 0;
+        if (supported_gl_versions[i] >= MAKEDWORD_VERSION(3, 2))
+            ctx_flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
+
+        /* WGL_create_context specifies that the context returned may implement
+         * a newer OpenGL version than requested, as long as it doesn't remove
+         * any feature of the requested version. */
+        ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
+        ctx_attribs[ctx_attrib_idx++] = major;
+        ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_MINOR_VERSION_ARB;
+        ctx_attribs[ctx_attrib_idx++] = minor;
+        if (ctx_flags)
+        {
+            ctx_attribs[ctx_attrib_idx++] = WGL_CONTEXT_FLAGS_ARB;
+            ctx_attribs[ctx_attrib_idx++] = ctx_flags;
+        }
+        ctx_attribs[ctx_attrib_idx] = 0;
+        if (!(ret = wined3d_caps_gl_ctx_create_attribs(&caps_gl_ctx, gl_info, ctx_attribs))
+                && ctx_flags & WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB)
+        {
+            ctx_attribs[ctx_attrib_idx - 1] &= ~WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
+            ret = wined3d_caps_gl_ctx_create_attribs(&caps_gl_ctx, gl_info, ctx_attribs);
+        }
+        if (ret)
+            break;
+
+        WARN("Couldn't create an OpenGL %u.%u context, trying fallback to a lower version.\n", major, minor);
     }
-    ctx_attribs[ctx_attrib_idx] = 0;
-    wined3d_caps_gl_ctx_create_attribs(&caps_gl_ctx, gl_info, ctx_attribs);
 
     if (!wined3d_adapter_init_gl_caps(adapter))
     {
diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h
index 4257cd2..8c07ed1 100644
--- a/dlls/wined3d/wined3d_gl.h
+++ b/dlls/wined3d/wined3d_gl.h
@@ -162,6 +162,7 @@ enum wined3d_gl_extension
     /* Internally used */
     WINED3D_GL_BLEND_EQUATION,
     WINED3D_GL_NORMALIZED_TEXRECT,
+    WINED3D_GL_LEGACY_CONTEXT,
     WINED3D_GL_VERSION_2_0,
 
     WINED3D_GL_EXT_COUNT,
diff --git a/dlls/wined3d/wined3d_main.c b/dlls/wined3d/wined3d_main.c
index 758ba43..1520493 100644
--- a/dlls/wined3d/wined3d_main.c
+++ b/dlls/wined3d/wined3d_main.c
@@ -25,6 +25,8 @@
 #include "config.h"
 #include "wine/port.h"
 
+#include <stdio.h>
+
 #include "initguid.h"
 #include "wined3d_private.h"
 
@@ -72,6 +74,7 @@ static CRITICAL_SECTION wined3d_wndproc_cs = {&wined3d_wndproc_cs_debug, -1, 0,
  * where appropriate. */
 struct wined3d_settings wined3d_settings =
 {
+    MAKEDWORD_VERSION(1, 0), /* Default to legacy OpenGL */
     TRUE,           /* Use of GLSL enabled by default */
     ORM_FBO,        /* Use FBOs to do offscreen rendering */
     PCI_VENDOR_NONE,/* PCI Vendor ID */
@@ -199,6 +202,15 @@ static BOOL wined3d_dll_init(HINSTANCE hInstDLL)
 
     if (hkey || appkey)
     {
+        if (!get_config_key(hkey, appkey, "MaxGLVersion", buffer, size))
+        {
+            unsigned int major, minor;
+
+            if (sscanf(buffer, "%u.%u", &major, &minor) == 2)
+                wined3d_settings.max_gl_version = MAKEDWORD_VERSION(major, minor);
+            else
+                ERR_(winediag)("Couldn't parse the requested maximum OpenGL version.\n");
+        }
         if ( !get_config_key( hkey, appkey, "UseGLSL", buffer, size) )
         {
             if (!strcmp(buffer,"disabled"))
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b7fa4c6..aa795c6 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -262,9 +262,7 @@ static inline float float_24_to_32(DWORD in)
  * values in wined3d_main.c as well. */
 struct wined3d_settings
 {
-    /* Ideally, we don't want the user to have to request GLSL. If the
-     * hardware supports GLSL, we should use it. However, until it's fully
-     * implemented, we'll leave it as a registry setting for developers. */
+    DWORD max_gl_version;
     BOOL glslRequested;
     int offscreen_rendering_mode;
     unsigned short pci_vendor_id;
@@ -1713,6 +1711,7 @@ struct wined3d_gl_limits
 
 struct wined3d_gl_info
 {
+    DWORD selected_gl_version;
     DWORD glsl_version;
     struct wined3d_gl_limits limits;
     DWORD reserved_glsl_constants, reserved_arb_constants;
-- 
2.3.6




More information about the wine-patches mailing list