diff --git a/configure b/configure index 2d1f47092a9..53e997f09c4 100755 --- a/configure +++ b/configure @@ -15276,12 +15276,68 @@ _ACEOF fi + if test "x$ac_cv_lib_soname_vulkan" = "x" + then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -lMoltenVK" >&5 +$as_echo_n "checking for -lMoltenVK... " >&6; } +if ${ac_cv_lib_soname_MoltenVK+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_soname_save_LIBS=$LIBS +LIBS="-lMoltenVK $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char vkGetInstanceProcAddr (); +int +main () +{ +return vkGetInstanceProcAddr (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + case "$LIBEXT" in + dll) ac_cv_lib_soname_MoltenVK=`$ac_cv_path_LDD conftest.exe | grep "MoltenVK" | sed -e "s/dll.*/dll/"';2,$d'` ;; + dylib) ac_cv_lib_soname_MoltenVK=`$OTOOL -L conftest$ac_exeext | grep "libMoltenVK\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libMoltenVK\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; + *) ac_cv_lib_soname_MoltenVK=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libMoltenVK\\.$LIBEXT" | sed -e "s/^.*\\[\\(libMoltenVK\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` + if ${ac_cv_lib_soname_MoltenVK:+false} :; then : + ac_cv_lib_soname_MoltenVK=`$LDD conftest$ac_exeext | grep "libMoltenVK\\.$LIBEXT" | sed -e "s/^.*\(libMoltenVK\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` +fi ;; + esac fi -if test "x$ac_cv_lib_soname_vulkan" = "x"; then : +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS=$ac_check_soname_save_LIBS +fi +if ${ac_cv_lib_soname_MoltenVK:+false} :; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_soname_MoltenVK" >&5 +$as_echo "$ac_cv_lib_soname_MoltenVK" >&6; } + +cat >>confdefs.h <<_ACEOF +#define SONAME_LIBMOLTENVK "$ac_cv_lib_soname_MoltenVK" +_ACEOF + + +fi + fi +fi +if test "x$ac_cv_lib_soname_vulkan" = "x" -a "x$ac_cv_lib_soname_MoltenVK" = "x"; then : case "x$with_vulkan" in - x) as_fn_append wine_notices "|libvulkan ${notice_platform}development files not found, Vulkan won't be supported." ;; + x) as_fn_append wine_notices "|libvulkan and libMoltenVK ${notice_platform}development files not found, Vulkan won't be supported." ;; xno) ;; - *) as_fn_error $? "libvulkan ${notice_platform}development files not found, Vulkan won't be supported. + *) as_fn_error $? "libvulkan and libMoltenVK ${notice_platform}development files not found, Vulkan won't be supported. This is an error since --with-vulkan was requested." "$LINENO" 5 ;; esac diff --git a/configure.ac b/configure.ac index 9ba9a28cc31..be247ea2003 100644 --- a/configure.ac +++ b/configure.ac @@ -1858,9 +1858,13 @@ dnl *** Check for Vulkan *** if test "x$with_vulkan" != "xno" then WINE_CHECK_SONAME(vulkan, vkGetInstanceProcAddr) + if test "x$ac_cv_lib_soname_vulkan" = "x" + then + WINE_CHECK_SONAME(MoltenVK, vkGetInstanceProcAddr) + fi fi -WINE_NOTICE_WITH(vulkan,[test "x$ac_cv_lib_soname_vulkan" = "x"], - [libvulkan ${notice_platform}development files not found, Vulkan won't be supported.]) +WINE_NOTICE_WITH(vulkan,[test "x$ac_cv_lib_soname_vulkan" = "x" -a "x$ac_cv_lib_soname_MoltenVK" = "x"], + [libvulkan and libMoltenVK ${notice_platform}development files not found, Vulkan won't be supported.]) dnl **** Check for vkd3d **** if test "x$with_vkd3d" != "xno" diff --git a/dlls/winemac.drv/Makefile.in b/dlls/winemac.drv/Makefile.in index 33f4e2ee002..3ffb7d666c6 100644 --- a/dlls/winemac.drv/Makefile.in +++ b/dlls/winemac.drv/Makefile.in @@ -17,6 +17,7 @@ C_SRCS = \ opengl.c \ surface.c \ systray.c \ + vulkan.c \ window.c OBJC_SRCS = \ diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c index 1f9ac8be417..77da2334ee9 100644 --- a/dlls/winemac.drv/gdi.c +++ b/dlls/winemac.drv/gdi.c @@ -418,7 +418,7 @@ static const struct gdi_dc_funcs macdrv_funcs = NULL, /* pUnrealizePalette */ NULL, /* pWidenPath */ macdrv_wine_get_wgl_driver, /* wine_get_wgl_driver */ - NULL, /* wine_get_vulkan_driver */ + macdrv_wine_get_vulkan_driver, /* wine_get_vulkan_driver */ GDI_PRIORITY_GRAPHICS_DRV /* priority */ }; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index bb0e8ed13f2..f948da42c71 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -209,6 +209,7 @@ static inline RECT rect_from_cgrect(CGRect cgrect) extern BOOL query_drag_drop(macdrv_query* query) DECLSPEC_HIDDEN; extern struct opengl_funcs *macdrv_wine_get_wgl_driver(PHYSDEV dev, UINT version) DECLSPEC_HIDDEN; +extern const struct vulkan_funcs *macdrv_wine_get_vulkan_driver(PHYSDEV dev, UINT version) DECLSPEC_HIDDEN; extern void sync_gl_view(struct macdrv_win_data* data, const RECT* old_whole_rect, const RECT* old_client_rect) DECLSPEC_HIDDEN; extern CGImageRef create_cgimage_from_icon_bitmaps(HDC hdc, HANDLE icon, HBITMAP hbmColor, diff --git a/dlls/winemac.drv/vulkan.c b/dlls/winemac.drv/vulkan.c new file mode 100644 index 00000000000..d590903310c --- /dev/null +++ b/dlls/winemac.drv/vulkan.c @@ -0,0 +1,613 @@ +/* Mac Driver Vulkan implementation + * + * Copyright 2017 Roderick Colenbrander + * Copyright 2018 Andrew Eikum for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* NOTE: If making changes here, consider whether they should be reflected in + * the other drivers. */ + +#include "config.h" +#include "wine/port.h" +#include "macdrv.h" + +#include +#include + +#include "windef.h" +#include "winbase.h" + +#include "wine/debug.h" +#include "wine/heap.h" +#include "wine/library.h" + +#define VK_NO_PROTOTYPES +#define WINE_VK_HOST + +#include "wine/vulkan.h" +#include "wine/vulkan_driver.h" + +WINE_DEFAULT_DEBUG_CHANNEL(vulkan); + +#ifdef SONAME_LIBMOLTENVK + +typedef VkFlags VkMacOSSurfaceCreateFlagsMVK; +#define VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK 1000123000 + +struct wine_vk_surface +{ + macdrv_metal_device device; + macdrv_metal_view view; + VkSurfaceKHR surface; /* native surface */ +}; + +typedef struct VkMacOSSurfaceCreateInfoMVK +{ + VkStructureType sType; + const void *pNext; + VkMacOSSurfaceCreateFlagsMVK flags; + const void *pView; /* NSView */ +} VkMacOSSurfaceCreateInfoMVK; + +static VkResult (*pvkAcquireNextImageKHR)(VkDevice, VkSwapchainKHR, uint64_t, VkSemaphore, VkFence, uint32_t *); +static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); +static VkResult (*pvkCreateSwapchainKHR)(VkDevice, const VkSwapchainCreateInfoKHR *, const VkAllocationCallbacks *, VkSwapchainKHR *); +static VkResult (*pvkCreateMacOSSurfaceMVK)(VkInstance, const VkMacOSSurfaceCreateInfoMVK*, const VkAllocationCallbacks *, VkSurfaceKHR *); +static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks *); +static void (*pvkDestroySurfaceKHR)(VkInstance, VkSurfaceKHR, const VkAllocationCallbacks *); +static void (*pvkDestroySwapchainKHR)(VkDevice, VkSwapchainKHR, const VkAllocationCallbacks *); +static VkResult (*pvkEnumerateInstanceExtensionProperties)(const char *, uint32_t *, VkExtensionProperties *); +static void * (*pvkGetDeviceProcAddr)(VkDevice, const char *); +static void * (*pvkGetInstanceProcAddr)(VkInstance, const char *); +static VkResult (*pvkGetPhysicalDeviceSurfaceCapabilitiesKHR)(VkPhysicalDevice, VkSurfaceKHR, VkSurfaceCapabilitiesKHR *); +static VkResult (*pvkGetPhysicalDeviceSurfaceFormatsKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkSurfaceFormatKHR *); +static VkResult (*pvkGetPhysicalDeviceSurfacePresentModesKHR)(VkPhysicalDevice, VkSurfaceKHR, uint32_t *, VkPresentModeKHR *); +static VkResult (*pvkGetPhysicalDeviceSurfaceSupportKHR)(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32 *); +static VkResult (*pvkGetSwapchainImagesKHR)(VkDevice, VkSwapchainKHR, uint32_t *, VkImage *); +static VkResult (*pvkQueuePresentKHR)(VkQueue, const VkPresentInfoKHR *); + +static void *macdrv_get_vk_device_proc_addr(const char *name); +static void *macdrv_get_vk_instance_proc_addr(VkInstance instance, const char *name); + +static inline struct wine_vk_surface *surface_from_handle(VkSurfaceKHR handle) +{ + return (struct wine_vk_surface *)(uintptr_t)handle; +} + +static void *vulkan_handle; + +static BOOL WINAPI wine_vk_init(INIT_ONCE *once, void *param, void **context) +{ + if (!(vulkan_handle = wine_dlopen(SONAME_LIBMOLTENVK, RTLD_NOW, NULL, 0))) + { + ERR("Failed to load %s\n", SONAME_LIBMOLTENVK); + return TRUE; + } + +#define LOAD_FUNCPTR(f) if ((p##f = wine_dlsym(vulkan_handle, #f, NULL, 0)) == NULL) goto fail; + LOAD_FUNCPTR(vkAcquireNextImageKHR) + LOAD_FUNCPTR(vkCreateInstance) + LOAD_FUNCPTR(vkCreateSwapchainKHR) + LOAD_FUNCPTR(vkCreateMacOSSurfaceMVK) + LOAD_FUNCPTR(vkDestroyInstance) + LOAD_FUNCPTR(vkDestroySurfaceKHR) + LOAD_FUNCPTR(vkDestroySwapchainKHR) + LOAD_FUNCPTR(vkEnumerateInstanceExtensionProperties) + LOAD_FUNCPTR(vkGetDeviceProcAddr) + LOAD_FUNCPTR(vkGetInstanceProcAddr) + LOAD_FUNCPTR(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) + LOAD_FUNCPTR(vkGetPhysicalDeviceSurfaceFormatsKHR) + LOAD_FUNCPTR(vkGetPhysicalDeviceSurfacePresentModesKHR) + LOAD_FUNCPTR(vkGetPhysicalDeviceSurfaceSupportKHR) + LOAD_FUNCPTR(vkGetSwapchainImagesKHR) + LOAD_FUNCPTR(vkQueuePresentKHR) +#undef LOAD_FUNCPTR + + return TRUE; + +fail: + wine_dlclose(vulkan_handle, NULL, 0); + vulkan_handle = NULL; + return TRUE; +} + +/* Helper function for converting between win32 and MoltenVK compatible VkInstanceCreateInfo. + * Caller is responsible for allocation and cleanup of 'dst'. + */ +static VkResult wine_vk_instance_convert_create_info(const VkInstanceCreateInfo *src, + VkInstanceCreateInfo *dst) +{ + unsigned int i; + const char **enabled_extensions = NULL; + + dst->sType = src->sType; + dst->flags = src->flags; + dst->pApplicationInfo = src->pApplicationInfo; + dst->pNext = src->pNext; + dst->enabledLayerCount = 0; + dst->ppEnabledLayerNames = NULL; + dst->enabledExtensionCount = 0; + dst->ppEnabledExtensionNames = NULL; + + if (src->enabledExtensionCount > 0) + { + enabled_extensions = heap_calloc(src->enabledExtensionCount, sizeof(*src->ppEnabledExtensionNames)); + if (!enabled_extensions) + { + ERR("Failed to allocate memory for enabled extensions\n"); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + for (i = 0; i < src->enabledExtensionCount; i++) + { + /* Substitute extension with MoltenVK ones else copy. Long-term, when we + * support more extensions, we should store these in a list. + */ + if (!strcmp(src->ppEnabledExtensionNames[i], "VK_KHR_win32_surface")) + { + enabled_extensions[i] = "VK_MVK_macos_surface"; + } + else + { + enabled_extensions[i] = src->ppEnabledExtensionNames[i]; + } + } + dst->ppEnabledExtensionNames = enabled_extensions; + dst->enabledExtensionCount = src->enabledExtensionCount; + } + + return VK_SUCCESS; +} + +static void wine_vk_surface_destroy(VkInstance instance, struct wine_vk_surface *surface) +{ + /* vkDestroySurfaceKHR must handle VK_NULL_HANDLE (0) for surface. */ + if (!surface) + return; + + pvkDestroySurfaceKHR(instance, surface->surface, NULL /* allocator */); + + if (surface->view) + macdrv_view_release_metal_view(surface->view); + + if (surface->device) + macdrv_release_metal_device(surface->device); + + heap_free(surface); +} + +static VkResult macdrv_vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, + uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *index) +{ + TRACE("%p, 0x%s, 0x%s, 0x%s, 0x%s, %p\n", device, + wine_dbgstr_longlong(swapchain), wine_dbgstr_longlong(timeout), + wine_dbgstr_longlong(semaphore), wine_dbgstr_longlong(fence), index); + + return pvkAcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, index); +} + +static VkResult macdrv_vkCreateInstance(const VkInstanceCreateInfo *create_info, + const VkAllocationCallbacks *allocator, VkInstance *instance) +{ + VkInstanceCreateInfo create_info_host; + VkResult res; + TRACE("create_info %p, allocator %p, instance %p\n", create_info, allocator, instance); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + /* Perform a second pass on converting VkInstanceCreateInfo. Winevulkan + * performed a first pass in which it handles everything except for WSI + * functionality such as VK_KHR_win32_surface. Handle this now. + */ + res = wine_vk_instance_convert_create_info(create_info, &create_info_host); + if (res != VK_SUCCESS) + { + ERR("Failed to convert instance create info, res=%d\n", res); + return res; + } + + res = pvkCreateInstance(&create_info_host, NULL /* allocator */, instance); + + heap_free((void *)create_info_host.ppEnabledExtensionNames); + return res; +} + +static VkResult macdrv_vkCreateSwapchainKHR(VkDevice device, + const VkSwapchainCreateInfoKHR *create_info, + const VkAllocationCallbacks *allocator, VkSwapchainKHR *swapchain) +{ + VkSwapchainCreateInfoKHR create_info_host; + TRACE("%p %p %p %p\n", device, create_info, allocator, swapchain); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + create_info_host = *create_info; + create_info_host.surface = surface_from_handle(create_info->surface)->surface; + + return pvkCreateSwapchainKHR(device, &create_info_host, NULL /* allocator */, + swapchain); +} + +static VkResult macdrv_vkCreateWin32SurfaceKHR(VkInstance instance, + const VkWin32SurfaceCreateInfoKHR *create_info, + const VkAllocationCallbacks *allocator, VkSurfaceKHR *surface) +{ + VkResult res; + VkMacOSSurfaceCreateInfoMVK create_info_host; + struct wine_vk_surface *mac_surface; + struct macdrv_win_data *data; + + TRACE("%p %p %p %p\n", instance, create_info, allocator, surface); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + if (!(data = get_win_data(create_info->hwnd))) + { + FIXME("DC for window %p of other process: not implemented\n", create_info->hwnd); + return VK_ERROR_INCOMPATIBLE_DRIVER; + } + + mac_surface = heap_alloc_zero(sizeof(*mac_surface)); + if (!mac_surface) + { + release_win_data(data); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + mac_surface->device = macdrv_create_metal_device(); + if (!mac_surface->device) + { + ERR("Failed to allocate Metal device for hwnd=%p\n", create_info->hwnd); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto err; + } + + mac_surface->view = macdrv_view_create_metal_view(data->client_cocoa_view, mac_surface->device); + if (!mac_surface->view) + { + ERR("Failed to allocate Metal view for hwnd=%p\n", create_info->hwnd); + + /* VK_KHR_win32_surface only allows out of host and device memory as errors. */ + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto err; + } + + create_info_host.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; + create_info_host.pNext = NULL; + create_info_host.flags = 0; /* reserved */ + create_info_host.pView = mac_surface->view; + + res = pvkCreateMacOSSurfaceMVK(instance, &create_info_host, NULL /* allocator */, &mac_surface->surface); + if (res != VK_SUCCESS) + { + ERR("Failed to create MoltenVK surface, res=%d\n", res); + goto err; + } + + *surface = (uintptr_t)mac_surface; + + release_win_data(data); + + TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*surface)); + return VK_SUCCESS; + +err: + wine_vk_surface_destroy(instance, mac_surface); + release_win_data(data); + return res; +} + +static void macdrv_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *allocator) +{ + TRACE("%p %p\n", instance, allocator); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + pvkDestroyInstance(instance, NULL /* allocator */); +} + +static void macdrv_vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, + const VkAllocationCallbacks *allocator) +{ + struct wine_vk_surface *mac_surface = surface_from_handle(surface); + + TRACE("%p 0x%s %p\n", instance, wine_dbgstr_longlong(surface), allocator); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + wine_vk_surface_destroy(instance, mac_surface); +} + +static void macdrv_vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, + const VkAllocationCallbacks *allocator) +{ + TRACE("%p, 0x%s %p\n", device, wine_dbgstr_longlong(swapchain), allocator); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + pvkDestroySwapchainKHR(device, swapchain, NULL /* allocator */); +} + +static VkResult macdrv_vkEnumerateInstanceExtensionProperties(const char *layer_name, + uint32_t *count, VkExtensionProperties* properties) +{ + unsigned int i; + VkResult res; + + TRACE("layer_name %p, count %p, properties %p\n", debugstr_a(layer_name), count, properties); + + /* This shouldn't get called with layer_name set, the ICD loader prevents it. */ + if (layer_name) + { + ERR("Layer enumeration not supported from ICD.\n"); + return VK_ERROR_LAYER_NOT_PRESENT; + } + + /* We will return the same number of instance extensions reported by the host back to + * winevulkan. Along the way we may replace MoltenVK extensions with their win32 equivalents. + * Winevulkan will perform more detailed filtering as it knows whether it has thunks + * for a particular extension. + */ + res = pvkEnumerateInstanceExtensionProperties(layer_name, count, properties); + if (!properties || res < 0) + return res; + + for (i = 0; i < *count; i++) + { + /* For now the only MoltenVK extension we need to fixup. Long-term we may need an array. */ + if (!strcmp(properties[i].extensionName, "VK_MVK_macos_surface")) + { + TRACE("Substituting VK_MVK_macos_surface for VK_KHR_win32_surface\n"); + + snprintf(properties[i].extensionName, sizeof(properties[i].extensionName), + VK_KHR_WIN32_SURFACE_EXTENSION_NAME); + properties[i].specVersion = VK_KHR_WIN32_SURFACE_SPEC_VERSION; + } + } + + TRACE("Returning %u extensions.\n", *count); + return res; +} + +static void *macdrv_vkGetDeviceProcAddr(VkDevice device, const char *name) +{ + void *proc_addr; + + TRACE("%p, %s\n", device, debugstr_a(name)); + + if ((proc_addr = macdrv_get_vk_device_proc_addr(name))) + return proc_addr; + + return pvkGetDeviceProcAddr(device, name); +} + +static void *macdrv_vkGetInstanceProcAddr(VkInstance instance, const char *name) +{ + void *proc_addr; + + TRACE("%p, %s\n", instance, debugstr_a(name)); + + if ((proc_addr = macdrv_get_vk_instance_proc_addr(instance, name))) + return proc_addr; + + return pvkGetInstanceProcAddr(instance, name); +} + +static VkResult macdrv_vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice phys_dev, + VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *capabilities) +{ + struct wine_vk_surface *mac_surface = surface_from_handle(surface); + + TRACE("%p, 0x%s, %p\n", phys_dev, wine_dbgstr_longlong(surface), capabilities); + + return pvkGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev, mac_surface->surface, + capabilities); +} + +static VkResult macdrv_vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice phys_dev, + VkSurfaceKHR surface, uint32_t *count, VkSurfaceFormatKHR *formats) +{ + struct wine_vk_surface *mac_surface = surface_from_handle(surface); + + TRACE("%p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), count, formats); + + return pvkGetPhysicalDeviceSurfaceFormatsKHR(phys_dev, mac_surface->surface, + count, formats); +} + +static VkResult macdrv_vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice phys_dev, + VkSurfaceKHR surface, uint32_t *count, VkPresentModeKHR *modes) +{ + struct wine_vk_surface *mac_surface = surface_from_handle(surface); + + TRACE("%p, 0x%s, %p, %p\n", phys_dev, wine_dbgstr_longlong(surface), count, modes); + + return pvkGetPhysicalDeviceSurfacePresentModesKHR(phys_dev, mac_surface->surface, count, + modes); +} + +static VkResult macdrv_vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice phys_dev, + uint32_t index, VkSurfaceKHR surface, VkBool32 *supported) +{ + struct wine_vk_surface *mac_surface = surface_from_handle(surface); + + TRACE("%p, %u, 0x%s, %p\n", phys_dev, index, wine_dbgstr_longlong(surface), supported); + + return pvkGetPhysicalDeviceSurfaceSupportKHR(phys_dev, index, mac_surface->surface, + supported); +} + +static VkBool32 macdrv_vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice phys_dev, + uint32_t index) +{ + TRACE("%p %u\n", phys_dev, index); + + return VK_TRUE; +} + +static VkResult macdrv_vkGetSwapchainImagesKHR(VkDevice device, + VkSwapchainKHR swapchain, uint32_t *count, VkImage *images) +{ + TRACE("%p, 0x%s %p %p\n", device, wine_dbgstr_longlong(swapchain), count, images); + return pvkGetSwapchainImagesKHR(device, swapchain, count, images); +} + +static VkResult macdrv_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *present_info) +{ + TRACE("%p, %p\n", queue, present_info); + return pvkQueuePresentKHR(queue, present_info); +} + +static const struct vulkan_funcs vulkan_funcs = +{ + macdrv_vkAcquireNextImageKHR, + macdrv_vkCreateInstance, + macdrv_vkCreateSwapchainKHR, + macdrv_vkCreateWin32SurfaceKHR, + macdrv_vkDestroyInstance, + macdrv_vkDestroySurfaceKHR, + macdrv_vkDestroySwapchainKHR, + macdrv_vkEnumerateInstanceExtensionProperties, + macdrv_vkGetDeviceProcAddr, + macdrv_vkGetInstanceProcAddr, + macdrv_vkGetPhysicalDeviceSurfaceCapabilitiesKHR, + macdrv_vkGetPhysicalDeviceSurfaceFormatsKHR, + macdrv_vkGetPhysicalDeviceSurfacePresentModesKHR, + macdrv_vkGetPhysicalDeviceSurfaceSupportKHR, + macdrv_vkGetPhysicalDeviceWin32PresentationSupportKHR, + macdrv_vkGetSwapchainImagesKHR, + macdrv_vkQueuePresentKHR, +}; + +static void *get_vulkan_driver_device_proc_addr(const struct vulkan_funcs *vulkan_funcs, + const char *name) +{ + if (!name || name[0] != 'v' || name[1] != 'k') + return NULL; + + name += 2; + + if (!strcmp(name, "AcquireNextImageKHR")) + return vulkan_funcs->p_vkAcquireNextImageKHR; + if (!strcmp(name, "CreateSwapchainKHR")) + return vulkan_funcs->p_vkCreateSwapchainKHR; + if (!strcmp(name, "DestroySwapchainKHR")) + return vulkan_funcs->p_vkDestroySwapchainKHR; + if (!strcmp(name, "GetDeviceProcAddr")) + return vulkan_funcs->p_vkGetDeviceProcAddr; + if (!strcmp(name, "GetSwapchainImagesKHR")) + return vulkan_funcs->p_vkGetSwapchainImagesKHR; + if (!strcmp(name, "QueuePresentKHR")) + return vulkan_funcs->p_vkQueuePresentKHR; + + return NULL; +} + +static void *macdrv_get_vk_device_proc_addr(const char *name) +{ + return get_vulkan_driver_device_proc_addr(&vulkan_funcs, name); +} + +static void *get_vulkan_driver_instance_proc_addr(const struct vulkan_funcs *vulkan_funcs, + VkInstance instance, const char *name) +{ + if (!name || name[0] != 'v' || name[1] != 'k') + return NULL; + + name += 2; + + if (!strcmp(name, "CreateInstance")) + return vulkan_funcs->p_vkCreateInstance; + if (!strcmp(name, "EnumerateInstanceExtensionProperties")) + return vulkan_funcs->p_vkEnumerateInstanceExtensionProperties; + + if (!instance) + return NULL; + + if (!strcmp(name, "CreateWin32SurfaceKHR")) + return vulkan_funcs->p_vkCreateWin32SurfaceKHR; + if (!strcmp(name, "DestroyInstance")) + return vulkan_funcs->p_vkDestroyInstance; + if (!strcmp(name, "DestroySurfaceKHR")) + return vulkan_funcs->p_vkDestroySurfaceKHR; + if (!strcmp(name, "GetInstanceProcAddr")) + return vulkan_funcs->p_vkGetInstanceProcAddr; + if (!strcmp(name, "GetPhysicalDeviceSurfaceCapabilitiesKHR")) + return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceCapabilitiesKHR; + if (!strcmp(name, "GetPhysicalDeviceSurfaceFormatsKHR")) + return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceFormatsKHR; + if (!strcmp(name, "GetPhysicalDeviceSurfacePresentModesKHR")) + return vulkan_funcs->p_vkGetPhysicalDeviceSurfacePresentModesKHR; + if (!strcmp(name, "GetPhysicalDeviceSurfaceSupportKHR")) + return vulkan_funcs->p_vkGetPhysicalDeviceSurfaceSupportKHR; + if (!strcmp(name, "GetPhysicalDeviceWin32PresentationSupportKHR")) + return vulkan_funcs->p_vkGetPhysicalDeviceWin32PresentationSupportKHR; + + name -= 2; + + return get_vulkan_driver_device_proc_addr(vulkan_funcs, name); +} + +static void *macdrv_get_vk_instance_proc_addr(VkInstance instance, const char *name) +{ + return get_vulkan_driver_instance_proc_addr(&vulkan_funcs, instance, name); +} + +static const struct vulkan_funcs *get_vulkan_driver(UINT version) +{ + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + + if (version != WINE_VULKAN_DRIVER_VERSION) + { + ERR("version mismatch, vulkan wants %u but driver has %u\n", version, WINE_VULKAN_DRIVER_VERSION); + return NULL; + } + + InitOnceExecuteOnce(&init_once, wine_vk_init, NULL, NULL); + if (vulkan_handle) + return &vulkan_funcs; + + return NULL; +} + +#else /* No vulkan */ + +static const struct vulkan_funcs *get_vulkan_driver(UINT version) +{ + ERR("Wine was built without Vulkan support.\n"); + return NULL; +} + +#endif /* SONAME_LIBMOLTENVK */ + +const struct vulkan_funcs *macdrv_wine_get_vulkan_driver(PHYSDEV dev, UINT version) +{ + const struct vulkan_funcs *ret; + + if (!(ret = get_vulkan_driver( version ))) + { + dev = GET_NEXT_PHYSDEV( dev, wine_get_vulkan_driver ); + ret = dev->funcs->wine_get_vulkan_driver( dev, version ); + } + return ret; +} diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index b0bce1ed57f..58c08ad8180 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -17,6 +17,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +/* NOTE: If making changes here, consider whether they should be reflected in + * the other drivers. */ + #include "config.h" #include "wine/port.h" diff --git a/include/config.h.in b/include/config.h.in index 67f802bcba3..b42de297949 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -1518,6 +1518,9 @@ /* Define to the soname of the libkrb5 library. */ #undef SONAME_LIBKRB5 +/* Define to the soname of the libMoltenVK library. */ +#undef SONAME_LIBMOLTENVK + /* Define to the soname of the libncurses library. */ #undef SONAME_LIBNCURSES