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 3:
* Fixed off-by-one error in wine_vk_instance_load_physical_devices().
* Removed redundant memory cleanup in wine_vk_instance_load_physical_devices(),
wine_vk_instance_free() is able to free partially initialized VkInstance_T objects.
* Use %u for usigned integers.
---
dlls/winevulkan/make_vulkan | 1 +
dlls/winevulkan/vulkan.c | 126 ++++++++++++++++++++++++++++++++++++++-
dlls/winevulkan/vulkan_private.h | 14 +++++
dlls/winevulkan/vulkan_thunks.c | 6 --
dlls/winevulkan/vulkan_thunks.h | 1 +
5 files changed, 141 insertions(+), 7 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
index 5657b70c4c73..3b045db8a927 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 0f48d971e2be..a2223cfa7590 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -58,6 +58,69 @@ 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)
+ return VK_SUCCESS;
+
+ tmp_phys_devs = heap_calloc(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_calloc(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++)
+ {
+ struct VkPhysicalDevice_T *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 + 1;
+ }
+ instance->num_phys_devs = num_phys_devs;
+
+ heap_free(tmp_phys_devs);
+ return VK_SUCCESS;
+
+err:
+ heap_free(tmp_phys_devs);
+
+ 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 +129,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 */);
@@ -83,7 +157,7 @@ static VkResult WINAPI wine_vkCreateInstance(const VkInstanceCreateInfo *create_
if (allocator)
FIXME("Support for allocation callbacks not implemented yet\n");
- object = heap_alloc(sizeof(*object));
+ object = heap_alloc_zero(sizeof(*object));
if (!object)
{
ERR("Failed to allocate memory for instance\n");
@@ -108,6 +182,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 +220,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 %u 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 16aa0ce55cd4..8ef4b924a2b9 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 c1c0b079a534..ae4f773ef0d8 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 087fa17d0eee..26e114ab74fb 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.16.2