Signed-off-by: Roderick Colenbrander thunderbird2k@gmail.com --- 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 5fff3f1511..ddae964457 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 *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 fe1f85121f..7b0a15f2af 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 %d, Wine supported extensions %d\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; + + if (phys_dev->properties) + 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 %d\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 897c1e1418..d49366fa5f 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 5d9826cd67..51de005a7f 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 *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 a91612e62b..13c1228196 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;