cmd: DIR command outputs free space for the path.
[wine.git] / dlls / winex11.drv / vulkan.c
blob101504a78870b87ebd686940fb9c294aef74e4ef
1 /* X11DRV Vulkan implementation
3 * Copyright 2017 Roderick Colenbrander
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 /* NOTE: If making changes here, consider whether they should be reflected in
21 * the other drivers. */
23 #if 0
24 #pragma makedep unix
25 #endif
27 #include "config.h"
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <dlfcn.h>
33 #include "windef.h"
34 #include "winbase.h"
36 #include "wine/debug.h"
37 #include "x11drv.h"
39 #define VK_NO_PROTOTYPES
40 #define WINE_VK_HOST
42 #include "wine/vulkan.h"
43 #include "wine/vulkan_driver.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
47 #ifdef SONAME_LIBVULKAN
48 WINE_DECLARE_DEBUG_CHANNEL(fps);
50 static pthread_mutex_t vulkan_mutex;
52 static XContext vulkan_hwnd_context;
54 #define VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR 1000004000
56 static struct list surface_list = LIST_INIT( surface_list );
58 struct wine_vk_surface
60 LONG ref;
61 struct list entry;
62 Window window;
63 VkSurfaceKHR surface; /* native surface */
64 HWND hwnd;
65 DWORD hwnd_thread_id;
68 typedef struct VkXlibSurfaceCreateInfoKHR
70 VkStructureType sType;
71 const void *pNext;
72 VkXlibSurfaceCreateFlagsKHR flags;
73 Display *dpy;
74 Window window;
75 } VkXlibSurfaceCreateInfoKHR;
77 static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *);
78 static VkResult (*pvkCreateSwapchainKHR)(VkDevice, const VkSwapchainCreateInfoKHR *, const VkAllocationCallbacks *, VkSwapchainKHR *);
79 static VkResult (*pvkCreateXlibSurfaceKHR)(VkInstance, const VkXlibSurfaceCreateInfoKHR *, const VkAllocationCallbacks *, VkSurfaceKHR *);
80 static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks *);
81 static void (*pvkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *);
82 static void (*pvkDestroySwapchainKHR)(VkDevice, VkSwapchainKHR, const VkAllocationCallbacks *);
83 static VkResult (*pvkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *);
84 static VkResult (*pvkGetDeviceGroupSurfacePresentModesKHR)(VkDevice, VkSurfaceKHR, VkDeviceGroupPresentModeFlagsKHR *);
85 static void * (*pvkGetDeviceProcAddr)(VkDevice, const char *);
86 static void * (*pvkGetInstanceProcAddr)(VkInstance, const char *);
87 static VkResult (*pvkGetPhysicalDevicePresentRectanglesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkRect2D *);
88 static VkResult (*pvkGetPhysicalDeviceSurfaceCapabilities2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, VkSurfaceCapabilities2KHR *);
89 static VkResult (*pvkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR *);
90 static VkResult (*pvkGetPhysicalDeviceSurfaceFormats2KHR)(VkPhysicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *, uint32_t *, VkSurfaceFormat2KHR *);
91 static VkResult (*pvkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkSurfaceFormatKHR *);
92 static VkResult (*pvkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkPresentModeKHR *);
93 static VkResult (*pvkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32 *);
94 static VkBool32 (*pvkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice, uint32_t, Display *, VisualID);
95 static VkResult (*pvkGetSwapchainImagesKHR)(VkDevice, VkSwapchainKHR, uint32_t *, VkImage *);
96 static VkResult (*pvkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *);
98 static void *X11DRV_get_vk_device_proc_addr(const char *name);
99 static void *X11DRV_get_vk_instance_proc_addr(VkInstance instance, const char *name);
101 static inline struct wine_vk_surface *surface_from_handle(VkSurfaceKHR handle)
103 return (struct wine_vk_surface *)(uintptr_t)handle;
106 static void *vulkan_handle;
108 static void wine_vk_init(void)
110 init_recursive_mutex(&vulkan_mutex);
112 if (!(vulkan_handle = dlopen(SONAME_LIBVULKAN, RTLD_NOW)))
114 ERR("Failed to load %s.\n", SONAME_LIBVULKAN);
115 return;
118 #define LOAD_FUNCPTR(f) if (!(p##f = dlsym(vulkan_handle, #f))) goto fail
119 #define LOAD_OPTIONAL_FUNCPTR(f) p##f = dlsym(vulkan_handle, #f)
120 LOAD_FUNCPTR(vkCreateInstance);
121 LOAD_FUNCPTR(vkCreateSwapchainKHR);
122 LOAD_FUNCPTR(vkCreateXlibSurfaceKHR);
123 LOAD_FUNCPTR(vkDestroyInstance);
124 LOAD_FUNCPTR(vkDestroySurfaceKHR);
125 LOAD_FUNCPTR(vkDestroySwapchainKHR);
126 LOAD_FUNCPTR(vkEnumerateInstanceExtensionProperties);
127 LOAD_FUNCPTR(vkGetDeviceProcAddr);
128 LOAD_FUNCPTR(vkGetInstanceProcAddr);
129 LOAD_OPTIONAL_FUNCPTR(vkGetPhysicalDeviceSurfaceCapabilities2KHR);
130 LOAD_FUNCPTR(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
131 LOAD_OPTIONAL_FUNCPTR(vkGetPhysicalDeviceSurfaceFormats2KHR);
132 LOAD_FUNCPTR(vkGetPhysicalDeviceSurfaceFormatsKHR);
133 LOAD_FUNCPTR(vkGetPhysicalDeviceSurfacePresentModesKHR);
134 LOAD_FUNCPTR(vkGetPhysicalDeviceSurfaceSupportKHR);
135 LOAD_FUNCPTR(vkGetPhysicalDeviceXlibPresentationSupportKHR);
136 LOAD_FUNCPTR(vkGetSwapchainImagesKHR);
137 LOAD_FUNCPTR(vkQueuePresentKHR);
138 LOAD_OPTIONAL_FUNCPTR(vkGetDeviceGroupSurfacePresentModesKHR);
139 LOAD_OPTIONAL_FUNCPTR(vkGetPhysicalDevicePresentRectanglesKHR);
140 #undef LOAD_FUNCPTR
141 #undef LOAD_OPTIONAL_FUNCPTR
143 vulkan_hwnd_context = XUniqueContext();
144 return;
146 fail:
147 dlclose(vulkan_handle);
148 vulkan_handle = NULL;
151 /* Helper function for converting between win32 and X11 compatible VkInstanceCreateInfo.
152 * Caller is responsible for allocation and cleanup of 'dst'.
154 static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo *src,
155 VkInstanceCreateInfo *dst)
157 unsigned int i;
158 const char **enabled_extensions = NULL;
160 dst->sType = src->sType;
161 dst->flags = src->flags;
162 dst->pApplicationInfo = src->pApplicationInfo;
163 dst->pNext = src->pNext;
164 dst->enabledLayerCount = 0;
165 dst->ppEnabledLayerNames = NULL;
166 dst->enabledExtensionCount = 0;
167 dst->ppEnabledExtensionNames = NULL;
169 if (src->enabledExtensionCount > 0)
171 enabled_extensions = calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames));
172 if (!enabled_extensions)
174 ERR("Failed to allocate memory for enabled extensions\n");
175 return VK_ERROR_OUT_OF_HOST_MEMORY;
178 for (i = 0; i < src->enabledExtensionCount; i++)
180 /* Substitute extension with X11 ones else copy. Long-term, when we
181 * support more extensions, we should store these in a list.
183 if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_win32_surface"))
185 enabled_extensions[i] = "VK_KHR_xlib_surface";
187 else
189 enabled_extensions[i] = src->ppEnabledExtensionNames[i];
192 dst->ppEnabledExtensionNames = enabled_extensions;
193 dst->enabledExtensionCount = src->enabledExtensionCount;
196 return VK_SUCCESS;
199 static struct wine_vk_surface *wine_vk_surface_grab(struct wine_vk_surface *surface)
201 InterlockedIncrement(&surface->ref);
202 return surface;
205 static void wine_vk_surface_release(struct wine_vk_surface *surface)
207 if (InterlockedDecrement(&surface->ref))
208 return;
210 if (surface->entry.next)
212 pthread_mutex_lock(&vulkan_mutex);
213 list_remove(&surface->entry);
214 pthread_mutex_unlock(&vulkan_mutex);
217 if (surface->window)
218 XDestroyWindow(gdi_display, surface->window);
220 free(surface);
223 void wine_vk_surface_destroy(HWND hwnd)
225 struct wine_vk_surface *surface;
226 pthread_mutex_lock(&vulkan_mutex);
227 if (!XFindContext(gdi_display, (XID)hwnd, vulkan_hwnd_context, (char **)&surface))
229 surface->hwnd_thread_id = 0;
230 surface->hwnd = NULL;
231 wine_vk_surface_release(surface);
233 XDeleteContext(gdi_display, (XID)hwnd, vulkan_hwnd_context);
234 pthread_mutex_unlock(&vulkan_mutex);
237 void vulkan_thread_detach(void)
239 struct wine_vk_surface *surface, *next;
240 DWORD thread_id = GetCurrentThreadId();
242 pthread_mutex_lock(&vulkan_mutex);
243 LIST_FOR_EACH_ENTRY_SAFE(surface, next, &surface_list, struct wine_vk_surface, entry)
245 if (surface->hwnd_thread_id != thread_id)
246 continue;
248 TRACE("Detaching surface %p, hwnd %p.\n", surface, surface->hwnd);
249 XReparentWindow(gdi_display, surface->window, get_dummy_parent(), 0, 0);
250 XSync(gdi_display, False);
251 wine_vk_surface_destroy(surface->hwnd);
253 pthread_mutex_unlock(&vulkan_mutex);
256 static VkResult X11DRV_vkCreateInstance(const VkInstanceCreateInfo *create_info,
257 const VkAllocationCallbacks *allocator, VkInstance *instance)
259 VkInstanceCreateInfo create_info_host;
260 VkResult res;
261 TRACE("create_info %p, allocator %p, instance %p\n", create_info, allocator, instance);
263 if (allocator)
264 FIXME("Support for allocation callbacks not implemented yet\n");
266 /* Perform a second pass on converting VkInstanceCreateInfo. Winevulkan
267 * performed a first pass in which it handles everything except for WSI
268 * functionality such as VK_KHR_win32_surface. Handle this now.
270 res = wine_vk_instance_convert_create_info(create_info, &create_info_host);
271 if (res != VK_SUCCESS)
273 ERR("Failed to convert instance create info, res=%d\n", res);
274 return res;
277 res = pvkCreateInstance(&create_info_host, NULL /* allocator */, instance);
279 free((void *)create_info_host.ppEnabledExtensionNames);
280 return res;
283 static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device,
284 const VkSwapchainCreateInfoKHR *create_info,
285 const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain)
287 struct wine_vk_surface *x11_surface = surface_from_handle(create_info->surface);
288 VkSwapchainCreateInfoKHR create_info_host;
289 TRACE("%p %p %p %p\n", device, create_info, allocator, swapchain);
291 if (allocator)
292 FIXME("Support for allocation callbacks not implemented yet\n");
294 if (!x11_surface->hwnd)
295 return VK_ERROR_SURFACE_LOST_KHR;
297 create_info_host = *create_info;
298 create_info_host.surface = x11_surface->surface;
300 return pvkCreateSwapchainKHR(device, &create_info_host, NULL /* allocator */, swapchain);
303 static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance,
304 const VkWin32SurfaceCreateInfoKHR *create_info,
305 const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface)
307 VkResult res;
308 VkXlibSurfaceCreateInfoKHR create_info_host;
309 struct wine_vk_surface *x11_surface;
311 TRACE("%p %p %p %p\n", instance, create_info, allocator, surface);
313 if (allocator)
314 FIXME("Support for allocation callbacks not implemented yet\n");
316 /* TODO: support child window rendering. */
317 if (create_info->hwnd && NtUserGetAncestor(create_info->hwnd, GA_PARENT) != NtUserGetDesktopWindow())
319 FIXME("Application requires child window rendering, which is not implemented yet!\n");
320 return VK_ERROR_INCOMPATIBLE_DRIVER;
323 x11_surface = calloc(1, sizeof(*x11_surface));
324 if (!x11_surface)
325 return VK_ERROR_OUT_OF_HOST_MEMORY;
327 x11_surface->ref = 1;
328 x11_surface->hwnd = create_info->hwnd;
329 if (x11_surface->hwnd)
331 x11_surface->window = create_client_window(create_info->hwnd, &default_visual);
332 x11_surface->hwnd_thread_id = NtUserGetWindowThread(x11_surface->hwnd, NULL);
334 else
336 x11_surface->window = create_dummy_client_window();
339 if (!x11_surface->window)
341 ERR("Failed to allocate client window for hwnd=%p\n", create_info->hwnd);
343 /* VK_KHR_win32_surface only allows out of host and device memory as errors. */
344 res = VK_ERROR_OUT_OF_HOST_MEMORY;
345 goto err;
348 create_info_host.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
349 create_info_host.pNext = NULL;
350 create_info_host.flags = 0; /* reserved */
351 create_info_host.dpy = gdi_display;
352 create_info_host.window = x11_surface->window;
354 res = pvkCreateXlibSurfaceKHR(instance, &create_info_host, NULL /* allocator */, &x11_surface->surface);
355 if (res != VK_SUCCESS)
357 ERR("Failed to create Xlib surface, res=%d\n", res);
358 goto err;
361 pthread_mutex_lock(&vulkan_mutex);
362 if (x11_surface->hwnd)
364 wine_vk_surface_destroy( x11_surface->hwnd );
365 XSaveContext(gdi_display, (XID)create_info->hwnd, vulkan_hwnd_context, (char *)wine_vk_surface_grab(x11_surface));
367 list_add_tail(&surface_list, &x11_surface->entry);
368 pthread_mutex_unlock(&vulkan_mutex);
370 *surface = (uintptr_t)x11_surface;
372 TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*surface));
373 return VK_SUCCESS;
375 err:
376 wine_vk_surface_release(x11_surface);
377 return res;
380 static void X11DRV_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *allocator)
382 TRACE("%p %p\n", instance, allocator);
384 if (allocator)
385 FIXME("Support for allocation callbacks not implemented yet\n");
387 pvkDestroyInstance(instance, NULL /* allocator */);
390 static void X11DRV_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface,
391 const VkAllocationCallbacks *allocator)
393 struct wine_vk_surface *x11_surface = surface_from_handle(surface);
395 TRACE("%p 0x%s %p\n", instance, wine_dbgstr_longlong(surface), allocator);
397 if (allocator)
398 FIXME("Support for allocation callbacks not implemented yet\n");
400 /* vkDestroySurfaceKHR must handle VK_NULL_HANDLE (0) for surface. */
401 if (x11_surface)
403 pvkDestroySurfaceKHR(instance, x11_surface->surface, NULL /* allocator */);
405 wine_vk_surface_release(x11_surface);
409 static void X11DRV_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain,
410 const VkAllocationCallbacks *allocator)
412 TRACE("%p, 0x%s %p\n", device, wine_dbgstr_longlong(swapchain), allocator);
414 if (allocator)
415 FIXME("Support for allocation callbacks not implemented yet\n");
417 pvkDestroySwapchainKHR(device, swapchain, NULL /* allocator */);
420 static VkResult X11DRV_vkEnumerateInstanceExtensionProperties(const char *layer_name,
421 uint32_t *count, VkExtensionProperties* properties)
423 unsigned int i;
424 VkResult res;
426 TRACE("layer_name %s, count %p, properties %p\n", debugstr_a(layer_name), count, properties);
428 /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
429 if (layer_name)
431 ERR("Layer enumeration not supported from ICD.\n");
432 return VK_ERROR_LAYER_NOT_PRESENT;
435 /* We will return the same number of instance extensions reported by the host back to
436 * winevulkan. Along the way we may replace xlib extensions with their win32 equivalents.
437 * Winevulkan will perform more detailed filtering as it knows whether it has thunks
438 * for a particular extension.
440 res = pvkEnumerateInstanceExtensionProperties(layer_name, count, properties);
441 if (!properties || res < 0)
442 return res;
444 for (i = 0; i < *count; i++)
446 /* For now the only x11 extension we need to fixup. Long-term we may need an array. */
447 if (!strcmp(properties[i].extensionName, "VK_KHR_xlib_surface"))
449 TRACE("Substituting VK_KHR_xlib_surface for VK_KHR_win32_surface\n");
451 snprintf(properties[i].extensionName, sizeof(properties[i].extensionName),
452 VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
453 properties[i].specVersion = VK_KHR_WIN32_SURFACE_SPEC_VERSION;
457 TRACE("Returning %u extensions.\n", *count);
458 return res;
461 static VkResult X11DRV_vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device,
462 VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR *flags)
464 struct wine_vk_surface *x11_surface = surface_from_handle(surface);
466 TRACE("%p, 0x%s, %p\n", device, wine_dbgstr_longlong(surface), flags);
468 return pvkGetDeviceGroupSurfacePresentModesKHR(device, x11_surface->surface, flags);
471 static const char *wine_vk_native_fn_name(const char *name)
473 if (!strcmp(name, "vkCreateWin32SurfaceKHR"))
474 return "vkCreateXlibSurfaceKHR";
475 if (!strcmp(name, "vkGetPhysicalDeviceWin32PresentationSupportKHR"))
476 return "vkGetPhysicalDeviceXlibPresentationSupportKHR";
478 return name;
481 static void *X11DRV_vkGetDeviceProcAddr(VkDevice device, const char *name)
483 void *proc_addr;
485 TRACE("%p, %s\n", device, debugstr_a(name));
487 if (!pvkGetDeviceProcAddr(device, wine_vk_native_fn_name(name)))
488 return NULL;
490 if ((proc_addr = X11DRV_get_vk_device_proc_addr(name)))
491 return proc_addr;
493 return pvkGetDeviceProcAddr(device, name);
496 static void *X11DRV_vkGetInstanceProcAddr(VkInstance instance, const char *name)
498 void *proc_addr;
500 TRACE("%p, %s\n", instance, debugstr_a(name));
502 if (!pvkGetInstanceProcAddr(instance, wine_vk_native_fn_name(name)))
503 return NULL;
505 if ((proc_addr = X11DRV_get_vk_instance_proc_addr(instance, name)))
506 return proc_addr;
508 return pvkGetInstanceProcAddr(instance, name);
511 static VkResult X11DRV_vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice phys_dev,
512 VkSurfaceKHR surface, uint32_t *count, VkRect2D *rects)
514 struct wine_vk_surface *x11_surface = surface_from_handle(surface);
516 TRACE("%p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), count, rects);
518 if (!x11_surface->hwnd)
520 if (rects)
521 return VK_ERROR_SURFACE_LOST_KHR;
523 *count = 1;
524 return VK_SUCCESS;
527 return pvkGetPhysicalDevicePresentRectanglesKHR(phys_dev, x11_surface->surface, count, rects);
530 static VkResult X11DRV_vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice phys_dev,
531 const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, VkSurfaceCapabilities2KHR *capabilities)
533 VkPhysicalDeviceSurfaceInfo2KHR surface_info_host;
534 TRACE("%p, %p, %p\n", phys_dev, surface_info, capabilities);
536 surface_info_host = *surface_info;
537 surface_info_host.surface = surface_from_handle(surface_info->surface)->surface;
539 if (pvkGetPhysicalDeviceSurfaceCapabilities2KHR)
540 return pvkGetPhysicalDeviceSurfaceCapabilities2KHR(phys_dev, &surface_info_host, capabilities);
542 /* Until the loader version exporting this function is common, emulate it using the older non-2 version. */
543 if (surface_info->pNext || capabilities->pNext)
544 FIXME("Emulating vkGetPhysicalDeviceSurfaceCapabilities2KHR with vkGetPhysicalDeviceSurfaceCapabilitiesKHR, pNext is ignored.\n");
546 return pvkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev, surface_info_host.surface, &capabilities->surfaceCapabilities);
549 static VkResult X11DRV_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice phys_dev,
550 VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *capabilities)
552 struct wine_vk_surface *x11_surface = surface_from_handle(surface);
554 TRACE("%p, 0x%s, %p\n", phys_dev, wine_dbgstr_longlong(surface), capabilities);
556 if (!x11_surface->hwnd)
557 return VK_ERROR_SURFACE_LOST_KHR;
559 return pvkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev, x11_surface->surface, capabilities);
562 static VkResult X11DRV_vkGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice phys_dev,
563 const VkPhysicalDeviceSurfaceInfo2KHR *surface_info, uint32_t *count, VkSurfaceFormat2KHR *formats)
565 VkPhysicalDeviceSurfaceInfo2KHR surface_info_host = *surface_info;
566 VkSurfaceFormatKHR *formats_host;
567 uint32_t i;
568 VkResult result;
569 TRACE("%p, %p, %p, %p\n", phys_dev, surface_info, count, formats);
571 surface_info_host = *surface_info;
572 surface_info_host.surface = surface_from_handle(surface_info->surface)->surface;
574 if (pvkGetPhysicalDeviceSurfaceFormats2KHR)
575 return pvkGetPhysicalDeviceSurfaceFormats2KHR(phys_dev, &surface_info_host, count, formats);
577 /* Until the loader version exporting this function is common, emulate it using the older non-2 version. */
578 if (surface_info->pNext)
579 FIXME("Emulating vkGetPhysicalDeviceSurfaceFormats2KHR with vkGetPhysicalDeviceSurfaceFormatsKHR, pNext is ignored.\n");
581 if (!formats)
582 return pvkGetPhysicalDeviceSurfaceFormatsKHR(phys_dev, surface_info_host.surface, count, NULL);
584 formats_host = calloc(*count, sizeof(*formats_host));
585 if (!formats_host) return VK_ERROR_OUT_OF_HOST_MEMORY;
586 result = pvkGetPhysicalDeviceSurfaceFormatsKHR(phys_dev, surface_info_host.surface, count, formats_host);
587 if (result == VK_SUCCESS || result == VK_INCOMPLETE)
589 for (i = 0; i < *count; i++)
590 formats[i].surfaceFormat = formats_host[i];
593 free(formats_host);
594 return result;
597 static VkResult X11DRV_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice phys_dev,
598 VkSurfaceKHR surface, uint32_t *count, VkSurfaceFormatKHR *formats)
600 struct wine_vk_surface *x11_surface = surface_from_handle(surface);
602 TRACE("%p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), count, formats);
604 return pvkGetPhysicalDeviceSurfaceFormatsKHR(phys_dev, x11_surface->surface, count, formats);
607 static VkResult X11DRV_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice phys_dev,
608 VkSurfaceKHR surface, uint32_t *count, VkPresentModeKHR *modes)
610 struct wine_vk_surface *x11_surface = surface_from_handle(surface);
612 TRACE("%p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), count, modes);
614 return pvkGetPhysicalDeviceSurfacePresentModesKHR(phys_dev, x11_surface->surface, count, modes);
617 static VkResult X11DRV_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice phys_dev,
618 uint32_t index, VkSurfaceKHR surface, VkBool32 *supported)
620 struct wine_vk_surface *x11_surface = surface_from_handle(surface);
622 TRACE("%p, %u, 0x%s, %p\n", phys_dev, index, wine_dbgstr_longlong(surface), supported);
624 return pvkGetPhysicalDeviceSurfaceSupportKHR(phys_dev, index, x11_surface->surface, supported);
627 static VkBool32 X11DRV_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice phys_dev,
628 uint32_t index)
630 TRACE("%p %u\n", phys_dev, index);
632 return pvkGetPhysicalDeviceXlibPresentationSupportKHR(phys_dev, index, gdi_display,
633 default_visual.visual->visualid);
636 static VkResult X11DRV_vkGetSwapchainImagesKHR(VkDevice device,
637 VkSwapchainKHR swapchain, uint32_t *count, VkImage *images)
639 TRACE("%p, 0x%s %p %p\n", device, wine_dbgstr_longlong(swapchain), count, images);
640 return pvkGetSwapchainImagesKHR(device, swapchain, count, images);
643 static VkResult X11DRV_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *present_info)
645 VkResult res;
647 TRACE("%p, %p\n", queue, present_info);
649 res = pvkQueuePresentKHR(queue, present_info);
651 if (TRACE_ON(fps))
653 static unsigned long frames, frames_total;
654 static long prev_time, start_time;
655 DWORD time;
657 time = NtGetTickCount();
658 frames++;
659 frames_total++;
660 if (time - prev_time > 1500)
662 TRACE_(fps)("%p @ approx %.2ffps, total %.2ffps\n",
663 queue, 1000.0 * frames / (time - prev_time),
664 1000.0 * frames_total / (time - start_time));
665 prev_time = time;
666 frames = 0;
667 if (!start_time)
668 start_time = time;
672 return res;
675 static VkSurfaceKHR X11DRV_wine_get_native_surface(VkSurfaceKHR surface)
677 struct wine_vk_surface *x11_surface = surface_from_handle(surface);
679 TRACE("0x%s\n", wine_dbgstr_longlong(surface));
681 return x11_surface->surface;
684 static const struct vulkan_funcs vulkan_funcs =
686 X11DRV_vkCreateInstance,
687 X11DRV_vkCreateSwapchainKHR,
688 X11DRV_vkCreateWin32SurfaceKHR,
689 X11DRV_vkDestroyInstance,
690 X11DRV_vkDestroySurfaceKHR,
691 X11DRV_vkDestroySwapchainKHR,
692 X11DRV_vkEnumerateInstanceExtensionProperties,
693 X11DRV_vkGetDeviceGroupSurfacePresentModesKHR,
694 X11DRV_vkGetDeviceProcAddr,
695 X11DRV_vkGetInstanceProcAddr,
696 X11DRV_vkGetPhysicalDevicePresentRectanglesKHR,
697 X11DRV_vkGetPhysicalDeviceSurfaceCapabilities2KHR,
698 X11DRV_vkGetPhysicalDeviceSurfaceCapabilitiesKHR,
699 X11DRV_vkGetPhysicalDeviceSurfaceFormats2KHR,
700 X11DRV_vkGetPhysicalDeviceSurfaceFormatsKHR,
701 X11DRV_vkGetPhysicalDeviceSurfacePresentModesKHR,
702 X11DRV_vkGetPhysicalDeviceSurfaceSupportKHR,
703 X11DRV_vkGetPhysicalDeviceWin32PresentationSupportKHR,
704 X11DRV_vkGetSwapchainImagesKHR,
705 X11DRV_vkQueuePresentKHR,
707 X11DRV_wine_get_native_surface,
710 static void *X11DRV_get_vk_device_proc_addr(const char *name)
712 return get_vulkan_driver_device_proc_addr(&vulkan_funcs, name);
715 static void *X11DRV_get_vk_instance_proc_addr(VkInstance instance, const char *name)
717 return get_vulkan_driver_instance_proc_addr(&vulkan_funcs, instance, name);
720 const struct vulkan_funcs *get_vulkan_driver(UINT version)
722 static pthread_once_t init_once = PTHREAD_ONCE_INIT;
724 if (version != WINE_VULKAN_DRIVER_VERSION)
726 ERR("version mismatch, vulkan wants %u but driver has %u\n", version, WINE_VULKAN_DRIVER_VERSION);
727 return NULL;
730 pthread_once(&init_once, wine_vk_init);
731 if (vulkan_handle)
732 return &vulkan_funcs;
734 return NULL;
737 #else /* No vulkan */
739 const struct vulkan_funcs *get_vulkan_driver(UINT version)
741 ERR("Wine was built without Vulkan support.\n");
742 return NULL;
745 void wine_vk_surface_destroy(HWND hwnd)
749 void vulkan_thread_detach(void)
753 #endif /* SONAME_LIBVULKAN */