The morph was recorded as unverifiable because "reading a weight back out of
RAM does not work -- the positions live inside regenerated VU packets". That
is right about the correspondence and wrong about the cause. The cause is
measurable, and it comes back clean:
patches 833
positions 40,600 disc == ram
positions identical 40,600
block bytes differing 166,465
inside a position unpack 0
inside another unpack 49,484
in a VIF command word 116,981
Range: level 0, all 833 tfrag patches, live PINE RAM against the disc. Two
independent measurements agree. Walking the VIF lists on both copies and
comparing parsed positions gives 40,600 identical and zero changed; a raw
per-byte diff of each patch's own extent classifies every differing byte, and
none of them is in a position unpack. The position ranges total 490,224 bytes.
So the blend is not precomputed into the geometry. The rewrites are packet
framing -- 70% command words -- plus other unpack payloads, which is the loader
rebuilding the VIF packet for the tier it selected while leaving the vertices
alone. The morph happens at draw time in the VU stream.
The standing note becomes a sharper one: there was never a correspondence
problem. The values were identical, so there was nothing to read.
gc-trace gains verify-morph, which does both measurements. TfragGeometry
gains position_ranges and other_ranges so the walk needed to classify a diff
is already paid for, and the ranges come from the same walk the rest of the
parse uses rather than a second one that could drift.
Per-patch extents are the gap to the next patch's data pointer. That is exact
and needs no guess about which header field marks a patch's end; the first
attempt at this compared each patch against the whole rest of the region and
reported 65 million differing bytes, which is what an unbounded comparison
looks like.
tfrag_positions_are_verbatim_and_the_rewrites_are_elsewhere is gated on
GC_SSTATE and asserts the four bounds, plus two guards: the rewrites must be
non-trivial (over 100,000 bytes) and mostly command words, so a RAM image that
was a verbatim copy of the disc -- which would make the zero look good for the
wrong reason -- fails instead.
Suite with the disc and GC_SSTATE: 68 disc tests, 156 gc-formats, 22
gc-trace, 23 gc-engine, 19 gc-game. Clippy clean.
39 lines
1.5 KiB
Rust
39 lines
1.5 KiB
Rust
//! `gc-trace` — the PCSX2 ground-truth harness.
|
|
//!
|
|
//! This crate is a **dev tool**. It never ships and no shipped crate depends
|
|
//! on it; the dependency direction is the other way round (`tools/` may read
|
|
//! what the engine computes). Its job is the one the rest of the suite cannot
|
|
//! do: compare what the real game does against what we compute, from the same
|
|
//! disc data.
|
|
//!
|
|
//! Inputs, in order of convenience:
|
|
//!
|
|
//! * **PINE** — the live emulator, over its unix socket. Needs PCSX2 running
|
|
//! with PINE enabled. No savestate, no files.
|
|
//! * **a PCSX2 savestate** (`.p2s`) — a zip with zstd/deflate entries holding
|
|
//! `eeMemory.bin` and friends. Repeatable input: the file can be kept,
|
|
//! but it is personal data and is never committed.
|
|
//! * **a raw EE RAM dump** — 32 MiB, whatever produced it.
|
|
//!
|
|
//! The one comparison that exists so far is
|
|
//! [`compare-tfrag-light`](tfrag_cmp::compare): the game's lit per-vertex
|
|
//! tfrag colours in EE RAM against [`gc_engine::tfrag_light::light_tfrag`] over
|
|
//! the same disc data. See `docs/plan/pcsx2-verification.md`.
|
|
//!
|
|
//! **Findings reach tests only as numbers.** A test never reads a savestate, a
|
|
//! dump or a live emulator; when a comparison becomes a regression, distil the
|
|
//! facts it needs into a small fixture and test against that.
|
|
|
|
pub mod ee;
|
|
pub mod morph;
|
|
pub mod overlay_base;
|
|
pub mod p2s;
|
|
pub mod pine;
|
|
pub mod tfrag_cmp;
|
|
pub mod tie_verify;
|
|
pub mod zip;
|
|
|
|
pub use ee::EeRam;
|
|
pub use p2s::Savestate;
|
|
pub use tfrag_cmp::{compare, print_report, LevelInputs, Report};
|