[PATCH 2/3] winevulkan: Implement vkEnumeratePhysicalDevices.

Roderick Colenbrander thunderbird2k at gmail.com
Fri Mar 2 00:13:36 CST 2018


Signed-off-by: Roderick Colenbrander <thunderbird2k at gmail.com>
---
 dlls/winevulkan/make_vulkan      |   1 +
 dlls/winevulkan/vulkan.c         | 140 +++++++++++++++++++++++++++++++++++++++
 dlls/winevulkan/vulkan_private.h |  14 ++++
 dlls/winevulkan/vulkan_thunks.c  |   6 --
 dlls/winevulkan/vulkan_thunks.h  |   1 +
 5 files changed, 156 insertions(+), 6 deletions(-)

diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
index 5657b70c4c..3b045db8a9 100755
--- a/dlls/winevulkan/make_vulkan
+++ b/dlls/winevulkan/make_vulkan
@@ -90,6 +90,7 @@ FUNCTION_OVERRIDES = {
 
     # Instance functions
     "vkDestroyInstance" : {"dispatch" : True, "driver" : True, "thunk" : False },
+    "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False},
 }
 
 
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index 0f48d971e2..234be589ae 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -58,6 +58,85 @@ static BOOL wine_vk_init(void)
     return TRUE;
 }
 
+/* Helper function which stores wrapped physical devices in the instance object. */
+static VkResult wine_vk_instance_load_physical_devices(struct VkInstance_T *instance)
+{
+    VkResult res;
+    struct VkPhysicalDevice_T **tmp_phys_devs = NULL;
+    uint32_t num_phys_devs = 0;
+    unsigned int i;
+
+    res = instance->funcs.p_vkEnumeratePhysicalDevices(instance->instance, &num_phys_devs, NULL);
+    if (res != VK_SUCCESS)
+    {
+        ERR("Failed to enumerate physical devices, res=%d\n", res);
+        return res;
+    }
+
+    /* Don't bother with any of the rest if the system just lacks devices. */
+    if (num_phys_devs == 0)
+    {
+        instance->num_phys_devs = 0;
+        return VK_SUCCESS;
+    }
+
+    tmp_phys_devs = heap_alloc(num_phys_devs * sizeof(*tmp_phys_devs));
+    if (!tmp_phys_devs)
+        return VK_ERROR_OUT_OF_HOST_MEMORY;
+
+    res = instance->funcs.p_vkEnumeratePhysicalDevices(instance->instance, &num_phys_devs, tmp_phys_devs);
+    if (res != VK_SUCCESS)
+        goto err;
+
+    instance->phys_devs = heap_alloc(num_phys_devs * sizeof(*instance->phys_devs));
+    if (!instance->phys_devs)
+    {
+        res = VK_ERROR_OUT_OF_HOST_MEMORY;
+        goto err;
+    }
+
+    /* Wrap each native physical device handle into a dispatchable object for the ICD loader. */
+    for (i = 0; i < num_phys_devs; i++)
+    {
+        VkPhysicalDevice phys_dev = heap_alloc(sizeof(*phys_dev));
+        if (!phys_dev)
+        {
+            ERR("Unable to allocate memory for physical device!\n");
+            res = VK_ERROR_OUT_OF_HOST_MEMORY;
+            goto err;
+        }
+
+        phys_dev->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
+        phys_dev->instance = instance;
+        phys_dev->phys_dev = tmp_phys_devs[i];
+
+        instance->phys_devs[i] = phys_dev;
+        instance->num_phys_devs = i;
+    }
+    instance->num_phys_devs = num_phys_devs;
+
+    heap_free(tmp_phys_devs);
+    return VK_SUCCESS;
+
+err:
+    if (tmp_phys_devs)
+        heap_free(tmp_phys_devs);
+
+    if (instance->phys_devs)
+    {
+        for (i = 0; i < instance->num_phys_devs; i++)
+        {
+            heap_free(instance->phys_devs[i]);
+            instance->phys_devs[i] = NULL;
+        }
+        heap_free(instance->phys_devs);
+        instance->num_phys_devs = 0;
+        instance->phys_devs = NULL;
+    }
+
+    return res;
+}
+
 /* Helper function used for freeing an instance structure. This function supports full
  * and partial object cleanups and can thus be used for vkCreateInstance failures.
  */
@@ -66,6 +145,17 @@ static void wine_vk_instance_free(struct VkInstance_T *instance)
     if (!instance)
         return;
 
+    if (instance->phys_devs)
+    {
+        unsigned int i;
+
+        for (i = 0; i < instance->num_phys_devs; i++)
+        {
+            heap_free(&instance->phys_devs[i]);
+        }
+        heap_free(instance->phys_devs);
+    }
+
     if (instance->instance)
         vk_funcs->p_vkDestroyInstance(instance->instance, NULL /* allocator */);
 
