[PATCH 0/5] MR10870: opengl32: Introduce PE-side display lists and track buffer name allocations.
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/opengl32/wgl.c | 48 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/dlls/opengl32/wgl.c b/dlls/opengl32/wgl.c index f4ca0e924b9..7e56f6596a5 100644 --- a/dlls/opengl32/wgl.c +++ b/dlls/opengl32/wgl.c @@ -259,10 +259,38 @@ BOOL WINAPI wglDestroyPbufferARB( HPBUFFERARB handle ) return args.ret; } +struct display_lists +{ + LONG refcount; +}; + +static struct display_lists *display_lists_create(void) +{ + struct display_lists *lists; + + if (!(lists = calloc( 1, sizeof(*lists) ))) return NULL; + lists->refcount = 1; + + return lists; +} + +static struct display_lists *display_lists_acquire( struct display_lists *lists ) +{ + InterlockedIncrement( &lists->refcount ); + return lists; +} + +static void display_lists_release( struct display_lists *lists ) +{ + if (InterlockedDecrement( &lists->refcount )) return; + free( lists ); +} + struct context { struct opengl_client_context base; - struct handle_table syncs; + struct handle_table syncs; + struct display_lists *lists; }; static struct context *context_from_opengl_client_context( struct opengl_client_context *base ) @@ -293,19 +321,23 @@ BOOL get_context_from_handle( HGLRC handle, HGLRC *obj ) return context || !handle; } -static struct handle_entry *alloc_client_context(void) +static struct handle_entry *alloc_client_context( struct context *share ) { struct context *context; struct handle_entry *ptr; if (!(context = calloc( 1, sizeof(*context) ))) return NULL; + if (!(context->lists = share ? display_lists_acquire( share->lists ) : display_lists_create())) goto failed; EnterCriticalSection( &wgl_cs ); ptr = alloc_handle( &contexts, context ); LeaveCriticalSection( &wgl_cs ); + if (ptr) return ptr; - if (!ptr) free( context ); - return ptr; + display_lists_release( context->lists ); +failed: + free( context ); + return NULL; } static void free_client_context( struct handle_entry *ptr ) @@ -318,6 +350,7 @@ static void free_client_context( struct handle_entry *ptr ) if (LOWORD(entry->handle) == 0xffff) continue; free( entry->user_data ); } + display_lists_release( context->lists ); EnterCriticalSection( &wgl_cs ); free_handle( &contexts, ptr ); @@ -342,17 +375,20 @@ HGLRC WINAPI wglCreateContext( HDC hdc ) HGLRC WINAPI wglCreateContextAttribsARB( HDC hdc, HGLRC share, const int *attribs ) { struct wglCreateContextAttribsARB_params args = { .teb = NtCurrentTeb(), .hDC = hdc, .attribList = attribs }; + struct context *share_context = NULL; struct handle_entry *ptr; NTSTATUS status; TRACE( "hdc %p, share %p, attribs %p\n", hdc, share, attribs ); - if (!get_context_from_handle( share, &args.hShareContext )) + if (share && !(share_context = context_from_handle( share ))) { SetLastError( ERROR_INVALID_OPERATION ); return NULL; } - if (!(ptr = alloc_client_context())) return NULL; + if (share) args.hShareContext = &share_context->base.obj; + + if (!(ptr = alloc_client_context( share_context ))) return NULL; args.ret = &ptr->context->obj; if ((status = UNIX_CALL( wglCreateContextAttribsARB, &args ))) WARN( "wglCreateContextAttribsARB returned %#lx\n", status ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10870
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/opengl32/make_opengl | 1 + dlls/opengl32/thunks.c | 11 ----------- dlls/opengl32/wgl.c | 27 +++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index 3dec39cc0f0..01dd4081ec5 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -172,6 +172,7 @@ my %manual_win_thunks = "wglMakeContextCurrentARB" => 1, "wglQueryCurrentRendererStringWINE" => 1, "wglQueryRendererStringWINE" => 1, + "wglShareLists" => 1, "wglSwapBuffers" => 1, ); diff --git a/dlls/opengl32/thunks.c b/dlls/opengl32/thunks.c index c62a6fdaa9f..134aecb3221 100644 --- a/dlls/opengl32/thunks.c +++ b/dlls/opengl32/thunks.c @@ -36,17 +36,6 @@ BOOL WINAPI wglSetPixelFormat( HDC hdc, int ipfd, const PIXELFORMATDESCRIPTOR *p return args.ret; } -BOOL WINAPI wglShareLists( HGLRC hrcSrvShare, HGLRC hrcSrvSource ) -{ - struct wglShareLists_params args = { .teb = NtCurrentTeb() }; - NTSTATUS status; - TRACE( "hrcSrvShare %p, hrcSrvSource %p\n", hrcSrvShare, hrcSrvSource ); - if (!get_context_from_handle( hrcSrvShare, &args.hrcSrvShare )) return 0; - if (!get_context_from_handle( hrcSrvSource, &args.hrcSrvSource )) return 0; - if ((status = UNIX_CALL( wglShareLists, &args ))) WARN( "wglShareLists returned %#lx\n", status ); - return args.ret; -} - void WINAPI glAccum( GLenum op, GLfloat value ) { struct glAccum_params args = { .teb = NtCurrentTeb(), .op = op, .value = value }; diff --git a/dlls/opengl32/wgl.c b/dlls/opengl32/wgl.c index 7e56f6596a5..82387aa118f 100644 --- a/dlls/opengl32/wgl.c +++ b/dlls/opengl32/wgl.c @@ -468,6 +468,33 @@ BOOL WINAPI wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, HGLRC handle ) return TRUE; } +/*********************************************************************** + * wglShareLists + */ +BOOL WINAPI wglShareLists( HGLRC src_handle, HGLRC dst_handle ) +{ + struct wglShareLists_params args = { .teb = NtCurrentTeb() }; + struct context *src_context, *dst_context; + struct display_lists *lists; + NTSTATUS status; + + TRACE( "src_handle %p, dst_handle %p\n", src_handle, dst_handle ); + + if (!(src_context = context_from_handle( src_handle ))) return FALSE; + if (!(dst_context = context_from_handle( dst_handle ))) return FALSE; + + args.hrcSrvShare = &src_context->base.obj; + args.hrcSrvSource = &dst_context->base.obj; + if ((status = UNIX_CALL( wglShareLists, &args ))) WARN( "wglShareLists returned %#lx\n", status ); + if (!args.ret) return FALSE; + + lists = display_lists_acquire( src_context->lists ); + lists = InterlockedExchangePointer( (void *)&dst_context->lists, lists ); + display_lists_release( lists ); + + return TRUE; +} + /*********************************************************************** * wglGetCurrentReadDCARB * -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10870
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/opengl32/unix_wgl.c | 1 + dlls/opengl32/wgl.c | 3 +++ include/wine/opengl_driver.h | 1 + 3 files changed, 5 insertions(+) diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index 762c31578d8..fbf5654aeaa 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -1083,6 +1083,7 @@ static void make_context_current( TEB *teb, const struct opengl_funcs *funcs, HD TRACE( "context %p version %d.%d\n", ctx, client->major_version, client->minor_version ); funcs->p_init_extensions( client->extensions ); + funcs->p_glGetIntegerv( GL_CONTEXT_PROFILE_MASK, &client->profile_mask ); if (client->major_version >= 3) { diff --git a/dlls/opengl32/wgl.c b/dlls/opengl32/wgl.c index 82387aa118f..e698a384c99 100644 --- a/dlls/opengl32/wgl.c +++ b/dlls/opengl32/wgl.c @@ -2110,6 +2110,9 @@ BOOL get_integer( GLenum name, GLint *data ) switch (name) { + case GL_CONTEXT_PROFILE_MASK: + *data = ctx->base.profile_mask; + return TRUE; case GL_MAJOR_VERSION: *data = ctx->base.major_version; return TRUE; diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index e70c00151a9..af745e038a6 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -75,6 +75,7 @@ struct opengl_client_context UINT64 unix_funcs; DWORD current_tid; /* thread that the context is current in */ GLenum last_error; + GLint profile_mask; int major_version; int minor_version; BOOLEAN extensions[GL_EXTENSION_COUNT]; /* exposed client extensions */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10870
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/opengl32/make_opengl | 72 +++++++++++++++++++- dlls/opengl32/private.h | 17 +++++ dlls/opengl32/thunks.c | 18 ++++- dlls/opengl32/wgl.c | 137 +++++++++++++++++++++++++++++++++++++- 4 files changed, 237 insertions(+), 7 deletions(-) diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index 01dd4081ec5..f1741033d62 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -678,19 +678,40 @@ sub get_handle_function($) return 0; } +sub get_object_type($$$$) +{ + my ($func, $ptype, $pname, $class) = @_; + + return "OBJ_TYPE_BUFFER" if $class eq "buffer"; + return "OBJ_TYPE_BUFFER" if $func eq "glDeleteObjectBufferATI" and $pname eq "buffer"; + return "OBJ_TYPE_BUFFER" if $func eq "glDrawCommandsNV" and $pname eq "buffer"; + return 0 if $class eq "framebuffer"; + return 0 if $class eq "renderbuffer"; + + return 0 if $class eq "SelectName"; + return 0 if $func eq "glGetActiveAtomicCounterBufferiv" and $pname eq "bufferIndex"; + return 0 if $func =~ /^glBlend(Equation|Func)/ and $pname eq "buf"; + return 0 if $func =~ /^gl(Signal|Wait)Semaphore/ and $pname eq "numBufferBarriers"; + return 0 if $ptype !~ /GLuint|GLhandleARB/; + + print "Missing possible buffer: $func $ptype $pname $class\n" if lc( $pname ) =~ /buffer/; + return 0; +} + sub generate_win_thunk($$) { my ($name, $func) = @_; my $get_integer = get_integer_call( $name, $func ); my $decl_args = get_func_args( $func ); my $func_ret = get_func_ret( $func ); + my $post_call = ""; + my $map_args = ""; my $params = ""; my $checks = ""; my $ret = ""; $ret .= "$func_ret WINAPI $name($decl_args)\n"; $ret .= "{\n"; - $ret .= " struct $name\_params args"; $params .= " .teb = NtCurrentTeb()"; foreach my $arg (@{$func->[1]}) { @@ -702,19 +723,52 @@ sub generate_win_thunk($$) $retval = "{ set_gl_error( GL_INVALID_VALUE ); $retval }" if $ptype =~ /GLsync/ && $name !~ /glIsSync/; $checks .= " if (!$get_handle( $pname, &args.$pname )) $retval\n"; } + elsif (my $map_type = get_object_type( $name, $ptype, $pname, get_arg_class( $arg ) )) + { + my $len = get_arg_len( $arg ); + my $addr = $len eq "1" ? "&" : ""; + my $deref = $len eq "1" ? "*" : ""; + + if ($name =~ /^(glGen|glCreate)/) + { + $params .= ", .$pname = $pname"; + $post_call .= " if ($len > 0) put_context_objects( $map_type, $len, $addr$pname );\n"; + } + elsif ($name =~ /^glDelete/) + { + if ($len eq "1") + { + $map_args .= " args.$pname = *del_context_objects( $map_type, 1, &$pname );\n"; + } + else + { + my ($buf, $tmp) = ($pname . "_buf", $pname . "_tmp"); + $ret .= " GLuint $buf\[64\], *$tmp;\n"; + + $map_args .= " $tmp = $len > 0 ? memdup_objects( $len, $pname, $buf, ARRAY_SIZE($buf) ) : NULL;\n"; + $map_args .= " args.$pname = $len > 0 ? del_context_objects( $map_type, $len, $tmp ) : NULL;\n"; + $post_call .= " if ($tmp != $buf) free( $tmp );\n"; + } + } + else + { + $params .= ", .$pname = $pname"; + } + } else { $params .= ", .$pname = $pname"; } } - $ret .= " = {$params }"; - $ret .= ";\n"; + $ret .= " struct $name\_params args = {$params };\n"; $ret .= " NTSTATUS status;\n"; $ret .= " int integer;\n" if $get_integer; $ret .= " " . get_func_trace( $name, $func, 1 ); $ret .= $checks; + $ret .= $map_args; $ret .= $get_integer ? " $get_integer\n else " : " "; $ret .= "if ((status = UNIX_CALL( $name, &args ))) WARN( \"$name returned %#lx\\n\", status );\n"; + $ret .= $post_call; $ret .= " return args.ret;\n" unless is_void_func($func); $ret .= "}\n"; @@ -818,6 +872,18 @@ sub get_arg_name($) return $name[0]->textContent(); } +sub get_arg_class($) +{ + my $p = shift; + return $p->{class} || $p->{kind} || ""; +} + +sub get_arg_len($) +{ + my $p = shift; + return $p->{len} || "1"; +} + # # Fetch the registry files # diff --git a/dlls/opengl32/private.h b/dlls/opengl32/private.h index aa14924d1a8..9bb9e8b77a9 100644 --- a/dlls/opengl32/private.h +++ b/dlls/opengl32/private.h @@ -46,4 +46,21 @@ extern void set_gl_error( GLenum error ); extern struct registry_entry *get_function_entry( const char *name ); extern BOOL get_integer( GLenum name, GLint *data ); +enum object_type +{ + OBJ_TYPE_BUFFER, + OBJ_TYPE_COUNT, +}; + +static inline GLuint *memdup_objects( UINT n, const GLuint *handles, GLuint *buf, UINT max ) +{ + GLuint *tmp = buf; + if (n > max && !(tmp = malloc( n * sizeof(*handles) ))) return NULL; + memcpy( tmp, handles, n * sizeof(*handles) ); + return tmp; +} + +extern void put_context_objects( enum object_type type, UINT n, GLuint *handles ); +extern GLuint *del_context_objects( enum object_type type, UINT n, GLuint *handles ); + #endif /* __WINE_OPENGL32_PRIVATE_H */ diff --git a/dlls/opengl32/thunks.c b/dlls/opengl32/thunks.c index 134aecb3221..774c894d91c 100644 --- a/dlls/opengl32/thunks.c +++ b/dlls/opengl32/thunks.c @@ -5322,6 +5322,7 @@ static void WINAPI glCreateBuffers( GLsizei n, GLuint *buffers ) NTSTATUS status; TRACE( "n %d, buffers %p\n", n, buffers ); if ((status = UNIX_CALL( glCreateBuffers, &args ))) WARN( "glCreateBuffers returned %#lx\n", status ); + if (n > 0) put_context_objects( OBJ_TYPE_BUFFER, n, buffers ); } static void WINAPI glCreateCommandListsNV( GLsizei n, GLuint *lists ) @@ -5629,18 +5630,26 @@ static void WINAPI glDeleteBufferRegion( GLenum region ) static void WINAPI glDeleteBuffers( GLsizei n, const GLuint *buffers ) { - struct glDeleteBuffers_params args = { .teb = NtCurrentTeb(), .n = n, .buffers = buffers }; + GLuint buffers_buf[64], *buffers_tmp; + struct glDeleteBuffers_params args = { .teb = NtCurrentTeb(), .n = n }; NTSTATUS status; TRACE( "n %d, buffers %p\n", n, buffers ); + buffers_tmp = n > 0 ? memdup_objects( n, buffers, buffers_buf, ARRAY_SIZE(buffers_buf) ) : NULL; + args.buffers = n > 0 ? del_context_objects( OBJ_TYPE_BUFFER, n, buffers_tmp ) : NULL; if ((status = UNIX_CALL( glDeleteBuffers, &args ))) WARN( "glDeleteBuffers returned %#lx\n", status ); + if (buffers_tmp != buffers_buf) free( buffers_tmp ); } static void WINAPI glDeleteBuffersARB( GLsizei n, const GLuint *buffers ) { - struct glDeleteBuffersARB_params args = { .teb = NtCurrentTeb(), .n = n, .buffers = buffers }; + GLuint buffers_buf[64], *buffers_tmp; + struct glDeleteBuffersARB_params args = { .teb = NtCurrentTeb(), .n = n }; NTSTATUS status; TRACE( "n %d, buffers %p\n", n, buffers ); + buffers_tmp = n > 0 ? memdup_objects( n, buffers, buffers_buf, ARRAY_SIZE(buffers_buf) ) : NULL; + args.buffers = n > 0 ? del_context_objects( OBJ_TYPE_BUFFER, n, buffers_tmp ) : NULL; if ((status = UNIX_CALL( glDeleteBuffersARB, &args ))) WARN( "glDeleteBuffersARB returned %#lx\n", status ); + if (buffers_tmp != buffers_buf) free( buffers_tmp ); } static void WINAPI glDeleteCommandListsNV( GLsizei n, const GLuint *lists ) @@ -5725,9 +5734,10 @@ static void WINAPI glDeleteObjectARB( GLhandleARB obj ) static void WINAPI glDeleteObjectBufferATI( GLuint buffer ) { - struct glDeleteObjectBufferATI_params args = { .teb = NtCurrentTeb(), .buffer = buffer }; + struct glDeleteObjectBufferATI_params args = { .teb = NtCurrentTeb() }; NTSTATUS status; TRACE( "buffer %d\n", buffer ); + args.buffer = *del_context_objects( OBJ_TYPE_BUFFER, 1, &buffer ); if ((status = UNIX_CALL( glDeleteObjectBufferATI, &args ))) WARN( "glDeleteObjectBufferATI returned %#lx\n", status ); } @@ -7475,6 +7485,7 @@ static void WINAPI glGenBuffers( GLsizei n, GLuint *buffers ) NTSTATUS status; TRACE( "n %d, buffers %p\n", n, buffers ); if ((status = UNIX_CALL( glGenBuffers, &args ))) WARN( "glGenBuffers returned %#lx\n", status ); + if (n > 0) put_context_objects( OBJ_TYPE_BUFFER, n, buffers ); } static void WINAPI glGenBuffersARB( GLsizei n, GLuint *buffers ) @@ -7483,6 +7494,7 @@ static void WINAPI glGenBuffersARB( GLsizei n, GLuint *buffers ) NTSTATUS status; TRACE( "n %d, buffers %p\n", n, buffers ); if ((status = UNIX_CALL( glGenBuffersARB, &args ))) WARN( "glGenBuffersARB returned %#lx\n", status ); + if (n > 0) put_context_objects( OBJ_TYPE_BUFFER, n, buffers ); } static void WINAPI glGenFencesAPPLE( GLsizei n, GLuint *fences ) diff --git a/dlls/opengl32/wgl.c b/dlls/opengl32/wgl.c index e698a384c99..da35e355332 100644 --- a/dlls/opengl32/wgl.c +++ b/dlls/opengl32/wgl.c @@ -101,6 +101,16 @@ static void cleanup_wow64_strings(void) #endif +static const char *debugstr_object_type( enum object_type type ) +{ + switch (type) + { + case OBJ_TYPE_BUFFER: return "buffer"; + case OBJ_TYPE_COUNT: break; + } + return wine_dbg_sprintf( "object (type %u)", type ); +} + static void init_wgl_extensions( const BOOLEAN extensions[GL_EXTENSION_COUNT] ) { UINT pos = 0, len = 0, ext; @@ -259,9 +269,92 @@ BOOL WINAPI wglDestroyPbufferARB( HPBUFFERARB handle ) return args.ret; } +#define L1_COUNT 0x80 +#define L2_COUNT 0x400 +#define L3_COUNT 0x8000 + +struct object_table +{ + enum object_type type; /* object type of the id table */ + SRWLOCK lock; /* lock for accessing the table */ + GLuint **host_ids[L1_COUNT]; /* client -> host id mapping sparse array */ +}; + +static GLuint *find_object_id( GLuint **ids[L1_COUNT], GLuint client_id ) +{ + GLuint i = client_id / L3_COUNT / L2_COUNT, j = (client_id / L3_COUNT) % L2_COUNT, k = client_id % L3_COUNT; + return ids[i] ? ids[i][j] ? ids[i][j] + k : NULL : NULL; +} + +static GLuint *alloc_object_ids( GLuint **ids[L1_COUNT], GLuint client_id ) +{ + GLuint i = client_id / L3_COUNT / L2_COUNT, j = (client_id / L3_COUNT) % L2_COUNT; + GLuint **ptr; + + if (!(ptr = ids[i]) && !(ptr = ids[i] = calloc( L2_COUNT, sizeof(*ptr) ))) return NULL; + if (!ptr[j] && !(ptr[j] = calloc( L3_COUNT, sizeof(*ptr[j]) ))) return NULL; + return ptr[j]; +} + +static void free_object_ids( struct object_table *table, GLuint **ids[L1_COUNT] ) +{ + GLuint **l1_block, *l2_block; + + for (int i = 0; i < L1_COUNT; i++) + { + if (!(l1_block = ids[i])) continue; + for (int j = 0; j < L2_COUNT; j++) + { + if (!(l2_block = l1_block[j])) continue; + free( l2_block ); + } + free( l1_block ); + } +} + +static GLuint set_object( struct object_table *table, GLuint client_id, GLuint host_id ) +{ + GLuint *ids; + + if (!(ids = alloc_object_ids( table->host_ids, client_id ))) goto failed; + ids[client_id % L3_COUNT] = host_id; + + TRACE( "Inserted %s client %#x, host %#x\n", debugstr_object_type( table->type ), client_id, host_id ); + return client_id; + +failed: + ERR( "Failed to allocate object id block\n" ); + return -1; +} + +static GLuint del_object( struct object_table *table, GLuint client_id ) +{ + GLuint *object, host_id = 0; + + if (!client_id || !(object = find_object_id( table->host_ids, client_id ))) return client_id; + host_id = *object; + *object = 0; + + TRACE( "Deleting %s client %#x, host %#x\n", debugstr_object_type( table->type ), client_id, host_id ); + return host_id ? host_id : client_id; +} + +static void free_object_table( struct object_table *table ) +{ + free_object_ids( table, table->host_ids ); +} + +static void init_object_table( struct object_table *table, enum object_type type ) +{ + InitializeSRWLock( &table->lock ); + table->type = type; +} + struct display_lists { - LONG refcount; + LONG refcount; + LONG modified; + struct object_table tables[OBJ_TYPE_COUNT]; }; static struct display_lists *display_lists_create(void) @@ -271,6 +364,9 @@ static struct display_lists *display_lists_create(void) if (!(lists = calloc( 1, sizeof(*lists) ))) return NULL; lists->refcount = 1; + for (UINT i = 0; i < OBJ_TYPE_COUNT; i++) + init_object_table( lists->tables + i, i ); + return lists; } @@ -283,6 +379,10 @@ static struct display_lists *display_lists_acquire( struct display_lists *lists static void display_lists_release( struct display_lists *lists ) { if (InterlockedDecrement( &lists->refcount )) return; + + for (UINT i = 0; i < OBJ_TYPE_COUNT; i++) + free_object_table( lists->tables + i ); + free( lists ); } @@ -365,6 +465,40 @@ void set_gl_error( GLenum error ) if (!context->last_error && !(context->last_error = glGetError())) context->last_error = error; } +static struct object_table *get_object_table( struct context *ctx, enum object_type type, BOOL write ) +{ + if (write) InterlockedExchange( &ctx->lists->modified, 1 ); + return type < OBJ_TYPE_COUNT ? ctx->lists->tables + type : NULL; +} + +void put_context_objects( enum object_type type, UINT n, GLuint *handles ) +{ + struct object_table *table; + struct context *ctx; + + if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return; + if (!(table = get_object_table( ctx, type, TRUE ))) return; + + AcquireSRWLockExclusive( &table->lock ); + for (UINT i = 0; i < n; i++) handles[i] = handles[i] ? set_object( table, handles[i], handles[i] ) : 0; + ReleaseSRWLockExclusive( &table->lock ); +} + +GLuint *del_context_objects( enum object_type type, UINT n, GLuint *handles ) +{ + struct object_table *table; + struct context *ctx; + + if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return handles; + if (!(table = get_object_table( ctx, type, FALSE ))) return handles; + + AcquireSRWLockExclusive( &table->lock ); + for (UINT i = 0; i < n; i++) handles[i] = del_object( table, handles[i] ); + ReleaseSRWLockExclusive( &table->lock ); + + return handles; +} + HGLRC WINAPI wglCreateContext( HDC hdc ) { static const int attribs[] = { WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, 0, 0 }; @@ -482,6 +616,7 @@ BOOL WINAPI wglShareLists( HGLRC src_handle, HGLRC dst_handle ) if (!(src_context = context_from_handle( src_handle ))) return FALSE; if (!(dst_context = context_from_handle( dst_handle ))) return FALSE; + if (ReadNoFence( &dst_context->lists->modified )) return FALSE; args.hrcSrvShare = &src_context->base.obj; args.hrcSrvSource = &dst_context->base.obj; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10870
From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/opengl32/make_opengl | 24 ++++++++++++ dlls/opengl32/private.h | 1 + dlls/opengl32/tests/opengl.c | 2 +- dlls/opengl32/thunks.c | 40 ++++++++++++++++++++ dlls/opengl32/wgl.c | 71 +++++++++++++++++++++++++++++++++++- 5 files changed, 136 insertions(+), 2 deletions(-) diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index f1741033d62..06e0f44eefb 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -698,6 +698,17 @@ sub get_object_type($$$$) return 0; } +sub allocate_object_names($) +{ + my $name = shift; + my $ret = $name =~ /(APPLE|ARB|ATI|EXT|NV)$/ ? "TRUE" : "FALSE"; + + return "TRUE" if has_extension( $name, "GL_EXT_direct_state_access" ); + return $ret if $name =~ /^glBindBuffer/; + + return 0; +} + sub generate_win_thunk($$) { my ($name, $func) = @_; @@ -752,6 +763,13 @@ sub generate_win_thunk($$) } else { + my $return = is_void_func($func) ? "" : " args.ret"; + my $alloc = allocate_object_names( $name ); + + if ($len eq "1") + { + $checks .= " if (!alloc_context_objects( $map_type, 1, &$pname, $alloc )) return$return;\n" if $alloc; + } $params .= ", .$pname = $pname"; } } @@ -1136,6 +1154,12 @@ sub is_exposed_function($) return 0; } +sub has_extension($$) +{ + my ($func, $name) = @_; + return grep( /^$name$/, keys %{$ext_functions{$func}->[2]} ); +} + # some functions need a hand-written wrapper sub needs_wrapper($$) { diff --git a/dlls/opengl32/private.h b/dlls/opengl32/private.h index 9bb9e8b77a9..6c45a665336 100644 --- a/dlls/opengl32/private.h +++ b/dlls/opengl32/private.h @@ -61,6 +61,7 @@ static inline GLuint *memdup_objects( UINT n, const GLuint *handles, GLuint *buf } extern void put_context_objects( enum object_type type, UINT n, GLuint *handles ); +extern BOOL alloc_context_objects( enum object_type type, UINT n, const GLuint *handles, BOOL extension ); extern GLuint *del_context_objects( enum object_type type, UINT n, GLuint *handles ); #endif /* __WINE_OPENGL32_PRIVATE_H */ diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index c9429d3d851..6d64ec6ee03 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -2021,7 +2021,7 @@ static void test_sharelists(HDC winhdc) ok_ret( GL_NO_ERROR, glGetError() ); /* cannot overwrite non-empty lists with some other */ - todo_wine ok_ret( FALSE, wglShareLists( ctx1, ctx3 ) ); + todo_wine_if( i >= 2 ) ok_ret( FALSE, wglShareLists( ctx1, ctx3 ) ); ok_ret( GL_NO_ERROR, glGetError() ); ok_ret( FALSE, wglShareLists( ctx2, ctx1 ) ); ok_ret( GL_NO_ERROR, glGetError() ); diff --git a/dlls/opengl32/thunks.c b/dlls/opengl32/thunks.c index 774c894d91c..14deacbdc67 100644 --- a/dlls/opengl32/thunks.c +++ b/dlls/opengl32/thunks.c @@ -3077,6 +3077,7 @@ static void WINAPI glBindBuffer( GLenum target, GLuint buffer ) struct glBindBuffer_params args = { .teb = NtCurrentTeb(), .target = target, .buffer = buffer }; NTSTATUS status; TRACE( "target %d, buffer %d\n", target, buffer ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, FALSE )) return; if ((status = UNIX_CALL( glBindBuffer, &args ))) WARN( "glBindBuffer returned %#lx\n", status ); } @@ -3085,6 +3086,7 @@ static void WINAPI glBindBufferARB( GLenum target, GLuint buffer ) struct glBindBufferARB_params args = { .teb = NtCurrentTeb(), .target = target, .buffer = buffer }; NTSTATUS status; TRACE( "target %d, buffer %d\n", target, buffer ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glBindBufferARB, &args ))) WARN( "glBindBufferARB returned %#lx\n", status ); } @@ -3093,6 +3095,7 @@ static void WINAPI glBindBufferBase( GLenum target, GLuint index, GLuint buffer struct glBindBufferBase_params args = { .teb = NtCurrentTeb(), .target = target, .index = index, .buffer = buffer }; NTSTATUS status; TRACE( "target %d, index %d, buffer %d\n", target, index, buffer ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, FALSE )) return; if ((status = UNIX_CALL( glBindBufferBase, &args ))) WARN( "glBindBufferBase returned %#lx\n", status ); } @@ -3101,6 +3104,7 @@ static void WINAPI glBindBufferBaseEXT( GLenum target, GLuint index, GLuint buff struct glBindBufferBaseEXT_params args = { .teb = NtCurrentTeb(), .target = target, .index = index, .buffer = buffer }; NTSTATUS status; TRACE( "target %d, index %d, buffer %d\n", target, index, buffer ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glBindBufferBaseEXT, &args ))) WARN( "glBindBufferBaseEXT returned %#lx\n", status ); } @@ -3109,6 +3113,7 @@ static void WINAPI glBindBufferBaseNV( GLenum target, GLuint index, GLuint buffe struct glBindBufferBaseNV_params args = { .teb = NtCurrentTeb(), .target = target, .index = index, .buffer = buffer }; NTSTATUS status; TRACE( "target %d, index %d, buffer %d\n", target, index, buffer ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glBindBufferBaseNV, &args ))) WARN( "glBindBufferBaseNV returned %#lx\n", status ); } @@ -3117,6 +3122,7 @@ static void WINAPI glBindBufferOffsetEXT( GLenum target, GLuint index, GLuint bu struct glBindBufferOffsetEXT_params args = { .teb = NtCurrentTeb(), .target = target, .index = index, .buffer = buffer, .offset = offset }; NTSTATUS status; TRACE( "target %d, index %d, buffer %d, offset %Id\n", target, index, buffer, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glBindBufferOffsetEXT, &args ))) WARN( "glBindBufferOffsetEXT returned %#lx\n", status ); } @@ -3125,6 +3131,7 @@ static void WINAPI glBindBufferOffsetNV( GLenum target, GLuint index, GLuint buf struct glBindBufferOffsetNV_params args = { .teb = NtCurrentTeb(), .target = target, .index = index, .buffer = buffer, .offset = offset }; NTSTATUS status; TRACE( "target %d, index %d, buffer %d, offset %Id\n", target, index, buffer, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glBindBufferOffsetNV, &args ))) WARN( "glBindBufferOffsetNV returned %#lx\n", status ); } @@ -3133,6 +3140,7 @@ static void WINAPI glBindBufferRange( GLenum target, GLuint index, GLuint buffer struct glBindBufferRange_params args = { .teb = NtCurrentTeb(), .target = target, .index = index, .buffer = buffer, .offset = offset, .size = size }; NTSTATUS status; TRACE( "target %d, index %d, buffer %d, offset %Id, size %Id\n", target, index, buffer, offset, size ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, FALSE )) return; if ((status = UNIX_CALL( glBindBufferRange, &args ))) WARN( "glBindBufferRange returned %#lx\n", status ); } @@ -3141,6 +3149,7 @@ static void WINAPI glBindBufferRangeEXT( GLenum target, GLuint index, GLuint buf struct glBindBufferRangeEXT_params args = { .teb = NtCurrentTeb(), .target = target, .index = index, .buffer = buffer, .offset = offset, .size = size }; NTSTATUS status; TRACE( "target %d, index %d, buffer %d, offset %Id, size %Id\n", target, index, buffer, offset, size ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glBindBufferRangeEXT, &args ))) WARN( "glBindBufferRangeEXT returned %#lx\n", status ); } @@ -3149,6 +3158,7 @@ static void WINAPI glBindBufferRangeNV( GLenum target, GLuint index, GLuint buff struct glBindBufferRangeNV_params args = { .teb = NtCurrentTeb(), .target = target, .index = index, .buffer = buffer, .offset = offset, .size = size }; NTSTATUS status; TRACE( "target %d, index %d, buffer %d, offset %Id, size %Id\n", target, index, buffer, offset, size ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glBindBufferRangeNV, &args ))) WARN( "glBindBufferRangeNV returned %#lx\n", status ); } @@ -4103,6 +4113,7 @@ static void WINAPI glClearNamedBufferDataEXT( GLuint buffer, GLenum internalform struct glClearNamedBufferDataEXT_params args = { .teb = NtCurrentTeb(), .buffer = buffer, .internalformat = internalformat, .format = format, .type = type, .data = data }; NTSTATUS status; TRACE( "buffer %d, internalformat %d, format %d, type %d, data %p\n", buffer, internalformat, format, type, data ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glClearNamedBufferDataEXT, &args ))) WARN( "glClearNamedBufferDataEXT returned %#lx\n", status ); } @@ -4119,6 +4130,7 @@ static void WINAPI glClearNamedBufferSubDataEXT( GLuint buffer, GLenum internalf struct glClearNamedBufferSubDataEXT_params args = { .teb = NtCurrentTeb(), .buffer = buffer, .internalformat = internalformat, .offset = offset, .size = size, .format = format, .type = type, .data = data }; NTSTATUS status; TRACE( "buffer %d, internalformat %d, offset %Id, size %Id, format %d, type %d, data %p\n", buffer, internalformat, offset, size, format, type, data ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glClearNamedBufferSubDataEXT, &args ))) WARN( "glClearNamedBufferSubDataEXT returned %#lx\n", status ); } @@ -6891,6 +6903,7 @@ static void WINAPI glFlushMappedNamedBufferRangeEXT( GLuint buffer, GLintptr off struct glFlushMappedNamedBufferRangeEXT_params args = { .teb = NtCurrentTeb(), .buffer = buffer, .offset = offset, .length = length }; NTSTATUS status; TRACE( "buffer %d, offset %Id, length %Id\n", buffer, offset, length ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glFlushMappedNamedBufferRangeEXT, &args ))) WARN( "glFlushMappedNamedBufferRangeEXT returned %#lx\n", status ); } @@ -9051,6 +9064,7 @@ static void WINAPI glGetNamedBufferParameterivEXT( GLuint buffer, GLenum pname, struct glGetNamedBufferParameterivEXT_params args = { .teb = NtCurrentTeb(), .buffer = buffer, .pname = pname, .params = params }; NTSTATUS status; TRACE( "buffer %d, pname %d, params %p\n", buffer, pname, params ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glGetNamedBufferParameterivEXT, &args ))) WARN( "glGetNamedBufferParameterivEXT returned %#lx\n", status ); } @@ -9075,6 +9089,7 @@ static void WINAPI glGetNamedBufferPointervEXT( GLuint buffer, GLenum pname, voi struct glGetNamedBufferPointervEXT_params args = { .teb = NtCurrentTeb(), .buffer = buffer, .pname = pname, .params = params }; NTSTATUS status; TRACE( "buffer %d, pname %d, params %p\n", buffer, pname, params ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glGetNamedBufferPointervEXT, &args ))) WARN( "glGetNamedBufferPointervEXT returned %#lx\n", status ); } @@ -9091,6 +9106,7 @@ static void WINAPI glGetNamedBufferSubDataEXT( GLuint buffer, GLintptr offset, G struct glGetNamedBufferSubDataEXT_params args = { .teb = NtCurrentTeb(), .buffer = buffer, .offset = offset, .size = size, .data = data }; NTSTATUS status; TRACE( "buffer %d, offset %Id, size %Id, data %p\n", buffer, offset, size, data ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glGetNamedBufferSubDataEXT, &args ))) WARN( "glGetNamedBufferSubDataEXT returned %#lx\n", status ); } @@ -12415,6 +12431,7 @@ static void * WINAPI glMapNamedBufferEXT( GLuint buffer, GLenum access ) struct glMapNamedBufferEXT_params args = { .teb = NtCurrentTeb(), .buffer = buffer, .access = access }; NTSTATUS status; TRACE( "buffer %d, access %d\n", buffer, access ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return args.ret; if ((status = UNIX_CALL( glMapNamedBufferEXT, &args ))) WARN( "glMapNamedBufferEXT returned %#lx\n", status ); return args.ret; } @@ -12433,6 +12450,7 @@ static void * WINAPI glMapNamedBufferRangeEXT( GLuint buffer, GLintptr offset, G struct glMapNamedBufferRangeEXT_params args = { .teb = NtCurrentTeb(), .buffer = buffer, .offset = offset, .length = length, .access = access }; NTSTATUS status; TRACE( "buffer %d, offset %Id, length %Id, access %d\n", buffer, offset, length, access ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return args.ret; if ((status = UNIX_CALL( glMapNamedBufferRangeEXT, &args ))) WARN( "glMapNamedBufferRangeEXT returned %#lx\n", status ); return args.ret; } @@ -13108,6 +13126,7 @@ static void WINAPI glMultiTexBufferEXT( GLenum texunit, GLenum target, GLenum in struct glMultiTexBufferEXT_params args = { .teb = NtCurrentTeb(), .texunit = texunit, .target = target, .internalformat = internalformat, .buffer = buffer }; NTSTATUS status; TRACE( "texunit %d, target %d, internalformat %d, buffer %d\n", texunit, target, internalformat, buffer ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glMultiTexBufferEXT, &args ))) WARN( "glMultiTexBufferEXT returned %#lx\n", status ); } @@ -14476,6 +14495,7 @@ static void WINAPI glNamedBufferDataEXT( GLuint buffer, GLsizeiptr size, const v struct glNamedBufferDataEXT_params args = { .teb = NtCurrentTeb(), .buffer = buffer, .size = size, .data = data, .usage = usage }; NTSTATUS status; TRACE( "buffer %d, size %Id, data %p, usage %d\n", buffer, size, data, usage ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glNamedBufferDataEXT, &args ))) WARN( "glNamedBufferDataEXT returned %#lx\n", status ); } @@ -14516,6 +14536,7 @@ static void WINAPI glNamedBufferStorageEXT( GLuint buffer, GLsizeiptr size, cons struct glNamedBufferStorageEXT_params args = { .teb = NtCurrentTeb(), .buffer = buffer, .size = size, .data = data, .flags = flags }; NTSTATUS status; TRACE( "buffer %d, size %Id, data %p, flags %d\n", buffer, size, data, flags ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glNamedBufferStorageEXT, &args ))) WARN( "glNamedBufferStorageEXT returned %#lx\n", status ); } @@ -14548,6 +14569,7 @@ static void WINAPI glNamedBufferSubDataEXT( GLuint buffer, GLintptr offset, GLsi struct glNamedBufferSubDataEXT_params args = { .teb = NtCurrentTeb(), .buffer = buffer, .offset = offset, .size = size, .data = data }; NTSTATUS status; TRACE( "buffer %d, offset %Id, size %Id, data %p\n", buffer, offset, size, data ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glNamedBufferSubDataEXT, &args ))) WARN( "glNamedBufferSubDataEXT returned %#lx\n", status ); } @@ -14556,6 +14578,8 @@ static void WINAPI glNamedCopyBufferSubDataEXT( GLuint readBuffer, GLuint writeB struct glNamedCopyBufferSubDataEXT_params args = { .teb = NtCurrentTeb(), .readBuffer = readBuffer, .writeBuffer = writeBuffer, .readOffset = readOffset, .writeOffset = writeOffset, .size = size }; NTSTATUS status; TRACE( "readBuffer %d, writeBuffer %d, readOffset %Id, writeOffset %Id, size %Id\n", readBuffer, writeBuffer, readOffset, writeOffset, size ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &readBuffer, TRUE )) return; + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &writeBuffer, TRUE )) return; if ((status = UNIX_CALL( glNamedCopyBufferSubDataEXT, &args ))) WARN( "glNamedCopyBufferSubDataEXT returned %#lx\n", status ); } @@ -19732,6 +19756,7 @@ static void WINAPI glTextureBufferEXT( GLuint texture, GLenum target, GLenum int struct glTextureBufferEXT_params args = { .teb = NtCurrentTeb(), .texture = texture, .target = target, .internalformat = internalformat, .buffer = buffer }; NTSTATUS status; TRACE( "texture %d, target %d, internalformat %d, buffer %d\n", texture, target, internalformat, buffer ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glTextureBufferEXT, &args ))) WARN( "glTextureBufferEXT returned %#lx\n", status ); } @@ -19748,6 +19773,7 @@ static void WINAPI glTextureBufferRangeEXT( GLuint texture, GLenum target, GLenu struct glTextureBufferRangeEXT_params args = { .teb = NtCurrentTeb(), .texture = texture, .target = target, .internalformat = internalformat, .buffer = buffer, .offset = offset, .size = size }; NTSTATUS status; TRACE( "texture %d, target %d, internalformat %d, buffer %d, offset %Id, size %Id\n", texture, target, internalformat, buffer, offset, size ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glTextureBufferRangeEXT, &args ))) WARN( "glTextureBufferRangeEXT returned %#lx\n", status ); } @@ -21223,6 +21249,7 @@ static GLboolean WINAPI glUnmapNamedBufferEXT( GLuint buffer ) struct glUnmapNamedBufferEXT_params args = { .teb = NtCurrentTeb(), .buffer = buffer }; NTSTATUS status; TRACE( "buffer %d\n", buffer ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return args.ret; if ((status = UNIX_CALL( glUnmapNamedBufferEXT, &args ))) WARN( "glUnmapNamedBufferEXT returned %#lx\n", status ); return args.ret; } @@ -21668,6 +21695,7 @@ static void WINAPI glVertexArrayBindVertexBufferEXT( GLuint vaobj, GLuint bindin struct glVertexArrayBindVertexBufferEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .bindingindex = bindingindex, .buffer = buffer, .offset = offset, .stride = stride }; NTSTATUS status; TRACE( "vaobj %d, bindingindex %d, buffer %d, offset %Id, stride %d\n", vaobj, bindingindex, buffer, offset, stride ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArrayBindVertexBufferEXT, &args ))) WARN( "glVertexArrayBindVertexBufferEXT returned %#lx\n", status ); } @@ -21684,6 +21712,7 @@ static void WINAPI glVertexArrayColorOffsetEXT( GLuint vaobj, GLuint buffer, GLi struct glVertexArrayColorOffsetEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .buffer = buffer, .size = size, .type = type, .stride = stride, .offset = offset }; NTSTATUS status; TRACE( "vaobj %d, buffer %d, size %d, type %d, stride %d, offset %Id\n", vaobj, buffer, size, type, stride, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArrayColorOffsetEXT, &args ))) WARN( "glVertexArrayColorOffsetEXT returned %#lx\n", status ); } @@ -21692,6 +21721,7 @@ static void WINAPI glVertexArrayEdgeFlagOffsetEXT( GLuint vaobj, GLuint buffer, struct glVertexArrayEdgeFlagOffsetEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .buffer = buffer, .stride = stride, .offset = offset }; NTSTATUS status; TRACE( "vaobj %d, buffer %d, stride %d, offset %Id\n", vaobj, buffer, stride, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArrayEdgeFlagOffsetEXT, &args ))) WARN( "glVertexArrayEdgeFlagOffsetEXT returned %#lx\n", status ); } @@ -21708,6 +21738,7 @@ static void WINAPI glVertexArrayFogCoordOffsetEXT( GLuint vaobj, GLuint buffer, struct glVertexArrayFogCoordOffsetEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .buffer = buffer, .type = type, .stride = stride, .offset = offset }; NTSTATUS status; TRACE( "vaobj %d, buffer %d, type %d, stride %d, offset %Id\n", vaobj, buffer, type, stride, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArrayFogCoordOffsetEXT, &args ))) WARN( "glVertexArrayFogCoordOffsetEXT returned %#lx\n", status ); } @@ -21716,6 +21747,7 @@ static void WINAPI glVertexArrayIndexOffsetEXT( GLuint vaobj, GLuint buffer, GLe struct glVertexArrayIndexOffsetEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .buffer = buffer, .type = type, .stride = stride, .offset = offset }; NTSTATUS status; TRACE( "vaobj %d, buffer %d, type %d, stride %d, offset %Id\n", vaobj, buffer, type, stride, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArrayIndexOffsetEXT, &args ))) WARN( "glVertexArrayIndexOffsetEXT returned %#lx\n", status ); } @@ -21724,6 +21756,7 @@ static void WINAPI glVertexArrayMultiTexCoordOffsetEXT( GLuint vaobj, GLuint buf struct glVertexArrayMultiTexCoordOffsetEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .buffer = buffer, .texunit = texunit, .size = size, .type = type, .stride = stride, .offset = offset }; NTSTATUS status; TRACE( "vaobj %d, buffer %d, texunit %d, size %d, type %d, stride %d, offset %Id\n", vaobj, buffer, texunit, size, type, stride, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArrayMultiTexCoordOffsetEXT, &args ))) WARN( "glVertexArrayMultiTexCoordOffsetEXT returned %#lx\n", status ); } @@ -21732,6 +21765,7 @@ static void WINAPI glVertexArrayNormalOffsetEXT( GLuint vaobj, GLuint buffer, GL struct glVertexArrayNormalOffsetEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .buffer = buffer, .type = type, .stride = stride, .offset = offset }; NTSTATUS status; TRACE( "vaobj %d, buffer %d, type %d, stride %d, offset %Id\n", vaobj, buffer, type, stride, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArrayNormalOffsetEXT, &args ))) WARN( "glVertexArrayNormalOffsetEXT returned %#lx\n", status ); } @@ -21764,6 +21798,7 @@ static void WINAPI glVertexArraySecondaryColorOffsetEXT( GLuint vaobj, GLuint bu struct glVertexArraySecondaryColorOffsetEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .buffer = buffer, .size = size, .type = type, .stride = stride, .offset = offset }; NTSTATUS status; TRACE( "vaobj %d, buffer %d, size %d, type %d, stride %d, offset %Id\n", vaobj, buffer, size, type, stride, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArraySecondaryColorOffsetEXT, &args ))) WARN( "glVertexArraySecondaryColorOffsetEXT returned %#lx\n", status ); } @@ -21772,6 +21807,7 @@ static void WINAPI glVertexArrayTexCoordOffsetEXT( GLuint vaobj, GLuint buffer, struct glVertexArrayTexCoordOffsetEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .buffer = buffer, .size = size, .type = type, .stride = stride, .offset = offset }; NTSTATUS status; TRACE( "vaobj %d, buffer %d, size %d, type %d, stride %d, offset %Id\n", vaobj, buffer, size, type, stride, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArrayTexCoordOffsetEXT, &args ))) WARN( "glVertexArrayTexCoordOffsetEXT returned %#lx\n", status ); } @@ -21812,6 +21848,7 @@ static void WINAPI glVertexArrayVertexAttribIOffsetEXT( GLuint vaobj, GLuint buf struct glVertexArrayVertexAttribIOffsetEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .buffer = buffer, .index = index, .size = size, .type = type, .stride = stride, .offset = offset }; NTSTATUS status; TRACE( "vaobj %d, buffer %d, index %d, size %d, type %d, stride %d, offset %Id\n", vaobj, buffer, index, size, type, stride, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArrayVertexAttribIOffsetEXT, &args ))) WARN( "glVertexArrayVertexAttribIOffsetEXT returned %#lx\n", status ); } @@ -21828,6 +21865,7 @@ static void WINAPI glVertexArrayVertexAttribLOffsetEXT( GLuint vaobj, GLuint buf struct glVertexArrayVertexAttribLOffsetEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .buffer = buffer, .index = index, .size = size, .type = type, .stride = stride, .offset = offset }; NTSTATUS status; TRACE( "vaobj %d, buffer %d, index %d, size %d, type %d, stride %d, offset %Id\n", vaobj, buffer, index, size, type, stride, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArrayVertexAttribLOffsetEXT, &args ))) WARN( "glVertexArrayVertexAttribLOffsetEXT returned %#lx\n", status ); } @@ -21836,6 +21874,7 @@ static void WINAPI glVertexArrayVertexAttribOffsetEXT( GLuint vaobj, GLuint buff struct glVertexArrayVertexAttribOffsetEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .buffer = buffer, .index = index, .size = size, .type = type, .normalized = normalized, .stride = stride, .offset = offset }; NTSTATUS status; TRACE( "vaobj %d, buffer %d, index %d, size %d, type %d, normalized %d, stride %d, offset %Id\n", vaobj, buffer, index, size, type, normalized, stride, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArrayVertexAttribOffsetEXT, &args ))) WARN( "glVertexArrayVertexAttribOffsetEXT returned %#lx\n", status ); } @@ -21868,6 +21907,7 @@ static void WINAPI glVertexArrayVertexOffsetEXT( GLuint vaobj, GLuint buffer, GL struct glVertexArrayVertexOffsetEXT_params args = { .teb = NtCurrentTeb(), .vaobj = vaobj, .buffer = buffer, .size = size, .type = type, .stride = stride, .offset = offset }; NTSTATUS status; TRACE( "vaobj %d, buffer %d, size %d, type %d, stride %d, offset %Id\n", vaobj, buffer, size, type, stride, offset ); + if (!alloc_context_objects( OBJ_TYPE_BUFFER, 1, &buffer, TRUE )) return; if ((status = UNIX_CALL( glVertexArrayVertexOffsetEXT, &args ))) WARN( "glVertexArrayVertexOffsetEXT returned %#lx\n", status ); } diff --git a/dlls/opengl32/wgl.c b/dlls/opengl32/wgl.c index da35e355332..db021aa5842 100644 --- a/dlls/opengl32/wgl.c +++ b/dlls/opengl32/wgl.c @@ -278,6 +278,8 @@ struct object_table enum object_type type; /* object type of the id table */ SRWLOCK lock; /* lock for accessing the table */ GLuint **host_ids[L1_COUNT]; /* client -> host id mapping sparse array */ + GLuint min_free; /* id to start looking for a free slot */ + BOOL implicit; /* table allows implicit allocation */ }; static GLuint *find_object_id( GLuint **ids[L1_COUNT], GLuint client_id ) @@ -312,6 +314,22 @@ static void free_object_ids( struct object_table *table, GLuint **ids[L1_COUNT] } } +static GLuint alloc_client_id( struct object_table *table, GLuint host_id ) +{ + /* if we don't need implicit allocations, use the host allocated ids directly */ + if (!table->implicit) return host_id; + + /* otherwise we need to allocate client id ourselves, lookup for a free id */ + for (GLuint id = table->min_free + 1, *ids; id != 0; id++) + { + if (!(ids = alloc_object_ids( table->host_ids, id ))) return 0; + if (ids[id % L3_COUNT]) continue; + return table->min_free = id; + } + + return 0; +} + static GLuint set_object( struct object_table *table, GLuint client_id, GLuint host_id ) { GLuint *ids; @@ -332,6 +350,7 @@ static GLuint del_object( struct object_table *table, GLuint client_id ) GLuint *object, host_id = 0; if (!client_id || !(object = find_object_id( table->host_ids, client_id ))) return client_id; + table->min_free = min( table->min_free, client_id - 1 ); host_id = *object; *object = 0; @@ -339,6 +358,15 @@ static GLuint del_object( struct object_table *table, GLuint client_id ) return host_id ? host_id : client_id; } +static GLuint get_object( struct object_table *table, GLuint client_id, BOOL check ) +{ + const GLuint *object = find_object_id( table->host_ids, client_id ); + GLuint host_id = object ? *object : 0; + + TRACE( "Found %s client %#x, host %#x\n", debugstr_object_type( table->type ), client_id, host_id ); + return check || host_id ? host_id : -1; +} + static void free_object_table( struct object_table *table ) { free_object_ids( table, table->host_ids ); @@ -480,10 +508,51 @@ void put_context_objects( enum object_type type, UINT n, GLuint *handles ) if (!(table = get_object_table( ctx, type, TRUE ))) return; AcquireSRWLockExclusive( &table->lock ); - for (UINT i = 0; i < n; i++) handles[i] = handles[i] ? set_object( table, handles[i], handles[i] ) : 0; + for (UINT i = 0; i < n; i++) handles[i] = handles[i] ? set_object( table, alloc_client_id( table, handles[i] ), handles[i] ) : 0; ReleaseSRWLockExclusive( &table->lock ); } +static void alloc_client_objects( struct context *ctx, enum object_type type, UINT n, const GLuint *handles ) +{ + struct object_table *table; + + if (!(table = get_object_table( ctx, type, TRUE ))) return; + + AcquireSRWLockExclusive( &table->lock ); + for (UINT i = 0; i < n; i++) + { + if (!handles[i] || get_object( table, handles[i], TRUE )) continue; + WARN( "Creating implicit %s client %#x\n", debugstr_object_type( type ), handles[i] ); + set_object( table, handles[i], handles[i] ); + table->implicit = TRUE; /* from now on we cannot rely on host-allocated ids */ + } + ReleaseSRWLockExclusive( &table->lock ); +} + +BOOL alloc_context_objects( enum object_type type, UINT n, const GLuint *handles, BOOL extension ) +{ + BOOL alloc_client = TRUE, needs_client = FALSE; + struct object_table *table; + struct context *ctx; + + if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return TRUE; + if (!(table = get_object_table( ctx, type, FALSE ))) return TRUE; + + /* only allow explicit allocation in some cases, use host allocated ids directly in that case */ + if (ctx->base.profile_mask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB) alloc_client = FALSE; + + AcquireSRWLockShared( &table->lock ); + for (UINT i = 0; i < n && !needs_client; i++) + needs_client = handles[i] && !get_object( table, handles[i], TRUE ); + ReleaseSRWLockShared( &table->lock ); + if (!needs_client) return TRUE; + + if (alloc_client) alloc_client_objects( ctx, type, n, handles ); + else set_gl_error( GL_INVALID_OPERATION ); + + return alloc_client; +} + GLuint *del_context_objects( enum object_type type, UINT n, GLuint *handles ) { struct object_table *table; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10870
Anything wrong with this? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10870#note_139938
It would be nice to add some justification. On its own, the series does not seem to improve anything... -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10870#note_140346
It introduces the mechanism, so yes it does not do much. The whole series will be much longer but we're often told to keep MRs small. The change at the very least is an improvement to wglShareLists implementation, which currently involves a complicated context state tracking and recreation. Although the current code is enough for the few games we have found to be using wglShareLists, it is not correct wrt actual wglShareLists behavior, and cannot be because of impedance mismatch with host GL API. I chose not to go through object name wrapping at the time because it was a larger impacting change, but after spending more time studying the options for framebuffer rendering, it seems now that it is unavoidable if we want more freedom with object allocation on the unix side. As discussed elsewhere, it is also necessary so that we can allocate GL objects in application rendering contexts on the unix side to implement our own GL swapchains, without breaking application assumptions about object names. GL allows most objects to be implicitly allocated, as https://gitlab.winehq.org/wine/wine/-/merge_requests/10739 tests shows, and many applications are hardcoding the object names they use without any explicit allocation. We cannot safely allocate GL objects unless they are isolated and hidden from application objects, and because of other GL context sharing and destruction semantics we will also have to track and isolate every shareable object name, and end up with a single global GL object namespace on the unix side. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10870#note_140538
Why is PE side involved at all? This essentially duplicates wow64 buffers tracking, why not extend that instead? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10870#note_140844
Why should it live on the unix side? This is not the same thing as wow64 buffer tracking: it is not limited to WOW64 and it is not meant to create object wrappers. We only need integral name mapping, and we want it to be as lightweight as possible. This starts with buffers but it will need to map several other kind of objects. GLsync handle allocation, which is on the PE side already will also be moved to the display lists for correctness. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10870#note_140923
Why should it live on the unix side?
That's where most of the logic already lives, including some of the logic that you are duplicating here, and it's not going away. Why would we split the logic when we don't need to? Instead of having a single module with the full picture, we'd end up with two modules and a non-obvious protocol between them. Having client IDs in the unixlib protocol simply seems much cleaner to me. I do not see why the PE side would need to know anything about IDs internal to Unix. There are cases where some split makes sense, for example for context handling. But in this case, I do not see any value added, thus my question.
This is not the same thing as wow64 buffer tracking: it is not limited to WOW64 and it is not meant to create object wrappers. We only need integral name mapping, and we want it to be as lightweight as possible.
We do not need all of them to be full wrappers. Whatever you do on the PE side can be done on the Unix side as well.
GLsync handle allocation, which is on the PE side already will also be moved to the display lists for correctness.
Maybe they should be on the Unix side too. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10870#note_141048
On Fri May 22 12:20:02 2026 +0000, Jacek Caban wrote:
Why should it live on the unix side? That's where most of the logic already lives, including some of the logic that you are duplicating here, and it's not going away. Why would we split the logic when we don't need to? Instead of having a single module with the full picture, we'd end up with two modules and a non-obvious protocol between them. Having client IDs in the unixlib protocol simply seems much cleaner to me. I do not see why the PE side would need to know anything about IDs internal to Unix. There are cases where some split makes sense, for example for context handling. But in this case, I do not see any value added, thus my question. This is not the same thing as wow64 buffer tracking: it is not limited to WOW64 and it is not meant to create object wrappers. We only need integral name mapping, and we want it to be as lightweight as possible. We do not need all of them to be full wrappers. Whatever you do on the PE side can be done on the Unix side as well. GLsync handle allocation, which is on the PE side already will also be moved to the display lists for correctness. Maybe they should be on the Unix side too. I don't think it makes sense: the current WOW64 buffer wrappers are about wrapping the buffer *storage*, and managing their mapped pointer location, which is also some WOW64-only logic. The wrappers are allocated only when the buffer storage is allocated, which is *not* the same thing as the buffer *names*, or the buffer *objects*. Buffer *names*, and *objects*, may be allocated without storage, and their lifetime is different.
This here, is not about buffer storage, not WOW64 specific, not just even about buffers, and is about *names* instead. It introduces and will implement a set of int-to-int mapping tables which are self sufficient and isolated, and won't need to interact with any other logic. Whether we use PE-side object names or unix side object names, depending on which side of it we're on, does not really matter. I don't see any non-obvious protocol here, this logic, on the PE side, will very obviously manage the PE-side contexts lifetime and wglShareLists-specific PE-side context-sharing logic. It will use the unix side names for that, yes, but that's an arbitrary choice, and I think any other choice is just as arbitrary, and that managing PE-side context sharing rules on the unix side is not obvious. Mixing this with the WOW64 buffer wrapper logic with different lifetime rules, is also unlikely going to make things clearer. Regarding the non-obviousness I believe the outlier right now is actually the opengl32 module unix side, which awkwardly sits between opengl32 PE side and win32u / user drivers / host GL. Whatever it does should probably be moved either to the PE side, or to win32u, which is what I am generally aiming for. In any case I see no good reason to rewrite a several dozen of patches just because of some arbitrary choice, and if there's nothing to be said on the code itself, please lets move on with this. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10870#note_141051
If there's nothing else, can we merge this? -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10870#note_141806
Please merge this, this is blocking all progress on implementing a compositing-like mechanism and we've wasted enough time on pointless discussions. We don't agree, so be it, it's not the first time, won't be the last. Whether that code belongs to PE or unix side is of no importance, it can always (but will unlikely need to) be moved around later, like I moved the client context handle allocation. I will even argue that ultimately, it's also likely that the GL host bridge is going to deprecate anyway, in favor of doing something like PE-side Zink, or re-implementing a similar PE-side GL runtime over GL or some other API on the PE side, for flexibility and compatibility reasons. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10870#note_142279
participants (3)
-
Jacek Caban (@jacek) -
Rémi Bernon -
Rémi Bernon (@rbernon)