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
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 off. 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
;
44 static void *wine_vk_get_global_proc_addr(const char *name
);
46 static const struct vulkan_funcs
*vk_funcs
;
48 static void wine_vk_physical_device_free(struct VkPhysicalDevice_T
*phys_dev
)
53 heap_free(phys_dev
->extensions
);
57 static struct VkPhysicalDevice_T
*wine_vk_physical_device_alloc(struct VkInstance_T
*instance
,
58 VkPhysicalDevice phys_dev
)
60 struct VkPhysicalDevice_T
*object
;
61 uint32_t num_host_properties
, num_properties
= 0;
62 VkExtensionProperties
*host_properties
= NULL
;
66 if (!(object
= heap_alloc_zero(sizeof(*object
))))
69 object
->base
.loader_magic
= VULKAN_ICD_MAGIC_VALUE
;
70 object
->instance
= instance
;
71 object
->phys_dev
= phys_dev
;
73 res
= instance
->funcs
.p_vkEnumerateDeviceExtensionProperties(phys_dev
,
74 NULL
, &num_host_properties
, NULL
);
75 if (res
!= VK_SUCCESS
)
77 ERR("Failed to enumerate device extensions, res=%d\n", res
);
81 host_properties
= heap_calloc(num_host_properties
, sizeof(*host_properties
));
84 ERR("Failed to allocate memory for device properties!\n");
88 res
= instance
->funcs
.p_vkEnumerateDeviceExtensionProperties(phys_dev
,
89 NULL
, &num_host_properties
, host_properties
);
90 if (res
!= VK_SUCCESS
)
92 ERR("Failed to enumerate device extensions, res=%d\n", res
);
96 /* Count list of extensions for which we have an implementation.
97 * TODO: perform translation for platform specific extensions.
99 for (i
= 0; i
< num_host_properties
; i
++)
101 if (wine_vk_device_extension_supported(host_properties
[i
].extensionName
))
103 TRACE("Enabling extension '%s' for physical device %p\n", host_properties
[i
].extensionName
, object
);
108 TRACE("Skipping extension '%s', no implementation found in winevulkan.\n", host_properties
[i
].extensionName
);
112 TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties
, num_properties
);
114 if (!(object
->extensions
= heap_calloc(num_properties
, sizeof(*object
->extensions
))))
116 ERR("Failed to allocate memory for device extensions!\n");
120 for (i
= 0, j
= 0; i
< num_host_properties
; i
++)
122 if (wine_vk_device_extension_supported(host_properties
[i
].extensionName
))
124 object
->extensions
[j
] = host_properties
[i
];
128 object
->extension_count
= num_properties
;
130 heap_free(host_properties
);
134 wine_vk_physical_device_free(object
);
135 heap_free(host_properties
);
139 /* Helper function to release command buffers. */
140 static void wine_vk_command_buffers_free(struct VkDevice_T
*device
, VkCommandPool pool
,
141 uint32_t count
, const VkCommandBuffer
*buffers
)
145 for (i
= 0; i
< count
; i
++)
150 device
->funcs
.p_vkFreeCommandBuffers(device
->device
, pool
, 1, &buffers
[i
]->command_buffer
);
151 heap_free(buffers
[i
]);
155 /* Helper function to create queues for a given family index. */
156 static struct VkQueue_T
*wine_vk_device_alloc_queues(struct VkDevice_T
*device
,
157 uint32_t family_index
, uint32_t queue_count
)
159 struct VkQueue_T
*queues
;
162 if (!(queues
= heap_calloc(queue_count
, sizeof(*queues
))))
164 ERR("Failed to allocate memory for queues\n");
168 for (i
= 0; i
< queue_count
; i
++)
170 struct VkQueue_T
*queue
= &queues
[i
];
171 queue
->device
= device
;
173 /* The native device was already allocated with the required number of queues,
174 * so just fetch them from there.
176 device
->funcs
.p_vkGetDeviceQueue(device
->device
, family_index
, i
, &queue
->queue
);
178 /* Set special header for ICD loader. */
179 queue
->base
.loader_magic
= VULKAN_ICD_MAGIC_VALUE
;
185 /* Helper function to convert win32 VkDeviceCreateInfo to host compatible. */
186 static void wine_vk_device_convert_create_info(const VkDeviceCreateInfo
*src
,
187 VkDeviceCreateInfo
*dst
)
193 /* Application and loader can pass in a chain of extensions through pNext.
194 * We can't blindly pass these through as often these contain callbacks or
195 * they can even be pass structures for loader / ICD internal use. For now
196 * we ignore everything in pNext chain, but we print FIXMEs.
200 const struct wine_vk_structure_header
*header
;
202 for (header
= src
->pNext
; header
; header
= header
->pNext
)
204 switch (header
->sType
)
206 case VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO
:
207 /* Used for loader to ICD communication. Ignore to not confuse
213 FIXME("Application requested a linked structure of type %#x.\n", header
->sType
);
217 /* For now don't support anything. */
220 /* Should be filtered out by loader as ICDs don't support layers. */
221 dst
->enabledLayerCount
= 0;
222 dst
->ppEnabledLayerNames
= NULL
;
224 TRACE("Enabled extensions: %u\n", dst
->enabledExtensionCount
);
225 for (i
= 0; i
< dst
->enabledExtensionCount
; i
++)
227 TRACE("Extension %u: %s\n", i
, debugstr_a(dst
->ppEnabledExtensionNames
[i
]));
231 /* Helper function used for freeing a device structure. This function supports full
232 * and partial object cleanups and can thus be used for vkCreateDevice failures.
234 static void wine_vk_device_free(struct VkDevice_T
*device
)
242 for (i
= 0; i
< device
->max_queue_families
; i
++)
244 heap_free(device
->queues
[i
]);
246 heap_free(device
->queues
);
247 device
->queues
= NULL
;
250 if (device
->device
&& device
->funcs
.p_vkDestroyDevice
)
252 device
->funcs
.p_vkDestroyDevice(device
->device
, NULL
/* pAllocator */);
258 static BOOL
wine_vk_init(void)
263 vk_funcs
= __wine_get_vulkan_driver(hdc
, WINE_VULKAN_DRIVER_VERSION
);
267 ERR("Failed to load Wine graphics driver supporting Vulkan.\n");
274 /* Helper function for converting between win32 and host compatible VkInstanceCreateInfo.
275 * This function takes care of extensions handled at winevulkan layer, a Wine graphics
276 * driver is responsible for handling e.g. surface extensions.
278 static void wine_vk_instance_convert_create_info(const VkInstanceCreateInfo
*src
,
279 VkInstanceCreateInfo
*dst
)
285 if (dst
->pApplicationInfo
)
287 const VkApplicationInfo
*app_info
= dst
->pApplicationInfo
;
288 TRACE("Application name %s, application version %#x\n",
289 debugstr_a(app_info
->pApplicationName
), app_info
->applicationVersion
);
290 TRACE("Engine name %s, engine version %#x\n", debugstr_a(app_info
->pEngineName
),
291 app_info
->engineVersion
);
292 TRACE("API version %#x\n", app_info
->apiVersion
);
295 /* Application and loader can pass in a chain of extensions through pNext.
296 * We can't blindly pass these through as often these contain callbacks or
297 * they can even be pass structures for loader / ICD internal use. For now
298 * we ignore everything in pNext chain, but we print FIXMEs.
302 const struct wine_vk_structure_header
*header
;
304 for (header
= src
->pNext
; header
; header
= header
->pNext
)
306 switch (header
->sType
)
308 case VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
:
309 /* Can be used to register new dispatchable object types
310 * to the loader. We should ignore it as it will confuse the
316 FIXME("Application requested a linked structure of type %#x.\n", header
->sType
);
320 /* For now don't support anything. */
323 /* ICDs don't support any layers, so nothing to copy. Modern versions of the loader
324 * filter this data out as well.
326 dst
->enabledLayerCount
= 0;
327 dst
->ppEnabledLayerNames
= NULL
;
329 TRACE("Enabled extensions: %u\n", dst
->enabledExtensionCount
);
330 for (i
= 0; i
< dst
->enabledExtensionCount
; i
++)
332 TRACE("Extension %u: %s\n", i
, debugstr_a(dst
->ppEnabledExtensionNames
[i
]));
336 /* Helper function which stores wrapped physical devices in the instance object. */
337 static VkResult
wine_vk_instance_load_physical_devices(struct VkInstance_T
*instance
)
340 struct VkPhysicalDevice_T
**tmp_phys_devs
;
341 uint32_t num_phys_devs
= 0;
344 res
= instance
->funcs
.p_vkEnumeratePhysicalDevices(instance
->instance
, &num_phys_devs
, NULL
);
345 if (res
!= VK_SUCCESS
)
347 ERR("Failed to enumerate physical devices, res=%d\n", res
);
351 /* Don't bother with any of the rest if the system just lacks devices. */
352 if (num_phys_devs
== 0)
355 tmp_phys_devs
= heap_calloc(num_phys_devs
, sizeof(*tmp_phys_devs
));
357 return VK_ERROR_OUT_OF_HOST_MEMORY
;
359 res
= instance
->funcs
.p_vkEnumeratePhysicalDevices(instance
->instance
, &num_phys_devs
, tmp_phys_devs
);
360 if (res
!= VK_SUCCESS
)
362 heap_free(tmp_phys_devs
);
366 instance
->phys_devs
= heap_calloc(num_phys_devs
, sizeof(*instance
->phys_devs
));
367 if (!instance
->phys_devs
)
369 heap_free(tmp_phys_devs
);
370 return VK_ERROR_OUT_OF_HOST_MEMORY
;
373 /* Wrap each native physical device handle into a dispatchable object for the ICD loader. */
374 for (i
= 0; i
< num_phys_devs
; i
++)
376 struct VkPhysicalDevice_T
*phys_dev
= wine_vk_physical_device_alloc(instance
, tmp_phys_devs
[i
]);
379 ERR("Unable to allocate memory for physical device!\n");
380 heap_free(tmp_phys_devs
);
381 return VK_ERROR_OUT_OF_HOST_MEMORY
;
384 instance
->phys_devs
[i
] = phys_dev
;
385 instance
->num_phys_devs
= i
+ 1;
387 instance
->num_phys_devs
= num_phys_devs
;
389 heap_free(tmp_phys_devs
);
393 /* Helper function used for freeing an instance structure. This function supports full
394 * and partial object cleanups and can thus be used for vkCreateInstance failures.
396 static void wine_vk_instance_free(struct VkInstance_T
*instance
)
401 if (instance
->phys_devs
)
405 for (i
= 0; i
< instance
->num_phys_devs
; i
++)
407 wine_vk_physical_device_free(instance
->phys_devs
[i
]);
409 heap_free(instance
->phys_devs
);
412 if (instance
->instance
)
413 vk_funcs
->p_vkDestroyInstance(instance
->instance
, NULL
/* allocator */);
418 VkResult WINAPI
wine_vkAllocateCommandBuffers(VkDevice device
,
419 const VkCommandBufferAllocateInfo
*allocate_info
, VkCommandBuffer
*buffers
)
421 VkResult res
= VK_SUCCESS
;
424 TRACE("%p %p %p\n", device
, allocate_info
, buffers
);
426 memset(buffers
, 0, allocate_info
->commandBufferCount
* sizeof(*buffers
));
428 for (i
= 0; i
< allocate_info
->commandBufferCount
; i
++)
430 #if defined(USE_STRUCT_CONVERSION)
431 VkCommandBufferAllocateInfo_host allocate_info_host
;
433 VkCommandBufferAllocateInfo allocate_info_host
;
435 /* TODO: future extensions (none yet) may require pNext conversion. */
436 allocate_info_host
.pNext
= allocate_info
->pNext
;
437 allocate_info_host
.sType
= allocate_info
->sType
;
438 allocate_info_host
.commandPool
= allocate_info
->commandPool
;
439 allocate_info_host
.level
= allocate_info
->level
;
440 allocate_info_host
.commandBufferCount
= 1;
442 TRACE("Creating command buffer %u, pool 0x%s, level %#x\n", i
,
443 wine_dbgstr_longlong(allocate_info_host
.commandPool
),
444 allocate_info_host
.level
);
446 if (!(buffers
[i
] = heap_alloc_zero(sizeof(*buffers
))))
448 res
= VK_ERROR_OUT_OF_HOST_MEMORY
;
452 buffers
[i
]->base
.loader_magic
= VULKAN_ICD_MAGIC_VALUE
;
453 buffers
[i
]->device
= device
;
454 res
= device
->funcs
.p_vkAllocateCommandBuffers(device
->device
,
455 &allocate_info_host
, &buffers
[i
]->command_buffer
);
456 if (res
!= VK_SUCCESS
)
458 ERR("Failed to allocate command buffer, res=%d\n", res
);
463 if (res
!= VK_SUCCESS
)
465 wine_vk_command_buffers_free(device
, allocate_info
->commandPool
, i
, buffers
);
466 memset(buffers
, 0, allocate_info
->commandBufferCount
* sizeof(*buffers
));
473 void WINAPI
wine_vkCmdExecuteCommands(VkCommandBuffer buffer
, uint32_t count
,
474 const VkCommandBuffer
*buffers
)
476 VkCommandBuffer
*tmp_buffers
;
479 TRACE("%p %u %p\n", buffer
, count
, buffers
);
481 if (!buffers
|| !count
)
484 /* Unfortunately we need a temporary buffer as our command buffers are wrapped.
485 * This call is called often and if a performance concern, we may want to use
486 * alloca as we shouldn't need much memory and it needs to be cleaned up after
489 if (!(tmp_buffers
= heap_alloc(count
* sizeof(*tmp_buffers
))))
491 ERR("Failed to allocate memory for temporary command buffers\n");
495 for (i
= 0; i
< count
; i
++)
496 tmp_buffers
[i
] = buffers
[i
]->command_buffer
;
498 buffer
->device
->funcs
.p_vkCmdExecuteCommands(buffer
->command_buffer
, count
, tmp_buffers
);
500 heap_free(tmp_buffers
);
503 VkResult WINAPI
wine_vkCreateDevice(VkPhysicalDevice phys_dev
,
504 const VkDeviceCreateInfo
*create_info
,
505 const VkAllocationCallbacks
*allocator
, VkDevice
*device
)
507 VkDeviceCreateInfo create_info_host
;
508 uint32_t max_queue_families
;
509 struct VkDevice_T
*object
;
513 TRACE("%p %p %p %p\n", phys_dev
, create_info
, allocator
, device
);
516 FIXME("Support for allocation callbacks not implemented yet\n");
518 object
= heap_alloc_zero(sizeof(*object
));
520 return VK_ERROR_OUT_OF_HOST_MEMORY
;
522 object
->base
.loader_magic
= VULKAN_ICD_MAGIC_VALUE
;
524 wine_vk_device_convert_create_info(create_info
, &create_info_host
);
526 res
= phys_dev
->instance
->funcs
.p_vkCreateDevice(phys_dev
->phys_dev
,
527 &create_info_host
, NULL
/* allocator */, &object
->device
);
528 if (res
!= VK_SUCCESS
)
530 ERR("Failed to create device.\n");
531 wine_vk_device_free(object
);
535 /* Just load all function pointers we are aware off. The loader takes care of filtering.
536 * We use vkGetDeviceProcAddr as opposed to vkGetInstanceProcAddr for efficiency reasons
537 * as functions pass through fewer dispatch tables within the loader.
539 #define USE_VK_FUNC(name) \
540 object->funcs.p_##name = (void *)vk_funcs->p_vkGetDeviceProcAddr(object->device, #name); \
541 if (object->funcs.p_##name == NULL) \
542 TRACE("Not found %s\n", #name);
543 ALL_VK_DEVICE_FUNCS()
546 /* We need to cache all queues within the device as each requires wrapping since queues are
547 * dispatchable objects.
549 phys_dev
->instance
->funcs
.p_vkGetPhysicalDeviceQueueFamilyProperties(phys_dev
->phys_dev
,
550 &max_queue_families
, NULL
);
551 object
->max_queue_families
= max_queue_families
;
552 TRACE("Max queue families: %u\n", object
->max_queue_families
);
554 object
->queues
= heap_calloc(max_queue_families
, sizeof(*object
->queues
));
557 wine_vk_device_free(object
);
558 return VK_ERROR_OUT_OF_HOST_MEMORY
;
561 for (i
= 0; i
< create_info_host
.queueCreateInfoCount
; i
++)
563 uint32_t family_index
= create_info_host
.pQueueCreateInfos
[i
].queueFamilyIndex
;
564 uint32_t queue_count
= create_info_host
.pQueueCreateInfos
[i
].queueCount
;
566 TRACE("queueFamilyIndex %u, queueCount %u\n", family_index
, queue_count
);
568 object
->queues
[family_index
] = wine_vk_device_alloc_queues(object
, family_index
, queue_count
);
569 if (!object
->queues
[family_index
])
571 ERR("Failed to allocate memory for queues\n");
572 wine_vk_device_free(object
);
573 return VK_ERROR_OUT_OF_HOST_MEMORY
;
577 object
->quirks
= phys_dev
->instance
->quirks
;
583 VkResult WINAPI
wine_vkCreateInstance(const VkInstanceCreateInfo
*create_info
,
584 const VkAllocationCallbacks
*allocator
, VkInstance
*instance
)
586 VkInstanceCreateInfo create_info_host
;
587 const VkApplicationInfo
*app_info
;
588 struct VkInstance_T
*object
;
591 TRACE("create_info %p, allocator %p, instance %p\n", create_info
, allocator
, instance
);
594 FIXME("Support for allocation callbacks not implemented yet\n");
596 if (!(object
= heap_alloc_zero(sizeof(*object
))))
598 ERR("Failed to allocate memory for instance\n");
599 return VK_ERROR_OUT_OF_HOST_MEMORY
;
601 object
->base
.loader_magic
= VULKAN_ICD_MAGIC_VALUE
;
603 wine_vk_instance_convert_create_info(create_info
, &create_info_host
);
605 res
= vk_funcs
->p_vkCreateInstance(&create_info_host
, NULL
/* allocator */, &object
->instance
);
606 if (res
!= VK_SUCCESS
)
608 ERR("Failed to create instance, res=%d\n", res
);
609 wine_vk_instance_free(object
);
613 /* Load all instance functions we are aware of. Note the loader takes care
614 * of any filtering for extensions which were not requested, but which the
617 #define USE_VK_FUNC(name) \
618 object->funcs.p_##name = (void *)vk_funcs->p_vkGetInstanceProcAddr(object->instance, #name);
619 ALL_VK_INSTANCE_FUNCS()
622 /* Cache physical devices for vkEnumeratePhysicalDevices within the instance as
623 * each vkPhysicalDevice is a dispatchable object, which means we need to wrap
624 * the native physical devices and present those to the application.
625 * Cleanup happens as part of wine_vkDestroyInstance.
627 res
= wine_vk_instance_load_physical_devices(object
);
628 if (res
!= VK_SUCCESS
)
630 ERR("Failed to load physical devices, res=%d\n", res
);
631 wine_vk_instance_free(object
);
635 if ((app_info
= create_info
->pApplicationInfo
) && app_info
->pApplicationName
)
637 if (!strcmp(app_info
->pApplicationName
, "DOOM")
638 || !strcmp(app_info
->pApplicationName
, "Wolfenstein II The New Colossus"))
639 object
->quirks
|= WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR
;
643 TRACE("Done, instance=%p native_instance=%p\n", object
, object
->instance
);
647 void WINAPI
wine_vkDestroyDevice(VkDevice device
, const VkAllocationCallbacks
*allocator
)
649 TRACE("%p %p\n", device
, allocator
);
652 FIXME("Support for allocation callbacks not implemented yet\n");
654 wine_vk_device_free(device
);
657 void WINAPI
wine_vkDestroyInstance(VkInstance instance
, const VkAllocationCallbacks
*allocator
)
659 TRACE("%p, %p\n", instance
, allocator
);
662 FIXME("Support allocation allocators\n");
664 wine_vk_instance_free(instance
);
667 VkResult WINAPI
wine_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice phys_dev
,
668 const char *layer_name
, uint32_t *count
, VkExtensionProperties
*properties
)
670 TRACE("%p, %p, %p, %p\n", phys_dev
, layer_name
, count
, properties
);
672 /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
675 ERR("Layer enumeration not supported from ICD.\n");
676 return VK_ERROR_LAYER_NOT_PRESENT
;
681 *count
= phys_dev
->extension_count
;
685 *count
= min(*count
, phys_dev
->extension_count
);
686 memcpy(properties
, phys_dev
->extensions
, *count
* sizeof(*properties
));
688 TRACE("Returning %u extensions.\n", *count
);
689 return *count
< phys_dev
->extension_count
? VK_INCOMPLETE
: VK_SUCCESS
;
692 VkResult WINAPI
wine_vkEnumerateInstanceExtensionProperties(const char *layer_name
,
693 uint32_t *count
, VkExtensionProperties
*properties
)
696 uint32_t num_properties
= 0, num_host_properties
= 0;
697 VkExtensionProperties
*host_properties
= NULL
;
700 TRACE("%p %p %p\n", layer_name
, count
, properties
);
702 /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
705 ERR("Layer enumeration not supported from ICD.\n");
706 return VK_ERROR_LAYER_NOT_PRESENT
;
709 res
= vk_funcs
->p_vkEnumerateInstanceExtensionProperties(NULL
, &num_host_properties
, NULL
);
710 if (res
!= VK_SUCCESS
)
713 host_properties
= heap_calloc(num_host_properties
, sizeof(*host_properties
));
714 if (!host_properties
)
715 return VK_ERROR_OUT_OF_HOST_MEMORY
;
717 res
= vk_funcs
->p_vkEnumerateInstanceExtensionProperties(NULL
, &num_host_properties
, host_properties
);
718 if (res
!= VK_SUCCESS
)
720 ERR("Failed to retrieve host properties, res=%d\n", res
);
721 heap_free(host_properties
);
725 /* The Wine graphics driver provides us with all extensions supported by the host side
726 * including extension fixup (e.g. VK_KHR_xlib_surface -> VK_KHR_win32_surface). It is
727 * up to us here to filter the list down to extensions for which we have thunks.
729 for (i
= 0; i
< num_host_properties
; i
++)
731 if (wine_vk_instance_extension_supported(host_properties
[i
].extensionName
))
734 TRACE("Instance extension '%s' is not supported.\n", host_properties
[i
].extensionName
);
739 TRACE("Returning %u extensions\n", num_properties
);
740 *count
= num_properties
;
741 heap_free(host_properties
);
745 for (i
= 0, j
= 0; i
< num_host_properties
&& j
< *count
; i
++)
747 if (wine_vk_instance_extension_supported(host_properties
[i
].extensionName
))
749 TRACE("Enabling extension '%s'\n", host_properties
[i
].extensionName
);
750 properties
[j
] = host_properties
[i
];
754 *count
= min(*count
, num_properties
);
756 heap_free(host_properties
);
757 return *count
< num_properties
? VK_INCOMPLETE
: VK_SUCCESS
;
760 VkResult WINAPI
wine_vkEnumeratePhysicalDevices(VkInstance instance
, uint32_t *count
,
761 VkPhysicalDevice
*devices
)
765 TRACE("%p %p %p\n", instance
, count
, devices
);
769 *count
= instance
->num_phys_devs
;
773 *count
= min(*count
, instance
->num_phys_devs
);
774 for (i
= 0; i
< *count
; i
++)
776 devices
[i
] = instance
->phys_devs
[i
];
779 TRACE("Returning %u devices.\n", *count
);
780 return *count
< instance
->num_phys_devs
? VK_INCOMPLETE
: VK_SUCCESS
;
783 void WINAPI
wine_vkFreeCommandBuffers(VkDevice device
, VkCommandPool pool
, uint32_t count
,
784 const VkCommandBuffer
*buffers
)
786 TRACE("%p 0x%s %u %p\n", device
, wine_dbgstr_longlong(pool
), count
, buffers
);
788 wine_vk_command_buffers_free(device
, pool
, count
, buffers
);
791 PFN_vkVoidFunction WINAPI
wine_vkGetDeviceProcAddr(VkDevice device
, const char *name
)
794 TRACE("%p, %s\n", device
, debugstr_a(name
));
796 /* The spec leaves return value undefined for a NULL device, let's just return NULL. */
797 if (!device
|| !name
)
800 /* Per the spec, we are only supposed to return device functions as in functions
801 * for which the first parameter is vkDevice or a child of vkDevice like a
802 * vkCommandBuffer or vkQueue.
803 * Loader takes care of filtering of extensions which are enabled or not.
805 func
= wine_vk_get_device_proc_addr(name
);
809 /* vkGetDeviceProcAddr was intended for loading device and subdevice functions.
810 * idTech 6 titles such as Doom and Wolfenstein II, however use it also for
811 * loading of instance functions. This is undefined behavior as the specification
812 * disallows using any of the returned function pointers outside of device /
813 * subdevice objects. The games don't actually use the function pointers and if they
814 * did, they would crash as VkInstance / VkPhysicalDevice parameters need unwrapping.
815 * Khronos clarified behavior in the Vulkan spec and expects drivers to get updated,
816 * however it would require both driver and game fixes.
817 * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/2323
818 * https://github.com/KhronosGroup/Vulkan-Docs/issues/655
820 if (device
->quirks
& WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR
821 && (func
= wine_vk_get_instance_proc_addr(name
)))
823 WARN("Returning instance function %s.\n", debugstr_a(name
));
827 TRACE("Function %s not found.\n", debugstr_a(name
));
831 void WINAPI
wine_vkGetDeviceQueue(VkDevice device
, uint32_t family_index
,
832 uint32_t queue_index
, VkQueue
*queue
)
834 TRACE("%p %u %u %p\n", device
, family_index
, queue_index
, queue
);
836 *queue
= &device
->queues
[family_index
][queue_index
];
839 PFN_vkVoidFunction WINAPI
wine_vkGetInstanceProcAddr(VkInstance instance
, const char *name
)
843 TRACE("%p %s\n", instance
, debugstr_a(name
));
848 /* vkGetInstanceProcAddr can load most Vulkan functions when an instance is passed in, however
849 * for a NULL instance it can only load global functions.
851 func
= wine_vk_get_global_proc_addr(name
);
858 FIXME("Global function %s not found.\n", debugstr_a(name
));
862 func
= wine_vk_get_instance_proc_addr(name
);
863 if (func
) return func
;
865 /* vkGetInstanceProcAddr also loads any children of instance, so device functions as well. */
866 func
= wine_vk_get_device_proc_addr(name
);
867 if (func
) return func
;
869 FIXME("Unsupported device or instance function: %s.\n", debugstr_a(name
));
873 void * WINAPI
wine_vk_icdGetInstanceProcAddr(VkInstance instance
, const char *name
)
875 TRACE("%p %s\n", instance
, debugstr_a(name
));
877 /* Initial version of the Vulkan ICD spec required vkGetInstanceProcAddr to be
878 * exported. vk_icdGetInstanceProcAddr was added later to separate ICD calls from
879 * Vulkan API. One of them in our case should forward to the other, so just forward
880 * to the older vkGetInstanceProcAddr.
882 return wine_vkGetInstanceProcAddr(instance
, name
);
885 VkResult WINAPI
wine_vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t *supported_version
)
887 uint32_t req_version
;
889 TRACE("%p\n", supported_version
);
891 /* The spec is not clear how to handle this. Mesa drivers don't check, but it
892 * is probably best to not explode. VK_INCOMPLETE seems to be the closest value.
894 if (!supported_version
)
895 return VK_INCOMPLETE
;
897 req_version
= *supported_version
;
898 *supported_version
= min(req_version
, WINE_VULKAN_ICD_VERSION
);
899 TRACE("Loader requested ICD version %u, returning %u\n", req_version
, *supported_version
);
904 VkResult WINAPI
wine_vkQueueSubmit(VkQueue queue
, uint32_t count
,
905 const VkSubmitInfo
*submits
, VkFence fence
)
907 VkSubmitInfo
*submits_host
;
909 VkCommandBuffer
*command_buffers
;
910 unsigned int i
, j
, num_command_buffers
;
912 TRACE("%p %u %p 0x%s\n", queue
, count
, submits
, wine_dbgstr_longlong(fence
));
916 return queue
->device
->funcs
.p_vkQueueSubmit(queue
->queue
, 0, NULL
, fence
);
919 submits_host
= heap_calloc(count
, sizeof(*submits_host
));
922 ERR("Unable to allocate memory for submit buffers!\n");
923 return VK_ERROR_OUT_OF_HOST_MEMORY
;
926 for (i
= 0; i
< count
; i
++)
928 memcpy(&submits_host
[i
], &submits
[i
], sizeof(*submits_host
));
930 num_command_buffers
= submits
[i
].commandBufferCount
;
931 command_buffers
= heap_calloc(num_command_buffers
, sizeof(*submits_host
));
932 if (!command_buffers
)
934 ERR("Unable to allocate memory for comman buffers!\n");
935 res
= VK_ERROR_OUT_OF_HOST_MEMORY
;
939 for (j
= 0; j
< num_command_buffers
; j
++)
941 command_buffers
[j
] = submits
[i
].pCommandBuffers
[j
]->command_buffer
;
943 submits_host
[i
].pCommandBuffers
= command_buffers
;
946 res
= queue
->device
->funcs
.p_vkQueueSubmit(queue
->queue
, count
, submits_host
, fence
);
949 for (i
= 0; i
< count
; i
++)
951 heap_free((void *)submits_host
[i
].pCommandBuffers
);
953 heap_free(submits_host
);
955 TRACE("Returning %d\n", res
);
960 BOOL WINAPI
DllMain(HINSTANCE hinst
, DWORD reason
, void *reserved
)
964 case DLL_PROCESS_ATTACH
:
965 DisableThreadLibraryCalls(hinst
);
966 return wine_vk_init();
971 static const struct vulkan_func vk_global_dispatch_table
[] =
973 {"vkCreateInstance", &wine_vkCreateInstance
},
974 {"vkEnumerateInstanceExtensionProperties", &wine_vkEnumerateInstanceExtensionProperties
},
975 {"vkGetInstanceProcAddr", &wine_vkGetInstanceProcAddr
},
978 static void *wine_vk_get_global_proc_addr(const char *name
)
982 for (i
= 0; i
< ARRAY_SIZE(vk_global_dispatch_table
); i
++)
984 if (strcmp(name
, vk_global_dispatch_table
[i
].name
) == 0)
986 TRACE("Found name=%s in global table\n", debugstr_a(name
));
987 return vk_global_dispatch_table
[i
].func
;