Signed-off-by: Roderick Colenbrander thunderbird2k@gmail.com --- dlls/winevulkan/make_vulkan | 32 ++++++++++++++++++++++++++++---- dlls/winevulkan/vulkan.c | 9 +++++++++ dlls/winevulkan/vulkan_private.h | 1 + dlls/winevulkan/vulkan_thunks.h | 29 +++++++++++++++++++++++++++++ dlls/winex11.drv/vulkan.c | 6 ++++-- 5 files changed, 71 insertions(+), 6 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 6c6cf2ea3c..5657b70c4c 100755 --- a/dlls/winevulkan/make_vulkan +++ b/dlls/winevulkan/make_vulkan @@ -1035,17 +1035,41 @@ class VkGenerator(object): # 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(): + if not vk_func.is_required() or vk_func.is_global_func() or vk_func.needs_thunk(): + continue + + f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN"))) + f.write("\n") + + f.write("/* For use by vkInstance and children */\n") + f.write("struct vulkan_instance_funcs\n{\n") + for vk_func in self.registry.instance_funcs: if not vk_func.is_required(): continue
- if vk_func.is_global_func(): + if not vk_func.needs_dispatch() or vk_func.is_driver_func(): + LOGGER.debug("skipping {0} in vulkan_instance_funcs".format(vk_func.name)) continue
- if vk_func.needs_thunk(): + f.write(" {0};\n".format(vk_func.pfn(conv=False))) + f.write("};\n\n") + + f.write("#define ALL_VK_INSTANCE_FUNCS() \\n") + first = True + for vk_func in self.registry.instance_funcs: + if not vk_func.is_required(): continue
- f.write("{0};\n".format(vk_func.prototype("WINAPI", prefix="wine_", postfix="DECLSPEC_HIDDEN"))) - f.write("\n") + if not vk_func.needs_dispatch() or vk_func.is_driver_func(): + LOGGER.debug("skipping {0} in ALL_VK_INSTANCE_FUNCS".format(vk_func.name)) + continue + + if first: + f.write(" USE_VK_FUNC({0})".format(vk_func.name)) + first = False + else: + f.write("\\n USE_VK_FUNC({0})".format(vk_func.name)) + f.write("\n\n")
f.write("#endif /* __WINE_VULKAN_THUNKS_H */\n")
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 85836bdd42..0f48d971e2 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -99,6 +99,15 @@ static VkResult WINAPI wine_vkCreateInstance(const VkInstanceCreateInfo *create_ goto err; }
+ /* Load all instance functions we are aware of. Note the loader takes care + * of any filtering for extensions which were not requested, but which the + * ICD may support. + */ +#define USE_VK_FUNC(name) \ + object->funcs.p_##name = (void*)vk_funcs->p_vkGetInstanceProcAddr(object->instance, #name); + ALL_VK_INSTANCE_FUNCS() +#undef USE_VK_FUNC + *instance = object; TRACE("Done, instance=%p native_instance=%p\n", object, object->instance); return VK_SUCCESS; diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h index 5688137833..16aa0ce55c 100644 --- a/dlls/winevulkan/vulkan_private.h +++ b/dlls/winevulkan/vulkan_private.h @@ -51,6 +51,7 @@ struct wine_vk_base struct VkInstance_T { struct wine_vk_base base; + struct vulkan_instance_funcs funcs; VkInstance instance; /* native instance */ };
diff --git a/dlls/winevulkan/vulkan_thunks.h b/dlls/winevulkan/vulkan_thunks.h index 969bf125f9..087fa17d0e 100644 --- a/dlls/winevulkan/vulkan_thunks.h +++ b/dlls/winevulkan/vulkan_thunks.h @@ -9,4 +9,33 @@ 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;
+/* For use by vkInstance and children */ +struct vulkan_instance_funcs +{ + VkResult (*p_vkCreateDevice)(VkPhysicalDevice, const VkDeviceCreateInfo *, const VkAllocationCallbacks *, VkDevice *); + VkResult (*p_vkEnumerateDeviceExtensionProperties)(VkPhysicalDevice, const char *, uint32_t *, VkExtensionProperties *); + VkResult (*p_vkEnumerateDeviceLayerProperties)(VkPhysicalDevice, uint32_t *, VkLayerProperties *); + VkResult (*p_vkEnumeratePhysicalDevices)(VkInstance, uint32_t *, VkPhysicalDevice *); + void (*p_vkGetPhysicalDeviceFeatures)(VkPhysicalDevice, VkPhysicalDeviceFeatures *); + void (*p_vkGetPhysicalDeviceFormatProperties)(VkPhysicalDevice, VkFormat, VkFormatProperties *); + VkResult (*p_vkGetPhysicalDeviceImageFormatProperties)(VkPhysicalDevice, VkFormat, VkImageType, VkImageTiling, VkImageUsageFlags, VkImageCreateFlags, VkImageFormatProperties *); + void (*p_vkGetPhysicalDeviceMemoryProperties)(VkPhysicalDevice, VkPhysicalDeviceMemoryProperties *); + void (*p_vkGetPhysicalDeviceProperties)(VkPhysicalDevice, VkPhysicalDeviceProperties *); + void (*p_vkGetPhysicalDeviceQueueFamilyProperties)(VkPhysicalDevice, uint32_t *, VkQueueFamilyProperties *); + void (*p_vkGetPhysicalDeviceSparseImageFormatProperties)(VkPhysicalDevice, VkFormat, VkImageType, VkSampleCountFlagBits, VkImageUsageFlags, VkImageTiling, uint32_t *, VkSparseImageFormatProperties *); +}; + +#define ALL_VK_INSTANCE_FUNCS() \ + USE_VK_FUNC(vkCreateDevice)\ + USE_VK_FUNC(vkEnumerateDeviceExtensionProperties)\ + USE_VK_FUNC(vkEnumerateDeviceLayerProperties)\ + USE_VK_FUNC(vkEnumeratePhysicalDevices)\ + USE_VK_FUNC(vkGetPhysicalDeviceFeatures)\ + USE_VK_FUNC(vkGetPhysicalDeviceFormatProperties)\ + USE_VK_FUNC(vkGetPhysicalDeviceImageFormatProperties)\ + USE_VK_FUNC(vkGetPhysicalDeviceMemoryProperties)\ + USE_VK_FUNC(vkGetPhysicalDeviceProperties)\ + USE_VK_FUNC(vkGetPhysicalDeviceQueueFamilyProperties)\ + USE_VK_FUNC(vkGetPhysicalDeviceSparseImageFormatProperties) + #endif /* __WINE_VULKAN_THUNKS_H */ diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index adc3da35e4..c3fed9e58a 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -36,6 +36,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks *); +static void * (*pvkGetInstanceProcAddr)(VkInstance, const char *);
static BOOL wine_vk_init(void) { @@ -50,6 +51,7 @@ static BOOL wine_vk_init(void) #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(vulkan_handle, #f, NULL, 0)) == NULL) return FALSE; LOAD_FUNCPTR(vkCreateInstance) LOAD_FUNCPTR(vkDestroyInstance) +LOAD_FUNCPTR(vkGetInstanceProcAddr) #undef LOAD_FUNCPTR
return TRUE; @@ -116,8 +118,8 @@ static VkResult X11DRV_vkEnumerateInstanceExtensionProperties(const char *layer_
static void * X11DRV_vkGetInstanceProcAddr(VkInstance instance, const char *name) { - FIXME("stub: %p, %s\n", instance, debugstr_a(name)); - return NULL; + TRACE("%p, %s\n", instance, debugstr_a(name)); + return pvkGetInstanceProcAddr(instance, name); }
static const struct vulkan_funcs vulkan_funcs =
Signed-off-by: Roderick Colenbrander thunderbird2k@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
On Fri, Mar 2, 2018 at 7:13 AM, Roderick Colenbrander thunderbird2k@gmail.com wrote:
Signed-off-by: Roderick Colenbrander thunderbird2k@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;
instance->phys_devs isn't initialized.
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;
This leaves a lot of fields uninitialized in "instance". We don't want to crash in wine_vk_instance_free().
- 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));
heap_calloc() may be more suitable.
- 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));
struct VkPhysicalDevice_T *
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);
It's fine to call heap_free() with NULL.
- 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);
- }
It might crash because "phys_devs" is uninitialized. We probably want to use heap_alloc_zero() to allocate "instance".
- 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
On Fri, Mar 2, 2018 at 3:57 AM, Józef Kucia joseph.kucia@gmail.com wrote:
On Fri, Mar 2, 2018 at 7:13 AM, Roderick Colenbrander thunderbird2k@gmail.com wrote:
Signed-off-by: Roderick Colenbrander thunderbird2k@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;
instance->phys_devs isn't initialized.
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;
This leaves a lot of fields uninitialized in "instance". We don't want to crash in wine_vk_instance_free().
- 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));
heap_calloc() may be more suitable.
- 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));
struct VkPhysicalDevice_T *
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);
It's fine to call heap_free() with NULL.
I believe it results in undefined behaviour, that's what MSDN told me and our heap_alloc doesn't have guards for NULL.
From MSDN:
"A pointer to the memory block to be freed. This pointer is returned by the HeapAlloc or HeapReAlloc function. If this pointer is NULL, the behavior is undefined."
- 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);
- }
It might crash because "phys_devs" is uninitialized. We probably want to use heap_alloc_zero() to allocate "instance".
You are right. I used to have a wine_vk_alloc or some call before heap_alloc got introduced, which did the zero'ing. Forgot to change this spot to heap_alloc_zero.
- 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
Signed-off-by: Roderick Colenbrander thunderbird2k@gmail.com --- dlls/winevulkan/make_vulkan | 1 + dlls/winevulkan/vulkan.c | 26 ++++++++++++++++++++++++++ dlls/winevulkan/vulkan_thunks.c | 6 ------ dlls/winevulkan/vulkan_thunks.h | 1 + 4 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan index 3b045db8a9..7499cf7011 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 }, + "vkEnumerateDeviceExtensionProperties" : {"dispatch" : True, "driver" : False, "thunk" : False}, "vkEnumeratePhysicalDevices" : {"dispatch" : True, "driver" : False, "thunk" : False}, }
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index 234be589ae..f740459ee3 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -229,6 +229,32 @@ void WINAPI wine_vkDestroyInstance(VkInstance instance, const VkAllocationCallba wine_vk_instance_free(instance); }
+VkResult WINAPI wine_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice phys_dev, + const char *layer_name, uint32_t *count, VkExtensionProperties *properties) +{ + 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. */ + if (layer_name) + { + ERR("Layer enumeration not supported from ICD.\n"); + return VK_ERROR_LAYER_NOT_PRESENT; + } + + if (!properties) + { + *count = 0; /* No extensions yet. */ + 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; +} + static VkResult WINAPI wine_vkEnumerateInstanceExtensionProperties(const char *layer_name, uint32_t *count, VkExtensionProperties *properties) { diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c index ae4f773ef0..2e1b62d23c 100644 --- a/dlls/winevulkan/vulkan_thunks.c +++ b/dlls/winevulkan/vulkan_thunks.c @@ -16,12 +16,6 @@ static VkResult WINAPI wine_vkCreateDevice(VkPhysicalDevice physicalDevice, cons return VK_ERROR_OUT_OF_HOST_MEMORY; }
-static VkResult WINAPI wine_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName, uint32_t *pPropertyCount, VkExtensionProperties *pProperties) -{ - FIXME("stub: %p, %p, %p, %p\n", physicalDevice, pLayerName, pPropertyCount, pProperties); - return VK_ERROR_OUT_OF_HOST_MEMORY; -} - static VkResult WINAPI wine_vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkLayerProperties *pProperties) { FIXME("stub: %p, %p, %p\n", physicalDevice, pPropertyCount, pProperties); diff --git a/dlls/winevulkan/vulkan_thunks.h b/dlls/winevulkan/vulkan_thunks.h index 26e114ab74..b8d2bbdb0f 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_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice physicalDevice, const char *pLayerName, uint32_t *pPropertyCount, VkExtensionProperties *pProperties) DECLSPEC_HIDDEN; VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices) DECLSPEC_HIDDEN;
/* For use by vkInstance and children */