vkd3d: Remove dependency on linking directly against libvulkan.

There is no reason to not load Vulkan dynamically, otherwise, we must
have loader dev packages installed, which is not ideal.

Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
This commit is contained in:
Hans-Kristian Arntzen 2020-06-15 11:46:10 +02:00
parent 4cf8467b9d
commit cbdf6f88d2
6 changed files with 111 additions and 36 deletions

View File

@ -25,7 +25,8 @@ vkd3d_public_headers = \
include/vkd3d_shader.h \ include/vkd3d_shader.h \
include/vkd3d_types.h \ include/vkd3d_types.h \
include/vkd3d_utils.h \ include/vkd3d_utils.h \
include/vkd3d_windows.h include/vkd3d_windows.h \
include/vkd3d_sonames.h
vkd3d_demos_shaders = \ vkd3d_demos_shaders = \
demos/gears.hlsl \ demos/gears.hlsl \
@ -156,14 +157,14 @@ AM_DEFAULT_SOURCE_EXT = .c
if BUILD_TESTS if BUILD_TESTS
check_PROGRAMS = $(vkd3d_tests) $(vkd3d_cross_tests) check_PROGRAMS = $(vkd3d_tests) $(vkd3d_cross_tests)
TESTS = $(vkd3d_tests) $(vkd3d_cross_tests) TESTS = $(vkd3d_tests) $(vkd3d_cross_tests)
tests_d3d12_LDADD = $(LDADD) @PTHREAD_LIBS@ @VULKAN_LIBS@ tests_d3d12_LDADD = $(LDADD) @PTHREAD_LIBS@
tests_d3d12_invalid_usage_LDADD = $(LDADD) @VULKAN_LIBS@ tests_d3d12_invalid_usage_LDADD = $(LDADD)
tests_vkd3d_api_LDADD = libvkd3d.la @VULKAN_LIBS@ tests_vkd3d_api_LDADD = libvkd3d.la
tests_vkd3d_shader_api_LDADD = libvkd3d-shader.la tests_vkd3d_shader_api_LDADD = libvkd3d-shader.la
endif endif
if BUILD_DEMOS if BUILD_DEMOS
DEMOS_LDADD = $(LDADD) libvkd3d-shader.la @XCB_LIBS@ @VULKAN_LIBS@ DEMOS_LDADD = $(LDADD) libvkd3d-shader.la @XCB_LIBS@ @DL_LIBS@
DEMOS_CFLAGS = $(AM_CFLAGS) @XCB_CFLAGS@ DEMOS_CFLAGS = $(AM_CFLAGS) @XCB_CFLAGS@
noinst_PROGRAMS += $(vkd3d_demos) noinst_PROGRAMS += $(vkd3d_demos)

View File

