From: Roderick Colenbrander <thunderbird2k(a)gmail.com>
Signed-off-by: Roderick Colenbrander <thunderbird2k(a)gmail.com>
Signed-off-by: Józef Kucia <jkucia(a)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