From c1213d8c07c21990f3d17ca783a256c5bcd8e4fc Mon Sep 17 00:00:00 2001 From: Beyley Thomas Date: Sun, 7 Aug 2022 19:46:26 -0700 Subject: [PATCH] Add GLFW WSI --- include/native/wsi/native_glfw.h | 26 ++++++ include/native/wsi/native_wsi.h | 2 + meson.build | 12 ++- src/dxvk/meson.build | 6 ++ src/dxvk/platform/dxvk_glfw_exts.cpp | 57 ++++++++++++ src/vulkan/vulkan_presenter.cpp | 10 ++- src/wsi/glfw/wsi_helpers_glfw.h | 16 ++++ src/wsi/glfw/wsi_mode_glfw.cpp | 94 ++++++++++++++++++++ src/wsi/glfw/wsi_monitor_glfw.cpp | 70 +++++++++++++++ src/wsi/glfw/wsi_presenter_glfw.cpp | 18 ++++ src/wsi/glfw/wsi_window_glfw.cpp | 125 +++++++++++++++++++++++++++ src/wsi/meson.build | 10 +++ 12 files changed, 440 insertions(+), 6 deletions(-) create mode 100644 include/native/wsi/native_glfw.h create mode 100644 src/dxvk/platform/dxvk_glfw_exts.cpp create mode 100644 src/wsi/glfw/wsi_helpers_glfw.h create mode 100644 src/wsi/glfw/wsi_mode_glfw.cpp create mode 100644 src/wsi/glfw/wsi_monitor_glfw.cpp create mode 100644 src/wsi/glfw/wsi_presenter_glfw.cpp create mode 100644 src/wsi/glfw/wsi_window_glfw.cpp diff --git a/include/native/wsi/native_glfw.h b/include/native/wsi/native_glfw.h new file mode 100644 index 00000000..7cbf9bc0 --- /dev/null +++ b/include/native/wsi/native_glfw.h @@ -0,0 +1,26 @@ +#include +#include + +#include + +namespace dxvk::wsi { + + inline GLFWwindow* fromHwnd(HWND hWindow) { + return reinterpret_cast(hWindow); + } + + inline HWND toHwnd(GLFWwindow* pWindow) { + return reinterpret_cast(pWindow); + } + + // Offset so null HMONITORs go to -1 + inline int32_t fromHmonitor(HMONITOR hMonitor) { + return static_cast(reinterpret_cast(hMonitor)) - 1; + } + + // Offset so -1 display id goes to 0 == NULL + inline HMONITOR toHmonitor(int32_t displayId) { + return reinterpret_cast(static_cast(displayId + 1)); + } + +} \ No newline at end of file diff --git a/include/native/wsi/native_wsi.h b/include/native/wsi/native_wsi.h index 00a29906..cfb64f12 100644 --- a/include/native/wsi/native_wsi.h +++ b/include/native/wsi/native_wsi.h @@ -4,6 +4,8 @@ #error You shouldnt be using this code path. #elif DXVK_WSI_SDL2 #include "wsi/native_sdl2.h" +#elif DXVK_WSI_GLFW +#include "wsi/native_glfw.h" #else #error Unknown wsi! #endif \ No newline at end of file diff --git a/meson.build b/meson.build index 0b9a1185..f09ecb53 100644 --- a/meson.build +++ b/meson.build @@ -136,12 +136,20 @@ else if dxvk_platform == 'windows' dxvk_include_path = include_directories('./include', './include/native/') lib_vulkan = dxvk_compiler.find_library('vulkan-1', dirs : dxvk_library_path) - lib_sdl2 = dxvk_compiler.find_library('SDL2', dirs : dxvk_library_path) + if dxvk_wsi == 'sdl2' + lib_sdl2 = dxvk_compiler.find_library('SDL2', dirs : dxvk_library_path) + elif dxvk_wsi == 'glfw' + lib_glfw = dxvk_compiler.find_library('glfw', dirs : dxvk_library_path) + endif wrc = find_program('rc') else dxvk_include_path = include_directories('./include', './include/native/', './include/native/windows', './include/native/directx') lib_vulkan = dxvk_compiler.find_library('vulkan') - lib_sdl2 = dxvk_compiler.find_library('SDL2') + if dxvk_wsi == 'sdl2' + lib_sdl2 = dxvk_compiler.find_library('SDL2') + elif dxvk_wsi == 'glfw' + lib_glfw = dxvk_compiler.find_library('glfw') + endif wrc = find_program('echo') so_prefix = 'libdxvk_' endif diff --git a/src/dxvk/meson.build b/src/dxvk/meson.build index 71359110..da95d7a7 100644 --- a/src/dxvk/meson.build +++ b/src/dxvk/meson.build @@ -122,10 +122,16 @@ dxvk_src_sdl2 = [ 'platform/dxvk_sdl2_exts.cpp' ] +dxvk_src_glfw = [ + 'platform/dxvk_glfw_exts.cpp' +] + if dxvk_wsi == 'win32' dxvk_src += dxvk_src_win32 elif dxvk_wsi == 'sdl2' dxvk_src += dxvk_src_sdl2 +elif dxvk_wsi == 'glfw' + dxvk_src += dxvk_src_glfw else error('Unknown platform for dxvk') endif diff --git a/src/dxvk/platform/dxvk_glfw_exts.cpp b/src/dxvk/platform/dxvk_glfw_exts.cpp new file mode 100644 index 00000000..c9ecf7e0 --- /dev/null +++ b/src/dxvk/platform/dxvk_glfw_exts.cpp @@ -0,0 +1,57 @@ +#include "../dxvk_platform_exts.h" + +#define GLFW_INCLUDE_VULKAN +#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!")); + + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + GLFWwindow* window = glfwCreateWindow(1, 1, "Dummy Window", nullptr, nullptr); + + if (window == nullptr) + throw DxvkError(str::format("GLFW WSI: Unable to create dummy window")); + + 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 (int i = 0; i < extensionCount; ++i) { + names.add(extensionArray[i]); + } + + glfwDestroyWindow(window); + + return names; + } + + + DxvkNameSet DxvkPlatformExts::getDeviceExtensions( + uint32_t adapterId) { + return DxvkNameSet(); + } + + + void DxvkPlatformExts::initInstanceExtensions() { + + } + + + void DxvkPlatformExts::initDeviceExtensions( + const DxvkInstance* instance) { + + } + +} \ No newline at end of file diff --git a/src/vulkan/vulkan_presenter.cpp b/src/vulkan/vulkan_presenter.cpp index 01811000..33cfc2d7 100644 --- a/src/vulkan/vulkan_presenter.cpp +++ b/src/vulkan/vulkan_presenter.cpp @@ -22,11 +22,13 @@ namespace dxvk::vk { } #endif - if (createSurface() != VK_SUCCESS) - throw DxvkError("Failed to create surface"); + auto result = createSurface(); + if (result != VK_SUCCESS) + throw DxvkError(str::format("Failed to create surface. Result: ", result)); - if (recreateSwapChain(desc) != VK_SUCCESS) - throw DxvkError("Failed to create swap chain"); + result = recreateSwapChain(desc); + if (result != VK_SUCCESS) + throw DxvkError(str::format("Failed to create swap chain. Result: ", result)); } diff --git a/src/wsi/glfw/wsi_helpers_glfw.h b/src/wsi/glfw/wsi_helpers_glfw.h new file mode 100644 index 00000000..993e5d81 --- /dev/null +++ b/src/wsi/glfw/wsi_helpers_glfw.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "../wsi_monitor.h" + +namespace dxvk { + + inline bool isDisplayValid(int32_t displayId) { + int32_t displayCount = 0; + glfwGetMonitors(&displayCount); + + return displayId < displayCount && displayId >= 0; + } + +} \ No newline at end of file diff --git a/src/wsi/glfw/wsi_mode_glfw.cpp b/src/wsi/glfw/wsi_mode_glfw.cpp new file mode 100644 index 00000000..4a940d23 --- /dev/null +++ b/src/wsi/glfw/wsi_mode_glfw.cpp @@ -0,0 +1,94 @@ +#include "../wsi_mode.h" + +#include "wsi_helpers_glfw.h" + +#include + +#include "../../util/util_string.h" +#include "../../util/log/log.h" + +namespace dxvk::wsi { + + static inline uint32_t roundToNextPow2(uint32_t num) { + if (num-- == 0) + return 0; + + num |= num >> 1; num |= num >> 2; + num |= num >> 4; num |= num >> 8; + num |= num >> 16; + + return ++num; + } + + + static inline void convertMode(const GLFWvidmode& mode, WsiMode* pMode) { + pMode->width = uint32_t(mode.width); + pMode->height = uint32_t(mode.height); + pMode->refreshRate = WsiRational{ uint32_t(mode.refreshRate) * 1000, 1000 }; + // BPP should always be a power of two + // to match Windows behaviour of including padding. + pMode->bitsPerPixel = roundToNextPow2(mode.blueBits + mode.redBits + mode.greenBits); + pMode->interlaced = false; + } + + + bool getDisplayMode( + HMONITOR hMonitor, + uint32_t ModeNumber, + WsiMode* pMode) { + const int32_t displayId = fromHmonitor(hMonitor); + int32_t displayCount = 0; + GLFWmonitor** monitors = glfwGetMonitors(&displayCount); + GLFWmonitor* monitor = monitors[displayId]; + + if (!isDisplayValid(displayId)) + return false; + + int32_t count = 0; + const GLFWvidmode* modes = glfwGetVideoModes(monitor, &count); + + convertMode(modes[ModeNumber], pMode); + + return true; + } + + + bool getCurrentDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode) { + const int32_t displayId = fromHmonitor(hMonitor); + + if (!isDisplayValid(displayId)) + return false; + + int32_t displayCount = 0; + GLFWmonitor** monitors = glfwGetMonitors(&displayCount); + GLFWmonitor* monitor = monitors[displayId]; + + auto mode = glfwGetVideoMode(monitor); + + convertMode(*mode, pMode); + + return true; + } + + + bool getDesktopDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode) { + const int32_t displayId = fromHmonitor(hMonitor); + + if (!isDisplayValid(displayId)) + return false; + + int32_t displayCount = 0; + GLFWmonitor** monitors = glfwGetMonitors(&displayCount); + GLFWmonitor* monitor = monitors[displayId]; + + //TODO: actually implement this properly, currently we just grab the current one + convertMode(*glfwGetVideoMode(monitor), pMode); + + return true; + } + +} diff --git a/src/wsi/glfw/wsi_monitor_glfw.cpp b/src/wsi/glfw/wsi_monitor_glfw.cpp new file mode 100644 index 00000000..9a9b8590 --- /dev/null +++ b/src/wsi/glfw/wsi_monitor_glfw.cpp @@ -0,0 +1,70 @@ +#include "../wsi_monitor.h" + +#include "wsi_helpers_glfw.h" + +#include +#include + +#include +#include + +namespace dxvk::wsi { + + HMONITOR getDefaultMonitor() { + return enumMonitors(0); + } + + + HMONITOR enumMonitors(uint32_t index) { + return isDisplayValid(int32_t(index)) + ? toHmonitor(index) + : nullptr; + } + + bool getDisplayName( + HMONITOR hMonitor, + WCHAR (&Name)[32]) { + const int32_t displayId = fromHmonitor(hMonitor); + + if (!isDisplayValid(displayId)) + return false; + + std::wstringstream nameStream; + nameStream << LR"(\\.\DISPLAY)" << (displayId + 1); + + std::wstring name = nameStream.str(); + + std::memset(Name, 0, sizeof(Name)); + name.copy(Name, name.length(), 0); + + return true; + } + + + bool getDesktopCoordinates( + HMONITOR hMonitor, + RECT* pRect) { + const int32_t displayId = fromHmonitor(hMonitor); + + if (!isDisplayValid(displayId)) + return false; + + int32_t displayCount = 0; + GLFWmonitor** monitors = glfwGetMonitors(&displayCount); + GLFWmonitor* monitor = monitors[displayId]; + + int32_t x; + int32_t y; + int32_t w; + int32_t h; + glfwGetMonitorWorkarea(monitor, &x, &y, &w, &h); + + pRect->left = x; + pRect->top = y; + pRect->right = x + w; + pRect->bottom = y + h; + + return true; + } + +} \ No newline at end of file diff --git a/src/wsi/glfw/wsi_presenter_glfw.cpp b/src/wsi/glfw/wsi_presenter_glfw.cpp new file mode 100644 index 00000000..8946fa88 --- /dev/null +++ b/src/wsi/glfw/wsi_presenter_glfw.cpp @@ -0,0 +1,18 @@ +#include "../wsi_presenter.h" + +#include + +#include + +namespace dxvk::wsi { + + VkResult createSurface( + HWND hWindow, + const Rc& vki, + VkSurfaceKHR* pSurface) { + GLFWwindow* window = fromHwnd(hWindow); + + return glfwCreateWindowSurface(vki->instance(), window, nullptr, pSurface); + } + +} \ No newline at end of file diff --git a/src/wsi/glfw/wsi_window_glfw.cpp b/src/wsi/glfw/wsi_window_glfw.cpp new file mode 100644 index 00000000..7cc2c964 --- /dev/null +++ b/src/wsi/glfw/wsi_window_glfw.cpp @@ -0,0 +1,125 @@ +#include "../wsi_window.h" + +#include "wsi_helpers_glfw.h" + +//#include + +#include +#include + +#include "../../util/util_string.h" +#include "../../util/log/log.h" + +namespace dxvk::wsi { + + void getWindowSize( + HWND hWindow, + uint32_t* pWidth, + uint32_t* pHeight) { + GLFWwindow* window = fromHwnd(hWindow); + + int32_t w, h; + glfwGetWindowSize(window, &w, &h); + + if (pWidth) + *pWidth = uint32_t(w); + + if (pHeight) + *pHeight = uint32_t(h); + } + + + void resizeWindow( + HWND hWindow, + DxvkWindowState* pState, + uint32_t Width, + uint32_t Height) { + GLFWwindow* window = fromHwnd(hWindow); + + glfwSetWindowSize(window, int32_t(Width), int32_t(Height)); + } + + + bool setWindowMode( + HMONITOR hMonitor, + HWND hWindow, + const WsiMode* pMode, + bool EnteringFullscreen) { + const int32_t displayId = fromHmonitor(hMonitor); + GLFWwindow* window = fromHwnd(hWindow); + + if (!isDisplayValid(displayId)) + return false; + + int32_t displayCount = 0; + GLFWmonitor** monitors = glfwGetMonitors(&displayCount); + GLFWmonitor* monitor = monitors[displayId]; + + GLFWvidmode wantedMode = { }; + wantedMode.width = pMode->width; + wantedMode.height = pMode->height; + wantedMode.refreshRate = pMode->refreshRate.numerator != 0 + ? pMode->refreshRate.numerator / pMode->refreshRate.denominator + : 0; + // TODO: Implement lookup format for bitsPerPixel here. + + glfwSetWindowMonitor(window, monitor, 0, 0, wantedMode.width, wantedMode.width, wantedMode.refreshRate); + + return true; + } + + bool enterFullscreenMode( + HMONITOR hMonitor, + HWND hWindow, + DxvkWindowState* pState, + bool ModeSwitch) { + const int32_t displayId = fromHmonitor(hMonitor); + GLFWwindow* window = fromHwnd(hWindow); + + if (!isDisplayValid(displayId)) + return false; + + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + auto videoMode = glfwGetVideoMode(monitor); + + // TODO: Set this on the correct monitor. + // Docs aren't clear on this... + glfwSetWindowMonitor(window, monitor, 0, 0, videoMode->width, videoMode->height, videoMode->refreshRate); + + return true; + } + + + bool leaveFullscreenMode( + HWND hWindow, + DxvkWindowState* pState) { + GLFWwindow* window = fromHwnd(hWindow); + + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + auto videoMode = glfwGetVideoMode(monitor); + glfwSetWindowMonitor(window, nullptr, 0, 0, videoMode->width, videoMode->height, videoMode->refreshRate); + + return true; + } + + + bool restoreDisplayMode(HMONITOR hMonitor) { + const int32_t displayId = fromHmonitor(hMonitor); + return isDisplayValid(displayId); + } + + + HMONITOR getWindowMonitor(HWND hWindow) { + GLFWwindow* window = fromHwnd(hWindow); + const int32_t displayId = 0; + + return toHmonitor(displayId); + } + + + bool isWindow(HWND hWindow) { + GLFWwindow* window = fromHwnd(hWindow); + return window != nullptr; + } + +} \ No newline at end of file diff --git a/src/wsi/meson.build b/src/wsi/meson.build index 6ab147be..cd517184 100644 --- a/src/wsi/meson.build +++ b/src/wsi/meson.build @@ -12,12 +12,22 @@ wsi_sdl2_src = [ 'sdl2/wsi_window_sdl2.cpp', ] +wsi_glfw_src = [ + 'glfw/wsi_mode_glfw.cpp', + 'glfw/wsi_monitor_glfw.cpp', + 'glfw/wsi_presenter_glfw.cpp', + 'glfw/wsi_window_glfw.cpp', +] + if dxvk_wsi == 'win32' wsi_src = wsi_win32_src wsi_deps = [] elif dxvk_wsi == 'sdl2' wsi_src = wsi_sdl2_src wsi_deps = [ lib_sdl2 ] +elif dxvk_wsi == 'glfw' + wsi_src = wsi_glfw_src + wsi_deps = [ lib_glfw ] else error('Unknown wsi') endif