@ -95,14 +95,6 @@ AC_CHECK_LIB([dl], [dlopen],
AC_ARG_VAR([PTHREAD_LIBS], [linker flags for pthreads]) AC_ARG_VAR([PTHREAD_LIBS], [linker flags for pthreads])
VKD3D_CHECK_PTHREAD VKD3D_CHECK_PTHREAD
AC_SUBST([VULKAN_LIBS])
VKD3D_CHECK_SONAME([vulkan], [vkGetInstanceProcAddr],
[VULKAN_LIBS="-lvulkan"],
[VKD3D_CHECK_SONAME([MoltenVK], [vkGetInstanceProcAddr],
[VULKAN_LIBS="-lMoltenVK"
AC_DEFINE_UNQUOTED([SONAME_LIBVULKAN],["$ac_cv_lib_soname_MoltenVK"])],
[AC_MSG_ERROR([libvulkan and libMoltenVK not found.])])])
AS_IF([test "x$with_spirv_tools" = "xyes"], AS_IF([test "x$with_spirv_tools" = "xyes"],
[PKG_CHECK_MODULES([SPIRV_TOOLS], [SPIRV-Tools-shared], [PKG_CHECK_MODULES([SPIRV_TOOLS], [SPIRV-Tools-shared],
[AC_DEFINE([HAVE_SPIRV_TOOLS], [1], [Define to 1 if you have SPIRV-Tools.])])], [AC_DEFINE([HAVE_SPIRV_TOOLS], [1], [Define to 1 if you have SPIRV-Tools.])])],

View File

@ -20,6 +20,7 @@
#define VK_USE_PLATFORM_XCB_KHR #define VK_USE_PLATFORM_XCB_KHR
#include <vkd3d.h> #include <vkd3d.h>
#include <vkd3d_utils.h> #include <vkd3d_utils.h>
#include <vkd3d_sonames.h>
#include <xcb/xcb_event.h> #include <xcb/xcb_event.h>
#include <xcb/xcb_icccm.h> #include <xcb/xcb_icccm.h>
#include <xcb/xcb_keysyms.h> #include <xcb/xcb_keysyms.h>
@ -28,6 +29,24 @@
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdbool.h> #include <stdbool.h>
#include <dlfcn.h>
#define SYMBOL(x) static PFN_vk##x x
SYMBOL(CreateXcbSurfaceKHR);
SYMBOL(GetPhysicalDeviceSurfaceSupportKHR);
SYMBOL(GetPhysicalDeviceSurfaceCapabilitiesKHR);
SYMBOL(GetPhysicalDeviceSurfaceFormatsKHR);
SYMBOL(CreateSwapchainKHR);
SYMBOL(CreateFence);
SYMBOL(GetSwapchainImagesKHR);
SYMBOL(AcquireNextImageKHR);
SYMBOL(WaitForFences);
SYMBOL(ResetFences);
SYMBOL(DestroyFence);
SYMBOL(DestroySurfaceKHR);
SYMBOL(QueuePresentKHR);
SYMBOL(DestroySwapchainKHR);
#undef SYMBOL
struct demo struct demo
{ {
@ -43,6 +62,7 @@ struct demo
void *user_data; void *user_data;
void (*idle_func)(struct demo *demo, void *user_data); void (*idle_func)(struct demo *demo, void *user_data);
}; };
struct demo_window struct demo_window
@ -70,6 +90,29 @@ struct demo_swapchain
ID3D12Resource *buffers[1]; ID3D12Resource *buffers[1];
}; };
static inline void init_symbols(VkInstance instance)
{
PFN_vkGetInstanceProcAddr gpa;
void *handle = dlopen(SONAME_LIBVULKAN, RTLD_LAZY);
gpa = (PFN_vkGetInstanceProcAddr)dlsym(handle, "vkGetInstanceProcAddr");
#define SYMBOL(x) x = (PFN_vk##x)gpa(instance, "vk" #x)
SYMBOL(CreateXcbSurfaceKHR);
SYMBOL(GetPhysicalDeviceSurfaceSupportKHR);
SYMBOL(GetPhysicalDeviceSurfaceCapabilitiesKHR);
SYMBOL(GetPhysicalDeviceSurfaceFormatsKHR);
SYMBOL(CreateSwapchainKHR);
SYMBOL(CreateFence);
SYMBOL(GetSwapchainImagesKHR);
SYMBOL(AcquireNextImageKHR);
SYMBOL(WaitForFences);
SYMBOL(ResetFences);
SYMBOL(DestroySurfaceKHR);
SYMBOL(DestroyFence);
SYMBOL(QueuePresentKHR);
SYMBOL(DestroySwapchainKHR);
#undef SYMBOL
}
static inline xcb_atom_t demo_get_atom(xcb_connection_t *c, const char *name) static inline xcb_atom_t demo_get_atom(xcb_connection_t *c, const char *name)
{ {
xcb_intern_atom_cookie_t cookie; xcb_intern_atom_cookie_t cookie;
@ -339,23 +382,25 @@ static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *c
vk_physical_device = vkd3d_get_vk_physical_device(d3d12_device); vk_physical_device = vkd3d_get_vk_physical_device(d3d12_device);
vk_device = vkd3d_get_vk_device(d3d12_device); vk_device = vkd3d_get_vk_device(d3d12_device);
init_symbols(vk_instance);
surface_desc.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; surface_desc.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
surface_desc.pNext = NULL; surface_desc.pNext = NULL;
surface_desc.flags = 0; surface_desc.flags = 0;
surface_desc.connection = window->demo->connection; surface_desc.connection = window->demo->connection;
surface_desc.window = window->window; surface_desc.window = window->window;
if (vkCreateXcbSurfaceKHR(vk_instance, &surface_desc, NULL, &vk_surface) < 0) if (CreateXcbSurfaceKHR(vk_instance, &surface_desc, NULL, &vk_surface) < 0)
{ {
ID3D12Device_Release(d3d12_device); ID3D12Device_Release(d3d12_device);
return NULL; return NULL;
} }
queue_family_index = vkd3d_get_vk_queue_family_index(command_queue); queue_family_index = vkd3d_get_vk_queue_family_index(command_queue);
if (vkGetPhysicalDeviceSurfaceSupportKHR(vk_physical_device, if (GetPhysicalDeviceSurfaceSupportKHR(vk_physical_device,
queue_family_index, vk_surface, &supported) < 0 || !supported) queue_family_index, vk_surface, &supported) < 0 || !supported)
goto fail; goto fail;
if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device, vk_surface, &surface_caps) < 0) if (GetPhysicalDeviceSurfaceCapabilitiesKHR(vk_physical_device, vk_surface, &surface_caps) < 0)
goto fail; goto fail;
if ((surface_caps.maxImageCount && desc->buffer_count > surface_caps.maxImageCount) if ((surface_caps.maxImageCount && desc->buffer_count > surface_caps.maxImageCount)
@ -365,11 +410,11 @@ static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *c
|| !(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)) || !(surface_caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR))
goto fail; goto fail;
if (vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, NULL) < 0 if (GetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, NULL) < 0
|| !format_count || !(formats = calloc(format_count, sizeof(*formats)))) || !format_count || !(formats = calloc(format_count, sizeof(*formats))))
goto fail; goto fail;
if (vkGetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, formats) < 0) if (GetPhysicalDeviceSurfaceFormatsKHR(vk_physical_device, vk_surface, &format_count, formats) < 0)
{ {
free(formats); free(formats);
goto fail; goto fail;
@ -413,20 +458,20 @@ static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *c
vk_swapchain_desc.presentMode = VK_PRESENT_MODE_FIFO_KHR; vk_swapchain_desc.presentMode = VK_PRESENT_MODE_FIFO_KHR;
vk_swapchain_desc.clipped = VK_TRUE; vk_swapchain_desc.clipped = VK_TRUE;
vk_swapchain_desc.oldSwapchain = VK_NULL_HANDLE; vk_swapchain_desc.oldSwapchain = VK_NULL_HANDLE;
if (vkCreateSwapchainKHR(vk_device, &vk_swapchain_desc, NULL, &vk_swapchain) < 0) if (CreateSwapchainKHR(vk_device, &vk_swapchain_desc, NULL, &vk_swapchain) < 0)
goto fail; goto fail;
fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fence_desc.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_desc.pNext = NULL; fence_desc.pNext = NULL;
fence_desc.flags = 0; fence_desc.flags = 0;
if (vkCreateFence(vk_device, &fence_desc, NULL, &vk_fence) < 0) if (CreateFence(vk_device, &fence_desc, NULL, &vk_fence) < 0)
goto fail; goto fail;
if (vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, NULL) < 0 if (GetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, NULL) < 0
|| !(vk_images = calloc(image_count, sizeof(*vk_images)))) || !(vk_images = calloc(image_count, sizeof(*vk_images))))
goto fail; goto fail;
if (vkGetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, vk_images) < 0) if (GetSwapchainImagesKHR(vk_device, vk_swapchain, &image_count, vk_images) < 0)
{ {
free(vk_images); free(vk_images);
goto fail; goto fail;
@ -443,10 +488,10 @@ static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *c
swapchain->vk_instance = vk_instance; swapchain->vk_instance = vk_instance;
swapchain->vk_device = vk_device; swapchain->vk_device = vk_device;
vkAcquireNextImageKHR(vk_device, vk_swapchain, UINT64_MAX, AcquireNextImageKHR(vk_device, vk_swapchain, UINT64_MAX,
VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer); VK_NULL_HANDLE, vk_fence, &swapchain->current_buffer);
vkWaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX); WaitForFences(vk_device, 1, &vk_fence, VK_TRUE, UINT64_MAX);
vkResetFences(vk_device, 1, &vk_fence); ResetFences(vk_device, 1, &vk_fence);
resource_create_info.type = VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO; resource_create_info.type = VKD3D_STRUCTURE_TYPE_IMAGE_RESOURCE_CREATE_INFO;
resource_create_info.next = NULL; resource_create_info.next = NULL;
@ -487,10 +532,10 @@ static inline struct demo_swapchain *demo_swapchain_create(ID3D12CommandQueue *c
fail: fail:
if (vk_fence != VK_NULL_HANDLE) if (vk_fence != VK_NULL_HANDLE)
vkDestroyFence(vk_device, vk_fence, NULL); DestroyFence(vk_device, vk_fence, NULL);
if (vk_swapchain != VK_NULL_HANDLE) if (vk_swapchain != VK_NULL_HANDLE)
vkDestroySwapchainKHR(vk_device, vk_swapchain, NULL); DestroySwapchainKHR(vk_device, vk_swapchain, NULL);
vkDestroySurfaceKHR(vk_instance, vk_surface, NULL); DestroySurfaceKHR(vk_instance, vk_surface, NULL);
ID3D12Device_Release(d3d12_device); ID3D12Device_Release(d3d12_device);
return NULL; return NULL;
} }
@ -525,13 +570,13 @@ static inline void demo_swapchain_present(struct demo_swapchain *swapchain)
present_desc.pResults = NULL; present_desc.pResults = NULL;
vk_queue = vkd3d_acquire_vk_queue(swapchain->command_queue); vk_queue = vkd3d_acquire_vk_queue(swapchain->command_queue);
vkQueuePresentKHR(vk_queue, &present_desc); QueuePresentKHR(vk_queue, &present_desc);
vkd3d_release_vk_queue(swapchain->command_queue); vkd3d_release_vk_queue(swapchain->command_queue);
vkAcquireNextImageKHR(swapchain->vk_device, swapchain->vk_swapchain, UINT64_MAX, AcquireNextImageKHR(swapchain->vk_device, swapchain->vk_swapchain, UINT64_MAX,
VK_NULL_HANDLE, swapchain->vk_fence, &swapchain->current_buffer); VK_NULL_HANDLE, swapchain->vk_fence, &swapchain->current_buffer);
vkWaitForFences(swapchain->vk_device, 1, &swapchain->vk_fence, VK_TRUE, UINT64_MAX); WaitForFences(swapchain->vk_device, 1, &swapchain->vk_fence, VK_TRUE, UINT64_MAX);
vkResetFences(swapchain->vk_device, 1, &swapchain->vk_fence); ResetFences(swapchain->vk_device, 1, &swapchain->vk_fence);
} }
static inline void demo_swapchain_destroy(struct demo_swapchain *swapchain) static inline void demo_swapchain_destroy(struct demo_swapchain *swapchain)
@ -543,9 +588,9 @@ static inline void demo_swapchain_destroy(struct demo_swapchain *swapchain)
{ {
ID3D12Resource_Release(swapchain->buffers[i]); ID3D12Resource_Release(swapchain->buffers[i]);
} }
vkDestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL); DestroyFence(swapchain->vk_device, swapchain->vk_fence, NULL);
vkDestroySwapchainKHR(swapchain->vk_device, swapchain->vk_swapchain, NULL); DestroySwapchainKHR(swapchain->vk_device, swapchain->vk_swapchain, NULL);
vkDestroySurfaceKHR(swapchain->vk_instance, swapchain->vk_surface, NULL); DestroySurfaceKHR(swapchain->vk_instance, swapchain->vk_surface, NULL);
free(swapchain); free(swapchain);
} }

