[native] Dynamically load SDL2/GLFW at runtime.

Removing these link-time dependencies is important for making a single binary that is compatible with either backend, regardless of whether or not each one is currently available to the program.
This commit is contained in:
Ethan Lee 2023-12-08 00:59:23 -05:00 committed by Joshie
parent 0f7c1f753a
commit 10b83d184b
7 changed files with 118 additions and 16 deletions

View File

@ -1,9 +1,37 @@
#include "wsi_platform_glfw.h"
#include "../../util/util_error.h"
#include "../../util/util_string.h"
#include "../../util/util_win32_compat.h"
namespace dxvk::wsi {
GlfwWsiDriver::GlfwWsiDriver() {
libglfw = LoadLibraryA( // FIXME: Get soname as string from meson
#if defined(_WIN32)
"glfw.dll"
#elif defined(__APPLE__)
"libglfw.3.dylib"
#else
"libglfw.so.3"
#endif
);
if (libglfw == nullptr)
throw DxvkError("GLFW WSI: Failed to load GLFW DLL.");
#define GLFW_PROC(ret, name, params) \
name = reinterpret_cast<pfn_##name>(GetProcAddress(libglfw, #name)); \
if (name == nullptr) { \
FreeLibrary(libglfw); \
libglfw = nullptr; \
throw DxvkError("GLFW WSI: Failed to load " #name "."); \
}
#include "wsi_platform_glfw_funcs.h"
}
GlfwWsiDriver::~GlfwWsiDriver() {
FreeLibrary(libglfw);
}
std::vector<const char *> GlfwWsiDriver::getInstanceExtensions() {
if (!glfwVulkanSupported())
throw DxvkError(str::format("GLFW WSI: Vulkan is not supported in any capacity!"));

View File

@ -8,7 +8,24 @@
namespace dxvk::wsi {
class GlfwWsiDriver : public WsiDriver {
private:
HMODULE libglfw;
#define GLFW_PROC(ret, name, params) \
typedef ret (*pfn_##name) params; \
pfn_##name name;
#include "wsi_platform_glfw_funcs.h"
inline bool isDisplayValid(int32_t displayId) {
int32_t displayCount = 0;
glfwGetMonitors(&displayCount);
return displayId < displayCount && displayId >= 0;
}
public:
GlfwWsiDriver();
~GlfwWsiDriver();
// Platform
virtual std::vector<const char *> getInstanceExtensions();
@ -89,12 +106,5 @@ namespace dxvk::wsi {
VkInstance instance,
VkSurfaceKHR* pSurface);
};
inline bool isDisplayValid(int32_t displayId) {
int32_t displayCount = 0;
glfwGetMonitors(&displayCount);
return displayId < displayCount && displayId >= 0;
}
}

View File

@ -0,0 +1,12 @@
GLFW_PROC(VkResult, glfwCreateWindowSurface, (VkInstance, GLFWwindow*, const VkAllocationCallbacks*, VkSurfaceKHR*))
GLFW_PROC(GLFWmonitor**, glfwGetMonitors, (int*))
GLFW_PROC(void, glfwGetMonitorWorkarea, (GLFWmonitor*, int*, int*, int*, int*))
GLFW_PROC(GLFWmonitor*, glfwGetPrimaryMonitor, (void))
GLFW_PROC(const char**, glfwGetRequiredInstanceExtensions, (uint32_t*))
GLFW_PROC(const GLFWvidmode*, glfwGetVideoMode, (GLFWmonitor*))
GLFW_PROC(const GLFWvidmode*, glfwGetVideoModes, (GLFWmonitor*, int*))
GLFW_PROC(void, glfwGetWindowSize, (GLFWwindow*, int*, int*))
GLFW_PROC(void, glfwSetWindowMonitor, (GLFWwindow*, GLFWmonitor*, int, int, int, int, int))
GLFW_PROC(void, glfwSetWindowSize, (GLFWwindow*, int, int))
GLFW_PROC(int, glfwVulkanSupported, (void))
#undef GLFW_PROC

View File

@ -23,16 +23,14 @@ wsi_glfw_src = [
if dxvk_wsi == 'win32'
wsi_src = wsi_common_src + wsi_win32_src
wsi_deps = [ dep_displayinfo ]
elif dxvk_wsi == 'sdl2'
wsi_src = wsi_common_src + wsi_sdl2_src
wsi_deps = [ dep_displayinfo, lib_sdl2 ]
elif dxvk_wsi == 'glfw'
wsi_src = wsi_common_src + wsi_glfw_src
wsi_deps = [ dep_displayinfo, lib_glfw ]
else
error('Unknown wsi')
endif
wsi_deps = [ dep_displayinfo ]
wsi_lib = static_library('wsi', wsi_src,
dependencies : wsi_deps,

View File

@ -1,11 +1,39 @@
#include "wsi_platform_sdl2.h"
#include "../../util/util_error.h"
#include "../../util/util_string.h"
#include "../../util/util_win32_compat.h"
#include <SDL2/SDL_vulkan.h>
namespace dxvk::wsi {
Sdl2WsiDriver::Sdl2WsiDriver() {
libsdl = LoadLibraryA( // FIXME: Get soname as string from meson
#if defined(_WIN32)
"SDL2.dll"
#elif defined(__APPLE__)
"libSDL2-2.0.0.dylib"
#else
"libSDL2-2.0.so.0"
#endif
);
if (libsdl == nullptr)
throw DxvkError("SDL2 WSI: Failed to load SDL2 DLL.");
#define SDL_PROC(ret, name, params) \
name = reinterpret_cast<pfn_##name>(GetProcAddress(libsdl, #name)); \
if (name == nullptr) { \
FreeLibrary(libsdl); \
libsdl = nullptr; \
throw DxvkError("SDL2 WSI: Failed to load " #name "."); \
}
#include "wsi_platform_sdl2_funcs.h"
}
Sdl2WsiDriver::~Sdl2WsiDriver() {
FreeLibrary(libsdl);
}
std::vector<const char *> Sdl2WsiDriver::getInstanceExtensions() {
SDL_Vulkan_LoadLibrary(nullptr);

View File

@ -7,7 +7,23 @@
namespace dxvk::wsi {
class Sdl2WsiDriver : public WsiDriver {
private:
HMODULE libsdl;
#define SDL_PROC(ret, name, params) \
typedef ret (SDLCALL *pfn_##name) params; \
pfn_##name name;
#include "wsi_platform_sdl2_funcs.h"
inline bool isDisplayValid(int32_t displayId) {
const int32_t displayCount = SDL_GetNumVideoDisplays();
return displayId < displayCount && displayId >= 0;
}
public:
Sdl2WsiDriver();
~Sdl2WsiDriver();
// Platform
virtual std::vector<const char *> getInstanceExtensions();
@ -88,11 +104,5 @@ namespace dxvk::wsi {
VkInstance instance,
VkSurfaceKHR* pSurface);
};
inline bool isDisplayValid(int32_t displayId) {
const int32_t displayCount = SDL_GetNumVideoDisplays();
return displayId < displayCount && displayId >= 0;
}
}

View File

@ -0,0 +1,16 @@
SDL_PROC(SDL_DisplayMode*, SDL_GetClosestDisplayMode, (int, const SDL_DisplayMode*, SDL_DisplayMode*))
SDL_PROC(int, SDL_GetCurrentDisplayMode, (int, SDL_DisplayMode*))
SDL_PROC(int, SDL_GetDesktopDisplayMode, (int, SDL_DisplayMode*))
SDL_PROC(int, SDL_GetDisplayBounds, (int, SDL_Rect*))
SDL_PROC(int, SDL_GetDisplayMode, (int, int, SDL_DisplayMode*))
SDL_PROC(const char*, SDL_GetError, (void))
SDL_PROC(int, SDL_GetNumVideoDisplays, (void))
SDL_PROC(int, SDL_GetWindowDisplayIndex, (SDL_Window*))
SDL_PROC(int, SDL_SetWindowDisplayMode, (SDL_Window*, const SDL_DisplayMode*))
SDL_PROC(int, SDL_SetWindowFullscreen, (SDL_Window*, Uint32))
SDL_PROC(void, SDL_GetWindowSize, (SDL_Window*, int*, int*))
SDL_PROC(void, SDL_SetWindowSize, (SDL_Window*, int, int))
SDL_PROC(SDL_bool, SDL_Vulkan_CreateSurface, (SDL_Window*, VkInstance, VkSurfaceKHR*))
SDL_PROC(SDL_bool, SDL_Vulkan_GetInstanceExtensions, (SDL_Window*, unsigned int*, const char**))
SDL_PROC(int, SDL_Vulkan_LoadLibrary, (const char*))
#undef SDL_PROC