From 2fa2531a2f3095d91698d018e1dcc07637387627 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Thu, 7 Dec 2023 23:57:02 -0500 Subject: [PATCH 01/12] [wsi] Add init/quit functions, integrate them into DxvkInstance. This is preparation for loading/unloading WSI backends at runtime, which will be in an upcoming commit. --- src/dxvk/dxvk_instance.cpp | 5 +++++ src/wsi/meson.build | 1 + src/wsi/wsi_platform.cpp | 11 +++++++++++ src/wsi/wsi_platform.h | 7 +++++++ 4 files changed, 24 insertions(+) create mode 100644 src/wsi/wsi_platform.cpp diff --git a/src/dxvk/dxvk_instance.cpp b/src/dxvk/dxvk_instance.cpp index e86896d8..12785183 100644 --- a/src/dxvk/dxvk_instance.cpp +++ b/src/dxvk/dxvk_instance.cpp @@ -4,6 +4,7 @@ #include "dxvk_openvr.h" #include "dxvk_openxr.h" #include "dxvk_platform_exts.h" +#include "../wsi/wsi_platform.h" #include #include @@ -20,6 +21,8 @@ namespace dxvk { Logger::info(str::format("Game: ", env::getExeName())); Logger::info(str::format("DXVK: ", DXVK_VERSION)); + wsi::init(); + m_config = Config::getUserConfig(); m_config.merge(Config::getAppConfig(env::getExePath())); m_config.logOptions(); @@ -64,6 +67,8 @@ namespace dxvk { DxvkInstance::~DxvkInstance() { if (m_messenger) m_vki->vkDestroyDebugUtilsMessengerEXT(m_vki->instance(), m_messenger, nullptr); + + wsi::quit(); } diff --git a/src/wsi/meson.build b/src/wsi/meson.build index 27603cea..372ae037 100644 --- a/src/wsi/meson.build +++ b/src/wsi/meson.build @@ -1,5 +1,6 @@ wsi_common_src = [ 'wsi_edid.cpp', + 'wsi_platform.cpp', ] wsi_win32_src = [ diff --git a/src/wsi/wsi_platform.cpp b/src/wsi/wsi_platform.cpp new file mode 100644 index 00000000..56cd6c45 --- /dev/null +++ b/src/wsi/wsi_platform.cpp @@ -0,0 +1,11 @@ +#include "wsi_platform.h" + +namespace dxvk::wsi { + + void init() { + } + + void quit() { + } + +} diff --git a/src/wsi/wsi_platform.h b/src/wsi/wsi_platform.h index 38b5c5aa..0c94a3fa 100644 --- a/src/wsi/wsi_platform.h +++ b/src/wsi/wsi_platform.h @@ -7,3 +7,10 @@ #elif defined(DXVK_WSI_GLFW) #include "glfw/wsi_platform_glfw.h" #endif + +namespace dxvk::wsi { + + void init(); + void quit(); + +} From e6cb4d9868e8670b40274d098942101d3d819e66 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Fri, 8 Dec 2023 00:09:56 -0500 Subject: [PATCH 02/12] [dxvk] Move getInstanceExtensions platform logic to wsi. This ensures that all of the WSI backend logic is in one place rather than two. --- ..._win32_exts.cpp => dxvk_platform_exts.cpp} | 12 +++-- src/dxvk/meson.build | 15 +----- src/dxvk/platform/dxvk_glfw_exts.cpp | 49 ------------------ src/dxvk/platform/dxvk_sdl2_exts.cpp | 50 ------------------- src/wsi/glfw/wsi_platform_glfw.cpp | 25 ++++++++++ src/wsi/meson.build | 3 ++ src/wsi/sdl2/wsi_platform_sdl2.cpp | 23 +++++++++ src/wsi/win32/wsi_platform_win32.cpp | 9 ++++ src/wsi/wsi_platform.h | 3 ++ 9 files changed, 72 insertions(+), 117 deletions(-) rename src/dxvk/{platform/dxvk_win32_exts.cpp => dxvk_platform_exts.cpp} (67%) delete mode 100644 src/dxvk/platform/dxvk_glfw_exts.cpp delete mode 100644 src/dxvk/platform/dxvk_sdl2_exts.cpp create mode 100644 src/wsi/glfw/wsi_platform_glfw.cpp create mode 100644 src/wsi/sdl2/wsi_platform_sdl2.cpp create mode 100644 src/wsi/win32/wsi_platform_win32.cpp diff --git a/src/dxvk/platform/dxvk_win32_exts.cpp b/src/dxvk/dxvk_platform_exts.cpp similarity index 67% rename from src/dxvk/platform/dxvk_win32_exts.cpp rename to src/dxvk/dxvk_platform_exts.cpp index 25c81cc5..a1a7adea 100644 --- a/src/dxvk/platform/dxvk_win32_exts.cpp +++ b/src/dxvk/dxvk_platform_exts.cpp @@ -1,17 +1,21 @@ -#include "../dxvk_platform_exts.h" +#include "dxvk_platform_exts.h" +#include "../wsi/wsi_platform.h" namespace dxvk { DxvkPlatformExts DxvkPlatformExts::s_instance; std::string_view DxvkPlatformExts::getName() { - return "Win32 WSI"; + return "Platform WSI"; } DxvkNameSet DxvkPlatformExts::getInstanceExtensions() { + std::vector extensionNames = wsi::getInstanceExtensions(); + DxvkNameSet names; - names.add(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); + for (const char* name : extensionNames) + names.add(name); return names; } @@ -33,4 +37,4 @@ namespace dxvk { } -} \ No newline at end of file +} diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index c8fa9bda..78ff2ecf 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -89,6 +89,7 @@ dxvk_src = [ 'dxvk_options.cpp', 'dxvk_pipelayout.cpp', 'dxvk_pipemanager.cpp', + 'dxvk_platform_exts.cpp', 'dxvk_presenter.cpp', 'dxvk_queue.cpp', 'dxvk_resource.cpp', @@ -117,20 +118,6 @@ if platform == 'windows' ] endif -if dxvk_wsi == 'win32' - dxvk_src += [ - 'platform/dxvk_win32_exts.cpp' - ] -elif dxvk_wsi == 'sdl2' - dxvk_src += [ - 'platform/dxvk_sdl2_exts.cpp' - ] -elif dxvk_wsi == 'glfw' - dxvk_src += [ - 'platform/dxvk_glfw_exts.cpp' - ] -endif - dxvk_extra_deps = [ dependency('threads') ] if platform == 'linux' dxvk_extra_deps += [ cpp.find_library('dl', required: false) ] diff --git a/src/dxvk/platform/dxvk_glfw_exts.cpp b/src/dxvk/platform/dxvk_glfw_exts.cpp deleted file mode 100644 index f5cfee88..00000000 --- a/src/dxvk/platform/dxvk_glfw_exts.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "../dxvk_platform_exts.h" - -#include "../../vulkan/vulkan_loader.h" -#include - -namespace dxvk { - - DxvkPlatformExts DxvkPlatformExts::s_instance; - - std::string_view DxvkPlatformExts::getName() { - return "GLFW WSI"; - } - - DxvkNameSet DxvkPlatformExts::getInstanceExtensions() { - if (!glfwVulkanSupported()) - throw DxvkError(str::format("GLFW WSI: Vulkan is not supported in any capacity!")); - - uint32_t extensionCount = 0; - const char** extensionArray = glfwGetRequiredInstanceExtensions(&extensionCount); - - if (extensionCount == 0) - throw DxvkError(str::format("GLFW WSI: Failed to get required instance extensions")); - - DxvkNameSet names; - for (uint32_t i = 0; i < extensionCount; ++i) { - names.add(extensionArray[i]); - } - - return names; - } - - - DxvkNameSet DxvkPlatformExts::getDeviceExtensions( - uint32_t adapterId) { - return DxvkNameSet(); - } - - - void DxvkPlatformExts::initInstanceExtensions() { - //Nothing needs to be done here on GLFW - } - - - void DxvkPlatformExts::initDeviceExtensions( - const DxvkInstance* instance) { - //Nothing needs to be done here on GLFW - } - -} \ No newline at end of file diff --git a/src/dxvk/platform/dxvk_sdl2_exts.cpp b/src/dxvk/platform/dxvk_sdl2_exts.cpp deleted file mode 100644 index 13583aa7..00000000 --- a/src/dxvk/platform/dxvk_sdl2_exts.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "../dxvk_platform_exts.h" - -#include -#include - -namespace dxvk { - - DxvkPlatformExts DxvkPlatformExts::s_instance; - - std::string_view DxvkPlatformExts::getName() { - return "SDL2 WSI"; - } - - - DxvkNameSet DxvkPlatformExts::getInstanceExtensions() { - 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())); - - auto extensionNames = std::vector(extensionCount); - if (!SDL_Vulkan_GetInstanceExtensions(nullptr, &extensionCount, extensionNames.data())) - throw DxvkError(str::format("SDL2 WSI: Failed to get instance extensions. ", SDL_GetError())); - - DxvkNameSet names; - for (const char* name : extensionNames) - names.add(name); - - return names; - } - - - DxvkNameSet DxvkPlatformExts::getDeviceExtensions( - uint32_t adapterId) { - return DxvkNameSet(); - } - - - void DxvkPlatformExts::initInstanceExtensions() { - - } - - - void DxvkPlatformExts::initDeviceExtensions( - const DxvkInstance* instance) { - - } - -} diff --git a/src/wsi/glfw/wsi_platform_glfw.cpp b/src/wsi/glfw/wsi_platform_glfw.cpp new file mode 100644 index 00000000..d180f597 --- /dev/null +++ b/src/wsi/glfw/wsi_platform_glfw.cpp @@ -0,0 +1,25 @@ +#include "wsi_platform_glfw.h" +#include "../../util/util_error.h" +#include "../../util/util_string.h" + +namespace dxvk::wsi { + + std::vector getInstanceExtensions() { + if (!glfwVulkanSupported()) + throw DxvkError(str::format("GLFW WSI: Vulkan is not supported in any capacity!")); + + uint32_t extensionCount = 0; + const char** extensionArray = glfwGetRequiredInstanceExtensions(&extensionCount); + + if (extensionCount == 0) + throw DxvkError(str::format("GLFW WSI: Failed to get required instance extensions")); + + std::vector names(extensionCount); + for (uint32_t i = 0; i < extensionCount; ++i) { + names.push_back(extensionArray[i]); + } + + return names; + } + +} diff --git a/src/wsi/meson.build b/src/wsi/meson.build index 372ae037..1cabcf2f 100644 --- a/src/wsi/meson.build +++ b/src/wsi/meson.build @@ -5,16 +5,19 @@ wsi_common_src = [ wsi_win32_src = [ 'win32/wsi_monitor_win32.cpp', + 'win32/wsi_platform_win32.cpp', 'win32/wsi_window_win32.cpp', ] wsi_sdl2_src = [ 'sdl2/wsi_monitor_sdl2.cpp', + 'sdl2/wsi_platform_sdl2.cpp', 'sdl2/wsi_window_sdl2.cpp', ] wsi_glfw_src = [ 'glfw/wsi_monitor_glfw.cpp', + 'glfw/wsi_platform_glfw.cpp', 'glfw/wsi_window_glfw.cpp', ] diff --git a/src/wsi/sdl2/wsi_platform_sdl2.cpp b/src/wsi/sdl2/wsi_platform_sdl2.cpp new file mode 100644 index 00000000..cc8ac22b --- /dev/null +++ b/src/wsi/sdl2/wsi_platform_sdl2.cpp @@ -0,0 +1,23 @@ +#include "wsi_platform_sdl2.h" +#include "../../util/util_error.h" +#include "../../util/util_string.h" + +#include + +namespace dxvk::wsi { + + std::vector getInstanceExtensions() { + 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())); + + auto extensionNames = std::vector(extensionCount); + if (!SDL_Vulkan_GetInstanceExtensions(nullptr, &extensionCount, extensionNames.data())) + throw DxvkError(str::format("SDL2 WSI: Failed to get instance extensions. ", SDL_GetError())); + + return extensionNames; + } + +} diff --git a/src/wsi/win32/wsi_platform_win32.cpp b/src/wsi/win32/wsi_platform_win32.cpp new file mode 100644 index 00000000..8b16de56 --- /dev/null +++ b/src/wsi/win32/wsi_platform_win32.cpp @@ -0,0 +1,9 @@ +#include "wsi_platform_win32.h" + +namespace dxvk::wsi { + + std::vector getInstanceExtensions() { + return { VK_KHR_WIN32_SURFACE_EXTENSION_NAME }; + } + +} diff --git a/src/wsi/wsi_platform.h b/src/wsi/wsi_platform.h index 0c94a3fa..7ccecc27 100644 --- a/src/wsi/wsi_platform.h +++ b/src/wsi/wsi_platform.h @@ -8,9 +8,12 @@ #include "glfw/wsi_platform_glfw.h" #endif +#include + namespace dxvk::wsi { void init(); void quit(); + std::vector getInstanceExtensions(); } From 90475ca14610d466c550eef89ae0a5627c9b8133 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Fri, 8 Dec 2023 00:45:46 -0500 Subject: [PATCH 03/12] [wsi] Refactor the WSI backends to be implementations of a WsiDriver interface. Rather than directly calling functions, the API now calls shared functions that call into a WsiDriver instance, which is allocated and implemented by the backend. Functionally this should be the same, it just has the extra allocation for the function table. This prepares the WSI library for supporting multiple implementations in a single binary. --- src/wsi/glfw/wsi_monitor_glfw.cpp | 18 ++-- src/wsi/glfw/wsi_platform_glfw.cpp | 6 +- src/wsi/glfw/wsi_platform_glfw.h | 89 ++++++++++++++++-- src/wsi/glfw/wsi_window_glfw.cpp | 22 ++--- src/wsi/sdl2/wsi_monitor_sdl2.cpp | 18 ++-- src/wsi/sdl2/wsi_platform_sdl2.cpp | 6 +- src/wsi/sdl2/wsi_platform_sdl2.h | 89 ++++++++++++++++-- src/wsi/sdl2/wsi_window_sdl2.cpp | 20 ++-- src/wsi/win32/wsi_monitor_win32.cpp | 20 ++-- src/wsi/win32/wsi_platform_win32.cpp | 6 +- src/wsi/win32/wsi_platform_win32.h | 92 ++++++++++++++++-- src/wsi/win32/wsi_window_win32.cpp | 23 +++-- src/wsi/wsi_platform.cpp | 135 +++++++++++++++++++++++++++ src/wsi/wsi_platform.h | 95 +++++++++++++++++-- src/wsi/wsi_window.h | 12 ++- 15 files changed, 559 insertions(+), 92 deletions(-) diff --git a/src/wsi/glfw/wsi_monitor_glfw.cpp b/src/wsi/glfw/wsi_monitor_glfw.cpp index e450f83c..00abc89a 100644 --- a/src/wsi/glfw/wsi_monitor_glfw.cpp +++ b/src/wsi/glfw/wsi_monitor_glfw.cpp @@ -11,22 +11,22 @@ namespace dxvk::wsi { - HMONITOR getDefaultMonitor() { + HMONITOR GlfwWsiDriver::getDefaultMonitor() { return enumMonitors(0); } - HMONITOR enumMonitors(uint32_t index) { + HMONITOR GlfwWsiDriver::enumMonitors(uint32_t index) { return isDisplayValid(int32_t(index)) ? toHmonitor(index) : nullptr; } - HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) { + HMONITOR GlfwWsiDriver::enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) { return enumMonitors(index); } - bool getDisplayName( + bool GlfwWsiDriver::getDisplayName( HMONITOR hMonitor, WCHAR (&Name)[32]) { const int32_t displayId = fromHmonitor(hMonitor); @@ -46,7 +46,7 @@ namespace dxvk::wsi { } - bool getDesktopCoordinates( + bool GlfwWsiDriver::getDesktopCoordinates( HMONITOR hMonitor, RECT* pRect) { const int32_t displayId = fromHmonitor(hMonitor); @@ -97,7 +97,7 @@ namespace dxvk::wsi { } - bool getDisplayMode( + bool GlfwWsiDriver::getDisplayMode( HMONITOR hMonitor, uint32_t ModeNumber, WsiMode* pMode) { @@ -121,7 +121,7 @@ namespace dxvk::wsi { } - bool getCurrentDisplayMode( + bool GlfwWsiDriver::getCurrentDisplayMode( HMONITOR hMonitor, WsiMode* pMode) { const int32_t displayId = fromHmonitor(hMonitor); @@ -141,7 +141,7 @@ namespace dxvk::wsi { } - bool getDesktopDisplayMode( + bool GlfwWsiDriver::getDesktopDisplayMode( HMONITOR hMonitor, WsiMode* pMode) { const int32_t displayId = fromHmonitor(hMonitor); @@ -159,7 +159,7 @@ namespace dxvk::wsi { return true; } - std::vector getMonitorEdid(HMONITOR hMonitor) { + std::vector GlfwWsiDriver::getMonitorEdid(HMONITOR hMonitor) { Logger::err("getMonitorEdid not implemented on this platform."); return {}; } diff --git a/src/wsi/glfw/wsi_platform_glfw.cpp b/src/wsi/glfw/wsi_platform_glfw.cpp index d180f597..fb711aeb 100644 --- a/src/wsi/glfw/wsi_platform_glfw.cpp +++ b/src/wsi/glfw/wsi_platform_glfw.cpp @@ -4,7 +4,7 @@ namespace dxvk::wsi { - std::vector getInstanceExtensions() { + std::vector GlfwWsiDriver::getInstanceExtensions() { if (!glfwVulkanSupported()) throw DxvkError(str::format("GLFW WSI: Vulkan is not supported in any capacity!")); @@ -22,4 +22,8 @@ namespace dxvk::wsi { return names; } + WsiDriver* platformCreateWsiDriver() { + return new GlfwWsiDriver(); + } + } diff --git a/src/wsi/glfw/wsi_platform_glfw.h b/src/wsi/glfw/wsi_platform_glfw.h index 25753494..83b95c5e 100644 --- a/src/wsi/glfw/wsi_platform_glfw.h +++ b/src/wsi/glfw/wsi_platform_glfw.h @@ -3,14 +3,91 @@ #include "../../vulkan/vulkan_loader.h" #include -#include "../wsi_monitor.h" +#include "../wsi_platform.h" namespace dxvk::wsi { - /** - * \brief Impl-dependent state - */ - struct DxvkWindowState { + class GlfwWsiDriver : public WsiDriver { + public: + // Platform + virtual std::vector getInstanceExtensions(); + + // Monitor + virtual HMONITOR getDefaultMonitor(); + + virtual HMONITOR enumMonitors(uint32_t index); + + virtual HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index); + + virtual bool getDisplayName( + HMONITOR hMonitor, + WCHAR (&Name)[32]); + + virtual bool getDesktopCoordinates( + HMONITOR hMonitor, + RECT* pRect); + + virtual bool getDisplayMode( + HMONITOR hMonitor, + uint32_t modeNumber, + WsiMode* pMode); + + virtual bool getCurrentDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode); + + virtual bool getDesktopDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode); + + virtual WsiEdidData getMonitorEdid(HMONITOR hMonitor); + + // Window + + virtual void getWindowSize( + HWND hWindow, + uint32_t* pWidth, + uint32_t* pWeight); + + virtual void resizeWindow( + HWND hWindow, + DxvkWindowState* pState, + uint32_t width, + uint32_t weight); + + virtual bool setWindowMode( + HMONITOR hMonitor, + HWND hWindow, + const WsiMode& mode); + + virtual bool enterFullscreenMode( + HMONITOR hMonitor, + HWND hWindow, + DxvkWindowState* pState, + [[maybe_unused]] + bool modeSwitch); + + virtual bool leaveFullscreenMode( + HWND hWindow, + DxvkWindowState* pState, + bool restoreCoordinates); + + virtual bool restoreDisplayMode(); + + virtual HMONITOR getWindowMonitor(HWND hWindow); + + virtual bool isWindow(HWND hWindow); + + virtual void updateFullscreenWindow( + HMONITOR hMonitor, + HWND hWindow, + bool forceTopmost); + + virtual VkResult createSurface( + HWND hWindow, + PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr, + VkInstance instance, + VkSurfaceKHR* pSurface); }; inline bool isDisplayValid(int32_t displayId) { @@ -20,4 +97,4 @@ namespace dxvk::wsi { return displayId < displayCount && displayId >= 0; } -} \ No newline at end of file +} diff --git a/src/wsi/glfw/wsi_window_glfw.cpp b/src/wsi/glfw/wsi_window_glfw.cpp index 70031250..b23a7923 100644 --- a/src/wsi/glfw/wsi_window_glfw.cpp +++ b/src/wsi/glfw/wsi_window_glfw.cpp @@ -12,7 +12,7 @@ namespace dxvk::wsi { - void getWindowSize( + void GlfwWsiDriver::getWindowSize( HWND hWindow, uint32_t* pWidth, uint32_t* pHeight) { @@ -29,7 +29,7 @@ namespace dxvk::wsi { } - void resizeWindow( + void GlfwWsiDriver::resizeWindow( HWND hWindow, DxvkWindowState* pState, uint32_t Width, @@ -40,7 +40,7 @@ namespace dxvk::wsi { } - bool setWindowMode( + bool GlfwWsiDriver::setWindowMode( HMONITOR hMonitor, HWND hWindow, const WsiMode& pMode) { @@ -67,7 +67,7 @@ namespace dxvk::wsi { return true; } - bool enterFullscreenMode( + bool GlfwWsiDriver::enterFullscreenMode( HMONITOR hMonitor, HWND hWindow, DxvkWindowState* pState, @@ -89,7 +89,7 @@ namespace dxvk::wsi { } - bool leaveFullscreenMode( + bool GlfwWsiDriver::leaveFullscreenMode( HWND hWindow, DxvkWindowState* pState, bool restoreCoordinates) { @@ -103,13 +103,13 @@ namespace dxvk::wsi { } - bool restoreDisplayMode() { + bool GlfwWsiDriver::restoreDisplayMode() { // Don't need to do anything with GLFW here. return true; } - HMONITOR getWindowMonitor(HWND hWindow) { + HMONITOR GlfwWsiDriver::getWindowMonitor(HWND hWindow) { // TODO: implement this with glfwGetWindowMonitor // (or maybe not? glfwGetWindowMonitor only seems to reference *fullscreen* windows) // GLFWwindow* window = fromHwnd(hWindow); @@ -119,19 +119,19 @@ namespace dxvk::wsi { } - bool isWindow(HWND hWindow) { + bool GlfwWsiDriver::isWindow(HWND hWindow) { GLFWwindow* window = fromHwnd(hWindow); return window != nullptr; } - void updateFullscreenWindow( + void GlfwWsiDriver::updateFullscreenWindow( HMONITOR hMonitor, HWND hWindow, bool forceTopmost) { // Don't need to do anything with GLFW here. } - VkResult createSurface( + VkResult GlfwWsiDriver::createSurface( HWND hWindow, PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr, VkInstance instance, @@ -141,4 +141,4 @@ namespace dxvk::wsi { return glfwCreateWindowSurface(instance, window, nullptr, pSurface); } -} \ No newline at end of file +} diff --git a/src/wsi/sdl2/wsi_monitor_sdl2.cpp b/src/wsi/sdl2/wsi_monitor_sdl2.cpp index f0de7cd6..5903ef68 100644 --- a/src/wsi/sdl2/wsi_monitor_sdl2.cpp +++ b/src/wsi/sdl2/wsi_monitor_sdl2.cpp @@ -12,22 +12,22 @@ namespace dxvk::wsi { - HMONITOR getDefaultMonitor() { + HMONITOR Sdl2WsiDriver::getDefaultMonitor() { return enumMonitors(0); } - HMONITOR enumMonitors(uint32_t index) { + HMONITOR Sdl2WsiDriver::enumMonitors(uint32_t index) { return isDisplayValid(int32_t(index)) ? toHmonitor(index) : nullptr; } - HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) { + HMONITOR Sdl2WsiDriver::enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) { return enumMonitors(index); } - bool getDisplayName( + bool Sdl2WsiDriver::getDisplayName( HMONITOR hMonitor, WCHAR (&Name)[32]) { const int32_t displayId = fromHmonitor(hMonitor); @@ -47,7 +47,7 @@ namespace dxvk::wsi { } - bool getDesktopCoordinates( + bool Sdl2WsiDriver::getDesktopCoordinates( HMONITOR hMonitor, RECT* pRect) { const int32_t displayId = fromHmonitor(hMonitor); @@ -90,7 +90,7 @@ namespace dxvk::wsi { } - bool getDisplayMode( + bool Sdl2WsiDriver::getDisplayMode( HMONITOR hMonitor, uint32_t ModeNumber, WsiMode* pMode) { @@ -109,7 +109,7 @@ namespace dxvk::wsi { } - bool getCurrentDisplayMode( + bool Sdl2WsiDriver::getCurrentDisplayMode( HMONITOR hMonitor, WsiMode* pMode) { const int32_t displayId = fromHmonitor(hMonitor); @@ -129,7 +129,7 @@ namespace dxvk::wsi { } - bool getDesktopDisplayMode( + bool Sdl2WsiDriver::getDesktopDisplayMode( HMONITOR hMonitor, WsiMode* pMode) { const int32_t displayId = fromHmonitor(hMonitor); @@ -148,7 +148,7 @@ namespace dxvk::wsi { return true; } - std::vector getMonitorEdid(HMONITOR hMonitor) { + std::vector Sdl2WsiDriver::getMonitorEdid(HMONITOR hMonitor) { Logger::err("getMonitorEdid not implemented on this platform."); return {}; } diff --git a/src/wsi/sdl2/wsi_platform_sdl2.cpp b/src/wsi/sdl2/wsi_platform_sdl2.cpp index cc8ac22b..96ecb076 100644 --- a/src/wsi/sdl2/wsi_platform_sdl2.cpp +++ b/src/wsi/sdl2/wsi_platform_sdl2.cpp @@ -6,7 +6,7 @@ namespace dxvk::wsi { - std::vector getInstanceExtensions() { + std::vector Sdl2WsiDriver::getInstanceExtensions() { SDL_Vulkan_LoadLibrary(nullptr); uint32_t extensionCount = 0; @@ -20,4 +20,8 @@ namespace dxvk::wsi { return extensionNames; } + WsiDriver* platformCreateWsiDriver() { + return new Sdl2WsiDriver(); + } + } diff --git a/src/wsi/sdl2/wsi_platform_sdl2.h b/src/wsi/sdl2/wsi_platform_sdl2.h index 411fe8f6..845725ab 100644 --- a/src/wsi/sdl2/wsi_platform_sdl2.h +++ b/src/wsi/sdl2/wsi_platform_sdl2.h @@ -2,14 +2,91 @@ #include -#include "../wsi_monitor.h" +#include "../wsi_platform.h" namespace dxvk::wsi { - /** - * \brief Impl-dependent state - */ - struct DxvkWindowState { + class Sdl2WsiDriver : public WsiDriver { + public: + // Platform + virtual std::vector getInstanceExtensions(); + + // Monitor + virtual HMONITOR getDefaultMonitor(); + + virtual HMONITOR enumMonitors(uint32_t index); + + virtual HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index); + + virtual bool getDisplayName( + HMONITOR hMonitor, + WCHAR (&Name)[32]); + + virtual bool getDesktopCoordinates( + HMONITOR hMonitor, + RECT* pRect); + + virtual bool getDisplayMode( + HMONITOR hMonitor, + uint32_t modeNumber, + WsiMode* pMode); + + virtual bool getCurrentDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode); + + virtual bool getDesktopDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode); + + virtual WsiEdidData getMonitorEdid(HMONITOR hMonitor); + + // Window + + virtual void getWindowSize( + HWND hWindow, + uint32_t* pWidth, + uint32_t* pWeight); + + virtual void resizeWindow( + HWND hWindow, + DxvkWindowState* pState, + uint32_t width, + uint32_t weight); + + virtual bool setWindowMode( + HMONITOR hMonitor, + HWND hWindow, + const WsiMode& mode); + + virtual bool enterFullscreenMode( + HMONITOR hMonitor, + HWND hWindow, + DxvkWindowState* pState, + [[maybe_unused]] + bool modeSwitch); + + virtual bool leaveFullscreenMode( + HWND hWindow, + DxvkWindowState* pState, + bool restoreCoordinates); + + virtual bool restoreDisplayMode(); + + virtual HMONITOR getWindowMonitor(HWND hWindow); + + virtual bool isWindow(HWND hWindow); + + virtual void updateFullscreenWindow( + HMONITOR hMonitor, + HWND hWindow, + bool forceTopmost); + + virtual VkResult createSurface( + HWND hWindow, + PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr, + VkInstance instance, + VkSurfaceKHR* pSurface); }; inline bool isDisplayValid(int32_t displayId) { @@ -18,4 +95,4 @@ namespace dxvk::wsi { return displayId < displayCount && displayId >= 0; } -} \ No newline at end of file +} diff --git a/src/wsi/sdl2/wsi_window_sdl2.cpp b/src/wsi/sdl2/wsi_window_sdl2.cpp index 1280b6c1..5622e876 100644 --- a/src/wsi/sdl2/wsi_window_sdl2.cpp +++ b/src/wsi/sdl2/wsi_window_sdl2.cpp @@ -11,7 +11,7 @@ namespace dxvk::wsi { - void getWindowSize( + void Sdl2WsiDriver::getWindowSize( HWND hWindow, uint32_t* pWidth, uint32_t* pHeight) { @@ -28,7 +28,7 @@ namespace dxvk::wsi { } - void resizeWindow( + void Sdl2WsiDriver::resizeWindow( HWND hWindow, DxvkWindowState* pState, uint32_t Width, @@ -39,7 +39,7 @@ namespace dxvk::wsi { } - bool setWindowMode( + bool Sdl2WsiDriver::setWindowMode( HMONITOR hMonitor, HWND hWindow, const WsiMode& pMode) { @@ -73,7 +73,7 @@ namespace dxvk::wsi { - bool enterFullscreenMode( + bool Sdl2WsiDriver::enterFullscreenMode( HMONITOR hMonitor, HWND hWindow, DxvkWindowState* pState, @@ -99,7 +99,7 @@ namespace dxvk::wsi { } - bool leaveFullscreenMode( + bool Sdl2WsiDriver::leaveFullscreenMode( HWND hWindow, DxvkWindowState* pState, bool restoreCoordinates) { @@ -114,13 +114,13 @@ namespace dxvk::wsi { } - bool restoreDisplayMode() { + bool Sdl2WsiDriver::restoreDisplayMode() { // Don't need to do anything with SDL2 here. return true; } - HMONITOR getWindowMonitor(HWND hWindow) { + HMONITOR Sdl2WsiDriver::getWindowMonitor(HWND hWindow) { SDL_Window* window = fromHwnd(hWindow); const int32_t displayId = SDL_GetWindowDisplayIndex(window); @@ -128,13 +128,13 @@ namespace dxvk::wsi { } - bool isWindow(HWND hWindow) { + bool Sdl2WsiDriver::isWindow(HWND hWindow) { SDL_Window* window = fromHwnd(hWindow); return window != nullptr; } - void updateFullscreenWindow( + void Sdl2WsiDriver::updateFullscreenWindow( HMONITOR hMonitor, HWND hWindow, bool forceTopmost) { @@ -142,7 +142,7 @@ namespace dxvk::wsi { } - VkResult createSurface( + VkResult Sdl2WsiDriver::createSurface( HWND hWindow, PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr, VkInstance instance, diff --git a/src/wsi/win32/wsi_monitor_win32.cpp b/src/wsi/win32/wsi_monitor_win32.cpp index ae4a0ff3..b37e0902 100644 --- a/src/wsi/win32/wsi_monitor_win32.cpp +++ b/src/wsi/win32/wsi_monitor_win32.cpp @@ -1,4 +1,4 @@ -#include "../wsi_monitor.h" +#include "wsi_platform_win32.h" #include "../../util/util_string.h" #include "../../util/log/log.h" @@ -13,7 +13,7 @@ namespace dxvk::wsi { - HMONITOR getDefaultMonitor() { + HMONITOR Win32WsiDriver::getDefaultMonitor() { return ::MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY); } @@ -45,7 +45,7 @@ namespace dxvk::wsi { return FALSE; } - HMONITOR enumMonitors(uint32_t index) { + HMONITOR Win32WsiDriver::enumMonitors(uint32_t index) { MonitorEnumInfo info; info.iMonitorId = index; info.oMonitor = nullptr; @@ -58,7 +58,7 @@ namespace dxvk::wsi { return info.oMonitor; } - HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) { + HMONITOR Win32WsiDriver::enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) { if (!numLUIDs) return enumMonitors(index); @@ -132,7 +132,7 @@ namespace dxvk::wsi { } - bool getDisplayName( + bool Win32WsiDriver::getDisplayName( HMONITOR hMonitor, WCHAR (&Name)[32]) { // Query monitor info to get the device name @@ -150,7 +150,7 @@ namespace dxvk::wsi { } - bool getDesktopCoordinates( + bool Win32WsiDriver::getDesktopCoordinates( HMONITOR hMonitor, RECT* pRect) { ::MONITORINFOEXW monInfo; @@ -200,7 +200,7 @@ namespace dxvk::wsi { } - bool getDisplayMode( + bool Win32WsiDriver::getDisplayMode( HMONITOR hMonitor, uint32_t modeNumber, WsiMode* pMode) { @@ -208,14 +208,14 @@ namespace dxvk::wsi { } - bool getCurrentDisplayMode( + bool Win32WsiDriver::getCurrentDisplayMode( HMONITOR hMonitor, WsiMode* pMode) { return retrieveDisplayMode(hMonitor, ENUM_CURRENT_SETTINGS, pMode); } - bool getDesktopDisplayMode( + bool Win32WsiDriver::getDesktopDisplayMode( HMONITOR hMonitor, WsiMode* pMode) { return retrieveDisplayMode(hMonitor, ENUM_REGISTRY_SETTINGS, pMode); @@ -308,7 +308,7 @@ namespace dxvk::wsi { wchar_t extraChars[MAX_DEVICE_ID_LEN]; }; - WsiEdidData getMonitorEdid(HMONITOR hMonitor) { + WsiEdidData Win32WsiDriver::getMonitorEdid(HMONITOR hMonitor) { static constexpr GUID GUID_DEVINTERFACE_MONITOR = { 0xe6f07b5f, 0xee97, 0x4a90, 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 }; static auto pfnSetupDiGetClassDevsW = reinterpret_cast (::GetProcAddress(::GetModuleHandleW(L"setupapi.dll"), "SetupDiGetClassDevsW")); static auto pfnSetupDiEnumDeviceInterfaces = reinterpret_cast (::GetProcAddress(::GetModuleHandleW(L"setupapi.dll"), "SetupDiEnumDeviceInterfaces")); diff --git a/src/wsi/win32/wsi_platform_win32.cpp b/src/wsi/win32/wsi_platform_win32.cpp index 8b16de56..ab27869a 100644 --- a/src/wsi/win32/wsi_platform_win32.cpp +++ b/src/wsi/win32/wsi_platform_win32.cpp @@ -2,8 +2,12 @@ namespace dxvk::wsi { - std::vector getInstanceExtensions() { + std::vector Win32WsiDriver::getInstanceExtensions() { return { VK_KHR_WIN32_SURFACE_EXTENSION_NAME }; } + WsiDriver* platformCreateWsiDriver() { + return new Win32WsiDriver(); + } + } diff --git a/src/wsi/win32/wsi_platform_win32.h b/src/wsi/win32/wsi_platform_win32.h index d382f20a..1364baf1 100644 --- a/src/wsi/win32/wsi_platform_win32.h +++ b/src/wsi/win32/wsi_platform_win32.h @@ -2,15 +2,91 @@ #include +#include "../wsi_platform.h" + namespace dxvk::wsi { - /** - * \brief Impl-dependent state - */ - struct DxvkWindowState { - LONG style = 0; - LONG exstyle = 0; - RECT rect = { 0, 0, 0, 0 }; + class Win32WsiDriver : public WsiDriver { + public: + // Platform + virtual std::vector getInstanceExtensions(); + + // Monitor + virtual HMONITOR getDefaultMonitor(); + + virtual HMONITOR enumMonitors(uint32_t index); + + virtual HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index); + + virtual bool getDisplayName( + HMONITOR hMonitor, + WCHAR (&Name)[32]); + + virtual bool getDesktopCoordinates( + HMONITOR hMonitor, + RECT* pRect); + + virtual bool getDisplayMode( + HMONITOR hMonitor, + uint32_t modeNumber, + WsiMode* pMode); + + virtual bool getCurrentDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode); + + virtual bool getDesktopDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode); + + virtual WsiEdidData getMonitorEdid(HMONITOR hMonitor); + + // Window + + virtual void getWindowSize( + HWND hWindow, + uint32_t* pWidth, + uint32_t* pWeight); + + virtual void resizeWindow( + HWND hWindow, + DxvkWindowState* pState, + uint32_t width, + uint32_t weight); + + virtual bool setWindowMode( + HMONITOR hMonitor, + HWND hWindow, + const WsiMode& mode); + + virtual bool enterFullscreenMode( + HMONITOR hMonitor, + HWND hWindow, + DxvkWindowState* pState, + [[maybe_unused]] + bool modeSwitch); + + virtual bool leaveFullscreenMode( + HWND hWindow, + DxvkWindowState* pState, + bool restoreCoordinates); + + virtual bool restoreDisplayMode(); + + virtual HMONITOR getWindowMonitor(HWND hWindow); + + virtual bool isWindow(HWND hWindow); + + virtual void updateFullscreenWindow( + HMONITOR hMonitor, + HWND hWindow, + bool forceTopmost); + + virtual VkResult createSurface( + HWND hWindow, + PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr, + VkInstance instance, + VkSurfaceKHR* pSurface); }; -} \ No newline at end of file +} diff --git a/src/wsi/win32/wsi_window_win32.cpp b/src/wsi/win32/wsi_window_win32.cpp index 597d7478..cf446980 100644 --- a/src/wsi/win32/wsi_window_win32.cpp +++ b/src/wsi/win32/wsi_window_win32.cpp @@ -1,5 +1,4 @@ -#include "../wsi_window.h" -#include "../wsi_monitor.h" +#include "wsi_platform_win32.h" #include "../../util/util_string.h" #include "../../util/log/log.h" @@ -94,7 +93,7 @@ namespace dxvk::wsi { } - void getWindowSize( + void Win32WsiDriver::getWindowSize( HWND hWindow, uint32_t* pWidth, uint32_t* pHeight) { @@ -109,7 +108,7 @@ namespace dxvk::wsi { } - void resizeWindow( + void Win32WsiDriver::resizeWindow( HWND hWindow, DxvkWindowState* pState, uint32_t width, @@ -130,7 +129,7 @@ namespace dxvk::wsi { } - bool setWindowMode( + bool Win32WsiDriver::setWindowMode( HMONITOR hMonitor, HWND hWindow, const WsiMode& mode) { @@ -163,7 +162,7 @@ namespace dxvk::wsi { } - bool enterFullscreenMode( + bool Win32WsiDriver::enterFullscreenMode( HMONITOR hMonitor, HWND hWindow, DxvkWindowState* pState, @@ -196,7 +195,7 @@ namespace dxvk::wsi { } - bool leaveFullscreenMode( + bool Win32WsiDriver::leaveFullscreenMode( HWND hWindow, DxvkWindowState* pState, bool restoreCoordinates) { @@ -225,7 +224,7 @@ namespace dxvk::wsi { } - bool restoreDisplayMode() { + bool Win32WsiDriver::restoreDisplayMode() { bool success = true; bool result = ::EnumDisplayMonitors(nullptr, nullptr, &restoreDisplayModeCallback, @@ -235,7 +234,7 @@ namespace dxvk::wsi { } - HMONITOR getWindowMonitor(HWND hWindow) { + HMONITOR Win32WsiDriver::getWindowMonitor(HWND hWindow) { RECT windowRect = { 0, 0, 0, 0 }; ::GetWindowRect(hWindow, &windowRect); @@ -248,12 +247,12 @@ namespace dxvk::wsi { } - bool isWindow(HWND hWindow) { + bool Win32WsiDriver::isWindow(HWND hWindow) { return ::IsWindow(hWindow); } - void updateFullscreenWindow( + void Win32WsiDriver::updateFullscreenWindow( HMONITOR hMonitor, HWND hWindow, bool forceTopmost) { @@ -274,7 +273,7 @@ namespace dxvk::wsi { } - VkResult createSurface( + VkResult Win32WsiDriver::createSurface( HWND hWindow, PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr, VkInstance instance, diff --git a/src/wsi/wsi_platform.cpp b/src/wsi/wsi_platform.cpp index 56cd6c45..f4802025 100644 --- a/src/wsi/wsi_platform.cpp +++ b/src/wsi/wsi_platform.cpp @@ -1,11 +1,146 @@ #include "wsi_platform.h" +#include "wsi_monitor.h" +#include "wsi_window.h" +#include "../util/util_error.h" namespace dxvk::wsi { + static WsiDriver* s_driver = nullptr; + static int s_refcount = 0; void init() { + if (s_refcount++ > 0) + return; + + s_driver = platformCreateWsiDriver(); + if (s_driver == nullptr) + throw DxvkError("Failed to initialize WSI."); } void quit() { + if (s_refcount == 0) + return; + + s_refcount--; + if (s_refcount == 0) { + delete s_driver; + s_driver = nullptr; + } + } + + std::vector getInstanceExtensions() { + return s_driver->getInstanceExtensions(); + } + + void getWindowSize( + HWND hWindow, + uint32_t* pWidth, + uint32_t* pHeight) { + s_driver->getWindowSize(hWindow, pWidth, pHeight); + } + + void resizeWindow( + HWND hWindow, + DxvkWindowState* pState, + uint32_t width, + uint32_t height) { + s_driver->resizeWindow(hWindow, pState, width, height); + } + + bool setWindowMode( + HMONITOR hMonitor, + HWND hWindow, + const WsiMode& mode) { + return s_driver->setWindowMode(hMonitor, hWindow, mode); + } + + bool enterFullscreenMode( + HMONITOR hMonitor, + HWND hWindow, + DxvkWindowState* pState, + [[maybe_unused]] + bool modeSwitch) { + return s_driver->enterFullscreenMode(hMonitor, hWindow, pState, modeSwitch); + } + + bool leaveFullscreenMode( + HWND hWindow, + DxvkWindowState* pState, + bool restoreCoordinates) { + return s_driver->leaveFullscreenMode(hWindow, pState, restoreCoordinates); + } + + bool restoreDisplayMode() { + return s_driver->restoreDisplayMode(); + } + + HMONITOR getWindowMonitor(HWND hWindow) { + return s_driver->getWindowMonitor(hWindow); + } + + bool isWindow(HWND hWindow) { + return s_driver->isWindow(hWindow); + } + + void updateFullscreenWindow( + HMONITOR hMonitor, + HWND hWindow, + bool forceTopmost) { + s_driver->updateFullscreenWindow(hMonitor, hWindow, forceTopmost); + } + + VkResult createSurface( + HWND hWindow, + PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr, + VkInstance instance, + VkSurfaceKHR* pSurface) { + return s_driver->createSurface(hWindow, pfnVkGetInstanceProcAddr, instance, pSurface); + } + + HMONITOR getDefaultMonitor() { + return s_driver->getDefaultMonitor(); + } + + HMONITOR enumMonitors(uint32_t index) { + return s_driver->enumMonitors(index); + } + + HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) { + return s_driver->enumMonitors(adapterLUID, numLUIDs, index); + } + + bool getDisplayName( + HMONITOR hMonitor, + WCHAR (&Name)[32]) { + return s_driver->getDisplayName(hMonitor, Name); + } + + bool getDesktopCoordinates( + HMONITOR hMonitor, + RECT* pRect) { + return s_driver->getDesktopCoordinates(hMonitor, pRect); + } + + bool getDisplayMode( + HMONITOR hMonitor, + uint32_t modeNumber, + WsiMode* pMode) { + return s_driver->getDisplayMode(hMonitor, modeNumber, pMode); + } + + bool getCurrentDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode) { + return s_driver->getCurrentDisplayMode(hMonitor, pMode); + } + + bool getDesktopDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode) { + return s_driver->getDesktopDisplayMode(hMonitor, pMode); + } + + WsiEdidData getMonitorEdid(HMONITOR hMonitor) { + return s_driver->getMonitorEdid(hMonitor); } } diff --git a/src/wsi/wsi_platform.h b/src/wsi/wsi_platform.h index 7ccecc27..f8373fe5 100644 --- a/src/wsi/wsi_platform.h +++ b/src/wsi/wsi_platform.h @@ -1,19 +1,100 @@ #pragma once -#if defined(DXVK_WSI_WIN32) -#include "win32/wsi_platform_win32.h" -#elif defined(DXVK_WSI_SDL2) -#include "sdl2/wsi_platform_sdl2.h" -#elif defined(DXVK_WSI_GLFW) -#include "glfw/wsi_platform_glfw.h" -#endif +#include "wsi_window.h" #include namespace dxvk::wsi { + class WsiDriver { + public: + virtual ~WsiDriver() { + } + + // Platform + virtual std::vector getInstanceExtensions() = 0; + + // Monitor + virtual HMONITOR getDefaultMonitor() = 0; + + virtual HMONITOR enumMonitors(uint32_t index) = 0; + + virtual HMONITOR enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) = 0; + + virtual bool getDisplayName( + HMONITOR hMonitor, + WCHAR (&Name)[32]) = 0; + + virtual bool getDesktopCoordinates( + HMONITOR hMonitor, + RECT* pRect) = 0; + + virtual bool getDisplayMode( + HMONITOR hMonitor, + uint32_t modeNumber, + WsiMode* pMode) = 0; + + virtual bool getCurrentDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode) = 0; + + virtual bool getDesktopDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode) = 0; + + virtual WsiEdidData getMonitorEdid(HMONITOR hMonitor) = 0; + + // Window + + virtual void getWindowSize( + HWND hWindow, + uint32_t* pWidth, + uint32_t* pWeight) = 0; + + virtual void resizeWindow( + HWND hWindow, + DxvkWindowState* pState, + uint32_t width, + uint32_t weight) = 0; + + virtual bool setWindowMode( + HMONITOR hMonitor, + HWND hWindow, + const WsiMode& mode) = 0; + + virtual bool enterFullscreenMode( + HMONITOR hMonitor, + HWND hWindow, + DxvkWindowState* pState, + [[maybe_unused]] + bool modeSwitch) = 0; + + virtual bool leaveFullscreenMode( + HWND hWindow, + DxvkWindowState* pState, + bool restoreCoordinates) = 0; + + virtual bool restoreDisplayMode() = 0; + + virtual HMONITOR getWindowMonitor(HWND hWindow) = 0; + + virtual bool isWindow(HWND hWindow) = 0; + + virtual void updateFullscreenWindow( + HMONITOR hMonitor, + HWND hWindow, + bool forceTopmost) = 0; + + virtual VkResult createSurface( + HWND hWindow, + PFN_vkGetInstanceProcAddr pfnVkGetInstanceProcAddr, + VkInstance instance, + VkSurfaceKHR* pSurface) = 0; + }; + void init(); void quit(); std::vector getInstanceExtensions(); + WsiDriver* platformCreateWsiDriver(); } diff --git a/src/wsi/wsi_window.h b/src/wsi/wsi_window.h index e0587a0f..68c6db9c 100644 --- a/src/wsi/wsi_window.h +++ b/src/wsi/wsi_window.h @@ -3,12 +3,22 @@ #include #include "wsi_monitor.h" -#include "wsi_platform.h" #include "../vulkan/vulkan_loader.h" namespace dxvk::wsi { + /** + * \brief Impl-dependent state + */ + struct DxvkWindowState { +#ifdef DXVK_WSI_WIN32 + LONG style = 0; + LONG exstyle = 0; + RECT rect = { 0, 0, 0, 0 }; +#endif + }; + /** * \brief The size of the window * From c307038a7189ab481c363f413304c4e8aa2b5b3e Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Fri, 8 Dec 2023 00:59:23 -0500 Subject: [PATCH 04/12] [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. --- src/wsi/glfw/wsi_platform_glfw.cpp | 28 ++++++++++++++++++++++++++ src/wsi/glfw/wsi_platform_glfw.h | 24 +++++++++++++++------- src/wsi/glfw/wsi_platform_glfw_funcs.h | 12 +++++++++++ src/wsi/meson.build | 4 +--- src/wsi/sdl2/wsi_platform_sdl2.cpp | 28 ++++++++++++++++++++++++++ src/wsi/sdl2/wsi_platform_sdl2.h | 22 ++++++++++++++------ src/wsi/sdl2/wsi_platform_sdl2_funcs.h | 16 +++++++++++++++ 7 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 src/wsi/glfw/wsi_platform_glfw_funcs.h create mode 100644 src/wsi/sdl2/wsi_platform_sdl2_funcs.h diff --git a/src/wsi/glfw/wsi_platform_glfw.cpp b/src/wsi/glfw/wsi_platform_glfw.cpp index fb711aeb..09b95628 100644 --- a/src/wsi/glfw/wsi_platform_glfw.cpp +++ b/src/wsi/glfw/wsi_platform_glfw.cpp @@ -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(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 GlfwWsiDriver::getInstanceExtensions() { if (!glfwVulkanSupported()) throw DxvkError(str::format("GLFW WSI: Vulkan is not supported in any capacity!")); diff --git a/src/wsi/glfw/wsi_platform_glfw.h b/src/wsi/glfw/wsi_platform_glfw.h index 83b95c5e..849ce4f5 100644 --- a/src/wsi/glfw/wsi_platform_glfw.h +++ b/src/wsi/glfw/wsi_platform_glfw.h @@ -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 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; - } } diff --git a/src/wsi/glfw/wsi_platform_glfw_funcs.h b/src/wsi/glfw/wsi_platform_glfw_funcs.h new file mode 100644 index 00000000..89cedfd0 --- /dev/null +++ b/src/wsi/glfw/wsi_platform_glfw_funcs.h @@ -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 diff --git a/src/wsi/meson.build b/src/wsi/meson.build index 1cabcf2f..f16a4e39 100644 --- a/src/wsi/meson.build +++ b/src/wsi/meson.build @@ -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, diff --git a/src/wsi/sdl2/wsi_platform_sdl2.cpp b/src/wsi/sdl2/wsi_platform_sdl2.cpp index 96ecb076..d2574430 100644 --- a/src/wsi/sdl2/wsi_platform_sdl2.cpp +++ b/src/wsi/sdl2/wsi_platform_sdl2.cpp @@ -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 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(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 Sdl2WsiDriver::getInstanceExtensions() { SDL_Vulkan_LoadLibrary(nullptr); diff --git a/src/wsi/sdl2/wsi_platform_sdl2.h b/src/wsi/sdl2/wsi_platform_sdl2.h index 845725ab..fc3ce353 100644 --- a/src/wsi/sdl2/wsi_platform_sdl2.h +++ b/src/wsi/sdl2/wsi_platform_sdl2.h @@ -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 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; - } } diff --git a/src/wsi/sdl2/wsi_platform_sdl2_funcs.h b/src/wsi/sdl2/wsi_platform_sdl2_funcs.h new file mode 100644 index 00000000..3da94922 --- /dev/null +++ b/src/wsi/sdl2/wsi_platform_sdl2_funcs.h @@ -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 From f7a6165f7e8c0a4959029c454eb03b2859cba2c0 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Fri, 8 Dec 2023 01:18:54 -0500 Subject: [PATCH 05/12] [wsi] Refactor platform system to support multiple WSI implementations --- meson.build | 15 ++++++++------- src/wsi/glfw/wsi_monitor_glfw.cpp | 4 ++++ src/wsi/glfw/wsi_platform_glfw.cpp | 18 ++++++++++++++++-- src/wsi/glfw/wsi_window_glfw.cpp | 6 +++++- src/wsi/meson.build | 20 +------------------- src/wsi/sdl2/wsi_monitor_sdl2.cpp | 4 ++++ src/wsi/sdl2/wsi_platform_sdl2.cpp | 18 ++++++++++++++++-- src/wsi/sdl2/wsi_window_sdl2.cpp | 6 +++++- src/wsi/win32/wsi_monitor_win32.cpp | 4 ++++ src/wsi/win32/wsi_platform_win32.cpp | 14 ++++++++++++-- src/wsi/win32/wsi_window_win32.cpp | 22 +++++++++++++--------- src/wsi/wsi_platform.cpp | 27 +++++++++++++++++++++++++-- src/wsi/wsi_platform.h | 16 +++++++++++++++- src/wsi/wsi_window.h | 16 ++++++++++++---- 14 files changed, 140 insertions(+), 50 deletions(-) diff --git a/meson.build b/meson.build index e35a9de0..1a82e4bc 100644 --- a/meson.build +++ b/meson.build @@ -115,7 +115,6 @@ if platform == 'windows' ) endif - dxvk_wsi = 'win32' dxvk_name_prefix = '' compiler_args += ['-DDXVK_WSI_WIN32'] else @@ -128,15 +127,17 @@ else './include/native/directx' ] - dxvk_wsi = get_option('dxvk_native_wsi') - - if dxvk_wsi == 'sdl2' - lib_sdl2 = cpp.find_library('SDL2') + lib_sdl2 = cpp.find_library('SDL2', required: false) + lib_glfw = cpp.find_library('glfw', required: false) + if lib_sdl2.found() compiler_args += ['-DDXVK_WSI_SDL2'] - elif dxvk_wsi == 'glfw' - lib_glfw = cpp.find_library('glfw') + endif + if lib_glfw.found() compiler_args += ['-DDXVK_WSI_GLFW'] endif + if (not lib_sdl2.found() and not lib_glfw.found()) + error('SDL2 or GLFW are required to build dxvk-native') + endif dxvk_name_prefix = 'libdxvk_' diff --git a/src/wsi/glfw/wsi_monitor_glfw.cpp b/src/wsi/glfw/wsi_monitor_glfw.cpp index 00abc89a..f6c09aaf 100644 --- a/src/wsi/glfw/wsi_monitor_glfw.cpp +++ b/src/wsi/glfw/wsi_monitor_glfw.cpp @@ -1,3 +1,5 @@ +#if defined(DXVK_WSI_GLFW) + #include "../wsi_monitor.h" #include "wsi/native_wsi.h" @@ -165,3 +167,5 @@ namespace dxvk::wsi { } } + +#endif diff --git a/src/wsi/glfw/wsi_platform_glfw.cpp b/src/wsi/glfw/wsi_platform_glfw.cpp index 09b95628..ee818bb2 100644 --- a/src/wsi/glfw/wsi_platform_glfw.cpp +++ b/src/wsi/glfw/wsi_platform_glfw.cpp @@ -1,3 +1,5 @@ +#if defined(DXVK_WSI_GLFW) + #include "wsi_platform_glfw.h" #include "../../util/util_error.h" #include "../../util/util_string.h" @@ -50,8 +52,20 @@ namespace dxvk::wsi { return names; } - WsiDriver* platformCreateWsiDriver() { - return new GlfwWsiDriver(); + static bool createGlfwWsiDriver(WsiDriver **driver) { + try { + *driver = new GlfwWsiDriver(); + } catch (const DxvkError& e) { + return false; + } + return true; } + WsiBootstrap GlfwWSI = { + "GLFW", + createGlfwWsiDriver + }; + } + +#endif diff --git a/src/wsi/glfw/wsi_window_glfw.cpp b/src/wsi/glfw/wsi_window_glfw.cpp index b23a7923..f763e759 100644 --- a/src/wsi/glfw/wsi_window_glfw.cpp +++ b/src/wsi/glfw/wsi_window_glfw.cpp @@ -1,6 +1,8 @@ +#if defined(DXVK_WSI_GLFW) + #include "../wsi_window.h" -#include "native/wsi/native_wsi.h" +#include "native/wsi/native_glfw.h" #include "wsi_platform_glfw.h" #include "../../util/util_string.h" @@ -142,3 +144,5 @@ namespace dxvk::wsi { } } + +#endif diff --git a/src/wsi/meson.build b/src/wsi/meson.build index f16a4e39..f60840b9 100644 --- a/src/wsi/meson.build +++ b/src/wsi/meson.build @@ -1,35 +1,17 @@ -wsi_common_src = [ +wsi_src = [ 'wsi_edid.cpp', 'wsi_platform.cpp', -] - -wsi_win32_src = [ 'win32/wsi_monitor_win32.cpp', 'win32/wsi_platform_win32.cpp', 'win32/wsi_window_win32.cpp', -] - -wsi_sdl2_src = [ 'sdl2/wsi_monitor_sdl2.cpp', 'sdl2/wsi_platform_sdl2.cpp', 'sdl2/wsi_window_sdl2.cpp', -] - -wsi_glfw_src = [ 'glfw/wsi_monitor_glfw.cpp', 'glfw/wsi_platform_glfw.cpp', 'glfw/wsi_window_glfw.cpp', ] -if dxvk_wsi == 'win32' - wsi_src = wsi_common_src + wsi_win32_src -elif dxvk_wsi == 'sdl2' - wsi_src = wsi_common_src + wsi_sdl2_src -elif dxvk_wsi == 'glfw' - wsi_src = wsi_common_src + wsi_glfw_src -else - error('Unknown wsi') -endif wsi_deps = [ dep_displayinfo ] wsi_lib = static_library('wsi', wsi_src, diff --git a/src/wsi/sdl2/wsi_monitor_sdl2.cpp b/src/wsi/sdl2/wsi_monitor_sdl2.cpp index 5903ef68..8f5f3290 100644 --- a/src/wsi/sdl2/wsi_monitor_sdl2.cpp +++ b/src/wsi/sdl2/wsi_monitor_sdl2.cpp @@ -1,3 +1,5 @@ +#if defined(DXVK_WSI_SDL2) + #include "../wsi_monitor.h" #include "wsi/native_wsi.h" @@ -154,3 +156,5 @@ namespace dxvk::wsi { } } + +#endif diff --git a/src/wsi/sdl2/wsi_platform_sdl2.cpp b/src/wsi/sdl2/wsi_platform_sdl2.cpp index d2574430..9223b598 100644 --- a/src/wsi/sdl2/wsi_platform_sdl2.cpp +++ b/src/wsi/sdl2/wsi_platform_sdl2.cpp @@ -1,3 +1,5 @@ +#if defined(DXVK_WSI_SDL2) + #include "wsi_platform_sdl2.h" #include "../../util/util_error.h" #include "../../util/util_string.h" @@ -48,8 +50,20 @@ namespace dxvk::wsi { return extensionNames; } - WsiDriver* platformCreateWsiDriver() { - return new Sdl2WsiDriver(); + static bool createSdl2WsiDriver(WsiDriver **driver) { + try { + *driver = new Sdl2WsiDriver(); + } catch (const DxvkError& e) { + return false; + } + return true; } + WsiBootstrap Sdl2WSI = { + "SDL2", + createSdl2WsiDriver + }; + } + +#endif diff --git a/src/wsi/sdl2/wsi_window_sdl2.cpp b/src/wsi/sdl2/wsi_window_sdl2.cpp index 5622e876..68e90229 100644 --- a/src/wsi/sdl2/wsi_window_sdl2.cpp +++ b/src/wsi/sdl2/wsi_window_sdl2.cpp @@ -1,6 +1,8 @@ +#if defined(DXVK_WSI_SDL2) + #include "../wsi_window.h" -#include "native/wsi/native_wsi.h" +#include "native/wsi/native_sdl2.h" #include "wsi_platform_sdl2.h" #include "../../util/util_string.h" @@ -155,3 +157,5 @@ namespace dxvk::wsi { } } + +#endif diff --git a/src/wsi/win32/wsi_monitor_win32.cpp b/src/wsi/win32/wsi_monitor_win32.cpp index b37e0902..0387d87f 100644 --- a/src/wsi/win32/wsi_monitor_win32.cpp +++ b/src/wsi/win32/wsi_monitor_win32.cpp @@ -1,3 +1,5 @@ +#if defined(DXVK_WSI_WIN32) + #include "wsi_platform_win32.h" #include "../../util/util_string.h" @@ -370,3 +372,5 @@ namespace dxvk::wsi { } } + +#endif diff --git a/src/wsi/win32/wsi_platform_win32.cpp b/src/wsi/win32/wsi_platform_win32.cpp index ab27869a..03bf40a5 100644 --- a/src/wsi/win32/wsi_platform_win32.cpp +++ b/src/wsi/win32/wsi_platform_win32.cpp @@ -1,3 +1,5 @@ +#if defined(DXVK_WSI_WIN32) + #include "wsi_platform_win32.h" namespace dxvk::wsi { @@ -6,8 +8,16 @@ namespace dxvk::wsi { return { VK_KHR_WIN32_SURFACE_EXTENSION_NAME }; } - WsiDriver* platformCreateWsiDriver() { - return new Win32WsiDriver(); + static bool createWin32WsiDriver(WsiDriver **driver) { + *driver = new Win32WsiDriver(); + return true; } + WsiBootstrap Win32WSI = { + "Win32", + createWin32WsiDriver + }; + } + +#endif diff --git a/src/wsi/win32/wsi_window_win32.cpp b/src/wsi/win32/wsi_window_win32.cpp index cf446980..894da8e7 100644 --- a/src/wsi/win32/wsi_window_win32.cpp +++ b/src/wsi/win32/wsi_window_win32.cpp @@ -1,3 +1,5 @@ +#if defined(DXVK_WSI_WIN32) + #include "wsi_platform_win32.h" #include "../../util/util_string.h" @@ -169,14 +171,14 @@ namespace dxvk::wsi { [[maybe_unused]] bool modeSwitch) { // Find a display mode that matches what we need - ::GetWindowRect(hWindow, &pState->rect); + ::GetWindowRect(hWindow, &pState->win.rect); // Change the window flags to remove the decoration etc. LONG style = ::GetWindowLongW(hWindow, GWL_STYLE); LONG exstyle = ::GetWindowLongW(hWindow, GWL_EXSTYLE); - pState->style = style; - pState->exstyle = exstyle; + pState->win.style = style; + pState->win.exstyle = exstyle; style &= ~WS_OVERLAPPEDWINDOW; exstyle &= ~WS_EX_OVERLAPPEDWINDOW; @@ -204,20 +206,20 @@ namespace dxvk::wsi { LONG curStyle = ::GetWindowLongW(hWindow, GWL_STYLE) & ~WS_VISIBLE; LONG curExstyle = ::GetWindowLongW(hWindow, GWL_EXSTYLE) & ~WS_EX_TOPMOST; - if (curStyle == (pState->style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW)) - && curExstyle == (pState->exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) { - ::SetWindowLongW(hWindow, GWL_STYLE, pState->style); - ::SetWindowLongW(hWindow, GWL_EXSTYLE, pState->exstyle); + if (curStyle == (pState->win.style & ~(WS_VISIBLE | WS_OVERLAPPEDWINDOW)) + && curExstyle == (pState->win.exstyle & ~(WS_EX_TOPMOST | WS_EX_OVERLAPPEDWINDOW))) { + ::SetWindowLongW(hWindow, GWL_STYLE, pState->win.style); + ::SetWindowLongW(hWindow, GWL_EXSTYLE, pState->win.exstyle); } // Restore window position and apply the style UINT flags = SWP_FRAMECHANGED | SWP_NOACTIVATE; - const RECT rect = pState->rect; + const RECT rect = pState->win.rect; if (!restoreCoordinates) flags |= SWP_NOSIZE | SWP_NOMOVE; - ::SetWindowPos(hWindow, (pState->exstyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_NOTOPMOST, + ::SetWindowPos(hWindow, (pState->win.exstyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_NOTOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, flags); return true; @@ -295,3 +297,5 @@ namespace dxvk::wsi { } } + +#endif diff --git a/src/wsi/wsi_platform.cpp b/src/wsi/wsi_platform.cpp index f4802025..27a342b2 100644 --- a/src/wsi/wsi_platform.cpp +++ b/src/wsi/wsi_platform.cpp @@ -1,18 +1,41 @@ #include "wsi_platform.h" #include "wsi_monitor.h" #include "wsi_window.h" +#include "../util/util_env.h" #include "../util/util_error.h" namespace dxvk::wsi { static WsiDriver* s_driver = nullptr; static int s_refcount = 0; + static const WsiBootstrap *wsiBootstrap[] = { +#if defined(DXVK_WSI_WIN32) + &Win32WSI, +#endif +#if defined(DXVK_WSI_SDL2) + &Sdl2WSI, +#endif +#if defined(DXVK_WSI_GLFW) + &GlfwWSI, +#endif + }; + void init() { if (s_refcount++ > 0) return; - s_driver = platformCreateWsiDriver(); - if (s_driver == nullptr) + bool success = false; + const std::string hint = dxvk::env::getEnvVar("DXVK_WSIDRIVER"); + for (const WsiBootstrap *b : wsiBootstrap) { + if ((hint != "") && (hint != b->name)) + continue; + if (b->createDriver(&s_driver)) { + success = true; + break; + } + } + + if (!success) throw DxvkError("Failed to initialize WSI."); } diff --git a/src/wsi/wsi_platform.h b/src/wsi/wsi_platform.h index f8373fe5..8c37bc94 100644 --- a/src/wsi/wsi_platform.h +++ b/src/wsi/wsi_platform.h @@ -92,9 +92,23 @@ namespace dxvk::wsi { VkSurfaceKHR* pSurface) = 0; }; + struct WsiBootstrap { + const std::string name; + bool (*createDriver)(WsiDriver **driver); + }; + +#if defined(DXVK_WSI_WIN32) + extern WsiBootstrap Win32WSI; +#endif +#if defined(DXVK_WSI_SDL2) + extern WsiBootstrap Sdl2WSI; +#endif +#if defined(DXVK_WSI_GLFW) + extern WsiBootstrap GlfwWSI; +#endif + void init(); void quit(); std::vector getInstanceExtensions(); - WsiDriver* platformCreateWsiDriver(); } diff --git a/src/wsi/wsi_window.h b/src/wsi/wsi_window.h index 68c6db9c..ceb14923 100644 --- a/src/wsi/wsi_window.h +++ b/src/wsi/wsi_window.h @@ -12,10 +12,18 @@ namespace dxvk::wsi { * \brief Impl-dependent state */ struct DxvkWindowState { -#ifdef DXVK_WSI_WIN32 - LONG style = 0; - LONG exstyle = 0; - RECT rect = { 0, 0, 0, 0 }; +#if defined(DXVK_WSI_WIN32) + struct { + LONG style = 0; + LONG exstyle = 0; + RECT rect = { 0, 0, 0, 0 }; + } win; +#endif +#if defined(DXVK_WSI_SDL2) + // Nothing to store +#endif +#if defined(DXVK_WSI_GLFW) + // Nothing to store #endif }; From 1bf42706c6cdcbaab4c03615f7e7a3e44b68f2c9 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Sat, 10 Feb 2024 13:06:33 -0500 Subject: [PATCH 06/12] [meson] Use dependency() instead of find_library() for SDL2/GLFW detection. Since we're not linking to the libraries anymore, it doesn't make much sense to use find_library, and in fact we need to use dependency() in order to get the right CFLAGS for includes, defines, etc, so use that instead. As a result, we can remove the 'SDL2/' folders from the includes, making the SDL includes more correct. --- include/native/wsi/native_sdl2.h | 4 ++-- meson.build | 4 ++-- src/wsi/meson.build | 7 +++++++ src/wsi/sdl2/wsi_platform_sdl2.h | 2 +- src/wsi/sdl2/wsi_window_sdl2.cpp | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/include/native/wsi/native_sdl2.h b/include/native/wsi/native_sdl2.h index b197d952..7ece3a55 100644 --- a/include/native/wsi/native_sdl2.h +++ b/include/native/wsi/native_sdl2.h @@ -1,6 +1,6 @@ #include -#include +#include namespace dxvk::wsi { @@ -22,4 +22,4 @@ namespace dxvk::wsi { return reinterpret_cast(static_cast(displayId + 1)); } -} \ No newline at end of file +} diff --git a/meson.build b/meson.build index 1a82e4bc..fe503562 100644 --- a/meson.build +++ b/meson.build @@ -127,8 +127,8 @@ else './include/native/directx' ] - lib_sdl2 = cpp.find_library('SDL2', required: false) - lib_glfw = cpp.find_library('glfw', required: false) + lib_sdl2 = dependency('SDL2', required: false) + lib_glfw = dependency('glfw', required: false) if lib_sdl2.found() compiler_args += ['-DDXVK_WSI_SDL2'] endif diff --git a/src/wsi/meson.build b/src/wsi/meson.build index f60840b9..4cfb13a8 100644 --- a/src/wsi/meson.build +++ b/src/wsi/meson.build @@ -14,6 +14,13 @@ wsi_src = [ wsi_deps = [ dep_displayinfo ] +if platform != 'windows' + wsi_deps += [ + lib_sdl2.partial_dependency(compile_args: true, includes: true), + lib_glfw.partial_dependency(compile_args: true, includes: true), + ] +endif + wsi_lib = static_library('wsi', wsi_src, dependencies : wsi_deps, include_directories : [ dxvk_include_path ]) diff --git a/src/wsi/sdl2/wsi_platform_sdl2.h b/src/wsi/sdl2/wsi_platform_sdl2.h index fc3ce353..1a6ac8aa 100644 --- a/src/wsi/sdl2/wsi_platform_sdl2.h +++ b/src/wsi/sdl2/wsi_platform_sdl2.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "../wsi_platform.h" diff --git a/src/wsi/sdl2/wsi_window_sdl2.cpp b/src/wsi/sdl2/wsi_window_sdl2.cpp index 68e90229..33084dc3 100644 --- a/src/wsi/sdl2/wsi_window_sdl2.cpp +++ b/src/wsi/sdl2/wsi_window_sdl2.cpp @@ -9,7 +9,7 @@ #include "../../util/log/log.h" #include -#include +#include namespace dxvk::wsi { From 434bf6f6a3e9995abf45805cda7df97cd839715c Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Tue, 12 Dec 2023 11:58:12 -0500 Subject: [PATCH 07/12] [build] Add soversion to dxvk-native binaries --- meson.build | 6 ++++++ src/d3d10/meson.build | 1 + src/d3d11/meson.build | 1 + src/d3d9/meson.build | 1 + src/dxgi/meson.build | 1 + 5 files changed, 10 insertions(+) diff --git a/meson.build b/meson.build index fe503562..a4ddbf24 100644 --- a/meson.build +++ b/meson.build @@ -54,6 +54,8 @@ dep_displayinfo = dependency( ) if platform == 'windows' + dxvk_so_version = {} + compiler_args += [ '-DNOMINMAX', '-D_WIN32_WINNT=0xa00', @@ -118,6 +120,10 @@ if platform == 'windows' dxvk_name_prefix = '' compiler_args += ['-DDXVK_WSI_WIN32'] else + dxvk_abi_version = '0' + dxvk_version = meson.project_version().strip('v').split('.') + dxvk_so_version = {'version': dxvk_abi_version + '.' + dxvk_version[0] + '.' + dxvk_version[1]} + wrc = find_program('touch') wrc_generator = generator(wrc, output : [ '@BASENAME@_ignored.h' ], arguments : [ '@OUTPUT@' ] ) diff --git a/src/d3d10/meson.build b/src/d3d10/meson.build index 51db067c..3d130b32 100644 --- a/src/d3d10/meson.build +++ b/src/d3d10/meson.build @@ -23,6 +23,7 @@ d3d10_core_dll = shared_library('d3d10core'+dll_ext, d3d10_core_src, d3d10_core_ vs_module_defs : 'd3d10core'+def_spec_ext, link_args : d3d10_core_ld_args, link_depends : [ d3d10_core_link_depends ], + kwargs : dxvk_so_version, ) d3d10_core_dep = declare_dependency( diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index 9b51e6ea..87b8b19f 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -86,6 +86,7 @@ d3d11_dll = shared_library('d3d11'+dll_ext, dxgi_common_src + d3d11_src + d3d10_ vs_module_defs : 'd3d11'+def_spec_ext, link_args : d3d11_ld_args, link_depends : [ d3d11_link_depends ], + kwargs : dxvk_so_version, ) d3d11_dep = declare_dependency( diff --git a/src/d3d9/meson.build b/src/d3d9/meson.build index dd6b2316..a4a5ee8a 100644 --- a/src/d3d9/meson.build +++ b/src/d3d9/meson.build @@ -65,6 +65,7 @@ d3d9_dll = shared_library('d3d9'+dll_ext, d3d9_src, glsl_generator.process(d3d9_ vs_module_defs : 'd3d9'+def_spec_ext, link_args : d3d9_ld_args, link_depends : [ d3d9_link_depends ], + kwargs : dxvk_so_version, ) d3d9_dep = declare_dependency( diff --git a/src/dxgi/meson.build b/src/dxgi/meson.build index a6e83b54..fda90020 100644 --- a/src/dxgi/meson.build +++ b/src/dxgi/meson.build @@ -29,6 +29,7 @@ dxgi_dll = shared_library('dxgi'+dll_ext, dxgi_src, dxgi_res, vs_module_defs : 'dxgi'+def_spec_ext, link_args : dxgi_ld_args, link_depends : [ dxgi_link_depends ], + kwargs : dxvk_so_version, ) dxgi_dep = declare_dependency( From d04c705ef9766318cf5c897ba082b239be998df3 Mon Sep 17 00:00:00 2001 From: Ethan Lee Date: Tue, 12 Dec 2023 17:41:54 -0500 Subject: [PATCH 08/12] Use a tarball for the steamrt-sniper artifact. Zips can't preserve the symlink, so make the .tar.gz package with package_native.sh and zip that up instead. --- .github/workflows/artifacts.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml index 9fe6485a..669a38fa 100644 --- a/.github/workflows/artifacts.yml +++ b/.github/workflows/artifacts.yml @@ -54,7 +54,7 @@ jobs: shell: bash run: | export VERSION_NAME="${GITHUB_REF##*/}-${GITHUB_SHA##*/}" - ./package-native.sh ${VERSION_NAME} build --no-package + ./package-native.sh ${VERSION_NAME} build echo "VERSION_NAME=${VERSION_NAME}" >> $GITHUB_ENV - name: Upload artifacts @@ -62,5 +62,5 @@ jobs: uses: actions/upload-artifact@v3 with: name: dxvk-${{ env.VERSION_NAME }} - path: build/dxvk-native-${{ env.VERSION_NAME }} + path: build/dxvk-native-${{ env.VERSION_NAME }}.tar.gz if-no-files-found: error From 99b47b5548604fb01f8d5551f6578aa0ac800113 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 31 Mar 2023 15:24:49 +0100 Subject: [PATCH 09/12] build: Omit v prefix from the version number It's conventional for version numbers to start with a digit. This isn't important yet, but will become significant when generating pkg-config metadata that can be queried for a sufficient version number. Signed-off-by: Simon McVittie --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index a4ddbf24..de89c317 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('dxvk', ['c', 'cpp'], version : 'v2.3.1', meson_version : '>= 0.58', default_options : [ 'cpp_std=c++17', 'warning_level=2' ]) +project('dxvk', ['c', 'cpp'], version : '2.3.1', meson_version : '>= 0.58', default_options : [ 'cpp_std=c++17', 'warning_level=2' ]) cpu_family = target_machine.cpu_family() platform = target_machine.system() From 99c65c7ccda95675a2f4cb4c89d83c9abdfb3107 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 31 Mar 2023 15:01:43 +0100 Subject: [PATCH 10/12] Set the stem of library names instead of the name_prefix This is necessary for compatibility with Meson's pkg module, which generates pkg-config metadata containing "-lNAME" where NAME is the first argument to shared_library(). Changing the name_prefix parameter would break that. Conversely, including .dll or .so in the first parameter would also break that, so remove the `+dll_ext` part (in practice this is not a functional change, because `dll_ext` is always set to an empty string). Signed-off-by: Simon McVittie --- meson.build | 5 ++--- src/d3d10/meson.build | 3 +-- src/d3d11/meson.build | 3 +-- src/d3d9/meson.build | 3 +-- src/dxgi/meson.build | 3 +-- 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/meson.build b/meson.build index de89c317..c68eb7c3 100644 --- a/meson.build +++ b/meson.build @@ -54,7 +54,7 @@ dep_displayinfo = dependency( ) if platform == 'windows' - dxvk_so_version = {} + dxvk_so_version = {'name_prefix': ''} compiler_args += [ '-DNOMINMAX', @@ -145,7 +145,7 @@ else error('SDL2 or GLFW are required to build dxvk-native') endif - dxvk_name_prefix = 'libdxvk_' + dxvk_name_prefix = 'dxvk_' link_args += [ '-static-libgcc', @@ -161,7 +161,6 @@ add_project_link_arguments(cpp.get_supported_link_arguments(link_args), language add_project_link_arguments(cc.get_supported_link_arguments(link_args), language: 'c') exe_ext = '' -dll_ext = '' def_spec_ext = '.def' glsl_compiler = find_program('glslang', 'glslangValidator') diff --git a/src/d3d10/meson.build b/src/d3d10/meson.build index 3d130b32..80038a96 100644 --- a/src/d3d10/meson.build +++ b/src/d3d10/meson.build @@ -15,8 +15,7 @@ else d3d10_d3d11_dep = d3d11_dep endif -d3d10_core_dll = shared_library('d3d10core'+dll_ext, d3d10_core_src, d3d10_core_res, - name_prefix : dxvk_name_prefix, +d3d10_core_dll = shared_library(dxvk_name_prefix+'d3d10core', d3d10_core_src, d3d10_core_res, dependencies : [ d3d10_d3d11_dep ], include_directories : dxvk_include_path, install : true, diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index 87b8b19f..195f2b77 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -77,9 +77,8 @@ else d3d11_dxgi_dep = dxgi_dep endif -d3d11_dll = shared_library('d3d11'+dll_ext, dxgi_common_src + d3d11_src + d3d10_src, +d3d11_dll = shared_library(dxvk_name_prefix+'d3d11', dxgi_common_src + d3d11_src + d3d10_src, glsl_generator.process(d3d11_shaders), d3d11_res, - name_prefix : dxvk_name_prefix, dependencies : [ d3d11_dxgi_dep, dxbc_dep, dxvk_dep ], include_directories : dxvk_include_path, install : true, diff --git a/src/d3d9/meson.build b/src/d3d9/meson.build index a4a5ee8a..34ef3fd8 100644 --- a/src/d3d9/meson.build +++ b/src/d3d9/meson.build @@ -57,8 +57,7 @@ if platform != 'windows' d3d9_link_depends += files('d3d9.sym') endif -d3d9_dll = shared_library('d3d9'+dll_ext, d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res, - name_prefix : dxvk_name_prefix, +d3d9_dll = shared_library(dxvk_name_prefix+'d3d9', d3d9_src, glsl_generator.process(d3d9_shaders), d3d9_res, dependencies : [ dxso_dep, dxvk_dep ], include_directories : dxvk_include_path, install : true, diff --git a/src/dxgi/meson.build b/src/dxgi/meson.build index fda90020..f34c7318 100644 --- a/src/dxgi/meson.build +++ b/src/dxgi/meson.build @@ -21,8 +21,7 @@ if platform != 'windows' dxgi_link_depends += files('dxgi.sym') endif -dxgi_dll = shared_library('dxgi'+dll_ext, dxgi_src, dxgi_res, - name_prefix : dxvk_name_prefix, +dxgi_dll = shared_library(dxvk_name_prefix+'dxgi', dxgi_src, dxgi_res, dependencies : [ dxvk_dep ], include_directories : dxvk_include_path, install : true, From 9f365de7d770e7d6660cbb0a4050206900f17eb6 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 31 Mar 2023 15:36:07 +0100 Subject: [PATCH 11/12] build: Install headers for native builds When building a game that has been ported to Linux using DXVK Native, these headers are necessary to provide the Direct3D and DXVK APIs. Signed-off-by: Simon McVittie --- include/native/meson.build | 18 ++++++++++++++++++ meson.build | 4 ++++ 2 files changed, 22 insertions(+) create mode 100644 include/native/meson.build diff --git a/include/native/meson.build b/include/native/meson.build new file mode 100644 index 00000000..4e1a6ff5 --- /dev/null +++ b/include/native/meson.build @@ -0,0 +1,18 @@ +install_subdir( + 'directx', + install_dir: get_option('includedir') / 'dxvk', + strip_directory: true, +) + +install_subdir( + 'windows', + install_dir: get_option('includedir') / 'dxvk', + strip_directory: true, +) + +install_headers( + 'wsi/native_wsi.h', + 'wsi/native_sdl2.h', + 'wsi/native_glfw.h', + subdir: 'dxvk/wsi', +) diff --git a/meson.build b/meson.build index c68eb7c3..cd08ac37 100644 --- a/meson.build +++ b/meson.build @@ -185,4 +185,8 @@ dxvk_version = vcs_tag( output: 'version.h', ) +if platform != 'windows' + subdir('include/native') +endif + subdir('src') From ee66e326e1c03a68ca1d2dc9cd5b2cbd1f7dfc1c Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 31 Mar 2023 15:23:03 +0100 Subject: [PATCH 12/12] build: Generate pkg-config metadata to link to DXVK libraries This allows dependent projects to query the version and location of DXVK via the pkg-config interface. The include directories aren't yet set, because the headers aren't installed; that will follow in a subsequent commit. The naming of these pkg-config files is based on proposed Fedora packages for DXVK 2.0, and is not compatible with older Fedora packages for DXVK 1.x (which used the naming convention dxvk-native-d3d9 and so on). Packagers can create symlinks such as dxvk-native-d3d9.pc -> dxvk-d3d9.pc if they want to retain compatibility with older names. Signed-off-by: Simon McVittie --- meson.build | 2 ++ src/d3d10/meson.build | 7 +++++++ src/d3d11/meson.build | 7 +++++++ src/d3d9/meson.build | 7 +++++++ src/dxgi/meson.build | 7 +++++++ 5 files changed, 30 insertions(+) diff --git a/meson.build b/meson.build index cd08ac37..a3ee4f43 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,6 @@ project('dxvk', ['c', 'cpp'], version : '2.3.1', meson_version : '>= 0.58', default_options : [ 'cpp_std=c++17', 'warning_level=2' ]) +pkg = import('pkgconfig') cpu_family = target_machine.cpu_family() platform = target_machine.system() fs = import('fs') @@ -146,6 +147,7 @@ else endif dxvk_name_prefix = 'dxvk_' + dxvk_pkg_prefix = 'dxvk-' link_args += [ '-static-libgcc', diff --git a/src/d3d10/meson.build b/src/d3d10/meson.build index 80038a96..6a690c43 100644 --- a/src/d3d10/meson.build +++ b/src/d3d10/meson.build @@ -28,3 +28,10 @@ d3d10_core_dll = shared_library(dxvk_name_prefix+'d3d10core', d3d10_core_src, d3 d3d10_core_dep = declare_dependency( link_with : [ d3d10_core_dll ], ) + +if platform != 'windows' + pkg.generate(d3d10_core_dll, + filebase: dxvk_pkg_prefix + 'd3d10core', + subdirs: 'dxvk', + ) +endif diff --git a/src/d3d11/meson.build b/src/d3d11/meson.build index 195f2b77..20bec082 100644 --- a/src/d3d11/meson.build +++ b/src/d3d11/meson.build @@ -92,3 +92,10 @@ d3d11_dep = declare_dependency( link_with : [ d3d11_dll ], include_directories : [ dxvk_include_path ], ) + +if platform != 'windows' + pkg.generate(d3d11_dll, + filebase: dxvk_pkg_prefix + 'd3d11', + subdirs: 'dxvk', + ) +endif diff --git a/src/d3d9/meson.build b/src/d3d9/meson.build index 34ef3fd8..bc3eac42 100644 --- a/src/d3d9/meson.build +++ b/src/d3d9/meson.build @@ -71,3 +71,10 @@ d3d9_dep = declare_dependency( link_with : [ d3d9_dll ], include_directories : [ dxvk_include_path ], ) + +if platform != 'windows' + pkg.generate(d3d9_dll, + filebase: dxvk_pkg_prefix + 'd3d9', + subdirs: 'dxvk', + ) +endif diff --git a/src/dxgi/meson.build b/src/dxgi/meson.build index f34c7318..7c3f4320 100644 --- a/src/dxgi/meson.build +++ b/src/dxgi/meson.build @@ -35,3 +35,10 @@ dxgi_dep = declare_dependency( link_with : [ dxgi_dll ], include_directories : [ dxvk_include_path ], ) + +if platform != 'windows' + pkg.generate(dxgi_dll, + filebase: dxvk_pkg_prefix + 'dxgi', + subdirs: 'dxvk', + ) +endif