From f64ca0ce3c5d596832d975c48cf8a9f8a6333911 Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 25 Aug 2026 01:45:55 -0700 Subject: [PATCH] config: honor title window width --- recompiler/src/config_loader.cpp | 8 ++++++++ recompiler/src/config_loader.h | 4 ++++ .../tests/video_enhancement_settings_test.cpp | 18 ++++++++++++++++++ runtime/src/main.cpp | 4 ++++ 4 files changed, 34 insertions(+) diff --git a/recompiler/src/config_loader.cpp b/recompiler/src/config_loader.cpp index 2718a242..3eb28f7e 100644 --- a/recompiler/src/config_loader.cpp +++ b/recompiler/src/config_loader.cpp @@ -545,6 +545,14 @@ static RuntimeConfig parse_runtime_block(const toml::value& cfg, const fs::path& } rt.video_supersampling = static_cast(n); } + if (video.contains("window_width")) { + const auto n = toml::find(video, "window_width"); + if (n < 640 || n > 7680) { + throw std::runtime_error(fmt::format( + "[video] window_width out of range (640..7680): {}", n)); + } + rt.video_window_width = static_cast(n); + } if (video.contains("antialiasing")) { rt.video_antialiasing = toml::find(video, "antialiasing"); } diff --git a/recompiler/src/config_loader.h b/recompiler/src/config_loader.h index c6fb9f68..5bfd566d 100644 --- a/recompiler/src/config_loader.h +++ b/recompiler/src/config_loader.h @@ -376,6 +376,10 @@ struct RuntimeConfig { // supersampling + edge anti-aliasing. Cost scales ~N^2 in fill rate. int video_supersampling = 1; + // Optional initial window width declared by the title profile. Zero keeps + // the historical fit-to-display behavior; player settings may override it. + int video_window_width = 0; + // antialiasing: when true the present path uses linear filtering when // scaling the framebuffer to the window (smooths the supersample // downscale and any window resize). false = nearest (sharp pixels). diff --git a/recompiler/tests/video_enhancement_settings_test.cpp b/recompiler/tests/video_enhancement_settings_test.cpp index d099a203..2be94aff 100644 --- a/recompiler/tests/video_enhancement_settings_test.cpp +++ b/recompiler/tests/video_enhancement_settings_test.cpp @@ -78,9 +78,12 @@ static void test_defaults_off() { static void test_game_toml_opt_in() { fs::path p = write_game_toml("psxrecomp_pgxp_on.toml", "[video]\n" + "window_width = 1920\n" "geometry_correction = true\n" "perspective_texturing = true\n"); auto gc = PSXRecompV4::load_game_config(p); + check(gc.runtime.video_window_width == 1920, + "[video] window_width is honoured"); check(gc.runtime.video_geometry_correction, "[video] geometry_correction = true is honoured"); check(gc.runtime.video_perspective_texturing, @@ -88,6 +91,20 @@ static void test_game_toml_opt_in() { fs::remove(p); } +static void test_game_window_width_validation() { + fs::path p = write_game_toml("psxrecomp_window_too_small.toml", + "[video]\n" + "window_width = 639\n"); + bool rejected = false; + try { + (void)PSXRecompV4::load_game_config(p); + } catch (const std::exception&) { + rejected = true; + } + check(rejected, "[video] window_width rejects values below 640"); + fs::remove(p); +} + /* The two knobs are independent: a title may want stable geometry without * changing texture mapping (or the reverse) — so a single flag would be wrong. */ static void test_knobs_independent() { @@ -173,6 +190,7 @@ static void test_user_settings_round_trip() { int main() { test_defaults_off(); test_game_toml_opt_in(); + test_game_window_width_validation(); test_knobs_independent(); test_user_settings_read(); test_user_settings_absent_key(); diff --git a/runtime/src/main.cpp b/runtime/src/main.cpp index 872d201e..f93fa29b 100644 --- a/runtime/src/main.cpp +++ b/runtime/src/main.cpp @@ -10693,6 +10693,10 @@ int main(int argc, char** argv) { for (uint32_t site : gc.vsync_event_horizon_extra_sites) psx_vsync_query_hle_add_extra_event_horizon_site(site); g_video_scale = gc.runtime.video_supersampling; + if (gc.runtime.video_window_width > 0) { + g_video_win_w = gc.runtime.video_window_width; + g_video_win_w_explicit = true; + } g_video_aa = gc.runtime.video_antialiasing; g_video_texfilter = gc.runtime.video_texture_filter; g_video_fmv_filter = gc.runtime.video_fmv_filter;