And use it to store the client pointer instead of storing it in the buffer data.
My main motivation is to make it easy to implement alternative solutions, such as `mach_vm_remap` or `glImportMemoryFdEXT`. However, I think this change is worth it on its own as the current strategy violates the spec by modifying pointers returned from read-only mappings. It will also make it possible to fix wow64 buffer leaks.
From: Jacek Caban jacek@codeweavers.com
And use it to store the client pointer instead of storing it in the buffer data. --- dlls/opengl32/make_opengl | 30 ++- dlls/opengl32/unix_private.h | 2 + dlls/opengl32/unix_thunks.c | 42 +++- dlls/opengl32/unix_thunks.h | 4 +- dlls/opengl32/unix_wgl.c | 362 +++++++++++++++++++++++++---------- 5 files changed, 333 insertions(+), 107 deletions(-)
diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl index 60ba6e2d5b1..97a3a1fb950 100755 --- a/dlls/opengl32/make_opengl +++ b/dlls/opengl32/make_opengl @@ -289,6 +289,7 @@ my %map_default_fbo_thunks = my %manual_wow64_wrappers = ( "glClientWaitSync" => 0, + "glDeleteBuffers" => 0, "glDeleteSync" => 0, "glFenceSync" => 0, "glGetBufferPointerv" => 0, @@ -310,6 +311,22 @@ my %manual_wow64_wrappers = "glUnmapNamedBufferEXT" => 1, "glWaitSync" => 0, ); +my %wow64_invalidate_buffer = + ( + "glBufferAttachMemoryNV" => 1, + "glBufferData" => 1, + "glBufferDataARB" => 1, + "glBufferStorage" => 1, + "glBufferStorageExternalEXT" => 1, + "glBufferStorageMemEXT" => 1, + "glNamedBufferAttachMemoryNV" => 1, + "glNamedBufferData" => 1, + "glNamedBufferDataEXT" => 1, + "glNamedBufferStorage" => 1, + "glNamedBufferStorageEXT" => 1, + "glNamedBufferStorageExternalEXT" => 1, + "glNamedBufferStorageMemEXT" => 1, + ); my %pointer_array_count = ( "glCompileShaderIncludeARB" => "count", @@ -431,6 +448,7 @@ sub generate_unix_thunk($$$$) my $need_lock = $func_ret =~ /HGLRC|HPBUFFERARB/; my $teb = $is_wow64 ? "teb" : "params->teb"; my $ret_stat = "return STATUS_SUCCESS;"; + my $invalidation = ""; my $input_conv = ""; my $output_conv = ""; my $call_args = ""; @@ -531,6 +549,13 @@ sub generate_unix_thunk($$$$) $ret .= "}\n\n"; return $ret; } + if (defined $wow64_invalidate_buffer{$name}) + { + $need_lock = 1; + $invalidation .= $name =~ /NamedBuffer/ + ? " invalidate_buffer_name( $teb, params->buffer );\n" + : " invalidate_buffer_target( $teb, params->target );\n"; + } $ret .= " TEB *teb = get_teb64( params->teb );\n" if $need_wrap || !$use_dc; } else @@ -571,7 +596,7 @@ sub generate_unix_thunk($$$$) } $ret .= " resolve_default_fbo( $teb, TRUE );\n" if defined $resolve_default_fbo_thunks{$name}; $ret .= " push_default_fbo( $teb );\n" if defined $hide_default_fbo_thunks{$name}; - $ret .= " pthread_mutex_lock( &wgl_lock );\n" if $need_lock; + $ret .= " pthread_mutex_lock( &wgl_lock );\n$invalidation" if $need_lock; $ret .= " $ret_expr"; $call_args =~ s/,$/ /; if ($manual_wow64_wrapper) @@ -1392,6 +1417,8 @@ close OUT; open OUT, ">unix_thunks.h" or die "cannot create unix_thunks.h"; print OUT "/* Automatically generated from http://www.opengl.org/registry files; DO NOT EDIT! */\n\n";
+print OUT "typedef ULONG PTR32;\n\n"; + foreach (sort keys %wgl_functions) { next if !needs_wrapper( $_, $wgl_functions{$_} ); @@ -1410,7 +1437,6 @@ foreach (sort keys %ext_functions) }
print OUT "\n#ifdef _WIN64\n"; -print OUT "typedef ULONG PTR32;\n";
foreach (sort keys %wgl_functions) { diff --git a/dlls/opengl32/unix_private.h b/dlls/opengl32/unix_private.h index 4b05a98cccf..9ced126e3ab 100644 --- a/dlls/opengl32/unix_private.h +++ b/dlls/opengl32/unix_private.h @@ -71,6 +71,8 @@ static inline TEB *get_teb64( ULONG teb32 ) return (TEB *)((char *)teb32_ptr + teb32_ptr->WowTebOffset); }
+extern void invalidate_buffer_name( TEB *teb, GLuint name ); +extern void invalidate_buffer_target( TEB *teb, GLenum target ); extern NTSTATUS return_wow64_string( const void *str, PTR32 *wow64_str );
#endif diff --git a/dlls/opengl32/unix_thunks.c b/dlls/opengl32/unix_thunks.c index 820bd47929f..abec508aafb 100644 --- a/dlls/opengl32/unix_thunks.c +++ b/dlls/opengl32/unix_thunks.c @@ -37327,7 +37327,10 @@ static NTSTATUS wow64_ext_glBufferAttachMemoryNV( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_target( teb, params->target ); funcs->p_glBufferAttachMemoryNV( params->target, params->memory, params->offset ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -37344,7 +37347,10 @@ static NTSTATUS wow64_ext_glBufferData( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_target( teb, params->target ); funcs->p_glBufferData( params->target, (GLsizeiptr)ULongToPtr(params->size), ULongToPtr(params->data), params->usage ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -37361,7 +37367,10 @@ static NTSTATUS wow64_ext_glBufferDataARB( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_target( teb, params->target ); funcs->p_glBufferDataARB( params->target, (GLsizeiptrARB)ULongToPtr(params->size), ULongToPtr(params->data), params->usage ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -37425,7 +37434,10 @@ static NTSTATUS wow64_ext_glBufferStorage( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_target( teb, params->target ); funcs->p_glBufferStorage( params->target, (GLsizeiptr)ULongToPtr(params->size), ULongToPtr(params->data), params->flags ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -37443,7 +37455,10 @@ static NTSTATUS wow64_ext_glBufferStorageExternalEXT( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_target( teb, params->target ); funcs->p_glBufferStorageExternalEXT( params->target, (GLintptr)ULongToPtr(params->offset), (GLsizeiptr)ULongToPtr(params->size), ULongToPtr(params->clientBuffer), params->flags ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -37460,7 +37475,10 @@ static NTSTATUS wow64_ext_glBufferStorageMemEXT( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_target( teb, params->target ); funcs->p_glBufferStorageMemEXT( params->target, (GLsizeiptr)ULongToPtr(params->size), params->memory, params->offset ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -41248,8 +41266,7 @@ static NTSTATUS wow64_ext_glDeleteBuffers( void *args ) PTR32 buffers; } *params = args; TEB *teb = get_teb64( params->teb ); - const struct opengl_funcs *funcs = teb->glTable; - funcs->p_glDeleteBuffers( params->n, ULongToPtr(params->buffers) ); + wow64_glDeleteBuffers( teb, params->n, ULongToPtr(params->buffers) ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -58106,7 +58123,10 @@ static NTSTATUS wow64_ext_glNamedBufferAttachMemoryNV( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_name( teb, params->buffer ); funcs->p_glNamedBufferAttachMemoryNV( params->buffer, params->memory, params->offset ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -58123,7 +58143,10 @@ static NTSTATUS wow64_ext_glNamedBufferData( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_name( teb, params->buffer ); funcs->p_glNamedBufferData( params->buffer, (GLsizeiptr)ULongToPtr(params->size), ULongToPtr(params->data), params->usage ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -58140,7 +58163,10 @@ static NTSTATUS wow64_ext_glNamedBufferDataEXT( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_name( teb, params->buffer ); funcs->p_glNamedBufferDataEXT( params->buffer, (GLsizeiptr)ULongToPtr(params->size), ULongToPtr(params->data), params->usage ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -58191,7 +58217,10 @@ static NTSTATUS wow64_ext_glNamedBufferStorage( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_name( teb, params->buffer ); funcs->p_glNamedBufferStorage( params->buffer, (GLsizeiptr)ULongToPtr(params->size), ULongToPtr(params->data), params->flags ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -58208,7 +58237,10 @@ static NTSTATUS wow64_ext_glNamedBufferStorageEXT( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_name( teb, params->buffer ); funcs->p_glNamedBufferStorageEXT( params->buffer, (GLsizeiptr)ULongToPtr(params->size), ULongToPtr(params->data), params->flags ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -58226,7 +58258,10 @@ static NTSTATUS wow64_ext_glNamedBufferStorageExternalEXT( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_name( teb, params->buffer ); funcs->p_glNamedBufferStorageExternalEXT( params->buffer, (GLintptr)ULongToPtr(params->offset), (GLsizeiptr)ULongToPtr(params->size), ULongToPtr(params->clientBuffer), params->flags ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } @@ -58243,7 +58278,10 @@ static NTSTATUS wow64_ext_glNamedBufferStorageMemEXT( void *args ) } *params = args; TEB *teb = get_teb64( params->teb ); const struct opengl_funcs *funcs = teb->glTable; + pthread_mutex_lock( &wgl_lock ); + invalidate_buffer_name( teb, params->buffer ); funcs->p_glNamedBufferStorageMemEXT( params->buffer, (GLsizeiptr)ULongToPtr(params->size), params->memory, params->offset ); + pthread_mutex_unlock( &wgl_lock ); set_context_attribute( teb, -1 /* unsupported */, NULL, 0 ); return STATUS_SUCCESS; } diff --git a/dlls/opengl32/unix_thunks.h b/dlls/opengl32/unix_thunks.h index 4cb48b7aa7b..8b73b95da33 100644 --- a/dlls/opengl32/unix_thunks.h +++ b/dlls/opengl32/unix_thunks.h @@ -1,5 +1,7 @@ /* Automatically generated from http://www.opengl.org/registry files; DO NOT EDIT! */
+typedef ULONG PTR32; + extern BOOL wrap_wglCopyContext( TEB *teb, HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask ); extern HGLRC wrap_wglCreateContext( TEB *teb, HDC hDc ); extern BOOL wrap_wglDeleteContext( TEB *teb, HGLRC oldContext ); @@ -45,8 +47,8 @@ extern BOOL wrap_wglReleaseTexImageARB( TEB *teb, HPBUFFERARB hPbuffer, int iBuf extern BOOL wrap_wglSetPbufferAttribARB( TEB *teb, HPBUFFERARB hPbuffer, const int *piAttribList );
#ifdef _WIN64 -typedef ULONG PTR32; extern GLenum wow64_glClientWaitSync( TEB *teb, GLsync sync, GLbitfield flags, GLuint64 timeout ); +extern void wow64_glDeleteBuffers( TEB *teb, GLsizei n, const GLuint *buffers ); extern void wow64_glDeleteSync( TEB *teb, GLsync sync ); extern GLsync wow64_glFenceSync( TEB *teb, GLenum condition, GLbitfield flags ); extern void wow64_glGetBufferPointerv( TEB *teb, GLenum target, GLenum pname, PTR32 *params ); diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index 7aa3d20bc7e..d7420a8ca6d 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -40,6 +40,7 @@ #include "unix_private.h"
#include "wine/debug.h" +#include "wine/rbtree.h"
WINE_DEFAULT_DEBUG_CHANNEL(opengl);
@@ -118,6 +119,12 @@ struct hint_state GLenum perspective_correction; };
+struct buffers +{ + unsigned int ref; + struct rb_tree map; +}; + struct context { struct wgl_context base; @@ -131,6 +138,7 @@ struct context GLubyte *extensions; /* extension string */ GLuint *disabled_exts; /* indices of disabled extensions */ GLubyte *wow64_version; /* wow64 GL version override */ + struct buffers *buffers; /* wow64 buffers map */
/* semi-stub state tracker for wglCopyContext */ GLbitfield used; /* context state used bits */ @@ -146,6 +154,16 @@ struct context GLboolean has_viewport; /* whether viewport has been initialized */ };
+struct buffer +{ + struct rb_entry entry; + GLuint name; + size_t size; + void *host_ptr; + void *map_ptr; + size_t copy_length; +}; + struct wgl_handle { UINT handle; @@ -315,6 +333,23 @@ static BOOL copy_context_attributes( TEB *teb, const struct opengl_funcs *funcs, return dst->used != -1 && src->used != -1; }
+static int compare_buffer_name( const void *key, const struct rb_entry *entry ) +{ + struct buffer *buffer = RB_ENTRY_VALUE( entry, struct buffer, entry ); + return memcmp( key, &buffer->name, sizeof(buffer->name) ); +} + +static void release_buffers( struct buffers *buffers ) +{ + struct buffer *buffer, *next; + + if (--buffers->ref) return; + + RB_FOR_EACH_ENTRY_DESTRUCTOR( buffer, next, &buffers->map, struct buffer, entry ) + free( buffer ); + free( buffers ); +} + static struct context *opengl_context_from_handle( TEB *teb, HGLRC handle, const struct opengl_funcs **funcs );
/* update handle context if it has been re-shared with another one */ @@ -332,6 +367,12 @@ static void update_handle_context( TEB *teb, HGLRC handle, struct wgl_handle *pt WARN( "Failed to re-create context for wglShareLists\n" ); return; } + if (shared && shared->buffers) + { + release_buffers( ctx->buffers ); + ctx->buffers = shared->buffers; + ctx->buffers->ref++; + } ctx->share = (HGLRC)-1; /* initial shared context */ copy_context_attributes( teb, funcs, handle, ctx, handle, ctx, ctx->used ); } @@ -1251,6 +1292,24 @@ HGLRC wrap_wglCreateContextAttribsARB( TEB *teb, HDC hdc, HGLRC share, const int context->hdc = hdc; context->share = (HGLRC)-1; /* initial shared context */ context->attribs = memdup_attribs( attribs ); + if (is_win64 && is_wow64()) + { + if (share_ctx) + { + context->buffers = share_ctx->buffers; + context->buffers->ref++; + } + else if (!(context->buffers = malloc( sizeof(*context->buffers )))) + { + free_context( context ); + return 0; + } + else + { + context->buffers->ref = 1; + rb_init( &context->buffers->map, compare_buffer_name ); + } + } if (!(funcs->p_wgl_context_reset( &context->base, hdc, share_ctx ? &share_ctx->base : NULL, attribs ))) free_context( context ); else if (!(ret = alloc_handle( HANDLE_CONTEXT, funcs, context ))) { @@ -2016,16 +2075,6 @@ static GLint get_buffer_param( TEB *teb, GLenum target, GLenum param ) return size; }
-static void *get_buffer_pointer( TEB *teb, GLenum target ) -{ - const struct opengl_funcs *funcs = teb->glTable; - typeof(*funcs->p_glGetBufferPointerv) *func; - void *ptr = NULL; - if (!(func = funcs->p_glGetBufferPointerv)) func = (void *)funcs->p_wglGetProcAddress( "glGetBufferPointerv" ); - if (func) func( target, GL_BUFFER_MAP_POINTER, &ptr ); - return ptr; -} - static GLint get_named_buffer_param( TEB *teb, GLint buffer, GLenum param ) { const struct opengl_funcs *funcs = teb->glTable; @@ -2036,16 +2085,6 @@ static GLint get_named_buffer_param( TEB *teb, GLint buffer, GLenum param ) return size; }
-static void *get_named_buffer_pointer( TEB *teb, GLint buffer ) -{ - const struct opengl_funcs *funcs = teb->glTable; - typeof(*funcs->p_glGetNamedBufferPointerv) *func; - void *ptr = NULL; - if (!(func = funcs->p_glGetNamedBufferPointerv)) func = (void *)funcs->p_wglGetProcAddress( "glGetNamedBufferPointerv" ); - if (func) func( buffer, GL_BUFFER_MAP_POINTER, &ptr ); - return ptr; -} - static void unmap_buffer( TEB *teb, GLenum target ) { const struct opengl_funcs *funcs = teb->glTable; @@ -2062,45 +2101,127 @@ static void unmap_named_buffer( TEB *teb, GLint buffer ) if (func) func( buffer ); }
-static PTR32 wow64_map_buffer( TEB *teb, GLuint name, GLenum target, void *ptr, SIZE_T size, - GLbitfield access, PTR32 *client_ptr ) +static GLuint get_target_name( TEB *teb, GLenum target ) +{ + const struct opengl_funcs *funcs = teb->glTable; + GLenum binding_name; + GLint name = 0; + + switch (target) + { + case GL_ARRAY_BUFFER: binding_name = GL_ARRAY_BUFFER_BINDING; break; + case GL_ATOMIC_COUNTER_BUFFER: binding_name = GL_ATOMIC_COUNTER_BUFFER_BINDING; break; + case GL_COPY_READ_BUFFER: binding_name = GL_COPY_READ_BUFFER_BINDING; break; + case GL_COPY_WRITE_BUFFER: binding_name = GL_COPY_WRITE_BUFFER_BINDING; break; + case GL_DISPATCH_INDIRECT_BUFFER: binding_name = GL_DISPATCH_INDIRECT_BUFFER_BINDING; break; + case GL_DRAW_INDIRECT_BUFFER: binding_name = GL_DRAW_INDIRECT_BUFFER_BINDING; break; + case GL_ELEMENT_ARRAY_BUFFER: binding_name = GL_ELEMENT_ARRAY_BUFFER_BINDING; break; + case GL_PIXEL_PACK_BUFFER: binding_name = GL_PIXEL_PACK_BUFFER_BINDING; break; + case GL_PIXEL_UNPACK_BUFFER: binding_name = GL_PIXEL_UNPACK_BUFFER_BINDING; break; + case GL_QUERY_BUFFER: binding_name = GL_QUERY_BUFFER_BINDING; break; + case GL_SHADER_STORAGE_BUFFER: binding_name = GL_SHADER_STORAGE_BUFFER_BINDING; break; + case GL_TEXTURE_BUFFER: binding_name = GL_TEXTURE_BUFFER_BINDING; break; + case GL_TRANSFORM_FEEDBACK_BUFFER: binding_name = GL_TRANSFORM_FEEDBACK_BUFFER_BINDING; break; + case GL_UNIFORM_BUFFER: binding_name = GL_UNIFORM_BUFFER_BINDING; break; + default: + FIXME( "unknown target %x\n", target ); + return 0; + }; + + funcs->p_glGetIntegerv( binding_name, &name ); + return name; +} + +static struct buffer *get_named_buffer( TEB *teb, GLuint name ) +{ + struct context *ctx = get_current_context( teb, NULL, NULL ); + struct rb_entry *entry; + + if (ctx && (entry = rb_get( &ctx->buffers->map, &name ))) + return RB_ENTRY_VALUE( entry, struct buffer, entry ); + return NULL; +} + +void invalidate_buffer_name( TEB *teb, GLuint name ) { - static unsigned int once; + struct buffer *buffer = get_named_buffer( teb, name ); + struct context *ctx; + + if (!buffer || !(ctx = get_current_context( teb, NULL, NULL ))) return; + rb_remove( &ctx->buffers->map, &buffer->entry ); + free( buffer ); +} + +void invalidate_buffer_target( TEB *teb, GLenum target ) +{ + GLuint name = get_target_name( teb, target ); + if (name) invalidate_buffer_name( teb, name ); +} + +static struct buffer *get_target_buffer( TEB *teb, GLenum target ) +{ + GLuint name = get_target_name( teb, target ); + return name ? get_named_buffer( teb, name ) : NULL; +} + +static PTR32 wow64_map_buffer( TEB *teb, GLenum target, GLuint name, GLintptr offset, + size_t length, GLbitfield access, void *ptr, PTR32 *client_ptr ) +{ + struct buffer *buffer = get_target_buffer( teb, target ); + + if (!ptr && (!*client_ptr || !buffer)) return 0; + + if (!buffer) + { + struct context *ctx = get_current_context( teb, NULL, NULL ); + + if (!(buffer = calloc( 1, sizeof(*buffer) ))) return 0; + buffer->name = name ? name : get_target_name( teb, target ); + buffer->size = name ? get_named_buffer_param( teb, name, GL_BUFFER_SIZE ) : get_buffer_param( teb, target, GL_BUFFER_SIZE ); + rb_put( &ctx->buffers->map, &buffer->name, &buffer->entry ); + TRACE( "allocated buffer %p for %u\n", buffer, buffer->name ); + } + + if (ptr) + { + buffer->host_ptr = ptr; + if (ULongToPtr(PtrToUlong(ptr)) == ptr) /* we're lucky */ + { + buffer->map_ptr = ptr; + TRACE( "returning %p\n", buffer->map_ptr ); + return PtrToUlong( buffer->map_ptr ); + } + } + + if (!offset && !length) length = buffer->size;
if (*client_ptr) /* wow64 pointer provided, map buffer to it */ { - PTR32 ret = *client_ptr; + buffer->map_ptr = UlongToPtr( *client_ptr ); + *client_ptr = 0; + buffer->copy_length = (access & GL_MAP_WRITE_BIT) ? length : 0; if (!(access & (GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT))) { + static int once; if (!once++) FIXME( "Doing a copy of a mapped buffer (expect performance issues)\n" );
- TRACE( "Copying %#zx from buffer at %p to wow64 buffer %p\n", size, ptr, UlongToPtr(*client_ptr) ); - memcpy( UlongToPtr(*client_ptr), ptr, size ); + TRACE( "Copying %#zx from buffer at %p to wow64 buffer %p\n", length, buffer->host_ptr, + buffer->map_ptr ); + memcpy( buffer->map_ptr, buffer->host_ptr, length ); } - - /* save the wow64 pointer in the buffer data, we'll overwrite it on unmap */ - *(PTR32 *)ptr = ret; + TRACE( "returning client buffer %p\n", buffer->map_ptr ); *client_ptr = 0; - return ret; + return PtrToUlong( buffer->map_ptr ); }
- if (ULongToPtr(PtrToUlong(ptr)) == ptr) return PtrToUlong(ptr); /* we're lucky */ if (access & GL_MAP_PERSISTENT_BIT) { FIXME( "GL_MAP_PERSISTENT_BIT not supported!\n" ); goto unmap; }
- if (!size) size = name ? get_named_buffer_param( teb, name, GL_BUFFER_SIZE ) : get_buffer_param( teb, target, GL_BUFFER_SIZE ); - if ((PTR32)size != size) goto unmap; /* overflow */ - if (size < sizeof(PTR32)) - { - FIXME( "Buffer too small for metadata!\n" ); - goto unmap; - } - - *client_ptr = size; + *client_ptr = length; return 0;
unmap: @@ -2124,71 +2245,85 @@ static GLbitfield map_range_flags_from_map_flags( GLenum flags ) } }
-static PTR32 wow64_unmap_buffer( void *ptr, SIZE_T size, GLbitfield access ) +void wow64_glDeleteBuffers( TEB *teb, GLsizei n, const GLuint *buffers ) { - void *wow_ptr; + const struct opengl_funcs *funcs = teb->glTable; + GLsizei i;
- if (ULongToPtr(PtrToUlong(ptr)) == ptr) return 0; /* we're lucky */ + pthread_mutex_lock( &wgl_lock );
- wow_ptr = UlongToPtr(*(PTR32 *)ptr); - if (access & GL_MAP_WRITE_BIT) - { - TRACE( "Copying %#zx from wow64 buffer %p to buffer %p\n", size, wow_ptr, ptr ); - memcpy( ptr, wow_ptr, size ); - } + funcs->p_glDeleteBuffers( n, buffers ); + for (i = 0; i < n; i++) invalidate_buffer_name( teb, buffers[i] );
- return PtrToUlong( wow_ptr ); + pthread_mutex_unlock( &wgl_lock ); }
-static void wow64_gl_get_buffer_pointer_v( GLenum pname, PTR32 *ptr, PTR32 *wow_ptr ) +static BOOL wow64_gl_get_buffer_pointer_v( TEB *teb, GLenum target, GLuint name, GLenum pname, PTR32 *wow_ptr ) { - if (pname != GL_BUFFER_MAP_POINTER) return; - if (ULongToPtr(*wow_ptr = PtrToUlong(ptr)) == ptr) return; /* we're lucky */ - *wow_ptr = ptr[0]; + struct buffer *buffer; + BOOL ret = FALSE; + + if (pname != GL_BUFFER_MAP_POINTER) return FALSE; + + pthread_mutex_lock( &wgl_lock ); + buffer = name ? get_named_buffer( teb, name ) : get_target_buffer( teb, target ); + if (buffer) + { + *wow_ptr = PtrToUlong( buffer->map_ptr ); + ret = TRUE; + } + pthread_mutex_unlock( &wgl_lock ); + return ret; }
void wow64_glGetBufferPointerv( TEB *teb, GLenum target, GLenum pname, PTR32 *params ) { const struct opengl_funcs *funcs = teb->glTable; void *ptr; + if (wow64_gl_get_buffer_pointer_v( teb, target, 0, pname, params )) return; funcs->p_glGetBufferPointerv( target, pname, &ptr ); - return wow64_gl_get_buffer_pointer_v( pname, ptr, params ); + *params = PtrToUlong(ptr); }
void wow64_glGetBufferPointervARB( TEB *teb, GLenum target, GLenum pname, PTR32 *params ) { const struct opengl_funcs *funcs = teb->glTable; void *ptr; - funcs->p_glGetBufferPointervARB( target, pname, &ptr ); - return wow64_gl_get_buffer_pointer_v( pname, ptr, params ); + if (wow64_gl_get_buffer_pointer_v( teb, target, 0, pname, params )) return; + funcs->p_glGetBufferPointerv( target, pname, &ptr ); + *params = PtrToUlong(ptr); }
void wow64_glGetNamedBufferPointerv( TEB *teb, GLuint buffer, GLenum pname, PTR32 *params ) { const struct opengl_funcs *funcs = teb->glTable; void *ptr; + if (buffer && wow64_gl_get_buffer_pointer_v( teb, 0, buffer, pname, params )) return; funcs->p_glGetNamedBufferPointerv( buffer, pname, &ptr ); - return wow64_gl_get_buffer_pointer_v( pname, ptr, params ); + *params = PtrToUlong(ptr); }
void wow64_glGetNamedBufferPointervEXT( TEB *teb, GLuint buffer, GLenum pname, PTR32 *params ) { const struct opengl_funcs *funcs = teb->glTable; void *ptr; + if (buffer && wow64_gl_get_buffer_pointer_v( teb, 0, buffer, pname, params )) return; funcs->p_glGetNamedBufferPointervEXT( buffer, pname, &ptr ); - return wow64_gl_get_buffer_pointer_v( pname, ptr, params ); + *params = PtrToUlong(ptr); }
static PTR32 wow64_gl_map_buffer( TEB *teb, GLenum target, GLenum access, PTR32 *client_ptr, PFN_glMapBuffer gl_map_buffer64 ) { GLbitfield range_access = map_range_flags_from_map_flags( access ); - void *ptr; - - /* if *ret, we're being called again with a wow64 pointer */ - ptr = *client_ptr ? get_buffer_pointer( teb, target ) : gl_map_buffer64( target, access ); + void *ptr = NULL; + PTR32 ret ;
- return wow64_map_buffer( teb, 0, target, ptr, 0, range_access, client_ptr ); + pthread_mutex_lock( &wgl_lock ); + if (!*client_ptr) ptr = gl_map_buffer64( target, access ); + ret = wow64_map_buffer( teb, target, 0, 0, 0, range_access, ptr, client_ptr ); + pthread_mutex_unlock( &wgl_lock ); + return ret; }
PTR32 wow64_glMapBuffer( TEB *teb, GLenum target, GLenum access, PTR32 *client_ptr ) @@ -2206,26 +2341,28 @@ PTR32 wow64_glMapBufferARB( TEB *teb, GLenum target, GLenum access, PTR32 *clien PTR32 wow64_glMapBufferRange( TEB *teb, GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access, PTR32 *client_ptr ) { const struct opengl_funcs *funcs = teb->glTable; - void *ptr; - - /* already mapped, we're being called again with a wow64 pointer */ - if (*client_ptr) ptr = (char *)get_buffer_pointer( teb, target ); - else ptr = funcs->p_glMapBufferRange( target, offset, length, access ); + void *ptr = NULL; + PTR32 ret;
- return wow64_map_buffer( teb, 0, target, ptr, length, access, client_ptr ); + pthread_mutex_lock( &wgl_lock ); + if (!*client_ptr) ptr = funcs->p_glMapBufferRange( target, offset, length, access ); + ret = wow64_map_buffer( teb, target, 0, offset, length, access, ptr, client_ptr ); + pthread_mutex_unlock( &wgl_lock ); + return ret; }
-static PTR32 wow64_gl_map_named_buffer( TEB *teb, GLuint buffer, GLenum access, PTR32 *client_ptr, +static PTR32 wow64_gl_map_named_buffer( TEB *teb, GLuint name, GLenum access, PTR32 *client_ptr, PFN_glMapNamedBuffer gl_map_named_buffer64 ) { GLbitfield range_access = map_range_flags_from_map_flags( access ); - void *ptr; - - /* already mapped, we're being called again with a wow64 pointer */ - if (*client_ptr) ptr = get_named_buffer_pointer( teb, buffer ); - else ptr = gl_map_named_buffer64( buffer, access ); + void *ptr = NULL; + PTR32 ret;
- return wow64_map_buffer( teb, buffer, 0, ptr, 0, range_access, client_ptr ); + pthread_mutex_lock( &wgl_lock ); + if (!*client_ptr) ptr = gl_map_named_buffer64( name, access ); + ret = wow64_map_buffer( teb, 0, name, 0, 0, range_access, ptr, client_ptr ); + pthread_mutex_unlock( &wgl_lock ); + return ret; }
PTR32 wow64_glMapNamedBuffer( TEB *teb, GLuint buffer, GLenum access, PTR32 *client_ptr ) @@ -2240,16 +2377,17 @@ PTR32 wow64_glMapNamedBufferEXT( TEB *teb, GLuint buffer, GLenum access, PTR32 * return wow64_gl_map_named_buffer( teb, buffer, access, client_ptr, funcs->p_glMapNamedBufferEXT ); }
-static NTSTATUS wow64_gl_map_named_buffer_range( TEB *teb, GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access, +static NTSTATUS wow64_gl_map_named_buffer_range( TEB *teb, GLuint name, GLintptr offset, GLsizeiptr length, GLbitfield access, PTR32 *client_ptr, PFN_glMapNamedBufferRange gl_map_named_buffer_range64 ) { - void *ptr; - - /* already mapped, we're being called again with a wow64 pointer */ - if (*client_ptr) ptr = get_named_buffer_pointer( teb, buffer ); - else ptr = gl_map_named_buffer_range64( buffer, offset, length, access ); + void *ptr = NULL; + PTR32 ret;
- return wow64_map_buffer( teb, buffer, 0, ptr, length, access, client_ptr ); + pthread_mutex_lock( &wgl_lock ); + if (!*client_ptr) ptr = gl_map_named_buffer_range64( name, offset, length, access ); + ret = wow64_map_buffer( teb, 0, name, offset, length, access, ptr, client_ptr ); + pthread_mutex_unlock( &wgl_lock ); + return ret; }
PTR32 wow64_glMapNamedBufferRange( TEB *teb, GLuint buffer, GLintptr offset, GLsizeiptr length, GLbitfield access, PTR32 *client_ptr ) @@ -2264,50 +2402,70 @@ PTR32 wow64_glMapNamedBufferRangeEXT( TEB *teb, GLuint buffer, GLintptr offset, return wow64_gl_map_named_buffer_range( teb, buffer, offset, length, access, client_ptr, funcs->p_glMapNamedBufferRangeEXT ); }
-static PTR32 wow64_unmap_client_buffer( TEB *teb, GLenum target ) +static void wow64_unmap_buffer( struct buffer *buffer, PTR32 *client_ptr ) +{ + if (!buffer->host_ptr) return; + + if (buffer->host_ptr != buffer->map_ptr) + { + if (buffer->copy_length) + { + TRACE( "Copying %#zx from wow64 buffer %p to buffer %p\n", buffer->copy_length, + buffer->map_ptr, buffer->host_ptr ); + memcpy( buffer->host_ptr, buffer->map_ptr, buffer->copy_length ); + } + *client_ptr = PtrToUlong( buffer->map_ptr ); + } + + buffer->host_ptr = buffer->map_ptr = NULL; +} + +static GLboolean wow64_unmap_target_buffer( TEB *teb, GLenum target, PTR32 *client_ptr, PFN_glUnmapBuffer gl_unmap ) { - PTR32 *ptr; + struct buffer *buffer; + GLboolean ret;
- if (!(ptr = get_buffer_pointer( teb, target ))) return 0; - return wow64_unmap_buffer( ptr, get_buffer_param( teb, target, GL_BUFFER_MAP_LENGTH ), - get_buffer_param( teb, target, GL_BUFFER_ACCESS_FLAGS ) ); + pthread_mutex_lock( &wgl_lock ); + if ((buffer = get_target_buffer( teb, target ))) wow64_unmap_buffer( buffer, client_ptr ); + ret = gl_unmap( target ); + pthread_mutex_unlock( &wgl_lock ); + return ret; }
GLboolean wow64_glUnmapBuffer( TEB *teb, GLenum target, PTR32 *client_ptr ) { const struct opengl_funcs *funcs = teb->glTable; - *client_ptr = wow64_unmap_client_buffer( teb, target ); - return funcs->p_glUnmapBuffer( target ); + return wow64_unmap_target_buffer( teb, target, client_ptr, funcs->p_glUnmapBuffer ); }
GLboolean wow64_glUnmapBufferARB( TEB *teb, GLenum target, PTR32 *client_ptr ) { const struct opengl_funcs *funcs = teb->glTable; - *client_ptr = wow64_unmap_client_buffer( teb, target ); - return funcs->p_glUnmapBuffer( target ); + return wow64_unmap_target_buffer( teb, target, client_ptr, funcs->p_glUnmapBufferARB ); }
-static PTR32 wow64_gl_unmap_named_buffer( TEB *teb, GLuint buffer ) +static GLboolean wow64_gl_unmap_named_buffer( TEB *teb, GLuint name, PTR32 *client_ptr, PFN_glUnmapBuffer gl_unmap ) { - PTR32 *ptr; + struct buffer *buffer; + GLboolean ret;
- if (!(ptr = get_named_buffer_pointer( teb, buffer ))) return 0; - return wow64_unmap_buffer( ptr, get_named_buffer_param( teb, buffer, GL_BUFFER_MAP_LENGTH ), - get_named_buffer_param( teb, buffer, GL_BUFFER_ACCESS_FLAGS ) ); + pthread_mutex_lock( &wgl_lock ); + if ((buffer = get_named_buffer( teb, name ))) wow64_unmap_buffer( buffer, client_ptr ); + ret = gl_unmap( name ); + pthread_mutex_unlock( &wgl_lock ); + return ret; }
GLboolean wow64_glUnmapNamedBuffer( TEB *teb, GLuint buffer, PTR32 *client_ptr ) { const struct opengl_funcs *funcs = teb->glTable; - *client_ptr = wow64_gl_unmap_named_buffer( teb, buffer ); - return funcs->p_glUnmapNamedBuffer( buffer ); + return wow64_gl_unmap_named_buffer( teb, buffer, client_ptr, funcs->p_glUnmapNamedBuffer ); }
GLboolean wow64_glUnmapNamedBufferEXT( TEB *teb, GLuint buffer, PTR32 *client_ptr ) { const struct opengl_funcs *funcs = teb->glTable; - *client_ptr = wow64_gl_unmap_named_buffer( teb, buffer ); - return funcs->p_glUnmapNamedBufferEXT( buffer ); + return wow64_gl_unmap_named_buffer( teb, buffer, client_ptr, funcs->p_glUnmapNamedBufferEXT ); }
NTSTATUS wow64_thread_attach( void *args )
What is the glImportMemoryFdEXT solution, implementing a suballocator?
On Sun Sep 7 13:55:21 2025 +0000, Derek Lesho wrote:
What is the glImportMemoryFdEXT solution, implementing a suballocator?
We could create a memory object with Vulkan, import it into GL, and then handle map, unmap, and flush via Vulkan. That would be very invasive for arbitrary buffer objects, but for buffer storage objects, where the caller specifies the intention to map at creation time, it doesn’t seem too bad and is enough to support persistent mappings. In my testing, that alone brings the wined3d GL renderer performance on par with old wow64. Other usage patterns might benefit from a suballocator, but for the experiment I just created separate fds for each GL buffer storage.
On Sun Sep 7 13:55:21 2025 +0000, Jacek Caban wrote:
We could create a memory object with Vulkan, import it into GL, and then handle map, unmap, and flush via Vulkan. That would be very invasive for arbitrary buffer objects, but for buffer storage objects, where the caller specifies the intention to map at creation time, it doesn’t seem too bad and is enough to support persistent mappings. In my testing, that alone brings the wined3d GL renderer performance on par with old wow64. Other usage patterns might benefit from a suballocator, but for the experiment I just created separate fds for each GL buffer storage.
Well, wined3d does its own suballocation. That's not true for arbitrary GL applications, though. I'm not saying we shouldn't commit such an approach, but we really should still be spending time on trying to get a generic extension.