Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

native: Add SDL3 WSI (for real) #4404

Merged
merged 2 commits into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ This is primarily useful for game and application ports to either avoid having t
DXVK Native replaces certain Windows-isms with a platform and framework-agnostic replacement, for example, `HWND`s can become `SDL_Window*`s, etc.
All it takes to do that is to add another WSI backend.

**Note:** DXVK Native requires a backend to be explicitly set via the `DXVK_WSI_DRIVER` environment variable. The current built-in options are `SDL2` and `GLFW`.
**Note:** DXVK Native requires a backend to be explicitly set via the `DXVK_WSI_DRIVER` environment variable. The current built-in options are `SDL3`, `SDL2`, and `GLFW`.

DXVK Native comes with a slim set of Windows header definitions required for D3D9/11 and the MinGW headers for D3D9/11.
In most cases, it will end up being plug and play with your renderer, but there may be certain teething issues such as:
Expand Down
1 change: 1 addition & 0 deletions include/native/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ install_subdir(

install_headers(
'wsi/native_wsi.h',
'wsi/native_sdl3.h',
'wsi/native_sdl2.h',
'wsi/native_glfw.h',
subdir: 'dxvk/wsi',
Expand Down
25 changes: 25 additions & 0 deletions include/native/wsi/native_sdl3.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <windows.h>

#include <SDL3/SDL.h>

namespace dxvk::wsi {

inline SDL_Window* fromHwnd(HWND hWindow) {
return reinterpret_cast<SDL_Window*>(hWindow);
}

inline HWND toHwnd(SDL_Window* pWindow) {
return reinterpret_cast<HWND>(pWindow);
}

// Offset so null HMONITORs go to -1
inline SDL_DisplayID fromHmonitor(HMONITOR hMonitor) {
return SDL_DisplayID(reinterpret_cast<uintptr_t>(hMonitor));
}

// Offset so -1 display id goes to 0 == NULL
inline HMONITOR toHmonitor(SDL_DisplayID display) {
return reinterpret_cast<HMONITOR>(uintptr_t(display));
}

}
2 changes: 2 additions & 0 deletions include/native/wsi/native_wsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#ifdef DXVK_WSI_WIN32
#error You shouldnt be using this code path.
#elif DXVK_WSI_SDL3
#include "wsi/native_sdl3.h"
#elif DXVK_WSI_SDL2
#include "wsi/native_sdl2.h"
#elif DXVK_WSI_GLFW
Expand Down
8 changes: 6 additions & 2 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -148,16 +148,20 @@ else
'./include/native/directx'
]

lib_sdl3 = dependency('SDL3', required: false)
lib_sdl2 = dependency('SDL2', required: false)
lib_glfw = dependency('glfw', required: false)
if lib_sdl3.found()
compiler_args += ['-DDXVK_WSI_SDL3']
endif
if lib_sdl2.found()
compiler_args += ['-DDXVK_WSI_SDL2']
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')
if (not lib_sdl3.found() and not lib_sdl2.found() and not lib_glfw.found())
error('SDL3, SDL2, or GLFW are required to build dxvk-native')
endif

dxvk_name_prefix = 'dxvk_'
Expand Down
2 changes: 1 addition & 1 deletion src/d3d9/d3d9_swapchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,7 @@ namespace dxvk {

HMONITOR monitor = wsi::getDefaultMonitor();

if (!wsi::setWindowMode(monitor, m_window, wsiMode))
if (!wsi::setWindowMode(monitor, m_window, &m_windowState, wsiMode))
return D3DERR_NOTAVAILABLE;

if (wsi::getCurrentDisplayMode(monitor, &wsiMode))
Expand Down
2 changes: 1 addition & 1 deletion src/dxgi/dxgi_swapchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,7 @@ namespace dxvk {
if (!selectedMode.RefreshRate.Denominator)
selectedMode.RefreshRate.Denominator = 1;

if (!wsi::setWindowMode(outputDesc.Monitor, m_window, ConvertDisplayMode(selectedMode)))
if (!wsi::setWindowMode(outputDesc.Monitor, m_window, &m_windowState, ConvertDisplayMode(selectedMode)))
return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE;

DXGI_VK_MONITOR_DATA* monitorData = nullptr;
Expand Down
2 changes: 1 addition & 1 deletion src/wsi/glfw/wsi_monitor_glfw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include "../wsi_monitor.h"

#include "wsi/native_wsi.h"
#include "wsi/native_glfw.h"
#include "wsi_platform_glfw.h"

#include "../../util/util_string.h"
Expand Down
1 change: 1 addition & 0 deletions src/wsi/glfw/wsi_platform_glfw.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ namespace dxvk::wsi {
virtual bool setWindowMode(
HMONITOR hMonitor,
HWND hWindow,
DxvkWindowState* pState,
const WsiMode& mode);

virtual bool enterFullscreenMode(
Expand Down
1 change: 1 addition & 0 deletions src/wsi/glfw/wsi_window_glfw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ namespace dxvk::wsi {
bool GlfwWsiDriver::setWindowMode(
HMONITOR hMonitor,
HWND hWindow,
DxvkWindowState* pState,
const WsiMode& pMode) {
const int32_t displayId = fromHmonitor(hMonitor);
GLFWwindow* window = fromHwnd(hWindow);
Expand Down
4 changes: 4 additions & 0 deletions src/wsi/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ wsi_src = [
'win32/wsi_monitor_win32.cpp',
'win32/wsi_platform_win32.cpp',
'win32/wsi_window_win32.cpp',
'sdl3/wsi_monitor_sdl3.cpp',
'sdl3/wsi_platform_sdl3.cpp',
'sdl3/wsi_window_sdl3.cpp',
'sdl2/wsi_monitor_sdl2.cpp',
'sdl2/wsi_platform_sdl2.cpp',
'sdl2/wsi_window_sdl2.cpp',
Expand All @@ -16,6 +19,7 @@ wsi_deps = [ dep_displayinfo ]

if platform != 'windows'
wsi_deps += [
lib_sdl3.partial_dependency(compile_args: true, includes: true),
lib_sdl2.partial_dependency(compile_args: true, includes: true),
lib_glfw.partial_dependency(compile_args: true, includes: true),
]
Expand Down
2 changes: 1 addition & 1 deletion src/wsi/sdl2/wsi_monitor_sdl2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include "../wsi_monitor.h"

#include "wsi/native_wsi.h"
#include "wsi/native_sdl2.h"
#include "wsi_platform_sdl2.h"

#include "../../util/util_string.h"
Expand Down
2 changes: 1 addition & 1 deletion src/wsi/sdl2/wsi_platform_sdl2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "../../util/util_string.h"
#include "../../util/util_win32_compat.h"

#include <SDL2/SDL_vulkan.h>
#include <SDL_vulkan.h>

namespace dxvk::wsi {

Expand Down
1 change: 1 addition & 0 deletions src/wsi/sdl2/wsi_platform_sdl2.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ namespace dxvk::wsi {
virtual bool setWindowMode(
HMONITOR hMonitor,
HWND hWindow,
DxvkWindowState* pState,
const WsiMode& mode);

virtual bool enterFullscreenMode(
Expand Down
1 change: 1 addition & 0 deletions src/wsi/sdl2/wsi_window_sdl2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ namespace dxvk::wsi {
bool Sdl2WsiDriver::setWindowMode(
HMONITOR hMonitor,
HWND hWindow,
DxvkWindowState* pState,
const WsiMode& pMode) {
const int32_t displayId = fromHmonitor(hMonitor);
SDL_Window* window = fromHwnd(hWindow);
Expand Down
157 changes: 157 additions & 0 deletions src/wsi/sdl3/wsi_monitor_sdl3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
#if defined(DXVK_WSI_SDL3)

#include "../wsi_monitor.h"

#include "wsi/native_sdl3.h"
#include "wsi_platform_sdl3.h"

#include "../../util/util_string.h"
#include "../../util/log/log.h"

#include <string>
#include <sstream>


namespace dxvk::wsi {

HMONITOR Sdl3WsiDriver::getDefaultMonitor() {
return enumMonitors(0);
}


HMONITOR Sdl3WsiDriver::enumMonitors(uint32_t index) {
int count = 0;

SDL_DisplayID* displays = SDL_GetDisplays(&count);

HMONITOR result = displays && int(index) < count
? toHmonitor(displays[index])
: nullptr;

SDL_free(displays);
return result;
}


HMONITOR Sdl3WsiDriver::enumMonitors(const LUID *adapterLUID[], uint32_t numLUIDs, uint32_t index) {
return enumMonitors(index);
}


bool Sdl3WsiDriver::getDisplayName(
HMONITOR hMonitor,
WCHAR (&Name)[32]) {
SDL_DisplayID displayId = fromHmonitor(hMonitor);

if (!displayId)
return false;

std::wstringstream nameStream;
nameStream << LR"(\\.\DISPLAY)" << displayId;

std::wstring name = nameStream.str();

std::memset(Name, 0, sizeof(Name));
name.copy(Name, name.length(), 0);

return true;
}


bool Sdl3WsiDriver::getDesktopCoordinates(
HMONITOR hMonitor,
RECT* pRect) {
SDL_DisplayID displayId = fromHmonitor(hMonitor);

if (!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;
}


bool Sdl3WsiDriver::getDisplayMode(
HMONITOR hMonitor,
uint32_t ModeNumber,
WsiMode* pMode) {
SDL_DisplayID displayId = fromHmonitor(hMonitor);

if (!displayId)
return false;

int count = 0;
auto* modes = SDL_GetFullscreenDisplayModes(displayId, &count);

if (!modes) {
Logger::err(str::format("SDL_GetFullscreenDisplayModes: ", SDL_GetError()));
return false;
}

if (int(ModeNumber) >= count) {
SDL_free(modes);
return false;
}

convertMode(*modes[ModeNumber], pMode);

SDL_free(modes);
return true;
}


bool Sdl3WsiDriver::getCurrentDisplayMode(
HMONITOR hMonitor,
WsiMode* pMode) {
SDL_DisplayID displayId = fromHmonitor(hMonitor);

if (!displayId)
return false;

auto* mode = SDL_GetCurrentDisplayMode(displayId);

if (!mode) {
Logger::err(str::format("SDL_GetCurrentDisplayMode: ", SDL_GetError()));
return false;
}

convertMode(*mode, pMode);
return true;
}


bool Sdl3WsiDriver::getDesktopDisplayMode(
HMONITOR hMonitor,
WsiMode* pMode) {
SDL_DisplayID displayId = fromHmonitor(hMonitor);

if (!displayId)
return false;

auto* mode = SDL_GetDesktopDisplayMode(displayId);

if (!mode) {
Logger::err(str::format("SDL_GetDesktopDisplayMode: ", SDL_GetError()));
return false;
}

convertMode(*mode, pMode);
return true;
}


std::vector<uint8_t> Sdl3WsiDriver::getMonitorEdid(HMONITOR hMonitor) {
Logger::err("getMonitorEdid not implemented on this platform.");
return {};
}

}

#endif
Loading