winex11.drv: Initialize GPU registry data.

Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com>
Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zhiyi Zhang 2019-06-10 22:07:14 +08:00 committed by Alexandre Julliard
parent 52a3d5db48
commit bada31698f
4 changed files with 202 additions and 1 deletions

View File

@ -1,5 +1,5 @@
MODULE = winex11.drv MODULE = winex11.drv
IMPORTS = uuid user32 gdi32 advapi32 IMPORTS = uuid setupapi rpcrt4 user32 gdi32 advapi32
DELAYIMPORTS = comctl32 ole32 shell32 imm32 DELAYIMPORTS = comctl32 ole32 shell32 imm32
EXTRAINCL = $(X_CFLAGS) EXTRAINCL = $(X_CFLAGS)
EXTRALIBS = $(X_LIBS) $(X_EXTRA_LIBS) EXTRALIBS = $(X_LIBS) $(X_EXTRA_LIBS)

View File

@ -25,12 +25,38 @@
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#include "winuser.h" #include "winuser.h"
#include "rpc.h"
#include "winreg.h" #include "winreg.h"
#include "initguid.h"
#include "devguid.h"
#include "devpkey.h"
#include "setupapi.h"
#define WIN32_NO_STATUS
#include "winternl.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/unicode.h"
#include "x11drv.h" #include "x11drv.h"
WINE_DEFAULT_DEBUG_CHANNEL(x11drv); WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
static const WCHAR video_idW[] = {'V','i','d','e','o','I','D',0};
static const WCHAR guid_fmtW[] = {
'{','%','0','8','x','-','%','0','4','x','-','%','0','4','x','-','%','0','2','x','%','0','2','x','-',
'%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x','}',0};
static const WCHAR gpu_instance_fmtW[] = {
'P','C','I','\\',
'V','E','N','_','%','0','4','X','&',
'D','E','V','_','%','0','4','X','&',
'S','U','B','S','Y','S','_','%','0','8','X','&',
'R','E','V','_','%','0','2','X','\\',
'%','0','8','X',0};
static const WCHAR gpu_hardware_id_fmtW[] = {
'P','C','I','\\',
'V','E','N','_','%','0','4','X','&',
'D','E','V','_','%','0','4','X','&',
'S','U','B','S','Y','S','_','0','0','0','0','0','0','0','0','&',
'R','E','V','_','0','0',0};
static const WCHAR video_keyW[] = { static const WCHAR video_keyW[] = {
'H','A','R','D','W','A','R','E','\\', 'H','A','R','D','W','A','R','E','\\',
'D','E','V','I','C','E','M','A','P','\\', 'D','E','V','I','C','E','M','A','P','\\',
@ -47,10 +73,120 @@ void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler
} }
} }
/* Initialize a GPU instance */
static BOOL X11DRV_InitGpu(HDEVINFO devinfo, const struct x11drv_gpu *gpu, INT gpu_index)
{
static const BOOL present = TRUE;
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
WCHAR instanceW[MAX_PATH];
WCHAR bufferW[1024];
HKEY hkey = NULL;
GUID guid;
INT written;
DWORD size;
BOOL ret = FALSE;
sprintfW(instanceW, gpu_instance_fmtW, gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id, gpu_index);
if (!SetupDiOpenDeviceInfoW(devinfo, instanceW, NULL, 0, &device_data))
{
SetupDiCreateDeviceInfoW(devinfo, instanceW, &GUID_DEVCLASS_DISPLAY, gpu->name, NULL, 0, &device_data);
if (!SetupDiRegisterDeviceInfo(devinfo, &device_data, 0, NULL, NULL, NULL))
goto done;
}
/* Write HardwareID registry property, REG_MULTI_SZ */
written = sprintfW(bufferW, gpu_hardware_id_fmtW, gpu->vendor_id, gpu->device_id);
bufferW[written + 1] = 0;
if (!SetupDiSetDeviceRegistryPropertyW(devinfo, &device_data, SPDRP_HARDWAREID, (const BYTE *)bufferW,
(written + 2) * sizeof(WCHAR)))
goto done;
/* Write DEVPKEY_Device_IsPresent property */
if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &DEVPKEY_Device_IsPresent, DEVPROP_TYPE_BOOLEAN,
(const BYTE *)&present, sizeof(present), 0))
goto done;
/* Open driver key.
* This is where HKLM\System\CurrentControlSet\Control\Video\{GPU GUID}\{Adapter Index} links to */
hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
/* Write DriverDesc value */
if (RegSetValueExW(hkey, driver_descW, 0, REG_SZ, (const BYTE *)gpu->name,
(strlenW(gpu->name) + 1) * sizeof(WCHAR)))
goto done;
RegCloseKey(hkey);
/* Write GUID in VideoID in .../instance/Device Parameters, reuse the GUID if it's existent */
hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, NULL, NULL);
size = sizeof(bufferW);
if (RegQueryValueExW(hkey, video_idW, 0, NULL, (BYTE *)bufferW, &size))
{
UuidCreate(&guid);
sprintfW(bufferW, guid_fmtW, guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1], guid.Data4[2],
guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
if (RegSetValueExW(hkey, video_idW, 0, REG_SZ, (const BYTE *)bufferW, (strlenW(bufferW) + 1) * sizeof(WCHAR)))
goto done;
}
ret = TRUE;
done:
RegCloseKey(hkey);
if (!ret)
ERR("Failed to initialize GPU\n");
return ret;
}
static void prepare_devices(void)
{
static const BOOL not_present = FALSE;
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
HDEVINFO devinfo;
DWORD i = 0;
/* FIXME:
* Currently SetupDiGetClassDevsW with DIGCF_PRESENT is unsupported, So we need to clean up not present devices in
* case application uses SetupDiGetClassDevsW to enumerate devices. Wrong devices could exist in registry as a result
* of prefix copying or having devices unplugged. But then we couldn't simply delete GPUs because we need to retain
* the same GUID for the same GPU. */
devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, 0);
while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
{
if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &DEVPKEY_Device_IsPresent, DEVPROP_TYPE_BOOLEAN,
(const BYTE *)&not_present, sizeof(not_present), 0))
ERR("Failed to set GPU present property\n");
}
SetupDiDestroyDeviceInfoList(devinfo);
}
static void cleanup_devices(void)
{
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
HDEVINFO devinfo;
DWORD type;
DWORD i = 0;
BOOL present;
devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, 0);
while (SetupDiEnumDeviceInfo(devinfo, i++, &device_data))
{
present = FALSE;
SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPKEY_Device_IsPresent, &type, (BYTE *)&present,
sizeof(present), NULL, 0);
if (!present && !SetupDiRemoveDevice(devinfo, &device_data))
ERR("Failed to remove GPU\n");
}
SetupDiDestroyDeviceInfoList(devinfo);
}
void X11DRV_DisplayDevices_Init(void) void X11DRV_DisplayDevices_Init(void)
{ {
static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0}; static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0};
HANDLE mutex; HANDLE mutex;
struct x11drv_gpu *gpus = NULL;
INT gpu_count;
INT gpu;
HDEVINFO gpu_devinfo = NULL;
HKEY video_hkey = NULL; HKEY video_hkey = NULL;
DWORD disposition = 0; DWORD disposition = 0;
@ -70,8 +206,26 @@ void X11DRV_DisplayDevices_Init(void)
TRACE("via %s\n", wine_dbgstr_a(handler.name)); TRACE("via %s\n", wine_dbgstr_a(handler.name));
prepare_devices();
gpu_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
/* Initialize GPUs */
if (!handler.pGetGpus(&gpus, &gpu_count))
goto done;
for (gpu = 0; gpu < gpu_count; gpu++)
{
if (!X11DRV_InitGpu(gpu_devinfo, &gpus[gpu], gpu))
goto done;
}
done: done:
cleanup_devices();
SetupDiDestroyDeviceInfoList(gpu_devinfo);
RegCloseKey(video_hkey); RegCloseKey(video_hkey);
ReleaseMutex(mutex); ReleaseMutex(mutex);
CloseHandle(mutex); CloseHandle(mutex);
if (gpus)
handler.pFreeGpus(gpus);
} }

