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