[native] Load SDL via dlopen instead of linking to libSDL2

This commit is contained in:
Ethan Lee 2023-12-06 15:29:45 -05:00
parent 7641260500
commit e97dbfa443
6 changed files with 93 additions and 28 deletions

View File

@ -9,6 +9,7 @@ wsi_win32_src = [
wsi_sdl2_src = [
'sdl2/wsi_monitor_sdl2.cpp',
'sdl2/wsi_platform_sdl2.cpp',
'sdl2/wsi_window_sdl2.cpp',
]
@ -22,7 +23,7 @@ if dxvk_wsi == 'win32'
wsi_deps = [ dep_displayinfo ]
elif dxvk_wsi == 'sdl2'
wsi_src = wsi_common_src + wsi_sdl2_src
wsi_deps = [ dep_displayinfo, lib_sdl2 ]
wsi_deps = [ dep_displayinfo ]
elif dxvk_wsi == 'glfw'
wsi_src = wsi_common_src + wsi_glfw_src
wsi_deps = [ dep_displayinfo, lib_glfw ]

View File

@ -56,7 +56,7 @@ namespace dxvk::wsi {
return false;
SDL_Rect rect = { };
SDL_GetDisplayBounds(displayId, &rect);
WsiLibrary::get()->SDL_GetDisplayBounds(displayId, &rect);
pRect->left = rect.x;
pRect->top = rect.y;
@ -100,7 +100,7 @@ namespace dxvk::wsi {
return false;
SDL_DisplayMode mode = { };
if (SDL_GetDisplayMode(displayId, ModeNumber, &mode) != 0)
if (WsiLibrary::get()->SDL_GetDisplayMode(displayId, ModeNumber, &mode) != 0)
return false;
convertMode(mode, pMode);
@ -118,8 +118,8 @@ namespace dxvk::wsi {
return false;
SDL_DisplayMode mode = { };
if (SDL_GetCurrentDisplayMode(displayId, &mode) != 0) {
Logger::err(str::format("SDL_GetCurrentDisplayMode: ", SDL_GetError()));
if (WsiLibrary::get()->SDL_GetCurrentDisplayMode(displayId, &mode) != 0) {
Logger::err(str::format("SDL_GetCurrentDisplayMode: ", WsiLibrary::get()->SDL_GetError()));
return false;
}
@ -138,8 +138,8 @@ namespace dxvk::wsi {
return false;
SDL_DisplayMode mode = { };
if (SDL_GetDesktopDisplayMode(displayId, &mode) != 0) {
Logger::err(str::format("SDL_GetCurrentDisplayMode: ", SDL_GetError()));
if (WsiLibrary::get()->SDL_GetDesktopDisplayMode(displayId, &mode) != 0) {
Logger::err(str::format("SDL_GetCurrentDisplayMode: ", WsiLibrary::get()->SDL_GetError()));
return false;
}

View File

@ -0,0 +1,34 @@
#include "wsi_platform_sdl2.h"
#include "../util/util_win32_compat.h"
namespace dxvk::wsi {
WsiLibrary *WsiLibrary::s_instance = nullptr;
WsiLibrary *WsiLibrary::get() {
if (s_instance != nullptr)
return s_instance;
s_instance = new WsiLibrary();
// FIXME: When do we free this...?
s_instance->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 (s_instance->libsdl == nullptr)
throw DxvkError("SDL2 WSI: Failed to load SDL2 DLL.");
#define SDL_PROC(ret, name, params) \
s_instance->name = reinterpret_cast<pfn_##name>(GetProcAddress(s_instance->libsdl, #name)); \
if (s_instance->name == nullptr) \
throw DxvkError("SDL2 WSI: Failed to load " #name ".");
#include "wsi_platform_sdl2_funcs.h"
return s_instance;
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_vulkan.h>
#include "../wsi_monitor.h"
@ -12,10 +13,24 @@ namespace dxvk::wsi {
struct DxvkWindowState {
};
struct WsiLibrary {
private:
static WsiLibrary *s_instance;
HMODULE libsdl;
public:
static WsiLibrary *get();
#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();
const int32_t displayCount = WsiLibrary::get()->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

View File

@ -7,7 +7,6 @@
#include "../../util/log/log.h"
#include <windows.h>
#include <SDL2/SDL_vulkan.h>
namespace dxvk::wsi {
@ -18,7 +17,7 @@ namespace dxvk::wsi {
SDL_Window* window = fromHwnd(hWindow);
int32_t w, h;
SDL_GetWindowSize(window, &w, &h);
WsiLibrary::get()->SDL_GetWindowSize(window, &w, &h);
if (pWidth)
*pWidth = uint32_t(w);
@ -35,7 +34,7 @@ namespace dxvk::wsi {
uint32_t Height) {
SDL_Window* window = fromHwnd(hWindow);
SDL_SetWindowSize(window, int32_t(Width), int32_t(Height));
WsiLibrary::get()->SDL_SetWindowSize(window, int32_t(Width), int32_t(Height));
}
@ -58,13 +57,13 @@ namespace dxvk::wsi {
// TODO: Implement lookup format for bitsPerPixel here.
SDL_DisplayMode mode = { };
if (SDL_GetClosestDisplayMode(displayId, &wantedMode, &mode) == nullptr) {
Logger::err(str::format("SDL2 WSI: setWindowMode: SDL_GetClosestDisplayMode: ", SDL_GetError()));
if (WsiLibrary::get()->SDL_GetClosestDisplayMode(displayId, &wantedMode, &mode) == nullptr) {
Logger::err(str::format("SDL2 WSI: setWindowMode: SDL_GetClosestDisplayMode: ", WsiLibrary::get()->SDL_GetError()));
return false;
}
if (SDL_SetWindowDisplayMode(window, &mode) != 0) {
Logger::err(str::format("SDL2 WSI: setWindowMode: SDL_SetWindowDisplayMode: ", SDL_GetError()));
if (WsiLibrary::get()->SDL_SetWindowDisplayMode(window, &mode) != 0) {
Logger::err(str::format("SDL2 WSI: setWindowMode: SDL_SetWindowDisplayMode: ", WsiLibrary::get()->SDL_GetError()));
return false;
}
@ -90,8 +89,8 @@ namespace dxvk::wsi {
// TODO: Set this on the correct monitor.
// Docs aren't clear on this...
if (SDL_SetWindowFullscreen(window, flags) != 0) {
Logger::err(str::format("SDL2 WSI: enterFullscreenMode: SDL_SetWindowFullscreen: ", SDL_GetError()));
if (WsiLibrary::get()->SDL_SetWindowFullscreen(window, flags) != 0) {
Logger::err(str::format("SDL2 WSI: enterFullscreenMode: SDL_SetWindowFullscreen: ", WsiLibrary::get()->SDL_GetError()));
return false;
}
@ -105,8 +104,8 @@ namespace dxvk::wsi {
bool restoreCoordinates) {
SDL_Window* window = fromHwnd(hWindow);
if (SDL_SetWindowFullscreen(window, 0) != 0) {
Logger::err(str::format("SDL2 WSI: leaveFullscreenMode: SDL_SetWindowFullscreen: ", SDL_GetError()));
if (WsiLibrary::get()->SDL_SetWindowFullscreen(window, 0) != 0) {
Logger::err(str::format("SDL2 WSI: leaveFullscreenMode: SDL_SetWindowFullscreen: ", WsiLibrary::get()->SDL_GetError()));
return false;
}
@ -122,7 +121,7 @@ namespace dxvk::wsi {
HMONITOR getWindowMonitor(HWND hWindow) {
SDL_Window* window = fromHwnd(hWindow);
const int32_t displayId = SDL_GetWindowDisplayIndex(window);
const int32_t displayId = WsiLibrary::get()->SDL_GetWindowDisplayIndex(window);
return toHmonitor(displayId);
}
@ -149,22 +148,22 @@ namespace dxvk::wsi {
VkSurfaceKHR* pSurface) {
SDL_Window* window = fromHwnd(hWindow);
return SDL_Vulkan_CreateSurface(window, instance, pSurface)
return WsiLibrary::get()->SDL_Vulkan_CreateSurface(window, instance, pSurface)
? VK_SUCCESS
: VK_ERROR_OUT_OF_HOST_MEMORY;
}
std::vector<const char *> getInstanceExtensions() {
SDL_Vulkan_LoadLibrary(nullptr);
WsiLibrary::get()->SDL_Vulkan_LoadLibrary(nullptr);
uint32_t extensionCount = 0;
if (!SDL_Vulkan_GetInstanceExtensions(nullptr, &extensionCount, nullptr))
throw DxvkError(str::format("SDL2 WSI: Failed to get instance extension count. ", SDL_GetError()));
if (!WsiLibrary::get()->SDL_Vulkan_GetInstanceExtensions(nullptr, &extensionCount, nullptr))
throw DxvkError(str::format("SDL2 WSI: Failed to get instance extension count. ", WsiLibrary::get()->SDL_GetError()));
auto extensionNames = std::vector<const char *>(extensionCount);
if (!SDL_Vulkan_GetInstanceExtensions(nullptr, &extensionCount, extensionNames.data()))
throw DxvkError(str::format("SDL2 WSI: Failed to get instance extensions. ", SDL_GetError()));
if (!WsiLibrary::get()->SDL_Vulkan_GetInstanceExtensions(nullptr, &extensionCount, extensionNames.data()))
throw DxvkError(str::format("SDL2 WSI: Failed to get instance extensions. ", WsiLibrary::get()->SDL_GetError()));
return extensionNames;
}