View File

@ -667,6 +667,20 @@ void X11DRV_XRandR_Init(void) DECLSPEC_HIDDEN;
/* X11 display device handler. Used to initialize display device registry data */ /* X11 display device handler. Used to initialize display device registry data */
/* Represent a physical GPU in the PCI slots */
struct x11drv_gpu
{
/* ID to uniquely identify a GPU in handler */
ULONG_PTR id;
/* Name */
WCHAR name[128];
/* PCI ID */
UINT vendor_id;
UINT device_id;
UINT subsys_id;
UINT revision_id;
};
/* Required functions for display device registry initialization */ /* Required functions for display device registry initialization */
struct x11drv_display_device_handler struct x11drv_display_device_handler
{ {
@ -675,6 +689,14 @@ struct x11drv_display_device_handler
/* Higher priority can override handlers with lower proprity */ /* Higher priority can override handlers with lower proprity */
INT priority; INT priority;
/* pGetGpus will be called to get a list of GPUs. First GPU has to be where the primary adapter is.
*
* Return FALSE on failure with parameters unchanged */
BOOL (*pGetGpus)(struct x11drv_gpu **gpus, int *count);
/* pFreeGpus will be called to free a GPU list from pGetGpus */
void (*pFreeGpus)(struct x11drv_gpu *gpus);
}; };
extern void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *handler) DECLSPEC_HIDDEN; extern void X11DRV_DisplayDevices_SetHandler(const struct x11drv_display_device_handler *handler) DECLSPEC_HIDDEN;

View File

@ -201,6 +201,29 @@ RECT get_primary_monitor_rect(void)
return get_primary()->rcMonitor; return get_primary()->rcMonitor;
} }
static BOOL xinerama_get_gpus( struct x11drv_gpu **new_gpus, int *count )
{
static const WCHAR wine_adapterW[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
struct x11drv_gpu *gpus;
/* Xinerama has no support for GPU, faking one */
gpus = heap_calloc( 1, sizeof(*gpus) );
if (!gpus)
return FALSE;
lstrcpyW( gpus[0].name, wine_adapterW );
*new_gpus = gpus;
*count = 1;
return TRUE;
}
static void xinerama_free_gpus( struct x11drv_gpu *gpus )
{
heap_free( gpus );
}
void xinerama_init( unsigned int width, unsigned int height ) void xinerama_init( unsigned int width, unsigned int height )
{ {
struct x11drv_display_device_handler handler; struct x11drv_display_device_handler handler;
@ -239,6 +262,8 @@ void xinerama_init( unsigned int width, unsigned int height )
handler.name = "Xinerama"; handler.name = "Xinerama";
handler.priority = 100; handler.priority = 100;
handler.pGetGpus = xinerama_get_gpus;
handler.pFreeGpus = xinerama_free_gpus;
X11DRV_DisplayDevices_SetHandler( &handler ); X11DRV_DisplayDevices_SetHandler( &handler );
TRACE( "virtual size: %s primary: %s\n", TRACE( "virtual size: %s primary: %s\n",