35
include/vkd3d_sonames.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright 2020 Hans-Kristian Arntzen for Valve Corporation
*
* 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 __VKD3D_SONAMES_H
#define __VKD3D_SONAMES_H
/* These sonames are defined by the loader ABI. */
#if defined(_WIN32)
#define SONAME_LIBVULKAN "vulkan-1.dll"
#elif defined(__linux__)
#define SONAME_LIBVULKAN "libvulkan.so.1"
#elif defined(__APPLE__)
#define SONAME_LIBVULKAN "libvulkan.1.dylib"
#else
#error "Unrecognized platform."
#endif
#endif

View File

@ -17,6 +17,7 @@
*/ */
#include "vkd3d_private.h" #include "vkd3d_private.h"
#include "vkd3d_sonames.h"
#ifdef HAVE_DLFCN_H #ifdef HAVE_DLFCN_H
#include <dlfcn.h> #include <dlfcn.h>

View File

@ -58,6 +58,7 @@ typedef int HRESULT;
# include "vkd3d_threads.h" # include "vkd3d_threads.h"
# include "vkd3d.h" # include "vkd3d.h"
# include "vkd3d_utils.h" # include "vkd3d_utils.h"
# include "vkd3d_sonames.h"
#endif #endif
#if !defined(_WIN32) #if !defined(_WIN32)
@ -418,7 +419,7 @@ static bool init_vulkan_loader(void)
return true; return true;
#ifdef _WIN32 #ifdef _WIN32
HMODULE mod = LoadLibrary(SONAME_LIBVULKAN); HMODULE mod = LoadLibraryA(SONAME_LIBVULKAN);
if (!mod) if (!mod)
return false; return false;