Mini: Set fullscreen display mode on "windows" on kmsdrm

Allow the user to choose the display mode.
pull/3699/head
Stenzek 7 months ago
parent 4f6c42e0f7
commit 0d0bd69ada
No known key found for this signature in database

@ -64,10 +64,9 @@ namespace MiniHost {
/// Use two async worker threads, should be enough for most tasks.
static constexpr u32 NUM_ASYNC_WORKER_THREADS = 2;
// static constexpr u32 DEFAULT_WINDOW_WIDTH = 1280;
// static constexpr u32 DEFAULT_WINDOW_HEIGHT = 720;
static constexpr u32 DEFAULT_WINDOW_WIDTH = 1920;
static constexpr u32 DEFAULT_WINDOW_HEIGHT = 1080;
static constexpr float DEFAULT_WINDOW_REFRESH_RATE = 60.0f;
static constexpr auto CORE_THREAD_POLL_INTERVAL =
std::chrono::milliseconds(8); // how often we'll poll controllers when paused
@ -96,6 +95,7 @@ static std::string GetWindowTitle(const std::string& game_title);
static std::optional<WindowInfo> TranslateSDLWindowInfo(SDL_Window* win, Error* error);
static bool GetSavedPlatformWindowGeometry(s32* x, s32* y, s32* width, s32* height);
static void SavePlatformWindowGeometry(s32 x, s32 y, s32 width, s32 height);
static void DestroySDLWindow();
struct SDLHostState
{
@ -111,6 +111,7 @@ struct SDLHostState
float sdl_window_scale = 0.0f;
float sdl_window_refresh_rate = 0.0f;
WindowInfoPrerotation force_prerotation = WindowInfoPrerotation::Identity;
bool use_window_fullscreen_mode = false;
Threading::Thread core_thread;
Threading::Thread video_thread;
@ -161,6 +162,23 @@ bool MiniHost::EarlyProcessStartup()
return false;
}
s_state.func_event_id = SDL_RegisterEvents(1);
if (s_state.func_event_id == static_cast<u32>(-1))
{
Host::ReportFatalError("Error", TinyString::from_format("SDL_RegisterEvents() failed: {}", SDL_GetError()));
return false;
}
#ifdef __linux__
// If we're running without a windowing system, force fullscreen.
if (const char* video_driver = SDL_GetCurrentVideoDriver(); video_driver && std::strcmp(video_driver, "kmsdrm") == 0)
{
fprintf(stderr, "kmsdrm video driver detected, using fullscreen display mode for windows.\n");
s_state.use_window_fullscreen_mode = true;
s_state.start_fullscreen_ui_fullscreen = true;
}
#endif
#if !__has_include("scmversion/tag.h")
//
// To those distributing their own builds or packages of DuckStation, and seeing this message:
@ -358,7 +376,19 @@ std::optional<WindowInfo> MiniHost::TranslateSDLWindowInfo(SDL_Window* win, Erro
int window_px_width = 1, window_px_height = 1;
SDL_GetWindowSize(win, &window_width, &window_height);
SDL_GetWindowSizeInPixels(win, &window_px_width, &window_px_height);
s_state.sdl_window_scale = SDL_GetWindowDisplayScale(win);
// For kmsdrm, assume 720p is 100% scale. Jank, but no other way to do it outside of querying the display size..
if (s_state.use_window_fullscreen_mode)
{
s_state.sdl_window_scale = std::clamp(std::min(window_px_width / 1280.0f, window_px_height / 720.0f), 1.0f, 4.0f);
INFO_LOG("Using window fullscreen display mode, setting scale to {}", s_state.sdl_window_scale);
}
else
{
s_state.sdl_window_scale = SDL_GetWindowDisplayScale(win);
INFO_LOG("Using window scale of {} (window size {}x{}, pixel size {}x{})", s_state.sdl_window_scale, window_width,
window_height, window_px_width, window_px_height);
}
const SDL_DisplayMode* dispmode = nullptr;
@ -481,6 +511,9 @@ std::optional<WindowInfo> Host::AcquireRenderWindow(RenderAPI render_api, bool f
std::optional<WindowInfo> wi;
Host::RunOnUIThread([render_api, fullscreen, error, &wi]() {
// Don't try to create multiple windows, kmsdrm breaks.
DestroySDLWindow();
const std::string window_title = GetWindowTitle(System::GetGameTitle());
const SDL_PropertiesID props = SDL_CreateProperties();
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, window_title.c_str());
@ -494,24 +527,61 @@ std::optional<WindowInfo> Host::AcquireRenderWindow(RenderAPI render_api, bool f
else if (render_api == RenderAPI::Vulkan)
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_VULKAN_BOOLEAN, true);
if (fullscreen)
{
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, true);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true);
}
std::optional<SDL_DisplayMode> window_fullscreen_mode;
if (s32 window_x, window_y, window_width, window_height;
MiniHost::GetSavedPlatformWindowGeometry(&window_x, &window_y, &window_width, &window_height))
if (!s_state.use_window_fullscreen_mode)
{
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, window_x);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, window_y);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, window_width);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, window_height);
if (fullscreen)
{
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, true);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true);
}
if (s32 window_x, window_y, window_width, window_height;
MiniHost::GetSavedPlatformWindowGeometry(&window_x, &window_y, &window_width, &window_height))
{
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, window_x);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, window_y);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, window_width);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, window_height);
}
else
{
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, DEFAULT_WINDOW_WIDTH);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, DEFAULT_WINDOW_HEIGHT);
}
}
else
{
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, DEFAULT_WINDOW_WIDTH);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, DEFAULT_WINDOW_HEIGHT);
std::optional<GPUDevice::ExclusiveFullscreenMode> fullscreen_mode =
GPUDevice::ExclusiveFullscreenMode::Parse(Core::GetTinyStringSettingValue("GPU", "FullscreenMode"));
if (!fullscreen_mode.has_value())
{
INFO_LOG("Using default fullscreen mode ({}x{})", DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT);
fullscreen_mode =
GPUDevice::ExclusiveFullscreenMode{DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT, DEFAULT_WINDOW_REFRESH_RATE};
}
window_fullscreen_mode.emplace();
if (SDL_GetClosestFullscreenDisplayMode(SDL_GetPrimaryDisplay(), fullscreen_mode->width, fullscreen_mode->height,
fullscreen_mode->refresh_rate, true, &window_fullscreen_mode.value()))
{
INFO_LOG("Requesting window fullscreen display mode {}x{} @ {} hz (closest match: {}x{} @ {} hz)",
fullscreen_mode->width, fullscreen_mode->height, fullscreen_mode->refresh_rate,
window_fullscreen_mode->w, window_fullscreen_mode->h, window_fullscreen_mode->refresh_rate);
// For GL we need to set the window size to the display mode. Annoyingly can't set the refresh rate...
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, window_fullscreen_mode->w);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, window_fullscreen_mode->h);
}
else
{
ERROR_LOG("SDL_GetClosestFullscreenDisplayMode() failed: {}", SDL_GetError());
window_fullscreen_mode.reset();
}
// Force fullscreen.
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, true);
}
s_state.sdl_window = SDL_CreateWindowWithProperties(props);
@ -519,6 +589,12 @@ std::optional<WindowInfo> Host::AcquireRenderWindow(RenderAPI render_api, bool f
if (s_state.sdl_window)
{
if (window_fullscreen_mode.has_value() &&
!SDL_SetWindowFullscreenMode(s_state.sdl_window, &window_fullscreen_mode.value()))
{
ERROR_LOG("SDL_SetWindowFullscreenMode() failed: {}", SDL_GetError());
}
wi = TranslateSDLWindowInfo(s_state.sdl_window, error);
if (!wi.has_value())
{
@ -556,27 +632,34 @@ void Host::ReleaseRenderWindow()
return;
Host::RunOnUIThread([]() {
if (!(SDL_GetWindowFlags(s_state.sdl_window) & SDL_WINDOW_FULLSCREEN))
{
int window_x = SDL_WINDOWPOS_UNDEFINED, window_y = SDL_WINDOWPOS_UNDEFINED;
int window_width = DEFAULT_WINDOW_WIDTH, window_height = DEFAULT_WINDOW_HEIGHT;
SDL_GetWindowPosition(s_state.sdl_window, &window_x, &window_y);
SDL_GetWindowSize(s_state.sdl_window, &window_width, &window_height);
MiniHost::SavePlatformWindowGeometry(window_x, window_y, window_width, window_height);
}
SDL_DestroyWindow(s_state.sdl_window);
s_state.sdl_window = nullptr;
DestroySDLWindow();
s_state.platform_window_updated.Post();
});
s_state.platform_window_updated.Wait();
}
void MiniHost::DestroySDLWindow()
{
if (!s_state.sdl_window)
return;
if (!(SDL_GetWindowFlags(s_state.sdl_window) & SDL_WINDOW_FULLSCREEN))
{
int window_x = SDL_WINDOWPOS_UNDEFINED, window_y = SDL_WINDOWPOS_UNDEFINED;
int window_width = DEFAULT_WINDOW_WIDTH, window_height = DEFAULT_WINDOW_HEIGHT;
SDL_GetWindowPosition(s_state.sdl_window, &window_x, &window_y);
SDL_GetWindowSize(s_state.sdl_window, &window_width, &window_height);
MiniHost::SavePlatformWindowGeometry(window_x, window_y, window_width, window_height);
}
SDL_DestroyWindow(s_state.sdl_window);
s_state.sdl_window = nullptr;
}
bool Host::CanChangeFullscreenMode(bool new_fullscreen_state)
{
return true;
return !MiniHost::s_state.use_window_fullscreen_mode;
}
void Host::BeginTextInput()
@ -1698,13 +1781,6 @@ int main(int argc, char* argv[])
return EXIT_FAILURE;
}
s_state.func_event_id = SDL_RegisterEvents(1);
if (s_state.func_event_id == static_cast<u32>(-1))
{
Host::ReportFatalError("Error", TinyString::from_format("SDL_RegisterEvents() failed: {}", SDL_GetError()));
return EXIT_FAILURE;
}
if (!EarlyProcessStartup())
return EXIT_FAILURE;

Loading…
Cancel
Save