mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
Game Mode: Steam Deck / gamescope boots straight into the game, fullscreen
Detected from a gamescope session (XDG_CURRENT_DESKTOP, GAMESCOPE_WAYLAND_DISPLAY) or Steam's gamepad UI (SteamGamepadUI=1); --game-mode / --no-game-mode and PSX_GAME_MODE override. When on and a disc is set up, the launcher is skipped and the game opens borderless fullscreen for that run (the saved Fullscreen choice is untouched); the first run still shows the launcher so the disc can be picked. Desktop sessions, --headless and --hidden-window are unchanged. game_mode_test covers detection and precedence; docs/GAME_MODE.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
# Game Mode (Steam Deck, gamescope)
|
||||
|
||||
On a Steam Deck in Game Mode, or any gamescope session, there is no desktop.
|
||||
The launcher is an extra screen built for a mouse, and a windowed game sits
|
||||
inside a fullscreen compositor anyway. Game Mode therefore boots straight into
|
||||
the game, borderless fullscreen.
|
||||
|
||||
| Source | Effect |
|
||||
| --- | --- |
|
||||
| `--game-mode` / `--no-game-mode` | on / off (wins over everything) |
|
||||
| `PSX_GAME_MODE=1` / `=0` | on / off |
|
||||
| `XDG_CURRENT_DESKTOP` contains `gamescope`, or `GAMESCOPE_WAYLAND_DISPLAY` is set | on (detected) |
|
||||
| `SteamGamepadUI=1` (started from Big Picture / Game Mode) | on (detected) |
|
||||
| none of the above | off: desktop behaviour, unchanged |
|
||||
|
||||
When it is on:
|
||||
|
||||
- With a disc already set up (settings.toml `[disc] path`, or `--disc`), the
|
||||
launcher is skipped and the game opens borderless fullscreen. The saved
|
||||
Fullscreen choice is not changed, so Desktop Mode keeps its own.
|
||||
- On the first run, with no disc yet, the launcher opens so the player can pick
|
||||
their disc image. The next start goes straight in.
|
||||
- `--launcher` still opens the launcher. In Game Mode, add it to the Steam
|
||||
shortcut's launch options to reach the settings.
|
||||
- `--headless` and `--hidden-window` runs are never affected.
|
||||
|
||||
The runtime logs the decision, for example
|
||||
`psxrecomp: game mode (gamescope session): fullscreen, no launcher`.
|
||||
@@ -1479,6 +1479,10 @@ if(BUILD_TESTING)
|
||||
target_link_libraries(dynamic_resolution_test PRIVATE m)
|
||||
endif()
|
||||
add_test(NAME dynamic_resolution_test COMMAND dynamic_resolution_test)
|
||||
# Game Mode (Steam Deck / gamescope) detection and precedence.
|
||||
add_executable(game_mode_test tests/test_game_mode.c src/game_mode.c)
|
||||
target_include_directories(game_mode_test PRIVATE include)
|
||||
add_test(NAME game_mode_test COMMAND game_mode_test)
|
||||
# The render-thread controller (dynrt_*) against a synthetic pipeline.
|
||||
add_executable(dynamic_resolution_rt_test
|
||||
tests/test_dynamic_resolution_rt.c
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
/* game_mode.h -- console "Game Mode" (Steam Deck Game Mode / gamescope).
|
||||
*
|
||||
* Under gamescope there is no desktop: the launcher window is an extra screen
|
||||
* with mouse-style controls, and a windowed game sits in a fullscreen
|
||||
* compositor anyway. Game Mode boots straight into the game, fullscreen, once
|
||||
* the player's disc is set up (the first run still shows the launcher so the
|
||||
* disc can be picked). Pure policy; the probes stay in main.cpp. */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct PsxGameModeEnv {
|
||||
const char *psx_game_mode; /* PSX_GAME_MODE: "1" on, "0" off, NULL auto */
|
||||
const char *xdg_current_desktop;/* "gamescope" in a gamescope session */
|
||||
const char *gamescope_display; /* GAMESCOPE_WAYLAND_DISPLAY */
|
||||
const char *steam_gamepad_ui; /* SteamGamepadUI=1: launched from Big Picture / Game Mode */
|
||||
int cli_game_mode; /* --game-mode: 1, --no-game-mode: 0, else -1 */
|
||||
} PsxGameModeEnv;
|
||||
|
||||
/* 1 when Game Mode applies. Precedence: the command line, then
|
||||
* PSX_GAME_MODE, then detection (gamescope session or Steam's gamepad UI). */
|
||||
int psx_game_mode_detect(const PsxGameModeEnv *env, const char **why);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -408,6 +408,7 @@ set(PSXRECOMP_RUNTIME_SOURCES
|
||||
${PSXRECOMP_ROOT}/runtime/src/render_pass_frame.c
|
||||
${PSXRECOMP_ROOT}/runtime/src/dynamic_resolution.c
|
||||
${PSXRECOMP_ROOT}/runtime/src/host_time.c
|
||||
${PSXRECOMP_ROOT}/runtime/src/game_mode.c
|
||||
${PSXRECOMP_ROOT}/runtime/src/psx_fiber.c
|
||||
${PSXRECOMP_ROOT}/runtime/src/sio.c
|
||||
${PSXRECOMP_ROOT}/runtime/src/memcard.c
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/* game_mode.c -- see game_mode.h. */
|
||||
#include "game_mode.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static int on(const char *s) { return s && s[0] && strcmp(s, "0") != 0; }
|
||||
|
||||
int psx_game_mode_detect(const PsxGameModeEnv *e, const char **why) {
|
||||
const char *dummy;
|
||||
if (!why) why = &dummy;
|
||||
if (!e) { *why = "no environment"; return 0; }
|
||||
if (e->cli_game_mode >= 0) {
|
||||
*why = e->cli_game_mode ? "--game-mode" : "--no-game-mode";
|
||||
return e->cli_game_mode;
|
||||
}
|
||||
if (e->psx_game_mode && e->psx_game_mode[0]) {
|
||||
*why = "PSX_GAME_MODE";
|
||||
return on(e->psx_game_mode);
|
||||
}
|
||||
if (e->xdg_current_desktop && strstr(e->xdg_current_desktop, "gamescope")) {
|
||||
*why = "gamescope session";
|
||||
return 1;
|
||||
}
|
||||
if (e->gamescope_display && e->gamescope_display[0]) {
|
||||
*why = "gamescope session";
|
||||
return 1;
|
||||
}
|
||||
if (on(e->steam_gamepad_ui)) {
|
||||
*why = "Steam gamepad UI";
|
||||
return 1;
|
||||
}
|
||||
*why = "desktop";
|
||||
return 0;
|
||||
}
|
||||
@@ -107,6 +107,7 @@ extern "C" void psx_event_step_conservative_env_init(void);
|
||||
#include "crash_trace.h"
|
||||
#include "freeze_heartbeat.h"
|
||||
#include "config_loader.h"
|
||||
#include "game_mode.h"
|
||||
#include "bios_rom_alias.h"
|
||||
#include "host_path.h"
|
||||
#include "launcher_device.h"
|
||||
@@ -15938,6 +15939,8 @@ int main(int argc, char** argv) {
|
||||
* PSX_NO_LAUNCHER env) forces it off. --launcher wins if both are given. */
|
||||
bool force_launcher = false;
|
||||
bool force_no_launcher = false;
|
||||
/* --game-mode / --no-game-mode (game_mode.h): -1 = detect. */
|
||||
int cli_game_mode = -1;
|
||||
/* CLI overrides for running several instances side by side (soak fleet).
|
||||
* These win over any game-config value and, crucially, work for the BIOS
|
||||
* (which has no [game]-block config schema, so debug_port/renderer can't be
|
||||
@@ -16031,6 +16034,10 @@ int main(int argc, char** argv) {
|
||||
force_launcher = true;
|
||||
} else if (std::strcmp(argv[i], "--no-launcher") == 0) {
|
||||
force_no_launcher = true;
|
||||
} else if (std::strcmp(argv[i], "--game-mode") == 0) {
|
||||
cli_game_mode = 1;
|
||||
} else if (std::strcmp(argv[i], "--no-game-mode") == 0) {
|
||||
cli_game_mode = 0;
|
||||
} else if (std::strcmp(argv[i], "--headless-opengl") == 0) {
|
||||
g_headless = 1;
|
||||
g_headless_opengl = 1;
|
||||
@@ -17366,6 +17373,31 @@ int main(int argc, char** argv) {
|
||||
* --no-launcher, or the persisted [launcher] skip_launcher setting — unless
|
||||
* --launcher forces it back on (mirrors snesrecomp's SkipLauncher / --launcher).
|
||||
* This removes the dismiss-the-launcher round-trip for scripted/debug runs. */
|
||||
/* Game Mode (Steam Deck / gamescope, game_mode.h): straight into the
|
||||
* game, fullscreen, once a disc is set up; the first run keeps the
|
||||
* launcher so the player can pick their disc. --launcher still wins. */
|
||||
{
|
||||
PsxGameModeEnv gm_env{};
|
||||
gm_env.psx_game_mode = std::getenv("PSX_GAME_MODE");
|
||||
gm_env.xdg_current_desktop = std::getenv("XDG_CURRENT_DESKTOP");
|
||||
gm_env.gamescope_display = std::getenv("GAMESCOPE_WAYLAND_DISPLAY");
|
||||
gm_env.steam_gamepad_ui = std::getenv("SteamGamepadUI");
|
||||
gm_env.cli_game_mode = cli_game_mode;
|
||||
const char *gm_why = "";
|
||||
if (psx_game_mode_detect(&gm_env, &gm_why) && !g_headless && !g_hidden_window) {
|
||||
std::error_code gm_ec;
|
||||
const bool disc_ready = disc_override_path ||
|
||||
(!resolved_disc.empty() && std::filesystem::exists(resolved_disc, gm_ec));
|
||||
if (disc_ready && !force_launcher) force_no_launcher = true;
|
||||
/* Borderless (gamescope owns the display mode), this run only:
|
||||
* set after the launcher would have seeded it, so a desktop
|
||||
* session's saved Fullscreen choice is never rewritten. */
|
||||
if (force_no_launcher) g_fullscreen = 1;
|
||||
std::fprintf(stdout, "psxrecomp: game mode (%s): fullscreen, %s\n", gm_why,
|
||||
force_no_launcher ? "no launcher"
|
||||
: "launcher first (no disc set up yet)");
|
||||
}
|
||||
}
|
||||
const bool want_launcher =
|
||||
force_launcher ||
|
||||
(!std::getenv("PSX_NO_LAUNCHER") && !force_no_launcher && !skip_launcher_setting);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/* game_mode: Steam Deck / gamescope detection and its precedence. */
|
||||
#include "game_mode.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static int fails;
|
||||
static void ok(int c, const char *w) { printf(" %s %s\n", c ? "ok " : "FAIL", w); if (!c) fails++; }
|
||||
|
||||
int main(void) {
|
||||
PsxGameModeEnv e;
|
||||
const char *why;
|
||||
memset(&e, 0, sizeof e); e.cli_game_mode = -1;
|
||||
ok(!psx_game_mode_detect(&e, &why) && !strcmp(why, "desktop"), "desktop: off");
|
||||
e.xdg_current_desktop = "gamescope";
|
||||
ok(psx_game_mode_detect(&e, &why), "XDG_CURRENT_DESKTOP=gamescope: on");
|
||||
e.xdg_current_desktop = "KDE"; e.gamescope_display = "gamescope-0";
|
||||
ok(psx_game_mode_detect(&e, &why), "GAMESCOPE_WAYLAND_DISPLAY: on");
|
||||
e.gamescope_display = NULL; e.steam_gamepad_ui = "1";
|
||||
ok(psx_game_mode_detect(&e, &why), "SteamGamepadUI=1: on");
|
||||
e.steam_gamepad_ui = "0";
|
||||
ok(!psx_game_mode_detect(&e, &why), "SteamGamepadUI=0: off");
|
||||
e.steam_gamepad_ui = "1"; e.psx_game_mode = "0";
|
||||
ok(!psx_game_mode_detect(&e, &why), "PSX_GAME_MODE=0 beats detection");
|
||||
e.psx_game_mode = "1"; e.steam_gamepad_ui = NULL;
|
||||
ok(psx_game_mode_detect(&e, &why), "PSX_GAME_MODE=1 on a desktop");
|
||||
e.cli_game_mode = 0;
|
||||
ok(!psx_game_mode_detect(&e, &why), "--no-game-mode beats PSX_GAME_MODE");
|
||||
e.cli_game_mode = 1; e.psx_game_mode = "0";
|
||||
ok(psx_game_mode_detect(&e, &why) && !strcmp(why, "--game-mode"), "--game-mode wins");
|
||||
ok(!psx_game_mode_detect(NULL, &why), "NULL env is safe");
|
||||
printf("%s\n", fails ? "FAILED" : "passed");
|
||||
return fails ? 1 : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user