[PATCH v2 1/7] winevulkan: Implement device extension enumeration.

Józef Kucia jkucia at codeweavers.com
Wed Mar 14 07:11:50 CDT 2018


From: Roderick Colenbrander <thunderbird2k at gmail.com>

Signed-off-by: Roderick Colenbrander <thunderbird2k at gmail.com>
Signed-off-by: Józef Kucia <jkucia at codeweavers.com>
---

Version 2:
* Remove redundant NULL check before heap_free().
* Use %u for unsigned integers.

---
 dlls/winevulkan/make_vulkan      |  22 +++++++
 dlls/winevulkan/vulkan.c         | 138 +++++++++++++++++++++++++++++++++++----
 dlls/winevulkan/vulkan_private.h |   4 ++
 dlls/winevulkan/vulkan_thunks.c  |  16 +++++
 dlls/winevulkan/vulkan_thunks.h  |   2 +
 5 files changed, 168 insertions(+), 14 deletions(-)

diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
index 5fff3f1511a1..b53203bd281e 100755
--- a/dlls/winevulkan/make_vulkan
+++ b/dlls/winevulkan/make_vulkan
@@ -1803,6 +1803,26 @@ class VkGenerator(object):
         f.write("        }\n")
         f.write("    }\n")
         f.write("    return NULL;\n")
+        f.write("}\n\n")
+
+        # Create array of device extensions.
+        f.write("static const char * const vk_device_extensions[] =\n{\n")
+        for ext in self.registry.extensions:
+            if ext["type"] != "device":
+                continue
+
+            f.write("    \"{0}\",\n".format(ext["name"]))
+        f.write("};\n\n")
+
+        f.write("BOOL wine_vk_device_extension_supported(const char *name)\n")
+        f.write("{\n")
+        f.write("    unsigned int i;\n")
+        f.write("    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)\n")
+        f.write("    {\n")
+        f.write("        if (strcmp(vk_device_extensions[i], name) == 0)\n")
+        f.write("            return TRUE;\n")
+        f.write("    }\n")
+        f.write("    return FALSE;\n")
         f.write("}\n")
 
     def generate_thunks_h(self, f, prefix):
@@ -1820,6 +1840,8 @@ class VkGenerator(object):
         f.write("void *wine_vk_get_device_proc_addr(const char *name) DECLSPEC_HIDDEN;\n")
         f.write("void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;\n\n")
 
+        f.write("BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;\n\n")
+
         # Generate prototypes for device and instance functions requiring a custom implementation.
         f.write("/* Functions for which we have custom implementations outside of the thunks. */\n")
         for vk_func in self.registry.funcs.values():
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index fe1f85121fc3..7b0fb37a00ee 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -46,6 +46,9 @@ struct wine_vk_structure_header
 };
 
 static void *wine_vk_get_global_proc_addr(const char *name);
+static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstance_T *instance,
+        VkPhysicalDevice phys_dev_host);
+static void wine_vk_physical_device_free(struct VkPhysicalDevice_T *phys_dev);
 
 static const struct vulkan_funcs *vk_funcs = NULL;
 
