[PATCH 2/7] winemac.drv: Initialize GPU registry data.

Zhiyi Zhang zzhang at codeweavers.com
Mon Apr 22 07:13:20 CDT 2019


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/winemac.drv/Makefile.in   |   2 +-
 dlls/winemac.drv/display.c     | 233 +++++++++++++++++++++++++++++++++++++++++
 dlls/winemac.drv/macdrv.h      |   1 +
 dlls/winemac.drv/macdrv_main.c |   3 +
 4 files changed, 238 insertions(+), 1 deletion(-)

diff --git a/dlls/winemac.drv/Makefile.in b/dlls/winemac.drv/Makefile.in
index 3ffb7d666c..a5bd9a426f 100644
--- a/dlls/winemac.drv/Makefile.in
+++ b/dlls/winemac.drv/Makefile.in
@@ -1,5 +1,5 @@
 MODULE    = winemac.drv
-IMPORTS   = uuid user32 gdi32 advapi32
+IMPORTS   = uuid user32 gdi32 advapi32 setupapi ntoskrnl
 DELAYIMPORTS = ole32 shell32 imm32
 EXTRALIBS = -framework AppKit -framework Carbon -framework Security -framework OpenGL -framework IOKit -framework CoreVideo $(METAL_LIBS)
 
diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c
index 00ad7738bb..b756510875 100644
--- a/dlls/winemac.drv/display.c
+++ b/dlls/winemac.drv/display.c
@@ -25,6 +25,13 @@
 #include "winuser.h"
 #include "winreg.h"
 #include "ddrawi.h"
+#include "initguid.h"
+#include "devguid.h"
+#include "devpkey.h"
+#include "setupapi.h"
+#define WIN32_NO_STATUS
+#include "winternl.h"
+#include "ddk/ntddk.h"
 #include "wine/unicode.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(display);
@@ -47,6 +54,41 @@ BOOL CDECL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode, LPDEVMODEW
 
 static const char initial_mode_key[] = "Initial Display Mode";
 static const WCHAR pixelencodingW[] = {'P','i','x','e','l','E','n','c','o','d','i','n','g',0};
+static const WCHAR driver_descW[] = {'D','r','i','v','e','r','D','e','s','c',0};
+static const WCHAR graphics_driverW[] = {'G','r','a','p','h','i','c','s','D','r','i','v','e','r',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 winemac_drvW[] = {
+    'C',':','\\',
+    'W','i','n','d','o','w','s','\\',
+    'S','y','s','t','e','m','3','2','\\',
+    'w','i','n','e','m','a','c','.','d','r','v',0};
+static const WCHAR nt_classW[] = {
+    '\\','R','e','g','i','s','t','r','y','\\',
+    'M','a','c','h','i','n','e','\\',
+    'S','y','s','t','e','m','\\',
+    'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
+    'C','o','n','t','r','o','l','\\',
+    'C','l','a','s','s','\\',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 CFArrayRef modes;
@@ -1397,3 +1439,194 @@ void macdrv_displays_changed(const macdrv_event *event)
                      MAKELPARAM(width, height));
     }
 }
