[RFC PATCH] winevulkan: Fill in device LUID from corresponding DXGI adapter.
Zhiyi Zhang
zzhang at codeweavers.com
Sat Mar 7 02:23:49 CST 2020
Hi Brendan,
LUIDs should be allocated in winex11/winemac user graphics drivers for each GPU,
and store them in SetupAPI. So that applications querying through SetupAPI or
registry have a unified view. A GUID is currently allocated for each GPU[1],
so it's easy to do the same for LUIDs as well. LUIDs can be stored as a SetupAPI
device property[2] using the DEVPROPKEY_DISPLAY_ADAPTER_LUID key.
Winevulkan/OpenGL should build on SetupAPI to query LUIDs for each physical device.
Specifically, winevulkan thunks vkGetPhysicalDeviceProperties2 to fill in LUID.
OpenGL in wine implements EXT_external_objects_win32[3] to report LUID.
Then wined3d can use LUIDs from winevulkan/OpenGL to fill in LUID for wined3d
adapters. Finally, DXGI gets adapter LUID from wined3d.
For a single GPU system. We can even use adapter ordinals as LUID(Proton hack).
A problem arises when multiple GPUs are present, we need to establish one-to-one
relationships for devices in each layer so that LUIDs can be used to uniquely
identify a device. Now, this is where things get tricky.
In winex11, GPUs are enumerated via XRandR extension. GPUs listed in XRandR mean
they're GDI-capable, but not necessarily OpenGL/Vulkan capable. So there may be
more GPUs in winex11 than in OpenGL/Vulkan. Also, the order of GPUs that get
enumerated in winex11 might be different from that in OpenGL/Vulkan so you can't
match them reliably. PCI IDs[4] help to guess the relationships but it still has
problems when GPUs have the same model. In essence, we need something like LUID
in native OpenGL/Vulkan/XRandR to match them, which I haven't found any. So to
solve this ultimately, a new extension in OpenGL/Vulkan/XRandR may to be introduced.
There're some discussions about LUID before in the wine-devel mail list[5].
That should give you more insight.
Thanks,
Zhiyi
[1]: wine/dlls/winex11.drv/display.c#X11DRV_InitGpu()
[2]: SetupDiGet/SetDevicePropertyW
[3]: https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_external_objects_win32.txt
[4]: https://source.winehq.org/patches/data/179386
[5]: https://www.winehq.org/pipermail/wine-devel/2018-December/136978.html
On 3/7/20 7:23 AM, Brendan Shanks wrote:
> ---
> Red Dead Redemption 2 relies on the deviceLUID returned by
> vkGetPhysicalDeviceProperties2() matching up with the LUID reported by
> other Windows APIs. This patch uses DXGI to enumerate adapters, and uses
> the LUID of the D3D adapter matching the UUID provided through Vulkan.
>
> The patch works, but I could see problems arising in case EnumAdapters()
> was backed by Vulkan and called vkGetPhysicalDeviceProperties2() itself.
>
> Would it be preferable to cache the UUID/LUID pairs in wine_vk_init()?
> Or should DXGI not be used at all, in favor of reading these out of the
> registry (with changes needed to wined3d)?
>
>
> dlls/winevulkan/Makefile.in | 2 +-
> dlls/winevulkan/make_vulkan | 2 +
> dlls/winevulkan/vulkan.c | 89 +++++++++++++++++++++++++++++++++
> dlls/winevulkan/vulkan_thunks.c | 10 +---
> dlls/winevulkan/vulkan_thunks.h | 4 ++
> 5 files changed, 98 insertions(+), 9 deletions(-)
>
> diff --git a/dlls/winevulkan/Makefile.in b/dlls/winevulkan/Makefile.in
> index e0bca6fad7..c112581e1e 100644
> --- a/dlls/winevulkan/Makefile.in
> +++ b/dlls/winevulkan/Makefile.in
> @@ -1,6 +1,6 @@
> MODULE = winevulkan.dll
> IMPORTLIB = winevulkan
> -IMPORTS = user32 gdi32
> +IMPORTS = dxgi user32 gdi32
>
> C_SRCS = \
> vulkan.c \
> diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
> index 3593410041..1879d640e0 100755
> --- a/dlls/winevulkan/make_vulkan
> +++ b/dlls/winevulkan/make_vulkan
> @@ -165,6 +165,8 @@ FUNCTION_OVERRIDES = {
> "vkGetPhysicalDeviceExternalFenceProperties" : {"dispatch" : False, "driver" : False, "thunk" : False},
> "vkGetPhysicalDeviceExternalSemaphoreProperties" : {"dispatch" : False, "driver" : False, "thunk" : False},
> "vkGetPhysicalDeviceImageFormatProperties2" : {"dispatch" : True, "driver" : False, "thunk" : True, "private_thunk" : True},
> + "vkGetPhysicalDeviceProperties2" : {"dispatch" : True, "driver" : False, "thunk" : False, "private_thunk" : True},
> + "vkGetPhysicalDeviceProperties2KHR" : {"dispatch" : True, "driver" : False, "thunk" : False, "private_thunk" : True},
>
> # Device functions
> "vkAllocateCommandBuffers" : {"dispatch" : True, "driver" : False, "thunk" : False},
> diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
> index 59472bcef8..2ef39ada79 100644
> --- a/dlls/winevulkan/vulkan.c
> +++ b/dlls/winevulkan/vulkan.c
> @@ -19,10 +19,16 @@
>
> #include <stdarg.h>
>
> +#define COBJMACROS
> #include "windef.h"
> #include "winbase.h"
> #include "winuser.h"
>
> +#include "initguid.h"
> +#include "dxgi.h"
> +#include "wine/wined3d.h"
> +#include "wine/winedxgi.h"
> +
> #include "vulkan_private.h"
>
> WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
> @@ -1261,6 +1267,89 @@ void WINAPI wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDev
> properties->externalSemaphoreFeatures = 0;
> }
>
> +static BOOL get_luid_for_device_uuid(const UUID *uuid, LUID *luid)
> +{
> + UINT i = 0;
> + BOOL found = FALSE;
> + IDXGIFactory *factory = NULL;
> + IDXGIAdapter *adapter = NULL;
> +
> + if (FAILED(CreateDXGIFactory(&IID_IDXGIFactory, (void **)&factory))) return FALSE;
> +
> + while (!found && IDXGIFactory_EnumAdapters(factory, i, &adapter) != DXGI_ERROR_NOT_FOUND)
> + {
> + IWineDXGIAdapter *wine_adapter = NULL;
> + if (SUCCEEDED(IUnknown_QueryInterface(adapter, &IID_IWineDXGIAdapter, (void **)&wine_adapter)))
> + {
> + struct wine_dxgi_adapter_info adapter_info;
> + if (SUCCEEDED(IWineDXGIAdapter_get_adapter_info(wine_adapter, &adapter_info)))
> + {
> + if (IsEqualGUID(uuid, &adapter_info.device_uuid))
> + {
> + *luid = adapter_info.luid;
> + found = TRUE;
> + }
> + }
> +
> + IWineDXGIAdapter_Release(wine_adapter);
> + }
> +
> + IDXGIAdapter_Release(adapter);
> + i++;
> + }
> +
> + if (factory) IDXGIFactory_Release(factory);
> + return found;
> +}
> +
> +void WINAPI wine_vkGetPhysicalDeviceProperties2(VkPhysicalDevice physical_device,
> + VkPhysicalDeviceProperties2 *properties)
> +{
> + VkPhysicalDeviceIDProperties *idprops;
> +
> + TRACE("%p, %p\n", physical_device, properties);
> + thunk_vkGetPhysicalDeviceProperties2(physical_device, properties);
> +
> + if ((idprops = wine_vk_find_struct(properties, PHYSICAL_DEVICE_ID_PROPERTIES)))
> + {
> + UUID *deviceUUID = (UUID *)idprops->deviceUUID;
> + LUID *luid = (LUID *)idprops->deviceLUID;
> + if (get_luid_for_device_uuid(deviceUUID, luid))
> + {
> + idprops->deviceNodeMask = 1;
> + idprops->deviceLUIDValid = VK_TRUE;
> + }
> + else
> + {
> + WARN("Failed to find corresponding adapter LUID for device UUID %s.\n", debugstr_guid(deviceUUID));
> + }
> + }
> +}
> +
> +void WINAPI wine_vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice physical_device,
> + VkPhysicalDeviceProperties2 *properties)
> +{
> + VkPhysicalDeviceIDProperties *idprops;
> +
> + TRACE("%p, %p\n", physical_device, properties);
> + thunk_vkGetPhysicalDeviceProperties2KHR(physical_device, properties);
> +
> + if ((idprops = wine_vk_find_struct(properties, PHYSICAL_DEVICE_ID_PROPERTIES)))
> + {
> + UUID *deviceUUID = (UUID *)idprops->deviceUUID;
> + LUID *luid = (LUID *)idprops->deviceLUID;
> + if (get_luid_for_device_uuid(deviceUUID, luid))
> + {
> + idprops->deviceNodeMask = 1;
> + idprops->deviceLUIDValid = VK_TRUE;
> + }
> + else
> + {
> + WARN("Failed to find corresponding adapter LUID for device UUID %s.\n", debugstr_guid(deviceUUID));
> + }
> + }
> +}
> +
> BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved)
> {
> TRACE("%p, %u, %p\n", hinst, reason, reserved);
> diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c
> index fecf9ab502..89878f189a 100644
> --- a/dlls/winevulkan/vulkan_thunks.c
> +++ b/dlls/winevulkan/vulkan_thunks.c
> @@ -4268,34 +4268,28 @@ void WINAPI wine_vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice,
> #endif
> }
>
> -void WINAPI wine_vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties)
> +void thunk_vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties)
> {
> #if defined(USE_STRUCT_CONVERSION)
> VkPhysicalDeviceProperties2_host pProperties_host;
> - TRACE("%p, %p\n", physicalDevice, pProperties);
> -
> convert_VkPhysicalDeviceProperties2_win_to_host(pProperties, &pProperties_host);
> physicalDevice->instance->funcs.p_vkGetPhysicalDeviceProperties2(physicalDevice->phys_dev, &pProperties_host);
>
> convert_VkPhysicalDeviceProperties2_host_to_win(&pProperties_host, pProperties);
> #else
> - TRACE("%p, %p\n", physicalDevice, pProperties);
> physicalDevice->instance->funcs.p_vkGetPhysicalDeviceProperties2(physicalDevice->phys_dev, pProperties);
> #endif
> }
>
> -static void WINAPI wine_vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties)
> +void thunk_vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties)
> {
> #if defined(USE_STRUCT_CONVERSION)
> VkPhysicalDeviceProperties2_host pProperties_host;
> - TRACE("%p, %p\n", physicalDevice, pProperties);
> -
> convert_VkPhysicalDeviceProperties2_win_to_host(pProperties, &pProperties_host);
> physicalDevice->instance->funcs.p_vkGetPhysicalDeviceProperties2KHR(physicalDevice->phys_dev, &pProperties_host);
>
> convert_VkPhysicalDeviceProperties2_host_to_win(&pProperties_host, pProperties);
> #else
> - TRACE("%p, %p\n", physicalDevice, pProperties);
> physicalDevice->instance->funcs.p_vkGetPhysicalDeviceProperties2KHR(physicalDevice->phys_dev, pProperties);
> #endif
> }
> diff --git a/dlls/winevulkan/vulkan_thunks.h b/dlls/winevulkan/vulkan_thunks.h
> index 01c1efb277..9896112176 100644
> --- a/dlls/winevulkan/vulkan_thunks.h
> +++ b/dlls/winevulkan/vulkan_thunks.h
> @@ -64,11 +64,15 @@ void WINAPI wine_vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice
> void WINAPI wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, VkExternalSemaphoreProperties *pExternalSemaphoreProperties) DECLSPEC_HIDDEN;
> VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties);
> VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties) DECLSPEC_HIDDEN;
> +void WINAPI wine_vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties);
> +void WINAPI wine_vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties) DECLSPEC_HIDDEN;
> VkResult WINAPI wine_vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence);
>
> /* Private thunks */
> VkResult thunk_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties) DECLSPEC_HIDDEN;
> VkResult thunk_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties) DECLSPEC_HIDDEN;
> +void thunk_vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties) DECLSPEC_HIDDEN;
> +void thunk_vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties) DECLSPEC_HIDDEN;
>
> typedef struct VkAcquireNextImageInfoKHR_host
> {
More information about the wine-devel
mailing list