Commit Graph

5 Commits

Author SHA1 Message Date
Alex Vanderveen 0d57ee5e79 gpu_parity: align the images by VRAM origin, and stop faking frame alignment
The fade question is settled: psx-runtime steps $s6 by 2 on CONSECUTIVE frames,
crossing its whole range in about 64 frames. A smooth sweep. Lockstep is clean
again over 2,755,940 blocks. So the guest side is exhausted and the image is
what is left — but the image comparison was measuring nothing.

91.9% of pixels differ, and that is what two CORRECT images produce when they
are offset. psx-runtime puts its visible framebuffer at VRAM (0, 0); the oracle
puts its at (1, 8) — consistently, in both halves of the double buffer (0/240
against 8/248). Each screenshot is that side's own display area, so pixel (0,0)
of one is not pixel (0,0) of the other. A 1-pixel horizontal and 8-pixel
vertical shift makes almost every pixel differ, and it was being read as a
rendering fault.

The images are now cropped to a common frame using each side's reported origin,
with the 240-line buffer-half jump taken modulo the frame height: that is
double buffering, not displacement, and treating it as displacement would crop
the entire frame away.

Frame alignment was also failing silently for two reasons. run_to_frame ARMS a
target and does not block, so the frame was read back straight afterwards and
of course had not moved. And more fundamentally, the two were 1818 frames apart
— those numbers count from each emulator's own boot, so closing that gap would
not put them at the same guest moment, only run one of them past the effect.
A gap beyond 120 frames is now reported as unbridgeable rather than attempted.

The remaining state differences are real and worth noting: width 320 against
319, height 240 against 224, and gpustat differing only in bit 31, the
interlace field.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 12:55:58 -04:00
Alex Vanderveen b609424177 gpu_parity: wait for the effect, because the image is the untested half
Pooling every scale observation taken so far:

  psx-runtime  28 36 42 48 60 64 66 68 72 94 128   (28..128)
  oracle       52 64 68 72 76 96 112 116 ... 128   (52..128)

The ranges overlap almost completely, and every sample is aliased. The scale
data cannot diagnose anything, and saying otherwise would be reading a pattern
into noise for the third time.

What the accumulated evidence does say is narrower. Both display lists carry
the SAME subtractive primitives — PolyF4+semi|B-F x184 and PolyG3+semi|B-F x176
on each side — and the flat ones were byte-identical at (64,64,64). Subtractive
blending is how the outer darkening is drawn, and "the vignette is missing" is
half the reported symptom. So the guest is submitting the darkening on both
sides.

Geometry identical, GTE unused, translation clean over 5.7M blocks, base colour
table identical at rest, subtractive primitives present and matching. Every
guest-side explanation has been measured and ruled out, and the one thing never
tested at this effect is the IMAGE — because the oracle could not reach the
scene until the memory card was shared.

So gpu_parity gains the same wait every other tool has, on both sides. An image
diff of a scene without the effect answers a question nobody asked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 12:55:58 -04:00
Alex Vanderveen 88fedc3694 parity: align BOTH emulators, and stop inventing display-state differences
Two bugs, both visible in every parity run so far.

Alignment only ever steered DuckStation. It read psx-runtime's frame, drove the
oracle at it, then took screenshots -- while the native run kept going. So the
two images were of different frames essentially always, and the tool printed
that as a warning to read past rather than as the reason the comparison was
void. It also failed outright whenever the oracle had already passed the target,
because run_to_frame cannot go backwards ("target frame already passed").

Neither side can rewind, but both can move FORWARD: psx-runtime by stepping
(pause/step are real again -- the "native run cannot be paused" in that warning
had been stale since they were restored), DuckStation by run_to_frame. The
target is therefore whichever emulator is further ahead, and the one behind
catches up. Both are parked for the screenshots, and the game is handed back
afterwards rather than left relying on the park's silence timeout.

The display-state block was pure noise. The two servers name the same facts
differently -- display_x/width/height against display_area_x/disp_w/disp_h --
so comparing raw keys reported native=None for every field. That reads as the
runtime failing to report its display state and is really a vocabulary
mismatch: a difference invented by the tool, printed under a heading saying the
emulators diverged. Names are now normalised, display_disable is inverted
rather than merely renamed onto display_enable (or every frame would differ),
and a field only one side reports is marked one_sided instead of counted as
disagreement.

Studio leads with the alignment verdict, because every other number in the
report is conditional on it.

Also: the resume-on-error patch first landed in align_frames() instead of
main(), referencing an `args` that does not exist there -- caught by extending
the undefined-global bytecode guard to gpu_parity, packet_writers and gte_check.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 12:55:57 -04:00
Alex Vanderveen 0e5d463356 duckstation linux build + frame capture diagnostics 2026-08-20 11:26:37 -04:00
Alex Vanderveen 1f65200e6f bump 2026-08-19 23:35:17 -04:00