Signed-off-by: Zhiyi Zhang zzhang@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,