shell32: Use Public instead of AllUsersProfile in the registry.
[wine.git] / dlls / winevulkan / vulkan.c
bloba1e970daff856ba2ec16a307c204114d0d073986
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 <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winuser.h"
26 #include "vulkan_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
30 /* For now default to 4 as it felt like a reasonable version feature wise to support.
31 * Don't support the optional vk_icdGetPhysicalDeviceProcAddr introduced in this version
32 * as it is unlikely we will implement physical device extensions, which the loader is not
33 * aware of. Version 5 adds more extensive version checks. Something to tackle later.
35 #define WINE_VULKAN_ICD_VERSION 4
37 /* All Vulkan structures use this structure for the first elements. */
38 struct wine_vk_structure_header
40 VkStructureType sType;
41 void *pNext;
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 struct wine_vk_structure_header *header;
49 for (header = s; header; header = header->pNext)
51 if (header->sType == t)
52 return header;
55 return NULL;
58 static void *wine_vk_get_global_proc_addr(const char *name);
60 static const struct vulkan_funcs *vk_funcs;
61 static VkResult (*p_vkEnumerateInstanceVersion)(uint32_t *version);
63 static void wine_vk_physical_device_free(struct VkPhysicalDevice_T *phys_dev)
65 if (!phys_dev)
66 return;
68 heap_free(phys_dev->extensions);
69 heap_free(phys_dev);
72 static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstance_T *instance,
73 VkPhysicalDevice phys_dev)
75 struct VkPhysicalDevice_T *object;
76 uint32_t num_host_properties, num_properties = 0;
77 VkExtensionProperties *host_properties = NULL;
78 VkResult res;
79 unsigned int i, j;
81 if (!(object = heap_alloc_zero(sizeof(*object))))
82 return NULL;
84 object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
85 object->instance = instance;
86 object->phys_dev = phys_dev;
88 res = instance->funcs.p_vkEnumerateDeviceExtensionProperties(phys_dev,
89 NULL, &num_host_properties, NULL);
90 if (res != VK_SUCCESS)
92 ERR("Failed to enumerate device extensions, res=%d\n", res);
93 goto err;
96 host_properties = heap_calloc(num_host_properties, sizeof(*host_properties));
97 if (!host_properties)
99 ERR("Failed to allocate memory for device properties!\n");
100 goto err;
103 res = instance->funcs.p_vkEnumerateDeviceExtensionProperties(phys_dev,
104 NULL, &num_host_properties, host_properties);
105 if (res != VK_SUCCESS)
107 ERR("Failed to enumerate device extensions, res=%d\n", res);
108 goto err;
111 /* Count list of extensions for which we have an implementation.
112 * TODO: perform translation for platform specific extensions.
114 for (i = 0; i < num_host_properties; i++)
116 if (wine_vk_device_extension_supported(host_properties[i].extensionName))
118 TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object);
119 num_properties++;
121 else
123 TRACE("Skipping extension '%s', no implementation found in winevulkan.\n", host_properties[i].extensionName);
127 TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties, num_properties);
129 if (!(object->extensions = heap_calloc(num_properties, sizeof(*object->extensions))))
131 ERR("Failed to allocate memory for device extensions!\n");
132 goto err;
135 for (i = 0, j = 0; i < num_host_properties; i++)
137 if (wine_vk_device_extension_supported(host_properties[i].extensionName))
139 object->extensions[j] = host_properties[i];
140 j++;
143 object->extension_count = num_properties;
145 heap_free(host_properties);
146 return object;
148 err:
149 wine_vk_physical_device_free(object);
150 heap_free(host_properties);
151 return NULL;
154 /* Helper function to release command buffers. */
155 static void wine_vk_command_buffers_free(struct VkDevice_T *device, VkCommandPool pool,
156 uint32_t count, const VkCommandBuffer *buffers)
158 unsigned int i;
160 for (i = 0; i < count; i++)
162 if (!buffers[i])
163 continue;
165 device->funcs.p_vkFreeCommandBuffers(device->device, pool, 1, &buffers[i]->command_buffer);
166 heap_free(buffers[i]);
170 /* Helper function to create queues for a given family index. */
171 static struct VkQueue_T *wine_vk_device_alloc_queues(struct VkDevice_T *device,
172 uint32_t family_index, uint32_t queue_count, VkDeviceQueueCreateFlags flags)
174 VkDeviceQueueInfo2 queue_info;
175 struct VkQueue_T *queues;
176 unsigned int i;
178 if (!(queues = heap_calloc(queue_count, sizeof(*queues))))
180 ERR("Failed to allocate memory for queues\n");
181 return NULL;
184 for (i = 0; i < queue_count; i++)
186 struct VkQueue_T *queue = &queues[i];
188 queue->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
189 queue->device = device;
190 queue->flags = flags;
192 /* The Vulkan spec says:
194 * "vkGetDeviceQueue must only be used to get queues that were created
195 * with the flags parameter of VkDeviceQueueCreateInfo set to zero."
197 if (flags && device->funcs.p_vkGetDeviceQueue2)
199 queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2;
200 queue_info.pNext = NULL;
201 queue_info.flags = flags;
202 queue_info.queueFamilyIndex = family_index;
203 queue_info.queueIndex = i;
204 device->funcs.p_vkGetDeviceQueue2(device->device, &queue_info, &queue->queue);
206 else
208 device->funcs.p_vkGetDeviceQueue(device->device, family_index, i, &queue->queue);
212 return queues;
215 static VkDeviceGroupDeviceCreateInfo *convert_VkDeviceGroupDeviceCreateInfo(const void *src)
217 const VkDeviceGroupDeviceCreateInfo *in = src;
218 VkDeviceGroupDeviceCreateInfo *out;
219 VkPhysicalDevice *physical_devices;
220 unsigned int i;
222 if (!(out = heap_alloc(sizeof(*out))))
223 return NULL;
225 *out = *in;
226 if (!(physical_devices = heap_calloc(in->physicalDeviceCount, sizeof(*physical_devices))))
228 heap_free(out);
229 return NULL;
231 for (i = 0; i < in->physicalDeviceCount; ++i)
232 physical_devices[i] = in->pPhysicalDevices[i]->phys_dev;
233 out->pPhysicalDevices = physical_devices;
235 return out;
238 static VkResult wine_vk_device_convert_create_info(const VkDeviceCreateInfo *src,
239 VkDeviceCreateInfo *dst)
241 unsigned int i;
243 *dst = *src;
245 /* Application and loader can pass in a chain of extensions through pNext.
246 * We can't blindly pass these through as often these contain callbacks or
247 * they can even be pass structures for loader / ICD internal use.
249 if (src->pNext)
251 const struct wine_vk_structure_header *header;
253 dst->pNext = NULL;
254 for (header = src->pNext; header; header = header->pNext)
256 switch (header->sType)
258 case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO:
259 /* Used for loader to ICD communication. Ignore to not confuse
260 * host loader.
262 break;
264 case VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO:
265 if (!(dst->pNext = convert_VkDeviceGroupDeviceCreateInfo(header)))
266 return VK_ERROR_OUT_OF_HOST_MEMORY;
267 break;
269 default:
270 FIXME("Application requested a linked structure of type %#x.\n", header->sType);
275 /* Should be filtered out by loader as ICDs don't support layers. */
276 dst->enabledLayerCount = 0;
277 dst->ppEnabledLayerNames = NULL;
279 TRACE("Enabled extensions: %u.\n", dst->enabledExtensionCount);
280 for (i = 0; i < dst->enabledExtensionCount; i++)
282 TRACE("Extension %u: %s.\n", i, debugstr_a(dst->ppEnabledExtensionNames[i]));
285 return VK_SUCCESS;
288 static void wine_vk_device_free_create_info(VkDeviceCreateInfo *create_info)
290 VkDeviceGroupDeviceCreateInfo *group_info;
292 if ((group_info = wine_vk_find_struct(create_info, DEVICE_GROUP_DEVICE_CREATE_INFO)))
294 heap_free((void *)group_info->pPhysicalDevices);
295 heap_free(group_info);
298 create_info->pNext = NULL;
301 /* Helper function used for freeing a device structure. This function supports full
302 * and partial object cleanups and can thus be used for vkCreateDevice failures.
304 static void wine_vk_device_free(struct VkDevice_T *device)
306 if (!device)
307 return;
309 if (device->queues)
311 unsigned int i;
312 for (i = 0; i < device->max_queue_families; i++)
314 heap_free(device->queues[i]);
316 heap_free(device->queues);
317 device->queues = NULL;
320 if (device->device && device->funcs.p_vkDestroyDevice)
322 device->funcs.p_vkDestroyDevice(device->device, NULL /* pAllocator */);
325 heap_free(device);
328 static BOOL wine_vk_init(void)
330 HDC hdc;
332 hdc = GetDC(0);
333 vk_funcs = __wine_get_vulkan_driver(hdc, WINE_VULKAN_DRIVER_VERSION);
334 ReleaseDC(0, hdc);
335 if (!vk_funcs)
337 ERR("Failed to load Wine graphics driver supporting Vulkan.\n");
338 return FALSE;
341 p_vkEnumerateInstanceVersion = vk_funcs->p_vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
343 return TRUE;
346 /* Helper function for converting between win32 and host compatible VkInstanceCreateInfo.
347 * This function takes care of extensions handled at winevulkan layer, a Wine graphics
348 * driver is responsible for handling e.g. surface extensions.
350 static void wine_vk_instance_convert_create_info(const VkInstanceCreateInfo *src,
351 VkInstanceCreateInfo *dst)
353 unsigned int i;
355 *dst = *src;
357 if (dst->pApplicationInfo)
359 const VkApplicationInfo *app_info = dst->pApplicationInfo;
360 TRACE("Application name %s, application version %#x\n",
361 debugstr_a(app_info->pApplicationName), app_info->applicationVersion);
362 TRACE("Engine name %s, engine version %#x\n", debugstr_a(app_info->pEngineName),
363 app_info->engineVersion);
364 TRACE("API version %#x\n", app_info->apiVersion);
367 /* Application and loader can pass in a chain of extensions through pNext.
368 * We can't blindly pass these through as often these contain callbacks or
369 * they can even be pass structures for loader / ICD internal use. For now
370 * we ignore everything in pNext chain, but we print FIXMEs.
372 if (src->pNext)
374 const struct wine_vk_structure_header *header;
376 for (header = src->pNext; header; header = header->pNext)
378 switch (header->sType)
380 case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:
381 /* Can be used to register new dispatchable object types
382 * to the loader. We should ignore it as it will confuse the
383 * host its loader.
385 break;
387 default:
388 FIXME("Application requested a linked structure of type %#x.\n", header->sType);
392 /* For now don't support anything. */
393 dst->pNext = NULL;
395 /* ICDs don't support any layers, so nothing to copy. Modern versions of the loader
396 * filter this data out as well.
398 dst->enabledLayerCount = 0;
399 dst->ppEnabledLayerNames = NULL;
401 TRACE("Enabled extensions: %u\n", dst->enabledExtensionCount);
402 for (i = 0; i < dst->enabledExtensionCount; i++)
404 TRACE("Extension %u: %s\n", i, debugstr_a(dst->ppEnabledExtensionNames[i]));
408 /* Helper function which stores wrapped physical devices in the instance object. */
409 static VkResult wine_vk_instance_load_physical_devices(struct VkInstance_T *instance)
411 VkPhysicalDevice *tmp_phys_devs;
412 uint32_t phys_dev_count;
413 unsigned int i;
414 VkResult res;
416 res = instance->funcs.p_vkEnumeratePhysicalDevices(instance->instance, &phys_dev_count, NULL);
417 if (res != VK_SUCCESS)
419 ERR("Failed to enumerate physical devices, res=%d\n", res);
420 return res;
422 if (!phys_dev_count)
423 return res;
425 if (!(tmp_phys_devs = heap_calloc(phys_dev_count, sizeof(*tmp_phys_devs))))
426 return VK_ERROR_OUT_OF_HOST_MEMORY;
428 res = instance->funcs.p_vkEnumeratePhysicalDevices(instance->instance, &phys_dev_count, tmp_phys_devs);
429 if (res != VK_SUCCESS)
431 heap_free(tmp_phys_devs);
432 return res;
435 instance->phys_devs = heap_calloc(phys_dev_count, sizeof(*instance->phys_devs));
436 if (!instance->phys_devs)
438 heap_free(tmp_phys_devs);
439 return VK_ERROR_OUT_OF_HOST_MEMORY;
442 /* Wrap each native physical device handle into a dispatchable object for the ICD loader. */
443 for (i = 0; i < phys_dev_count; i++)
445 struct VkPhysicalDevice_T *phys_dev = wine_vk_physical_device_alloc(instance, tmp_phys_devs[i]);
446 if (!phys_dev)
448 ERR("Unable to allocate memory for physical device!\n");
449 heap_free(tmp_phys_devs);
450 return VK_ERROR_OUT_OF_HOST_MEMORY;
453 instance->phys_devs[i] = phys_dev;
454 instance->phys_dev_count = i + 1;
456 instance->phys_dev_count = phys_dev_count;
458 heap_free(tmp_phys_devs);
459 return VK_SUCCESS;
462 static struct VkPhysicalDevice_T *wine_vk_instance_wrap_physical_device(struct VkInstance_T *instance,
463 VkPhysicalDevice physical_device)
465 unsigned int i;
467 for (i = 0; i < instance->phys_dev_count; ++i)
469 struct VkPhysicalDevice_T *current = instance->phys_devs[i];
470 if (current->phys_dev == physical_device)
471 return current;
474 ERR("Unrecognized physical device %p.\n", physical_device);
475 return NULL;
478 /* Helper function used for freeing an instance structure. This function supports full
479 * and partial object cleanups and can thus be used for vkCreateInstance failures.
481 static void wine_vk_instance_free(struct VkInstance_T *instance)
483 if (!instance)
484 return;
486 if (instance->phys_devs)
488 unsigned int i;
490 for (i = 0; i < instance->phys_dev_count; i++)
492 wine_vk_physical_device_free(instance->phys_devs[i]);
494 heap_free(instance->phys_devs);
497 if (instance->instance)
498 vk_funcs->p_vkDestroyInstance(instance->instance, NULL /* allocator */);
500 heap_free(instance);
503 VkResult WINAPI wine_vkAllocateCommandBuffers(VkDevice device,
504 const VkCommandBufferAllocateInfo *allocate_info, VkCommandBuffer *buffers)
506 VkResult res = VK_SUCCESS;
507 unsigned int i;
509 TRACE("%p %p %p\n", device, allocate_info, buffers);
511 memset(buffers, 0, allocate_info->commandBufferCount * sizeof(*buffers));
513 for (i = 0; i < allocate_info->commandBufferCount; i++)
515 #if defined(USE_STRUCT_CONVERSION)
516 VkCommandBufferAllocateInfo_host allocate_info_host;
517 #else
518 VkCommandBufferAllocateInfo allocate_info_host;
519 #endif
520 /* TODO: future extensions (none yet) may require pNext conversion. */
521 allocate_info_host.pNext = allocate_info->pNext;
522 allocate_info_host.sType = allocate_info->sType;
523 allocate_info_host.commandPool = allocate_info->commandPool;
524 allocate_info_host.level = allocate_info->level;
525 allocate_info_host.commandBufferCount = 1;
527 TRACE("Creating command buffer %u, pool 0x%s, level %#x\n", i,
528 wine_dbgstr_longlong(allocate_info_host.commandPool),
529 allocate_info_host.level);
531 if (!(buffers[i] = heap_alloc_zero(sizeof(**buffers))))
533 res = VK_ERROR_OUT_OF_HOST_MEMORY;
534 break;
537 buffers[i]->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
538 buffers[i]->device = device;
539 res = device->funcs.p_vkAllocateCommandBuffers(device->device,
540 &allocate_info_host, &buffers[i]->command_buffer);
541 if (res != VK_SUCCESS)
543 ERR("Failed to allocate command buffer, res=%d\n", res);
544 break;
548 if (res != VK_SUCCESS)
550 wine_vk_command_buffers_free(device, allocate_info->commandPool, i, buffers);
551 memset(buffers, 0, allocate_info->commandBufferCount * sizeof(*buffers));
552 return res;
555 return VK_SUCCESS;
558 void WINAPI wine_vkCmdExecuteCommands(VkCommandBuffer buffer, uint32_t count,
559 const VkCommandBuffer *buffers)
561 VkCommandBuffer *tmp_buffers;
562 unsigned int i;
564 TRACE("%p %u %p\n", buffer, count, buffers);
566 if (!buffers || !count)
567 return;
569 /* Unfortunately we need a temporary buffer as our command buffers are wrapped.
570 * This call is called often and if a performance concern, we may want to use
571 * alloca as we shouldn't need much memory and it needs to be cleaned up after
572 * the call anyway.
574 if (!(tmp_buffers = heap_alloc(count * sizeof(*tmp_buffers))))
576 ERR("Failed to allocate memory for temporary command buffers\n");
577 return;
580 for (i = 0; i < count; i++)
581 tmp_buffers[i] = buffers[i]->command_buffer;
583 buffer->device->funcs.p_vkCmdExecuteCommands(buffer->command_buffer, count, tmp_buffers);
585 heap_free(tmp_buffers);
588 VkResult WINAPI wine_vkCreateDevice(VkPhysicalDevice phys_dev,
589 const VkDeviceCreateInfo *create_info,
590 const VkAllocationCallbacks *allocator, VkDevice *device)
592 VkDeviceCreateInfo create_info_host;
593 uint32_t max_queue_families;
594 struct VkDevice_T *object;
595 unsigned int i;
596 VkResult res;
598 TRACE("%p, %p, %p, %p\n", phys_dev, create_info, allocator, device);
600 if (allocator)
601 FIXME("Support for allocation callbacks not implemented yet\n");
603 if (!(object = heap_alloc_zero(sizeof(*object))))
604 return VK_ERROR_OUT_OF_HOST_MEMORY;
606 object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
608 res = wine_vk_device_convert_create_info(create_info, &create_info_host);
609 if (res != VK_SUCCESS)
611 ERR("Failed to convert VkDeviceCreateInfo, res=%d.\n", res);
612 wine_vk_device_free(object);
613 return res;
616 res = phys_dev->instance->funcs.p_vkCreateDevice(phys_dev->phys_dev,
617 &create_info_host, NULL /* allocator */, &object->device);
618 wine_vk_device_free_create_info(&create_info_host);
619 if (res != VK_SUCCESS)
621 ERR("Failed to create device.\n");
622 wine_vk_device_free(object);
623 return res;
626 /* Just load all function pointers we are aware off. The loader takes care of filtering.
627 * We use vkGetDeviceProcAddr as opposed to vkGetInstanceProcAddr for efficiency reasons
628 * as functions pass through fewer dispatch tables within the loader.
630 #define USE_VK_FUNC(name) \
631 object->funcs.p_##name = (void *)vk_funcs->p_vkGetDeviceProcAddr(object->device, #name); \
632 if (object->funcs.p_##name == NULL) \
633 TRACE("Not found %s\n", #name);
634 ALL_VK_DEVICE_FUNCS()
635 #undef USE_VK_FUNC
637 /* We need to cache all queues within the device as each requires wrapping since queues are
638 * dispatchable objects.
640 phys_dev->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties(phys_dev->phys_dev,
641 &max_queue_families, NULL);
642 object->max_queue_families = max_queue_families;
643 TRACE("Max queue families: %u\n", object->max_queue_families);
645 object->queues = heap_calloc(max_queue_families, sizeof(*object->queues));
646 if (!object->queues)
648 wine_vk_device_free(object);
649 return VK_ERROR_OUT_OF_HOST_MEMORY;
652 for (i = 0; i < create_info_host.queueCreateInfoCount; i++)
654 uint32_t flags = create_info_host.pQueueCreateInfos[i].flags;
655 uint32_t family_index = create_info_host.pQueueCreateInfos[i].queueFamilyIndex;
656 uint32_t queue_count = create_info_host.pQueueCreateInfos[i].queueCount;
658 TRACE("queueFamilyIndex %u, queueCount %u\n", family_index, queue_count);
660 object->queues[family_index] = wine_vk_device_alloc_queues(object, family_index,
661 queue_count, flags);
662 if (!object->queues[family_index])
664 ERR("Failed to allocate memory for queues\n");
665 wine_vk_device_free(object);
666 return VK_ERROR_OUT_OF_HOST_MEMORY;
670 object->quirks = phys_dev->instance->quirks;
672 *device = object;
673 TRACE("Created device %p (native device %p).\n", object, object->device);
674 return VK_SUCCESS;
677 VkResult WINAPI wine_vkCreateInstance(const VkInstanceCreateInfo *create_info,
678 const VkAllocationCallbacks *allocator, VkInstance *instance)
680 VkInstanceCreateInfo create_info_host;
681 const VkApplicationInfo *app_info;
682 struct VkInstance_T *object;
683 VkResult res;
685 TRACE("create_info %p, allocator %p, instance %p\n", create_info, allocator, instance);
687 if (allocator)
688 FIXME("Support for allocation callbacks not implemented yet\n");
690 if (!(object = heap_alloc_zero(sizeof(*object))))
692 ERR("Failed to allocate memory for instance\n");
693 return VK_ERROR_OUT_OF_HOST_MEMORY;
695 object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
697 wine_vk_instance_convert_create_info(create_info, &create_info_host);
699 res = vk_funcs->p_vkCreateInstance(&create_info_host, NULL /* allocator */, &object->instance);
700 if (res != VK_SUCCESS)
702 ERR("Failed to create instance, res=%d\n", res);
703 wine_vk_instance_free(object);
704 return res;
707 /* Load all instance functions we are aware of. Note the loader takes care
708 * of any filtering for extensions which were not requested, but which the
709 * ICD may support.
711 #define USE_VK_FUNC(name) \
712 object->funcs.p_##name = (void *)vk_funcs->p_vkGetInstanceProcAddr(object->instance, #name);
713 ALL_VK_INSTANCE_FUNCS()
714 #undef USE_VK_FUNC
716 /* Cache physical devices for vkEnumeratePhysicalDevices within the instance as
717 * each vkPhysicalDevice is a dispatchable object, which means we need to wrap
718 * the native physical devices and present those to the application.
719 * Cleanup happens as part of wine_vkDestroyInstance.
721 res = wine_vk_instance_load_physical_devices(object);
722 if (res != VK_SUCCESS)
724 ERR("Failed to load physical devices, res=%d\n", res);
725 wine_vk_instance_free(object);
726 return res;
729 if ((app_info = create_info->pApplicationInfo) && app_info->pApplicationName)
731 if (!strcmp(app_info->pApplicationName, "DOOM")
732 || !strcmp(app_info->pApplicationName, "Wolfenstein II The New Colossus"))
733 object->quirks |= WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR;
736 *instance = object;
737 TRACE("Created instance %p (native instance %p).\n", object, object->instance);
738 return VK_SUCCESS;
741 void WINAPI wine_vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *allocator)
743 TRACE("%p %p\n", device, allocator);
745 if (allocator)
746 FIXME("Support for allocation callbacks not implemented yet\n");
748 wine_vk_device_free(device);
751 void WINAPI wine_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *allocator)
753 TRACE("%p, %p\n", instance, allocator);
755 if (allocator)
756 FIXME("Support allocation allocators\n");
758 wine_vk_instance_free(instance);
761 VkResult WINAPI wine_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice phys_dev,
762 const char *layer_name, uint32_t *count, VkExtensionProperties *properties)
764 TRACE("%p, %p, %p, %p\n", phys_dev, layer_name, count, properties);
766 /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
767 if (layer_name)
769 ERR("Layer enumeration not supported from ICD.\n");
770 return VK_ERROR_LAYER_NOT_PRESENT;
773 if (!properties)
775 *count = phys_dev->extension_count;
776 return VK_SUCCESS;
779 *count = min(*count, phys_dev->extension_count);
780 memcpy(properties, phys_dev->extensions, *count * sizeof(*properties));
782 TRACE("Returning %u extensions.\n", *count);
783 return *count < phys_dev->extension_count ? VK_INCOMPLETE : VK_SUCCESS;
786 VkResult WINAPI wine_vkEnumerateInstanceExtensionProperties(const char *layer_name,
787 uint32_t *count, VkExtensionProperties *properties)
789 uint32_t num_properties = 0, num_host_properties;
790 VkExtensionProperties *host_properties;
791 unsigned int i, j;
792 VkResult res;
794 TRACE("%p, %p, %p\n", layer_name, count, properties);
796 if (layer_name)
798 WARN("Layer enumeration not supported from ICD.\n");
799 return VK_ERROR_LAYER_NOT_PRESENT;
802 res = vk_funcs->p_vkEnumerateInstanceExtensionProperties(NULL, &num_host_properties, NULL);
803 if (res != VK_SUCCESS)
804 return res;
806 if (!(host_properties = heap_calloc(num_host_properties, sizeof(*host_properties))))
807 return VK_ERROR_OUT_OF_HOST_MEMORY;
809 res = vk_funcs->p_vkEnumerateInstanceExtensionProperties(NULL, &num_host_properties, host_properties);
810 if (res != VK_SUCCESS)
812 ERR("Failed to retrieve host properties, res=%d.\n", res);
813 heap_free(host_properties);
814 return res;
817 /* The Wine graphics driver provides us with all extensions supported by the host side
818 * including extension fixup (e.g. VK_KHR_xlib_surface -> VK_KHR_win32_surface). It is
819 * up to us here to filter the list down to extensions for which we have thunks.
821 for (i = 0; i < num_host_properties; i++)
823 if (wine_vk_instance_extension_supported(host_properties[i].extensionName))
824 num_properties++;
825 else
826 TRACE("Instance extension '%s' is not supported.\n", host_properties[i].extensionName);
829 if (!properties)
831 TRACE("Returning %u extensions.\n", num_properties);
832 *count = num_properties;
833 heap_free(host_properties);
834 return VK_SUCCESS;
837 for (i = 0, j = 0; i < num_host_properties && j < *count; i++)
839 if (wine_vk_instance_extension_supported(host_properties[i].extensionName))
841 TRACE("Enabling extension '%s'.\n", host_properties[i].extensionName);
842 properties[j++] = host_properties[i];
845 *count = min(*count, num_properties);
847 heap_free(host_properties);
848 return *count < num_properties ? VK_INCOMPLETE : VK_SUCCESS;
851 VkResult WINAPI wine_vkEnumerateInstanceLayerProperties(uint32_t *count, VkLayerProperties *properties)
853 TRACE("%p, %p\n", count, properties);
855 if (!properties)
857 *count = 0;
858 return VK_SUCCESS;
861 return VK_ERROR_LAYER_NOT_PRESENT;
864 VkResult WINAPI wine_vkEnumerateInstanceVersion(uint32_t *version)
866 VkResult res;
868 TRACE("%p\n", version);
870 if (p_vkEnumerateInstanceVersion)
872 res = p_vkEnumerateInstanceVersion(version);
874 else
876 *version = VK_API_VERSION_1_0;
877 res = VK_SUCCESS;
880 TRACE("API version %u.%u.%u.\n",
881 VK_VERSION_MAJOR(*version), VK_VERSION_MINOR(*version), VK_VERSION_PATCH(*version));
882 *version = min(WINE_VK_VERSION, *version);
883 return res;
886 VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *count,
887 VkPhysicalDevice *devices)
889 unsigned int i;
891 TRACE("%p %p %p\n", instance, count, devices);
893 if (!devices)
895 *count = instance->phys_dev_count;
896 return VK_SUCCESS;
899 *count = min(*count, instance->phys_dev_count);
900 for (i = 0; i < *count; i++)
902 devices[i] = instance->phys_devs[i];
905 TRACE("Returning %u devices.\n", *count);
906 return *count < instance->phys_dev_count ? VK_INCOMPLETE : VK_SUCCESS;
909 void WINAPI wine_vkFreeCommandBuffers(VkDevice device, VkCommandPool pool, uint32_t count,
910 const VkCommandBuffer *buffers)
912 TRACE("%p 0x%s %u %p\n", device, wine_dbgstr_longlong(pool), count, buffers);
914 wine_vk_command_buffers_free(device, pool, count, buffers);
917 PFN_vkVoidFunction WINAPI wine_vkGetDeviceProcAddr(VkDevice device, const char *name)
919 void *func;
920 TRACE("%p, %s\n", device, debugstr_a(name));
922 /* The spec leaves return value undefined for a NULL device, let's just return NULL. */
923 if (!device || !name)
924 return NULL;
926 /* Per the spec, we are only supposed to return device functions as in functions
927 * for which the first parameter is vkDevice or a child of vkDevice like a
928 * vkCommandBuffer or vkQueue.
929 * Loader takes care of filtering of extensions which are enabled or not.
931 func = wine_vk_get_device_proc_addr(name);
932 if (func)
933 return func;
935 /* vkGetDeviceProcAddr was intended for loading device and subdevice functions.
936 * idTech 6 titles such as Doom and Wolfenstein II, however use it also for
937 * loading of instance functions. This is undefined behavior as the specification
938 * disallows using any of the returned function pointers outside of device /
939 * subdevice objects. The games don't actually use the function pointers and if they
940 * did, they would crash as VkInstance / VkPhysicalDevice parameters need unwrapping.
941 * Khronos clarified behavior in the Vulkan spec and expects drivers to get updated,
942 * however it would require both driver and game fixes.
943 * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/2323
944 * https://github.com/KhronosGroup/Vulkan-Docs/issues/655
946 if (device->quirks & WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR
947 && (func = wine_vk_get_instance_proc_addr(name)))
949 WARN("Returning instance function %s.\n", debugstr_a(name));
950 return func;
953 WARN("Unsupported device function: %s.\n", debugstr_a(name));
954 return NULL;
957 void WINAPI wine_vkGetDeviceQueue(VkDevice device, uint32_t family_index,
958 uint32_t queue_index, VkQueue *queue)
960 TRACE("%p, %u, %u, %p\n", device, family_index, queue_index, queue);
962 *queue = &device->queues[family_index][queue_index];
965 void WINAPI wine_vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *info, VkQueue *queue)
967 const struct wine_vk_structure_header *chain;
968 struct VkQueue_T *matching_queue;
970 TRACE("%p, %p, %p\n", device, info, queue);
972 if ((chain = info->pNext))
973 FIXME("Ignoring a linked structure of type %#x.\n", chain->sType);
975 matching_queue = &device->queues[info->queueFamilyIndex][info->queueIndex];
976 if (matching_queue->flags != info->flags)
978 WARN("No matching flags were specified %#x, %#x.\n", matching_queue->flags, info->flags);
979 matching_queue = VK_NULL_HANDLE;
981 *queue = matching_queue;
984 PFN_vkVoidFunction WINAPI wine_vkGetInstanceProcAddr(VkInstance instance, const char *name)
986 void *func;
988 TRACE("%p, %s\n", instance, debugstr_a(name));
990 if (!name)
991 return NULL;
993 /* vkGetInstanceProcAddr can load most Vulkan functions when an instance is passed in, however
994 * for a NULL instance it can only load global functions.
996 func = wine_vk_get_global_proc_addr(name);
997 if (func)
999 return func;
1001 if (!instance)
1003 WARN("Global function %s not found.\n", debugstr_a(name));
1004 return NULL;
1007 func = wine_vk_get_instance_proc_addr(name);
1008 if (func) return func;
1010 /* vkGetInstanceProcAddr also loads any children of instance, so device functions as well. */
1011 func = wine_vk_get_device_proc_addr(name);
1012 if (func) return func;
1014 WARN("Unsupported device or instance function: %s.\n", debugstr_a(name));
1015 return NULL;
1018 void * WINAPI wine_vk_icdGetInstanceProcAddr(VkInstance instance, const char *name)
1020 TRACE("%p, %s\n", instance, debugstr_a(name));
1022 /* Initial version of the Vulkan ICD spec required vkGetInstanceProcAddr to be
1023 * exported. vk_icdGetInstanceProcAddr was added later to separate ICD calls from
1024 * Vulkan API. One of them in our case should forward to the other, so just forward
1025 * to the older vkGetInstanceProcAddr.
1027 return wine_vkGetInstanceProcAddr(instance, name);
1030 VkResult WINAPI wine_vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t *supported_version)
1032 uint32_t req_version;
1034 TRACE("%p\n", supported_version);
1036 /* The spec is not clear how to handle this. Mesa drivers don't check, but it
1037 * is probably best to not explode. VK_INCOMPLETE seems to be the closest value.
1039 if (!supported_version)
1040 return VK_INCOMPLETE;
1042 req_version = *supported_version;
1043 *supported_version = min(req_version, WINE_VULKAN_ICD_VERSION);
1044 TRACE("Loader requested ICD version %u, returning %u\n", req_version, *supported_version);
1046 return VK_SUCCESS;
1049 VkResult WINAPI wine_vkQueueSubmit(VkQueue queue, uint32_t count,
1050 const VkSubmitInfo *submits, VkFence fence)
1052 VkSubmitInfo *submits_host;
1053 VkResult res;
1054 VkCommandBuffer *command_buffers;
1055 unsigned int i, j, num_command_buffers;
1057 TRACE("%p %u %p 0x%s\n", queue, count, submits, wine_dbgstr_longlong(fence));
1059 if (count == 0)
1061 return queue->device->funcs.p_vkQueueSubmit(queue->queue, 0, NULL, fence);
1064 submits_host = heap_calloc(count, sizeof(*submits_host));
1065 if (!submits_host)
1067 ERR("Unable to allocate memory for submit buffers!\n");
1068 return VK_ERROR_OUT_OF_HOST_MEMORY;
1071 for (i = 0; i < count; i++)
1073 memcpy(&submits_host[i], &submits[i], sizeof(*submits_host));
1075 num_command_buffers = submits[i].commandBufferCount;
1076 command_buffers = heap_calloc(num_command_buffers, sizeof(*submits_host));
1077 if (!command_buffers)
1079 ERR("Unable to allocate memory for comman buffers!\n");
1080 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1081 goto err;
1084 for (j = 0; j < num_command_buffers; j++)
1086 command_buffers[j] = submits[i].pCommandBuffers[j]->command_buffer;
1088 submits_host[i].pCommandBuffers = command_buffers;
1091 res = queue->device->funcs.p_vkQueueSubmit(queue->queue, count, submits_host, fence);
1093 err:
1094 for (i = 0; i < count; i++)
1096 heap_free((void *)submits_host[i].pCommandBuffers);
1098 heap_free(submits_host);
1100 TRACE("Returning %d\n", res);
1101 return res;
1104 static VkResult wine_vk_enumerate_physical_device_groups(struct VkInstance_T *instance,
1105 VkResult (*p_vkEnumeratePhysicalDeviceGroups)(VkInstance, uint32_t *, VkPhysicalDeviceGroupProperties *),
1106 uint32_t *count, VkPhysicalDeviceGroupProperties *properties)
1108 unsigned int i, j;
1109 VkResult res;
1111 res = p_vkEnumeratePhysicalDeviceGroups(instance->instance, count, properties);
1112 if (res < 0 || !properties)
1113 return res;
1115 for (i = 0; i < *count; ++i)
1117 VkPhysicalDeviceGroupProperties *current = &properties[i];
1118 for (j = 0; j < current->physicalDeviceCount; ++j)
1120 VkPhysicalDevice dev = current->physicalDevices[j];
1121 if (!(current->physicalDevices[j] = wine_vk_instance_wrap_physical_device(instance, dev)))
1122 return VK_ERROR_INITIALIZATION_FAILED;
1126 return res;
1129 VkResult WINAPI wine_vkEnumeratePhysicalDeviceGroups(VkInstance instance,
1130 uint32_t *count, VkPhysicalDeviceGroupProperties *properties)
1132 TRACE("%p, %p, %p\n", instance, count, properties);
1133 return wine_vk_enumerate_physical_device_groups(instance,
1134 instance->funcs.p_vkEnumeratePhysicalDeviceGroups, count, properties);
1137 VkResult WINAPI wine_vkEnumeratePhysicalDeviceGroupsKHR(VkInstance instance,
1138 uint32_t *count, VkPhysicalDeviceGroupProperties *properties)
1140 TRACE("%p, %p, %p\n", instance, count, properties);
1141 return wine_vk_enumerate_physical_device_groups(instance,
1142 instance->funcs.p_vkEnumeratePhysicalDeviceGroupsKHR, count, properties);
1145 BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved)
1147 TRACE("%p, %u, %p\n", hinst, reason, reserved);
1149 switch (reason)
1151 case DLL_PROCESS_ATTACH:
1152 DisableThreadLibraryCalls(hinst);
1153 return wine_vk_init();
1155 return TRUE;
1158 static const struct vulkan_func vk_global_dispatch_table[] =
1160 {"vkCreateInstance", &wine_vkCreateInstance},
1161 {"vkEnumerateInstanceExtensionProperties", &wine_vkEnumerateInstanceExtensionProperties},
1162 {"vkEnumerateInstanceLayerProperties", &wine_vkEnumerateInstanceLayerProperties},
1163 {"vkEnumerateInstanceVersion", &wine_vkEnumerateInstanceVersion},
1164 {"vkGetInstanceProcAddr", &wine_vkGetInstanceProcAddr},
1167 static void *wine_vk_get_global_proc_addr(const char *name)
1169 unsigned int i;
1171 for (i = 0; i < ARRAY_SIZE(vk_global_dispatch_table); i++)
1173 if (strcmp(name, vk_global_dispatch_table[i].name) == 0)
1175 TRACE("Found name=%s in global table\n", debugstr_a(name));
1176 return vk_global_dispatch_table[i].func;
1179 return NULL;
1183 * Wrapper around driver vkGetInstanceProcAddr implementation.
1184 * Allows winelib applications to access Vulkan functions with Wine
1185 * additions and native ABI.
1187 void *native_vkGetInstanceProcAddrWINE(VkInstance instance, const char *name)
1189 return vk_funcs->p_vkGetInstanceProcAddr(instance, name);