Fixes a deadlock with display_device_init mutex and display_lock when trying to open the D3DKMT adapter while holding the mutex in the caller.
From: Rémi Bernon rbernon@codeweavers.com
Fixes a deadlock with display_device_init mutex and display_lock when trying to open the D3DKMT adapter while holding the mutex in the caller.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56764 --- dlls/gdi32/Makefile.in | 2 +- dlls/gdi32/objects.c | 78 ++--------------------------------------- dlls/win32u/sysparams.c | 30 ++++++++++++++++ include/ntuser.h | 8 +++++ 4 files changed, 41 insertions(+), 77 deletions(-)
diff --git a/dlls/gdi32/Makefile.in b/dlls/gdi32/Makefile.in index 8c5a299933d..80a5ad0858b 100644 --- a/dlls/gdi32/Makefile.in +++ b/dlls/gdi32/Makefile.in @@ -2,7 +2,7 @@ EXTRADEFS = -D_GDI32_ MODULE = gdi32.dll IMPORTLIB = gdi32 IMPORTS = user32 advapi32 win32u -DELAYIMPORTS = setupapi winspool +DELAYIMPORTS = winspool
SOURCES = \ dc.c \ diff --git a/dlls/gdi32/objects.c b/dlls/gdi32/objects.c index 070ce9c3885..0c7eacae2e5 100644 --- a/dlls/gdi32/objects.c +++ b/dlls/gdi32/objects.c @@ -886,89 +886,15 @@ UINT WINAPI SetDIBColorTable( HDC hdc, UINT start, UINT count, const RGBQUAD *co return NtGdiDoPalette( hdc, start, count, (void *)colors, NtGdiSetDIBColorTable, FALSE ); }
-static HANDLE get_display_device_init_mutex( void ) -{ - HANDLE mutex = CreateMutexW( NULL, FALSE, L"display_device_init" ); - - WaitForSingleObject( mutex, INFINITE ); - return mutex; -} - -static void release_display_device_init_mutex( HANDLE mutex ) -{ - ReleaseMutex( mutex ); - CloseHandle( mutex ); -} - /*********************************************************************** * D3DKMTOpenAdapterFromGdiDisplayName (GDI32.@) */ NTSTATUS WINAPI D3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *desc ) { - WCHAR *end, key_nameW[MAX_PATH], bufferW[MAX_PATH]; - HDEVINFO devinfo = INVALID_HANDLE_VALUE; - NTSTATUS status = STATUS_UNSUCCESSFUL; - D3DKMT_OPENADAPTERFROMLUID luid_desc; - SP_DEVINFO_DATA device_data; - DWORD size, state_flags; - DEVPROPTYPE type; - HANDLE mutex; - int index; - TRACE("(%p)\n", desc);
- if (!desc) - return STATUS_UNSUCCESSFUL; - - TRACE("DeviceName: %s\n", wine_dbgstr_w( desc->DeviceName )); - if (wcsnicmp( desc->DeviceName, L"\\.\DISPLAY", lstrlenW(L"\\.\DISPLAY") )) - return STATUS_UNSUCCESSFUL; - - index = wcstol( desc->DeviceName + lstrlenW(L"\\.\DISPLAY"), &end, 10 ) - 1; - if (*end) - return STATUS_UNSUCCESSFUL; - - /* Get adapter LUID from SetupAPI */ - mutex = get_display_device_init_mutex(); - - size = sizeof( bufferW ); - swprintf( key_nameW, MAX_PATH, L"\Device\Video%d", index ); - if (RegGetValueW( HKEY_LOCAL_MACHINE, L"HARDWARE\DEVICEMAP\VIDEO", key_nameW, - RRF_RT_REG_SZ, NULL, bufferW, &size )) - goto done; - - /* Strip \Registry\Machine\ prefix and retrieve Wine specific data set by the display driver */ - lstrcpyW( key_nameW, bufferW + 18 ); - size = sizeof( state_flags ); - if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"StateFlags", RRF_RT_REG_DWORD, NULL, - &state_flags, &size )) - goto done; - - if (!(state_flags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) - goto done; - - size = sizeof( bufferW ); - if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, L"GPUID", RRF_RT_REG_SZ, NULL, bufferW, &size )) - goto done; - - devinfo = SetupDiCreateDeviceInfoList( &GUID_DEVCLASS_DISPLAY, NULL ); - device_data.cbSize = sizeof( device_data ); - SetupDiOpenDeviceInfoW( devinfo, bufferW, NULL, 0, &device_data ); - if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &DEVPROPKEY_GPU_LUID, &type, - (BYTE *)&luid_desc.AdapterLuid, sizeof( luid_desc.AdapterLuid ), - NULL, 0)) - goto done; - - if ((status = NtGdiDdDDIOpenAdapterFromLuid( &luid_desc ))) goto done; - - desc->hAdapter = luid_desc.hAdapter; - desc->AdapterLuid = luid_desc.AdapterLuid; - desc->VidPnSourceId = index; - -done: - SetupDiDestroyDeviceInfoList( devinfo ); - release_display_device_init_mutex( mutex ); - return status; + if (!desc) return STATUS_UNSUCCESSFUL; + return NtUserD3DKMTOpenAdapterFromGdiDisplayName( desc ); }
/*********************************************************************** diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 49bf26214e7..96aeade50f9 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2730,6 +2730,33 @@ static void monitor_get_interface_name( struct monitor *monitor, WCHAR *interfac asciiz_to_unicode( interface_name, buffer ); }
+/* see D3DKMTOpenAdapterFromGdiDisplayName */ +static NTSTATUS d3dkmt_open_adapter_from_gdi_display_name( D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *desc ) +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + D3DKMT_OPENADAPTERFROMLUID luid_desc; + struct source *source; + UNICODE_STRING name; + + TRACE( "desc %p, name %s\n", desc, debugstr_w( desc->DeviceName ) ); + + RtlInitUnicodeString( &name, desc->DeviceName ); + if (!(source = find_source( &name ))) return STATUS_UNSUCCESSFUL; + + luid_desc.AdapterLuid = source->gpu->luid; + if ((source->state_flags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) && + !(status = NtGdiDdDDIOpenAdapterFromLuid( &luid_desc ))) + { + desc->hAdapter = luid_desc.hAdapter; + desc->AdapterLuid = luid_desc.AdapterLuid; + desc->VidPnSourceId = source->id + 1; + } + + source_release( source ); + return status; +} + + /*********************************************************************** * NtUserEnumDisplayDevices (win32u.@) */ @@ -6407,6 +6434,9 @@ ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code ) case NtUserCallOneParam_SetThreadDpiAwarenessContext: return set_thread_dpi_awareness_context( arg );
+ case NtUserCallOneParam_D3DKMTOpenAdapterFromGdiDisplayName: + return d3dkmt_open_adapter_from_gdi_display_name( (void *)arg ); + /* temporary exports */ case NtUserGetDeskPattern: return get_entry( &entry_DESKPATTERN, 256, (WCHAR *)arg ); diff --git a/include/ntuser.h b/include/ntuser.h index ff45ffa2bc8..b6af76c7ab0 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -911,6 +911,7 @@ enum NtUserCallOneParam_SetProcessDefaultLayout, NtUserCallOneParam_SetKeyboardAutoRepeat, NtUserCallOneParam_SetThreadDpiAwarenessContext, + NtUserCallOneParam_D3DKMTOpenAdapterFromGdiDisplayName, /* temporary exports */ NtUserGetDeskPattern, }; @@ -1034,6 +1035,13 @@ static inline UINT NtUserSetThreadDpiAwarenessContext( UINT context ) return NtUserCallOneParam( context, NtUserCallOneParam_SetThreadDpiAwarenessContext ); }
+typedef struct _D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME; + +static inline NTSTATUS NtUserD3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *desc ) +{ + return NtUserCallOneParam( (UINT_PTR)desc, NtUserCallOneParam_D3DKMTOpenAdapterFromGdiDisplayName ); +} + /* NtUserCallTwoParam codes, not compatible with Windows */ enum {
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=146049
Your paranoid android.
=== debian11 (32 bit report) ===
gdi32: driver.c:101: Test failed: Got unexpected return code 0.
=== debian11b (64 bit WoW report) ===
gdi32: driver.c:101: Test failed: Got unexpected return code 0.
This is causing a test failure: ``` gdi32:driver start dlls/gdi32/tests/driver.c driver.c:101: Test failed: Got unexpected return code 0. ```