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;
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- The failing case is similar to the previous patch but now getting GL drawable in winex11.drv faile due to WindowFromDC() fails through GetDCHook() which can't get_dc_ptr() on the context. Also, SetHookFlags() is already using get_dc_obj() so maybe doing the same in SetDCHook() and GetDCHook() makes sense regardless.
dlls/win32u/dc.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/dlls/win32u/dc.c b/dlls/win32u/dc.c index 9c09bf66e03..cb38c4161ee 100644 --- a/dlls/win32u/dc.c +++ b/dlls/win32u/dc.c @@ -1007,13 +1007,18 @@ BOOL WINAPI NtGdiGetTransform( HDC hdc, DWORD which, XFORM *xform ) */ BOOL WINAPI SetDCHook( HDC hdc, DCHOOKPROC hookProc, DWORD_PTR dwHookData ) { - DC *dc = get_dc_ptr( hdc ); + DC *dc = get_dc_obj( hdc );
if (!dc) return FALSE; + if (dc->attr->disabled) + { + GDI_ReleaseObj( hdc ); + return 0; + }
dc->dwHookData = dwHookData; dc->hookProc = hookProc; - release_dc_ptr( dc ); + GDI_ReleaseObj( hdc ); return TRUE; }
@@ -1025,13 +1030,18 @@ BOOL WINAPI SetDCHook( HDC hdc, DCHOOKPROC hookProc, DWORD_PTR dwHookData ) */ DWORD_PTR WINAPI GetDCHook( HDC hdc, DCHOOKPROC *proc ) { - DC *dc = get_dc_ptr( hdc ); + DC *dc = get_dc_obj( hdc ); DWORD_PTR ret;
if (!dc) return 0; + if (dc->attr->disabled) + { + GDI_ReleaseObj( hdc ); + return 0; + } if (proc) *proc = dc->hookProc; ret = dc->dwHookData; - release_dc_ptr( dc ); + GDI_ReleaseObj( hdc ); return ret; }
Signed-off-by: Huw Davies huw@codeweavers.com