The tie control region is not a VIF or GIF tag stream; and vert_ofs is mis-named
Went after the GS's GIF packets in the tie AD-GIF region. Got a negative result,
a new universal invariant, and a retraction of my own first probe, which reached
the right answer for the wrong reason twice.
THE NEGATIVE RESULT
Tried the leading `5 * shader_count` quadwords of each packet (the
`bfc_distance` field's stated meaning) as VIF tags -- command in bits 0-6, size
in 7-14, mark in 15 -- and as GIF tags -- type in the top byte of word 1, length
in bits 0-2 of word 0. Both uniform. Over 13,042 records: 10,443 distinct values
of word 0, no GIF tag type above a count of 2. That is the control result rule 4
asks for, and it says stop.
THE RETRACTION
The first probe scanned `bfc_distance` quadwords, which for most records
overruns `vert_ofs` and runs into the vertex data. Pooling a control region with
vertex positions -- two populations with different structure -- gives a uniform
answer, so "not a tag stream" came out right from a measurement that was
measuring the wrong bytes. That is exactly the rule 3a failure, and I only caught
it because the hex dump I took next looked structured while the histogram said
random.
Re-measuring quadword 0 alone, on its own population, gives the same uniformity.
The conclusion survives; the reasoning did not, and both are recorded.
THE PARTITION, AND A NEW INVARIANT
The hex dump showed the packet layout directly:
q[0 .. vert_ofs) control 3..8 quadwords, peak at 5
q[vert_ofs .. +vert_size) vertices
q[vert_ofs+vert_size ..] scissor
and `scissor_ofs == vert_ofs + vert_size` holds on **15,219 of 15,219** records
across all 27 levels, including every one whose strip_count is non-zero. That is a
derived quantity stored explicitly, and it holds everywhere -- which is the check
that confirms the three regions really are laid out the way the existing packet
length formula assumed. It is now a hard check in invariants_hold(), which is
something the previous four could not be.
The fixture in tie.rs failed the moment I added it: it had vert_ofs 4 and
vert_size 0x20 with scissor_ofs 0x30, which is 4 + 0x24. The synthetic data was
never constrained by a relation that did not exist yet. Fixed to 0x24.
vert_ofs IS MIS-NAMED
It is not a vertex offset. It is the *length* of the leading control region, and
the vertex data begins at that many quadwords into the packet. The field name
stays because the on-disc order is fixed and everything already written about this
record says vert_ofs, but the doc now states what the value is and gives the
distribution.
STILL UNKNOWN
What the control region contains. Not standard DMA tags; possibly pre-merged GS
register writes in another framing, or per-class state rather than per-primitive
draw data. Recorded as an open question rather than guessed at.
23 + 19 + 58 + 156 + 22 = 278 passing with the disc present (disc binary 35.67s),
clippy clean.
This commit is contained in:
@@ -1766,3 +1766,47 @@ than two independent tables that happen to agree.
|
||||
named. The Moby class-ID enrichment from earlier stands separately: 9,493 hits
|
||||
against 246.1 expected is real, and the class arrays are contiguous per type, but
|
||||
that identifies *where classes are referenced*, not which chunk is `moby_anim`.
|
||||
|
||||
|
||||
## The tie control region is not a tag stream (negative result)
|
||||
|
||||
Went looking for the GS's GIF packets, which the tie packet header calls AD-GIF
|
||||
(`shader_count` at `+0x04`, and `bfc_distance == 5 * shader_count` at `+0x05`).
|
||||
Tried the first `5 * shader_count` quadwords of each packet as VIF tags (command
|
||||
in bits 0-6, size in 7-14, mark in 15) and as GIF tags (type in the top byte of
|
||||
word 1, length in bits 0-2 of word 0).
|
||||
|
||||
**Both came out uniform.** Over 13,042 records, 10,443 distinct values of word 0
|
||||
and no GIF tag type above a count of 2. By rule 4 that is the control result:
|
||||
the region is not a tag stream, and no further effort should go into decoding it
|
||||
as one.
|
||||
|
||||
The first version of that probe was wrong and worth recording, because it reached
|
||||
the *opposite* conclusion twice. It scanned `bfc_distance` quadwords, which for
|
||||
most records overruns `vert_ofs` and runs into the vertex data. Pooling a
|
||||
control region with vertex positions -- two populations with different
|
||||
structure -- produced the uniform answer, and "not a tag stream" was the right
|
||||
conclusion for the wrong reason. Re-measuring quadword 0 alone on its own gives
|
||||
the same uniformity, so the conclusion survives; the reasoning did not.
|
||||
|
||||
What the probe did establish is the **packet partition**:
|
||||
|
||||
q[0 .. vert_ofs) control 3..8 quadwords (peak 5)
|
||||
q[vert_ofs .. +vert_size) vertices
|
||||
q[vert_ofs+vert_size ..] scissor
|
||||
|
||||
and a new **universal invariant**: `scissor_ofs == vert_ofs + vert_size` on
|
||||
**15,219 of 15,219** records across all 27 levels, including every record whose
|
||||
`strip_count` is non-zero. That is a derived quantity stored explicitly, and it
|
||||
holds everywhere -- which is the check that confirms the three regions really are
|
||||
laid out as the packet-length formula assumed.
|
||||
|
||||
It also found `vert_ofs` mis-named. It is not a vertex offset; it is the *length*
|
||||
of the leading control region. The vertex data begins at that many quadwords into
|
||||
the packet. The field name is left alone because the on-disc order is fixed and
|
||||
everything already written about this record says `vert_ofs`, but the doc now
|
||||
says what the value is.
|
||||
|
||||
**Still not known:** what the control region actually contains. It is not
|
||||
standard VIF or GIF DMA tags. It may be pre-merged GS register writes in a
|
||||
different framing, or per-class state rather than per-primitive draw data.
|
||||
|
||||
Reference in New Issue
Block a user