wined3d: Pass a wined3d_device_context to wined3d_cs_emit_blt_sub_resource().
[wine/zf.git] / dlls / winevulkan / vulkan.c
blobb20452957181fd6474224ef50bfbb71c2e72ab34
1 /* Wine Vulkan ICD implementation
3 * Copyright 2017 Roderick Colenbrander
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "config.h"
21 #include <time.h>
22 #include <stdarg.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winreg.h"
27 #include "winuser.h"
28 #include "initguid.h"
29 #include "devguid.h"
30 #include "setupapi.h"
32 #include "vulkan_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
36 DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2);
37 DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_GPU_VULKAN_UUID, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5c, 2);
39 /* For now default to 4 as it felt like a reasonable version feature wise to support.
40 * Version 5 adds more extensive version checks. Something to tackle later.
42 #define WINE_VULKAN_ICD_VERSION 4
44 #define wine_vk_find_struct(s, t) wine_vk_find_struct_((void *)s, VK_STRUCTURE_TYPE_##t)
45 static void *wine_vk_find_struct_(void *s, VkStructureType t)
47 VkBaseOutStructure *header;
49 for (header = s; header; header = header->pNext)
51 if (header->sType == t)
52 return header;
55 return NULL;
58 #define wine_vk_count_struct(s, t) wine_vk_count_struct_((void *)s, VK_STRUCTURE_TYPE_##t)
59 static uint32_t wine_vk_count_struct_(void *s, VkStructureType t)
61 const VkBaseInStructure *header;
62 uint32_t result = 0;
64 for (header = s; header; header = header->pNext)
66 if (header->sType == t)
67 result++;
70 return result;
73 static void *wine_vk_get_global_proc_addr(const char *name);
75 static HINSTANCE hinstance;
76 static const struct vulkan_funcs *vk_funcs;
77 static VkResult (*p_vkEnumerateInstanceVersion)(uint32_t *version);
79 void WINAPI wine_vkGetPhysicalDeviceProperties(VkPhysicalDevice physical_device,
80 VkPhysicalDeviceProperties *properties);
82 #define WINE_VK_ADD_DISPATCHABLE_MAPPING(instance, object, native_handle) \
83 wine_vk_add_handle_mapping((instance), (uint64_t) (uintptr_t) (object), (uint64_t) (uintptr_t) (native_handle), &(object)->mapping)
84 #define WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(instance, object, native_handle) \
85 wine_vk_add_handle_mapping((instance), (uint64_t) (uintptr_t) (object), (uint64_t) (native_handle), &(object)->mapping)
86 static void wine_vk_add_handle_mapping(struct VkInstance_T *instance, uint64_t wrapped_handle,
87 uint64_t native_handle, struct wine_vk_mapping *mapping)
89 if (instance->enable_wrapper_list)
91 mapping->native_handle = native_handle;
92 mapping->wine_wrapped_handle = wrapped_handle;
93 AcquireSRWLockExclusive(&instance->wrapper_lock);
94 list_add_tail(&instance->wrappers, &mapping->link);
95 ReleaseSRWLockExclusive(&instance->wrapper_lock);
99 #define WINE_VK_REMOVE_HANDLE_MAPPING(instance, object) \
100 wine_vk_remove_handle_mapping((instance), &(object)->mapping)
101 static void wine_vk_remove_handle_mapping(struct VkInstance_T *instance, struct wine_vk_mapping *mapping)
103 if (instance->enable_wrapper_list)
105 AcquireSRWLockExclusive(&instance->wrapper_lock);
106 list_remove(&mapping->link);
107 ReleaseSRWLockExclusive(&instance->wrapper_lock);
111 static uint64_t wine_vk_get_wrapper(struct VkInstance_T *instance, uint64_t native_handle)
113 struct wine_vk_mapping *mapping;
114 uint64_t result = 0;
116 AcquireSRWLockShared(&instance->wrapper_lock);
117 LIST_FOR_EACH_ENTRY(mapping, &instance->wrappers, struct wine_vk_mapping, link)
119 if (mapping->native_handle == native_handle)
121 result = mapping->wine_wrapped_handle;
122 break;
125 ReleaseSRWLockShared(&instance->wrapper_lock);
126 return result;
129 static VkBool32 debug_utils_callback_conversion(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
130 VkDebugUtilsMessageTypeFlagsEXT message_types,
131 #if defined(USE_STRUCT_CONVERSION)
132 const VkDebugUtilsMessengerCallbackDataEXT_host *callback_data,
133 #else
134 const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
135 #endif
136 void *user_data)
138 struct VkDebugUtilsMessengerCallbackDataEXT wine_callback_data;
139 VkDebugUtilsObjectNameInfoEXT *object_name_infos;
140 struct wine_debug_utils_messenger *object;
141 VkBool32 result;
142 unsigned int i;
144 TRACE("%i, %u, %p, %p\n", severity, message_types, callback_data, user_data);
146 object = user_data;
148 if (!object->instance->instance)
150 /* instance wasn't yet created, this is a message from the native loader */
151 return VK_FALSE;
154 wine_callback_data = *((VkDebugUtilsMessengerCallbackDataEXT *) callback_data);
156 object_name_infos = heap_calloc(wine_callback_data.objectCount, sizeof(*object_name_infos));
158 for (i = 0; i < wine_callback_data.objectCount; i++)
160 object_name_infos[i].sType = callback_data->pObjects[i].sType;
161 object_name_infos[i].pNext = callback_data->pObjects[i].pNext;
162 object_name_infos[i].objectType = callback_data->pObjects[i].objectType;
163 object_name_infos[i].pObjectName = callback_data->pObjects[i].pObjectName;
165 if (wine_vk_is_type_wrapped(callback_data->pObjects[i].objectType))
167 object_name_infos[i].objectHandle = wine_vk_get_wrapper(object->instance, callback_data->pObjects[i].objectHandle);
168 if (!object_name_infos[i].objectHandle)
170 WARN("handle conversion failed 0x%s\n", wine_dbgstr_longlong(callback_data->pObjects[i].objectHandle));
171 heap_free(object_name_infos);
172 return VK_FALSE;
175 else
177 object_name_infos[i].objectHandle = callback_data->pObjects[i].objectHandle;
181 wine_callback_data.pObjects = object_name_infos;
183 /* applications should always return VK_FALSE */
184 result = object->user_callback(severity, message_types, &wine_callback_data, object->user_data);
186 heap_free(object_name_infos);
188 return result;
191 static VkBool32 debug_report_callback_conversion(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT object_type,
192 uint64_t object_handle, size_t location, int32_t code, const char *layer_prefix, const char *message, void *user_data)
194 struct wine_debug_report_callback *object;
196 TRACE("%#x, %#x, 0x%s, 0x%s, %d, %p, %p, %p\n", flags, object_type, wine_dbgstr_longlong(object_handle),
197 wine_dbgstr_longlong(location), code, layer_prefix, message, user_data);
199 object = user_data;
201 if (!object->instance->instance)
203 /* instance wasn't yet created, this is a message from the native loader */
204 return VK_FALSE;
207 object_handle = wine_vk_get_wrapper(object->instance, object_handle);
208 if (!object_handle)
209 object_type = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;
211 return object->user_callback(
212 flags, object_type, object_handle, location, code, layer_prefix, message, object->user_data);
215 static void wine_vk_physical_device_free(struct VkPhysicalDevice_T *phys_dev)
217 if (!phys_dev)
218 return;
220 WINE_VK_REMOVE_HANDLE_MAPPING(phys_dev->instance, phys_dev);
221 heap_free(phys_dev->extensions);
222 heap_free(phys_dev);
225 static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstance_T *instance,
226 VkPhysicalDevice phys_dev)
228 struct VkPhysicalDevice_T *object;
229 uint32_t num_host_properties, num_properties = 0;
230 VkExtensionProperties *host_properties = NULL;
231 VkResult res;
232 unsigned int i, j;
234 if (!(object = heap_alloc_zero(sizeof(*object))))
235 return NULL;
237 object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
238 object->instance = instance;
239 object->phys_dev = phys_dev;
241 WINE_VK_ADD_DISPATCHABLE_MAPPING(instance, object, phys_dev);
243 res = instance->funcs.p_vkEnumerateDeviceExtensionProperties(phys_dev,
244 NULL, &num_host_properties, NULL);
245 if (res != VK_SUCCESS)
247 ERR("Failed to enumerate device extensions, res=%d\n", res);
248 goto err;
251 host_properties = heap_calloc(num_host_properties, sizeof(*host_properties));
252 if (!host_properties)
254 ERR("Failed to allocate memory for device properties!\n");
255 goto err;
258 res = instance->funcs.p_vkEnumerateDeviceExtensionProperties(phys_dev,
259 NULL, &num_host_properties, host_properties);
260 if (res != VK_SUCCESS)
262 ERR("Failed to enumerate device extensions, res=%d\n", res);
263 goto err;
266 /* Count list of extensions for which we have an implementation.
267 * TODO: perform translation for platform specific extensions.
269 for (i = 0; i < num_host_properties; i++)
271 if (wine_vk_device_extension_supported(host_properties[i].extensionName))
273 TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object);
274 num_properties++;
276 else
278 TRACE("Skipping extension '%s', no implementation found in winevulkan.\n", host_properties[i].extensionName);
282 TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties, num_properties);
284 if (!(object->extensions = heap_calloc(num_properties, sizeof(*object->extensions))))
286 ERR("Failed to allocate memory for device extensions!\n");
287 goto err;
290 for (i = 0, j = 0; i < num_host_properties; i++)
292 if (wine_vk_device_extension_supported(host_properties[i].extensionName))
294 object->extensions[j] = host_properties[i];
295 j++;
298 object->extension_count = num_properties;
300 heap_free(host_properties);
301 return object;
303 err:
304 wine_vk_physical_device_free(object);
305 heap_free(host_properties);
306 return NULL;
309 static void wine_vk_free_command_buffers(struct VkDevice_T *device,
310 struct wine_cmd_pool *pool, uint32_t count, const VkCommandBuffer *buffers)
312 unsigned int i;
314 for (i = 0; i < count; i++)
316 if (!buffers[i])
317 continue;
319 device->funcs.p_vkFreeCommandBuffers(device->device, pool->command_pool, 1, &buffers[i]->command_buffer);
320 list_remove(&buffers[i]->pool_link);
321 WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, buffers[i]);
322 heap_free(buffers[i]);
326 static struct VkQueue_T *wine_vk_device_alloc_queues(struct VkDevice_T *device,
327 uint32_t family_index, uint32_t queue_count, VkDeviceQueueCreateFlags flags)
329 VkDeviceQueueInfo2 queue_info;
330 struct VkQueue_T *queues;
331 unsigned int i;
333 if (!(queues = heap_calloc(queue_count, sizeof(*queues))))
335 ERR("Failed to allocate memory for queues\n");
336 return NULL;
339 for (i = 0; i < queue_count; i++)
341 struct VkQueue_T *queue = &queues[i];
343 queue->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
344 queue->device = device;
345 queue->flags = flags;
347 /* The Vulkan spec says:
349 * "vkGetDeviceQueue must only be used to get queues that were created
350 * with the flags parameter of VkDeviceQueueCreateInfo set to zero."
352 if (flags && device->funcs.p_vkGetDeviceQueue2)
354 queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2;
355 queue_info.pNext = NULL;
356 queue_info.flags = flags;
357 queue_info.queueFamilyIndex = family_index;
358 queue_info.queueIndex = i;
359 device->funcs.p_vkGetDeviceQueue2(device->device, &queue_info, &queue->queue);
361 else
363 device->funcs.p_vkGetDeviceQueue(device->device, family_index, i, &queue->queue);
366 WINE_VK_ADD_DISPATCHABLE_MAPPING(device->phys_dev->instance, queue, queue->queue);
369 return queues;
372 static void wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info)
374 VkDeviceGroupDeviceCreateInfo *group_info;
376 if ((group_info = wine_vk_find_struct(create_info, DEVICE_GROUP_DEVICE_CREATE_INFO)))
378 heap_free((void *)group_info->pPhysicalDevices);
381 free_VkDeviceCreateInfo_struct_chain(create_info);
384 static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src,
385 VkDeviceCreateInfo *dst)
387 VkDeviceGroupDeviceCreateInfo *group_info;
388 unsigned int i;
389 VkResult res;
391 *dst = *src;
393 if ((res = convert_VkDeviceCreateInfo_struct_chain(src->pNext, dst)) < 0)
395 WARN("Failed to convert VkDeviceCreateInfo pNext chain, res=%d.\n", res);
396 return res;
399 /* FIXME: convert_VkDeviceCreateInfo_struct_chain() should unwrap handles for us. */
400 if ((group_info = wine_vk_find_struct(dst, DEVICE_GROUP_DEVICE_CREATE_INFO)))
402 VkPhysicalDevice *physical_devices;
404 if (!(physical_devices = heap_calloc(group_info->physicalDeviceCount, sizeof(*physical_devices))))
406 free_VkDeviceCreateInfo_struct_chain(dst);
407 return VK_ERROR_OUT_OF_HOST_MEMORY;
409 for (i = 0; i < group_info->physicalDeviceCount; ++i)
411 physical_devices[i] = group_info->pPhysicalDevices[i]->phys_dev;
413 group_info->pPhysicalDevices = physical_devices;
416 /* Should be filtered out by loader as ICDs don't support layers. */
417 dst->enabledLayerCount = 0;
418 dst->ppEnabledLayerNames = NULL;
420 TRACE("Enabled %u extensions.\n", dst->enabledExtensionCount);
421 for (i = 0; i < dst->enabledExtensionCount; i++)
423 const char *extension_name = dst->ppEnabledExtensionNames[i];
424 TRACE("Extension %u: %s.\n", i, debugstr_a(extension_name));
425 if (!wine_vk_device_extension_supported(extension_name))
427 WARN("Extension %s is not supported.\n", debugstr_a(extension_name));
428 wine_vk_device_free_create_info(dst);
429 return VK_ERROR_EXTENSION_NOT_PRESENT;
433 return VK_SUCCESS;
436 /* Helper function used for freeing a device structure. This function supports full
437 * and partial object cleanups and can thus be used for vkCreateDevice failures.
439 static void wine_vk_device_free(struct VkDevice_T *device)
441 if (!device)
442 return;
444 if (device->queues)
446 unsigned int i;
447 for (i = 0; i < device->max_queue_families; i++)
449 if (device->queues[i] && device->queues[i]->queue)
450 WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, device->queues[i]);
451 heap_free(device->queues[i]);
453 heap_free(device->queues);
454 device->queues = NULL;
457 if (device->device && device->funcs.p_vkDestroyDevice)
459 WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, device);
460 device->funcs.p_vkDestroyDevice(device->device, NULL /* pAllocator */);
463 heap_free(device);
466 static BOOL WINAPI wine_vk_init(INIT_ONCE *once, void *param, void **context)
468 HDC hdc;
470 hdc = GetDC(0);
471 vk_funcs = __wine_get_vulkan_driver(hdc, WINE_VULKAN_DRIVER_VERSION);
472 ReleaseDC(0, hdc);
473 if (!vk_funcs)
474 ERR("Failed to load Wine graphics driver supporting Vulkan.\n");
475 else
476 p_vkEnumerateInstanceVersion = vk_funcs->p_vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
478 return TRUE;
481 static void wine_vk_init_once(void)
483 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
485 InitOnceExecuteOnce(&init_once, wine_vk_init, NULL, NULL);
488 /* Helper function for converting between win32 and host compatible VkInstanceCreateInfo.
489 * This function takes care of extensions handled at winevulkan layer, a Wine graphics
490 * driver is responsible for handling e.g. surface extensions.
492 static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo *src,
493 VkInstanceCreateInfo *dst, struct VkInstance_T *object)
495 VkDebugUtilsMessengerCreateInfoEXT *debug_utils_messenger;
496 VkDebugReportCallbackCreateInfoEXT *debug_report_callback;
497 VkBaseInStructure *header;
498 unsigned int i;
499 VkResult res;
501 *dst = *src;
503 if ((res = convert_VkInstanceCreateInfo_struct_chain(src->pNext, dst)) < 0)
505 WARN("Failed to convert VkInstanceCreateInfo pNext chain, res=%d.\n", res);
506 return res;
509 object->utils_messenger_count = wine_vk_count_struct(dst, DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT);
510 object->utils_messengers = heap_calloc(object->utils_messenger_count, sizeof(*object->utils_messengers));
511 header = (VkBaseInStructure *) dst;
512 for (i = 0; i < object->utils_messenger_count; i++)
514 header = wine_vk_find_struct(header->pNext, DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT);
515 debug_utils_messenger = (VkDebugUtilsMessengerCreateInfoEXT *) header;
517 object->utils_messengers[i].instance = object;
518 object->utils_messengers[i].debug_messenger = VK_NULL_HANDLE;
519 object->utils_messengers[i].user_callback = debug_utils_messenger->pfnUserCallback;
520 object->utils_messengers[i].user_data = debug_utils_messenger->pUserData;
522 /* convert_VkInstanceCreateInfo_struct_chain already copied the chain,
523 * so we can modify it in-place.
525 debug_utils_messenger->pfnUserCallback = (void *) &debug_utils_callback_conversion;
526 debug_utils_messenger->pUserData = &object->utils_messengers[i];
529 debug_report_callback = wine_vk_find_struct(header->pNext, DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT);
530 if (debug_report_callback)
532 object->default_callback.instance = object;
533 object->default_callback.debug_callback = VK_NULL_HANDLE;
534 object->default_callback.user_callback = debug_report_callback->pfnCallback;
535 object->default_callback.user_data = debug_report_callback->pUserData;
537 debug_report_callback->pfnCallback = (void *) &debug_report_callback_conversion;
538 debug_report_callback->pUserData = &object->default_callback;
541 /* ICDs don't support any layers, so nothing to copy. Modern versions of the loader
542 * filter this data out as well.
544 if (object->quirks & WINEVULKAN_QUIRK_IGNORE_EXPLICIT_LAYERS) {
545 dst->enabledLayerCount = 0;
546 dst->ppEnabledLayerNames = NULL;
547 WARN("Ignoring explicit layers!\n");
548 } else if (dst->enabledLayerCount) {
549 FIXME("Loading explicit layers is not supported by winevulkan!\n");
550 return VK_ERROR_LAYER_NOT_PRESENT;
553 TRACE("Enabled %u instance extensions.\n", dst->enabledExtensionCount);
554 for (i = 0; i < dst->enabledExtensionCount; i++)
556 const char *extension_name = dst->ppEnabledExtensionNames[i];
557 TRACE("Extension %u: %s.\n", i, debugstr_a(extension_name));
558 if (!wine_vk_instance_extension_supported(extension_name))
560 WARN("Extension %s is not supported.\n", debugstr_a(extension_name));
561 free_VkInstanceCreateInfo_struct_chain(dst);
562 return VK_ERROR_EXTENSION_NOT_PRESENT;
564 if (!strcmp(extension_name, "VK_EXT_debug_utils") || !strcmp(extension_name, "VK_EXT_debug_report"))
566 object->enable_wrapper_list = VK_TRUE;
570 return VK_SUCCESS;
573 /* Helper function which stores wrapped physical devices in the instance object. */
574 static VkResult wine_vk_instance_load_physical_devices(struct VkInstance_T *instance)
576 VkPhysicalDevice *tmp_phys_devs;
577 uint32_t phys_dev_count;
578 unsigned int i;
579 VkResult res;
581 res = instance->funcs.p_vkEnumeratePhysicalDevices(instance->instance, &phys_dev_count, NULL);
582 if (res != VK_SUCCESS)
584 ERR("Failed to enumerate physical devices, res=%d\n", res);
585 return res;
587 if (!phys_dev_count)
588 return res;
590 if (!(tmp_phys_devs = heap_calloc(phys_dev_count, sizeof(*tmp_phys_devs))))
591 return VK_ERROR_OUT_OF_HOST_MEMORY;
593 res = instance->funcs.p_vkEnumeratePhysicalDevices(instance->instance, &phys_dev_count, tmp_phys_devs);
594 if (res != VK_SUCCESS)
596 heap_free(tmp_phys_devs);
597 return res;
600 instance->phys_devs = heap_calloc(phys_dev_count, sizeof(*instance->phys_devs));
601 if (!instance->phys_devs)
603 heap_free(tmp_phys_devs);
604 return VK_ERROR_OUT_OF_HOST_MEMORY;
607 /* Wrap each native physical device handle into a dispatchable object for the ICD loader. */
608 for (i = 0; i < phys_dev_count; i++)
610 struct VkPhysicalDevice_T *phys_dev = wine_vk_physical_device_alloc(instance, tmp_phys_devs[i]);
611 if (!phys_dev)
613 ERR("Unable to allocate memory for physical device!\n");
614 heap_free(tmp_phys_devs);
615 return VK_ERROR_OUT_OF_HOST_MEMORY;
618 instance->phys_devs[i] = phys_dev;
619 instance->phys_dev_count = i + 1;
621 instance->phys_dev_count = phys_dev_count;
623 heap_free(tmp_phys_devs);
624 return VK_SUCCESS;
627 static struct VkPhysicalDevice_T *wine_vk_instance_wrap_physical_device(struct VkInstance_T *instance,
628 VkPhysicalDevice physical_device)
630 unsigned int i;
632 for (i = 0; i < instance->phys_dev_count; ++i)
634 struct VkPhysicalDevice_T *current = instance->phys_devs[i];
635 if (current->phys_dev == physical_device)
636 return current;
639 ERR("Unrecognized physical device %p.\n", physical_device);
640 return NULL;
643 /* Helper function used for freeing an instance structure. This function supports full
644 * and partial object cleanups and can thus be used for vkCreateInstance failures.
646 static void wine_vk_instance_free(struct VkInstance_T *instance)
648 if (!instance)
649 return;
651 if (instance->phys_devs)
653 unsigned int i;
655 for (i = 0; i < instance->phys_dev_count; i++)
657 wine_vk_physical_device_free(instance->phys_devs[i]);
659 heap_free(instance->phys_devs);
662 if (instance->instance)
664 vk_funcs->p_vkDestroyInstance(instance->instance, NULL /* allocator */);
665 WINE_VK_REMOVE_HANDLE_MAPPING(instance, instance);
668 heap_free(instance->utils_messengers);
670 heap_free(instance);
673 VkResult WINAPI wine_vkAllocateCommandBuffers(VkDevice device,
674 const VkCommandBufferAllocateInfo *allocate_info, VkCommandBuffer *buffers)
676 struct wine_cmd_pool *pool;
677 VkResult res = VK_SUCCESS;
678 unsigned int i;
680 TRACE("%p, %p, %p\n", device, allocate_info, buffers);
682 pool = wine_cmd_pool_from_handle(allocate_info->commandPool);
684 memset(buffers, 0, allocate_info->commandBufferCount * sizeof(*buffers));
686 for (i = 0; i < allocate_info->commandBufferCount; i++)
688 #if defined(USE_STRUCT_CONVERSION)
689 VkCommandBufferAllocateInfo_host allocate_info_host;
690 #else
691 VkCommandBufferAllocateInfo allocate_info_host;
692 #endif
693 /* TODO: future extensions (none yet) may require pNext conversion. */
694 allocate_info_host.pNext = allocate_info->pNext;
695 allocate_info_host.sType = allocate_info->sType;
696 allocate_info_host.commandPool = pool->command_pool;
697 allocate_info_host.level = allocate_info->level;
698 allocate_info_host.commandBufferCount = 1;
700 TRACE("Allocating command buffer %u from pool 0x%s.\n",
701 i, wine_dbgstr_longlong(allocate_info_host.commandPool));
703 if (!(buffers[i] = heap_alloc_zero(sizeof(**buffers))))
705 res = VK_ERROR_OUT_OF_HOST_MEMORY;
706 break;
709 buffers[i]->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
710 buffers[i]->device = device;
711 list_add_tail(&pool->command_buffers, &buffers[i]->pool_link);
712 res = device->funcs.p_vkAllocateCommandBuffers(device->device,
713 &allocate_info_host, &buffers[i]->command_buffer);
714 WINE_VK_ADD_DISPATCHABLE_MAPPING(device->phys_dev->instance, buffers[i], buffers[i]->command_buffer);
715 if (res != VK_SUCCESS)
717 ERR("Failed to allocate command buffer, res=%d.\n", res);
718 buffers[i]->command_buffer = VK_NULL_HANDLE;
719 break;
723 if (res != VK_SUCCESS)
725 wine_vk_free_command_buffers(device, pool, i + 1, buffers);
726 memset(buffers, 0, allocate_info->commandBufferCount * sizeof(*buffers));
729 return res;
732 void WINAPI wine_vkCmdExecuteCommands(VkCommandBuffer buffer, uint32_t count,
733 const VkCommandBuffer *buffers)
735 VkCommandBuffer *tmp_buffers;
736 unsigned int i;
738 TRACE("%p %u %p\n", buffer, count, buffers);
740 if (!buffers || !count)
741 return;
743 /* Unfortunately we need a temporary buffer as our command buffers are wrapped.
744 * This call is called often and if a performance concern, we may want to use
745 * alloca as we shouldn't need much memory and it needs to be cleaned up after
746 * the call anyway.
748 if (!(tmp_buffers = heap_alloc(count * sizeof(*tmp_buffers))))
750 ERR("Failed to allocate memory for temporary command buffers\n");
751 return;
754 for (i = 0; i < count; i++)
755 tmp_buffers[i] = buffers[i]->command_buffer;
757 buffer->device->funcs.p_vkCmdExecuteCommands(buffer->command_buffer, count, tmp_buffers);
759 heap_free(tmp_buffers);
762 VkResult WINAPI wine_vkCreateDevice(VkPhysicalDevice phys_dev,
763 const VkDeviceCreateInfo *create_info,
764 const VkAllocationCallbacks *allocator, VkDevice *device)
766 VkDeviceCreateInfo create_info_host;
767 uint32_t max_queue_families;
768 struct VkDevice_T *object;
769 unsigned int i;
770 VkResult res;
772 TRACE("%p, %p, %p, %p\n", phys_dev, create_info, allocator, device);
774 if (allocator)
775 FIXME("Support for allocation callbacks not implemented yet\n");
777 if (TRACE_ON(vulkan))
779 VkPhysicalDeviceProperties properties;
781 wine_vkGetPhysicalDeviceProperties(phys_dev, &properties);
783 TRACE("Device name: %s.\n", debugstr_a(properties.deviceName));
784 TRACE("Vendor ID: %#x, Device ID: %#x.\n", properties.vendorID, properties.deviceID);
785 TRACE("Driver version: %#x.\n", properties.driverVersion);
788 if (!(object = heap_alloc_zero(sizeof(*object))))
789 return VK_ERROR_OUT_OF_HOST_MEMORY;
791 object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
792 object->phys_dev = phys_dev;
794 res = wine_vk_device_convert_create_info(create_info, &create_info_host);
795 if (res != VK_SUCCESS)
796 goto fail;
798 res = phys_dev->instance->funcs.p_vkCreateDevice(phys_dev->phys_dev,
799 &create_info_host, NULL /* allocator */, &object->device);
800 wine_vk_device_free_create_info(&create_info_host);
801 WINE_VK_ADD_DISPATCHABLE_MAPPING(phys_dev->instance, object, object->device);
802 if (res != VK_SUCCESS)
804 WARN("Failed to create device, res=%d.\n", res);
805 goto fail;
808 /* Just load all function pointers we are aware off. The loader takes care of filtering.
809 * We use vkGetDeviceProcAddr as opposed to vkGetInstanceProcAddr for efficiency reasons
810 * as functions pass through fewer dispatch tables within the loader.
812 #define USE_VK_FUNC(name) \
813 object->funcs.p_##name = (void *)vk_funcs->p_vkGetDeviceProcAddr(object->device, #name); \
814 if (object->funcs.p_##name == NULL) \
815 TRACE("Not found '%s'.\n", #name);
816 ALL_VK_DEVICE_FUNCS()
817 #undef USE_VK_FUNC
819 /* We need to cache all queues within the device as each requires wrapping since queues are
820 * dispatchable objects.
822 phys_dev->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties(phys_dev->phys_dev,
823 &max_queue_families, NULL);
824 object->max_queue_families = max_queue_families;
825 TRACE("Max queue families: %u.\n", object->max_queue_families);
827 if (!(object->queues = heap_calloc(max_queue_families, sizeof(*object->queues))))
829 res = VK_ERROR_OUT_OF_HOST_MEMORY;
830 goto fail;
833 for (i = 0; i < create_info_host.queueCreateInfoCount; i++)
835 uint32_t flags = create_info_host.pQueueCreateInfos[i].flags;
836 uint32_t family_index = create_info_host.pQueueCreateInfos[i].queueFamilyIndex;
837 uint32_t queue_count = create_info_host.pQueueCreateInfos[i].queueCount;
839 TRACE("Queue family index %u, queue count %u.\n", family_index, queue_count);
841 if (!(object->queues[family_index] = wine_vk_device_alloc_queues(object, family_index, queue_count, flags)))
843 ERR("Failed to allocate memory for queues.\n");
844 res = VK_ERROR_OUT_OF_HOST_MEMORY;
845 goto fail;
849 object->quirks = phys_dev->instance->quirks;
851 *device = object;
852 TRACE("Created device %p (native device %p).\n", object, object->device);
853 return VK_SUCCESS;
855 fail:
856 wine_vk_device_free(object);
857 return res;
860 VkResult WINAPI wine_vkCreateInstance(const VkInstanceCreateInfo *create_info,
861 const VkAllocationCallbacks *allocator, VkInstance *instance)
863 VkInstanceCreateInfo create_info_host;
864 const VkApplicationInfo *app_info;
865 struct VkInstance_T *object;
866 VkResult res;
868 TRACE("create_info %p, allocator %p, instance %p\n", create_info, allocator, instance);
870 wine_vk_init_once();
871 if (!vk_funcs)
872 return VK_ERROR_INITIALIZATION_FAILED;
874 if (allocator)
875 FIXME("Support for allocation callbacks not implemented yet\n");
877 if (!(object = heap_alloc_zero(sizeof(*object))))
879 ERR("Failed to allocate memory for instance\n");
880 return VK_ERROR_OUT_OF_HOST_MEMORY;
882 object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
883 list_init(&object->wrappers);
884 InitializeSRWLock(&object->wrapper_lock);
886 res = wine_vk_instance_convert_create_info(create_info, &create_info_host, object);
887 if (res != VK_SUCCESS)
889 wine_vk_instance_free(object);
890 return res;
893 res = vk_funcs->p_vkCreateInstance(&create_info_host, NULL /* allocator */, &object->instance);
894 free_VkInstanceCreateInfo_struct_chain(&create_info_host);
895 if (res != VK_SUCCESS)
897 ERR("Failed to create instance, res=%d\n", res);
898 wine_vk_instance_free(object);
899 return res;
902 WINE_VK_ADD_DISPATCHABLE_MAPPING(object, object, object->instance);
904 /* Load all instance functions we are aware of. Note the loader takes care
905 * of any filtering for extensions which were not requested, but which the
906 * ICD may support.
908 #define USE_VK_FUNC(name) \
909 object->funcs.p_##name = (void *)vk_funcs->p_vkGetInstanceProcAddr(object->instance, #name);
910 ALL_VK_INSTANCE_FUNCS()
911 #undef USE_VK_FUNC
913 /* Cache physical devices for vkEnumeratePhysicalDevices within the instance as
914 * each vkPhysicalDevice is a dispatchable object, which means we need to wrap
915 * the native physical devices and present those to the application.
916 * Cleanup happens as part of wine_vkDestroyInstance.
918 res = wine_vk_instance_load_physical_devices(object);
919 if (res != VK_SUCCESS)
921 ERR("Failed to load physical devices, res=%d\n", res);
922 wine_vk_instance_free(object);
923 return res;
926 if ((app_info = create_info->pApplicationInfo))
928 TRACE("Application name %s, application version %#x.\n",
929 debugstr_a(app_info->pApplicationName), app_info->applicationVersion);
930 TRACE("Engine name %s, engine version %#x.\n", debugstr_a(app_info->pEngineName),
931 app_info->engineVersion);
932 TRACE("API version %#x.\n", app_info->apiVersion);
934 if (app_info->pEngineName && !strcmp(app_info->pEngineName, "idTech"))
935 object->quirks |= WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR;
938 object->quirks |= WINEVULKAN_QUIRK_ADJUST_MAX_IMAGE_COUNT;
940 *instance = object;
941 TRACE("Created instance %p (native instance %p).\n", object, object->instance);
942 return VK_SUCCESS;
945 void WINAPI wine_vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *allocator)
947 TRACE("%p %p\n", device, allocator);
949 if (allocator)
950 FIXME("Support for allocation callbacks not implemented yet\n");
952 wine_vk_device_free(device);
955 void WINAPI wine_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *allocator)
957 TRACE("%p, %p\n", instance, allocator);
959 if (allocator)
960 FIXME("Support allocation allocators\n");
962 wine_vk_instance_free(instance);
965 VkResult WINAPI wine_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice phys_dev,
966 const char *layer_name, uint32_t *count, VkExtensionProperties *properties)
968 TRACE("%p, %p, %p, %p\n", phys_dev, layer_name, count, properties);
970 /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
971 if (layer_name)
973 ERR("Layer enumeration not supported from ICD.\n");
974 return VK_ERROR_LAYER_NOT_PRESENT;
977 if (!properties)
979 *count = phys_dev->extension_count;
980 return VK_SUCCESS;
983 *count = min(*count, phys_dev->extension_count);
984 memcpy(properties, phys_dev->extensions, *count * sizeof(*properties));
986 TRACE("Returning %u extensions.\n", *count);
987 return *count < phys_dev->extension_count ? VK_INCOMPLETE : VK_SUCCESS;
990 VkResult WINAPI wine_vkEnumerateInstanceExtensionProperties(const char *layer_name,
991 uint32_t *count, VkExtensionProperties *properties)
993 uint32_t num_properties = 0, num_host_properties;
994 VkExtensionProperties *host_properties;
995 unsigned int i, j;
996 VkResult res;
998 TRACE("%p, %p, %p\n", layer_name, count, properties);
1000 if (layer_name)
1002 WARN("Layer enumeration not supported from ICD.\n");
1003 return VK_ERROR_LAYER_NOT_PRESENT;
1006 wine_vk_init_once();
1007 if (!vk_funcs)
1009 *count = 0;
1010 return VK_SUCCESS;
1013 res = vk_funcs->p_vkEnumerateInstanceExtensionProperties(NULL, &num_host_properties, NULL);
1014 if (res != VK_SUCCESS)
1015 return res;
1017 if (!(host_properties = heap_calloc(num_host_properties, sizeof(*host_properties))))
1018 return VK_ERROR_OUT_OF_HOST_MEMORY;
1020 res = vk_funcs->p_vkEnumerateInstanceExtensionProperties(NULL, &num_host_properties, host_properties);
1021 if (res != VK_SUCCESS)
1023 ERR("Failed to retrieve host properties, res=%d.\n", res);
1024 heap_free(host_properties);
1025 return res;
1028 /* The Wine graphics driver provides us with all extensions supported by the host side
1029 * including extension fixup (e.g. VK_KHR_xlib_surface -> VK_KHR_win32_surface). It is
1030 * up to us here to filter the list down to extensions for which we have thunks.
1032 for (i = 0; i < num_host_properties; i++)
1034 if (wine_vk_instance_extension_supported(host_properties[i].extensionName))
1035 num_properties++;
1036 else
1037 TRACE("Instance extension '%s' is not supported.\n", host_properties[i].extensionName);
1040 if (!properties)
1042 TRACE("Returning %u extensions.\n", num_properties);
1043 *count = num_properties;
1044 heap_free(host_properties);
1045 return VK_SUCCESS;
1048 for (i = 0, j = 0; i < num_host_properties && j < *count; i++)
1050 if (wine_vk_instance_extension_supported(host_properties[i].extensionName))
1052 TRACE("Enabling extension '%s'.\n", host_properties[i].extensionName);
1053 properties[j++] = host_properties[i];
1056 *count = min(*count, num_properties);
1058 heap_free(host_properties);
1059 return *count < num_properties ? VK_INCOMPLETE : VK_SUCCESS;
1062 VkResult WINAPI wine_vkEnumerateDeviceLayerProperties(VkPhysicalDevice phys_dev, uint32_t *count, VkLayerProperties *properties)
1064 TRACE("%p, %p, %p\n", phys_dev, count, properties);
1066 *count = 0;
1067 return VK_SUCCESS;
1070 VkResult WINAPI wine_vkEnumerateInstanceLayerProperties(uint32_t *count, VkLayerProperties *properties)
1072 TRACE("%p, %p\n", count, properties);
1074 *count = 0;
1075 return VK_SUCCESS;
1078 VkResult WINAPI wine_vkEnumerateInstanceVersion(uint32_t *version)
1080 VkResult res;
1082 TRACE("%p\n", version);
1084 wine_vk_init_once();
1086 if (p_vkEnumerateInstanceVersion)
1088 res = p_vkEnumerateInstanceVersion(version);
1090 else
1092 *version = VK_API_VERSION_1_0;
1093 res = VK_SUCCESS;
1096 TRACE("API version %u.%u.%u.\n",
1097 VK_VERSION_MAJOR(*version), VK_VERSION_MINOR(*version), VK_VERSION_PATCH(*version));
1098 *version = min(WINE_VK_VERSION, *version);
1099 return res;
1102 VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *count,
1103 VkPhysicalDevice *devices)
1105 unsigned int i;
1107 TRACE("%p %p %p\n", instance, count, devices);
1109 if (!devices)
1111 *count = instance->phys_dev_count;
1112 return VK_SUCCESS;
1115 *count = min(*count, instance->phys_dev_count);
1116 for (i = 0; i < *count; i++)
1118 devices[i] = instance->phys_devs[i];
1121 TRACE("Returning %u devices.\n", *count);
1122 return *count < instance->phys_dev_count ? VK_INCOMPLETE : VK_SUCCESS;
1125 void WINAPI wine_vkFreeCommandBuffers(VkDevice device, VkCommandPool pool_handle,
1126 uint32_t count, const VkCommandBuffer *buffers)
1128 struct wine_cmd_pool *pool = wine_cmd_pool_from_handle(pool_handle);
1130 TRACE("%p, 0x%s, %u, %p\n", device, wine_dbgstr_longlong(pool_handle), count, buffers);
1132 wine_vk_free_command_buffers(device, pool, count, buffers);
1135 PFN_vkVoidFunction WINAPI wine_vkGetDeviceProcAddr(VkDevice device, const char *name)
1137 void *func;
1138 TRACE("%p, %s\n", device, debugstr_a(name));
1140 /* The spec leaves return value undefined for a NULL device, let's just return NULL. */
1141 if (!device || !name)
1142 return NULL;
1144 /* Per the spec, we are only supposed to return device functions as in functions
1145 * for which the first parameter is vkDevice or a child of vkDevice like a
1146 * vkCommandBuffer or vkQueue.
1147 * Loader takes care of filtering of extensions which are enabled or not.
1149 func = wine_vk_get_device_proc_addr(name);
1150 if (func)
1151 return func;
1153 /* vkGetDeviceProcAddr was intended for loading device and subdevice functions.
1154 * idTech 6 titles such as Doom and Wolfenstein II, however use it also for
1155 * loading of instance functions. This is undefined behavior as the specification
1156 * disallows using any of the returned function pointers outside of device /
1157 * subdevice objects. The games don't actually use the function pointers and if they
1158 * did, they would crash as VkInstance / VkPhysicalDevice parameters need unwrapping.
1159 * Khronos clarified behavior in the Vulkan spec and expects drivers to get updated,
1160 * however it would require both driver and game fixes.
1161 * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/2323
1162 * https://github.com/KhronosGroup/Vulkan-Docs/issues/655
1164 if (device->quirks & WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR
1165 && ((func = wine_vk_get_instance_proc_addr(name))
1166 || (func = wine_vk_get_phys_dev_proc_addr(name))))
1168 WARN("Returning instance function %s.\n", debugstr_a(name));
1169 return func;
1172 WARN("Unsupported device function: %s.\n", debugstr_a(name));
1173 return NULL;
1176 void WINAPI wine_vkGetDeviceQueue(VkDevice device, uint32_t family_index,
1177 uint32_t queue_index, VkQueue *queue)
1179 TRACE("%p, %u, %u, %p\n", device, family_index, queue_index, queue);
1181 *queue = &device->queues[family_index][queue_index];
1184 void WINAPI wine_vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *info, VkQueue *queue)
1186 struct VkQueue_T *matching_queue;
1187 const VkBaseInStructure *chain;
1189 TRACE("%p, %p, %p\n", device, info, queue);
1191 if ((chain = info->pNext))
1192 FIXME("Ignoring a linked structure of type %u.\n", chain->sType);
1194 matching_queue = &device->queues[info->queueFamilyIndex][info->queueIndex];
1195 if (matching_queue->flags != info->flags)
1197 WARN("No matching flags were specified %#x, %#x.\n", matching_queue->flags, info->flags);
1198 matching_queue = VK_NULL_HANDLE;
1200 *queue = matching_queue;
1203 PFN_vkVoidFunction WINAPI wine_vkGetInstanceProcAddr(VkInstance instance, const char *name)
1205 void *func;
1207 TRACE("%p, %s\n", instance, debugstr_a(name));
1209 if (!name)
1210 return NULL;
1212 /* vkGetInstanceProcAddr can load most Vulkan functions when an instance is passed in, however
1213 * for a NULL instance it can only load global functions.
1215 func = wine_vk_get_global_proc_addr(name);
1216 if (func)
1218 return func;
1220 if (!instance)
1222 WARN("Global function %s not found.\n", debugstr_a(name));
1223 return NULL;
1226 func = wine_vk_get_instance_proc_addr(name);
1227 if (func) return func;
1229 func = wine_vk_get_phys_dev_proc_addr(name);
1230 if (func) return func;
1232 /* vkGetInstanceProcAddr also loads any children of instance, so device functions as well. */
1233 func = wine_vk_get_device_proc_addr(name);
1234 if (func) return func;
1236 WARN("Unsupported device or instance function: %s.\n", debugstr_a(name));
1237 return NULL;
1240 void * WINAPI wine_vk_icdGetPhysicalDeviceProcAddr(VkInstance instance, const char *name)
1242 TRACE("%p, %s\n", instance, debugstr_a(name));
1244 return wine_vk_get_phys_dev_proc_addr(name);
1247 void * WINAPI wine_vk_icdGetInstanceProcAddr(VkInstance instance, const char *name)
1249 TRACE("%p, %s\n", instance, debugstr_a(name));
1251 /* Initial version of the Vulkan ICD spec required vkGetInstanceProcAddr to be
1252 * exported. vk_icdGetInstanceProcAddr was added later to separate ICD calls from
1253 * Vulkan API. One of them in our case should forward to the other, so just forward
1254 * to the older vkGetInstanceProcAddr.
1256 return wine_vkGetInstanceProcAddr(instance, name);
1259 VkResult WINAPI wine_vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t *supported_version)
1261 uint32_t req_version;
1263 TRACE("%p\n", supported_version);
1265 /* The spec is not clear how to handle this. Mesa drivers don't check, but it
1266 * is probably best to not explode. VK_INCOMPLETE seems to be the closest value.
1268 if (!supported_version)
1269 return VK_INCOMPLETE;
1271 req_version = *supported_version;
1272 *supported_version = min(req_version, WINE_VULKAN_ICD_VERSION);
1273 TRACE("Loader requested ICD version %u, returning %u\n", req_version, *supported_version);
1275 return VK_SUCCESS;
1278 VkResult WINAPI wine_vkQueueSubmit(VkQueue queue, uint32_t count,
1279 const VkSubmitInfo *submits, VkFence fence)
1281 VkSubmitInfo *submits_host;
1282 VkResult res;
1283 VkCommandBuffer *command_buffers;
1284 unsigned int i, j, num_command_buffers;
1286 TRACE("%p %u %p 0x%s\n", queue, count, submits, wine_dbgstr_longlong(fence));
1288 if (count == 0)
1290 return queue->device->funcs.p_vkQueueSubmit(queue->queue, 0, NULL, fence);
1293 submits_host = heap_calloc(count, sizeof(*submits_host));
1294 if (!submits_host)
1296 ERR("Unable to allocate memory for submit buffers!\n");
1297 return VK_ERROR_OUT_OF_HOST_MEMORY;
1300 for (i = 0; i < count; i++)
1302 memcpy(&submits_host[i], &submits[i], sizeof(*submits_host));
1304 num_command_buffers = submits[i].commandBufferCount;
1305 command_buffers = heap_calloc(num_command_buffers, sizeof(*command_buffers));
1306 if (!command_buffers)
1308 ERR("Unable to allocate memory for command buffers!\n");
1309 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1310 goto done;
1313 for (j = 0; j < num_command_buffers; j++)
1315 command_buffers[j] = submits[i].pCommandBuffers[j]->command_buffer;
1317 submits_host[i].pCommandBuffers = command_buffers;
1320 res = queue->device->funcs.p_vkQueueSubmit(queue->queue, count, submits_host, fence);
1322 done:
1323 for (i = 0; i < count; i++)
1325 heap_free((void *)submits_host[i].pCommandBuffers);
1327 heap_free(submits_host);
1329 TRACE("Returning %d\n", res);
1330 return res;
1333 VkResult WINAPI wine_vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *info,
1334 const VkAllocationCallbacks *allocator, VkCommandPool *command_pool)
1336 struct wine_cmd_pool *object;
1337 VkResult res;
1339 TRACE("%p, %p, %p, %p\n", device, info, allocator, command_pool);
1341 if (allocator)
1342 FIXME("Support for allocation callbacks not implemented yet\n");
1344 if (!(object = heap_alloc_zero(sizeof(*object))))
1345 return VK_ERROR_OUT_OF_HOST_MEMORY;
1347 list_init(&object->command_buffers);
1349 res = device->funcs.p_vkCreateCommandPool(device->device, info, NULL, &object->command_pool);
1351 if (res == VK_SUCCESS)
1353 WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(device->phys_dev->instance, object, object->command_pool);
1354 *command_pool = wine_cmd_pool_to_handle(object);
1356 else
1358 heap_free(object);
1361 return res;
1364 void WINAPI wine_vkDestroyCommandPool(VkDevice device, VkCommandPool handle,
1365 const VkAllocationCallbacks *allocator)
1367 struct wine_cmd_pool *pool = wine_cmd_pool_from_handle(handle);
1368 struct VkCommandBuffer_T *buffer, *cursor;
1370 TRACE("%p, 0x%s, %p\n", device, wine_dbgstr_longlong(handle), allocator);
1372 if (!handle)
1373 return;
1375 if (allocator)
1376 FIXME("Support for allocation callbacks not implemented yet\n");
1378 /* The Vulkan spec says:
1380 * "When a pool is destroyed, all command buffers allocated from the pool are freed."
1382 LIST_FOR_EACH_ENTRY_SAFE(buffer, cursor, &pool->command_buffers, struct VkCommandBuffer_T, pool_link)
1384 WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, buffer);
1385 heap_free(buffer);
1388 WINE_VK_REMOVE_HANDLE_MAPPING(device->phys_dev->instance, pool);
1390 device->funcs.p_vkDestroyCommandPool(device->device, pool->command_pool, NULL);
1391 heap_free(pool);
1394 static VkResult wine_vk_enumerate_physical_device_groups(struct VkInstance_T *instance,
1395 VkResult (*p_vkEnumeratePhysicalDeviceGroups)(VkInstance, uint32_t *, VkPhysicalDeviceGroupProperties *),
1396 uint32_t *count, VkPhysicalDeviceGroupProperties *properties)
1398 unsigned int i, j;
1399 VkResult res;
1401 res = p_vkEnumeratePhysicalDeviceGroups(instance->instance, count, properties);
1402 if (res < 0 || !properties)
1403 return res;
1405 for (i = 0; i < *count; ++i)
1407 VkPhysicalDeviceGroupProperties *current = &properties[i];
1408 for (j = 0; j < current->physicalDeviceCount; ++j)
1410 VkPhysicalDevice dev = current->physicalDevices[j];
1411 if (!(current->physicalDevices[j] = wine_vk_instance_wrap_physical_device(instance, dev)))
1412 return VK_ERROR_INITIALIZATION_FAILED;
1416 return res;
1419 VkResult WINAPI wine_vkEnumeratePhysicalDeviceGroups(VkInstance instance,
1420 uint32_t *count, VkPhysicalDeviceGroupProperties *properties)
1422 TRACE("%p, %p, %p\n", instance, count, properties);
1423 return wine_vk_enumerate_physical_device_groups(instance,
1424 instance->funcs.p_vkEnumeratePhysicalDeviceGroups, count, properties);
1427 VkResult WINAPI wine_vkEnumeratePhysicalDeviceGroupsKHR(VkInstance instance,
1428 uint32_t *count, VkPhysicalDeviceGroupProperties *properties)
1430 TRACE("%p, %p, %p\n", instance, count, properties);
1431 return wine_vk_enumerate_physical_device_groups(instance,
1432 instance->funcs.p_vkEnumeratePhysicalDeviceGroupsKHR, count, properties);
1435 void WINAPI wine_vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice phys_dev,
1436 const VkPhysicalDeviceExternalFenceInfo *fence_info, VkExternalFenceProperties *properties)
1438 TRACE("%p, %p, %p\n", phys_dev, fence_info, properties);
1439 properties->exportFromImportedHandleTypes = 0;
1440 properties->compatibleHandleTypes = 0;
1441 properties->externalFenceFeatures = 0;
1444 void WINAPI wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice phys_dev,
1445 const VkPhysicalDeviceExternalFenceInfo *fence_info, VkExternalFenceProperties *properties)
1447 TRACE("%p, %p, %p\n", phys_dev, fence_info, properties);
1448 properties->exportFromImportedHandleTypes = 0;
1449 properties->compatibleHandleTypes = 0;
1450 properties->externalFenceFeatures = 0;
1453 void WINAPI wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice phys_dev,
1454 const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties)
1456 TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties);
1457 memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
1460 void WINAPI wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_dev,
1461 const VkPhysicalDeviceExternalBufferInfo *buffer_info, VkExternalBufferProperties *properties)
1463 TRACE("%p, %p, %p\n", phys_dev, buffer_info, properties);
1464 memset(&properties->externalMemoryProperties, 0, sizeof(properties->externalMemoryProperties));
1467 VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev,
1468 const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties)
1470 VkExternalImageFormatProperties *external_image_properties;
1471 VkResult res;
1473 TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
1475 res = thunk_vkGetPhysicalDeviceImageFormatProperties2(phys_dev, format_info, properties);
1477 if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES)))
1479 VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties;
1480 p->externalMemoryFeatures = 0;
1481 p->exportFromImportedHandleTypes = 0;
1482 p->compatibleHandleTypes = 0;
1485 return res;
1488 VkResult WINAPI wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev,
1489 const VkPhysicalDeviceImageFormatInfo2 *format_info, VkImageFormatProperties2 *properties)
1491 VkExternalImageFormatProperties *external_image_properties;
1492 VkResult res;
1494 TRACE("%p, %p, %p\n", phys_dev, format_info, properties);
1496 res = thunk_vkGetPhysicalDeviceImageFormatProperties2KHR(phys_dev, format_info, properties);
1498 if ((external_image_properties = wine_vk_find_struct(properties, EXTERNAL_IMAGE_FORMAT_PROPERTIES)))
1500 VkExternalMemoryProperties *p = &external_image_properties->externalMemoryProperties;
1501 p->externalMemoryFeatures = 0;
1502 p->exportFromImportedHandleTypes = 0;
1503 p->compatibleHandleTypes = 0;
1506 return res;
1509 /* From ntdll/unix/sync.c */
1510 #define NANOSECONDS_IN_A_SECOND 1000000000
1511 #define TICKSPERSEC 10000000
1513 static inline VkTimeDomainEXT get_performance_counter_time_domain(void)
1515 #if !defined(__APPLE__) && defined(HAVE_CLOCK_GETTIME)
1516 # ifdef CLOCK_MONOTONIC_RAW
1517 return VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT;
1518 # else
1519 return VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT;
1520 # endif
1521 #else
1522 FIXME("No mapping for VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT on this platform.\n");
1523 return VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT;
1524 #endif
1527 static VkTimeDomainEXT map_to_host_time_domain(VkTimeDomainEXT domain)
1529 /* Matches ntdll/unix/sync.c's performance counter implementation. */
1530 if (domain == VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT)
1531 return get_performance_counter_time_domain();
1533 return domain;
1536 static inline uint64_t convert_monotonic_timestamp(uint64_t value)
1538 return value / (NANOSECONDS_IN_A_SECOND / TICKSPERSEC);
1541 static inline uint64_t convert_timestamp(VkTimeDomainEXT host_domain, VkTimeDomainEXT target_domain, uint64_t value)
1543 if (host_domain == target_domain)
1544 return value;
1546 /* Convert between MONOTONIC time in ns -> QueryPerformanceCounter */
1547 if ((host_domain == VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT || host_domain == VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT)
1548 && target_domain == VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT)
1549 return convert_monotonic_timestamp(value);
1551 FIXME("Couldn't translate between host domain %d and target domain %d\n", host_domain, target_domain);
1552 return value;
1555 VkResult WINAPI wine_vkGetCalibratedTimestampsEXT(VkDevice device,
1556 uint32_t timestamp_count, const VkCalibratedTimestampInfoEXT *timestamp_infos,
1557 uint64_t *timestamps, uint64_t *max_deviation)
1559 VkCalibratedTimestampInfoEXT* host_timestamp_infos;
1560 unsigned int i;
1561 VkResult res;
1562 TRACE("%p, %u, %p, %p, %p\n", device, timestamp_count, timestamp_infos, timestamps, max_deviation);
1564 if (!(host_timestamp_infos = heap_alloc(sizeof(VkCalibratedTimestampInfoEXT) * timestamp_count)))
1565 return VK_ERROR_OUT_OF_HOST_MEMORY;
1567 for (i = 0; i < timestamp_count; i++)
1569 host_timestamp_infos[i].sType = timestamp_infos[i].sType;
1570 host_timestamp_infos[i].pNext = timestamp_infos[i].pNext;
1571 host_timestamp_infos[i].timeDomain = map_to_host_time_domain(timestamp_infos[i].timeDomain);
1574 res = device->funcs.p_vkGetCalibratedTimestampsEXT(device->device, timestamp_count, host_timestamp_infos, timestamps, max_deviation);
1575 if (res != VK_SUCCESS)
1576 return res;
1578 for (i = 0; i < timestamp_count; i++)
1579 timestamps[i] = convert_timestamp(host_timestamp_infos[i].timeDomain, timestamp_infos[i].timeDomain, timestamps[i]);
1581 heap_free(host_timestamp_infos);
1583 return res;
1586 VkResult WINAPI wine_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(VkPhysicalDevice phys_dev,
1587 uint32_t *time_domain_count, VkTimeDomainEXT *time_domains)
1589 BOOL supports_device = FALSE, supports_monotonic = FALSE, supports_monotonic_raw = FALSE;
1590 const VkTimeDomainEXT performance_counter_domain = get_performance_counter_time_domain();
1591 VkTimeDomainEXT *host_time_domains;
1592 uint32_t host_time_domain_count;
1593 VkTimeDomainEXT out_time_domains[2];
1594 uint32_t out_time_domain_count;
1595 unsigned int i;
1596 VkResult res;
1598 TRACE("%p, %p, %p\n", phys_dev, time_domain_count, time_domains);
1600 /* Find out the time domains supported on the host */
1601 res = phys_dev->instance->funcs.p_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(phys_dev->phys_dev, &host_time_domain_count, NULL);
1602 if (res != VK_SUCCESS)
1603 return res;
1605 if (!(host_time_domains = heap_alloc(sizeof(VkTimeDomainEXT) * host_time_domain_count)))
1606 return VK_ERROR_OUT_OF_HOST_MEMORY;
1608 res = phys_dev->instance->funcs.p_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(phys_dev->phys_dev, &host_time_domain_count, host_time_domains);
1609 if (res != VK_SUCCESS)
1611 heap_free(host_time_domains);
1612 return res;
1615 for (i = 0; i < host_time_domain_count; i++)
1617 if (host_time_domains[i] == VK_TIME_DOMAIN_DEVICE_EXT)
1618 supports_device = TRUE;
1619 else if (host_time_domains[i] == VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT)
1620 supports_monotonic = TRUE;
1621 else if (host_time_domains[i] == VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT)
1622 supports_monotonic_raw = TRUE;
1623 else
1624 FIXME("Unknown time domain %d\n", host_time_domains[i]);
1627 heap_free(host_time_domains);
1629 out_time_domain_count = 0;
1631 /* Map our monotonic times -> QPC */
1632 if (supports_monotonic_raw && performance_counter_domain == VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT)
1633 out_time_domains[out_time_domain_count++] = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT;
1634 else if (supports_monotonic && performance_counter_domain == VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT)
1635 out_time_domains[out_time_domain_count++] = VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT;
1636 else
1637 FIXME("VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT not supported on this platform.\n");
1639 /* Forward the device domain time */
1640 if (supports_device)
1641 out_time_domains[out_time_domain_count++] = VK_TIME_DOMAIN_DEVICE_EXT;
1643 /* Send the count/domains back to the app */
1644 if (!time_domains)
1646 *time_domain_count = out_time_domain_count;
1647 return VK_SUCCESS;
1650 for (i = 0; i < min(*time_domain_count, out_time_domain_count); i++)
1651 time_domains[i] = out_time_domains[i];
1653 res = *time_domain_count < out_time_domain_count ? VK_INCOMPLETE : VK_SUCCESS;
1654 *time_domain_count = out_time_domain_count;
1655 return res;
1658 static HANDLE get_display_device_init_mutex(void)
1660 static const WCHAR init_mutexW[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0};
1661 HANDLE mutex = CreateMutexW(NULL, FALSE, init_mutexW);
1663 WaitForSingleObject(mutex, INFINITE);
1664 return mutex;
1667 static void release_display_device_init_mutex(HANDLE mutex)
1669 ReleaseMutex(mutex);
1670 CloseHandle(mutex);
1673 /* Wait until graphics driver is loaded by explorer */
1674 static void wait_graphics_driver_ready(void)
1676 static BOOL ready = FALSE;
1678 if (!ready)
1680 SendMessageW(GetDesktopWindow(), WM_NULL, 0, 0);
1681 ready = TRUE;
1685 static void fill_luid_property(VkPhysicalDeviceProperties2 *properties2)
1687 static const WCHAR pci[] = {'P','C','I',0};
1688 VkPhysicalDeviceIDProperties *id;
1689 SP_DEVINFO_DATA device_data;
1690 DWORD type, device_idx = 0;
1691 HDEVINFO devinfo;
1692 HANDLE mutex;
1693 GUID uuid;
1694 LUID luid;
1696 if (!(id = wine_vk_find_struct(properties2, PHYSICAL_DEVICE_ID_PROPERTIES)))
1697 return;
1699 wait_graphics_driver_ready();
1700 mutex = get_display_device_init_mutex();
1701 devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, pci, NULL, 0);
1702 device_data.cbSize = sizeof(device_data);
1703 while (SetupDiEnumDeviceInfo(devinfo, device_idx++, &device_data))
1705 if (!SetupDiGetDevicePropertyW(devinfo, &device_data, &WINE_DEVPROPKEY_GPU_VULKAN_UUID,
1706 &type, (BYTE *)&uuid, sizeof(uuid), NULL, 0))
1707 continue;
1709 if (!IsEqualGUID(&uuid, id->deviceUUID))
1710 continue;
1712 if (SetupDiGetDevicePropertyW(devinfo, &device_data, &DEVPROPKEY_GPU_LUID, &type,
1713 (BYTE *)&luid, sizeof(luid), NULL, 0))
1715 memcpy(&id->deviceLUID, &luid, sizeof(id->deviceLUID));
1716 id->deviceLUIDValid = VK_TRUE;
1717 id->deviceNodeMask = 1;
1718 break;
1721 SetupDiDestroyDeviceInfoList(devinfo);
1722 release_display_device_init_mutex(mutex);
1724 TRACE("deviceName:%s deviceLUIDValid:%d LUID:%08x:%08x deviceNodeMask:%#x.\n",
1725 properties2->properties.deviceName, id->deviceLUIDValid, luid.HighPart, luid.LowPart,
1726 id->deviceNodeMask);
1729 void WINAPI wine_vkGetPhysicalDeviceProperties2(VkPhysicalDevice phys_dev,
1730 VkPhysicalDeviceProperties2 *properties2)
1732 TRACE("%p, %p\n", phys_dev, properties2);
1734 thunk_vkGetPhysicalDeviceProperties2(phys_dev, properties2);
1735 fill_luid_property(properties2);
1738 void WINAPI wine_vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice phys_dev,
1739 VkPhysicalDeviceProperties2 *properties2)
1741 TRACE("%p, %p\n", phys_dev, properties2);
1743 thunk_vkGetPhysicalDeviceProperties2KHR(phys_dev, properties2);
1744 fill_luid_property(properties2);
1747 void WINAPI wine_vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice phys_dev,
1748 const VkPhysicalDeviceExternalSemaphoreInfo *semaphore_info, VkExternalSemaphoreProperties *properties)
1750 TRACE("%p, %p, %p\n", phys_dev, semaphore_info, properties);
1751 properties->exportFromImportedHandleTypes = 0;
1752 properties->compatibleHandleTypes = 0;
1753 properties->externalSemaphoreFeatures = 0;
1756 void WINAPI wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDevice phys_dev,
1757 const VkPhysicalDeviceExternalSemaphoreInfo *semaphore_info, VkExternalSemaphoreProperties *properties)
1759 TRACE("%p, %p, %p\n", phys_dev, semaphore_info, properties);
1760 properties->exportFromImportedHandleTypes = 0;
1761 properties->compatibleHandleTypes = 0;
1762 properties->externalSemaphoreFeatures = 0;
1765 VkResult WINAPI wine_vkSetPrivateDataEXT(VkDevice device, VkObjectType object_type, uint64_t object_handle,
1766 VkPrivateDataSlotEXT private_data_slot, uint64_t data)
1768 TRACE("%p, %#x, 0x%s, 0x%s, 0x%s\n", device, object_type, wine_dbgstr_longlong(object_handle),
1769 wine_dbgstr_longlong(private_data_slot), wine_dbgstr_longlong(data));
1771 object_handle = wine_vk_unwrap_handle(object_type, object_handle);
1772 return device->funcs.p_vkSetPrivateDataEXT(device->device, object_type, object_handle, private_data_slot, data);
1775 void WINAPI wine_vkGetPrivateDataEXT(VkDevice device, VkObjectType object_type, uint64_t object_handle,
1776 VkPrivateDataSlotEXT private_data_slot, uint64_t *data)
1778 TRACE("%p, %#x, 0x%s, 0x%s, %p\n", device, object_type, wine_dbgstr_longlong(object_handle),
1779 wine_dbgstr_longlong(private_data_slot), data);
1781 object_handle = wine_vk_unwrap_handle(object_type, object_handle);
1782 device->funcs.p_vkGetPrivateDataEXT(device->device, object_type, object_handle, private_data_slot, data);
1785 VkResult WINAPI wine_vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *create_info,
1786 const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain)
1788 VkSwapchainCreateInfoKHR native_info;
1790 TRACE("%p, %p, %p, %p\n", device, create_info, allocator, swapchain);
1792 native_info = *create_info;
1793 native_info.surface = wine_surface_from_handle(create_info->surface)->driver_surface;
1795 return thunk_vkCreateSwapchainKHR(device, &native_info, allocator, swapchain);
1798 VkResult WINAPI wine_vkCreateWin32SurfaceKHR(VkInstance instance,
1799 const VkWin32SurfaceCreateInfoKHR *createInfo, const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface)
1801 struct wine_surface *object;
1802 VkResult res;
1804 TRACE("%p, %p, %p, %p\n", instance, createInfo, allocator, surface);
1806 if (allocator)
1807 FIXME("Support for allocation callbacks not implemented yet\n");
1809 object = heap_alloc_zero(sizeof(*object));
1811 if (!object)
1812 return VK_ERROR_OUT_OF_HOST_MEMORY;
1814 res = instance->funcs.p_vkCreateWin32SurfaceKHR(instance->instance, createInfo, NULL, &object->driver_surface);
1816 if (res != VK_SUCCESS)
1818 heap_free(object);
1819 return res;
1822 object->surface = vk_funcs->p_wine_get_native_surface(object->driver_surface);
1824 WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(instance, object, object->surface);
1826 *surface = wine_surface_to_handle(object);
1828 return VK_SUCCESS;
1831 void WINAPI wine_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *allocator)
1833 struct wine_surface *object = wine_surface_from_handle(surface);
1835 TRACE("%p, 0x%s, %p\n", instance, wine_dbgstr_longlong(surface), allocator);
1837 if (!object)
1838 return;
1840 instance->funcs.p_vkDestroySurfaceKHR(instance->instance, object->driver_surface, NULL);
1842 WINE_VK_REMOVE_HANDLE_MAPPING(instance, object);
1843 heap_free(object);
1846 VkResult WINAPI wine_vkGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice phys_dev,
1847 const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, uint32_t *formats_count, VkSurfaceFormat2KHR *formats)
1849 VkPhysicalDeviceSurfaceInfo2KHR native_info;
1851 TRACE("%p, %p, %p, %p\n", phys_dev, surface_info, formats_count, formats);
1853 native_info = *surface_info;
1854 native_info.surface = wine_surface_from_handle(surface_info->surface)->driver_surface;
1856 return thunk_vkGetPhysicalDeviceSurfaceFormats2KHR(phys_dev, &native_info, formats_count, formats);
1859 static inline void adjust_max_image_count(VkPhysicalDevice phys_dev, VkSurfaceCapabilitiesKHR* capabilities)
1861 /* Many Windows games, for example Strange Brigade, No Man's Sky, Path of Exile
1862 * and World War Z, do not expect that maxImageCount can be set to 0.
1863 * A value of 0 means that there is no limit on the number of images.
1864 * Nvidia reports 8 on Windows, AMD 16.
1865 * https://vulkan.gpuinfo.org/displayreport.php?id=9122#surface
1866 * https://vulkan.gpuinfo.org/displayreport.php?id=9121#surface
1868 if ((phys_dev->instance->quirks & WINEVULKAN_QUIRK_ADJUST_MAX_IMAGE_COUNT) && !capabilities->maxImageCount)
1870 capabilities->maxImageCount = max(capabilities->minImageCount, 16);
1874 VkResult WINAPI wine_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice phys_dev,
1875 VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *capabilities)
1877 VkResult res;
1879 TRACE("%p, 0x%s, %p\n", phys_dev, wine_dbgstr_longlong(surface), capabilities);
1881 res = thunk_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev, surface, capabilities);
1883 if (res == VK_SUCCESS)
1884 adjust_max_image_count(phys_dev, capabilities);
1886 return res;
1889 VkResult WINAPI wine_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice phys_dev,
1890 const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, VkSurfaceCapabilities2KHR *capabilities)
1892 VkPhysicalDeviceSurfaceInfo2KHR native_info;
1893 VkResult res;
1895 TRACE("%p, %p, %p\n", phys_dev, surface_info, capabilities);
1897 native_info = *surface_info;
1898 native_info.surface = wine_surface_from_handle(surface_info->surface)->driver_surface;
1900 res = thunk_vkGetPhysicalDeviceSurfaceCapabilities2KHR(phys_dev, &native_info, capabilities);
1902 if (res == VK_SUCCESS)
1903 adjust_max_image_count(phys_dev, &capabilities->surfaceCapabilities);
1905 return res;
1908 VkResult WINAPI wine_vkCreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *create_info,
1909 const VkAllocationCallbacks *allocator, VkDebugUtilsMessengerEXT *messenger)
1911 VkDebugUtilsMessengerCreateInfoEXT wine_create_info;
1912 struct wine_debug_utils_messenger *object;
1913 VkResult res;
1915 TRACE("%p, %p, %p, %p\n", instance, create_info, allocator, messenger);
1917 if (allocator)
1918 FIXME("Support for allocation callbacks not implemented yet\n");
1920 if (!(object = heap_alloc_zero(sizeof(*object))))
1921 return VK_ERROR_OUT_OF_HOST_MEMORY;
1923 object->instance = instance;
1924 object->user_callback = create_info->pfnUserCallback;
1925 object->user_data = create_info->pUserData;
1927 wine_create_info = *create_info;
1929 wine_create_info.pfnUserCallback = (void *) &debug_utils_callback_conversion;
1930 wine_create_info.pUserData = object;
1932 res = instance->funcs.p_vkCreateDebugUtilsMessengerEXT(instance->instance, &wine_create_info, NULL, &object->debug_messenger);
1934 if (res != VK_SUCCESS)
1936 heap_free(object);
1937 return res;
1940 WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(instance, object, object->debug_messenger);
1941 *messenger = wine_debug_utils_messenger_to_handle(object);
1943 return VK_SUCCESS;
1946 void WINAPI wine_vkDestroyDebugUtilsMessengerEXT(
1947 VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks *allocator)
1949 struct wine_debug_utils_messenger *object;
1951 TRACE("%p, 0x%s, %p\n", instance, wine_dbgstr_longlong(messenger), allocator);
1953 object = wine_debug_utils_messenger_from_handle(messenger);
1955 if (!object)
1956 return;
1958 instance->funcs.p_vkDestroyDebugUtilsMessengerEXT(instance->instance, object->debug_messenger, NULL);
1959 WINE_VK_REMOVE_HANDLE_MAPPING(instance, object);
1961 heap_free(object);
1964 void WINAPI wine_vkSubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT severity,
1965 VkDebugUtilsMessageTypeFlagsEXT types, const VkDebugUtilsMessengerCallbackDataEXT *callback_data)
1967 VkDebugUtilsMessengerCallbackDataEXT native_callback_data;
1968 VkDebugUtilsObjectNameInfoEXT *object_names;
1969 unsigned int i;
1971 TRACE("%p, %#x, %#x, %p\n", instance, severity, types, callback_data);
1973 native_callback_data = *callback_data;
1974 object_names = heap_calloc(callback_data->objectCount, sizeof(*object_names));
1975 memcpy(object_names, callback_data->pObjects, callback_data->objectCount * sizeof(*object_names));
1976 native_callback_data.pObjects = object_names;
1978 for (i = 0; i < callback_data->objectCount; i++)
1980 object_names[i].objectHandle =
1981 wine_vk_unwrap_handle(callback_data->pObjects[i].objectType, callback_data->pObjects[i].objectHandle);
1984 thunk_vkSubmitDebugUtilsMessageEXT(instance, severity, types, &native_callback_data);
1986 heap_free(object_names);
1989 VkResult WINAPI wine_vkSetDebugUtilsObjectTagEXT(VkDevice device, const VkDebugUtilsObjectTagInfoEXT *tag_info)
1991 VkDebugUtilsObjectTagInfoEXT wine_tag_info;
1993 TRACE("%p, %p\n", device, tag_info);
1995 wine_tag_info = *tag_info;
1996 wine_tag_info.objectHandle = wine_vk_unwrap_handle(tag_info->objectType, tag_info->objectHandle);
1998 return thunk_vkSetDebugUtilsObjectTagEXT(device, &wine_tag_info);
2001 VkResult WINAPI wine_vkSetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT *name_info)
2003 VkDebugUtilsObjectNameInfoEXT wine_name_info;
2005 TRACE("%p, %p\n", device, name_info);
2007 wine_name_info = *name_info;
2008 wine_name_info.objectHandle = wine_vk_unwrap_handle(name_info->objectType, name_info->objectHandle);
2010 return thunk_vkSetDebugUtilsObjectNameEXT(device, &wine_name_info);
2013 VkResult WINAPI wine_vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *create_info,
2014 const VkAllocationCallbacks *allocator, VkDebugReportCallbackEXT *callback)
2016 VkDebugReportCallbackCreateInfoEXT wine_create_info;
2017 struct wine_debug_report_callback *object;
2018 VkResult res;
2020 TRACE("%p, %p, %p, %p\n", instance, create_info, allocator, callback);
2022 if (allocator)
2023 FIXME("Support for allocation callbacks not implemented yet\n");
2025 if (!(object = heap_alloc_zero(sizeof(*object))))
2026 return VK_ERROR_OUT_OF_HOST_MEMORY;
2028 object->instance = instance;
2029 object->user_callback = create_info->pfnCallback;
2030 object->user_data = create_info->pUserData;
2032 wine_create_info = *create_info;
2034 wine_create_info.pfnCallback = (void *) debug_report_callback_conversion;
2035 wine_create_info.pUserData = object;
2037 res = instance->funcs.p_vkCreateDebugReportCallbackEXT(instance->instance, &wine_create_info, NULL, &object->debug_callback);
2039 if (res != VK_SUCCESS)
2041 heap_free(object);
2042 return res;
2045 WINE_VK_ADD_NON_DISPATCHABLE_MAPPING(instance, object, object->debug_callback);
2046 *callback = wine_debug_report_callback_to_handle(object);
2048 return VK_SUCCESS;
2051 void WINAPI wine_vkDestroyDebugReportCallbackEXT(
2052 VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks *allocator)
2054 struct wine_debug_report_callback *object;
2056 TRACE("%p, 0x%s, %p\n", instance, wine_dbgstr_longlong(callback), allocator);
2058 object = wine_debug_report_callback_from_handle(callback);
2060 if (!object)
2061 return;
2063 instance->funcs.p_vkDestroyDebugReportCallbackEXT(instance->instance, object->debug_callback, NULL);
2065 WINE_VK_REMOVE_HANDLE_MAPPING(instance, object);
2067 heap_free(object);
2070 void WINAPI wine_vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT object_type,
2071 uint64_t object, size_t location, int32_t code, const char *layer_prefix, const char *message)
2073 TRACE("%p, %#x, %#x, 0x%s, 0x%s, %d, %p, %p\n", instance, flags, object_type, wine_dbgstr_longlong(object),
2074 wine_dbgstr_longlong(location), code, layer_prefix, message);
2076 object = wine_vk_unwrap_handle(object_type, object);
2078 instance->funcs.p_vkDebugReportMessageEXT(
2079 instance->instance, flags, object_type, object, location, code, layer_prefix, message);
2082 VkResult WINAPI wine_vkDebugMarkerSetObjectTagEXT(VkDevice device, const VkDebugMarkerObjectTagInfoEXT *tag_info)
2084 VkDebugMarkerObjectTagInfoEXT wine_tag_info;
2086 TRACE("%p, %p\n", device, tag_info);
2088 wine_tag_info = *tag_info;
2089 wine_tag_info.object = wine_vk_unwrap_handle(tag_info->objectType, tag_info->object);
2091 return thunk_vkDebugMarkerSetObjectTagEXT(device, &wine_tag_info);
2094 VkResult WINAPI wine_vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebugMarkerObjectNameInfoEXT *name_info)
2096 VkDebugMarkerObjectNameInfoEXT wine_name_info;
2098 TRACE("%p, %p\n", device, name_info);
2100 wine_name_info = *name_info;
2101 wine_name_info.object = wine_vk_unwrap_handle(name_info->objectType, name_info->object);
2103 return thunk_vkDebugMarkerSetObjectNameEXT(device, &wine_name_info);
2106 BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved)
2108 TRACE("%p, %u, %p\n", hinst, reason, reserved);
2110 switch (reason)
2112 case DLL_PROCESS_ATTACH:
2113 hinstance = hinst;
2114 DisableThreadLibraryCalls(hinst);
2115 break;
2117 return TRUE;
2120 static const struct vulkan_func vk_global_dispatch_table[] =
2122 /* These functions must call wine_vk_init_once() before accessing vk_funcs. */
2123 {"vkCreateInstance", &wine_vkCreateInstance},
2124 {"vkEnumerateInstanceExtensionProperties", &wine_vkEnumerateInstanceExtensionProperties},
2125 {"vkEnumerateInstanceLayerProperties", &wine_vkEnumerateInstanceLayerProperties},
2126 {"vkEnumerateInstanceVersion", &wine_vkEnumerateInstanceVersion},
2127 {"vkGetInstanceProcAddr", &wine_vkGetInstanceProcAddr},
2130 static void *wine_vk_get_global_proc_addr(const char *name)
2132 unsigned int i;
2134 for (i = 0; i < ARRAY_SIZE(vk_global_dispatch_table); i++)
2136 if (strcmp(name, vk_global_dispatch_table[i].name) == 0)
2138 TRACE("Found name=%s in global table\n", debugstr_a(name));
2139 return vk_global_dispatch_table[i].func;
2142 return NULL;
2146 * Wrapper around driver vkGetInstanceProcAddr implementation.
2147 * Allows winelib applications to access Vulkan functions with Wine
2148 * additions and native ABI.
2150 void *native_vkGetInstanceProcAddrWINE(VkInstance instance, const char *name)
2152 wine_vk_init_once();
2153 if (!vk_funcs)
2154 return NULL;
2156 return vk_funcs->p_vkGetInstanceProcAddr(instance, name);
2160 static const WCHAR winevulkan_json_resW[] = {'w','i','n','e','v','u','l','k','a','n','_','j','s','o','n',0};
2161 static const WCHAR winevulkan_json_pathW[] = {'\\','w','i','n','e','v','u','l','k','a','n','.','j','s','o','n',0};
2162 static const WCHAR vulkan_driversW[] = {'S','o','f','t','w','a','r','e','\\','K','h','r','o','n','o','s','\\',
2163 'V','u','l','k','a','n','\\','D','r','i','v','e','r','s',0};
2165 HRESULT WINAPI DllRegisterServer(void)
2167 WCHAR json_path[MAX_PATH];
2168 HRSRC rsrc;
2169 const char *data;
2170 DWORD datalen, written, zero = 0;
2171 HANDLE file;
2172 HKEY key;
2174 /* Create the JSON manifest and registry key to register this ICD with the official Vulkan loader. */
2175 TRACE("\n");
2176 rsrc = FindResourceW(hinstance, winevulkan_json_resW, (const WCHAR *)RT_RCDATA);
2177 data = LockResource(LoadResource(hinstance, rsrc));
2178 datalen = SizeofResource(hinstance, rsrc);
2180 GetSystemDirectoryW(json_path, ARRAY_SIZE(json_path));
2181 lstrcatW(json_path, winevulkan_json_pathW);
2182 file = CreateFileW(json_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
2183 if (file == INVALID_HANDLE_VALUE)
2185 ERR("Unable to create JSON manifest.\n");
2186 return E_UNEXPECTED;
2188 WriteFile(file, data, datalen, &written, NULL);
2189 CloseHandle(file);
2191 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE, vulkan_driversW, 0, NULL, 0, KEY_SET_VALUE, NULL, &key, NULL))
2193 RegSetValueExW(key, json_path, 0, REG_DWORD, (const BYTE *)&zero, sizeof(zero));
2194 RegCloseKey(key);
2196 return S_OK;
2199 HRESULT WINAPI DllUnregisterServer(void)
2201 WCHAR json_path[MAX_PATH];
2202 HKEY key;
2204 /* Remove the JSON manifest and registry key */
2205 TRACE("\n");
2206 GetSystemDirectoryW(json_path, ARRAY_SIZE(json_path));
2207 lstrcatW(json_path, winevulkan_json_pathW);
2208 DeleteFileW(json_path);
2210 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, vulkan_driversW, 0, KEY_SET_VALUE, &key) == ERROR_SUCCESS)
2212 RegDeleteValueW(key, json_path);
2213 RegCloseKey(key);
2216 return S_OK;