 
            I plan to do the same to extensions.
 
            From: Jacek Caban jacek@codeweavers.com
And store version in the context struct. --- dlls/opengl32/unix_wgl.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index caeefeea18e..3b27046b4d9 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -133,6 +133,8 @@ struct context HGLRC share; /* context to be shared with */ int *attribs; /* creation attributes */ DWORD tid; /* thread that the context is current in */ + int major_version; /* major GL version */ + int minor_version; /* minor GL version */ UINT64 debug_callback; /* client pointer */ UINT64 debug_user; /* client pointer */ GLubyte *extensions; /* extension string */ @@ -838,6 +840,19 @@ static BOOL check_extension_support( TEB *teb, const char *extension, const char return FALSE; }
+static void sync_context_version( TEB *teb, struct context *ctx ) +{ + const struct opengl_funcs *funcs = teb->glTable; + const char *version; + + if (ctx->major_version) return; /* already synced */ + + version = (const char *)funcs->p_glGetString( GL_VERSION ); + if (version) parse_gl_version( version, &ctx->major_version, &ctx->minor_version ); + if (!ctx->major_version) ctx->major_version = 1; + TRACE( "context %p version %d.%d\n", ctx, ctx->major_version, ctx->minor_version ); +} + static BOOL get_default_fbo_integer( struct context *ctx, struct opengl_drawable *draw, struct opengl_drawable *read, GLenum pname, GLint *data ) { @@ -1008,24 +1023,14 @@ static char *build_extension_list( TEB *teb ) return available_extensions; }
-static UINT get_context_major_version( TEB *teb ) -{ - struct context *ctx; - - if (!(ctx = get_current_context( teb, NULL, NULL ))) return TRUE; - for (const int *attr = ctx->attribs; attr && attr[0]; attr += 2) - if (attr[0] == WGL_CONTEXT_MAJOR_VERSION_ARB) return attr[1]; - - return 1; -} - /* Check if a GL extension is supported */ -static BOOL is_extension_supported( TEB *teb, const char *extension ) +static BOOL is_extension_supported( TEB *teb, struct context *ctx, const char *extension ) { char *available_extensions = NULL; BOOL ret = FALSE;
- if (get_context_major_version( teb ) < 3) available_extensions = strdup( (const char *)wrap_glGetString( teb, GL_EXTENSIONS ) ); + sync_context_version( teb, ctx ); + if (ctx->major_version < 3) available_extensions = strdup( (const char *)wrap_glGetString( teb, GL_EXTENSIONS ) ); if (!available_extensions) available_extensions = build_extension_list( teb );
if (!available_extensions) ERR( "No OpenGL extensions found, check if your OpenGL setup is correct!\n" ); @@ -1046,11 +1051,12 @@ PROC wrap_wglGetProcAddress( TEB *teb, LPCSTR name ) const struct registry_entry entry = {.name = name}, *found; struct opengl_funcs *funcs = teb->glTable; const void **func_ptr; + struct context *ctx;
/* Without an active context opengl32 doesn't know to what * driver it has to dispatch wglGetProcAddress. */ - if (!get_current_context( teb, NULL, NULL )) + if (!(ctx = get_current_context( teb, NULL, NULL ))) { WARN( "No active WGL context found\n" ); return (void *)-1; @@ -1067,7 +1073,7 @@ PROC wrap_wglGetProcAddress( TEB *teb, LPCSTR name ) { void *driver_func = funcs->p_wglGetProcAddress( name );
- if (!is_extension_supported( teb, found->extension )) + if (!is_extension_supported( teb, ctx, found->extension )) { unsigned int i; static const struct { const char *name, *alt; } alternatives[] =
 
            From: Jacek Caban jacek@codeweavers.com
--- dlls/opengl32/unix_wgl.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-)
diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index 3b27046b4d9..454e94f7a3d 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -792,9 +792,8 @@ static const GLuint *disabled_extensions_index( TEB *teb ) }
/* Check if a GL extension is supported */ -static BOOL check_extension_support( TEB *teb, const char *extension, const char *available_extensions ) +static BOOL check_extension_support( struct context *ctx, const char *extension, const char *available_extensions ) { - const struct opengl_funcs *funcs = teb->glTable; size_t len;
TRACE( "Checking for extension '%s'\n", extension ); @@ -816,21 +815,15 @@ static BOOL check_extension_support( TEB *teb, const char *extension, const char * Check if we are searching for a core GL function */ if (!strncmp( extension, "GL_VERSION_", 11 )) { - const GLubyte *gl_version = funcs->p_glGetString( GL_VERSION ); - const char *version = extension + 11; /* Move past 'GL_VERSION_' */ - - if (!gl_version) - { - ERR( "No OpenGL version found!\n" ); - return FALSE; - } + int major = extension[11] - '0'; /* Move past 'GL_VERSION_' */ + int minor = extension[13] - '0';
/* Compare the major/minor version numbers of the native OpenGL library and what is required by the function. * The gl_version string is guaranteed to have at least a major/minor and sometimes it has a release number as well. */ - if ((gl_version[0] > version[0]) || ((gl_version[0] == version[0]) && (gl_version[2] >= version[2]))) return TRUE; + if (ctx->major_version > major || (ctx->major_version == major && ctx->minor_version >= minor)) return TRUE;
- WARN( "The function requires OpenGL version '%c.%c' while your drivers only provide '%c.%c'\n", - version[0], version[2], gl_version[0], gl_version[2] ); + WARN( "The function requires OpenGL version '%d.%d' while your drivers only provide '%d.%d'\n", + major, minor, ctx->major_version, ctx->minor_version ); }
if (extension[len] == ' ') len++; @@ -1034,7 +1027,7 @@ static BOOL is_extension_supported( TEB *teb, struct context *ctx, const char *e if (!available_extensions) available_extensions = build_extension_list( teb );
if (!available_extensions) ERR( "No OpenGL extensions found, check if your OpenGL setup is correct!\n" ); - else ret = check_extension_support( teb, extension, available_extensions ); + else ret = check_extension_support( ctx, extension, available_extensions );
free( available_extensions ); return ret;
 
            From: Jacek Caban jacek@codeweavers.com
--- dlls/opengl32/unix_wgl.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index 454e94f7a3d..75355a610d8 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -844,6 +844,16 @@ static void sync_context_version( TEB *teb, struct context *ctx ) if (version) parse_gl_version( version, &ctx->major_version, &ctx->minor_version ); if (!ctx->major_version) ctx->major_version = 1; TRACE( "context %p version %d.%d\n", ctx, ctx->major_version, ctx->minor_version ); + + if (is_win64 && is_wow64()) + { + if (ctx->major_version > 4 || (ctx->major_version == 4 && ctx->minor_version > 3)) + { + FIXME( "GL version %d.%d is not supported on wow64, using 4.3\n ", ctx->major_version, ctx->minor_version ); + ctx->major_version = 4; + ctx->minor_version = 3; + } + } }
static BOOL get_default_fbo_integer( struct context *ctx, struct opengl_drawable *draw, struct opengl_drawable *read,
 
            From: Jacek Caban jacek@codeweavers.com
--- dlls/opengl32/unix_wgl.c | 50 +++++++++++++++------------------------- 1 file changed, 19 insertions(+), 31 deletions(-)
diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index 75355a610d8..343863d0c72 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -906,41 +906,29 @@ static BOOL get_integer( TEB *teb, GLenum pname, GLint *data ) return TRUE; }
- if (is_win64 && is_wow64()) - { - /* 4.4 depends on ARB_buffer_storage, which we don't support on wow64. */ - if (pname == GL_MAJOR_VERSION) - { - funcs->p_glGetIntegerv( pname, data ); - if (*data > 4) *data = 4; - return TRUE; - } - if (pname == GL_MINOR_VERSION) - { - GLint major; - funcs->p_glGetIntegerv( GL_MAJOR_VERSION, &major ); - funcs->p_glGetIntegerv( pname, data ); - if (major == 4 && *data > 3) *data = 3; - return TRUE; - } - } + if (!(ctx = get_current_context( teb, &draw, &read ))) return FALSE;
- if ((ctx = get_current_context( teb, &draw, &read ))) + switch (pname) { - if (pname == GL_DRAW_FRAMEBUFFER_BINDING && draw->draw_fbo) - { - *data = ctx->draw_fbo; - return TRUE; - } - if (pname == GL_READ_FRAMEBUFFER_BINDING && read->read_fbo) - { - *data = ctx->read_fbo; - return TRUE; - } - if (get_default_fbo_integer( ctx, draw, read, pname, data )) return TRUE; + case GL_MAJOR_VERSION: + sync_context_version( teb, ctx ); + *data = ctx->major_version; + return TRUE; + case GL_MINOR_VERSION: + sync_context_version( teb, ctx ); + *data = ctx->minor_version; + return TRUE; + case GL_DRAW_FRAMEBUFFER_BINDING: + if (!draw->draw_fbo) break; + *data = ctx->draw_fbo; + return TRUE; + case GL_READ_FRAMEBUFFER_BINDING: + if (!read->read_fbo) break; + *data = ctx->read_fbo; + return TRUE; }
- return FALSE; + return get_default_fbo_integer( ctx, draw, read, pname, data ); }
const GLubyte *wrap_glGetString( TEB *teb, GLenum name )
 
            From: Jacek Caban jacek@codeweavers.com
--- dlls/opengl32/unix_wgl.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-)
diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index 343863d0c72..b610d376e7b 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -139,7 +139,7 @@ struct context UINT64 debug_user; /* client pointer */ GLubyte *extensions; /* extension string */ GLuint *disabled_exts; /* indices of disabled extensions */ - GLubyte *wow64_version; /* wow64 GL version override */ + char *wow64_version; /* wow64 GL version override */ struct buffers *buffers; /* wow64 buffers map */ GLenum gl_error; /* wrapped GL error */
@@ -836,12 +836,12 @@ static BOOL check_extension_support( struct context *ctx, const char *extension, static void sync_context_version( TEB *teb, struct context *ctx ) { const struct opengl_funcs *funcs = teb->glTable; - const char *version; + const char *version, *rest = "";
if (ctx->major_version) return; /* already synced */
version = (const char *)funcs->p_glGetString( GL_VERSION ); - if (version) parse_gl_version( version, &ctx->major_version, &ctx->minor_version ); + if (version) rest = parse_gl_version( version, &ctx->major_version, &ctx->minor_version ); if (!ctx->major_version) ctx->major_version = 1; TRACE( "context %p version %d.%d\n", ctx, ctx->major_version, ctx->minor_version );
@@ -852,6 +852,7 @@ static void sync_context_version( TEB *teb, struct context *ctx ) FIXME( "GL version %d.%d is not supported on wow64, using 4.3\n ", ctx->major_version, ctx->minor_version ); ctx->major_version = 4; ctx->minor_version = 3; + asprintf( &ctx->wow64_version, "4.3%s", rest ); } } } @@ -945,21 +946,11 @@ const GLubyte *wrap_glGetString( TEB *teb, GLenum name ) GLuint **disabled = &ctx->disabled_exts; if (*extensions || filter_extensions( teb, (const char *)ret, extensions, disabled )) return *extensions; } - else if (name == GL_VERSION && is_win64 && is_wow64()) + else if (name == GL_VERSION) { struct context *ctx = get_current_context( teb, NULL, NULL ); - GLubyte **str = &ctx->wow64_version; - int major, minor; - - if (!*str) - { - const char *rest = parse_gl_version( (const char *)ret, &major, &minor ); - /* 4.4 depends on ARB_buffer_storage, which we don't support on wow64. */ - if (major > 4 || (major == 4 && minor >= 4)) asprintf( (char **)str, "4.3%s", rest ); - else *str = (GLubyte *)strdup( (char *)ret ); - } - - return *str; + sync_context_version( teb, ctx ); + if (ctx->wow64_version) return (const GLubyte *)ctx->wow64_version; } }
 
            Rémi Bernon (@rbernon) commented about dlls/opengl32/unix_wgl.c:
