feat(video): perspective_texturing defaults ON

The two PGXP-family knobs now default differently, on purpose.

geometry_correction stays OFF and stays out of the UI: it moves vertices, and at
the ~5% coverage a position-keyed lookup can reach (93% of lookups ambiguous), a
corrected triangle meets an uncorrected neighbour and their shared edge splits.
Partial coverage is a visible defect there, not a partial feature.

perspective_texturing has no such failure mode, which is why it can ship on. It
never moves a vertex — it only changes how UVs are interpolated inside a polygon
whose SWC2 projection provenance is already fully proven. A polygon that does not
qualify simply keeps the PS1's affine interpolation, so neighbours can never
disagree about a shared edge and coverage below 100% degrades to "some polygons
look better" rather than "meshes crack".

Layering is unchanged and the faithful path is still one key away:
[video] perspective_texturing = false in game.toml or settings.toml opts out, and
settings.toml still wins over game.toml. The launcher row seeds from this default,
so the checkbox now presents as ticked.

Test updated rather than deleted: it pins the DIFFERENCE between the two defaults,
and gains a converse case proving that naming geometry_correction alone does not
disturb perspective_texturing's new default. 38/41 recompiler tests pass; the 3
failures (mod_load_acceleration, release_zip, sdl3_main_single_include) were
already failing before this change.

Not visually validated at the new default: perspective textures were confirmed
clean on Ape Escape / OpenGL / supersampling 2 only. Vulkan and the other titles
inherit the default without an isolation run of their own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matthew Stanley
2026-08-05 17:30:02 -07:00
parent 26f4a4aef5
commit a423bb9c2d
2 changed files with 37 additions and 10 deletions
+10 -2
View File
@@ -349,8 +349,16 @@ struct RuntimeConfig {
// on large floor/wall polygons as the camera moves). Uses the exact SWC2
// projection provenance — a polygon only qualifies when every one of its
// position words was written to that DMA packet address by a projection
// store — so CPU-built UI and 2D sprites are never touched. Default off.
bool video_perspective_texturing = false;
// store — so CPU-built UI and 2D sprites are never touched.
//
// Default ON (enhancement-phase default, 2026-08-05). Unlike
// geometry_correction above, this never moves a vertex: it only changes how
// UVs are interpolated inside a polygon whose provenance is already proven,
// so adjacent polygons cannot disagree about a shared edge and partial
// coverage cannot crack a mesh. A polygon that does not qualify simply keeps
// the PS1's affine interpolation. Opt out per-game with
// [video] perspective_texturing = false.
bool video_perspective_texturing = true;
// offer_vulkan: expose the experimental Vulkan renderer in the launcher.
// Defaults false even for Vulkan-enabled builds; developers must opt in per
@@ -58,13 +58,17 @@ static fs::path write_game_toml(const std::string& name,
+ video_block);
}
static void test_defaults_off() {
/* The two defaults deliberately DIFFER. geometry_correction moves vertices and
* cracks meshes at the coverage the runtime can reach, so it stays off and has no
* launcher control. perspective_texturing never moves a vertex, so partial
* coverage is harmless and it ships on. See ENHANCEMENTS.md G1.8/G1.9. */
static void test_defaults() {
fs::path p = write_game_toml("psxrecomp_pgxp_default.toml", "");
auto gc = PSXRecompV4::load_game_config(p);
check(!gc.runtime.video_geometry_correction,
"geometry_correction defaults off (faithful floor)");
check(!gc.runtime.video_perspective_texturing,
"perspective_texturing defaults off (faithful floor)");
"geometry_correction defaults OFF (known to crack meshes)");
check(gc.runtime.video_perspective_texturing,
"perspective_texturing defaults ON (cannot crack; enhancement default)");
fs::remove(p);
}
@@ -84,15 +88,30 @@ static void test_game_toml_opt_in() {
/* 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() {
/* Each knob must be settable against the other's default: geometry ON while
* perspective is explicitly opted OUT proves neither key implies the other. */
fs::path p = write_game_toml("psxrecomp_pgxp_geom_only.toml",
"[video]\n"
"geometry_correction = true\n");
"geometry_correction = true\n"
"perspective_texturing = false\n");
auto gc = PSXRecompV4::load_game_config(p);
check(gc.runtime.video_geometry_correction,
"geometry_correction alone turns on");
"geometry_correction turns on independently");
check(!gc.runtime.video_perspective_texturing,
"geometry_correction alone leaves perspective_texturing off");
"perspective_texturing can be opted OUT while geometry is on");
fs::remove(p);
/* And the converse: naming only geometry_correction must not disturb
* perspective_texturing's on-by-default state. */
fs::path q = write_game_toml("psxrecomp_pgxp_geom_named.toml",
"[video]\n"
"geometry_correction = true\n");
auto gq = PSXRecompV4::load_game_config(q);
check(gq.runtime.video_geometry_correction,
"geometry_correction alone turns on");
check(gq.runtime.video_perspective_texturing,
"naming geometry_correction leaves perspective_texturing at its default");
fs::remove(q);
}
static void test_user_settings_read() {
@@ -141,7 +160,7 @@ static void test_user_settings_round_trip() {
}
int main() {
test_defaults_off();
test_defaults();
test_game_toml_opt_in();
test_knobs_independent();
test_user_settings_read();