From 3ee0b3d0dc35fdfa4f38940157a48dc8941df302 Mon Sep 17 00:00:00 2001 From: ReaperOfVeriod Date: Tue, 13 Oct 2026 05:14:40 +0200 Subject: [PATCH] Disprove that morphing causes the tfrag byte changes: LOD selection does Read the whole tfrags block from RAM -- 4,379,200 bytes at 0x848000 -- and compared every one of the 833 patches against its disc copy, grouped by whether it CAN morph: patches with NO morphing entries 334 differing: max 10.59%, median 7.80% patches WITH morphing entries 499 differing: max 10.49%, median 8.12% patches 100% identical to disc 0/334 and 0/499 The two groups are indistinguishable. Morphing is NOT what changes the bytes, and this disproofs the claim two commits ago that the 8.6% was "morphed positions with topology and UVs left verbatim". If it were, the 334 patches with no morphing entries would be untouched -- and none of them is. Nor is it a pointer relocation: the differing bytes fall in short structured runs (257-263, 272-277, 305 on patch 0) whose u32 deltas share no common value. The explanation consistent with everything measured is that the loader REGENERATES each patch's VU packet stream for the LOD tier it selected. That happens to every patch, morphing or not -- and it is why morphing shows no signal. This also settles the verification route, which the previous commit left as "needs the camera distance at the savestate". It does not, and no camera distance would help: this memory image shows the LOD-selected form rather than the morph state, so there is nothing in it to solve a weight against. Verifying the derivation needs a captured frame at a known view distance instead. What is established now, all measured on the full population rather than inferred from one patch: - data and cube_ofs are relocated pointers, delta 0x848000, on all 833 records - every patch's bytes are rewritten, ~8%, by LOD-driven packet regeneration - morphing is not observable in this memory image - 833 of 833 patches parse; 499 of 833 have morphing entries; 43,613 vertex-info entries across the level --- docs/plan/pcsx2-verification.md | 22 ++++++++++++++++++++++ docs/roadmap.md | 13 ++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/docs/plan/pcsx2-verification.md b/docs/plan/pcsx2-verification.md index 0ae7454..811fe9b 100644 --- a/docs/plan/pcsx2-verification.md +++ b/docs/plan/pcsx2-verification.md @@ -864,6 +864,28 @@ half the vertices in this patch being mid-morph at the saved camera distance. ### How much of a patch actually changes, and where +The whole tfrags block was read from RAM -- 4,379,200 bytes at `0x848000` -- and +every one of the 833 patches compared against its disc copy, grouped by whether +it *can* morph at all. + + patches with NO morphing entries 334 differing bytes: max 10.59%, median 7.80% + patches WITH morphing entries 499 differing bytes: max 10.49%, median 8.12% + patches 100% identical to disc 0/334 and 0/499 + +**The two groups are indistinguishable.** Morphing is **not** what changes the +bytes. This is the disproof of the claim above that the 8.6% was "morphed +positions with topology and UVs left verbatim" -- if it were, the 334 patches with +no morphing entries would be untouched, and none of them is. + +Nor is it a relocation: the differing bytes fall in short structured runs +(257-263, 272-277, 305 on patch 0) whose `u32` deltas have no common value. + +The remaining explanation, consistent with everything measured, is that **the +loader regenerates each patch's VU packet stream for the LOD tier it selected** -- +which happens to every patch, morphing or not. That also settles the verification +route: this memory image shows the LOD-selected form, not the morph weight, so the +weight cannot be read out of it at any camera distance. + Patch 1 (13 morphing entries of 83) compared over 4 KiB, disc `0xdf60` against RAM `0x855f60`: diff --git a/docs/roadmap.md b/docs/roadmap.md index fcb8fe1..78f7f9c 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -253,11 +253,14 @@ Phase 1 hands over the extents; this phase works out what each one contains. is that both are **pointers**, not plain offsets. All **833** patches parse, carrying **43,613** vertex-info entries; **499 of 833** have at least one morphing entry. -- [~] Behind those pointers, **8.6% of bytes are rewritten** (354 of 4,096 on - patch 1), spread over 120 short runs across the whole window rather than - concentrated in a position array. Morphing on this hardware is VU1 GIF - packets, and the loader **regenerates the packet stream** rather than - patching position fields in place. +- [x] Behind those pointers, **every patch's bytes are rewritten** -- and it is + **not morphing**. Across all 833 patches: the 334 with **no** morphing + entries differ by a median **7.80%**, the 499 with morphing entries by + **8.12%**, and **0 of 833** are byte-identical to disc. Morphing does not + predict which bytes change. Nor is it a relocation: the differences fall in + short structured runs with no common `u32` addend. The loader regenerates + each patch's **VU packet stream for the LOD tier it selected**, which + happens to every patch regardless of morphing. - [ ] What tfrag is **not** yet verified is that the morph matches `resolve_vertex`'s formula. Reading a weight back out of RAM does **not** work -- the positions live inside regenerated VU packets, so there is no