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
21 #include "wine/port.h"
28 #include "wine/debug.h"
29 #include "wine/heap.h"
30 #include "wine/library.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
);
44 #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
47 typedef VkFlags VkXlibSurfaceCreateFlagsKHR
;
48 #define VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR 1000004000
50 struct wine_vk_surface
53 VkSurfaceKHR surface
; /* native surface */
56 typedef struct VkXlibSurfaceCreateInfoKHR
58 VkStructureType sType
;
60 VkXlibSurfaceCreateFlagsKHR flags
;
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
);
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
)
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
)
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";
141 enabled_extensions
[i
] = src
->ppEnabledExtensionNames
[i
];
144 dst
->ppEnabledExtensionNames
= enabled_extensions
;
145 dst
->enabledExtensionCount
= src
->enabledExtensionCount
;
151 static void wine_vk_surface_destroy(VkInstance instance
, struct wine_vk_surface
*surface
)
156 /* vkDestroySurfaceKHR must handle VK_NULL_HANDLE (0) for surface. */
157 pvkDestroySurfaceKHR(instance
, surface
->surface
, NULL
/* allocator */);
160 XDestroyWindow(gdi_display
, surface
->window
);
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
;
180 TRACE("create_info %p, allocator %p, instance %p\n", create_info
, allocator
, instance
);
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
);
196 res
= pvkCreateInstance(&create_info_host
, NULL
/* allocator */, instance
);
198 heap_free((void *)create_info_host
.ppEnabledExtensionNames
);
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
)
215 VkXlibSurfaceCreateInfoKHR create_info_host
;
216 struct wine_vk_surface
*x11_surface
;
218 TRACE("%p %p %p %p\n", instance
, create_info
, allocator
, surface
);
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
));
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
;
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
);
257 *surface
= (uintptr_t)x11_surface
;
259 TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*surface
));
263 wine_vk_surface_destroy(instance
, x11_surface
);
267 static void X11DRV_vkDestroyInstance(VkInstance instance
, const VkAllocationCallbacks
*allocator
)
269 TRACE("%p %p\n", instance
, 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
)
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. */
300 ERR("Layer enumeration not supported from ICD.\n");
301 return VK_ERROR_LAYER_NOT_PRESENT
;
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
);
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.
325 num_copies
= ARRAY_SIZE(winex11_vk_instance_extensions
);
329 for (i
= 0; i
< num_copies
; i
++)
331 memcpy(&properties
[i
], &winex11_vk_instance_extensions
[i
], sizeof(winex11_vk_instance_extensions
[i
]));
335 TRACE("Result %d, extensions copied %u\n", res
, num_copies
);
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
,
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
);
432 return &vulkan_funcs
;
437 #else /* No vulkan */
439 const struct vulkan_funcs
*get_vulkan_driver(UINT version
)
444 #endif /* SONAME_LIBVULKAN */