winex11: Implement vkGetPhysicalDeviceWin32PresentationSupportKHR.
[wine.git] / dlls / winex11.drv / vulkan.c
blobcdcf741957d5ed164481efdf4b548a3764435e13
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 #include "config.h"
21 #include "wine/port.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
28 #include "wine/debug.h"
29 #include "wine/heap.h"
30 #include "wine/library.h"
31 #include "x11drv.h"
33 /* We only want host compatible structures and don't need alignment. */
34 #define WINE_VK_ALIGN(x)
36 #include "wine/vulkan.h"
37 #include "wine/vulkan_driver.h"
39 #ifdef SONAME_LIBVULKAN
41 WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
43 #ifndef ARRAY_SIZE
44 #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
45 #endif
47 typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
48 #define VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR 1000004000
50 struct wine_vk_surface
52 Window window;
53 VkSurfaceKHR surface; /* native surface */
56 typedef struct VkXlibSurfaceCreateInfoKHR
58 VkStructureType sType;
59 const void *pNext;
60 VkXlibSurfaceCreateFlagsKHR flags;
61 Display *dpy;
62 Window window;
63 } VkXlibSurfaceCreateInfoKHR;
65 static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *);
66 static VkResult (*pvkCreateXlibSurfaceKHR)(VkInstance, const VkXlibSurfaceCreateInfoKHR *, const VkAllocationCallbacks *, VkSurfaceKHR *);
67 static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks *);
68 static void (*pvkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *);
69 static void * (*pvkGetDeviceProcAddr)(VkDevice, const char *);
70 static void * (*pvkGetInstanceProcAddr)(VkInstance, const char *);
71 static VkBool32 (*pvkGetPhysicalDeviceXlibPresentationSupportKHR)(VkPhysicalDevice, uint32_t, Display *, VisualID);
73 /* TODO: dynamically generate based on host driver capabilities. */
74 static const struct VkExtensionProperties winex11_vk_instance_extensions[] =
76 { "VK_KHR_surface", 1 },
77 { "VK_KHR_win32_surface", 1},
80 static BOOL wine_vk_init(void)
82 static BOOL init_done = FALSE;
83 static void *vulkan_handle;
85 if (init_done) return (vulkan_handle != NULL);
86 init_done = TRUE;
88 if (!(vulkan_handle = wine_dlopen(SONAME_LIBVULKAN, RTLD_NOW, NULL, 0))) return FALSE;
90 #define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(vulkan_handle, #f, NULL, 0)) == NULL) return FALSE;
91 LOAD_FUNCPTR(vkCreateInstance)
92 LOAD_FUNCPTR(vkCreateXlibSurfaceKHR)
93 LOAD_FUNCPTR(vkDestroyInstance)
94 LOAD_FUNCPTR(vkDestroySurfaceKHR)
95 LOAD_FUNCPTR(vkGetDeviceProcAddr)
96 LOAD_FUNCPTR(vkGetInstanceProcAddr)
97 LOAD_FUNCPTR(vkGetPhysicalDeviceXlibPresentationSupportKHR)
98 #undef LOAD_FUNCPTR
100 return TRUE;
103 /* Helper function for converting between win32 and X11 compatible VkInstanceCreateInfo.
104 * Caller is responsible for allocation and cleanup of 'dst'.
106 static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo *src,
107 VkInstanceCreateInfo *dst)
109 unsigned int i;
110 const char **enabled_extensions = NULL;
112 dst->sType = src->sType;
113 dst->flags = src->flags;
114 dst->pApplicationInfo = src->pApplicationInfo;
115 dst->pNext = src->pNext;
116 dst->enabledLayerCount = 0;
117 dst->ppEnabledLayerNames = NULL;
118 dst->enabledExtensionCount = 0;
119 dst->ppEnabledExtensionNames = NULL;
121 if (src->enabledExtensionCount > 0)
123 enabled_extensions = heap_calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames));
124 if (!enabled_extensions)
126 ERR("Failed to allocate memory for enabled extensions\n");
127 return VK_ERROR_OUT_OF_HOST_MEMORY;
130 for (i = 0; i < src->enabledExtensionCount; i++)
132 /* Substitute extension with X11 ones else copy. Long-term, when we
133 * support more extensions, we should store these in a list.
135 if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_win32_surface"))
137 enabled_extensions[i] = "VK_KHR_xlib_surface";
139 else
141 enabled_extensions[i] = src->ppEnabledExtensionNames[i];
144 dst->ppEnabledExtensionNames = enabled_extensions;
145 dst->enabledExtensionCount = src->enabledExtensionCount;
148 return VK_SUCCESS;
151 static void wine_vk_surface_destroy(VkInstance instance, struct wine_vk_surface *surface)
153 if (!surface)
154 return;
156 /* vkDestroySurfaceKHR must handle VK_NULL_HANDLE (0) for surface. */
157 pvkDestroySurfaceKHR(instance, surface->surface, NULL /* allocator */);
159 if (surface->window)
160 XDestroyWindow(gdi_display, surface->window);
162 heap_free(surface);
165 static VkResult X11DRV_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain,
166 uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *index)
168 FIXME("stub: %p, 0x%s, 0x%s, 0x%s, 0x%s, %p\n", device,
169 wine_dbgstr_longlong(swapchain), wine_dbgstr_longlong(timeout),
170 wine_dbgstr_longlong(semaphore), wine_dbgstr_longlong(fence), index);
172 return VK_ERROR_OUT_OF_HOST_MEMORY;
175 static VkResult X11DRV_vkCreateInstance(const VkInstanceCreateInfo *create_info,
176 const VkAllocationCallbacks *allocator, VkInstance *instance)
178 VkInstanceCreateInfo create_info_host;
179 VkResult res;
180 TRACE("create_info %p, allocator %p, instance %p\n", create_info, allocator, instance);
182 if (allocator)
183 FIXME("Support for allocation callbacks not implemented yet\n");
185 /* Perform a second pass on converting VkInstanceCreateInfo. Winevulkan
186 * performed a first pass in which it handles everything except for WSI
187 * functionality such as VK_KHR_win32_surface. Handle this now.
189 res = wine_vk_instance_convert_create_info(create_info, &create_info_host);
190 if (res != VK_SUCCESS)
192 ERR("Failed to convert instance create info, res=%d\n", res);
193 return res;
196 res = pvkCreateInstance(&create_info_host, NULL /* allocator */, instance);
198 heap_free((void *)create_info_host.ppEnabledExtensionNames);
199 return res;
202 static VkResult X11DRV_vkCreateSwapchainKHR(VkDevice device,
203 const VkSwapchainCreateInfoKHR *create_info,
204 const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain)
206 FIXME("stub: %p %p %p %p\n", device, create_info, allocator, swapchain);
207 return VK_ERROR_OUT_OF_HOST_MEMORY;
210 static VkResult X11DRV_vkCreateWin32SurfaceKHR(VkInstance instance,
211 const VkWin32SurfaceCreateInfoKHR *create_info,
212 const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface)
214 VkResult res;
215 VkXlibSurfaceCreateInfoKHR create_info_host;
216 struct wine_vk_surface *x11_surface;
218 TRACE("%p %p %p %p\n", instance, create_info, allocator, surface);
220 if (allocator)
221 FIXME("Support for allocation callbacks not implemented yet\n");
223 /* TODO: support child window rendering. */
224 if (GetAncestor(create_info->hwnd, GA_PARENT) != GetDesktopWindow())
226 FIXME("Application requires child window rendering, which is not implemented yet!\n");
227 return VK_ERROR_INCOMPATIBLE_DRIVER;
230 x11_surface = heap_alloc_zero(sizeof(*x11_surface));
231 if (!x11_surface)
232 return VK_ERROR_OUT_OF_HOST_MEMORY;
234 x11_surface->window = create_client_window(create_info->hwnd, &default_visual);
235 if (!x11_surface->window)
237 ERR("Failed to allocate client window for hwnd=%p\n", create_info->hwnd);
239 /* VK_KHR_win32_surface only allows out of host and device memory as errors. */
240 res = VK_ERROR_OUT_OF_HOST_MEMORY;
241 goto err;
244 create_info_host.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
245 create_info_host.pNext = NULL;
246 create_info_host.flags = 0; /* reserved */
247 create_info_host.dpy = gdi_display;
248 create_info_host.window = x11_surface->window;
250 res = pvkCreateXlibSurfaceKHR(instance, &create_info_host, NULL /* allocator */, &x11_surface->surface);
251 if (res != VK_SUCCESS)
253 ERR("Failed to create Xlib surface, res=%d\n", res);
254 goto err;
257 *surface = (uintptr_t)x11_surface;
259 TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*surface));
260 return VK_SUCCESS;
262 err:
263 wine_vk_surface_destroy(instance, x11_surface);
264 return res;
267 static void X11DRV_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *allocator)
269 TRACE("%p %p\n", instance, allocator);
271 if (allocator)
272 FIXME("Support for allocation callbacks not implemented yet\n");
274 pvkDestroyInstance(instance, NULL /* allocator */);
277 static void X11DRV_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface,
278 const VkAllocationCallbacks *allocator)
280 FIXME("stub: %p 0x%s %p\n", instance, wine_dbgstr_longlong(surface), allocator);
283 static void X11DRV_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain,
284 const VkAllocationCallbacks *allocator)
286 FIXME("stub: %p, 0x%s %p\n", device, wine_dbgstr_longlong(swapchain), allocator);
289 static VkResult X11DRV_vkEnumerateInstanceExtensionProperties(const char *layer_name,
290 uint32_t *count, VkExtensionProperties* properties)
292 VkResult res;
293 unsigned int i, num_copies;
295 TRACE("layer_name %p, count %p, properties %p\n", debugstr_a(layer_name), count, properties);
297 /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
298 if (layer_name)
300 ERR("Layer enumeration not supported from ICD.\n");
301 return VK_ERROR_LAYER_NOT_PRESENT;
304 if (!properties)
306 /* When properties is NULL, we need to return the number of extensions
307 * supported. For now report 0 until we add some e.g.
308 * VK_KHR_win32_surface. Long-term this needs to be an intersection
309 * between what the native library supports and what thunks we have.
311 *count = ARRAY_SIZE(winex11_vk_instance_extensions);
312 return VK_SUCCESS;
315 if (*count < ARRAY_SIZE(winex11_vk_instance_extensions))
317 /* Incomplete is a type of success used to signal the application
318 * that not all devices got copied.
320 num_copies = *count;
321 res = VK_INCOMPLETE;
323 else
325 num_copies = ARRAY_SIZE(winex11_vk_instance_extensions);
326 res = VK_SUCCESS;
329 for (i = 0; i < num_copies; i++)
331 memcpy(&properties[i], &winex11_vk_instance_extensions[i], sizeof(winex11_vk_instance_extensions[i]));
333 *count = num_copies;
335 TRACE("Result %d, extensions copied %u\n", res, num_copies);
336 return res;
339 static void * X11DRV_vkGetDeviceProcAddr(VkDevice device, const char *name)
341 TRACE("%p, %s\n", device, debugstr_a(name));
342 return pvkGetDeviceProcAddr(device, name);
345 static void * X11DRV_vkGetInstanceProcAddr(VkInstance instance, const char *name)
347 TRACE("%p, %s\n", instance, debugstr_a(name));
348 return pvkGetInstanceProcAddr(instance, name);
351 static VkResult X11DRV_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice phys_dev,
352 VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *capabilities)
354 FIXME("stub: %p, 0x%s, %p\n", phys_dev, wine_dbgstr_longlong(surface), capabilities);
355 return VK_ERROR_OUT_OF_HOST_MEMORY;
358 static VkResult X11DRV_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice phys_dev,
359 VkSurfaceKHR surface, uint32_t *count, VkSurfaceFormatKHR *formats)
361 FIXME("stub: %p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), count, formats);
362 return VK_ERROR_OUT_OF_HOST_MEMORY;
365 static VkResult X11DRV_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice phys_dev,
366 VkSurfaceKHR surface, uint32_t *count, VkPresentModeKHR *modes)
368 FIXME("stub: %p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), count, modes);
369 return VK_ERROR_OUT_OF_HOST_MEMORY;
372 static VkResult X11DRV_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice phys_dev,
373 uint32_t index, VkSurfaceKHR surface, VkBool32 *supported)
375 FIXME("stub: %p, %u, 0x%s, %p\n", phys_dev, index, wine_dbgstr_longlong(surface), supported);
376 return VK_ERROR_OUT_OF_HOST_MEMORY;
379 static VkBool32 X11DRV_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice phys_dev,
380 uint32_t index)
382 TRACE("%p %u\n", phys_dev, index);
384 return pvkGetPhysicalDeviceXlibPresentationSupportKHR(phys_dev, index, gdi_display,
385 default_visual.visual->visualid);
388 static VkResult X11DRV_vkGetSwapchainImagesKHR(VkDevice device,
389 VkSwapchainKHR swapchain, uint32_t *count, VkImage *images)
391 FIXME("stub: %p, 0x%s %p %p\n", device, wine_dbgstr_longlong(swapchain), count, images);
392 return VK_ERROR_OUT_OF_HOST_MEMORY;
395 static VkResult X11DRV_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *present_info)
397 FIXME("stub: %p, %p\n", queue, present_info);
398 return VK_ERROR_OUT_OF_HOST_MEMORY;
402 static const struct vulkan_funcs vulkan_funcs =
404 X11DRV_vkAcquireNextImageKHR,
405 X11DRV_vkCreateInstance,
406 X11DRV_vkCreateSwapchainKHR,
407 X11DRV_vkCreateWin32SurfaceKHR,
408 X11DRV_vkDestroyInstance,
409 X11DRV_vkDestroySurfaceKHR,
410 X11DRV_vkDestroySwapchainKHR,
411 X11DRV_vkEnumerateInstanceExtensionProperties,
412 X11DRV_vkGetDeviceProcAddr,
413 X11DRV_vkGetInstanceProcAddr,
414 X11DRV_vkGetPhysicalDeviceSurfaceCapabilitiesKHR,
415 X11DRV_vkGetPhysicalDeviceSurfaceFormatsKHR,
416 X11DRV_vkGetPhysicalDeviceSurfacePresentModesKHR,
417 X11DRV_vkGetPhysicalDeviceSurfaceSupportKHR,
418 X11DRV_vkGetPhysicalDeviceWin32PresentationSupportKHR,
419 X11DRV_vkGetSwapchainImagesKHR,
420 X11DRV_vkQueuePresentKHR
423 const struct vulkan_funcs *get_vulkan_driver(UINT version)
425 if (version != WINE_VULKAN_DRIVER_VERSION)
427 ERR("version mismatch, vulkan wants %u but driver has %u\n", version, WINE_VULKAN_DRIVER_VERSION);
428 return NULL;
431 if (wine_vk_init())
432 return &vulkan_funcs;
434 return NULL;
437 #else /* No vulkan */
439 const struct vulkan_funcs *get_vulkan_driver(UINT version)
441 return NULL;
444 #endif /* SONAME_LIBVULKAN */