Signed-off-by: Zhiyi Zhang zzhang@codeweavers.com --- v2: Supersede 185706. Don't use EnumDisplayDevicesW().
dlls/gdi32/Makefile.in | 2 +- dlls/gdi32/driver.c | 84 +++++++++++++++++++++++++++++++++++---- dlls/gdi32/tests/driver.c | 2 + 3 files changed, 79 insertions(+), 9 deletions(-)
diff --git a/dlls/gdi32/Makefile.in b/dlls/gdi32/Makefile.in index e1ac922ce52..32b2e6959c1 100644 --- a/dlls/gdi32/Makefile.in +++ b/dlls/gdi32/Makefile.in @@ -4,7 +4,7 @@ IMPORTLIB = gdi32 IMPORTS = advapi32 EXTRAINCL = $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) EXTRALIBS = $(CARBON_LIBS) $(APPKIT_LIBS) -DELAYIMPORTS = usp10 +DELAYIMPORTS = usp10 setupapi
C_SRCS = \ bidi.c \ diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c index 90977383a58..4f1cef0b4f9 100644 --- a/dlls/gdi32/driver.c +++ b/dlls/gdi32/driver.c @@ -31,10 +31,14 @@ #include "windef.h" #include "winbase.h" #include "wingdi.h" +#include "winreg.h" #include "ddrawgdi.h" #include "wine/winbase16.h" #include "winuser.h" #include "winternl.h" +#include "initguid.h" +#include "devguid.h" +#include "setupapi.h" #include "ddk/d3dkmthk.h"
#include "gdi_private.h" @@ -45,6 +49,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(driver);
+DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2); + struct graphics_driver { struct list entry; @@ -159,6 +165,20 @@ static BOOL is_display_device( LPCWSTR name ) return TRUE; }
+static HANDLE get_display_device_init_mutex( void ) +{ + static const WCHAR init_mutex[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0}; + HANDLE mutex = CreateMutexW( NULL, FALSE, init_mutex ); + + WaitForSingleObject( mutex, INFINITE ); + return mutex; +} + +static void release_display_device_init_mutex( HANDLE mutex ) +{ + ReleaseMutex( mutex ); + CloseHandle( mutex ); +}
/********************************************************************** * DRIVER_load_driver @@ -1351,17 +1371,31 @@ NTSTATUS WINAPI D3DKMTCloseAdapter( const D3DKMT_CLOSEADAPTER *desc ) NTSTATUS WINAPI D3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *desc ) { static const WCHAR displayW[] = {'\','\','.','\','D','I','S','P','L','A','Y'}; + static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0}; + static const WCHAR video_value_fmtW[] = {'\','D','e','v','i','c','e','\', + 'V','i','d','e','o','%','d',0}; + static const WCHAR video_keyW[] = {'H','A','R','D','W','A','R','E','\', + 'D','E','V','I','C','E','M','A','P','\', + 'V','I','D','E','O','\',0}; + static const WCHAR gpu_idW[] = {'G','P','U','I','D',0}; + WCHAR *end, key_nameW[MAX_PATH], bufferW[MAX_PATH]; + HDEVINFO devinfo = INVALID_HANDLE_VALUE; + NTSTATUS status = STATUS_UNSUCCESSFUL; static D3DKMT_HANDLE handle_start = 0; struct d3dkmt_adapter *adapter; - WCHAR *end; - int id; + SP_DEVINFO_DATA device_data; + DWORD size, state_flags; + DEVPROPTYPE type; + HANDLE mutex; + LUID luid; + int index;
TRACE("(%p) semi-stub\n", desc);
if (!desc || strncmpiW( desc->DeviceName, displayW, ARRAY_SIZE(displayW) )) return STATUS_UNSUCCESSFUL;
- id = strtolW( desc->DeviceName + ARRAY_SIZE(displayW), &end, 10 ) - 1; + index = strtolW( desc->DeviceName + ARRAY_SIZE(displayW), &end, 10 ) - 1; if (*end) return STATUS_UNSUCCESSFUL;
@@ -1369,6 +1403,35 @@ NTSTATUS WINAPI D3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADAPTERFROMGDIDI if (!adapter) return STATUS_NO_MEMORY;
+ /* Get adapter LUID from SetupAPI */ + mutex = get_display_device_init_mutex(); + + size = sizeof( bufferW ); + sprintfW( key_nameW, video_value_fmtW, index ); + if (RegGetValueW( HKEY_LOCAL_MACHINE, video_keyW, key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size )) + goto done; + + /* Strip \Registry\Machine\ prefix */ + lstrcpyW( key_nameW, bufferW + 18 ); + size = sizeof( state_flags ); + if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, state_flagsW, 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, gpu_idW, 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, sizeof( luid ), NULL, 0)) + goto done; + EnterCriticalSection( &driver_section ); /* D3DKMT_HANDLE is UINT, so we can't use pointer as handle */ adapter->handle = ++handle_start; @@ -1376,11 +1439,16 @@ NTSTATUS WINAPI D3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADAPTERFROMGDIDI LeaveCriticalSection( &driver_section );
desc->hAdapter = handle_start; - /* FIXME: Support AdapterLuid */ - desc->AdapterLuid.LowPart = 0; - desc->AdapterLuid.HighPart = 0; - desc->VidPnSourceId = id; - return STATUS_SUCCESS; + desc->AdapterLuid = luid; + desc->VidPnSourceId = index; + status = STATUS_SUCCESS; + +done: + SetupDiDestroyDeviceInfoList( devinfo ); + release_display_device_init_mutex( mutex ); + if (status != STATUS_SUCCESS) + heap_free( adapter ); + return status; }
/****************************************************************************** diff --git a/dlls/gdi32/tests/driver.c b/dlls/gdi32/tests/driver.c index 6172d4a7983..c656eb4245a 100644 --- a/dlls/gdi32/tests/driver.c +++ b/dlls/gdi32/tests/driver.c @@ -86,6 +86,8 @@ static void test_D3DKMTOpenAdapterFromGdiDisplayName(void) }
ok(open_adapter_gdi_desc.hAdapter, "Expect not null.\n"); + ok(open_adapter_gdi_desc.AdapterLuid.LowPart || open_adapter_gdi_desc.AdapterLuid.HighPart, + "Expect LUID not zero.\n");
close_adapter_desc.hAdapter = open_adapter_gdi_desc.hAdapter; status = pD3DKMTCloseAdapter(&close_adapter_desc);
On Thu, Jun 11, 2020 at 05:19:17PM +0800, Zhiyi Zhang wrote:
/**********************************************************************
DRIVER_load_driver
@@ -1351,17 +1371,31 @@ NTSTATUS WINAPI D3DKMTCloseAdapter( const D3DKMT_CLOSEADAPTER *desc ) NTSTATUS WINAPI D3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *desc ) { static const WCHAR displayW[] = {'\','\','.','\','D','I','S','P','L','A','Y'};
- static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0};
- static const WCHAR video_value_fmtW[] = {'\','D','e','v','i','c','e','\',
'V','i','d','e','o','%','d',0};
- static const WCHAR video_keyW[] = {'H','A','R','D','W','A','R','E','\',
'D','E','V','I','C','E','M','A','P','\\',
'V','I','D','E','O','\\',0};
- static const WCHAR gpu_idW[] = {'G','P','U','I','D',0};
- WCHAR *end, key_nameW[MAX_PATH], bufferW[MAX_PATH];
- HDEVINFO devinfo = INVALID_HANDLE_VALUE;
- NTSTATUS status = STATUS_UNSUCCESSFUL; static D3DKMT_HANDLE handle_start = 0; struct d3dkmt_adapter *adapter;
- WCHAR *end;
- int id;
SP_DEVINFO_DATA device_data;
DWORD size, state_flags;
DEVPROPTYPE type;
HANDLE mutex;
LUID luid;
int index;
TRACE("(%p) semi-stub\n", desc);
Is this still a semi-stub? Also, it might be useful to output desc->DeviceName.
if (!desc || strncmpiW( desc->DeviceName, displayW, ARRAY_SIZE(displayW) )) return STATUS_UNSUCCESSFUL;
- id = strtolW( desc->DeviceName + ARRAY_SIZE(displayW), &end, 10 ) - 1;
- index = strtolW( desc->DeviceName + ARRAY_SIZE(displayW), &end, 10 ) - 1; if (*end) return STATUS_UNSUCCESSFUL;
@@ -1369,6 +1403,35 @@ NTSTATUS WINAPI D3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADAPTERFROMGDIDI if (!adapter) return STATUS_NO_MEMORY;
- /* Get adapter LUID from SetupAPI */
- mutex = get_display_device_init_mutex();
- size = sizeof( bufferW );
- sprintfW( key_nameW, video_value_fmtW, index );
- if (RegGetValueW( HKEY_LOCAL_MACHINE, video_keyW, key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size ))
goto done;
- /* Strip \Registry\Machine\ prefix */
- lstrcpyW( key_nameW, bufferW + 18 );
- size = sizeof( state_flags );
- if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, state_flagsW, RRF_RT_REG_DWORD, NULL,
&state_flags, &size ))
goto done;
\Registry\Machine is HKLM not HKCC; I know what Wine has the information in both places, but still.
It might be better to use the Nt registry functions here (of course you'd then lose the RegGetValue() helper).
Thanks, Huw.
On Thu, Jun 11, 2020 at 11:15:50AM +0100, Huw Davies wrote:
On Thu, Jun 11, 2020 at 05:19:17PM +0800, Zhiyi Zhang wrote:
@@ -1369,6 +1403,35 @@ NTSTATUS WINAPI D3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADAPTERFROMGDIDI if (!adapter) return STATUS_NO_MEMORY;
- /* Get adapter LUID from SetupAPI */
- mutex = get_display_device_init_mutex();
- size = sizeof( bufferW );
- sprintfW( key_nameW, video_value_fmtW, index );
- if (RegGetValueW( HKEY_LOCAL_MACHINE, video_keyW, key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size ))
goto done;
- /* Strip \Registry\Machine\ prefix */
- lstrcpyW( key_nameW, bufferW + 18 );
- size = sizeof( state_flags );
- if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, state_flagsW, RRF_RT_REG_DWORD, NULL,
&state_flags, &size ))
goto done;
\Registry\Machine is HKLM not HKCC; I know what Wine has the information in both places, but still.
Oh, I've figured it out now, this is the Wine specific data set by the driver. Could you add a comment to this effect? Something like: /* Retrieve Wine specific data set by the display driver */
It might be better to use the Nt registry functions here (of course you'd then lose the RegGetValue() helper).
So this now becomes irrelevant.
Huw.
On 6/11/20 6:15 PM, Huw Davies wrote:
On Thu, Jun 11, 2020 at 05:19:17PM +0800, Zhiyi Zhang wrote:
/**********************************************************************
DRIVER_load_driver
@@ -1351,17 +1371,31 @@ NTSTATUS WINAPI D3DKMTCloseAdapter( const D3DKMT_CLOSEADAPTER *desc ) NTSTATUS WINAPI D3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADAPTERFROMGDIDISPLAYNAME *desc ) { static const WCHAR displayW[] = {'\','\','.','\','D','I','S','P','L','A','Y'};
- static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0};
- static const WCHAR video_value_fmtW[] = {'\','D','e','v','i','c','e','\',
'V','i','d','e','o','%','d',0};
- static const WCHAR video_keyW[] = {'H','A','R','D','W','A','R','E','\',
'D','E','V','I','C','E','M','A','P','\\',
'V','I','D','E','O','\\',0};
- static const WCHAR gpu_idW[] = {'G','P','U','I','D',0};
- WCHAR *end, key_nameW[MAX_PATH], bufferW[MAX_PATH];
- HDEVINFO devinfo = INVALID_HANDLE_VALUE;
- NTSTATUS status = STATUS_UNSUCCESSFUL; static D3DKMT_HANDLE handle_start = 0; struct d3dkmt_adapter *adapter;
- WCHAR *end;
- int id;
SP_DEVINFO_DATA device_data;
DWORD size, state_flags;
DEVPROPTYPE type;
HANDLE mutex;
LUID luid;
int index;
TRACE("(%p) semi-stub\n", desc);
Is this still a semi-stub? Also, it might be useful to output desc->DeviceName.
The VidPnSourceId is still fake. But yeah, I guess it's ok to remove semi-stub.
if (!desc || strncmpiW( desc->DeviceName, displayW, ARRAY_SIZE(displayW) )) return STATUS_UNSUCCESSFUL;
- id = strtolW( desc->DeviceName + ARRAY_SIZE(displayW), &end, 10 ) - 1;
- index = strtolW( desc->DeviceName + ARRAY_SIZE(displayW), &end, 10 ) - 1; if (*end) return STATUS_UNSUCCESSFUL;
@@ -1369,6 +1403,35 @@ NTSTATUS WINAPI D3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADAPTERFROMGDIDI if (!adapter) return STATUS_NO_MEMORY;
- /* Get adapter LUID from SetupAPI */
- mutex = get_display_device_init_mutex();
- size = sizeof( bufferW );
- sprintfW( key_nameW, video_value_fmtW, index );
- if (RegGetValueW( HKEY_LOCAL_MACHINE, video_keyW, key_nameW, RRF_RT_REG_SZ, NULL, bufferW, &size ))
goto done;
- /* Strip \Registry\Machine\ prefix */
- lstrcpyW( key_nameW, bufferW + 18 );
- size = sizeof( state_flags );
- if (RegGetValueW( HKEY_CURRENT_CONFIG, key_nameW, state_flagsW, RRF_RT_REG_DWORD, NULL,
&state_flags, &size ))
goto done;
\Registry\Machine is HKLM not HKCC; I know what Wine has the information in both places, but still.
It might be better to use the Nt registry functions here (of course you'd then lose the RegGetValue() helper).
Thanks, Huw.