+
+/***********************************************************************
+ *              macdrv_init_gpu
+ *
+ * Initialize a GPU instance and return its GUID string in guid_string and driver value in driver parameter.
+ *
+ * Return FALSE on failure and TRUE on success.
+ */
+static BOOL macdrv_init_gpu(HDEVINFO devinfo, const struct macdrv_gpu *gpu, int gpu_index, WCHAR *guid_string,
+                            WCHAR *driver)
+{
+    static const BOOL present = TRUE;
+    SP_DEVINFO_DATA device_data = {sizeof(device_data)};
+    WCHAR instanceW[MAX_PATH];
+    WCHAR nameW[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);
+    MultiByteToWideChar(CP_UTF8, 0, gpu->name, -1, nameW, ARRAY_SIZE(nameW));
+    if (!SetupDiOpenDeviceInfoW(devinfo, instanceW, NULL, 0, &device_data))
+    {
+        SetupDiCreateDeviceInfoW(devinfo, instanceW, &GUID_DEVCLASS_DISPLAY, nameW, NULL, 0, &device_data);
+        if (!SetupDiRegisterDeviceInfo(devinfo, &device_data, 0, NULL, NULL, NULL))
+            goto fail;
+    }
+
+    /* Write HaredwareID registry property */
+    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 fail;
+
+    /* Write DEVPKEY_Device_IsPresent property */
+    if (!SetupDiSetDevicePropertyW(devinfo, &device_data, &DEVPKEY_Device_IsPresent, DEVPROP_TYPE_BOOLEAN,
+                                   (const BYTE *)&present, sizeof(present), 0))
+        goto fail;
+
+    /* Open driver key.
+     * This is where HKLM\System\CurrentControlSet\Control\Video\{GPU GUID}\{Adapter Index} links to */
+    hkey = SetupDiOpenDevRegKey(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_ALL_ACCESS);
+    if (hkey == INVALID_HANDLE_VALUE)
+        hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
+
+    /* Write GraphicsDriver value */
+    if (RegSetValueExW(hkey, graphics_driverW, 0, REG_SZ, (const BYTE *)winemac_drvW, sizeof(winemac_drvW)))
+        goto fail;
+
+    /* Write DriverDesc value */
+    if (RegSetValueExW(hkey, driver_descW, 0, REG_SZ, (const BYTE *)nameW, (strlenW(nameW) + 1) * sizeof(WCHAR)))
+        goto fail;
+    RegCloseKey(hkey);
+    hkey = NULL;
+
+    /* Retrieve driver value for adapters */
+    if (!SetupDiGetDeviceRegistryPropertyW(devinfo, &device_data, SPDRP_DRIVER, NULL, (BYTE *)bufferW, sizeof(bufferW),
+                                           NULL))
+        goto fail;
+    strcpyW(driver, nt_classW);
+    strcatW(driver, bufferW);
+
+    /* Write GUID in VideoID in .../instance/Device Parameters, reuse the GUID if it's existent */
+    hkey = SetupDiOpenDevRegKey(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_ALL_ACCESS);
+    if (hkey == INVALID_HANDLE_VALUE)
+        hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, NULL, NULL);
+    size = sizeof(bufferW);
+    bufferW[0] = 0;
+    if (RegQueryValueExW(hkey, video_idW, 0, NULL, (BYTE *)bufferW, &size))
+    {
+        ExUuidCreate(&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 fail;
+    }
+    strcpyW(guid_string, bufferW);
+
+    ret = TRUE;
+fail:
+    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;
+
+    /* Set all GPUs as not present. We can't simply delete them because we need to keep the GUID consistent with
+     * each initialization run. We clean up non present GPUs at the end of initialization */
+    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);
+}
+
+/***********************************************************************
+ *              macdrv_init_display_devices
+ *
+ * Initialize display device registry data.
+ *
+ * Return FALSE on failure and TRUE on success.
+ */
+BOOL macdrv_init_display_devices(void)
+{
+    struct macdrv_gpu *gpus = NULL;
+    INT gpu_count;
+    INT gpu;
+    HDEVINFO gpu_devinfo = NULL;
+    HKEY video_hkey = NULL;
+    DWORD disposition = 0;
+    WCHAR guidW[40];
+    WCHAR driverW[1024];
+    BOOL ret = FALSE;
+
+    TRACE("\n");
+
+    if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, video_keyW, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &video_hkey,
+                        &disposition))
+        goto fail;
+
+    /* Ensure only one thread is initializing the registry and avoid unnecessary reinit */
+    if (disposition != REG_CREATED_NEW_KEY)
+    {
+        ret = TRUE;
+        goto fail;
+    }
+
+    /* FIXME:
+     * Currently we have no idea how to implement SetupDiGetClassDevsW with DIGCF_PRESENT properly. So we need to clean
+     * up not present devices in case applications use 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. */
+    prepare_devices();
+
+    gpu_devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
+
+    /* Initialize GPUs */
+    if (macdrv_get_gpus(&gpus, &gpu_count))
+        goto fail;
+
+    for (gpu = 0; gpu < gpu_count; gpu++)
+    {
+        if (!macdrv_init_gpu(gpu_devinfo, &gpus[gpu], gpu, guidW, driverW))
+            goto fail;
+    }
+
+    ret = TRUE;
+fail:
+    cleanup_devices();
+    SetupDiDestroyDeviceInfoList(gpu_devinfo);
+    RegCloseKey(video_hkey);
+    if (gpus)
+        macdrv_free_gpus(gpus);
+    if (!ret)
+        ERR("Failed to initialize display devices\n");
+    return ret;
+}
\ No newline at end of file
diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h
index f948da42c7..dca89b04f0 100644
--- a/dlls/winemac.drv/macdrv.h
+++ b/dlls/winemac.drv/macdrv.h
@@ -223,6 +223,7 @@ extern CGImageRef create_cgimage_from_icon_bitmaps(HDC hdc, HANDLE icon, HBITMAP
 extern void macdrv_status_item_mouse_move(const macdrv_event *event) DECLSPEC_HIDDEN;
 
 extern void check_retina_status(void) DECLSPEC_HIDDEN;
+extern BOOL macdrv_init_display_devices(void) DECLSPEC_HIDDEN;
 
 /**************************************************************************
  * Mac IME driver
diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c
index 544d448f9f..0779952e9a 100644
--- a/dlls/winemac.drv/macdrv_main.c
+++ b/dlls/winemac.drv/macdrv_main.c
@@ -299,6 +299,9 @@ static BOOL process_attach(void)
         return FALSE;
     }
 
+    if (!macdrv_init_display_devices())
+        return FALSE;
+
     return TRUE;
 }
 
-- 
2.15.2 (Apple Git-101.1)





More information about the wine-devel mailing list