diff --git a/src/wsi/meson.build b/src/wsi/meson.build index 0e0f9da39..a7442dfb4 100644 --- a/src/wsi/meson.build +++ b/src/wsi/meson.build @@ -3,9 +3,17 @@ wsi_win32_src = [ 'win32/wsi_window_win32.cpp', ] +wsi_sdl2_src = [ + 'sdl2/wsi_monitor_sdl2.cpp', + 'sdl2/wsi_window_sdl2.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 ] else error('Unknown wsi') endif diff --git a/src/wsi/sdl2/wsi_monitor_sdl2.cpp b/src/wsi/sdl2/wsi_monitor_sdl2.cpp new file mode 100644 index 000000000..1ab82301c --- /dev/null +++ b/src/wsi/sdl2/wsi_monitor_sdl2.cpp @@ -0,0 +1,147 @@ +#include "../wsi_monitor.h" + +#include "wsi/native_wsi.h" +#include "wsi_platform_sdl2.h" + +#include "../../util/util_string.h" +#include "../../util/log/log.h" + +#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; + + SDL_Rect rect = { }; + SDL_GetDisplayBounds(displayId, &rect); + + pRect->left = rect.x; + pRect->top = rect.y; + pRect->right = rect.x + rect.w; + pRect->bottom = rect.y + rect.h; + + return true; + } + + + 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 SDL_DisplayMode& mode, WsiMode* pMode) { + pMode->width = uint32_t(mode.w); + pMode->height = uint32_t(mode.h); + pMode->refreshRate = WsiRational{ uint32_t(mode.refresh_rate) * 1000, 1000 }; + // BPP should always be a power of two + // to match Windows behaviour of including padding. + pMode->bitsPerPixel = roundToNextPow2(SDL_BITSPERPIXEL(mode.format)); + pMode->interlaced = false; + } + + + bool getDisplayMode( + HMONITOR hMonitor, + uint32_t ModeNumber, + WsiMode* pMode) { + const int32_t displayId = fromHmonitor(hMonitor); + + if (!isDisplayValid(displayId)) + return false; + + SDL_DisplayMode mode = { }; + if (SDL_GetDisplayMode(displayId, ModeNumber, &mode) != 0) + return false; + + convertMode(mode, pMode); + + return true; + } + + + bool getCurrentDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode) { + const int32_t displayId = fromHmonitor(hMonitor); + + if (!isDisplayValid(displayId)) + return false; + + SDL_DisplayMode mode = { }; + if (SDL_GetCurrentDisplayMode(displayId, &mode) != 0) { + Logger::err(str::format("SDL_GetCurrentDisplayMode: ", SDL_GetError())); + return false; + } + + convertMode(mode, pMode); + + return true; + } + + + bool getDesktopDisplayMode( + HMONITOR hMonitor, + WsiMode* pMode) { + const int32_t displayId = fromHmonitor(hMonitor); + + if (!isDisplayValid(displayId)) + return false; + + SDL_DisplayMode mode = { }; + if (SDL_GetDesktopDisplayMode(displayId, &mode) != 0) { + Logger::err(str::format("SDL_GetCurrentDisplayMode: ", SDL_GetError())); + return false; + } + + convertMode(mode, pMode); + + return true; + } + +} \ No newline at end of file diff --git a/src/wsi/sdl2/wsi_platform_sdl2.h b/src/wsi/sdl2/wsi_platform_sdl2.h new file mode 100644 index 000000000..411fe8f6f --- /dev/null +++ b/src/wsi/sdl2/wsi_platform_sdl2.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +#include "../wsi_monitor.h" + +namespace dxvk::wsi { + + /** + * \brief Impl-dependent state + */ + struct DxvkWindowState { + }; + + inline bool isDisplayValid(int32_t displayId) { + const int32_t displayCount = SDL_GetNumVideoDisplays(); + + 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 new file mode 100644 index 000000000..7fbbb0ae2 --- /dev/null +++ b/src/wsi/sdl2/wsi_window_sdl2.cpp @@ -0,0 +1,155 @@ +#include "../wsi_window.h" + +#include "native/wsi/native_wsi.h" +#include "wsi_platform_sdl2.h" + +#include "../../util/util_string.h" +#include "../../util/log/log.h" + +#include +#include + +namespace dxvk::wsi { + + void getWindowSize( + HWND hWindow, + uint32_t* pWidth, + uint32_t* pHeight) { + SDL_Window* window = fromHwnd(hWindow); + + int32_t w, h; + SDL_GetWindowSize(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) { + SDL_Window* window = fromHwnd(hWindow); + + SDL_SetWindowSize(window, int32_t(Width), int32_t(Height)); + } + + + bool setWindowMode( + HMONITOR hMonitor, + HWND hWindow, + const WsiMode& pMode) { + const int32_t displayId = fromHmonitor(hMonitor); + SDL_Window* window = fromHwnd(hWindow); + + if (!isDisplayValid(displayId)) + return false; + + SDL_DisplayMode wantedMode = { }; + wantedMode.w = pMode.width; + wantedMode.h = pMode.height; + wantedMode.refresh_rate = pMode.refreshRate.numerator != 0 + ? pMode.refreshRate.numerator / pMode.refreshRate.denominator + : 0; + // 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())); + return false; + } + + if (SDL_SetWindowDisplayMode(window, &mode) != 0) { + Logger::err(str::format("SDL2 WSI: setWindowMode: SDL_SetWindowDisplayMode: ", SDL_GetError())); + return false; + } + + return true; + } + + + + bool enterFullscreenMode( + HMONITOR hMonitor, + HWND hWindow, + DxvkWindowState* pState, + bool ModeSwitch) { + const int32_t displayId = fromHmonitor(hMonitor); + SDL_Window* window = fromHwnd(hWindow); + + if (!isDisplayValid(displayId)) + return false; + + uint32_t flags = ModeSwitch + ? SDL_WINDOW_FULLSCREEN + : SDL_WINDOW_FULLSCREEN_DESKTOP; + + // 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())); + return false; + } + + return true; + } + + + bool leaveFullscreenMode( + HWND hWindow, + DxvkWindowState* pState) { + SDL_Window* window = fromHwnd(hWindow); + + if (SDL_SetWindowFullscreen(window, 0) != 0) { + Logger::err(str::format("SDL2 WSI: leaveFullscreenMode: SDL_SetWindowFullscreen: ", SDL_GetError())); + return false; + } + + return true; + } + + + bool restoreDisplayMode() { + // Don't need to do anything with SDL2 here. + return true; + } + + + HMONITOR getWindowMonitor(HWND hWindow) { + SDL_Window* window = fromHwnd(hWindow); + const int32_t displayId = SDL_GetWindowDisplayIndex(window); + + return toHmonitor(displayId); + } + + + bool isWindow(HWND hWindow) { + SDL_Window* window = fromHwnd(hWindow); + return window != nullptr; + } + + + void updateFullscreenWindow( + HMONITOR hMonitor, + HWND hWindow, + bool forceTopmost) { + // Don't need to do anything with SDL2 here. + } + + + VkResult createSurface( + HWND hWindow, + const Rc& vki, + VkSurfaceKHR* pSurface) { + SDL_Window* window = fromHwnd(hWindow); + + return SDL_Vulkan_CreateSurface(window, vki->instance(), pSurface) + ? VK_SUCCESS + : VK_ERROR_OUT_OF_HOST_MEMORY; + } + +} \ No newline at end of file diff --git a/src/wsi/wsi_platform.h b/src/wsi/wsi_platform.h index 5028b20bb..2cbcd2292 100644 --- a/src/wsi/wsi_platform.h +++ b/src/wsi/wsi_platform.h @@ -1,5 +1,7 @@ #pragma once -#ifdef DXVK_WSI_WIN32 +#if defined(DXVK_WSI_WIN32) #include "win32/wsi_platform_win32.h" +#elif defined(DXVK_WSI_SDL2) +#include "sdl2/wsi_platform_sdl2.h" #endif