Module: wine Branch: master Commit: 6b8cdda502a5fd726529af0cdb14c57467cde14b URL: https://gitlab.winehq.org/wine/wine/-/commit/6b8cdda502a5fd726529af0cdb14c57...
Author: Rémi Bernon rbernon@codeweavers.com Date: Tue Jun 4 12:46:47 2024 +0200
gdi32: Use an internal NtUser call for D3DKMTOpenAdapterFromGdiDisplayName.
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 | 31 ++++++++++++++++++++ include/ntuser.h | 8 +++++ 4 files changed, 42 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 db23795d57c..7c0ef662014 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2730,6 +2730,34 @@ 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 (!name.Length) return STATUS_UNSUCCESSFUL; + 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.@) */ @@ -6433,6 +6461,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 1d2f32b5ea6..35936a99fd3 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -912,6 +912,7 @@ enum NtUserCallOneParam_SetProcessDefaultLayout, NtUserCallOneParam_SetKeyboardAutoRepeat, NtUserCallOneParam_SetThreadDpiAwarenessContext, + NtUserCallOneParam_D3DKMTOpenAdapterFromGdiDisplayName, /* temporary exports */ NtUserGetDeskPattern, }; @@ -1035,6 +1036,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 {