Preserve PGXP mod selection through renderer initialization

This commit is contained in:
Matthew Stanley
2026-10-02 18:05:59 -07:00
parent a408bd8368
commit 9c1e716a61
7 changed files with 104 additions and 17 deletions
+7
View File
@@ -733,6 +733,13 @@ some selections of one feature is a `[[requirement]]`, not a dependency.
## Implicit requirements across packages
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
settings. Session start clears the selection before activating the new plan;
the player's persistent settings remain unchanged. Explicit validation
environment overrides still take precedence at renderer initialization.
Package format 7 lets a feature, while a condition on its own options holds,
need a feature of **another** package:
+3
View File
@@ -46,6 +46,9 @@ if(BUILD_TESTING)
add_executable(mod_session_baseline_test tests/test_mod_session_baseline.c)
target_include_directories(mod_session_baseline_test PRIVATE include)
add_test(NAME mod_session_baseline_test COMMAND mod_session_baseline_test)
add_executable(mod_pgxp_policy_test tests/test_mod_pgxp_policy.c)
target_include_directories(mod_pgxp_policy_test PRIVATE include)
add_test(NAME mod_pgxp_policy_test COMMAND mod_pgxp_policy_test)
# Netplay: libjuice resolves from third_party/ with the network sealed,
# and a recomp-net pinning another libjuice stops the configure.
foreach(_psx_juice_case same other)
+28
View File
@@ -0,0 +1,28 @@
#ifndef PSX_MOD_PGXP_POLICY_H
#define PSX_MOD_PGXP_POLICY_H
/* Session overrides are independent of the player's persistent video config.
* Renderer initialization resolves them again after activation, because GTE
* and GPU initialization may reset the live correction flags. */
typedef struct PSXModPgxpConfig {
int geometry, textures, cpu;
} PSXModPgxpConfig;
typedef struct PSXModPgxpPolicy {
int enabled, cpu; /* -1: no mod selection */
} PSXModPgxpPolicy;
static inline void psx_mod_pgxp_reset(PSXModPgxpPolicy* policy) {
policy->enabled = policy->cpu = -1;
}
static inline void psx_mod_pgxp_select(PSXModPgxpPolicy* policy, int enabled, int cpu) {
policy->enabled = enabled != 0;
policy->cpu = cpu != 0;
}
static inline PSXModPgxpConfig psx_mod_pgxp_resolve(
const PSXModPgxpPolicy* policy, PSXModPgxpConfig base) {
if (policy->enabled >= 0) {
base.geometry = base.textures = policy->enabled;
base.cpu = policy->cpu;
}
return base;
}
#endif
+6
View File
@@ -138,6 +138,12 @@ uint32_t psx_mod_alloc_gpu_dma_memory(uint32_t size, uint32_t alignment);
*/
int psx_mod_set_main_ram_8mb(int enabled);
/* Session-owned precision selection, applied immediately and retained across
* renderer initialization. Disabling a mod restores the player's base config
* at the next session; explicit debug environment overrides still take priority.
* Does not modify persistent settings or architectural GTE state. */
void psx_mod_set_pgxp_precision(int enabled, int cpu_mode);
/* Current per-side widescreen reveal in native game pixels (zero at 4:3). */
int32_t psx_mod_widescreen_x_margin(void);
+25 -10
View File
@@ -94,6 +94,7 @@ extern "C" void psx_event_step_conservative_env_init(void);
#include "game_options.h"
#include "mod_plugins.h"
#include "mod_session_baseline.h"
#include "mod_pgxp_policy.h"
#include "mod_runtime.h"
#include "mod_packages.h"
#include "present_image_ring.h"
@@ -1245,6 +1246,14 @@ static int g_video_geometry_correction = 0;
static int g_video_perspective_texturing = 0;
static int g_video_pgxp_cpu_mode = 0;
static float g_video_pgxp_tolerance = 0.5f;
static PSXModPgxpPolicy g_mod_pgxp_policy = {-1, -1};
extern "C" void psx_mod_set_pgxp_precision(int enabled, int cpu_mode) {
psx_mod_pgxp_select(&g_mod_pgxp_policy, enabled, cpu_mode);
gte_geometry_correction_set(enabled != 0);
gpu_texture_correction_set(enabled != 0);
pgxp_set_cpu_mode(cpu_mode != 0);
}
static int g_video_renderer = PSXRecompV4::DEFAULT_VIDEO_RENDERER;
/* Settings -> Display -> Internal resolution (internal_resolution.h). The
@@ -1533,6 +1542,10 @@ extern "C" int psx_mod_set_adaptive_display_aspect(
static PSXModSessionBaseline g_mod_owned_baseline;
static void reset_mod_owned_presentation(void) {
psx_mod_pgxp_reset(&g_mod_pgxp_policy);
gte_geometry_correction_set(g_video_geometry_correction);
gpu_texture_correction_set(g_video_perspective_texturing);
pgxp_set_cpu_mode(g_video_pgxp_cpu_mode);
PSXModSessionScalars live;
live.video_vsync = g_video_vsync;
live.frame_interpolation = g_frame_interpolation;
@@ -15933,15 +15946,17 @@ session_reboot:
* corrections from process start so free-running (headless) boots can be
* measured from the first projected vertex — a TCP toggle always arrives
* after the interesting window. '0' = off, anything else = on. */
PSXModPgxpConfig precision = psx_mod_pgxp_resolve(&g_mod_pgxp_policy,
{g_video_geometry_correction, g_video_perspective_texturing, g_video_pgxp_cpu_mode});
if (const char* e = std::getenv("PSX_GEOMETRY_CORRECTION"))
g_video_geometry_correction = (*e && *e != '0') ? 1 : 0;
precision.geometry = (*e && *e != '0') ? 1 : 0;
if (const char* e = std::getenv("PSX_PERSPECTIVE_TEXTURING"))
g_video_perspective_texturing = (*e && *e != '0') ? 1 : 0;
precision.textures = (*e && *e != '0') ? 1 : 0;
if (const char* e = std::getenv("PSX_PGXP_CPU_MODE"))
g_video_pgxp_cpu_mode = (*e && *e != '0') ? 1 : 0;
gte_geometry_correction_set(g_video_geometry_correction);
gpu_texture_correction_set(g_video_perspective_texturing);
pgxp_set_cpu_mode(g_video_pgxp_cpu_mode);
precision.cpu = (*e && *e != '0') ? 1 : 0;
gte_geometry_correction_set(precision.geometry);
gpu_texture_correction_set(precision.textures);
pgxp_set_cpu_mode(precision.cpu);
pgxp_set_tolerance(g_video_pgxp_tolerance);
/* Scanlines: env override wins over config, same as the corrections above,
* so a headless/free-run boot can be captured with the effect armed from the
@@ -15955,12 +15970,12 @@ session_reboot:
}
gl_renderer_set_scanlines(g_video_scanlines ? 1 : 0,
g_video_scanline_strength);
if (g_video_geometry_correction || g_video_perspective_texturing) {
if (precision.geometry || precision.textures) {
std::fprintf(stdout,
"psxrecomp: geometry correction %s, perspective texturing %s%s\n",
g_video_geometry_correction ? "on" : "off",
g_video_perspective_texturing ? "on" : "off",
(g_video_geometry_correction && requested_scale < 2)
precision.geometry ? "on" : "off",
precision.textures ? "on" : "off",
(precision.geometry && requested_scale < 2)
? " (needs [video] supersampling >= 2 to be visible)" : "");
}
/* Display aspect. Identity at the default 4:3. The present letterbox uses
+1 -7
View File
@@ -21,10 +21,6 @@
#define PKG_PGXP "psx.enhancement.pgxp"
/* gte.cpp / gpu.c — the two correction toggles this mod arms. */
extern void gte_geometry_correction_set(int enabled);
extern void gpu_texture_correction_set(int enabled);
static int pgxp_option_flag(const char* feature, const char* id) {
char text[16] = "";
return psx_mod_option_value(PKG_PGXP, feature, id, text, sizeof text) &&
@@ -32,9 +28,7 @@ static int pgxp_option_flag(const char* feature, const char* id) {
}
static void builtin_pgxp_activate(void) {
gte_geometry_correction_set(1);
gpu_texture_correction_set(1); /* also arms the shadow engine */
pgxp_set_cpu_mode(pgxp_option_flag("pgxp", "cpu_mode"));
psx_mod_set_pgxp_precision(1, pgxp_option_flag("pgxp", "cpu_mode"));
}
PSX_MOD_CONSTRUCTOR(psx_register_builtin_pgxp_plugin) {
+34
View File
@@ -0,0 +1,34 @@
#include "mod_pgxp_policy.h"
#include <assert.h>
#include <stdio.h>
int main(void) {
PSXModPgxpPolicy policy;
PSXModPgxpConfig configured = {0, 0, 1};
psx_mod_pgxp_reset(&policy);
PSXModPgxpConfig live = psx_mod_pgxp_resolve(&policy, configured);
assert(!live.geometry && !live.textures && live.cpu);
/* Activation before renderer initialization must survive re-resolution. */
psx_mod_pgxp_select(&policy, 1, 0);
live = psx_mod_pgxp_resolve(&policy, configured);
assert(live.geometry && live.textures && !live.cpu);
assert(!configured.geometry && !configured.textures && configured.cpu);
/* A later vanilla/netplay session inherits the player's config only. */
psx_mod_pgxp_reset(&policy);
live = psx_mod_pgxp_resolve(&policy, configured);
assert(!live.geometry && !live.textures && live.cpu);
configured.geometry = 1;
live = psx_mod_pgxp_resolve(&policy, configured);
assert(live.geometry && !live.textures && live.cpu);
psx_mod_pgxp_select(&policy, 0, 1);
live = psx_mod_pgxp_resolve(&policy, configured);
assert(!live.geometry && !live.textures && live.cpu);
psx_mod_pgxp_select(&policy, 1, 1);
live = psx_mod_pgxp_resolve(&policy, configured);
assert(live.geometry && live.textures && live.cpu);
puts("PGXP session policy passed");
return 0;
}