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
30 #include "vulkan_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(vulkan
);
34 DEFINE_DEVPROPKEY(DEVPROPKEY_GPU_LUID
, 0x60b193cb, 0x5276, 0x4d0f, 0x96, 0xfc, 0xf1, 0x73, 0xab, 0xad, 0x3e, 0xc6, 2);
35 DEFINE_DEVPROPKEY(WINE_DEVPROPKEY_GPU_VULKAN_UUID
, 0x233a9ef3, 0xafc4, 0x4abd, 0xb5, 0x64, 0xc3, 0x2f, 0x21, 0xf1, 0x53, 0x5c, 2);
37 /* For now default to 4 as it felt like a reasonable version feature wise to support.
38 * Don't support the optional vk_icdGetPhysicalDeviceProcAddr introduced in this version
39 * as it is unlikely we will implement physical device extensions, which the loader is not
40 * aware of. 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 static void *wine_vk_get_global_proc_addr(const char *name
);
60 static HINSTANCE hinstance
;
61 static const struct vulkan_funcs
*vk_funcs
;
62 static VkResult (*p_vkEnumerateInstanceVersion
)(uint32_t *version
);
64 void WINAPI
wine_vkGetPhysicalDeviceProperties(VkPhysicalDevice physical_device
,
65 VkPhysicalDeviceProperties
*properties
);
67 static void wine_vk_physical_device_free(struct VkPhysicalDevice_T
*phys_dev
)
72 heap_free(phys_dev
->extensions
);
76 static struct VkPhysicalDevice_T
*wine_vk_physical_device_alloc(struct VkInstance_T
*instance
,
77 VkPhysicalDevice phys_dev
)
79 struct VkPhysicalDevice_T
*object
;
80 uint32_t num_host_properties
, num_properties
= 0;
81 VkExtensionProperties
*host_properties
= NULL
;
85 if (!(object
= heap_alloc_zero(sizeof(*object
))))
88 object
->base
.loader_magic
= VULKAN_ICD_MAGIC_VALUE
;
89 object
->instance
= instance
;
90 object
->phys_dev
= phys_dev
;
92 res
= instance
->funcs
.p_vkEnumerateDeviceExtensionProperties(phys_dev
,
93 NULL
, &num_host_properties
, NULL
);
94 if (res
!= VK_SUCCESS
)
96 ERR("Failed to enumerate device extensions, res=%d\n", res
);
100 host_properties
= heap_calloc(num_host_properties
, sizeof(*host_properties
));
101 if (!host_properties
)
103 ERR("Failed to allocate memory for device properties!\n");
107 res
= instance
->funcs
.p_vkEnumerateDeviceExtensionProperties(phys_dev
,
108 NULL
, &num_host_properties
, host_properties
);
109 if (res
!= VK_SUCCESS
)
111 ERR("Failed to enumerate device extensions, res=%d\n", res
);
115 /* Count list of extensions for which we have an implementation.
116 * TODO: perform translation for platform specific extensions.
118 for (i
= 0; i
< num_host_properties
; i
++)
120 if (wine_vk_device_extension_supported(host_properties
[i
].extensionName
))
122 TRACE("Enabling extension '%s' for physical device %p\n", host_properties
[i
].extensionName
, object
);
127 TRACE("Skipping extension '%s', no implementation found in winevulkan.\n", host_properties
[i
].extensionName
);
131 TRACE("Host supported extensions %u, Wine supported extensions %u\n", num_host_properties
, num_properties
);
133 if (!(object
->extensions
= heap_calloc(num_properties
, sizeof(*object
->extensions
))))
135 ERR("Failed to allocate memory for device extensions!\n");
139 for (i
= 0, j
= 0; i
< num_host_properties
; i
++)
141 if (wine_vk_device_extension_supported(host_properties
[i
].extensionName
))
143 object
->extensions
[j
] = host_properties
[i
];
147 object
->extension_count
= num_properties
;
149 heap_free(host_properties
);
153 wine_vk_physical_device_free(object
);
154 heap_free(host_properties
);
158 static void wine_vk_free_command_buffers(struct VkDevice_T
*device
,
159 struct wine_cmd_pool
*pool
, uint32_t count
, const VkCommandBuffer
*buffers
)
163 for (i
= 0; i
< count
; i
++)
168 device
->funcs
.p_vkFreeCommandBuffers(device
->device
, pool
->command_pool
, 1, &buffers
[i
]->command_buffer
);
169 list_remove(&buffers
[i
]->pool_link
);
170 heap_free(buffers
[i
]);
174 static struct VkQueue_T
*wine_vk_device_alloc_queues(struct VkDevice_T
*device
,
175 uint32_t family_index
, uint32_t queue_count
, VkDeviceQueueCreateFlags flags
)
177 VkDeviceQueueInfo2 queue_info
;
178 struct VkQueue_T
*queues
;
181 if (!(queues
= heap_calloc(queue_count
, sizeof(*queues
))))
183 ERR("Failed to allocate memory for queues\n");
187 for (i
= 0; i
< queue_count
; i
++)
189 struct VkQueue_T
*queue
= &queues
[i
];
191 queue
->base
.loader_magic
= VULKAN_ICD_MAGIC_VALUE
;
192 queue
->device
= device
;
193 queue
->flags
= flags
;
195 /* The Vulkan spec says:
197 * "vkGetDeviceQueue must only be used to get queues that were created
198 * with the flags parameter of VkDeviceQueueCreateInfo set to zero."
200 if (flags
&& device
->funcs
.p_vkGetDeviceQueue2
)
202 queue_info
.sType
= VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2
;
203 queue_info
.pNext
= NULL
;
204 queue_info
.flags
= flags
;
205 queue_info
.queueFamilyIndex
= family_index
;
206 queue_info
.queueIndex
= i
;
207 device
->funcs
.p_vkGetDeviceQueue2(device
->device
, &queue_info
, &queue
->queue
);
211 device
->funcs
.p_vkGetDeviceQueue(device
->device
, family_index
, i
, &queue
->queue
);
218 static void wine_vk_device_free_create_info(VkDeviceCreateInfo
*create_info
)
220 VkDeviceGroupDeviceCreateInfo
*group_info
;
222 if ((group_info
= wine_vk_find_struct(create_info
, DEVICE_GROUP_DEVICE_CREATE_INFO
)))
224 heap_free((void *)group_info
->pPhysicalDevices
);
227 free_VkDeviceCreateInfo_struct_chain(create_info
);
230 static VkResult
wine_vk_device_convert_create_info(const VkDeviceCreateInfo
*src
,
231 VkDeviceCreateInfo
*dst
)
233 VkDeviceGroupDeviceCreateInfo
*group_info
;
239 if ((res
= convert_VkDeviceCreateInfo_struct_chain(src
->pNext
, dst
)) < 0)
241 WARN("Failed to convert VkDeviceCreateInfo pNext chain, res=%d.\n", res
);
245 /* FIXME: convert_VkDeviceCreateInfo_struct_chain() should unwrap handles for us. */
246 if ((group_info
= wine_vk_find_struct(dst
, DEVICE_GROUP_DEVICE_CREATE_INFO
)))
248 VkPhysicalDevice
*physical_devices
;
250 if (!(physical_devices
= heap_calloc(group_info
->physicalDeviceCount
, sizeof(*physical_devices
))))
252 free_VkDeviceCreateInfo_struct_chain(dst
);
253 return VK_ERROR_OUT_OF_HOST_MEMORY
;
255 for (i
= 0; i
< group_info
->physicalDeviceCount
; ++i
)
257 physical_devices
[i
] = group_info
->pPhysicalDevices
[i
]->phys_dev
;
259 group_info
->pPhysicalDevices
= physical_devices
;
262 /* Should be filtered out by loader as ICDs don't support layers. */
263 dst
->enabledLayerCount
= 0;
264 dst
->ppEnabledLayerNames
= NULL
;
266 TRACE("Enabled %u extensions.\n", dst
->enabledExtensionCount
);
267 for (i
= 0; i
< dst
->enabledExtensionCount
; i
++)
269 const char *extension_name
= dst
->ppEnabledExtensionNames
[i
];
270 TRACE("Extension %u: %s.\n", i
, debugstr_a(extension_name
));
271 if (!wine_vk_device_extension_supported(extension_name
))
273 WARN("Extension %s is not supported.\n", debugstr_a(extension_name
));
274 wine_vk_device_free_create_info(dst
);
275 return VK_ERROR_EXTENSION_NOT_PRESENT
;
282 /* Helper function used for freeing a device structure. This function supports full
283 * and partial object cleanups and can thus be used for vkCreateDevice failures.
285 static void wine_vk_device_free(struct VkDevice_T
*device
)
293 for (i
= 0; i
< device
->max_queue_families
; i
++)
295 heap_free(device
->queues
[i
]);
297 heap_free(device
->queues
);
298 device
->queues
= NULL
;
301 if (device
->device
&& device
->funcs
.p_vkDestroyDevice
)
303 device
->funcs
.p_vkDestroyDevice(device
->device
, NULL
/* pAllocator */);
309 static BOOL WINAPI
wine_vk_init(INIT_ONCE
*once
, void *param
, void **context
)
314 vk_funcs
= __wine_get_vulkan_driver(hdc
, WINE_VULKAN_DRIVER_VERSION
);
317 ERR("Failed to load Wine graphics driver supporting Vulkan.\n");
319 p_vkEnumerateInstanceVersion
= vk_funcs
->p_vkGetInstanceProcAddr(NULL
, "vkEnumerateInstanceVersion");
324 static void wine_vk_init_once(void)
326 static INIT_ONCE init_once
= INIT_ONCE_STATIC_INIT
;
328 InitOnceExecuteOnce(&init_once
, wine_vk_init
, NULL
, NULL
);
331 /* Helper function for converting between win32 and host compatible VkInstanceCreateInfo.
332 * This function takes care of extensions handled at winevulkan layer, a Wine graphics
333 * driver is responsible for handling e.g. surface extensions.
335 static VkResult
wine_vk_instance_convert_create_info(const VkInstanceCreateInfo
*src
,
336 VkInstanceCreateInfo
*dst
)
343 if ((res
= convert_VkInstanceCreateInfo_struct_chain(src
->pNext
, dst
)) < 0)
345 WARN("Failed to convert VkInstanceCreateInfo pNext chain, res=%d.\n", res
);
349 /* ICDs don't support any layers, so nothing to copy. Modern versions of the loader
350 * filter this data out as well.
352 dst
->enabledLayerCount
= 0;
353 dst
->ppEnabledLayerNames
= NULL
;
355 TRACE("Enabled %u instance extensions.\n", dst
->enabledExtensionCount
);
356 for (i
= 0; i
< dst
->enabledExtensionCount
; i
++)
358 const char *extension_name
= dst
->ppEnabledExtensionNames
[i
];
359 TRACE("Extension %u: %s.\n", i
, debugstr_a(extension_name
));
360 if (!wine_vk_instance_extension_supported(extension_name
))
362 WARN("Extension %s is not supported.\n", debugstr_a(extension_name
));
363 free_VkInstanceCreateInfo_struct_chain(dst
);
364 return VK_ERROR_EXTENSION_NOT_PRESENT
;
371 /* Helper function which stores wrapped physical devices in the instance object. */
372 static VkResult
wine_vk_instance_load_physical_devices(struct VkInstance_T
*instance
)
374 VkPhysicalDevice
*tmp_phys_devs
;
375 uint32_t phys_dev_count
;
379 res
= instance
->funcs
.p_vkEnumeratePhysicalDevices(instance
->instance
, &phys_dev_count
, NULL
);
380 if (res
!= VK_SUCCESS
)
382 ERR("Failed to enumerate physical devices, res=%d\n", res
);
388 if (!(tmp_phys_devs
= heap_calloc(phys_dev_count
, sizeof(*tmp_phys_devs
))))
389 return VK_ERROR_OUT_OF_HOST_MEMORY
;
391 res
= instance
->funcs
.p_vkEnumeratePhysicalDevices(instance
->instance
, &phys_dev_count
, tmp_phys_devs
);
392 if (res
!= VK_SUCCESS
)
394 heap_free(tmp_phys_devs
);
398 instance
->phys_devs
= heap_calloc(phys_dev_count
, sizeof(*instance
->phys_devs
));
399 if (!instance
->phys_devs
)
401 heap_free(tmp_phys_devs
);
402 return VK_ERROR_OUT_OF_HOST_MEMORY
;
405 /* Wrap each native physical device handle into a dispatchable object for the ICD loader. */
406 for (i
= 0; i
< phys_dev_count
; i
++)
408 struct VkPhysicalDevice_T
*phys_dev
= wine_vk_physical_device_alloc(instance
, tmp_phys_devs
[i
]);
411 ERR("Unable to allocate memory for physical device!\n");
412 heap_free(tmp_phys_devs
);
413 return VK_ERROR_OUT_OF_HOST_MEMORY
;
416 instance
->phys_devs
[i
] = phys_dev
;
417 instance
->phys_dev_count
= i
+ 1;
419 instance
->phys_dev_count
= phys_dev_count
;
421 heap_free(tmp_phys_devs
);
425 static struct VkPhysicalDevice_T
*wine_vk_instance_wrap_physical_device(struct VkInstance_T
*instance
,
426 VkPhysicalDevice physical_device
)
430 for (i
= 0; i
< instance
->phys_dev_count
; ++i
)
432 struct VkPhysicalDevice_T
*current
= instance
->phys_devs
[i
];
433 if (current
->phys_dev
== physical_device
)
437 ERR("Unrecognized physical device %p.\n", physical_device
);
441 /* Helper function used for freeing an instance structure. This function supports full
442 * and partial object cleanups and can thus be used for vkCreateInstance failures.
444 static void wine_vk_instance_free(struct VkInstance_T
*instance
)
449 if (instance
->phys_devs
)
453 for (i
= 0; i
< instance
->phys_dev_count
; i
++)
455 wine_vk_physical_device_free(instance
->phys_devs
[i
]);
457 heap_free(instance
->phys_devs
);
460 if (instance
->instance
)
461 vk_funcs
->p_vkDestroyInstance(instance
->instance
, NULL
/* allocator */);
466 VkResult WINAPI
wine_vkAllocateCommandBuffers(VkDevice device
,
467 const VkCommandBufferAllocateInfo
*allocate_info
, VkCommandBuffer
*buffers
)
469 struct wine_cmd_pool
*pool
;
470 VkResult res
= VK_SUCCESS
;
473 TRACE("%p, %p, %p\n", device
, allocate_info
, buffers
);
475 pool
= wine_cmd_pool_from_handle(allocate_info
->commandPool
);
477 memset(buffers
, 0, allocate_info
->commandBufferCount
* sizeof(*buffers
));
479 for (i
= 0; i
< allocate_info
->commandBufferCount
; i
++)
481 #if defined(USE_STRUCT_CONVERSION)
482 VkCommandBufferAllocateInfo_host allocate_info_host
;
484 VkCommandBufferAllocateInfo allocate_info_host
;
486 /* TODO: future extensions (none yet) may require pNext conversion. */
487 allocate_info_host
.pNext
= allocate_info
->pNext
;
488 allocate_info_host
.sType
= allocate_info
->sType
;
489 allocate_info_host
.commandPool
= pool
->command_pool
;
490 allocate_info_host
.level
= allocate_info
->level
;
491 allocate_info_host
.commandBufferCount
= 1;
493 TRACE("Allocating command buffer %u from pool 0x%s.\n",
494 i
, wine_dbgstr_longlong(allocate_info_host
.commandPool
));
496 if (!(buffers
[i
] = heap_alloc_zero(sizeof(**buffers
))))
498 res
= VK_ERROR_OUT_OF_HOST_MEMORY
;
502 buffers
[i
]->base
.loader_magic
= VULKAN_ICD_MAGIC_VALUE
;
503 buffers
[i
]->device
= device
;
504 list_add_tail(&pool
->command_buffers
, &buffers
[i
]->pool_link
);
505 res
= device
->funcs
.p_vkAllocateCommandBuffers(device
->device
,
506 &allocate_info_host
, &buffers
[i
]->command_buffer
);
507 if (res
!= VK_SUCCESS
)
509 ERR("Failed to allocate command buffer, res=%d.\n", res
);
510 buffers
[i
]->command_buffer
= VK_NULL_HANDLE
;
515 if (res
!= VK_SUCCESS
)
517 wine_vk_free_command_buffers(device
, pool
, i
+ 1, buffers
);
518 memset(buffers
, 0, allocate_info
->commandBufferCount
* sizeof(*buffers
));
524 void WINAPI
wine_vkCmdExecuteCommands(VkCommandBuffer buffer
, uint32_t count
,
525 const VkCommandBuffer
*buffers
)
527 VkCommandBuffer
*tmp_buffers
;
530 TRACE("%p %u %p\n", buffer
, count
, buffers
);
532 if (!buffers
|| !count
)
535 /* Unfortunately we need a temporary buffer as our command buffers are wrapped.
536 * This call is called often and if a performance concern, we may want to use
537 * alloca as we shouldn't need much memory and it needs to be cleaned up after
540 if (!(tmp_buffers
= heap_alloc(count
* sizeof(*tmp_buffers
))))
542 ERR("Failed to allocate memory for temporary command buffers\n");
546 for (i
= 0; i
< count
; i
++)
547 tmp_buffers
[i
] = buffers
[i
]->command_buffer
;
549 buffer
->device
->funcs
.p_vkCmdExecuteCommands(buffer
->command_buffer
, count
, tmp_buffers
);
551 heap_free(tmp_buffers
);
554 VkResult WINAPI
wine_vkCreateDevice(VkPhysicalDevice phys_dev
,
555 const VkDeviceCreateInfo
*create_info
,
556 const VkAllocationCallbacks
*allocator
, VkDevice
*device
)
558 VkDeviceCreateInfo create_info_host
;
559 uint32_t max_queue_families
;
560 struct VkDevice_T
*object
;
564 TRACE("%p, %p, %p, %p\n", phys_dev
, create_info
, allocator
, device
);
567 FIXME("Support for allocation callbacks not implemented yet\n");
569 if (TRACE_ON(vulkan
))
571 VkPhysicalDeviceProperties properties
;
573 wine_vkGetPhysicalDeviceProperties(phys_dev
, &properties
);
575 TRACE("Device name: %s.\n", debugstr_a(properties
.deviceName
));
576 TRACE("Vendor ID: %#x, Device ID: %#x.\n", properties
.vendorID
, properties
.deviceID
);
577 TRACE("Driver version: %#x.\n", properties
.driverVersion
);
580 if (!(object
= heap_alloc_zero(sizeof(*object
))))
581 return VK_ERROR_OUT_OF_HOST_MEMORY
;
583 object
->base
.loader_magic
= VULKAN_ICD_MAGIC_VALUE
;
585 res
= wine_vk_device_convert_create_info(create_info
, &create_info_host
);
586 if (res
!= VK_SUCCESS
)
589 res
= phys_dev
->instance
->funcs
.p_vkCreateDevice(phys_dev
->phys_dev
,
590 &create_info_host
, NULL
/* allocator */, &object
->device
);
591 wine_vk_device_free_create_info(&create_info_host
);
592 if (res
!= VK_SUCCESS
)
594 WARN("Failed to create device, res=%d.\n", res
);
598 /* Just load all function pointers we are aware off. The loader takes care of filtering.
599 * We use vkGetDeviceProcAddr as opposed to vkGetInstanceProcAddr for efficiency reasons
600 * as functions pass through fewer dispatch tables within the loader.
602 #define USE_VK_FUNC(name) \
603 object->funcs.p_##name = (void *)vk_funcs->p_vkGetDeviceProcAddr(object->device, #name); \
604 if (object->funcs.p_##name == NULL) \
605 TRACE("Not found '%s'.\n", #name);
606 ALL_VK_DEVICE_FUNCS()
609 /* We need to cache all queues within the device as each requires wrapping since queues are
610 * dispatchable objects.
612 phys_dev
->instance
->funcs
.p_vkGetPhysicalDeviceQueueFamilyProperties(phys_dev
->phys_dev
,
613 &max_queue_families
, NULL
);
614 object
->max_queue_families
= max_queue_families
;
615 TRACE("Max queue families: %u.\n", object
->max_queue_families
);
617 if (!(object
->queues
= heap_calloc(max_queue_families
, sizeof(*object
->queues
))))
619 res
= VK_ERROR_OUT_OF_HOST_MEMORY
;
623 for (i
= 0; i
< create_info_host
.queueCreateInfoCount
; i
++)
625 uint32_t flags
= create_info_host
.pQueueCreateInfos
[i
].flags
;
626 uint32_t family_index
= create_info_host
.pQueueCreateInfos
[i
].queueFamilyIndex
;
627 uint32_t queue_count
= create_info_host
.pQueueCreateInfos
[i
].queueCount
;
629 TRACE("Queue family index %u, queue count %u.\n", family_index
, queue_count
);
631 if (!(object
->queues
[family_index
] = wine_vk_device_alloc_queues(object
, family_index
, queue_count
, flags
)))
633 ERR("Failed to allocate memory for queues.\n");
634 res
= VK_ERROR_OUT_OF_HOST_MEMORY
;
639 object
->quirks
= phys_dev
->instance
->quirks
;
642 TRACE("Created device %p (native device %p).\n", object
, object
->device
);
646 wine_vk_device_free(object
);
650 VkResult WINAPI
wine_vkCreateInstance(const VkInstanceCreateInfo
*create_info
,
651 const VkAllocationCallbacks
*allocator
, VkInstance
*instance
)
653 VkInstanceCreateInfo create_info_host
;
654 const VkApplicationInfo
*app_info
;
655 struct VkInstance_T
*object
;
658 TRACE("create_info %p, allocator %p, instance %p\n", create_info
, allocator
, instance
);
662 return VK_ERROR_INITIALIZATION_FAILED
;
665 FIXME("Support for allocation callbacks not implemented yet\n");
667 if (!(object
= heap_alloc_zero(sizeof(*object
))))
669 ERR("Failed to allocate memory for instance\n");
670 return VK_ERROR_OUT_OF_HOST_MEMORY
;
672 object
->base
.loader_magic
= VULKAN_ICD_MAGIC_VALUE
;
674 res
= wine_vk_instance_convert_create_info(create_info
, &create_info_host
);
675 if (res
!= VK_SUCCESS
)
677 wine_vk_instance_free(object
);
681 res
= vk_funcs
->p_vkCreateInstance(&create_info_host
, NULL
/* allocator */, &object
->instance
);
682 free_VkInstanceCreateInfo_struct_chain(&create_info_host
);
683 if (res
!= VK_SUCCESS
)
685 ERR("Failed to create instance, res=%d\n", res
);
686 wine_vk_instance_free(object
);
690 /* Load all instance functions we are aware of. Note the loader takes care
691 * of any filtering for extensions which were not requested, but which the
694 #define USE_VK_FUNC(name) \
695 object->funcs.p_##name = (void *)vk_funcs->p_vkGetInstanceProcAddr(object->instance, #name);
696 ALL_VK_INSTANCE_FUNCS()
699 /* Cache physical devices for vkEnumeratePhysicalDevices within the instance as
700 * each vkPhysicalDevice is a dispatchable object, which means we need to wrap
701 * the native physical devices and present those to the application.
702 * Cleanup happens as part of wine_vkDestroyInstance.
704 res
= wine_vk_instance_load_physical_devices(object
);
705 if (res
!= VK_SUCCESS
)
707 ERR("Failed to load physical devices, res=%d\n", res
);
708 wine_vk_instance_free(object
);
712 if ((app_info
= create_info
->pApplicationInfo
))
714 TRACE("Application name %s, application version %#x.\n",
715 debugstr_a(app_info
->pApplicationName
), app_info
->applicationVersion
);
716 TRACE("Engine name %s, engine version %#x.\n", debugstr_a(app_info
->pEngineName
),
717 app_info
->engineVersion
);
718 TRACE("API version %#x.\n", app_info
->apiVersion
);
720 if (app_info
->pEngineName
&& !strcmp(app_info
->pEngineName
, "idTech"))
721 object
->quirks
|= WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR
;
725 TRACE("Created instance %p (native instance %p).\n", object
, object
->instance
);
729 void WINAPI
wine_vkDestroyDevice(VkDevice device
, const VkAllocationCallbacks
*allocator
)
731 TRACE("%p %p\n", device
, allocator
);
734 FIXME("Support for allocation callbacks not implemented yet\n");
736 wine_vk_device_free(device
);
739 void WINAPI
wine_vkDestroyInstance(VkInstance instance
, const VkAllocationCallbacks
*allocator
)
741 TRACE("%p, %p\n", instance
, allocator
);
744 FIXME("Support allocation allocators\n");
746 wine_vk_instance_free(instance
);
749 VkResult WINAPI
wine_vkEnumerateDeviceExtensionProperties(VkPhysicalDevice phys_dev
,
750 const char *layer_name
, uint32_t *count
, VkExtensionProperties
*properties
)
752 TRACE("%p, %p, %p, %p\n", phys_dev
, layer_name
, count
, properties
);
754 /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
757 ERR("Layer enumeration not supported from ICD.\n");
758 return VK_ERROR_LAYER_NOT_PRESENT
;
763 *count
= phys_dev
->extension_count
;
767 *count
= min(*count
, phys_dev
->extension_count
);
768 memcpy(properties
, phys_dev
->extensions
, *count
* sizeof(*properties
));
770 TRACE("Returning %u extensions.\n", *count
);
771 return *count
< phys_dev
->extension_count
? VK_INCOMPLETE
: VK_SUCCESS
;
774 VkResult WINAPI
wine_vkEnumerateInstanceExtensionProperties(const char *layer_name
,
775 uint32_t *count
, VkExtensionProperties
*properties
)
777 uint32_t num_properties
= 0, num_host_properties
;
778 VkExtensionProperties
*host_properties
;
782 TRACE("%p, %p, %p\n", layer_name
, count
, properties
);
786 WARN("Layer enumeration not supported from ICD.\n");
787 return VK_ERROR_LAYER_NOT_PRESENT
;
792 return VK_ERROR_INITIALIZATION_FAILED
;
794 res
= vk_funcs
->p_vkEnumerateInstanceExtensionProperties(NULL
, &num_host_properties
, NULL
);
795 if (res
!= VK_SUCCESS
)
798 if (!(host_properties
= heap_calloc(num_host_properties
, sizeof(*host_properties
))))
799 return VK_ERROR_OUT_OF_HOST_MEMORY
;
801 res
= vk_funcs
->p_vkEnumerateInstanceExtensionProperties(NULL
, &num_host_properties
, host_properties
);
802 if (res
!= VK_SUCCESS
)
804 ERR("Failed to retrieve host properties, res=%d.\n", res
);
805 heap_free(host_properties
);
809 /* The Wine graphics driver provides us with all extensions supported by the host side
810 * including extension fixup (e.g. VK_KHR_xlib_surface -> VK_KHR_win32_surface). It is
811 * up to us here to filter the list down to extensions for which we have thunks.
813 for (i
= 0; i
< num_host_properties
; i
++)
815 if (wine_vk_instance_extension_supported(host_properties
[i
].extensionName
))
818 TRACE("Instance extension '%s' is not supported.\n", host_properties
[i
].extensionName
);
823 TRACE("Returning %u extensions.\n", num_properties
);
824 *count
= num_properties
;
825 heap_free(host_properties
);
829 for (i
= 0, j
= 0; i
< num_host_properties
&& j
< *count
; i
++)
831 if (wine_vk_instance_extension_supported(host_properties
[i
].extensionName
))
833 TRACE("Enabling extension '%s'.\n", host_properties
[i
].extensionName
);
834 properties
[j
++] = host_properties
[i
];
837 *count
= min(*count
, num_properties
);
839 heap_free(host_properties
);
840 return *count
< num_properties
? VK_INCOMPLETE
: VK_SUCCESS
;
843 VkResult WINAPI
wine_vkEnumerateInstanceLayerProperties(uint32_t *count
, VkLayerProperties
*properties
)
845 TRACE("%p, %p\n", count
, properties
);
853 return VK_ERROR_LAYER_NOT_PRESENT
;
856 VkResult WINAPI
wine_vkEnumerateInstanceVersion(uint32_t *version
)
860 TRACE("%p\n", version
);
864 if (p_vkEnumerateInstanceVersion
)
866 res
= p_vkEnumerateInstanceVersion(version
);
870 *version
= VK_API_VERSION_1_0
;
874 TRACE("API version %u.%u.%u.\n",
875 VK_VERSION_MAJOR(*version
), VK_VERSION_MINOR(*version
), VK_VERSION_PATCH(*version
));
876 *version
= min(WINE_VK_VERSION
, *version
);
880 VkResult WINAPI
wine_vkEnumeratePhysicalDevices(VkInstance instance
, uint32_t *count
,
881 VkPhysicalDevice
*devices
)
885 TRACE("%p %p %p\n", instance
, count
, devices
);
889 *count
= instance
->phys_dev_count
;
893 *count
= min(*count
, instance
->phys_dev_count
);
894 for (i
= 0; i
< *count
; i
++)
896 devices
[i
] = instance
->phys_devs
[i
];
899 TRACE("Returning %u devices.\n", *count
);
900 return *count
< instance
->phys_dev_count
? VK_INCOMPLETE
: VK_SUCCESS
;
903 void WINAPI
wine_vkFreeCommandBuffers(VkDevice device
, VkCommandPool pool_handle
,
904 uint32_t count
, const VkCommandBuffer
*buffers
)
906 struct wine_cmd_pool
*pool
= wine_cmd_pool_from_handle(pool_handle
);
908 TRACE("%p, 0x%s, %u, %p\n", device
, wine_dbgstr_longlong(pool_handle
), count
, buffers
);
910 wine_vk_free_command_buffers(device
, pool
, count
, buffers
);
913 PFN_vkVoidFunction WINAPI
wine_vkGetDeviceProcAddr(VkDevice device
, const char *name
)
916 TRACE("%p, %s\n", device
, debugstr_a(name
));
918 /* The spec leaves return value undefined for a NULL device, let's just return NULL. */
919 if (!device
|| !name
)
922 /* Per the spec, we are only supposed to return device functions as in functions
923 * for which the first parameter is vkDevice or a child of vkDevice like a
924 * vkCommandBuffer or vkQueue.
925 * Loader takes care of filtering of extensions which are enabled or not.
927 func
= wine_vk_get_device_proc_addr(name
);
931 /* vkGetDeviceProcAddr was intended for loading device and subdevice functions.
932 * idTech 6 titles such as Doom and Wolfenstein II, however use it also for
933 * loading of instance functions. This is undefined behavior as the specification
934 * disallows using any of the returned function pointers outside of device /
935 * subdevice objects. The games don't actually use the function pointers and if they
936 * did, they would crash as VkInstance / VkPhysicalDevice parameters need unwrapping.
937 * Khronos clarified behavior in the Vulkan spec and expects drivers to get updated,
938 * however it would require both driver and game fixes.
939 * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/2323
940 * https://github.com/KhronosGroup/Vulkan-Docs/issues/655
942 if (device
->quirks
& WINEVULKAN_QUIRK_GET_DEVICE_PROC_ADDR
943 && (func
= wine_vk_get_instance_proc_addr(name
)))
945 WARN("Returning instance function %s.\n", debugstr_a(name
));
949 WARN("Unsupported device function: %s.\n", debugstr_a(name
));
953 void WINAPI
wine_vkGetDeviceQueue(VkDevice device
, uint32_t family_index
,
954 uint32_t queue_index
, VkQueue
*queue
)
956 TRACE("%p, %u, %u, %p\n", device
, family_index
, queue_index
, queue
);
958 *queue
= &device
->queues
[family_index
][queue_index
];
961 void WINAPI
wine_vkGetDeviceQueue2(VkDevice device
, const VkDeviceQueueInfo2
*info
, VkQueue
*queue
)
963 struct VkQueue_T
*matching_queue
;
964 const VkBaseInStructure
*chain
;
966 TRACE("%p, %p, %p\n", device
, info
, queue
);
968 if ((chain
= info
->pNext
))
969 FIXME("Ignoring a linked structure of type %u.\n", chain
->sType
);
971 matching_queue
= &device
->queues
[info
->queueFamilyIndex
][info
->queueIndex
];
972 if (matching_queue
->flags
!= info
->flags
)
974 WARN("No matching flags were specified %#x, %#x.\n", matching_queue
->flags
, info
->flags
);
975 matching_queue
= VK_NULL_HANDLE
;
977 *queue
= matching_queue
;
980 PFN_vkVoidFunction WINAPI
wine_vkGetInstanceProcAddr(VkInstance instance
, const char *name
)
984 TRACE("%p, %s\n", instance
, debugstr_a(name
));
989 /* vkGetInstanceProcAddr can load most Vulkan functions when an instance is passed in, however
990 * for a NULL instance it can only load global functions.
992 func
= wine_vk_get_global_proc_addr(name
);
999 WARN("Global function %s not found.\n", debugstr_a(name
));
1003 func
= wine_vk_get_instance_proc_addr(name
);
1004 if (func
) return func
;
1006 /* vkGetInstanceProcAddr also loads any children of instance, so device functions as well. */
1007 func
= wine_vk_get_device_proc_addr(name
);
1008 if (func
) return func
;
1010 WARN("Unsupported device or instance function: %s.\n", debugstr_a(name
));
1014 void * WINAPI
wine_vk_icdGetInstanceProcAddr(VkInstance instance
, const char *name
)
1016 TRACE("%p, %s\n", instance
, debugstr_a(name
));
1018 /* Initial version of the Vulkan ICD spec required vkGetInstanceProcAddr to be
1019 * exported. vk_icdGetInstanceProcAddr was added later to separate ICD calls from
1020 * Vulkan API. One of them in our case should forward to the other, so just forward
1021 * to the older vkGetInstanceProcAddr.
1023 return wine_vkGetInstanceProcAddr(instance
, name
);
1026 VkResult WINAPI
wine_vk_icdNegotiateLoaderICDInterfaceVersion(uint32_t *supported_version
)
1028 uint32_t req_version
;
1030 TRACE("%p\n", supported_version
);
1032 /* The spec is not clear how to handle this. Mesa drivers don't check, but it
1033 * is probably best to not explode. VK_INCOMPLETE seems to be the closest value.
1035 if (!supported_version
)
1036 return VK_INCOMPLETE
;
1038 req_version
= *supported_version
;
1039 *supported_version
= min(req_version
, WINE_VULKAN_ICD_VERSION
);
1040 TRACE("Loader requested ICD version %u, returning %u\n", req_version
, *supported_version
);
1045 VkResult WINAPI
wine_vkQueueSubmit(VkQueue queue
, uint32_t count
,
1046 const VkSubmitInfo
*submits
, VkFence fence
)
1048 VkSubmitInfo
*submits_host
;
1050 VkCommandBuffer
*command_buffers
;
1051 unsigned int i
, j
, num_command_buffers
;
1053 TRACE("%p %u %p 0x%s\n", queue
, count
, submits
, wine_dbgstr_longlong(fence
));
1057 return queue
->device
->funcs
.p_vkQueueSubmit(queue
->queue
, 0, NULL
, fence
);
1060 submits_host
= heap_calloc(count
, sizeof(*submits_host
));
1063 ERR("Unable to allocate memory for submit buffers!\n");
1064 return VK_ERROR_OUT_OF_HOST_MEMORY
;
1067 for (i
= 0; i
< count
; i
++)
1069 memcpy(&submits_host
[i
], &submits
[i
], sizeof(*submits_host
));
1071 num_command_buffers
= submits
[i
].commandBufferCount
;
1072 command_buffers
= heap_calloc(num_command_buffers
, sizeof(*submits_host
));
1073 if (!command_buffers
)
1075 ERR("Unable to allocate memory for command buffers!\n");
1076 res
= VK_ERROR_OUT_OF_HOST_MEMORY
;
1080 for (j
= 0; j
< num_command_buffers
; j
++)
1082 command_buffers
[j
] = submits
[i
].pCommandBuffers
[j
]->command_buffer
;
1084 submits_host
[i
].pCommandBuffers
= command_buffers
;
1087 res
= queue
->device
->funcs
.p_vkQueueSubmit(queue
->queue
, count
, submits_host
, fence
);
1090 for (i
= 0; i
< count
; i
++)
1092 heap_free((void *)submits_host
[i
].pCommandBuffers
);
1094 heap_free(submits_host
);
1096 TRACE("Returning %d\n", res
);
1100 VkResult WINAPI
wine_vkCreateCommandPool(VkDevice device
, const VkCommandPoolCreateInfo
*info
,
1101 const VkAllocationCallbacks
*allocator
, VkCommandPool
*command_pool
)
1103 struct wine_cmd_pool
*object
;
1106 TRACE("%p, %p, %p, %p\n", device
, info
, allocator
, command_pool
);
1109 FIXME("Support for allocation callbacks not implemented yet\n");
1111 if (!(object
= heap_alloc_zero(sizeof(*object
))))
1112 return VK_ERROR_OUT_OF_HOST_MEMORY
;
1114 list_init(&object
->command_buffers
);
1116 res
= device
->funcs
.p_vkCreateCommandPool(device
->device
, info
, NULL
, &object
->command_pool
);
1118 if (res
== VK_SUCCESS
)
1119 *command_pool
= wine_cmd_pool_to_handle(object
);
1126 void WINAPI
wine_vkDestroyCommandPool(VkDevice device
, VkCommandPool handle
,
1127 const VkAllocationCallbacks
*allocator
)
1129 struct wine_cmd_pool
*pool
= wine_cmd_pool_from_handle(handle
);
1130 struct VkCommandBuffer_T
*buffer
, *cursor
;
1132 TRACE("%p, 0x%s, %p\n", device
, wine_dbgstr_longlong(handle
), allocator
);
1138 FIXME("Support for allocation callbacks not implemented yet\n");
1140 /* The Vulkan spec says:
1142 * "When a pool is destroyed, all command buffers allocated from the pool are freed."
1144 LIST_FOR_EACH_ENTRY_SAFE(buffer
, cursor
, &pool
->command_buffers
, struct VkCommandBuffer_T
, pool_link
)
1149 device
->funcs
.p_vkDestroyCommandPool(device
->device
, pool
->command_pool
, NULL
);
1153 static VkResult
wine_vk_enumerate_physical_device_groups(struct VkInstance_T
*instance
,
1154 VkResult (*p_vkEnumeratePhysicalDeviceGroups
)(VkInstance
, uint32_t *, VkPhysicalDeviceGroupProperties
*),
1155 uint32_t *count
, VkPhysicalDeviceGroupProperties
*properties
)
1160 res
= p_vkEnumeratePhysicalDeviceGroups(instance
->instance
, count
, properties
);
1161 if (res
< 0 || !properties
)
1164 for (i
= 0; i
< *count
; ++i
)
1166 VkPhysicalDeviceGroupProperties
*current
= &properties
[i
];
1167 for (j
= 0; j
< current
->physicalDeviceCount
; ++j
)
1169 VkPhysicalDevice dev
= current
->physicalDevices
[j
];
1170 if (!(current
->physicalDevices
[j
] = wine_vk_instance_wrap_physical_device(instance
, dev
)))
1171 return VK_ERROR_INITIALIZATION_FAILED
;
1178 VkResult WINAPI
wine_vkEnumeratePhysicalDeviceGroups(VkInstance instance
,
1179 uint32_t *count
, VkPhysicalDeviceGroupProperties
*properties
)
1181 TRACE("%p, %p, %p\n", instance
, count
, properties
);
1182 return wine_vk_enumerate_physical_device_groups(instance
,
1183 instance
->funcs
.p_vkEnumeratePhysicalDeviceGroups
, count
, properties
);
1186 VkResult WINAPI
wine_vkEnumeratePhysicalDeviceGroupsKHR(VkInstance instance
,
1187 uint32_t *count
, VkPhysicalDeviceGroupProperties
*properties
)
1189 TRACE("%p, %p, %p\n", instance
, count
, properties
);
1190 return wine_vk_enumerate_physical_device_groups(instance
,
1191 instance
->funcs
.p_vkEnumeratePhysicalDeviceGroupsKHR
, count
, properties
);
1194 void WINAPI
wine_vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice phys_dev
,
1195 const VkPhysicalDeviceExternalFenceInfo
*fence_info
, VkExternalFenceProperties
*properties
)
1197 TRACE("%p, %p, %p\n", phys_dev
, fence_info
, properties
);
1198 properties
->exportFromImportedHandleTypes
= 0;
1199 properties
->compatibleHandleTypes
= 0;
1200 properties
->externalFenceFeatures
= 0;
1203 void WINAPI
wine_vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice phys_dev
,
1204 const VkPhysicalDeviceExternalFenceInfo
*fence_info
, VkExternalFenceProperties
*properties
)
1206 TRACE("%p, %p, %p\n", phys_dev
, fence_info
, properties
);
1207 properties
->exportFromImportedHandleTypes
= 0;
1208 properties
->compatibleHandleTypes
= 0;
1209 properties
->externalFenceFeatures
= 0;
1212 void WINAPI
wine_vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice phys_dev
,
1213 const VkPhysicalDeviceExternalBufferInfo
*buffer_info
, VkExternalBufferProperties
*properties
)
1215 TRACE("%p, %p, %p\n", phys_dev
, buffer_info
, properties
);
1216 memset(&properties
->externalMemoryProperties
, 0, sizeof(properties
->externalMemoryProperties
));
1219 void WINAPI
wine_vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice phys_dev
,
1220 const VkPhysicalDeviceExternalBufferInfo
*buffer_info
, VkExternalBufferProperties
*properties
)
1222 TRACE("%p, %p, %p\n", phys_dev
, buffer_info
, properties
);
1223 memset(&properties
->externalMemoryProperties
, 0, sizeof(properties
->externalMemoryProperties
));
1226 VkResult WINAPI
wine_vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice phys_dev
,
1227 const VkPhysicalDeviceImageFormatInfo2
*format_info
, VkImageFormatProperties2
*properties
)
1229 VkExternalImageFormatProperties
*external_image_properties
;
1232 TRACE("%p, %p, %p\n", phys_dev
, format_info
, properties
);
1234 res
= thunk_vkGetPhysicalDeviceImageFormatProperties2(phys_dev
, format_info
, properties
);
1236 if ((external_image_properties
= wine_vk_find_struct(properties
, EXTERNAL_IMAGE_FORMAT_PROPERTIES
)))
1238 VkExternalMemoryProperties
*p
= &external_image_properties
->externalMemoryProperties
;
1239 p
->externalMemoryFeatures
= 0;
1240 p
->exportFromImportedHandleTypes
= 0;
1241 p
->compatibleHandleTypes
= 0;
1247 VkResult WINAPI
wine_vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice phys_dev
,
1248 const VkPhysicalDeviceImageFormatInfo2
*format_info
, VkImageFormatProperties2
*properties
)
1250 VkExternalImageFormatProperties
*external_image_properties
;
1253 TRACE("%p, %p, %p\n", phys_dev
, format_info
, properties
);
1255 res
= thunk_vkGetPhysicalDeviceImageFormatProperties2KHR(phys_dev
, format_info
, properties
);
1257 if ((external_image_properties
= wine_vk_find_struct(properties
, EXTERNAL_IMAGE_FORMAT_PROPERTIES
)))
1259 VkExternalMemoryProperties
*p
= &external_image_properties
->externalMemoryProperties
;
1260 p
->externalMemoryFeatures
= 0;
1261 p
->exportFromImportedHandleTypes
= 0;
1262 p
->compatibleHandleTypes
= 0;
1268 static HANDLE
get_display_device_init_mutex(void)
1270 static const WCHAR init_mutexW
[] = {'d','i','s','p','l','a','y','_','d','e','v','i','c','e','_','i','n','i','t',0};
1271 HANDLE mutex
= CreateMutexW(NULL
, FALSE
, init_mutexW
);
1273 WaitForSingleObject(mutex
, INFINITE
);
1277 static void release_display_device_init_mutex(HANDLE mutex
)
1279 ReleaseMutex(mutex
);
1283 /* Wait until graphics driver is loaded by explorer */
1284 static void wait_graphics_driver_ready(void)
1286 static BOOL ready
= FALSE
;
1290 SendMessageW(GetDesktopWindow(), WM_NULL
, 0, 0);
1295 static void fill_luid_property(VkPhysicalDeviceProperties2
*properties2
)
1297 static const WCHAR pci
[] = {'P','C','I',0};
1298 VkPhysicalDeviceIDProperties
*id
;
1299 SP_DEVINFO_DATA device_data
;
1300 DWORD type
, device_idx
= 0;
1306 if (!(id
= wine_vk_find_struct(properties2
, PHYSICAL_DEVICE_ID_PROPERTIES
)))
1309 wait_graphics_driver_ready();
1310 mutex
= get_display_device_init_mutex();
1311 devinfo
= SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY
, pci
, NULL
, 0);
1312 device_data
.cbSize
= sizeof(device_data
);
1313 while (SetupDiEnumDeviceInfo(devinfo
, device_idx
++, &device_data
))
1315 if (!SetupDiGetDevicePropertyW(devinfo
, &device_data
, &WINE_DEVPROPKEY_GPU_VULKAN_UUID
,
1316 &type
, (BYTE
*)&uuid
, sizeof(uuid
), NULL
, 0))
1319 if (!IsEqualGUID(&uuid
, id
->deviceUUID
))
1322 if (SetupDiGetDevicePropertyW(devinfo
, &device_data
, &DEVPROPKEY_GPU_LUID
, &type
,
1323 (BYTE
*)&luid
, sizeof(luid
), NULL
, 0))
1325 memcpy(&id
->deviceLUID
, &luid
, sizeof(id
->deviceLUID
));
1326 id
->deviceLUIDValid
= VK_TRUE
;
1327 id
->deviceNodeMask
= 1;
1331 SetupDiDestroyDeviceInfoList(devinfo
);
1332 release_display_device_init_mutex(mutex
);
1334 TRACE("deviceName:%s deviceLUIDValid:%d LUID:%08x:%08x deviceNodeMask:%#x.\n",
1335 properties2
->properties
.deviceName
, id
->deviceLUIDValid
, luid
.HighPart
, luid
.LowPart
,
1336 id
->deviceNodeMask
);
1339 void WINAPI
wine_vkGetPhysicalDeviceProperties2(VkPhysicalDevice phys_dev
,
1340 VkPhysicalDeviceProperties2
*properties2
)
1342 TRACE("%p, %p\n", phys_dev
, properties2
);
1344 thunk_vkGetPhysicalDeviceProperties2(phys_dev
, properties2
);
1345 fill_luid_property(properties2
);
1348 void WINAPI
wine_vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice phys_dev
,
1349 VkPhysicalDeviceProperties2
*properties2
)
1351 TRACE("%p, %p\n", phys_dev
, properties2
);
1353 thunk_vkGetPhysicalDeviceProperties2KHR(phys_dev
, properties2
);
1354 fill_luid_property(properties2
);
1357 void WINAPI
wine_vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice phys_dev
,
1358 const VkPhysicalDeviceExternalSemaphoreInfo
*semaphore_info
, VkExternalSemaphoreProperties
*properties
)
1360 TRACE("%p, %p, %p\n", phys_dev
, semaphore_info
, properties
);
1361 properties
->exportFromImportedHandleTypes
= 0;
1362 properties
->compatibleHandleTypes
= 0;
1363 properties
->externalSemaphoreFeatures
= 0;
1366 void WINAPI
wine_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDevice phys_dev
,
1367 const VkPhysicalDeviceExternalSemaphoreInfo
*semaphore_info
, VkExternalSemaphoreProperties
*properties
)
1369 TRACE("%p, %p, %p\n", phys_dev
, semaphore_info
, properties
);
1370 properties
->exportFromImportedHandleTypes
= 0;
1371 properties
->compatibleHandleTypes
= 0;
1372 properties
->externalSemaphoreFeatures
= 0;
1375 static uint64_t unwrap_object_handle(VkObjectType type
, uint64_t handle
)
1379 case VK_OBJECT_TYPE_DEVICE
:
1380 return (uint64_t) (uintptr_t) ((VkDevice
) (uintptr_t) handle
)->device
;
1381 case VK_OBJECT_TYPE_QUEUE
:
1382 return (uint64_t) (uintptr_t) ((VkQueue
) (uintptr_t) handle
)->queue
;
1383 case VK_OBJECT_TYPE_COMMAND_BUFFER
:
1384 return (uint64_t) (uintptr_t) ((VkCommandBuffer
) (uintptr_t) handle
)->command_buffer
;
1385 case VK_OBJECT_TYPE_COMMAND_POOL
:
1386 return (uint64_t) wine_cmd_pool_from_handle(handle
)->command_pool
;
1392 VkResult WINAPI
wine_vkSetPrivateDataEXT(VkDevice device
, VkObjectType object_type
, uint64_t object_handle
,
1393 VkPrivateDataSlotEXT private_data_slot
, uint64_t data
)
1395 TRACE("%p, %#x, 0x%s, 0x%s, 0x%s\n", device
, object_type
, wine_dbgstr_longlong(object_handle
),
1396 wine_dbgstr_longlong(private_data_slot
), wine_dbgstr_longlong(data
));
1398 object_handle
= unwrap_object_handle(object_type
, object_handle
);
1399 return device
->funcs
.p_vkSetPrivateDataEXT(device
->device
, object_type
, object_handle
, private_data_slot
, data
);
1402 void WINAPI
wine_vkGetPrivateDataEXT(VkDevice device
, VkObjectType object_type
, uint64_t object_handle
,
1403 VkPrivateDataSlotEXT private_data_slot
, uint64_t *data
)
1405 TRACE("%p, %#x, 0x%s, 0x%s, %p\n", device
, object_type
, wine_dbgstr_longlong(object_handle
),
1406 wine_dbgstr_longlong(private_data_slot
), data
);
1408 object_handle
= unwrap_object_handle(object_type
, object_handle
);
1409 device
->funcs
.p_vkGetPrivateDataEXT(device
->device
, object_type
, object_handle
, private_data_slot
, data
);
1412 BOOL WINAPI
DllMain(HINSTANCE hinst
, DWORD reason
, void *reserved
)
1414 TRACE("%p, %u, %p\n", hinst
, reason
, reserved
);
1418 case DLL_PROCESS_ATTACH
:
1420 DisableThreadLibraryCalls(hinst
);
1426 static const struct vulkan_func vk_global_dispatch_table
[] =
1428 /* These functions must call wine_vk_init_once() before accessing vk_funcs. */
1429 {"vkCreateInstance", &wine_vkCreateInstance
},
1430 {"vkEnumerateInstanceExtensionProperties", &wine_vkEnumerateInstanceExtensionProperties
},
1431 {"vkEnumerateInstanceLayerProperties", &wine_vkEnumerateInstanceLayerProperties
},
1432 {"vkEnumerateInstanceVersion", &wine_vkEnumerateInstanceVersion
},
1433 {"vkGetInstanceProcAddr", &wine_vkGetInstanceProcAddr
},
1436 static void *wine_vk_get_global_proc_addr(const char *name
)
1440 for (i
= 0; i
< ARRAY_SIZE(vk_global_dispatch_table
); i
++)
1442 if (strcmp(name
, vk_global_dispatch_table
[i
].name
) == 0)
1444 TRACE("Found name=%s in global table\n", debugstr_a(name
));
1445 return vk_global_dispatch_table
[i
].func
;
1452 * Wrapper around driver vkGetInstanceProcAddr implementation.
1453 * Allows winelib applications to access Vulkan functions with Wine
1454 * additions and native ABI.
1456 void *native_vkGetInstanceProcAddrWINE(VkInstance instance
, const char *name
)
1458 return vk_funcs
->p_vkGetInstanceProcAddr(instance
, name
);
1462 static const WCHAR winevulkan_json_resW
[] = {'w','i','n','e','v','u','l','k','a','n','_','j','s','o','n',0};
1463 static const WCHAR winevulkan_json_pathW
[] = {'\\','w','i','n','e','v','u','l','k','a','n','.','j','s','o','n',0};
1464 static const WCHAR vulkan_driversW
[] = {'S','o','f','t','w','a','r','e','\\','K','h','r','o','n','o','s','\\',
1465 'V','u','l','k','a','n','\\','D','r','i','v','e','r','s',0};
1467 HRESULT WINAPI
DllRegisterServer(void)
1469 WCHAR json_path
[MAX_PATH
];
1472 DWORD datalen
, written
, zero
= 0;
1476 /* Create the JSON manifest and registry key to register this ICD with the official Vulkan loader. */
1478 rsrc
= FindResourceW(hinstance
, winevulkan_json_resW
, (const WCHAR
*)RT_RCDATA
);
1479 data
= LockResource(LoadResource(hinstance
, rsrc
));
1480 datalen
= SizeofResource(hinstance
, rsrc
);
1482 GetSystemDirectoryW(json_path
, ARRAY_SIZE(json_path
));
1483 lstrcatW(json_path
, winevulkan_json_pathW
);
1484 file
= CreateFileW(json_path
, GENERIC_WRITE
, 0, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1485 if (file
== INVALID_HANDLE_VALUE
)
1487 ERR("Unable to create JSON manifest.\n");
1488 return E_UNEXPECTED
;
1490 WriteFile(file
, data
, datalen
, &written
, NULL
);
1493 if (!RegCreateKeyExW(HKEY_LOCAL_MACHINE
, vulkan_driversW
, 0, NULL
, 0, KEY_SET_VALUE
, NULL
, &key
, NULL
))
1495 RegSetValueExW(key
, json_path
, 0, REG_DWORD
, (const BYTE
*)&zero
, sizeof(zero
));
1501 HRESULT WINAPI
DllUnregisterServer(void)
1503 WCHAR json_path
[MAX_PATH
];
1506 /* Remove the JSON manifest and registry key */
1508 GetSystemDirectoryW(json_path
, ARRAY_SIZE(json_path
));
1509 lstrcatW(json_path
, winevulkan_json_pathW
);
1510 DeleteFileW(json_path
);
1512 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, vulkan_driversW
, 0, KEY_SET_VALUE
, &key
) == ERROR_SUCCESS
)
1514 RegDeleteValueW(key
, json_path
);