quartz/tests: Make testpin_{AddRef,Release}() static.
[wine.git] / dlls / winemac.drv / vulkan.c
blobd49c9a1ab2fc9750c70c9f1a57b1c6512bb21cff
1 /* Mac Driver Vulkan implementation
3 * Copyright 2017 Roderick Colenbrander
4 * Copyright 2018 Andrew Eikum for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 /* NOTE: If making changes here, consider whether they should be reflected in
22 * the other drivers. */
24 #include "config.h"
25 #include "wine/port.h"
26 #include "macdrv.h"
28 #include <stdarg.h>
29 #include <stdio.h>
31 #include "windef.h"
32 #include "winbase.h"
34 #include "wine/debug.h"
35 #include "wine/heap.h"
36 #include "wine/library.h"
38 #define VK_NO_PROTOTYPES
39 #define WINE_VK_HOST
41 #include "wine/vulkan.h"
42 #include "wine/vulkan_driver.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
46 #ifdef SONAME_LIBMOLTENVK
48 typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
49 #define VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK 1000123000
51 struct wine_vk_surface
53 macdrv_metal_device device;
54 macdrv_metal_view view;
55 VkSurfaceKHR surface; /* native surface */
58 typedef struct VkMacOSSurfaceCreateInfoMVK
60 VkStructureType sType;
61 const void *pNext;
62 VkMacOSSurfaceCreateFlagsMVK flags;
63 const void *pView; /* NSView */
64 } VkMacOSSurfaceCreateInfoMVK;
66 static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *);
67 static VkResult (*pvkCreateSwapchainKHR)(VkDevice, const VkSwapchainCreateInfoKHR *, const VkAllocationCallbacks *, VkSwapchainKHR *);
68 static VkResult (*pvkCreateMacOSSurfaceMVK)(VkInstance, const VkMacOSSurfaceCreateInfoMVK*, const VkAllocationCallbacks *, VkSurfaceKHR *);
69 static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks *);
70 static void (*pvkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *);
71 static void (*pvkDestroySwapchainKHR)(VkDevice, VkSwapchainKHR, const VkAllocationCallbacks *);
72 static VkResult (*pvkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *);
73 static void * (*pvkGetDeviceProcAddr)(VkDevice, const char *);
74 static void * (*pvkGetInstanceProcAddr)(VkInstance, const char *);
75 static VkResult (*pvkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR *);
76 static VkResult (*pvkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkSurfaceFormatKHR *);
77 static VkResult (*pvkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkPresentModeKHR *);
78 static VkResult (*pvkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32 *);
79 static VkResult (*pvkGetSwapchainImagesKHR)(VkDevice, VkSwapchainKHR, uint32_t *, VkImage *);
80 static VkResult (*pvkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *);
82 static void *macdrv_get_vk_device_proc_addr(const char *name);
83 static void *macdrv_get_vk_instance_proc_addr(VkInstance instance, const char *name);
85 static inline struct wine_vk_surface *surface_from_handle(VkSurfaceKHR handle)
87 return (struct wine_vk_surface *)(uintptr_t)handle;
90 static void *vulkan_handle;
92 static BOOL WINAPI wine_vk_init(INIT_ONCE *once, void *param, void **context)
94 if (!(vulkan_handle = wine_dlopen(SONAME_LIBMOLTENVK, RTLD_NOW, NULL, 0)))
96 ERR("Failed to load %s\n", SONAME_LIBMOLTENVK);
97 return TRUE;
100 #define LOAD_FUNCPTR(f) if ((p##f = wine_dlsym(vulkan_handle, #f, NULL, 0)) == NULL) goto fail;
101 LOAD_FUNCPTR(vkCreateInstance)
102 LOAD_FUNCPTR(vkCreateSwapchainKHR)
103 LOAD_FUNCPTR(vkCreateMacOSSurfaceMVK)
104 LOAD_FUNCPTR(vkDestroyInstance)
105 LOAD_FUNCPTR(vkDestroySurfaceKHR)
106 LOAD_FUNCPTR(vkDestroySwapchainKHR)
107 LOAD_FUNCPTR(vkEnumerateInstanceExtensionProperties)
108 LOAD_FUNCPTR(vkGetDeviceProcAddr)
109 LOAD_FUNCPTR(vkGetInstanceProcAddr)
110 LOAD_FUNCPTR(vkGetPhysicalDeviceSurfaceCapabilitiesKHR)
111 LOAD_FUNCPTR(vkGetPhysicalDeviceSurfaceFormatsKHR)
112 LOAD_FUNCPTR(vkGetPhysicalDeviceSurfacePresentModesKHR)
113 LOAD_FUNCPTR(vkGetPhysicalDeviceSurfaceSupportKHR)
114 LOAD_FUNCPTR(vkGetSwapchainImagesKHR)
115 LOAD_FUNCPTR(vkQueuePresentKHR)
116 #undef LOAD_FUNCPTR
118 return TRUE;
120 fail:
121 wine_dlclose(vulkan_handle, NULL, 0);
122 vulkan_handle = NULL;
123 return TRUE;
126 /* Helper function for converting between win32 and MoltenVK compatible VkInstanceCreateInfo.
127 * Caller is responsible for allocation and cleanup of 'dst'.
129 static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo *src,
130 VkInstanceCreateInfo *dst)
132 unsigned int i;
133 const char **enabled_extensions = NULL;
135 dst->sType = src->sType;
136 dst->flags = src->flags;
137 dst->pApplicationInfo = src->pApplicationInfo;
138 dst->pNext = src->pNext;
139 dst->enabledLayerCount = 0;
140 dst->ppEnabledLayerNames = NULL;
141 dst->enabledExtensionCount = 0;
142 dst->ppEnabledExtensionNames = NULL;
144 if (src->enabledExtensionCount > 0)
146 enabled_extensions = heap_calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames));
147 if (!enabled_extensions)
149 ERR("Failed to allocate memory for enabled extensions\n");
150 return VK_ERROR_OUT_OF_HOST_MEMORY;
153 for (i = 0; i < src->enabledExtensionCount; i++)
155 /* Substitute extension with MoltenVK ones else copy. Long-term, when we
156 * support more extensions, we should store these in a list.
158 if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_win32_surface"))
160 enabled_extensions[i] = "VK_MVK_macos_surface";
162 else
164 enabled_extensions[i] = src->ppEnabledExtensionNames[i];
167 dst->ppEnabledExtensionNames = enabled_extensions;
168 dst->enabledExtensionCount = src->enabledExtensionCount;
171 return VK_SUCCESS;
174 static void wine_vk_surface_destroy(VkInstance instance, struct wine_vk_surface *surface)
176 /* vkDestroySurfaceKHR must handle VK_NULL_HANDLE (0) for surface. */
177 if (!surface)
178 return;
180 pvkDestroySurfaceKHR(instance, surface->surface, NULL /* allocator */);
182 if (surface->view)
183 macdrv_view_release_metal_view(surface->view);
185 if (surface->device)
186 macdrv_release_metal_device(surface->device);
188 heap_free(surface);
191 static VkResult macdrv_vkCreateInstance(const VkInstanceCreateInfo *create_info,
192 const VkAllocationCallbacks *allocator, VkInstance *instance)
194 VkInstanceCreateInfo create_info_host;
195 VkResult res;
196 TRACE("create_info %p, allocator %p, instance %p\n", create_info, allocator, instance);
198 if (allocator)
199 FIXME("Support for allocation callbacks not implemented yet\n");
201 /* Perform a second pass on converting VkInstanceCreateInfo. Winevulkan
202 * performed a first pass in which it handles everything except for WSI
203 * functionality such as VK_KHR_win32_surface. Handle this now.
205 res = wine_vk_instance_convert_create_info(create_info, &create_info_host);
206 if (res != VK_SUCCESS)
208 ERR("Failed to convert instance create info, res=%d\n", res);
209 return res;
212 res = pvkCreateInstance(&create_info_host, NULL /* allocator */, instance);
214 heap_free((void *)create_info_host.ppEnabledExtensionNames);
215 return res;
218 static VkResult macdrv_vkCreateSwapchainKHR(VkDevice device,
219 const VkSwapchainCreateInfoKHR *create_info,
220 const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain)
222 VkSwapchainCreateInfoKHR create_info_host;
223 TRACE("%p %p %p %p\n", device, create_info, allocator, swapchain);
225 if (allocator)
226 FIXME("Support for allocation callbacks not implemented yet\n");
228 create_info_host = *create_info;
229 create_info_host.surface = surface_from_handle(create_info->surface)->surface;
231 return pvkCreateSwapchainKHR(device, &create_info_host, NULL /* allocator */,
232 swapchain);
235 static VkResult macdrv_vkCreateWin32SurfaceKHR(VkInstance instance,
236 const VkWin32SurfaceCreateInfoKHR *create_info,
237 const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface)
239 VkResult res;
240 VkMacOSSurfaceCreateInfoMVK create_info_host;
241 struct wine_vk_surface *mac_surface;
242 struct macdrv_win_data *data;
244 TRACE("%p %p %p %p\n", instance, create_info, allocator, surface);
246 if (allocator)
247 FIXME("Support for allocation callbacks not implemented yet\n");
249 if (!(data = get_win_data(create_info->hwnd)))
251 FIXME("DC for window %p of other process: not implemented\n", create_info->hwnd);
252 return VK_ERROR_INCOMPATIBLE_DRIVER;
255 mac_surface = heap_alloc_zero(sizeof(*mac_surface));
256 if (!mac_surface)
258 release_win_data(data);
259 return VK_ERROR_OUT_OF_HOST_MEMORY;
262 mac_surface->device = macdrv_create_metal_device();
263 if (!mac_surface->device)
265 ERR("Failed to allocate Metal device for hwnd=%p\n", create_info->hwnd);
266 res = VK_ERROR_OUT_OF_HOST_MEMORY;
267 goto err;
270 mac_surface->view = macdrv_view_create_metal_view(data->client_cocoa_view, mac_surface->device);
271 if (!mac_surface->view)
273 ERR("Failed to allocate Metal view for hwnd=%p\n", create_info->hwnd);
275 /* VK_KHR_win32_surface only allows out of host and device memory as errors. */
276 res = VK_ERROR_OUT_OF_HOST_MEMORY;
277 goto err;
280 create_info_host.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
281 create_info_host.pNext = NULL;
282 create_info_host.flags = 0; /* reserved */
283 create_info_host.pView = mac_surface->view;
285 res = pvkCreateMacOSSurfaceMVK(instance, &create_info_host, NULL /* allocator */, &mac_surface->surface);
286 if (res != VK_SUCCESS)
288 ERR("Failed to create MoltenVK surface, res=%d\n", res);
289 goto err;
292 *surface = (uintptr_t)mac_surface;
294 release_win_data(data);
296 TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*surface));
297 return VK_SUCCESS;
299 err:
300 wine_vk_surface_destroy(instance, mac_surface);
301 release_win_data(data);
302 return res;
305 static void macdrv_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *allocator)
307 TRACE("%p %p\n", instance, allocator);
309 if (allocator)
310 FIXME("Support for allocation callbacks not implemented yet\n");
312 pvkDestroyInstance(instance, NULL /* allocator */);
315 static void macdrv_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface,
316 const VkAllocationCallbacks *allocator)
318 struct wine_vk_surface *mac_surface = surface_from_handle(surface);
320 TRACE("%p 0x%s %p\n", instance, wine_dbgstr_longlong(surface), allocator);
322 if (allocator)
323 FIXME("Support for allocation callbacks not implemented yet\n");
325 wine_vk_surface_destroy(instance, mac_surface);
328 static void macdrv_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain,
329 const VkAllocationCallbacks *allocator)
331 TRACE("%p, 0x%s %p\n", device, wine_dbgstr_longlong(swapchain), allocator);
333 if (allocator)
334 FIXME("Support for allocation callbacks not implemented yet\n");
336 pvkDestroySwapchainKHR(device, swapchain, NULL /* allocator */);
339 static VkResult macdrv_vkEnumerateInstanceExtensionProperties(const char *layer_name,
340 uint32_t *count, VkExtensionProperties* properties)
342 unsigned int i;
343 VkResult res;
345 TRACE("layer_name %s, count %p, properties %p\n", debugstr_a(layer_name), count, properties);
347 /* This shouldn't get called with layer_name set, the ICD loader prevents it. */
348 if (layer_name)
350 ERR("Layer enumeration not supported from ICD.\n");
351 return VK_ERROR_LAYER_NOT_PRESENT;
354 /* We will return the same number of instance extensions reported by the host back to
355 * winevulkan. Along the way we may replace MoltenVK extensions with their win32 equivalents.
356 * Winevulkan will perform more detailed filtering as it knows whether it has thunks
357 * for a particular extension.
359 res = pvkEnumerateInstanceExtensionProperties(layer_name, count, properties);
360 if (!properties || res < 0)
361 return res;
363 for (i = 0; i < *count; i++)
365 /* For now the only MoltenVK extension we need to fixup. Long-term we may need an array. */
366 if (!strcmp(properties[i].extensionName, "VK_MVK_macos_surface"))
368 TRACE("Substituting VK_MVK_macos_surface for VK_KHR_win32_surface\n");
370 snprintf(properties[i].extensionName, sizeof(properties[i].extensionName),
371 VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
372 properties[i].specVersion = VK_KHR_WIN32_SURFACE_SPEC_VERSION;
376 TRACE("Returning %u extensions.\n", *count);
377 return res;
380 static void *macdrv_vkGetDeviceProcAddr(VkDevice device, const char *name)
382 void *proc_addr;
384 TRACE("%p, %s\n", device, debugstr_a(name));
386 if ((proc_addr = macdrv_get_vk_device_proc_addr(name)))
387 return proc_addr;
389 return pvkGetDeviceProcAddr(device, name);
392 static void *macdrv_vkGetInstanceProcAddr(VkInstance instance, const char *name)
394 void *proc_addr;
396 TRACE("%p, %s\n", instance, debugstr_a(name));
398 if ((proc_addr = macdrv_get_vk_instance_proc_addr(instance, name)))
399 return proc_addr;
401 return pvkGetInstanceProcAddr(instance, name);
404 static VkResult macdrv_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice phys_dev,
405 VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *capabilities)
407 struct wine_vk_surface *mac_surface = surface_from_handle(surface);
409 TRACE("%p, 0x%s, %p\n", phys_dev, wine_dbgstr_longlong(surface), capabilities);
411 return pvkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev, mac_surface->surface,
412 capabilities);
415 static VkResult macdrv_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice phys_dev,
416 VkSurfaceKHR surface, uint32_t *count, VkSurfaceFormatKHR *formats)
418 struct wine_vk_surface *mac_surface = surface_from_handle(surface);
420 TRACE("%p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), count, formats);
422 return pvkGetPhysicalDeviceSurfaceFormatsKHR(phys_dev, mac_surface->surface,
423 count, formats);
426 static VkResult macdrv_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice phys_dev,
427 VkSurfaceKHR surface, uint32_t *count, VkPresentModeKHR *modes)
429 struct wine_vk_surface *mac_surface = surface_from_handle(surface);
431 TRACE("%p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), count, modes);
433 return pvkGetPhysicalDeviceSurfacePresentModesKHR(phys_dev, mac_surface->surface, count,
434 modes);
437 static VkResult macdrv_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice phys_dev,
438 uint32_t index, VkSurfaceKHR surface, VkBool32 *supported)
440 struct wine_vk_surface *mac_surface = surface_from_handle(surface);
442 TRACE("%p, %u, 0x%s, %p\n", phys_dev, index, wine_dbgstr_longlong(surface), supported);
444 return pvkGetPhysicalDeviceSurfaceSupportKHR(phys_dev, index, mac_surface->surface,
445 supported);
448 static VkBool32 macdrv_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice phys_dev,
449 uint32_t index)
451 TRACE("%p %u\n", phys_dev, index);
453 return VK_TRUE;
456 static VkResult macdrv_vkGetSwapchainImagesKHR(VkDevice device,
457 VkSwapchainKHR swapchain, uint32_t *count, VkImage *images)
459 TRACE("%p, 0x%s %p %p\n", device, wine_dbgstr_longlong(swapchain), count, images);
460 return pvkGetSwapchainImagesKHR(device, swapchain, count, images);
463 static VkResult macdrv_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *present_info)
465 TRACE("%p, %p\n", queue, present_info);
466 return pvkQueuePresentKHR(queue, present_info);
469 static const struct vulkan_funcs vulkan_funcs =
471 macdrv_vkCreateInstance,
472 macdrv_vkCreateSwapchainKHR,
473 macdrv_vkCreateWin32SurfaceKHR,
474 macdrv_vkDestroyInstance,
475 macdrv_vkDestroySurfaceKHR,
476 macdrv_vkDestroySwapchainKHR,
477 macdrv_vkEnumerateInstanceExtensionProperties,
478 NULL,
479 macdrv_vkGetDeviceProcAddr,
480 macdrv_vkGetInstanceProcAddr,
481 NULL,
482 macdrv_vkGetPhysicalDeviceSurfaceCapabilitiesKHR,
483 macdrv_vkGetPhysicalDeviceSurfaceFormatsKHR,
484 macdrv_vkGetPhysicalDeviceSurfacePresentModesKHR,
485 macdrv_vkGetPhysicalDeviceSurfaceSupportKHR,
486 macdrv_vkGetPhysicalDeviceWin32PresentationSupportKHR,
487 macdrv_vkGetSwapchainImagesKHR,
488 macdrv_vkQueuePresentKHR,
491 static void *macdrv_get_vk_device_proc_addr(const char *name)
493 return get_vulkan_driver_device_proc_addr(&vulkan_funcs, name);
496 static void *macdrv_get_vk_instance_proc_addr(VkInstance instance, const char *name)
498 return get_vulkan_driver_instance_proc_addr(&vulkan_funcs, instance, name);
501 static const struct vulkan_funcs *get_vulkan_driver(UINT version)
503 static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
505 if (version != WINE_VULKAN_DRIVER_VERSION)
507 ERR("version mismatch, vulkan wants %u but driver has %u\n", version, WINE_VULKAN_DRIVER_VERSION);
508 return NULL;
511 InitOnceExecuteOnce(&init_once, wine_vk_init, NULL, NULL);
512 if (vulkan_handle)
513 return &vulkan_funcs;
515 return NULL;
518 #else /* No vulkan */
520 static const struct vulkan_funcs *get_vulkan_driver(UINT version)
522 ERR("Wine was built without Vulkan support.\n");
523 return NULL;
526 #endif /* SONAME_LIBMOLTENVK */
528 const struct vulkan_funcs *macdrv_wine_get_vulkan_driver(PHYSDEV dev, UINT version)
530 const struct vulkan_funcs *ret;
532 if (!(ret = get_vulkan_driver( version )))
534 dev = GET_NEXT_PHYSDEV( dev, wine_get_vulkan_driver );
535 ret = dev->funcs->wine_get_vulkan_driver( dev, version );
537 return ret;