Signed-off-by: Paul Gofman pgofman@codeweavers.com --- Runescape calls GL functions (SwapBuffers, glFinish) from different threads. That mostly goes well except for when the DC is locked by ExtEscape() and the other thread calls, e. g., SwapBuffers that fails because GL can't get driver funcs (get_dc_ptr() in__wine_get_wgl_driver() returns NULL as the DC is locked by the other thread).
I don't see any reason why getting GL funcs should fail in this case. Caching gl_funcs and using them with get_dc_obj() locking solves this type of race.
dlls/win32u/dc.c | 19 ------------------- dlls/win32u/driver.c | 20 ++++++++++++-------- dlls/win32u/ntgdi_private.h | 21 +++++++++++++++++++++ 3 files changed, 33 insertions(+), 27 deletions(-)
diff --git a/dlls/win32u/dc.c b/dlls/win32u/dc.c index 3aae73779e9..9c09bf66e03 100644 --- a/dlls/win32u/dc.c +++ b/dlls/win32u/dc.c @@ -63,25 +63,6 @@ static const struct gdi_obj_funcs dc_funcs = };
-static inline DC *get_dc_obj( HDC hdc ) -{ - DWORD type; - DC *dc = get_any_obj_ptr( hdc, &type ); - if (!dc) return NULL; - - switch (type) - { - case NTGDI_OBJ_DC: - case NTGDI_OBJ_MEMDC: - case NTGDI_OBJ_ENHMETADC: - return dc; - default: - GDI_ReleaseObj( hdc ); - SetLastError( ERROR_INVALID_HANDLE ); - return NULL; - } -} - /* alloc DC_ATTR from a pool of memory accessible from client */ static DC_ATTR *alloc_dc_attr(void) { diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index 39996086c6d..233427b0964 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -1347,14 +1347,18 @@ NTSTATUS WINAPI NtGdiDdDDICheckVidPnExclusiveOwnership( const D3DKMT_CHECKVIDPNE */ struct opengl_funcs * CDECL __wine_get_wgl_driver( HDC hdc, UINT version ) { - struct opengl_funcs *ret = NULL; - DC * dc = get_dc_ptr( hdc ); + struct opengl_funcs *ret; + PHYSDEV physdev; + DC * dc;
- if (dc) - { - PHYSDEV physdev = GET_DC_PHYSDEV( dc, wine_get_wgl_driver ); - ret = physdev->funcs->wine_get_wgl_driver( physdev, version ); - release_dc_ptr( dc ); - } + if (!(dc = get_dc_obj( hdc ))) return NULL; + ret = dc->gl_funcs; + GDI_ReleaseObj( hdc ); + if (ret) return ret; + + if (!(dc = get_dc_ptr( hdc ))) return NULL; + physdev = GET_DC_PHYSDEV( dc, wine_get_wgl_driver ); + dc->gl_funcs = ret = physdev->funcs->wine_get_wgl_driver( physdev, version ); + release_dc_ptr( dc ); return ret; } diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index bfeb4557da7..54a4dc17eaf 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -87,6 +87,8 @@ typedef struct tagDC XFORM xformVport2World; /* Inverse of the above transformation */ BOOL vport2WorldValid; /* Is xformVport2World valid? */ RECT bounds; /* Current bounding rect */ + + struct opengl_funcs *gl_funcs; /* Opengl driver functions */ } DC;
/* Certain functions will do no further processing if the driver returns this. @@ -660,6 +662,25 @@ static inline void copy_bitmapinfo( BITMAPINFO *dst, const BITMAPINFO *src ) memcpy( dst, src, get_dib_info_size( src, DIB_RGB_COLORS )); }
+static inline DC *get_dc_obj( HDC hdc ) +{ + DWORD type; + DC *dc = get_any_obj_ptr( hdc, &type ); + if (!dc) return NULL; + + switch (type) + { + case NTGDI_OBJ_DC: + case NTGDI_OBJ_MEMDC: + case NTGDI_OBJ_ENHMETADC: + return dc; + default: + GDI_ReleaseObj( hdc ); + SetLastError( ERROR_INVALID_HANDLE ); + return NULL; + } +} + extern void CDECL free_heap_bits( struct gdi_image_bits *bits ) DECLSPEC_HIDDEN;
void set_gdi_client_ptr( HGDIOBJ handle, void *ptr ) DECLSPEC_HIDDEN;