Framework fixes surfaced while bringing up a title that stresses overlays, HD
texture replacement and PGXP at a doubled CRTC rate. All are general; the
title's own configuration stays in its game repository.
CORRECTNESS
* Overlay DLL shim was deleted by the preprocessor. compile_overlays.py injected
overlay_dispatch_preamble.c.inc after the syntactically LAST #include. A
conditional i-cache include moved that anchor inside an #else, and DLL builds
define PSX_OVERLAY_DLL_BUILD, so the callback definitions preprocessed away and
every overlay DLL failed to link. Any title using overlays would silently fall
back to per-instruction interpretation. The shim is now anchored to the
unconditional #include "psx_runtime.h" and raises if that anchor is absent.
* Overlay capture kept stale PC bitmaps when executed code later became data, so
one variant's PC set could be compiled against another variant's bytes.
overlay_watch_note_write now retires the whole page's execution/dispatch epoch
when any executed word is overwritten; static demand is keyed by
(load_addr, size, bytes) and resolved only against matching range identities.
* VRAM-to-VRAM copies only invalidated the destination and never registered it as
a replacement candidate, so textures arriving by copy could not be dumped or
replaced at all. gr_copy_rect now calls tex_pack_on_copy with the same
(texture,palette) key semantics as CPU uploads.
* PGXP shared-edge seams: a per-primitive all-or-nothing gate cannot stop two
adjacent primitives disagreeing about a shared endpoint, so the edge is
submitted at two sub-pixel positions. Adds a frame-stamped canonical endpoint
cache keyed by final integer screen position: the first use fixes the
coordinates and every later occurrence reuses them.
* PGXP provenance: PGXPValue carries per-component X/Y/Z projection ids, so a
value assembled from different projections can no longer arm correction.
Destructive AND/XOR/NOR/SLT, link and COP0 writes now invalidate shadows, and
the SXYP shadow FIFO shifts with guest SXY.
* Precise NCLIP no longer replaces guest MAC0. It is telemetry only, so face
visibility stays bit-exact with the integer GTE.
* Removed two counters that were reported as correctness evidence but were never
incremented anywhere.
PERFORMANCE
* PSX_ENABLE_LTO plus a noinline guard on the shared cycle wrappers. Unguarded
ThinLTO clones hot interlock bodies and REGRESSES the hot path; guarded, it
becomes a win. Adds runtime/tests/bench_psx_runtime_hotpath.c, which verifies
variant equivalence by digest so codegen changes are measurable.
* Cycle accounting: emitters select specialized arity-0/1/2/3 helpers at
generation time instead of a generic dependency-mask loop; main-RAM loads
combine base/wait/completion into one exact charge. Exactness is covered by
pipeline-state, load-state, deadline-crossing and cross-device causality tests.
* HD texture invalidation replaced a linear scan of up to 8192 upload records per
VRAM write with a tile-refcount index; out-of-domain writes early-out.
* Translation/text-substitution dispatch is gated behind a monotonic mutation
epoch instead of running a callback on every dispatch.
* card_data_writes_check no longer runs on every RAM write.
CAPABILITY
* fixed_outer_aspect: the outer presentation aspect becomes a function of user
configuration only. Scene classification selects content transforms, never the
outer viewport, so menus/FMV stay centred undistorted inside a wide canvas.
VERIFICATION AND LIMITS
docs/UPSTREAM_2026-08-20.md audits each change against the diff, marks
unsupported claims UNKNOWN, and lists a suggested PR split and review focus.
Unit and structural tests accompany each item, but this body of work has NOT
been validated end-to-end against a fixed reproducible workload -- reviewers
should treat the timing-exactness and PGXP changes as the highest-risk areas.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>