Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/winex11.drv/Makefile.in | 3 +-
dlls/winex11.drv/adapter.c | 220 +++++++++++++++++++++++++++++++++++
dlls/winex11.drv/init.c | 3 +
dlls/winex11.drv/x11drv.h | 1 +
4 files changed, 226 insertions(+), 1 deletion(-)
create mode 100644 dlls/winex11.drv/adapter.c
diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in
index 747f509b44..509e84670d 100644
--- a/dlls/winex11.drv/Makefile.in
+++ b/dlls/winex11.drv/Makefile.in
@@ -1,10 +1,11 @@
MODULE = winex11.drv
-IMPORTS = uuid user32 gdi32 advapi32
+IMPORTS = uuid user32 gdi32 advapi32 setupapi
DELAYIMPORTS = comctl32 ole32 shell32 imm32
EXTRAINCL = $(X_CFLAGS)
EXTRALIBS = $(X_LIBS) $(X_EXTRA_LIBS)
C_SRCS = \
+ adapter.c \
bitblt.c \
brush.c \
clipboard.c \
diff --git a/dlls/winex11.drv/adapter.c b/dlls/winex11.drv/adapter.c
new file mode 100644
index 0000000000..b8c4b9e437
--- /dev/null
+++ b/dlls/winex11.drv/adapter.c
@@ -0,0 +1,220 @@
+/*
+ * Adapter enumeration
+ *
+ * Copyright 2018 Zhiyi Zhang for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include "config.h"
+#include "wine/port.h"
+
+#include <stdarg.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "winuser.h"
+#include "wine/debug.h"
+#include "wine/heap.h"
+#include "wine/unicode.h"
+#include "wine/vulkan.h"
+#include "wine/vulkan_driver.h"
+
+#include "initguid.h"
+#include "devguid.h"
+#include "devpkey.h"
+#include "setupapi.h"
+#include "x11drv.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
+
+DEFINE_DEVPROPKEY(DEVPROPKEY_DISPLAY_ADAPTER_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2);
+/* Private DEVPROPKEY for associating an physical adapter to a vulkan adapter */
+DEFINE_DEVPROPKEY(DEVPROPKEY_DISPLAY_ADAPTER_UUID, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5b, 2);
+
+struct adapter_desc
+{
+ uint32_t vendor_id;
+ uint32_t device_id;
+ GUID uuid;
+ WCHAR *device_name;
+};
+
+static WCHAR *heap_strdupAtoW(const char *str)
+{
+ WCHAR *ret;
+ INT len;
+
+ len = MultiByteToWideChar(CP_ACP, 0, str, -1, 0, 0);
+ ret = heap_alloc(len * sizeof(WCHAR));
+ MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
+
+ return ret;
+}
+
+static BOOL add_adapter_entry(const struct adapter_desc *adapter, uint32_t index)
+{
+ static const WCHAR instance_formatW[] = {'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',
+ /* Fake instance id */
+ '\\', '3',
+ '&', '2', '6', '7', 'a', '6', '1', '6', 'a',
+ '&', '0',
+ '&', '%','0','2', 'u', 0};
+ WCHAR instanceW[ARRAY_SIZE(instance_formatW)];
+ HDEVINFO devinfo;
+ SP_DEVINFO_DATA devinfo_data = {sizeof(SP_DEVINFO_DATA)};
+ LUID luid;
+ BOOL ret = FALSE;
+
+ sprintfW(instanceW, instance_formatW, adapter->vendor_id, adapter->device_id, index);
+
+ devinfo = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_DISPLAY, NULL);
+ if (devinfo == INVALID_HANDLE_VALUE)
+ goto fail;
+ if (!SetupDiCreateDeviceInfoW(devinfo, instanceW, &GUID_DEVCLASS_DISPLAY, adapter->device_name, NULL, 0,
+ &devinfo_data))
+ goto fail;
+ if (!AllocateLocallyUniqueId(&luid))
+ goto fail;
+ if (!SetupDiSetDevicePropertyW(devinfo, &devinfo_data, &DEVPROPKEY_DISPLAY_ADAPTER_LUID, DEVPROP_TYPE_UINT64,
+ (const BYTE *)&luid, sizeof(luid), 0))
+ goto fail;
+ if (!SetupDiSetDevicePropertyW(devinfo, &devinfo_data, &DEVPROPKEY_DISPLAY_ADAPTER_UUID, DEVPROP_TYPE_UINT64,
+ (const BYTE *)&adapter->uuid, sizeof(adapter->uuid), 0))
+ goto fail;
+ if (!SetupDiSetDevicePropertyW(devinfo, &devinfo_data, &DEVPKEY_NAME, DEVPROP_TYPE_STRING,
+ (const BYTE *)adapter->device_name,
+ (strlenW(adapter->device_name) + 1) * sizeof(WCHAR), 0))
+ goto fail;
+ if (!SetupDiRegisterDeviceInfo(devinfo, &devinfo_data, 0, NULL, NULL, NULL))
+ goto fail;
+
+ ret = TRUE;
+fail:
+ SetupDiDestroyDeviceInfoList(devinfo);
+ return ret;
+}
+
+static BOOL init_vulkan_adapters(void)
+{
+ static const CHAR *extensions[] = {VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME};
+ const struct vulkan_funcs *vk_funcs;
+ PFN_vkEnumeratePhysicalDevices p_vkEnumeratePhysicalDevices;
+ PFN_vkGetPhysicalDeviceProperties2KHR p_vkGetPhysicalDeviceProperties2KHR;
+ VkInstanceCreateInfo create_info = {0};
+ VkInstance instance;
+ VkPhysicalDevice *devices = NULL;
+ VkPhysicalDeviceProperties2 prop2;
+ VkPhysicalDeviceIDProperties id;
+ VkResult vr;
+ struct adapter_desc desc;
+ uint32_t i, count = 0;
+ BOOL ret = FALSE;
+
+ vk_funcs = get_vulkan_driver(WINE_VULKAN_DRIVER_VERSION);
+ if (!vk_funcs)
+ return FALSE;
+
+ create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ create_info.enabledExtensionCount = ARRAY_SIZE(extensions);
+ create_info.ppEnabledExtensionNames = extensions;
+ vr = vk_funcs->p_vkCreateInstance(&create_info, NULL, &instance);
+ if (vr != VK_SUCCESS)
+ return FALSE;
+
+ p_vkEnumeratePhysicalDevices =
+ (PFN_vkEnumeratePhysicalDevices)vk_funcs->p_vkGetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices");
+ p_vkGetPhysicalDeviceProperties2KHR = (PFN_vkGetPhysicalDeviceProperties2KHR)vk_funcs->p_vkGetInstanceProcAddr(
+ instance, "vkGetPhysicalDeviceProperties2KHR");
+
+ vr = p_vkEnumeratePhysicalDevices(instance, &count, NULL);
+ if (vr != VK_SUCCESS || count == 0)
+ goto fail;
+
+ devices = heap_alloc(count * sizeof(VkPhysicalDevice));
+ if (!devices)
+ goto fail;
+
+ vr = p_vkEnumeratePhysicalDevices(instance, &count, devices);
+ if (vr != VK_SUCCESS)
+ goto fail;
+
+ for (i = 0; i < count; i++)
+ {
+ prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ prop2.pNext = &id;
+
+ id.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
+ id.pNext = NULL;
+
+ p_vkGetPhysicalDeviceProperties2KHR(devices[i], &prop2);
+ desc.vendor_id = prop2.properties.vendorID;
+ desc.device_id = prop2.properties.deviceID;
+ desc.uuid = *(GUID *)id.deviceUUID;
+ desc.device_name = heap_strdupAtoW(prop2.properties.deviceName);
+ ret = add_adapter_entry(&desc, i);
+ heap_free(desc.device_name);
+ if (!ret)
+ goto fail;
+ }
+
+fail:
+ heap_free(devices);
+ vk_funcs->p_vkDestroyInstance(instance, NULL);
+ return ret;
+}
+
+static void init_default_adpater(void)
+{
+ WCHAR device_name[] = {'W', 'i', 'n', 'e', ' ', 'X', '1', '1', ' ', 'D', 'r', 'i', 'v', 'e', 'r', 0};
+ struct adapter_desc desc = {0, 0, {0}, device_name};
+ if (!add_adapter_entry(&desc, 0))
+ ERR("Failed to initialize the default adapter\n");
+}
+
+static void delete_all_adapters(void)
+{
+ HDEVINFO devinfo;
+ SP_DEVINFO_DATA devinfo_data = {0};
+ DWORD i = 0;
+ BOOL result;
+
+ devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, 0);
+ if (devinfo == INVALID_HANDLE_VALUE)
+ return;
+
+ while (SetupDiEnumDeviceInfo(devinfo, i++, &devinfo_data))
+ {
+ result = SetupDiRemoveDevice(devinfo, &devinfo_data);
+ if (!result)
+ ERR("Failed to remove adapter %d\n", i);
+ }
+
+ SetupDiDestroyDeviceInfoList(devinfo);
+}
+
+void X11DRV_Adapter_Init(void)
+{
+ delete_all_adapters();
+ if (!init_vulkan_adapters())
+ {
+ WARN("Failed to enumerate adapters via Vulkan, fallling back to using the default adapter\n");
+ init_default_adpater();
+ }
+}
\ No newline at end of file
diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c
index 326873314c..f27d0e178f 100644
--- a/dlls/winex11.drv/init.c
+++ b/dlls/winex11.drv/init.c
@@ -59,6 +59,9 @@ static BOOL WINAPI device_init( INIT_ONCE *once, void *param, void **context )
stock_bitmap_pixmap = XCreatePixmap( gdi_display, root_window, 1, 1, 1 );
+ /* Enumerate adapters */
+ X11DRV_Adapter_Init();
+
return TRUE;
}
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index a0308b0675..608eda1db5 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -194,6 +194,7 @@ extern BOOL X11DRV_UnrealizePalette( HPALETTE hpal ) DECLSPEC_HIDDEN;
extern void X11DRV_Xcursor_Init(void) DECLSPEC_HIDDEN;
extern void X11DRV_XInput2_Init(void) DECLSPEC_HIDDEN;
+extern void X11DRV_Adapter_Init(void) DECLSPEC_HIDDEN;
extern DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
--
2.19.2