diff --git a/docs/MOD_PACKAGES.md b/docs/MOD_PACKAGES.md index 9fad8eca..2c2ea70a 100644 --- a/docs/MOD_PACKAGES.md +++ b/docs/MOD_PACKAGES.md @@ -757,6 +757,13 @@ some selections of one feature is a `[[requirement]]`, not a dependency. ## Implicit requirements across packages +Trusted graphics plugins can call `psx_mod_set_internal_resolution(lines)` to +request a rendering height for their session. Values from 120 through 8192 use +the existing integer-scale resolver and backend allocation limits; zero clears +the request. `PSX_INTERNAL_RESOLUTION` takes precedence. The player's saved +resolution stays unchanged, and every new session clears the request before +its mod plan activates, including rematches and sessions without that mod. + The shared PGXP plugin uses `psx_mod_set_pgxp_precision(enabled, cpu_mode)`. This stores a session selection as well as setting live correction flags, so later renderer initialization cannot erase mod activation with the base video diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index e324baef..a8c1d80a 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -1248,6 +1248,12 @@ if(BUILD_TESTING) endif() add_test(NAME render_pass_plan_test COMMAND render_pass_plan_test) + add_executable(mod_internal_resolution_test + tests/test_mod_internal_resolution.c + src/mod_internal_resolution.c) + target_include_directories(mod_internal_resolution_test PRIVATE include) + add_test(NAME mod_internal_resolution_test COMMAND mod_internal_resolution_test) + # Motion kit and per-frame driver for render-pass plugins: blending, # identity matching, limits and the crossfade fallback, on mock RAM. add_executable(render_pass_motion_test diff --git a/runtime/include/mod_internal_resolution.h b/runtime/include/mod_internal_resolution.h new file mode 100644 index 00000000..e81c6a4a --- /dev/null +++ b/runtime/include/mod_internal_resolution.h @@ -0,0 +1,17 @@ +#ifndef PSX_MOD_INTERNAL_RESOLUTION_H +#define PSX_MOD_INTERNAL_RESOLUTION_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Runtime session plumbing; plugins use mod_plugins.h. Zero means no request. */ +uint32_t psx_mod_internal_resolution_request(void); +void psx_mod_internal_resolution_reset(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/runtime/include/mod_plugins.h b/runtime/include/mod_plugins.h index 353d298b..61fbbf4c 100644 --- a/runtime/include/mod_plugins.h +++ b/runtime/include/mod_plugins.h @@ -431,6 +431,13 @@ int psx_mod_set_adaptive_display_aspect(uint32_t max_numerator, * title's setting before activation. */ int psx_mod_set_widescreen_hud_size(int proportional); +/* Request an internal rendering height for this mod session (120..8192). + * The existing resolution resolver selects an integer raster scale and the + * backend applies its normal allocation limits. Zero clears the request. + * Player settings are preserved, explicit PSX_INTERNAL_RESOLUTION overrides + * win, and each session clears this request before activating its committed + * mod plan. */ +int psx_mod_set_internal_resolution(uint32_t target_lines); /* * Set the wall-clock cadence of simulated guest VBlanks. A value of zero * removes frontend pacing; 60 and higher request that many native guest diff --git a/runtime/runtime.cmake b/runtime/runtime.cmake index 06ed5efd..57ceae34 100644 --- a/runtime/runtime.cmake +++ b/runtime/runtime.cmake @@ -472,6 +472,7 @@ set(PSXRECOMP_RUNTIME_SOURCES ${PSXRECOMP_ROOT}/runtime/src/game_options.c ${PSXRECOMP_ROOT}/runtime/src/mod_builtin_speed.c ${PSXRECOMP_ROOT}/runtime/src/mod_builtin_pgxp.c + ${PSXRECOMP_ROOT}/runtime/src/mod_internal_resolution.c ${PSXRECOMP_ROOT}/runtime/src/mod_builtin_bezel.c ${PSXRECOMP_ROOT}/runtime/src/mod_builtin_ram.c ${PSXRECOMP_ROOT}/runtime/src/mod_builtin_hd_textures.c diff --git a/runtime/src/main.cpp b/runtime/src/main.cpp index c94e99de..d6dfb162 100644 --- a/runtime/src/main.cpp +++ b/runtime/src/main.cpp @@ -11,6 +11,7 @@ #include "mod_controller_source.h" #include "window_size.h" /* default game-window size */ #include "internal_resolution.h" /* Settings -> Display -> Internal resolution */ +#include "mod_internal_resolution.h" #include "dynamic_resolution.h" /* [video] dynamic_resolution: the step controller */ #include "render_thread.h" /* rt_get_stats: queue backpressure (dynres) */ #include "psx_scheduler.h" /* psx_scheduler_run — deterministic TCB scheduler */ @@ -1362,11 +1363,11 @@ static int video_scale_ceiling(void) { return g_video_renderer == 1 ? GL_MAX_INTERNAL_SCALE : SW_MAX_INTERNAL_SCALE; } -/* The preset in effect this run: the environment override, else the - * configured one. */ +/* Session priority: environment override, active mod request, player setting. */ static int effective_internal_resolution(void) { + const uint32_t mod_lines = psx_mod_internal_resolution_request(); return g_video_internal_res_env != PSX_IR_UNSET ? g_video_internal_res_env - : g_video_internal_res; + : mod_lines ? (int)mod_lines : g_video_internal_res; } /* Resolve the Internal resolution preset into g_video_scale. display_px_h is @@ -1703,6 +1704,7 @@ extern "C" int psx_mod_set_adaptive_display_aspect( static PSXModSessionBaseline g_mod_owned_baseline; static void reset_mod_owned_presentation(void) { + psx_mod_internal_resolution_reset(); psx_local_mouse_clear(); PSXModSessionScalars live; live.video_vsync = g_video_vsync; diff --git a/runtime/src/mod_internal_resolution.c b/runtime/src/mod_internal_resolution.c new file mode 100644 index 00000000..b272c902 --- /dev/null +++ b/runtime/src/mod_internal_resolution.c @@ -0,0 +1,19 @@ +#include "mod_plugins.h" +#include "mod_internal_resolution.h" + +static uint32_t requested_lines; + +int psx_mod_set_internal_resolution(uint32_t target_lines) { + if (target_lines && (target_lines < 120u || target_lines > 8192u)) + return 0; + requested_lines = target_lines; + return 1; +} + +uint32_t psx_mod_internal_resolution_request(void) { + return requested_lines; +} + +void psx_mod_internal_resolution_reset(void) { + requested_lines = 0; +} diff --git a/runtime/tests/test_mod_internal_resolution.c b/runtime/tests/test_mod_internal_resolution.c new file mode 100644 index 00000000..f33ce426 --- /dev/null +++ b/runtime/tests/test_mod_internal_resolution.c @@ -0,0 +1,25 @@ +#include "mod_plugins.h" +#include "mod_internal_resolution.h" +#include + +#define CHECK(x) do { if (!(x)) { fprintf(stderr, "Failed: %s\n", #x); return 1; } } while (0) + +int main(void) { + /* Disabled sessions retain the configured baseline; a later launch must + * not inherit an earlier active graphics mod's requested height. */ + CHECK(psx_mod_internal_resolution_request() == 0u); + CHECK(psx_mod_set_internal_resolution(1080u)); + CHECK(psx_mod_internal_resolution_request() == 1080u); + CHECK(!psx_mod_set_internal_resolution(119u)); + CHECK(!psx_mod_set_internal_resolution(8193u)); + CHECK(!psx_mod_set_internal_resolution(UINT32_MAX)); + CHECK(psx_mod_internal_resolution_request() == 1080u); + psx_mod_internal_resolution_reset(); + CHECK(psx_mod_internal_resolution_request() == 0u); + CHECK(psx_mod_set_internal_resolution(120u)); + CHECK(psx_mod_set_internal_resolution(8192u)); + CHECK(psx_mod_set_internal_resolution(0u)); + CHECK(psx_mod_internal_resolution_request() == 0u); + puts("session-scoped mod resolution validation passed"); + return 0; +}