-- v2: opengl32: Use stored extensions in filter_extensions. opengl32: Use stored extension list in is_extension_supported. opengl32: Compute supported extensions in make_context_current.
From: Jacek Caban jacek@codeweavers.com
--- dlls/opengl32/unix_wgl.c | 213 ++++++++++++++++++++------------------- 1 file changed, 112 insertions(+), 101 deletions(-)
diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index 35600e79e02..cde876eb7fc 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -26,6 +26,7 @@
#include <stdarg.h> #include <stdlib.h> +#include <assert.h>
#include <pthread.h>
@@ -129,19 +130,20 @@ struct context { struct wgl_context base;
- HDC hdc; /* context creation DC */ - 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 */ - GLuint *disabled_exts; /* indices of disabled extensions */ - char *wow64_version; /* wow64 GL version override */ - struct buffers *buffers; /* wow64 buffers map */ - GLenum gl_error; /* wrapped GL error */ + HDC hdc; /* context creation DC */ + 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 */ + char *wow64_version; /* wow64 GL version override */ + struct buffers *buffers; /* wow64 buffers map */ + GLenum gl_error; /* wrapped GL error */ + const char **extension_array; /* array of supported extensions */ + size_t extension_count; /* size of supported extensions */
/* semi-stub state tracker for wglCopyContext */ GLbitfield used; /* context state used bits */ @@ -555,60 +557,6 @@ static const char *parse_gl_version( const char *gl_version, int *major, int *mi return ptr; }
-static GLuint *filter_extensions_index( TEB *teb, const char *disabled, const char *enabled ) -{ - const struct opengl_funcs *funcs = teb->glTable; - const char *ext, *version; - GLuint *disabled_index; - GLint extensions_count; - unsigned int i = 0, j, len; - int major, minor; - - if (!funcs->p_glGetStringi) - { - void **func_ptr = (void **)&funcs->p_glGetStringi; - *func_ptr = funcs->p_wglGetProcAddress( "glGetStringi" ); - if (!funcs->p_glGetStringi) return NULL; - } - - version = (const char *)funcs->p_glGetString( GL_VERSION ); - parse_gl_version( version, &major, &minor ); - if (major < 3) - return NULL; - - funcs->p_glGetIntegerv( GL_NUM_EXTENSIONS, &extensions_count ); - disabled_index = malloc( extensions_count * sizeof(*disabled_index) ); - if (!disabled_index) return NULL; - - TRACE( "GL_EXTENSIONS:\n" ); - - for (j = 0; j < extensions_count; ++j) - { - ext = (const char *)funcs->p_glGetStringi( GL_EXTENSIONS, j ); - len = strlen( ext ); - - /* We do not support GL_MAP_PERSISTENT_BIT, and hence - * ARB_buffer_storage, on wow64. */ - if (is_win64 && is_wow64() && (!strcmp( ext, "GL_ARB_buffer_storage" ) || !strcmp( ext, "GL_EXT_buffer_storage" ))) - { - TRACE( "-- %s (disabled due to wow64)\n", ext ); - disabled_index[i++] = j; - } - else if (!has_extension( disabled, ext, len ) && (!*enabled || has_extension( enabled, ext, len ))) - { - TRACE( "++ %s\n", ext ); - } - else - { - TRACE( "-- %s (disabled by config)\n", ext ); - disabled_index[i++] = j; - } - } - - disabled_index[i] = ~0u; - return disabled_index; -} - static inline void ascii_to_unicode( WCHAR *dst, const char *src, size_t len ) { while (len--) *dst++ = (unsigned char)*src++; @@ -762,7 +710,7 @@ static char *query_opengl_option( const char *name ) }
/* build the extension string by filtering out the disabled extensions */ -static BOOL filter_extensions( TEB * teb, const char *extensions, GLubyte **exts_list, GLuint **disabled_exts ) +static BOOL filter_extensions( TEB * teb, const char *extensions, GLubyte **exts_list ) { static const char *disabled, *enabled; char *str; @@ -779,16 +727,20 @@ static BOOL filter_extensions( TEB * teb, const char *extensions, GLubyte **exts }
if (extensions && !*exts_list) *exts_list = filter_extensions_list( extensions, disabled, enabled ); - if (!*disabled_exts) *disabled_exts = filter_extensions_index( teb, disabled, enabled ); - return (exts_list && *exts_list) || *disabled_exts; + return exts_list && *exts_list; }
-static const GLuint *disabled_extensions_index( TEB *teb ) +static int extensions_entry_cmp( const void *p1, const void *p2 ) { - struct context *ctx = get_current_context( teb, NULL, NULL ); - GLuint **disabled = &ctx->disabled_exts; - if (*disabled || filter_extensions( teb, NULL, NULL, disabled )) return *disabled; - return NULL; + const char *s1 = *(const char **)p1; + const char *s2 = *(const char **)p2; + while (*s1 && *s1 != ' ') + { + if (*s1 != *s2) return (int)*s1 - (int)*s2; + s1++; + s2++; + } + return (!*s2 || *s2 == ' ') ? 0 : -1; }
/* Check if a GL extension is supported */ @@ -869,20 +821,9 @@ static BOOL get_default_fbo_integer( struct context *ctx, struct opengl_drawable
static BOOL get_integer( TEB *teb, GLenum pname, GLint *data ) { - const struct opengl_funcs *funcs = teb->glTable; struct opengl_drawable *draw, *read; - const GLuint *disabled; struct context *ctx;
- if (pname == GL_NUM_EXTENSIONS) - { - funcs->p_glGetIntegerv( pname, data ); - if ((disabled = disabled_extensions_index( teb ))) - while (*disabled++ != ~0u) (*data)--; - *data += ARRAY_SIZE(legacy_extensions) - 1; - return TRUE; - } - if (!(ctx = get_current_context( teb, &draw, &read ))) return FALSE;
switch (pname) @@ -893,6 +834,9 @@ static BOOL get_integer( TEB *teb, GLenum pname, GLint *data ) case GL_MINOR_VERSION: *data = ctx->minor_version; return TRUE; + case GL_NUM_EXTENSIONS: + *data = ctx->extension_count; + return TRUE; case GL_DRAW_FRAMEBUFFER_BINDING: if (!draw->draw_fbo) break; *data = ctx->draw_fbo; @@ -917,8 +861,7 @@ const GLubyte *wrap_glGetString( TEB *teb, GLenum name ) { struct context *ctx = get_current_context( teb, NULL, NULL ); GLubyte **extensions = &ctx->extensions; - GLuint **disabled = &ctx->disabled_exts; - if (*extensions || filter_extensions( teb, (const char *)ret, extensions, disabled )) return *extensions; + if (*extensions || filter_extensions( teb, (const char *)ret, extensions )) return *extensions; } else if (name == GL_VERSION) { @@ -933,8 +876,6 @@ const GLubyte *wrap_glGetString( TEB *teb, GLenum name ) const GLubyte *wrap_glGetStringi( TEB *teb, GLenum name, GLuint index ) { const struct opengl_funcs *funcs = teb->glTable; - const GLuint *disabled; - GLint count;
if (!funcs->p_glGetStringi) { @@ -944,13 +885,9 @@ const GLubyte *wrap_glGetStringi( TEB *teb, GLenum name, GLuint index )
if (name == GL_EXTENSIONS) { - funcs->p_glGetIntegerv( GL_NUM_EXTENSIONS, &count ); - - if ((disabled = disabled_extensions_index( teb ))) - while (index >= *disabled++) index++; - - if (index >= count && index - count < ARRAY_SIZE(legacy_extensions)) - return (const GLubyte *)legacy_extensions[index - count]; + struct context *ctx = get_current_context( teb, NULL, NULL ); + if (index < ctx->extension_count) return (const GLubyte *)ctx->extension_array[index]; + index = -1; }
return funcs->p_glGetStringi( name, index ); @@ -958,7 +895,7 @@ const GLubyte *wrap_glGetStringi( TEB *teb, GLenum name, GLuint index )
static char *build_extension_list( TEB *teb ) { - GLint len = 0, capacity, i, extensions_count; + GLint len = 0, capacity, i, extensions_count = 0; char *extension, *tmp, *available_extensions;
get_integer( teb, GL_NUM_EXTENSIONS, &extensions_count ); @@ -1081,7 +1018,11 @@ static void make_context_current( TEB *teb, const struct opengl_funcs *funcs, HD HGLRC hglrc, struct context *ctx ) { DWORD tid = HandleToULong(teb->ClientId.UniqueThread); - const char *version, *rest = ""; + size_t size = ARRAYSIZE(legacy_extensions) - 1, count = 0; + const char *version, *rest = "", **extensions; + int i, j; + + static const char *disabled, *enabled;
ctx->tid = tid; teb->glReserved1[0] = draw_hdc; @@ -1093,10 +1034,70 @@ static void make_context_current( TEB *teb, const struct opengl_funcs *funcs, HD 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 );
+ if (ctx->major_version >= 3) + { + GLint extensions_count; + + if (!funcs->p_glGetStringi) + { + void **func_ptr = (void **)&funcs->p_glGetStringi; + *func_ptr = funcs->p_wglGetProcAddress( "glGetStringi" ); + } + + funcs->p_glGetIntegerv( GL_NUM_EXTENSIONS, &extensions_count ); + size += extensions_count; + if (!(extensions = malloc( size * sizeof(*extensions) ))) return; + for (i = 0; i < extensions_count; i++) extensions[count++] = (const char *)funcs->p_glGetStringi( GL_EXTENSIONS, i ); + } + else + { + const char *str = (const char *)funcs->p_glGetString( GL_EXTENSIONS ); + size_t len = strlen( str ); + const char *p; + char *ext; + if (!str) str = ""; + if ((len = strlen( str )) && str[len - 1] == ' ') len--; + if (*str) size++; + for (p = str; p < str + len; p++) if (*p == ' ') size++; + if (!(extensions = malloc( size * sizeof(*extensions) + len + 1 ))) return; + ext = (char *)&extensions[size]; + memcpy( ext, str, len ); + ext[len] = 0; + if (*ext) extensions[count++] = ext; + while (*ext) + { + if (*ext == ' ') + { + *ext = 0; + extensions[count++] = ext + 1; + } + ext++; + } + assert( count + ARRAYSIZE(legacy_extensions) - 1 == size ); + } + + if (!disabled && !(disabled = query_opengl_option( "DisabledExtensions" ))) disabled = ""; + if (!enabled && !(enabled = query_opengl_option( "EnabledExtensions" ))) enabled = ""; + if (*enabled || *disabled) + { + for (i = 0, j = 0; i < count; i++) + { + size_t len = strlen( extensions[i] ); + if (!has_extension( disabled, extensions[i], len ) && (!*enabled || has_extension( enabled, extensions[i], len ))) + extensions[j++] = extensions[i]; + else + TRACE( "-- %s (disabled by config)\n", extensions[i] ); + } + count = j; + } + + for (i = 0; legacy_extensions[i]; i++) extensions[count++] = legacy_extensions[i]; + qsort( extensions, count, sizeof(*extensions), extensions_entry_cmp ); + if (is_win64 && is_wow64()) { if (ctx->major_version > 4 || (ctx->major_version == 4 && ctx->minor_version > 3)) @@ -1106,7 +1107,17 @@ static void make_context_current( TEB *teb, const struct opengl_funcs *funcs, HD ctx->minor_version = 3; asprintf( &ctx->wow64_version, "4.3%s", rest ); } + for (i = 0; i < count; i++) + { + if (strcmp( extensions[i], "GL_ARB_buffer_storage" ) && strcmp( extensions[i], "GL_ARB_buffer_storage" )) continue; + FIXME( "Disabling %s extension on wow64\n", extensions[i] ); + if (i != --count) memmove( &extensions[i], &extensions[i + 1], (count - i) * sizeof(extensions[0]) ); + } } + + ctx->extension_array = extensions; + ctx->extension_count = count; + if (TRACE_ON(opengl)) for (i = 0; i < count; i++) TRACE( "++ %s\n", extensions[i] ); }
BOOL wrap_wglMakeCurrent( TEB *teb, HDC hdc, HGLRC hglrc ) @@ -1147,7 +1158,7 @@ BOOL wrap_wglMakeCurrent( TEB *teb, HDC hdc, HGLRC hglrc ) static void free_context( struct context *ctx ) { free( ctx->wow64_version ); - free( ctx->disabled_exts ); + free( ctx->extension_array ); free( ctx->extensions ); free( ctx->attribs ); free( ctx );
From: Jacek Caban jacek@codeweavers.com
--- dlls/opengl32/unix_wgl.c | 51 ++++++++-------------------------------- 1 file changed, 10 insertions(+), 41 deletions(-)
diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index cde876eb7fc..e5c48dc0b3f 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -744,7 +744,14 @@ static int extensions_entry_cmp( const void *p1, const void *p2 ) }
/* Check if a GL extension is supported */ -static BOOL check_extension_support( struct context *ctx, const char *extension, const char *available_extensions ) +static BOOL is_extension_supported( struct context *ctx, const char *extension ) +{ + return bsearch( &extension, ctx->extension_array, ctx->extension_count, + sizeof(ctx->extension_array[0]), extensions_entry_cmp ) != NULL; +} + +/* Check if any GL extension from the list is supported */ +static BOOL is_any_extension_supported( struct context *ctx, const char *extension ) { size_t len;
@@ -759,7 +766,7 @@ static BOOL check_extension_support( struct context *ctx, const char *extension, while ((len = strcspn( extension, " " ))) { /* Check if the extension is part of the GL extension string to see if it is supported. */ - if (has_extension( available_extensions, extension, len )) return TRUE; + if (is_extension_supported( ctx, extension )) return TRUE;
/* In general an OpenGL function starts as an ARB/EXT extension and at some stage * it becomes part of the core OpenGL library and can be reached without the ARB/EXT @@ -893,44 +900,6 @@ const GLubyte *wrap_glGetStringi( TEB *teb, GLenum name, GLuint index ) return funcs->p_glGetStringi( name, index ); }
-static char *build_extension_list( TEB *teb ) -{ - GLint len = 0, capacity, i, extensions_count = 0; - char *extension, *tmp, *available_extensions; - - get_integer( teb, GL_NUM_EXTENSIONS, &extensions_count ); - capacity = 128 * extensions_count; - - if (!(available_extensions = malloc( capacity ))) return NULL; - for (i = 0; i < extensions_count; ++i) - { - extension = (char *)wrap_glGetStringi( teb, GL_EXTENSIONS, i ); - capacity = max( capacity, len + strlen( extension ) + 2 ); - if (!(tmp = realloc( available_extensions, capacity ))) break; - available_extensions = tmp; - len += snprintf( available_extensions + len, capacity - len, "%s ", extension ); - } - if (len) available_extensions[len - 1] = 0; - - return available_extensions; -} - -/* Check if a GL extension is supported */ -static BOOL is_extension_supported( TEB *teb, struct context *ctx, const char *extension ) -{ - char *available_extensions = NULL; - BOOL ret = FALSE; - - 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" ); - else ret = check_extension_support( ctx, extension, available_extensions ); - - free( available_extensions ); - return ret; -} - static int registry_entry_cmp( const void *a, const void *b ) { const struct registry_entry *entry_a = a, *entry_b = b; @@ -964,7 +933,7 @@ PROC wrap_wglGetProcAddress( TEB *teb, LPCSTR name ) { void *driver_func = funcs->p_wglGetProcAddress( name );
- if (!is_extension_supported( teb, ctx, found->extension )) + if (!is_any_extension_supported( 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 | 123 +++++++++++++++------------------------ 1 file changed, 47 insertions(+), 76 deletions(-)
diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index e5c48dc0b3f..8cc4abee161 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -485,60 +485,6 @@ static const char *legacy_extensions[] = NULL, };
-static GLubyte *filter_extensions_list( const char *extensions, const char *disabled, const char *enabled ) -{ - const char *end, **extra; - char *p, *str; - size_t size, len; - - size = strlen( extensions ) + 2; - for (extra = legacy_extensions; *extra; extra++) size += strlen( *extra ) + 1; - if (!(p = str = malloc( size ))) return NULL; - - TRACE( "GL_EXTENSIONS:\n" ); - - for (;;) - { - while (*extensions == ' ') extensions++; - if (!*extensions) break; - - if (!(end = strchr( extensions, ' ' ))) end = extensions + strlen( extensions ); - memcpy( p, extensions, end - extensions ); - len = end - extensions; - p[len] = 0; - - /* We do not support GL_MAP_PERSISTENT_BIT, and hence - * ARB_buffer_storage, on wow64. */ - if (is_win64 && is_wow64() && (!strcmp( p, "GL_ARB_buffer_storage" ) || !strcmp( p, "GL_EXT_buffer_storage" ))) - { - TRACE( "-- %s (disabled due to wow64)\n", p ); - } - else if (!has_extension( disabled, p, len ) && (!*enabled || has_extension( enabled, p, len ))) - { - TRACE( "++ %s\n", p ); - p += end - extensions; - *p++ = ' '; - } - else - { - TRACE( "-- %s (disabled by config)\n", p ); - } - extensions = end; - } - - for (extra = legacy_extensions; *extra; extra++) - { - size = strlen( *extra ); - memcpy( p, *extra, size ); - p += size; - *p++ = ' '; - } - - if (p != str) --p; - *p = 0; - return (GLubyte *)str; -} - static const char *parse_gl_version( const char *gl_version, int *major, int *minor ) { const char *ptr = gl_version; @@ -709,27 +655,6 @@ static char *query_opengl_option( const char *name ) return str; }
-/* build the extension string by filtering out the disabled extensions */ -static BOOL filter_extensions( TEB * teb, const char *extensions, GLubyte **exts_list ) -{ - static const char *disabled, *enabled; - char *str; - - if (!disabled) - { - if (!(str = query_opengl_option( "DisabledExtensions" ))) disabled = ""; - else if (InterlockedCompareExchangePointer( (void **)&disabled, str, NULL )) free( str ); - } - if (!enabled) - { - if (!(str = query_opengl_option( "EnabledExtensions" ))) enabled = ""; - else if (InterlockedCompareExchangePointer( (void **)&enabled, str, NULL )) free( str ); - } - - if (extensions && !*exts_list) *exts_list = filter_extensions_list( extensions, disabled, enabled ); - return exts_list && *exts_list; -} - static int extensions_entry_cmp( const void *p1, const void *p2 ) { const char *s1 = *(const char **)p1; @@ -750,6 +675,52 @@ static BOOL is_extension_supported( struct context *ctx, const char *extension ) sizeof(ctx->extension_array[0]), extensions_entry_cmp ) != NULL; }
+/* build the extension string by filtering out the disabled extensions */ +static GLubyte *filter_extensions( struct context *ctx, const char *extensions ) +{ + const char *end, **extra; + size_t size, len; + char *p, *str; + + size = strlen( extensions ) + 2; + for (extra = legacy_extensions; *extra; extra++) size += strlen( *extra ) + 1; + if (!(p = str = malloc( size ))) return NULL; + + TRACE( "GL_EXTENSIONS:\n" ); + + for (;;) + { + while (*extensions == ' ') extensions++; + if (!*extensions) break; + len = (end = strchr( extensions, ' ' )) ? end - extensions : strlen( extensions ); + memcpy( p, extensions, len ); + p[len] = 0; + if (is_extension_supported( ctx, extensions )) + { + TRACE( "++ %s\n", p ); + p += len; + *p++ = ' '; + } + else + { + TRACE( "-- %s (disabled in context)\n", p ); + } + extensions = end; + } + + for (extra = legacy_extensions; *extra; extra++) + { + size = strlen( *extra ); + memcpy( p, *extra, size ); + p += size; + *p++ = ' '; + } + + if (p != str) --p; + *p = 0; + return (GLubyte *)str; +} + /* Check if any GL extension from the list is supported */ static BOOL is_any_extension_supported( struct context *ctx, const char *extension ) { @@ -868,7 +839,7 @@ const GLubyte *wrap_glGetString( TEB *teb, GLenum name ) { struct context *ctx = get_current_context( teb, NULL, NULL ); GLubyte **extensions = &ctx->extensions; - if (*extensions || filter_extensions( teb, (const char *)ret, extensions )) return *extensions; + if (*extensions || (*extensions = filter_extensions( ctx, (const char *)ret ))) return *extensions; } else if (name == GL_VERSION) {
On Thu Oct 23 14:17:45 2025 +0000, Rémi Bernon wrote:
Can glGetString really return NULL? What about making this more readable?
const char *str, *ptr; char *out; if (!(str = (const char *)funcs->p_glGetString( GL_EXTENSIONS ))) str = ""; for (ptr = str; *ptr; ptr++) if (ptr == str || (ptr[0] == ' ' && ptr[1])) size++; if (ptr > str && ptr[-1] == ' ') ptr--; /* strip trailing space */ if (!(extensions = malloc( size * sizeof(*extensions) + (ptr - str) ))) return; out = (char *)&extensions[size]; memcpy( out, str, ptr - str ); for (ptr = strtok( out, " " ); ptr; ptr = strtok( NULL, " " )) extensions[count++] = ptr; assert( count + ARRAY_SIZE(legacy_extensions) - 1 == size );
It returns NULL on core contexts. Those should usually fall into version >= 3.0 branch, so it's it requires additional weirdness, but I've seen it with d3d11 tests when I hacked things to test this branch.
On Thu Oct 23 14:17:45 2025 +0000, Rémi Bernon wrote:
Why move this out of the loop? I think it could be kept more like it was and avoid the memmove.
I'd like to be able to enable the hack conditionally, and by having it in all in a single branch instead of spread across the code helps with that.
With Vulkan memory mapping, it will be useful to have a place where we can easily check for available extensions (GL_EXT_memory_object_fd) and depending on that (and Vulkan capabilities) decide if we want to disable buffer storage after all.
On Thu Oct 23 14:17:45 2025 +0000, Rémi Bernon wrote:
Is this really necessary? Extensions should be tokenized already no? What about strcmp?
Not all use cases are tokenized. Extensions in `registry_entry` and in `filter_extension` are not and it's convenient just not to worry about in places where the main logic happens.
We could fully tokenize extensions and I have a draft of that, but it's not what this MR is about. In my draft, I convert extension to an enum, which allows eliminating the entire bsearch.
On Thu Oct 23 14:17:46 2025 +0000, Rémi Bernon wrote:
I would rather have some more explicit name, because it's getting quite confusing with `extensions`. Something like `extension_array` for instance. Or rename the other `extension_string`.
Done.
On Thu Oct 23 14:38:34 2025 +0000, Jacek Caban wrote:
changed this line in [version 2 of the diff](/wine/wine/-/merge_requests/9263/diffs?diff_id=218199&start_sha=98a1cee6a50f58c610863a258460a32ac2e5664e#f4de89b6fe59a53c44625c669ffde0c88cf41d0b_674_674)
Again, not everything is tokenized.
On Thu Oct 23 14:17:46 2025 +0000, Rémi Bernon wrote:
Do we really need to filter extensions there again? What about pre-computing the extension string right away from the extension array after we've initialized it?
Drivers return extensions via `glGetStringi` in a different order than `glGetString`. MESA uses alphabetical order for the former and historical order for the latter (also making it possible to apply additional filters like `MESA_EXTENSION_MAX_YEAR`). If we want to preserve all that, we can't just compute that from `extension_array`, we need to apply a filter to what the driver reports.
On Thu Oct 23 14:41:46 2025 +0000, Jacek Caban wrote:
It returns NULL on core contexts. Those should usually fall into version
= 3.0 branch, so it's it requires additional weirdness, but I've seen
it with d3d11 tests when I hacked things to test this branch.
Okay. I'd prefer to make the code readable as suggested still.
On Thu Oct 23 14:52:52 2025 +0000, Jacek Caban wrote:
Again, not everything is tokenized.
Sure, that's why I'm suggesting to copy the extension to a temporary buffer to make sure that it is zero terminated and avoid having to open code some `strcmp` variant for comparison. Especially as we have the extension name length here already.
On Thu Oct 23 14:58:28 2025 +0000, Jacek Caban wrote:
Drivers return extensions via `glGetStringi` in a different order than `glGetString`. MESA uses alphabetical order for the former and historical order for the latter (also making it possible to apply additional filters like `MESA_EXTENSION_MAX_YEAR`). If we want to preserve all that, we can't just compute that from `extension_array`, we need to apply a filter to what the driver reports.
I think it could be better moved to make_context_current nonetheless, keeping the order from the host reported string if that's important while filtering it with the just built array. It would make things simpler and all located in the same place, would save counting extensions again and tracing the list twice.
On Thu Oct 23 15:51:16 2025 +0000, Rémi Bernon wrote:
Sure, that's why I'm suggesting to copy the extension to a temporary buffer to make sure that it is zero terminated and avoid having to open code some `strcmp` variant for comparison. Especially as we have the extension name length here already.
I don't like complicating callers. As I said, the way to remove that is to properly tokenize. Ad-hoc temporary buffers don't seem like an improvement.
On Thu Oct 23 15:51:16 2025 +0000, Rémi Bernon wrote:
I think it could be better moved to make_context_current nonetheless, keeping the order from the host reported string if that's important while filtering it with the just built array. It would make things simpler and all located in the same place, would save counting extensions again and tracing the list twice.
Sure, I just kept it as it was, but it would be easy to do on top of this MR. Note that in >=3 contexts this string is deprecated, so I'd rather avoid the call in the first place unless we have to.
On Thu Oct 23 16:14:45 2025 +0000, Jacek Caban wrote:
Sure, I just kept it as it was, but it would be easy to do on top of this MR. Note that in >=3 contexts this string is deprecated, so I'd rather avoid the call in the first place unless we have to.
Actually, it may even generate an error on core contexts, so we shouldn't do that in `make_context_current`.