const struct registry_entry entry = {.name = name}, *found; struct opengl_funcs *funcs = teb->glTable; const void **func_ptr;
struct context *ctx;
/* Without an active context opengl32 doesn't know to what
- driver it has to dispatch wglGetProcAddress.
*/
- if (!get_current_context( teb, NULL, NULL ))
- if (!(ctx = get_current_context( teb, NULL, NULL ))) { WARN( "No active WGL context found\n" ); return (void *)-1; }
Arguably I think this is incorrect in the first place, unlike Vulkan, GL functions may be queried without a context and they get dispatched when called instead.
 
            Rémi Bernon (@rbernon) commented about dlls/opengl32/unix_wgl.c:
- if (!(ctx = get_current_context( teb, NULL, NULL ))) return TRUE;
- for (const int *attr = ctx->attribs; attr && attr[0]; attr += 2)
if (attr[0] == WGL_CONTEXT_MAJOR_VERSION_ARB) return attr[1];- return 1;
-}
/* Check if a GL extension is supported */ -static BOOL is_extension_supported( TEB *teb, const char *extension ) +static BOOL is_extension_supported( TEB *teb, struct context *ctx, const char *extension ) { char *available_extensions = NULL; BOOL ret = FALSE;
- if (get_context_major_version( teb ) < 3) available_extensions = strdup( (const char *)wrap_glGetString( teb, GL_EXTENSIONS ) );
- sync_context_version( teb, ctx );
We could do that query after the context is made current (or perhaps we could try making it current right after creation, then restore the previous one, idk if that's better) instead of spreading `sync_context_version` here and there.
 
            On Wed Oct 22 14:18:33 2025 +0000, Rémi Bernon wrote:
Arguably I think this is incorrect in the first place, unlike Vulkan, GL functions may be queried without a context and they get dispatched when called instead.
It is correct and we have tests for that. I think you're confusing it with EGL/GLX, which indeed returns context-independent pointers, so they don't need an active context. WGL is different than that. Returned pointers are documented to be context-dependent and may even be valid between contexts.
 
            On Wed Oct 22 14:18:33 2025 +0000, Jacek Caban wrote:
It is correct and we have tests for that. I think you're confusing it with EGL/GLX, which indeed returns context-independent pointers, so they don't need an active context. WGL is different than that. Returned pointers are documented to be context-dependent and may even be valid between contexts.
Alright, my bad.