@@ -108,6 +198,18 @@ static VkResult WINAPI wine_vkCreateInstance(const VkInstanceCreateInfo *create_
     ALL_VK_INSTANCE_FUNCS()
 #undef USE_VK_FUNC
 
+    /* Cache physical devices for vkEnumeratePhysicalDevices within the instance as
+     * each vkPhysicalDevice is a dispatchable object, which means we need to wrap
+     * the native physical device and present those the application.
+     * Cleanup happens as part of wine_vkDestroyInstance.
+     */
+    res = wine_vk_instance_load_physical_devices(object);
+    if (res != VK_SUCCESS)
+    {
+        ERR("Failed to cache physical devices, res=%d\n", res);
+        goto err;
+    }
+
     *instance = object;
     TRACE("Done, instance=%p native_instance=%p\n", object, object->instance);
     return VK_SUCCESS;
@@ -134,6 +236,44 @@ static VkResult WINAPI wine_vkEnumerateInstanceExtensionProperties(const char *l
     return vk_funcs->p_vkEnumerateInstanceExtensionProperties(layer_name, count, properties);
 }
 
+VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *device_count,
+        VkPhysicalDevice *devices)
+{
+    VkResult res;
+    unsigned int i, num_copies;
+
+    TRACE("%p %p %p\n", instance, device_count, devices);
+
+    if (!devices)
+    {
+        *device_count = instance->num_phys_devs;
+        return VK_SUCCESS;
+    }
+
+    if (*device_count < instance->num_phys_devs)
+    {
+        /* Incomplete is a type of success used to signal the application
+         * that not all devices got copied.
+         */
+        num_copies = *device_count;
+        res = VK_INCOMPLETE;
+    }
+    else
+    {
+        num_copies = instance->num_phys_devs;
+        res = VK_SUCCESS;
+    }
+
+    for (i = 0; i < num_copies; i++)
+    {
+        devices[i] = instance->phys_devs[i];
+    }
+    *device_count = num_copies;
+
+    TRACE("Returning %d devices\n", *device_count);
+    return res;
+}
+
 static PFN_vkVoidFunction WINAPI wine_vkGetInstanceProcAddr(VkInstance instance, const char *name)
 {
     void *func;
diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h
index 16aa0ce55c..8ef4b924a2 100644
--- a/dlls/winevulkan/vulkan_private.h
+++ b/dlls/winevulkan/vulkan_private.h
@@ -52,7 +52,21 @@ struct VkInstance_T
 {
     struct wine_vk_base base;
     struct vulkan_instance_funcs funcs;
+
+    /* We cache devices as we need to wrap them as they are
+     * dispatchable objects.
+     */
+    uint32_t num_phys_devs;
+    struct VkPhysicalDevice_T **phys_devs;
+
     VkInstance instance; /* native instance */
 };
 
+struct VkPhysicalDevice_T
+{
+    struct wine_vk_base base;
+    struct VkInstance_T *instance; /* parent */
+    VkPhysicalDevice phys_dev; /* native physical device */
+};
+
 #endif /* __WINE_VULKAN_PRIVATE_H */
diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c
index c1c0b079a5..ae4f773ef0 100644
--- a/dlls/winevulkan/vulkan_thunks.c
+++ b/dlls/winevulkan/vulkan_thunks.c
@@ -28,12 +28,6 @@ static VkResult WINAPI wine_vkEnumerateDeviceLayerProperties(VkPhysicalDevice ph
     return VK_ERROR_OUT_OF_HOST_MEMORY;
 }
 
-static VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices)
-{
-    FIXME("stub: %p, %p, %p\n", instance, pPhysicalDeviceCount, pPhysicalDevices);
-    return VK_ERROR_OUT_OF_HOST_MEMORY;
-}
-
 static void WINAPI wine_vkGetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures)
 {
     FIXME("stub: %p, %p\n", physicalDevice, pFeatures);
diff --git a/dlls/winevulkan/vulkan_thunks.h b/dlls/winevulkan/vulkan_thunks.h
index 087fa17d0e..26e114ab74 100644
--- a/dlls/winevulkan/vulkan_thunks.h
+++ b/dlls/winevulkan/vulkan_thunks.h
@@ -8,6 +8,7 @@ void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;
 
 /* Functions for which we have custom implementations outside of the thunks. */
 void WINAPI wine_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator) DECLSPEC_HIDDEN;
+VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) DECLSPEC_HIDDEN;
 
 /* For use by vkInstance and children */
 struct vulkan_instance_funcs
-- 
2.14.3




More information about the wine-devel mailing list