From: Rémi Bernon <rbernon@codeweavers.com> This also requires to explicitly destroy objects when display lists are destroyed. --- dlls/opengl32/tests/opengl.c | 20 +++++++++---------- dlls/opengl32/unix_wgl.c | 4 ++-- dlls/opengl32/wgl.c | 31 ++++++++++++++++++++++++++++-- dlls/win32u/opengl.c | 37 +++++++++++++++++++++++++----------- include/wine/opengl_driver.h | 4 ++-- 5 files changed, 68 insertions(+), 28 deletions(-) diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c index f4809b9e915..89d6d072f48 100644 --- a/dlls/opengl32/tests/opengl.c +++ b/dlls/opengl32/tests/opengl.c @@ -1982,7 +1982,7 @@ static void test_sharelists(HDC winhdc) ok_ret( TRUE, wglShareLists( ctx1, ctx3 ) ); ok_ret( GL_NO_ERROR, glGetError() ); /* object 1 is now valid there as well */ - todo_wine ok_ret( TRUE, test->exists( obj1 ) ); + ok_ret( TRUE, test->exists( obj1 ) ); ok_ret( GL_NO_ERROR, glGetError() ); /* object 1 is still valid in ctx2 */ @@ -2052,21 +2052,19 @@ static void test_sharelists(HDC winhdc) ok_u4( obj3, ==, 3 ); ok_ret( TRUE, wglMakeCurrent( winhdc, ctx3 ) ); ok_ret( GL_NO_ERROR, glGetError() ); - todo_wine ok_ret( TRUE, test->exists( obj1 ) ); + ok_ret( TRUE, test->exists( obj1 ) ); ok_ret( GL_NO_ERROR, glGetError() ); ok_ret( FALSE, test->exists( obj2 ) ); ok_ret( GL_NO_ERROR, glGetError() ); - todo_wine ok_ret( TRUE, test->exists( obj3 ) ); + ok_ret( TRUE, test->exists( obj3 ) ); ok_ret( GL_NO_ERROR, glGetError() ); /* test deleting objects in shared contexts */ delete_object( test->type, obj1 ); - todo_wine_if( test->type == OBJ_PROGRAM_OBJECT || test->type == OBJ_PROGRAM_OBJECT_ARB || - test->type == OBJ_SHADER_OBJECT || test->type == OBJ_SHADER_OBJECT_ARB ) ok_ret( GL_NO_ERROR, glGetError() ); ok_ret( TRUE, wglMakeCurrent( winhdc, ctx2 ) ); ok_ret( GL_NO_ERROR, glGetError() ); - todo_wine_if( i >= 14 ) ok_ret( FALSE, test->exists( obj1 ) ); + ok_ret( FALSE, test->exists( obj1 ) ); ok_ret( GL_NO_ERROR, glGetError() ); ok_ret( FALSE, test->exists( obj2 ) ); ok_ret( GL_NO_ERROR, glGetError() ); @@ -2077,7 +2075,7 @@ static void test_sharelists(HDC winhdc) ok_ret( TRUE, wglDeleteContext( ctx3 ) ); /* objects are still valid after shared context destruction */ - todo_wine_if( i >= 14 ) ok_ret( FALSE, test->exists( obj1 ) ); + ok_ret( FALSE, test->exists( obj1 ) ); ok_ret( GL_NO_ERROR, glGetError() ); ok_ret( FALSE, test->exists( obj2 ) ); ok_ret( GL_NO_ERROR, glGetError() ); @@ -2138,7 +2136,7 @@ static void test_sharelists(HDC winhdc) ok_ret( TRUE, wglShareLists( ctx1, ctx3 ) ); ok_ret( GL_NO_ERROR, glGetError() ); /* object 1 is now valid there as well */ - todo_wine ok_ret( TRUE, ext.glIsSync( obj1 ) ); + ok_ret( TRUE, ext.glIsSync( obj1 ) ); ok_ret( GL_NO_ERROR, glGetError() ); /* object 1 is still valid in ctx2 */ @@ -2211,16 +2209,16 @@ static void test_sharelists(HDC winhdc) todo_wine ok_ptr( obj3, ==, (GLsync)3 ); ok_ret( TRUE, wglMakeCurrent( winhdc, ctx3 ) ); ok_ret( GL_NO_ERROR, glGetError() ); - todo_wine ok_ret( TRUE, ext.glIsSync( obj1 ) ); + ok_ret( TRUE, ext.glIsSync( obj1 ) ); ok_ret( GL_NO_ERROR, glGetError() ); ok_ret( FALSE, ext.glIsSync( obj2 ) ); ok_ret( GL_NO_ERROR, glGetError() ); - todo_wine ok_ret( TRUE, ext.glIsSync( obj3 ) ); + ok_ret( TRUE, ext.glIsSync( obj3 ) ); ok_ret( GL_NO_ERROR, glGetError() ); /* test deleting objects in shared contexts */ ext.glDeleteSync( obj1 ); - todo_wine ok_ret( GL_NO_ERROR, glGetError() ); + ok_ret( GL_NO_ERROR, glGetError() ); ok_ret( TRUE, wglMakeCurrent( winhdc, ctx2 ) ); ok_ret( GL_NO_ERROR, glGetError() ); ok_ret( FALSE, ext.glIsSync( obj1 ) ); diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c index fcaa5345c2d..c1a21c58245 100644 --- a/dlls/opengl32/unix_wgl.c +++ b/dlls/opengl32/unix_wgl.c @@ -439,7 +439,7 @@ static struct context *update_context( TEB *teb, HGLRC client_context, struct co if (ctx->share == (HGLRC)-1) return ctx; /* not re-shared */ share = ctx->share ? get_updated_context( teb, ctx->share ) : NULL; - if (!funcs->p_context_reset( &ctx->base, share ? &share->base : NULL, ctx->attribs )) + if (!funcs->p_context_reset( &ctx->base, ctx->attribs )) { WARN( "Failed to re-create context for wglShareLists\n" ); return ctx; @@ -1350,7 +1350,7 @@ HGLRC wrap_wglCreateContextAttribsARB( TEB *teb, HDC hdc, HGLRC client_shared, c } } - if (!(funcs->p_context_create( &context->base, hdc, shared ? &shared->base : NULL, attribs ))) + if (!(funcs->p_context_create( &context->base, hdc, attribs ))) { free_context( context ); return 0; diff --git a/dlls/opengl32/wgl.c b/dlls/opengl32/wgl.c index 667d555069e..a66400c23f1 100644 --- a/dlls/opengl32/wgl.c +++ b/dlls/opengl32/wgl.c @@ -418,18 +418,41 @@ static GLuint create_object( enum object_type type ) return 0; } +static void destroy_object( enum object_type type, GLuint object ) +{ + switch (type) + { + case OBJ_TYPE_BUFFER: { MAKE_OBJECT_CALL( glDeleteBuffers, .n = 1, .buffers = &object ); return; } + case OBJ_TYPE_DISPLAY_LIST: { MAKE_OBJECT_CALL( glDeleteLists, .range = 1, .list = object ); return; } + case OBJ_TYPE_FRAMEBUFFER: { MAKE_OBJECT_CALL( glDeleteFramebuffers, .n = 1, .framebuffers = &object ); return; } + case OBJ_TYPE_MEMORY: { MAKE_OBJECT_CALL( glDeleteMemoryObjectsEXT, .n = 1, .memoryObjects = &object ); return; } + case OBJ_TYPE_PATH: { MAKE_OBJECT_CALL( glDeletePathsNV, .range = 1, .path = object ); return; } + case OBJ_TYPE_PROGRAM: { MAKE_OBJECT_CALL( glDeleteProgramsARB, .n = 1, .programs = &object ); return; } + case OBJ_TYPE_RENDERBUFFER: { MAKE_OBJECT_CALL( glDeleteRenderbuffers, .n = 1, .renderbuffers = &object ); return; } + case OBJ_TYPE_SAMPLER: { MAKE_OBJECT_CALL( glDeleteSamplers, .count = 1, .samplers = &object ); return; } + case OBJ_TYPE_SEMAPHORE: { MAKE_OBJECT_CALL( glDeleteSemaphoresEXT, .n = 1, .semaphores = &object ); return; } + case OBJ_TYPE_SHADER: { MAKE_OBJECT_CALL( glDeleteObjectARB, .obj = object ); return; } + case OBJ_TYPE_SHADER_ATI: { MAKE_OBJECT_CALL( glDeleteFragmentShaderATI, .id = object ); return; } + case OBJ_TYPE_SHADER_EXT: { MAKE_OBJECT_CALL( glDeleteVertexShaderEXT, .id = object ); return; } + case OBJ_TYPE_TEXTURE: { MAKE_OBJECT_CALL( glDeleteTextures, .n = 1, .textures = &object ); return; } + case OBJ_TYPE_COUNT: return; + } +} + #undef MAKE_OBJECT_CALL static void destroy_host_object( struct object_table *table, GLuint host_id, GLuint client_id ) { - WARN( "Leaking %s client %#x, host %#x\n", debugstr_object_type( table->type ), client_id, host_id ); + WARN( "Destroying %s client %#x, host %#x\n", debugstr_object_type( table->type ), client_id, host_id ); + destroy_object( table->type, host_id ); } static void destroy_host_shader( struct object_table *table, GLuint host_id, GLuint client_id ) { GLuint *object; if (!(object = find_object_id( table->client_ids, host_id )) || !(client_id = *object)) return; - WARN( "Leaking %s client %#x, host %#x\n", debugstr_object_type( table->type ), client_id, host_id ); + WARN( "Destroying %s client %#x, host %#x\n", debugstr_object_type( table->type ), client_id, host_id ); + destroy_object( table->type, host_id ); } static void free_object_table( struct object_table *table ) @@ -475,6 +498,8 @@ static struct display_lists *display_lists_acquire( struct display_lists *lists static void display_lists_release( struct display_lists *lists ) { + struct glDeleteSync_params delete_sync = { .teb = NtCurrentTeb() }; + if (InterlockedDecrement( &lists->refcount )) return; for (UINT i = 0; i < OBJ_TYPE_COUNT; i++) @@ -485,6 +510,8 @@ static void display_lists_release( struct display_lists *lists ) struct handle_entry *entry = lists->syncs.handles + i; if (LOWORD(entry->handle) == 0xffff) continue; WARN( "Leaking sync client %#x, host %p\n", entry->handle, entry->user_data ); + delete_sync.sync = entry->user_data; + UNIX_CALL( glDeleteSync, &delete_sync ); free( entry->user_data ); } diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c index bb4b7c93e48..feaad7ffda9 100644 --- a/dlls/win32u/opengl.c +++ b/dlls/win32u/opengl.c @@ -77,6 +77,7 @@ static const struct opengl_driver_funcs nulldrv_funcs, *driver_funcs = &nulldrv_ static struct list devices_egl = LIST_INIT( devices_egl ); static struct egl_platform display_egl; static struct opengl_funcs display_funcs; +static void *global_context; static BOOLEAN global_extensions[GL_EXTENSION_COUNT]; static struct wgl_pixel_format *pixel_formats; @@ -215,7 +216,7 @@ static BOOL make_null_context_current(void) } if (format > formats_count) return FALSE; - driver_funcs->p_context_create( format, NULL, NULL, &data->null_context ); + driver_funcs->p_context_create( format, global_context, NULL, &data->null_context ); if (driver_funcs->p_null_surface_create) driver_funcs->p_null_surface_create( format, &data->null_surface ); } @@ -1238,6 +1239,11 @@ static void init_device_info( struct egl_platform *egl, const struct opengl_func TRACE( " - device_uuid: %s\n", debugstr_guid(&egl->device_uuid) ); TRACE( " - driver_uuid: %s\n", debugstr_guid(&egl->driver_uuid) ); + if (egl == &display_egl) + { + if (core_context) core_context = InterlockedExchangePointer( &global_context, core_context ); + else if (compat_context) compat_context = InterlockedExchangePointer( &global_context, compat_context ); + } if (compat_context) funcs->p_eglDestroyContext( egl->display, compat_context ); if (core_context) funcs->p_eglDestroyContext( egl->display, core_context ); @@ -1923,7 +1929,7 @@ static void push_internal_context( struct opengl_context *context, struct opengl if (!context->internal_context) { - driver_funcs->p_context_create( format, context->driver_private, NULL, &context->internal_context ); + driver_funcs->p_context_create( format, global_context, NULL, &context->internal_context ); if (!context->internal_context) ERR( "Failed to create internal context\n" ); } @@ -2303,12 +2309,11 @@ static int get_window_swap_interval( HWND hwnd ) return interval; } -static BOOL win32u_context_create( struct opengl_context *context, HDC hdc, struct opengl_context *share, const int *attribs ) +static BOOL win32u_context_create( struct opengl_context *context, HDC hdc, const int *attribs ) { - void *share_private = share ? share->driver_private : NULL; int format; - TRACE( "context %p, hdc %p, share %p, attribs %p\n", context, hdc, share, attribs ); + TRACE( "context %p, hdc %p, attribs %p\n", context, hdc, attribs ); if ((format = get_dc_pixel_format( hdc )) <= 0 && (format = get_window_pixel_format( NtUserWindowFromDC( hdc ) )) <= 0) @@ -2317,7 +2322,7 @@ static BOOL win32u_context_create( struct opengl_context *context, HDC hdc, stru else RtlSetLastWin32Error( ERROR_INVALID_HANDLE ); return FALSE; } - if (!driver_funcs->p_context_create( format, share_private, attribs, &context->driver_private )) + if (!driver_funcs->p_context_create( format, global_context, attribs, &context->driver_private )) { WARN( "Failed to create driver context for context %p\n", context ); return FALSE; @@ -2347,14 +2352,12 @@ static BOOL win32u_context_destroy( struct opengl_context *context ) return TRUE; } -static BOOL win32u_context_reset( struct opengl_context *context, struct opengl_context *share, const int *attribs ) +static BOOL win32u_context_reset( struct opengl_context *context, const int *attribs ) { - void *share_private = share ? share->driver_private : NULL; - - TRACE( "context %p, share %p, attribs %p\n", context, share, attribs ); + TRACE( "context %p, attribs %p\n", context, attribs ); if (!win32u_context_destroy( context )) return FALSE; - return driver_funcs->p_context_create( context->format, share_private, attribs, &context->driver_private ); + return driver_funcs->p_context_create( context->format, global_context, attribs, &context->driver_private ); } static BOOL flush_memory_pbuffer( void (*flush)(void) ) @@ -2829,6 +2832,18 @@ static void display_funcs_init(void) LIST_FOR_EACH_ENTRY_SAFE( egl, next, &devices_egl, struct egl_platform, entry ) init_device_info( egl, &display_funcs ); } + + if (!global_context) + { + for (int format = 1; format <= formats_count; format++) + { + struct wgl_pixel_format *desc = pixel_formats + format - 1; + if (!(desc->pfd.dwFlags & PFD_SUPPORT_OPENGL)) continue; + if (desc->pfd.iPixelType != PFD_TYPE_RGBA) continue; + if (desc->pfd.cColorBits < 24) continue; + if (driver_funcs->p_context_create( format, NULL, NULL, &global_context )) break; + } + } } /*********************************************************************** diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h index 79babe18ff3..7c138d37e64 100644 --- a/include/wine/opengl_driver.h +++ b/include/wine/opengl_driver.h @@ -146,9 +146,9 @@ struct opengl_funcs void (*p_get_pixel_formats)( struct wgl_pixel_format *formats, UINT max_formats, UINT *num_formats, UINT *num_onscreen_formats ); BOOL (*p_query_renderer)( UINT attribute, void *value ); BOOL (*p_context_flush)( struct opengl_context *context, void (*flush)(void), UINT flags ); - BOOL (*p_context_create)( struct opengl_context *context, HDC hdc, struct opengl_context *share, const int *attribs ); + BOOL (*p_context_create)( struct opengl_context *context, HDC hdc, const int *attribs ); BOOL (*p_context_destroy)( struct opengl_context *context ); - BOOL (*p_context_reset)( struct opengl_context *context, struct opengl_context *share, const int *attribs ); + BOOL (*p_context_reset)( struct opengl_context *context, const int *attribs ); BOOL (*p_pbuffer_create)( HDC hdc, int format, int width, int height, const int *attribs, HPBUFFERARB client_pbuffer ); void *egl_handle; }; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11161