[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