1
0
mirror of https://github.com/wine-mirror/wine synced 2024-07-01 07:14:31 +00:00

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
This commit is contained in:
Rémi Bernon 2024-06-04 12:46:47 +02:00 committed by Alexandre Julliard
parent 0da33d5493
commit 6b8cdda502
4 changed files with 42 additions and 77 deletions

View File

@ -2,7 +2,7 @@ EXTRADEFS = -D_GDI32_
MODULE = gdi32.dll
IMPORTLIB = gdi32
IMPORTS = user32 advapi32 win32u
DELAYIMPORTS = setupapi winspool
DELAYIMPORTS = winspool
SOURCES = \
dc.c \

View File

@ -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 );
}
/***********************************************************************

View File

@ -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 );

View File

@ -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
{