@@ -170,7 +173,7 @@ static VkResult wine_vk_instance_load_physical_devices(struct VkInstance_T *inst
     /* Wrap each native physical device handle into a dispatchable object for the ICD loader. */
     for (i = 0; i < num_phys_devs; i++)
     {
-        struct VkPhysicalDevice_T *phys_dev = heap_alloc(sizeof(*phys_dev));
+        struct VkPhysicalDevice_T *phys_dev = wine_vk_physical_device_alloc(instance, tmp_phys_devs[i]);
         if (!phys_dev)
         {
             ERR("Unable to allocate memory for physical device!\n");
@@ -178,10 +181,6 @@ static VkResult wine_vk_instance_load_physical_devices(struct VkInstance_T *inst
             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 + 1;
     }
@@ -192,7 +191,6 @@ static VkResult wine_vk_instance_load_physical_devices(struct VkInstance_T *inst
 
 err:
     heap_free(tmp_phys_devs);
-
     return res;
 }
 
@@ -210,7 +208,7 @@ static void wine_vk_instance_free(struct VkInstance_T *instance)
 
         for (i = 0; i < instance->num_phys_devs; i++)
         {
-            heap_free(&instance->phys_devs[i]);
+            wine_vk_physical_device_free(instance->phys_devs[i]);
         }
         heap_free(instance->phys_devs);
     }
@@ -221,6 +219,99 @@ static void wine_vk_instance_free(struct VkInstance_T *instance)
     heap_free(instance);
 }
 
+static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstance_T *instance,
+        VkPhysicalDevice phys_dev)
+{
+    struct VkPhysicalDevice_T *object;
+    uint32_t num_host_properties, num_properties = 0;
+    VkExtensionProperties *host_properties = NULL;
+    VkResult res;
+    unsigned int i, j;
+
+    object = heap_alloc_zero(sizeof(*object));
+    if (!object)
+        return NULL;
+
+    object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
+    object->instance = instance;
+    object->phys_dev = phys_dev;
+
+    res = instance->funcs.p_vkEnumerateDeviceExtensionProperties(phys_dev,
+            NULL, &num_host_properties, NULL);
+    if (res != VK_SUCCESS)
+    {
+        ERR("Failed to enumerate device extensions, res=%d\n", res);
+        goto err;
+    }
+
+    host_properties = heap_calloc(num_host_properties, sizeof(*host_properties));
+    if (!host_properties)
+    {
+        ERR("Failed to allocate memory for device properties!\n");
+        goto err;
+    }
+
+    res = instance->funcs.p_vkEnumerateDeviceExtensionProperties(phys_dev,
+            NULL, &num_host_properties, host_properties);
+    if (res != VK_SUCCESS)
+    {
+        ERR("Failed to enumerate device extensions, res=%d\n", res);
+        goto err;
+    }
+
+    /* Count list of extensions for which we have an implementation.
+     * TODO: perform translation for platform specific extensions.
+     */
+    for (i = 0; i < num_host_properties; i++)
+    {
+        if (wine_vk_device_extension_supported(host_properties[i].extensionName))
+        {
+            TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object);
+            num_properties++;
+        }
+        else
+        {
+            TRACE("Skipping extension '%s', no implementation found in winevulkan.\n", host_properties[i].extensionName);
+        }
+    }
+
+    TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties, num_properties);
+
+    object->properties = heap_calloc(num_properties, sizeof(*object->properties));
+    if (!object->properties)
+    {
+        ERR("Failed to allocate memory for device properties!\n");
+        goto err;
+    }
+
+    for (i = 0, j = 0; i < num_host_properties; i++)
+    {
+        if (wine_vk_device_extension_supported(host_properties[i].extensionName))
+        {
+            memcpy(&object->properties[j], &host_properties[i], sizeof(*object->properties));
+            j++;
+        }
+    }
+    object->num_properties = num_properties;
+
+    heap_free(host_properties);
+    return object;
+
+err:
+    wine_vk_physical_device_free(object);
+    heap_free(host_properties);
+    return NULL;
+}
+
+static void wine_vk_physical_device_free(struct VkPhysicalDevice_T *phys_dev)
+{
+    if (!phys_dev)
+        return;
+
+    heap_free(phys_dev->properties);
+    heap_free(phys_dev);
+}
+
 VkResult WINAPI wine_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain,
         uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *image_index)
 {
@@ -460,6 +551,9 @@ void WINAPI wine_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain
 VkResult WINAPI wine_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice phys_dev,
         const char *layer_name, uint32_t *count, VkExtensionProperties *properties)
 {
+    VkResult res;
+    unsigned int i, num_copies;
+
     TRACE("%p, %p, %p, %p\n", phys_dev, layer_name, count, properties);
 
     /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
@@ -471,16 +565,32 @@ VkResult WINAPI wine_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice phys_
 
     if (!properties)
     {
-        *count = 0; /* No extensions yet. */
+        *count = phys_dev->num_properties;
         return VK_SUCCESS;
     }
 
-    /* When properties is not NULL, we copy the extensions over and set count to
-     * the number of copied extensions. For now we don't have much to do as we don't support
-     * any extensions yet.
-     */
-    *count = 0;
-    return VK_SUCCESS;
+    if (*count < phys_dev->num_properties)
+    {
+        /* Incomplete is a type of success used to signal the application
+         * that not all devices got copied.
+         */
+        num_copies = *count;
+        res = VK_INCOMPLETE;
+    }
+    else
+    {
+        num_copies = phys_dev->num_properties;
+        res = VK_SUCCESS;
+    }
+
+    for (i = 0; i < num_copies; i++)
+    {
+        memcpy(&properties[i], &phys_dev->properties[i], sizeof(phys_dev->properties[i]));
+    }
+    *count = num_copies;
+
+    TRACE("Result %d, extensions copied %u\n", res, num_copies);
+    return res;
 }
 
 static VkResult WINAPI wine_vkEnumerateInstanceExtensionProperties(const char *layer_name,
diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h
index 897c1e1418da..d49366fa5fb1 100644
--- a/dlls/winevulkan/vulkan_private.h
+++ b/dlls/winevulkan/vulkan_private.h
@@ -74,6 +74,10 @@ struct VkPhysicalDevice_T
 {
     struct wine_vk_base base;
     struct VkInstance_T *instance; /* parent */
+
+    uint32_t num_properties;
+    VkExtensionProperties *properties;
+
     VkPhysicalDevice phys_dev; /* native physical device */
 };
 
diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c
index 5d9826cd6756..dfda842b664b 100644
--- a/dlls/winevulkan/vulkan_thunks.c
+++ b/dlls/winevulkan/vulkan_thunks.c
@@ -1073,3 +1073,19 @@ void *wine_vk_get_instance_proc_addr(const char *name)
     }
     return NULL;
 }
+
+static const char * const vk_device_extensions[] =
+{
+    "VK_KHR_swapchain",
+};
+
+BOOL wine_vk_device_extension_supported(const char *name)
+{
+    unsigned int i;
+    for (i = 0; i < ARRAY_SIZE(vk_device_extensions); i++)
+    {
+        if (strcmp(vk_device_extensions[i], name) == 0)
+            return TRUE;
+    }
+    return FALSE;
+}
diff --git a/dlls/winevulkan/vulkan_thunks.h b/dlls/winevulkan/vulkan_thunks.h
index a91612e62b69..13c1228196ae 100644
--- a/dlls/winevulkan/vulkan_thunks.h
+++ b/dlls/winevulkan/vulkan_thunks.h
@@ -12,6 +12,8 @@
 void *wine_vk_get_device_proc_addr(const char *name) DECLSPEC_HIDDEN;
 void *wine_vk_get_instance_proc_addr(const char *name) DECLSPEC_HIDDEN;
 
+BOOL wine_vk_device_extension_supported(const char *name) DECLSPEC_HIDDEN;
+
 /* Functions for which we have custom implementations outside of the thunks. */
 VkResult WINAPI wine_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex) DECLSPEC_HIDDEN;
 VkResult WINAPI wine_vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDevice *pDevice) DECLSPEC_HIDDEN;
-- 
2.16.1




More information about the wine-devel mailing list