Files
psxrecomp/runtime/include/window_fullscreen.h
T
yacineolivier-maker 20a9312049 Borderless fullscreen (Windows): keep the window composed (one row taller)
A window exactly covering the display is promoted by Windows to a direct /
independent flip. OpenGL swaps issued from the render thread then stop
reaching the screen on NVIDIA drivers: the image freezes while the game keeps
running, and it comes back as soon as anything forces composition (taskbar,
another window, a tooltip). The borderless window is now one row taller than
the display (the extra row is off-screen), so it always stays composed.
test_window_fullscreen checks the new size.

Seen with R4 on an RTX 3060 (driver 576.57), Windows 11, render thread on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rkyma8rbyPiccs9n2bkyG6
2026-10-20 21:58:41 +02:00

105 lines
4.1 KiB
C

#pragma once
#include "psx_sdl.h"
/* On Windows/SDL3, borderless stays a normal desktop-sized window. Other
* window managers retain native desktop fullscreen (Wayland owns placement). */
struct PsxWindowFullscreen {
int mode = 0;
int x = 0, y = 0, width = 0, height = 0;
bool maximized = false;
bool bordered = true;
bool resizable = true;
bool cursor_visible = true;
};
static inline int psx_window_fullscreen_set(SDL_Window* window,
PsxWindowFullscreen* state, int mode)
{
if (!window || !state || mode < 0 || mode > 2) return -1;
if (state->mode == mode) return 0;
if (state->mode == 0) {
const auto flags = SDL_GetWindowFlags(window);
state->maximized = (flags & SDL_WINDOW_MAXIMIZED) != 0;
state->bordered = (flags & SDL_WINDOW_BORDERLESS) == 0;
state->resizable = (flags & SDL_WINDOW_RESIZABLE) != 0;
if (state->maximized) {
SDL_RestoreWindow(window);
#if defined(PSX_SDL3)
SDL_SyncWindow(window);
#endif
}
SDL_GetWindowPosition(window, &state->x, &state->y);
SDL_GetWindowSize(window, &state->width, &state->height);
#if defined(PSX_SDL3)
state->cursor_visible = SDL_CursorVisible();
#else
state->cursor_visible = SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE;
#endif
}
SDL_Rect desktop{};
#if defined(PSX_SDL3)
const SDL_DisplayID display = SDL_GetDisplayForWindow(window);
if (mode == 1 && (!display || !SDL_GetDisplayBounds(display, &desktop))) return -1;
SDL_DisplayMode exclusive{};
if (mode == 2) {
const SDL_DisplayMode* current = SDL_GetDesktopDisplayMode(display);
if (!current || !SDL_GetClosestFullscreenDisplayMode(display, current->w,
current->h, current->refresh_rate, true, &exclusive)) return -1;
}
if (!SDL_SetWindowFullscreen(window, false)) return -1;
if (!SDL_SetWindowFullscreenMode(window, mode == 2 ? &exclusive : nullptr)) return -1;
#else
const int display = SDL_GetWindowDisplayIndex(window);
if (mode == 1 && (display < 0 || SDL_GetDisplayBounds(display, &desktop) != 0)) return -1;
if (SDL_SetWindowFullscreen(window, 0) != 0) return -1;
#endif
/* Maximized windows can ignore manual geometry; restore before resizing. */
SDL_RestoreWindow(window);
#if defined(PSX_SDL3)
SDL_SyncWindow(window);
#endif
if (mode == 1) {
#if defined(_WIN32) && defined(PSX_SDL3)
SDL_SetWindowBordered(window, SDL_FALSE);
SDL_SetWindowResizable(window, SDL_FALSE);
SDL_SetWindowPosition(window, desktop.x, desktop.y);
/* One row taller than the display: a window exactly covering it is
* promoted by Windows to a direct/independent flip, and OpenGL swaps
* from the render thread then stop reaching the screen (NVIDIA: the
* image freezes while the game runs; any overlay -- taskbar, another
* window -- forces composition and the frames reappear). The extra
* row is off-screen; the window stays composed. */
SDL_SetWindowSize(window, desktop.w, desktop.h + 1);
SDL_SyncWindow(window);
#elif defined(PSX_SDL3)
if (!SDL_SetWindowFullscreen(window, true)) return -1;
#else
if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP) != 0) return -1;
#endif
} else {
SDL_SetWindowBordered(window, state->bordered ? SDL_TRUE : SDL_FALSE);
SDL_SetWindowResizable(window, state->resizable ? SDL_TRUE : SDL_FALSE);
SDL_SetWindowSize(window, state->width, state->height);
SDL_SetWindowPosition(window, state->x, state->y);
if (mode == 2) {
#if defined(PSX_SDL3)
if (!SDL_SetWindowFullscreen(window, true)) return -1;
#else
if (SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN) != 0) return -1;
#endif
} else if (state->maximized) {
SDL_MaximizeWindow(window);
}
}
state->mode = mode;
#if defined(PSX_SDL3)
if (mode || !state->cursor_visible) SDL_HideCursor();
else SDL_ShowCursor();
#else
SDL_ShowCursor(mode || !state->cursor_visible ? SDL_DISABLE : SDL_ENABLE);
#endif
return 0;
}