winevulkan: Fix some typos in comments.
[wine.git] / dlls / winevulkan / vulkan.c
blob41a45efc7962c83044df6cb2e84d1c4e64e8ce52
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 "wine/debug.h"
27 #include "wine/heap.h"
28 #include "wine/vulkan.h"
29 #include "wine/vulkan_driver.h"
30 #include "vulkan_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
34 /* For now default to 4 as it felt like a reasonable version feature wise to support.
35 * Don't support the optional vk_icdGetPhysicalDeviceProcAddr introduced in this version
36 * as it is unlikely we will implement physical device extensions, which the loader is not
37 * aware off. Version 5 adds more extensive version checks. Something to tackle later.
39 #define WINE_VULKAN_ICD_VERSION 4
41 /* All Vulkan structures use this structure for the first elements. */
42 struct wine_vk_structure_header
44 VkStructureType sType;
45 const void *pNext;
48 static void *wine_vk_get_global_proc_addr(const char *name);
49 static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstance_T *instance,
50 VkPhysicalDevice phys_dev_host);
51 static void wine_vk_physical_device_free(struct VkPhysicalDevice_T *phys_dev);
53 static const struct vulkan_funcs *vk_funcs = NULL;
55 /* Helper function for release command buffers. */
56 static void wine_vk_command_buffers_free(struct VkDevice_T *device, VkCommandPool pool,
57 uint32_t count, const VkCommandBuffer *buffers)
59 unsigned int i;
61 for (i = 0; i < count; i++)
63 if (!buffers[i])
64 continue;
66 device->funcs.p_vkFreeCommandBuffers(device->device, pool, 1, &buffers[i]->command_buffer);
67 heap_free(buffers[i]);
71 /* Helper function to create queues for a given family index. */
72 static struct VkQueue_T *wine_vk_device_alloc_queues(struct VkDevice_T *device,
73 uint32_t family_index, uint32_t queue_count)
75 struct VkQueue_T *queues;
76 unsigned int i;
78 if (!(queues = heap_calloc(queue_count, sizeof(*queues))))
80 ERR("Failed to allocate memory for queues\n");
81 return NULL;
84 for (i = 0; i < queue_count; i++)
86 struct VkQueue_T *queue = &queues[i];
87 queue->device = device;
89 /* The native device was already allocated with the required number of queues,
90 * so just fetch them from there.
92 device->funcs.p_vkGetDeviceQueue(device->device, family_index, i, &queue->queue);
94 /* Set special header for ICD loader. */
95 ((struct wine_vk_base *)queue)->loader_magic = VULKAN_ICD_MAGIC_VALUE;
98 return queues;
101 /* Helper function used for freeing a device structure. This function supports full
102 * and partial object cleanups and can thus be used for vkCreateDevice failures.
104 static void wine_vk_device_free(struct VkDevice_T *device)
106 if (!device)
107 return;
109 if (device->queues)
111 unsigned int i;
112 for (i = 0; i < device->max_queue_families; i++)
114 heap_free(device->queues[i]);
116 heap_free(device->queues);
117 device->queues = NULL;
120 if (device->device && device->funcs.p_vkDestroyDevice)
122 device->funcs.p_vkDestroyDevice(device->device, NULL /* pAllocator */);
125 heap_free(device);
128 static BOOL wine_vk_init(void)
130 HDC hdc = GetDC(0);
132 vk_funcs = __wine_get_vulkan_driver(hdc, WINE_VULKAN_DRIVER_VERSION);
133 if (!vk_funcs)
135 ERR("Failed to load Wine graphics driver supporting Vulkan.\n");
136 ReleaseDC(0, hdc);
137 return FALSE;
140 ReleaseDC(0, hdc);
141 return TRUE;
144 /* Helper function for converting between win32 and host compatible VkInstanceCreateInfo.
145 * This function takes care of extensions handled at winevulkan layer, a Wine graphics
146 * driver is responsible for handling e.g. surface extensions.
148 static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo *src,
149 VkInstanceCreateInfo *dst)
151 dst->sType = src->sType;
152 dst->flags = src->flags;
153 dst->pApplicationInfo = src->pApplicationInfo;
155 /* Application and loader can pass in a chain of extensions through pNext.
156 * We can't blindly pass these through as often these contain callbacks or
157 * they can even be pass structures for loader / ICD internal use. For now
158 * we ignore everything in pNext chain, but we print FIXMEs.
160 if (src->pNext)
162 const struct wine_vk_structure_header *header;
164 for (header = src->pNext; header; header = header->pNext)
166 switch (header->sType)
168 case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO:
169 /* Can be used to register new dispatchable object types
170 * to the loader. We should ignore it as it will confuse the
171 * host its loader.
173 break;
175 default:
176 FIXME("Application requested a linked structure of type %d\n", header->sType);
180 /* For now don't support anything. */
181 dst->pNext = NULL;
183 /* ICDs don't support any layers, so nothing to copy. Modern versions of the loader
184 * filter this data out as well.
186 dst->enabledLayerCount = 0;
187 dst->ppEnabledLayerNames = NULL;
189 /* TODO: convert non-WSI win32 extensions here to host specific ones. */
190 dst->ppEnabledExtensionNames = src->ppEnabledExtensionNames;
191 dst->enabledExtensionCount = src->enabledExtensionCount;
193 return VK_SUCCESS;
196 /* Helper function which stores wrapped physical devices in the instance object. */
197 static VkResult wine_vk_instance_load_physical_devices(struct VkInstance_T *instance)
199 VkResult res;
200 struct VkPhysicalDevice_T **tmp_phys_devs = NULL;
201 uint32_t num_phys_devs = 0;
202 unsigned int i;
204 res = instance->funcs.p_vkEnumeratePhysicalDevices(instance->instance, &num_phys_devs, NULL);
205 if (res != VK_SUCCESS)
207 ERR("Failed to enumerate physical devices, res=%d\n", res);
208 return res;
211 /* Don't bother with any of the rest if the system just lacks devices. */
212 if (num_phys_devs == 0)
213 return VK_SUCCESS;
215 tmp_phys_devs = heap_calloc(num_phys_devs, sizeof(*tmp_phys_devs));
216 if (!tmp_phys_devs)
217 return VK_ERROR_OUT_OF_HOST_MEMORY;
219 res = instance->funcs.p_vkEnumeratePhysicalDevices(instance->instance, &num_phys_devs, tmp_phys_devs);
220 if (res != VK_SUCCESS)
221 goto err;
223 instance->phys_devs = heap_calloc(num_phys_devs, sizeof(*instance->phys_devs));
224 if (!instance->phys_devs)
226 res = VK_ERROR_OUT_OF_HOST_MEMORY;
227 goto err;
230 /* Wrap each native physical device handle into a dispatchable object for the ICD loader. */
231 for (i = 0; i < num_phys_devs; i++)
233 struct VkPhysicalDevice_T *phys_dev = wine_vk_physical_device_alloc(instance, tmp_phys_devs[i]);
234 if (!phys_dev)
236 ERR("Unable to allocate memory for physical device!\n");
237 res = VK_ERROR_OUT_OF_HOST_MEMORY;
238 goto err;
241 instance->phys_devs[i] = phys_dev;
242 instance->num_phys_devs = i + 1;
244 instance->num_phys_devs = num_phys_devs;
246 heap_free(tmp_phys_devs);
247 return VK_SUCCESS;
249 err:
250 heap_free(tmp_phys_devs);
251 return res;
254 /* Helper function used for freeing an instance structure. This function supports full
255 * and partial object cleanups and can thus be used for vkCreateInstance failures.
257 static void wine_vk_instance_free(struct VkInstance_T *instance)
259 if (!instance)
260 return;
262 if (instance->phys_devs)
264 unsigned int i;
266 for (i = 0; i < instance->num_phys_devs; i++)
268 wine_vk_physical_device_free(instance->phys_devs[i]);
270 heap_free(instance->phys_devs);
273 if (instance->instance)
274 vk_funcs->p_vkDestroyInstance(instance->instance, NULL /* allocator */);
276 heap_free(instance);
279 static struct VkPhysicalDevice_T *wine_vk_physical_device_alloc(struct VkInstance_T *instance,
280 VkPhysicalDevice phys_dev)
282 struct VkPhysicalDevice_T *object;
283 uint32_t num_host_properties, num_properties = 0;
284 VkExtensionProperties *host_properties = NULL;
285 VkResult res;
286 unsigned int i, j;
288 object = heap_alloc_zero(sizeof(*object));
289 if (!object)
290 return NULL;
292 object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
293 object->instance = instance;
294 object->phys_dev = phys_dev;
296 res = instance->funcs.p_vkEnumerateDeviceExtensionProperties(phys_dev,
297 NULL, &num_host_properties, NULL);
298 if (res != VK_SUCCESS)
300 ERR("Failed to enumerate device extensions, res=%d\n", res);
301 goto err;
304 host_properties = heap_calloc(num_host_properties, sizeof(*host_properties));
305 if (!host_properties)
307 ERR("Failed to allocate memory for device properties!\n");
308 goto err;
311 res = instance->funcs.p_vkEnumerateDeviceExtensionProperties(phys_dev,
312 NULL, &num_host_properties, host_properties);
313 if (res != VK_SUCCESS)
315 ERR("Failed to enumerate device extensions, res=%d\n", res);
316 goto err;
319 /* Count list of extensions for which we have an implementation.
320 * TODO: perform translation for platform specific extensions.
322 for (i = 0; i < num_host_properties; i++)
324 if (wine_vk_device_extension_supported(host_properties[i].extensionName))
326 TRACE("Enabling extension '%s' for physical device %p\n", host_properties[i].extensionName, object);
327 num_properties++;
329 else
331 TRACE("Skipping extension '%s', no implementation found in winevulkan.\n", host_properties[i].extensionName);
335 TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties, num_properties);
337 object->properties = heap_calloc(num_properties, sizeof(*object->properties));
338 if (!object->properties)
340 ERR("Failed to allocate memory for device properties!\n");
341 goto err;
344 for (i = 0, j = 0; i < num_host_properties; i++)
346 if (wine_vk_device_extension_supported(host_properties[i].extensionName))
348 memcpy(&object->properties[j], &host_properties[i], sizeof(*object->properties));
349 j++;
352 object->num_properties = num_properties;
354 heap_free(host_properties);
355 return object;
357 err:
358 wine_vk_physical_device_free(object);
359 heap_free(host_properties);
360 return NULL;
363 static void wine_vk_physical_device_free(struct VkPhysicalDevice_T *phys_dev)
365 if (!phys_dev)
366 return;
368 heap_free(phys_dev->properties);
369 heap_free(phys_dev);
372 VkResult WINAPI wine_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain,
373 uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *image_index)
375 TRACE("%p, 0x%s, 0x%s, 0x%s, 0x%s, %p\n", device, wine_dbgstr_longlong(swapchain),
376 wine_dbgstr_longlong(timeout), wine_dbgstr_longlong(semaphore),
377 wine_dbgstr_longlong(fence), image_index);
379 return vk_funcs->p_vkAcquireNextImageKHR(device->device, swapchain, timeout,
380 semaphore, fence, image_index);
383 VkResult WINAPI wine_vkAllocateCommandBuffers(VkDevice device,
384 const VkCommandBufferAllocateInfo *allocate_info, VkCommandBuffer *buffers)
386 VkResult res = VK_SUCCESS;
387 unsigned int i;
389 TRACE("%p %p %p\n", device, allocate_info, buffers);
391 memset(buffers, 0, allocate_info->commandBufferCount * sizeof(*buffers));
393 for (i = 0; i < allocate_info->commandBufferCount; i++)
395 #if defined(USE_STRUCT_CONVERSION)
396 VkCommandBufferAllocateInfo_host allocate_info_host;
397 #else
398 VkCommandBufferAllocateInfo allocate_info_host;
399 #endif
400 /* TODO: future extensions (none yet) may require pNext conversion. */
401 allocate_info_host.pNext = allocate_info->pNext;
402 allocate_info_host.sType = allocate_info->sType;
403 allocate_info_host.commandPool = allocate_info->commandPool;
404 allocate_info_host.level = allocate_info->level;
405 allocate_info_host.commandBufferCount = 1;
407 TRACE("Creating command buffer %u, pool 0x%s, level %#x\n", i,
408 wine_dbgstr_longlong(allocate_info_host.commandPool),
409 allocate_info_host.level);
411 if (!(buffers[i] = heap_alloc_zero(sizeof(*buffers))))
413 res = VK_ERROR_OUT_OF_HOST_MEMORY;
414 break;
417 buffers[i]->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
418 buffers[i]->device = device;
419 res = device->funcs.p_vkAllocateCommandBuffers(device->device,
420 &allocate_info_host, &buffers[i]->command_buffer);
421 if (res != VK_SUCCESS)
423 ERR("Failed to allocate command buffer, res=%d\n", res);
424 break;
428 if (res != VK_SUCCESS)
430 wine_vk_command_buffers_free(device, allocate_info->commandPool, i, buffers);
431 memset(buffers, 0, allocate_info->commandBufferCount * sizeof(*buffers));
432 return res;
435 return VK_SUCCESS;
438 void WINAPI wine_vkCmdExecuteCommands(VkCommandBuffer buffer, uint32_t count,
439 const VkCommandBuffer *buffers)
441 VkCommandBuffer *tmp_buffers;
442 unsigned int i;
444 TRACE("%p %u %p\n", buffer, count, buffers);
446 if (!buffers || !count)
447 return;
449 /* Unfortunately we need a temporary buffer as our command buffers are wrapped.
450 * This call is called often and if a performance concern, we may want to use
451 * alloca as we shouldn't need much memory and it needs to be cleaned up after
452 * the call anyway.
454 if (!(tmp_buffers = heap_alloc(count * sizeof(*tmp_buffers))))
456 ERR("Failed to allocate memory for temporary command buffers\n");
457 return;
460 for (i = 0; i < count; i++)
461 tmp_buffers[i] = buffers[i]->command_buffer;
463 buffer->device->funcs.p_vkCmdExecuteCommands(buffer->command_buffer, count, tmp_buffers);
465 heap_free(tmp_buffers);
468 VkResult WINAPI wine_vkCreateDevice(VkPhysicalDevice phys_dev,
469 const VkDeviceCreateInfo *create_info,
470 const VkAllocationCallbacks *allocator, VkDevice *device)
472 struct VkDevice_T *object = NULL;
473 uint32_t max_queue_families;
474 VkResult res;
475 unsigned int i;
477 TRACE("%p %p %p %p\n", phys_dev, create_info, allocator, device);
479 if (allocator)
480 FIXME("Support for allocation callbacks not implemented yet\n");
482 object = heap_alloc_zero(sizeof(*object));
483 if (!object)
484 return VK_ERROR_OUT_OF_HOST_MEMORY;
486 object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
488 /* At least for now we can directly pass create_info through. All extensions we report
489 * should be compatible. In addition the loader is supposed to sanitize values e.g. layers.
491 res = phys_dev->instance->funcs.p_vkCreateDevice(phys_dev->phys_dev,
492 create_info, NULL /* allocator */, &object->device);
493 if (res != VK_SUCCESS)
495 ERR("Failed to create device\n");
496 goto err;
499 object->phys_dev = phys_dev;
501 /* Just load all function pointers we are aware off. The loader takes care of filtering.
502 * We use vkGetDeviceProcAddr as opposed to vkGetInstanceProcAddr for efficiency reasons
503 * as functions pass through fewer dispatch tables within the loader.
505 #define USE_VK_FUNC(name) \
506 object->funcs.p_##name = (void *)vk_funcs->p_vkGetDeviceProcAddr(object->device, #name); \
507 if (object->funcs.p_##name == NULL) \
508 TRACE("Not found %s\n", #name);
509 ALL_VK_DEVICE_FUNCS()
510 #undef USE_VK_FUNC
512 /* We need to cache all queues within the device as each requires wrapping since queues are
513 * dispatchable objects.
515 phys_dev->instance->funcs.p_vkGetPhysicalDeviceQueueFamilyProperties(phys_dev->phys_dev,
516 &max_queue_families, NULL);
517 object->max_queue_families = max_queue_families;
518 TRACE("Max queue families: %d\n", object->max_queue_families);
520 object->queues = heap_calloc(max_queue_families, sizeof(*object->queues));
521 if (!object->queues)
523 res = VK_ERROR_OUT_OF_HOST_MEMORY;
524 goto err;
527 for (i = 0; i < create_info->queueCreateInfoCount; i++)
529 uint32_t family_index = create_info->pQueueCreateInfos[i].queueFamilyIndex;
530 uint32_t queue_count = create_info->pQueueCreateInfos[i].queueCount;
532 TRACE("queueFamilyIndex %u, queueCount %u\n", family_index, queue_count);
534 object->queues[family_index] = wine_vk_device_alloc_queues(object, family_index, queue_count);
535 if (!object->queues[family_index])
537 res = VK_ERROR_OUT_OF_HOST_MEMORY;
538 ERR("Failed to allocate memory for queues\n");
539 goto err;
543 *device = object;
544 return VK_SUCCESS;
546 err:
547 wine_vk_device_free(object);
548 return res;
551 static VkResult WINAPI wine_vkCreateInstance(const VkInstanceCreateInfo *create_info,
552 const VkAllocationCallbacks *allocator, VkInstance *instance)
554 struct VkInstance_T *object = NULL;
555 VkInstanceCreateInfo create_info_host;
556 VkResult res;
558 TRACE("create_info %p, allocator %p, instance %p\n", create_info, allocator, instance);
560 if (allocator)
561 FIXME("Support for allocation callbacks not implemented yet\n");
563 object = heap_alloc_zero(sizeof(*object));
564 if (!object)
566 ERR("Failed to allocate memory for instance\n");
567 res = VK_ERROR_OUT_OF_HOST_MEMORY;
568 goto err;
570 object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE;
572 res = wine_vk_instance_convert_create_info(create_info, &create_info_host);
573 if (res != VK_SUCCESS)
575 ERR("Failed to convert instance create info, res=%d\n", res);
576 goto err;
579 res = vk_funcs->p_vkCreateInstance(&create_info_host, NULL /* allocator */, &object->instance);
580 if (res != VK_SUCCESS)
582 ERR("Failed to create instance, res=%d\n", res);
583 goto err;
586 /* Load all instance functions we are aware of. Note the loader takes care
587 * of any filtering for extensions which were not requested, but which the
588 * ICD may support.
590 #define USE_VK_FUNC(name) \
591 object->funcs.p_##name = (void *)vk_funcs->p_vkGetInstanceProcAddr(object->instance, #name);
592 ALL_VK_INSTANCE_FUNCS()
593 #undef USE_VK_FUNC
595 /* Cache physical devices for vkEnumeratePhysicalDevices within the instance as
596 * each vkPhysicalDevice is a dispatchable object, which means we need to wrap
597 * the native physical device and present those the application.
598 * Cleanup happens as part of wine_vkDestroyInstance.
600 res = wine_vk_instance_load_physical_devices(object);
601 if (res != VK_SUCCESS)
603 ERR("Failed to cache physical devices, res=%d\n", res);
604 goto err;
607 *instance = object;
608 TRACE("Done, instance=%p native_instance=%p\n", object, object->instance);
609 return VK_SUCCESS;
611 err:
612 wine_vk_instance_free(object);
613 return res;
616 #if defined(USE_STRUCT_CONVERSION)
617 static inline void convert_VkSwapchainCreateInfoKHR_win_to_host(const VkSwapchainCreateInfoKHR *in,
618 VkSwapchainCreateInfoKHR_host *out)
620 if (!in) return;
622 out->sType = in->sType;
623 out->pNext = in->pNext;
624 out->flags = in->flags;
625 out->surface = in->surface;
626 out->minImageCount = in->minImageCount;
627 out->imageFormat = in->imageFormat;
628 out->imageColorSpace = in->imageColorSpace;
629 out->imageExtent = in->imageExtent;
630 out->imageArrayLayers = in->imageArrayLayers;
631 out->imageUsage = in->imageUsage;
632 out->imageSharingMode = in->imageSharingMode;
633 out->queueFamilyIndexCount = in->queueFamilyIndexCount;
634 out->pQueueFamilyIndices = in->pQueueFamilyIndices;
635 out->preTransform = in->preTransform;
636 out->compositeAlpha = in->compositeAlpha;
637 out->presentMode = in->presentMode;
638 out->clipped = in->clipped;
639 out->oldSwapchain = in->oldSwapchain;
641 #endif
643 VkResult WINAPI wine_vkCreateSwapchainKHR(VkDevice device,
644 const VkSwapchainCreateInfoKHR *create_info,
645 const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain)
647 #if defined(USE_STRUCT_CONVERSION)
648 VkSwapchainCreateInfoKHR_host create_info_host;
649 TRACE("%p %p %p %p\n", device, create_info, allocator, swapchain);
651 if (allocator)
652 FIXME("Support allocation allocators\n");
654 convert_VkSwapchainCreateInfoKHR_win_to_host(create_info, &create_info_host);
656 /* Wine graphics driver only uses structs in host format. */
657 return vk_funcs->p_vkCreateSwapchainKHR(device->device,
658 (VkSwapchainCreateInfoKHR *)&create_info_host, allocator, swapchain);
659 #else
660 TRACE("%p %p %p %p\n", device, create_info, allocator, swapchain);
662 if (allocator)
663 FIXME("Support allocation allocators\n");
665 return vk_funcs->p_vkCreateSwapchainKHR(device->device, create_info, allocator, swapchain);
666 #endif
669 VkResult WINAPI wine_vkCreateWin32SurfaceKHR(VkInstance instance,
670 const VkWin32SurfaceCreateInfoKHR *create_info,
671 const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface)
673 TRACE("%p %p %p %p\n", instance, create_info, allocator, surface);
675 if (allocator)
676 FIXME("Support allocation allocators\n");
678 return vk_funcs->p_vkCreateWin32SurfaceKHR(instance->instance, create_info,
679 NULL /* allocator */, surface);
682 void WINAPI wine_vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *allocator)
684 TRACE("%p %p\n", device, allocator);
686 if (allocator)
687 FIXME("Support for allocation callbacks not implemented yet\n");
689 wine_vk_device_free(device);
692 void WINAPI wine_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *allocator)
694 TRACE("%p, %p\n", instance, allocator);
696 if (allocator)
697 FIXME("Support allocation allocators\n");
699 wine_vk_instance_free(instance);
702 void WINAPI wine_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface,
703 const VkAllocationCallbacks *allocator)
705 TRACE("%p, 0x%s, %p\n", instance, wine_dbgstr_longlong(surface), allocator);
707 if (allocator)
708 FIXME("Support allocation allocators\n");
710 vk_funcs->p_vkDestroySurfaceKHR(instance->instance, surface, NULL /* allocator */);
713 void WINAPI wine_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain,
714 const VkAllocationCallbacks *allocator)
716 TRACE("%p, 0x%s %p\n", device, wine_dbgstr_longlong(swapchain), allocator);
718 if (allocator)
719 FIXME("Support allocation allocators\n");
721 vk_funcs->p_vkDestroySwapchainKHR(device->device, swapchain, NULL /* allocator */);
724 VkResult WINAPI wine_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice phys_dev,
725 const char *layer_name, uint32_t *count, VkExtensionProperties *properties)
727 VkResult res;
728 unsigned int i, num_copies;
730 TRACE("%p, %p, %p, %p\n", phys_dev, layer_name, count, properties);
732 /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
733 if (layer_name)
735 ERR("Layer enumeration not supported from ICD.\n");
736 return VK_ERROR_LAYER_NOT_PRESENT;
739 if (!properties)
741 *count = phys_dev->num_properties;
742 return VK_SUCCESS;
745 if (*count < phys_dev->num_properties)
747 /* Incomplete is a type of success used to signal the application
748 * that not all devices got copied.
750 num_copies = *count;
751 res = VK_INCOMPLETE;
753 else
755 num_copies = phys_dev->num_properties;
756 res = VK_SUCCESS;
759 for (i = 0; i < num_copies; i++)
761 memcpy(&properties[i], &phys_dev->properties[i], sizeof(phys_dev->properties[i]));
763 *count = num_copies;
765 TRACE("Result %d, extensions copied %u\n", res, num_copies);
766 return res;
769 static VkResult WINAPI wine_vkEnumerateInstanceExtensionProperties(const char *layer_name,
770 uint32_t *count, VkExtensionProperties *properties)
772 VkResult res;
773 uint32_t num_properties = 0, num_host_properties = 0;
774 VkExtensionProperties *host_properties = NULL;
775 unsigned int i, j;
777 TRACE("%p %p %p\n", layer_name, count, properties);
779 /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
780 if (layer_name)
782 ERR("Layer enumeration not supported from ICD.\n");
783 return VK_ERROR_LAYER_NOT_PRESENT;
786 res = vk_funcs->p_vkEnumerateInstanceExtensionProperties(NULL, &num_host_properties, NULL);
787 if (res != VK_SUCCESS)
788 return res;
790 host_properties = heap_calloc(num_host_properties, sizeof(*host_properties));
791 if (!host_properties)
792 return VK_ERROR_OUT_OF_HOST_MEMORY;
794 res = vk_funcs->p_vkEnumerateInstanceExtensionProperties(NULL, &num_host_properties, host_properties);
795 if (res != VK_SUCCESS)
797 ERR("Failed to retrieve host properties, res=%d\n", res);
798 heap_free(host_properties);
799 return res;
802 /* The Wine graphics driver provides us with all extensions supported by the host side
803 * including extension fixup (e.g. VK_KHR_xlib_surface -> VK_KHR_win32_surface). It is
804 * up to us here to filter the list down to extensions for which we have thunks.
806 for (i = 0; i < num_host_properties; i++)
808 if (wine_vk_instance_extension_supported(host_properties[i].extensionName))
809 num_properties++;
812 /* We only have to count. */
813 if (!properties)
815 TRACE("Returning %u extensions\n", num_properties);
816 *count = num_properties;
817 heap_free(host_properties);
818 return VK_SUCCESS;
821 for (i = 0, j = 0; i < num_host_properties && j < *count; i++)
823 if (wine_vk_instance_extension_supported(host_properties[i].extensionName))
825 TRACE("Enabling extension '%s'\n", host_properties[i].extensionName);
826 memcpy(&properties[j], &host_properties[i], sizeof(*properties));
827 j++;
831 /* Return incomplete if the buffer is smaller than the number of supported extensions. */
832 if (*count < num_properties)
833 res = VK_INCOMPLETE;
834 else
835 res = VK_SUCCESS;
837 heap_free(host_properties);
838 return res;
841 VkResult WINAPI wine_vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *count,
842 VkPhysicalDevice *devices)
844 unsigned int i;
846 TRACE("%p %p %p\n", instance, count, devices);
848 if (!devices)
850 *count = instance->num_phys_devs;
851 return VK_SUCCESS;
854 *count = min(*count, instance->num_phys_devs);
855 for (i = 0; i < *count; i++)
857 devices[i] = instance->phys_devs[i];
860 TRACE("Returning %u devices.\n", *count);
861 return *count < instance->num_phys_devs ? VK_INCOMPLETE : VK_SUCCESS;
864 void WINAPI wine_vkFreeCommandBuffers(VkDevice device, VkCommandPool pool, uint32_t count,
865 const VkCommandBuffer *buffers)
867 TRACE("%p 0x%s %u %p\n", device, wine_dbgstr_longlong(pool), count, buffers);
869 wine_vk_command_buffers_free(device, pool, count, buffers);
872 PFN_vkVoidFunction WINAPI wine_vkGetDeviceProcAddr(VkDevice device, const char *name)
874 void *func;
875 TRACE("%p, %s\n", device, debugstr_a(name));
877 /* The spec leaves return value undefined for a NULL device, let's just return NULL. */
878 if (!device || !name)
879 return NULL;
881 /* Per the spec, we are only supposed to return device functions as in functions
882 * for which the first parameter is vkDevice or a child of vkDevice like a
883 * vkCommandBuffer or vkQueue.
884 * Loader takes are of filtering of extensions which are enabled or not.
886 func = wine_vk_get_device_proc_addr(name);
887 if (func)
888 return func;
890 /* vkGetDeviceProcAddr was intended for loading device and subdevice functions.
891 * idTech 6 titles such as Doom and Wolfenstein II, however use it also for
892 * loading of instance functions. This is undefined behavior as the specification
893 * disallows using any of the returned function pointers outside of device /
894 * subdevice objects. The games don't actually use the function pointers and if they
895 * did, they would crash as VkInstance / VkPhysicalDevice parameters need unwrapping.
896 * Khronos clarified behavior in the Vulkan spec and expects drivers to get updated,
897 * however it would require both driver and game fixes. Since it are major titles
898 * it is not clear what will happen. At least for now we need the hack below.
899 * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/2323
900 * https://github.com/KhronosGroup/Vulkan-Docs/issues/655
902 func = wine_vk_get_instance_proc_addr(name);
903 if (func)
905 WARN("Returning instance function '%s'.\n", debugstr_a(name));
906 return func;
909 TRACE("Function %s not found.\n", debugstr_a(name));
910 return NULL;
913 void WINAPI wine_vkGetDeviceQueue(VkDevice device, uint32_t family_index,
914 uint32_t queue_index, VkQueue *queue)
916 TRACE("%p %u %u %p\n", device, family_index, queue_index, queue);
918 *queue = &device->queues[family_index][queue_index];
921 static PFN_vkVoidFunction WINAPI wine_vkGetInstanceProcAddr(VkInstance instance, const char *name)
923 void *func;
925 TRACE("%p %s\n", instance, debugstr_a(name));
927 if (!name)
928 return NULL;
930 /* vkGetInstanceProcAddr can load most Vulkan functions when an instance is passed in, however
931 * for a NULL instance it can only load global functions.
933 func = wine_vk_get_global_proc_addr(name);
934 if (func)
936 return func;
938 if (!instance)
940 FIXME("Global function '%s' not found\n", debugstr_a(name));
941 return NULL;
944 func = wine_vk_get_instance_proc_addr(name);
945 if (func) return func;
947 /* vkGetInstanceProcAddr also loads any children of instance, so device functions as well. */
948 func = wine_vk_get_device_proc_addr(name);
949 if (func) return func;
951 FIXME("Unsupported device or instance function: '%s'\n", debugstr_a(name));
952 return NULL;
955 VkResult WINAPI wine_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice phys_dev,
956 VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *capabilities)
958 TRACE("%p, 0x%s, %p\n", phys_dev, wine_dbgstr_longlong(surface), capabilities);
959 return vk_funcs->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev->phys_dev,
960 surface, capabilities);
963 VkResult WINAPI wine_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice phys_dev,
964 VkSurfaceKHR surface, uint32_t *format_count, VkSurfaceFormatKHR *formats)
966 TRACE("%p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), format_count, formats);
967 return vk_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR(phys_dev->phys_dev,
968 surface, format_count, formats);
971 VkResult WINAPI wine_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice phys_dev,
972 VkSurfaceKHR surface, uint32_t *mode_count, VkPresentModeKHR *modes)
974 TRACE("%p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), mode_count, modes);
975 return vk_funcs->p_vkGetPhysicalDeviceSurfacePresentModesKHR(phys_dev->phys_dev,
976 surface, mode_count, modes);
979 VkResult WINAPI wine_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice phys_dev,
980 uint32_t queue_family_index, VkSurfaceKHR surface, VkBool32 *supported)
982 TRACE("%p, %u, 0x%s, %p\n", phys_dev, queue_family_index, wine_dbgstr_longlong(surface), supported);
983 return vk_funcs->p_vkGetPhysicalDeviceSurfaceSupportKHR(phys_dev->phys_dev,
984 queue_family_index, surface, supported);
987 VkBool32 WINAPI wine_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice phys_dev,
988 uint32_t queue_family_index)
990 TRACE("%p %u\n", phys_dev, queue_family_index);
991 return vk_funcs->p_vkGetPhysicalDeviceWin32PresentationSupportKHR(phys_dev->phys_dev,
992 queue_family_index);
995 VkResult WINAPI wine_vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain,
996 uint32_t *image_count, VkImage *images)
998 TRACE("%p, 0x%s %p %p\n", device, wine_dbgstr_longlong(swapchain), image_count, images);
999 return vk_funcs->p_vkGetSwapchainImagesKHR(device->device, swapchain,
1000 image_count, images);
1003 VkResult WINAPI wine_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *present_info)
1005 TRACE("%p, %p\n", queue, present_info);
1006 return vk_funcs->p_vkQueuePresentKHR(queue->queue, present_info);
1009 void * WINAPI wine_vk_icdGetInstanceProcAddr(VkInstance instance, const char *name)
1011 TRACE("%p %s\n", instance, debugstr_a(name));
1013 /* Initial version of the Vulkan ICD spec required vkGetInstanceProcAddr to be
1014 * exported. vk_icdGetInstanceProcAddr was added later to separate ICD calls from
1015 * Vulkan API. One of them in our case should forward to the other, so just forward
1016 * to the older vkGetInstanceProcAddr.
1018 return wine_vkGetInstanceProcAddr(instance, name);
1021 VkResult WINAPI wine_vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t *supported_version)
1023 uint32_t req_version;
1025 TRACE("%p\n", supported_version);
1027 /* The spec is not clear how to handle this. Mesa drivers don't check, but it
1028 * is probably best to not explode. VK_INCOMPLETE seems to be the closest value.
1030 if (!supported_version)
1031 return VK_INCOMPLETE;
1033 req_version = *supported_version;
1034 *supported_version = min(req_version, WINE_VULKAN_ICD_VERSION);
1035 TRACE("Loader requested ICD version %u, returning %u\n", req_version, *supported_version);
1037 return VK_SUCCESS;
1040 VkResult WINAPI wine_vkQueueSubmit(VkQueue queue, uint32_t count,
1041 const VkSubmitInfo *submits, VkFence fence)
1043 VkSubmitInfo *submits_host;
1044 VkResult res;
1045 VkCommandBuffer *command_buffers;
1046 unsigned int i, j, num_command_buffers;
1048 TRACE("%p %u %p 0x%s\n", queue, count, submits, wine_dbgstr_longlong(fence));
1050 if (count == 0)
1052 return queue->device->funcs.p_vkQueueSubmit(queue->queue, 0, NULL, fence);
1055 submits_host = heap_calloc(count, sizeof(*submits_host));
1056 if (!submits_host)
1058 ERR("Unable to allocate memory for submit buffers!\n");
1059 return VK_ERROR_OUT_OF_HOST_MEMORY;
1062 for (i = 0; i < count; i++)
1064 memcpy(&submits_host[i], &submits[i], sizeof(*submits_host));
1066 num_command_buffers = submits[i].commandBufferCount;
1067 command_buffers = heap_calloc(num_command_buffers, sizeof(*submits_host));
1068 if (!command_buffers)
1070 ERR("Unable to allocate memory for comman buffers!\n");
1071 res = VK_ERROR_OUT_OF_HOST_MEMORY;
1072 goto err;
1075 for (j = 0; j < num_command_buffers; j++)
1077 command_buffers[j] = submits[i].pCommandBuffers[j]->command_buffer;
1079 submits_host[i].pCommandBuffers = command_buffers;
1082 res = queue->device->funcs.p_vkQueueSubmit(queue->queue, count, submits_host, fence);
1084 err:
1085 for (i = 0; i < count; i++)
1087 heap_free((void *)submits_host[i].pCommandBuffers);
1089 heap_free(submits_host);
1091 TRACE("Returning %d\n", res);
1092 return res;
1096 BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, void *reserved)
1098 switch (reason)
1100 case DLL_PROCESS_ATTACH:
1101 DisableThreadLibraryCalls(hinst);
1102 return wine_vk_init();
1104 return TRUE;
1107 static const struct vulkan_func vk_global_dispatch_table[] =
1109 {"vkCreateInstance", &wine_vkCreateInstance},
1110 {"vkEnumerateInstanceExtensionProperties", &wine_vkEnumerateInstanceExtensionProperties},
1111 {"vkGetInstanceProcAddr", &wine_vkGetInstanceProcAddr},
1114 static void *wine_vk_get_global_proc_addr(const char *name)
1116 unsigned int i;
1118 for (i = 0; i < ARRAY_SIZE(vk_global_dispatch_table); i++)
1120 if (strcmp(name, vk_global_dispatch_table[i].name) == 0)
1122 TRACE("Found name=%s in global table\n", debugstr_a(name));
1123 return vk_global_dispatch_table[i].func;
1126 return NULL;