D203 - The typed-buffer format table is measured from the assembler, both directions
Status: decided (2026-08-21)
A typed buffer access carries a seven-bit format in bits 25:19 saying how many components it moves, how wide each is, and how the bits become a number. Getting it wrong produces a shader that runs and draws the wrong thing.
orbistoun-gen buffer-formats derives the whole table: it
assembles format:N for every code, reads the field back to
confirm the code it asked for is the code it got, and records the name
the reference prints. The structure is in the name -
BUF_FMT_32_32_FLOAT is two thirty-two-bit components read
as floating point - so parsing the name yields the meaning.
Same footing as the encoding and operand tables, and for the same reason: a transcribed table cannot be checked without the document that produced it.
The sweep has a blind spot, and it needs the opposite question
Codes that print no name are two different facts.
Code 1 is the default, which the disassembler omits exactly as
it omits any modifier sitting at its default. Codes 78 to 127 are
reserved and print back as bare numbers. Code 0 is explicitly
BUF_FMT_INVALID.
Only the numeric sweep cannot separate the first from the second, and the default is a real format a real shader uses. So there is a second pass asking the question the other way round: build candidate names from the component layouts and types the first pass already observed, assemble each by name, and see which code comes back. Nothing is invented - every candidate is a recombination of parts already measured - and a name that assembles into a given code is a measurement.
That recovered code 1 as BUF_FMT_8_UNORM. Reading it off
the sequence would have got the same answer and would have been a
guess.
It also needed a fix to be trustworthy. The recovery
takes the name from what was asked for, which means pairing
each output with its input line. Refused lines produce no output, so
pairing positionally without accounting for them shifts every later
result by one - silently, into answers that still look plausible.
assemble now reads the diagnostics for refused line numbers
and carries the surviving index with each encoding.
What the table refuses to say
Whether a format can be translated. A normalised eight-bit component
is a real format whether or not there is code to convert one, and
omitting it would record the limits of the table's first consumer as
facts about the hardware. is_plain_words() is where a
consumer draws that line: all-32-bit components move words unchanged,
anything narrower needs unpacking and conversion, and that is the
consumer's problem.
A code with no meaning returns None rather than the
nearest real format. Picking a neighbour would turn a broken shader into
one that draws.