diff --git a/configure b/configure index 10ca89aebd3..20be8b91c23 100755 --- a/configure +++ b/configure @@ -864,6 +864,7 @@ with_tiff with_udev with_sdl with_v4l +with_vulkan with_xcomposite with_xcursor with_xfixes @@ -2439,6 +2440,7 @@ Optional Packages: --without-udev do not use udev (plug and play support) --without-sdl do not use SDL --without-v4l do not use v4l1 (v4l support) + --without-vulkan do not use Vulkan --without-xcomposite do not use the Xcomposite extension --without-xcursor do not use the Xcursor extension --without-xfixes do not use Xfixes for clipboard change notifications @@ -3759,6 +3761,12 @@ if test "${with_v4l+set}" = set; then : fi +# Check whether --with-vulkan was given. +if test "${with_vulkan+set}" = set; then : + withval=$with_vulkan; +fi + + # Check whether --with-xcomposite was given. if test "${with_xcomposite+set}" = set; then : withval=$with_xcomposite; if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi @@ -14603,6 +14611,72 @@ then as_fn_append wine_warnings "|No sound system was found. Windows applications will be silent." fi +if test "x$with_vulkan" != "xno" +then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -lvulkan" >&5 +$as_echo_n "checking for -lvulkan... " >&6; } +if ${ac_cv_lib_soname_vulkan+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_soname_save_LIBS=$LIBS +LIBS="-lvulkan $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_vulkan=`$ac_cv_path_LDD conftest.exe | grep "vulkan" | sed -e "s/dll.*/dll/"';2,$d'` ;; + dylib) ac_cv_lib_soname_vulkan=`$OTOOL -L conftest$ac_exeext | grep "libvulkan\\.[0-9A-Za-z.]*dylib" | sed -e "s/^.*\/\(libvulkan\.[0-9A-Za-z.]*dylib\).*$/\1/"';2,$d'` ;; + *) ac_cv_lib_soname_vulkan=`$READELF -d conftest$ac_exeext | grep "NEEDED.*libvulkan\\.$LIBEXT" | sed -e "s/^.*\\[\\(libvulkan\\.$LIBEXT[^ ]*\\)\\].*$/\1/"';2,$d'` + if ${ac_cv_lib_soname_vulkan:+false} :; then : + ac_cv_lib_soname_vulkan=`$LDD conftest$ac_exeext | grep "libvulkan\\.$LIBEXT" | sed -e "s/^.*\(libvulkan\.$LIBEXT[^ ]*\).*$/\1/"';2,$d'` +fi ;; + esac +fi +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_vulkan:+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_vulkan" >&5 +$as_echo "$ac_cv_lib_soname_vulkan" >&6; } + +cat >>confdefs.h <<_ACEOF +#define SONAME_LIBVULKAN "$ac_cv_lib_soname_vulkan" +_ACEOF + + +fi +fi +if test "x$ac_cv_lib_soname_vulkan" = "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." ;; + xno) ;; + *) as_fn_error $? "libvulkan ${notice_platform}development files not found, Vulkan won't be supported. +This is an error since --with-vulkan was requested." "$LINENO" 5 ;; +esac + +fi + EXTRACFLAGS="" diff --git a/configure.ac b/configure.ac index 02937cab5db..3b93966c364 100644 --- a/configure.ac +++ b/configure.ac @@ -81,6 +81,7 @@ AC_ARG_WITH(tiff, AS_HELP_STRING([--without-tiff],[do not use TIFF])) AC_ARG_WITH(udev, AS_HELP_STRING([--without-udev],[do not use udev (plug and play support)])) AC_ARG_WITH(sdl, AS_HELP_STRING([--without-sdl],[do not use SDL])) AC_ARG_WITH(v4l, AS_HELP_STRING([--without-v4l],[do not use v4l1 (v4l support)])) +AC_ARG_WITH(vulkan, AS_HELP_STRING([--without-vulkan],[do not use Vulkan])) AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]), [if test "x$withval" = "xno"; then ac_cv_header_X11_extensions_Xcomposite_h=no; fi]) AC_ARG_WITH(xcursor, AS_HELP_STRING([--without-xcursor],[do not use the Xcursor extension]), @@ -1836,6 +1837,14 @@ then WINE_WARNING([No sound system was found. Windows applications will be silent.]) fi +dnl *** Check for Vulkan *** +if test "x$with_vulkan" != "xno" +then + WINE_CHECK_SONAME(vulkan, vkGetInstanceProcAddr) +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.]) + dnl **** Check for gcc specific options **** AC_SUBST(EXTRACFLAGS,"") diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c index e6c77cab325..2152cb15fef 100644 --- a/dlls/winevulkan/vulkan.c +++ b/dlls/winevulkan/vulkan.c @@ -24,8 +24,10 @@ #include "winuser.h" #include "wine/debug.h" +#include "wine/heap.h" #include "wine/vulkan.h" #include "wine/vulkan_driver.h" +#include "vulkan_private.h" WINE_DEFAULT_DEBUG_CHANNEL(vulkan); @@ -66,11 +68,54 @@ static BOOL wine_vk_init(void) return TRUE; } +/* Helper function used for freeing an instance structure. This function supports full + * and partial object cleanups and can thus be used for vkCreateInstance failures. + */ +static void wine_vk_instance_free(struct VkInstance_T *instance) +{ + if (!instance) + return; + + if (instance->instance) + vk_funcs->p_vkDestroyInstance(instance->instance, NULL /* allocator */); + + heap_free(instance); +} + static VkResult WINAPI wine_vkCreateInstance(const VkInstanceCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkInstance *instance) { - TRACE("%p %p %p\n", create_info, allocator, instance); - return vk_funcs->p_vkCreateInstance(create_info, allocator, instance); + struct VkInstance_T *object = NULL; + 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"); + + object = heap_alloc(sizeof(*object)); + if (!object) + { + ERR("Failed to allocate memory for instance\n"); + res = VK_ERROR_OUT_OF_HOST_MEMORY; + goto err; + } + object->base.loader_magic = VULKAN_ICD_MAGIC_VALUE; + + res = vk_funcs->p_vkCreateInstance(create_info, NULL /* allocator */, &object->instance); + if (res != VK_SUCCESS) + { + ERR("Failed to create instance, res=%d\n", res); + goto err; + } + + *instance = object; + TRACE("Done, instance=%p native_instance=%p\n", object, object->instance); + return VK_SUCCESS; + +err: + wine_vk_instance_free(object); + return res; } static VkResult WINAPI wine_vkEnumerateInstanceExtensionProperties(const char *layer_name, diff --git a/dlls/winevulkan/vulkan_private.h b/dlls/winevulkan/vulkan_private.h new file mode 100644 index 00000000000..6b83e875a29 --- /dev/null +++ b/dlls/winevulkan/vulkan_private.h @@ -0,0 +1,45 @@ +/* Wine Vulkan ICD private data structures + * + * Copyright 2017 Roderick Colenbrander + * + * 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 + */ + +#ifndef __WINE_VULKAN_PRIVATE_H +#define __WINE_VULKAN_PRIVATE_H + +/* Magic value defined by Vulkan ICD / Loader spec */ +#define VULKAN_ICD_MAGIC_VALUE 0x01CDC0DE + +/* Base 'class' for our Vulkan dispatchable objects such as VkDevice and VkInstance. + * This structure MUST be the first element of a dispatchable object as the ICD + * loader depends on it. For now only contains loader_magic, but over time more common + * functionality is expected. + */ +struct wine_vk_base +{ + /* Special section in each dispatchable object for use by the ICD loader for + * storing dispatch tables. The start contains a magical value '0x01CDC0DE'. + */ + UINT_PTR loader_magic; +}; + +struct VkInstance_T +{ + struct wine_vk_base base; + VkInstance instance; /* native instance */ +}; + +#endif /* __WINE_VULKAN_PRIVATE_H */ diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c index 92f8a0e4526..adc3da35e49 100644 --- a/dlls/winex11.drv/vulkan.c +++ b/dlls/winex11.drv/vulkan.c @@ -20,22 +20,67 @@ #include "config.h" #include "wine/port.h" +#include + +#include "windef.h" +#include "winbase.h" + #include "wine/debug.h" +#include "wine/library.h" #include "wine/vulkan.h" #include "wine/vulkan_driver.h" +#ifdef SONAME_LIBVULKAN + WINE_DEFAULT_DEBUG_CHANNEL(vulkan); +static VkResult (*pvkCreateInstance)(const VkInstanceCreateInfo *, const VkAllocationCallbacks *, VkInstance *); +static void (*pvkDestroyInstance)(VkInstance, const VkAllocationCallbacks *); + +static BOOL wine_vk_init(void) +{ + static BOOL init_done = FALSE; + static void *vulkan_handle; + + if (init_done) return (vulkan_handle != NULL); + init_done = TRUE; + + if (!(vulkan_handle = wine_dlopen(SONAME_LIBVULKAN, RTLD_NOW, NULL, 0))) return FALSE; + +#define LOAD_FUNCPTR(f) if((p##f = wine_dlsym(vulkan_handle, #f, NULL, 0)) == NULL) return FALSE; +LOAD_FUNCPTR(vkCreateInstance) +LOAD_FUNCPTR(vkDestroyInstance) +#undef LOAD_FUNCPTR + + return TRUE; +} + static VkResult X11DRV_vkCreateInstance(const VkInstanceCreateInfo *create_info, const VkAllocationCallbacks *allocator, VkInstance *instance) { - FIXME("stub: %p %p %p\n", create_info, allocator, instance); - return VK_ERROR_INCOMPATIBLE_DRIVER; + TRACE("create_info %p, allocator %p, instance %p\n", create_info, allocator, instance); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + /* TODO: convert win32 to x11 extensions here. */ + if (create_info->enabledExtensionCount > 0) + { + FIXME("Extensions are not supported yet, aborting!\n"); + return VK_ERROR_INCOMPATIBLE_DRIVER; + } + + return pvkCreateInstance(create_info, NULL /* allocator */, instance); } static void X11DRV_vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *allocator) { - FIXME("stub: %p %p\n", instance, allocator); + TRACE("%p %p\n", instance, allocator); + + if (allocator) + FIXME("Support for allocation callbacks not implemented yet\n"); + + pvkDestroyInstance(instance, NULL /* allocator */); } static VkResult X11DRV_vkEnumerateInstanceExtensionProperties(const char *layer_name, @@ -75,7 +120,7 @@ static void * X11DRV_vkGetInstanceProcAddr(VkInstance instance, const char *name return NULL; } -static struct vulkan_funcs vulkan_funcs = +static const struct vulkan_funcs vulkan_funcs = { X11DRV_vkCreateInstance, X11DRV_vkDestroyInstance, @@ -91,5 +136,17 @@ const struct vulkan_funcs *get_vulkan_driver(UINT version) return NULL; } - return &vulkan_funcs; + if (wine_vk_init()) + return &vulkan_funcs; + + return NULL; } + +#else /* No vulkan */ + +const struct vulkan_funcs *get_vulkan_driver(UINT version) +{ + return NULL; +} + +#endif /* SONAME_LIBVULKAN */ diff --git a/include/config.h.in b/include/config.h.in index b7ed9d2b8c6..353c1463881 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -1527,6 +1527,9 @@ /* Define to the soname of the libv4l1 library. */ #undef SONAME_LIBV4L1 +/* Define to the soname of the libvulkan library. */ +#undef SONAME_LIBVULKAN + /* Define to the soname of the libX11 library. */ #undef SONAME_LIBX11