Skip to main content

d3d9_reader/
program.rs

1//! The token stream: records and the decoder.
2//!
3//! A program is a version token, then instruction tokens each followed by its operand tokens, then `END`
4//! (`0x0000ffff`). An instruction token holds the opcode in bits 0 to 15, opcode-specific controls in bits 16 to 23,
5//! from Shader Model 2 on the count of operand tokens that follow in bits 24 to 27, the predicate flag in bit 28 and
6//! the pixel 1.x co-issue flag in bit 30. A comment token (`0xfffe`) holds its length in words in bits 16 to 30.
7//!
8//! An operand token has bit 31 set, the register number in bits 0 to 10 and the register type split over bits 28 to 30
9//! (its low three bits) and 11 to 12 (its high two). A destination has its write mask in bits 16 to 19, its result
10//! modifiers in 20 to 23 and the pixel 1.x result shift in 24 to 27; a source its swizzle in bits 16 to 23 and its
11//! modifier in 24 to 27. Bit 13 marks a relatively addressed operand: from Shader Model 2 on a relative-address token
12//! (the address register `a0` or the loop counter `aL`, with a swizzle) follows it; in a vertex 1.x program the index
13//! is always `a0.x` and no token follows.
14
15use crate::opcodes::Shape;
16use crate::{ConstantTable, DebugInfo, Opcode, Result, Stage, Version, error};
17
18/// The most words a program may have, END included.
19const MAX_WORDS: usize = 1_048_576;
20
21/// A register type (`D3DSHADER_PARAM_REGISTER_TYPE`, `D3DSPR_*`). Type 3 is the address register in a vertex program
22/// and a texture register in a pixel program; type 6 is a vertex program's texture-coordinate output (`oTN`) before
23/// 3.0 and its output `oN` in 3.0.
24#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
25pub enum RegisterType {
26    /// `rN` (`D3DSPR_TEMP`, 0).
27    Temp,
28    /// `vN` (`D3DSPR_INPUT`, 1).
29    Input,
30    /// `cN` (`D3DSPR_CONST`, 2).
31    Const,
32    /// `a0` of a vertex program (`D3DSPR_ADDR`, 3).
33    Address,
34    /// `tN` of a pixel program (`D3DSPR_TEXTURE`, 3).
35    Texture,
36    /// `oPos` (0), `oFog` (1) or `oPts` (2) of a vertex program before 3.0 (`D3DSPR_RASTOUT`, 4).
37    RasterizerOut,
38    /// `oDN`, a vertex program's colour output before 3.0 (`D3DSPR_ATTROUT`, 5).
39    AttributeOut,
40    /// `oTN` before vertex 3.0, `oN` in 3.0 (`D3DSPR_TEXCRDOUT` and `D3DSPR_OUTPUT`, 6).
41    Output,
42    /// `iN`, an integer constant (`D3DSPR_CONSTINT`, 7).
43    ConstInt,
44    /// `oCN`, a pixel program's colour output (`D3DSPR_COLOROUT`, 8).
45    ColorOut,
46    /// `oDepth` (`D3DSPR_DEPTHOUT`, 9).
47    DepthOut,
48    /// `sN` (`D3DSPR_SAMPLER`, 10).
49    Sampler,
50    /// `cN` from 2048 on, the number being `N - 2048` (`D3DSPR_CONST2`, 11).
51    Const2,
52    /// `cN` from 4096 on (`D3DSPR_CONST3`, 12).
53    Const3,
54    /// `cN` from 6144 on (`D3DSPR_CONST4`, 13).
55    Const4,
56    /// `bN`, a boolean constant (`D3DSPR_CONSTBOOL`, 14).
57    ConstBool,
58    /// `aL`, the loop counter (`D3DSPR_LOOP`, 15).
59    Loop,
60    /// `vPos` (0) or `vFace` (1) of a pixel 3.0 program (`D3DSPR_MISCTYPE`, 17).
61    Misc,
62    /// `lN`, a label (`D3DSPR_LABEL`, 18).
63    Label,
64    /// `p0`, the predicate (`D3DSPR_PREDICATE`, 19).
65    Predicate,
66}
67
68impl RegisterType {
69    /// The type's value in the token (`D3DSPR_*`).
70    pub fn code(self) -> u8 {
71        use RegisterType::*;
72        match self {
73            Temp => 0,
74            Input => 1,
75            Const => 2,
76            Address | Texture => 3,
77            RasterizerOut => 4,
78            AttributeOut => 5,
79            Output => 6,
80            ConstInt => 7,
81            ColorOut => 8,
82            DepthOut => 9,
83            Sampler => 10,
84            Const2 => 11,
85            Const3 => 12,
86            Const4 => 13,
87            ConstBool => 14,
88            Loop => 15,
89            Misc => 17,
90            Label => 18,
91            Predicate => 19,
92        }
93    }
94
95    /// The register type of a token value in `version` (whose stage tells `a0` from `tN`), and the largest register
96    /// number it has (`None` for a bank whose size is the device's), or why the value names no register. A type is
97    /// read in any version, as Microsoft's disassembler lists it.
98    fn of(code: u32, version: Version) -> std::result::Result<(Self, Option<u32>), String> {
99        use RegisterType::*;
100        Ok(match code {
101            0 => (Temp, None),
102            1 => (Input, None),
103            2 => (Const, None),
104            3 if version.stage == Stage::Vertex => (Address, Some(0)),
105            3 => (Texture, None),
106            4 => (RasterizerOut, Some(2)),
107            5 => (AttributeOut, None),
108            6 => (Output, None),
109            7 => (ConstInt, None),
110            8 => (ColorOut, None),
111            9 => (DepthOut, Some(0)),
112            10 => (Sampler, None),
113            11 => (Const2, None),
114            12 => (Const3, None),
115            13 => (Const4, None),
116            14 => (ConstBool, None),
117            15 => (Loop, Some(0)),
118            17 => (Misc, Some(1)),
119            18 => (Label, None),
120            19 => (Predicate, Some(0)),
121            _ => return Err("is not a Direct3D 9 register type".into()),
122        })
123    }
124}
125
126/// A register: its type and number.
127#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
128pub struct Register {
129    /// The register type.
130    pub kind: RegisterType,
131    /// The register number, bits 0 to 10 of the operand token.
132    pub number: u32,
133}
134
135/// A source modifier (`D3DSHADER_PARAM_SRCMOD_TYPE`, `D3DSPSM_*`), bits 24 to 27 of a source token.
136#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
137pub enum Modifier {
138    /// No modifier (0).
139    None,
140    /// `-r` (1).
141    Negate,
142    /// `r_bias`, `r - 0.5` (2).
143    Bias,
144    /// `-r_bias` (3).
145    BiasNegate,
146    /// `r_bx2`, `2 * (r - 0.5)` (4).
147    Sign,
148    /// `-r_bx2` (5).
149    SignNegate,
150    /// `1 - r` (6).
151    Complement,
152    /// `r_x2` (7).
153    X2,
154    /// `-r_x2` (8).
155    X2Negate,
156    /// `r_dz`, divided by its z lane (9).
157    DivideZ,
158    /// `r_dw`, divided by its w lane (10).
159    DivideW,
160    /// `r_abs` (11).
161    Abs,
162    /// `-r_abs` (12).
163    AbsNegate,
164    /// `!r`, of a boolean or predicate (13).
165    Not,
166}
167
168impl Modifier {
169    /// The modifier's value in the token.
170    pub fn code(self) -> u8 {
171        use Modifier::*;
172        match self {
173            None => 0,
174            Negate => 1,
175            Bias => 2,
176            BiasNegate => 3,
177            Sign => 4,
178            SignNegate => 5,
179            Complement => 6,
180            X2 => 7,
181            X2Negate => 8,
182            DivideZ => 9,
183            DivideW => 10,
184            Abs => 11,
185            AbsNegate => 12,
186            Not => 13,
187        }
188    }
189
190    fn of(code: u32) -> Option<Self> {
191        use Modifier::*;
192        Some(match code {
193            0 => None,
194            1 => Negate,
195            2 => Bias,
196            3 => BiasNegate,
197            4 => Sign,
198            5 => SignNegate,
199            6 => Complement,
200            7 => X2,
201            8 => X2Negate,
202            9 => DivideZ,
203            10 => DivideW,
204            11 => Abs,
205            12 => AbsNegate,
206            13 => Not,
207            _ => return Option::None,
208        })
209    }
210}
211
212/// The index register of a relatively addressed operand (`c[a0.x + 4]`, `v[aL]`).
213#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
214pub struct Relative {
215    /// The word of the relative-address token; `None` in a vertex 1.x program, whose index is `a0.x` with no token of
216    /// its own.
217    pub word: Option<usize>,
218    /// The index register: the address register `a0` or the loop counter `aL`.
219    pub register: Register,
220    /// The relative-address token's swizzle, as stored (bits 16 to 23). Compilers write the lane they index with
221    /// replicated (`a0.x` as `.xxxx`); Microsoft's assembler writes `c0[a0]` and `[aL]` with `.xyzw`. `[0, 0, 0, 0]`
222    /// in a vertex 1.x program.
223    pub swizzle: [u8; 4],
224}
225
226/// A destination operand.
227#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
228pub struct Destination {
229    /// The word of the operand token.
230    pub word: usize,
231    /// The register written.
232    pub register: Register,
233    /// The lanes written, bit 0 x to bit 3 w (bits 16 to 19); a declaration's lanes declared.
234    pub mask: u8,
235    /// `_sat` (`D3DSPDM_SATURATE`, bit 20).
236    pub saturate: bool,
237    /// `_pp` (`D3DSPDM_PARTIALPRECISION`, bit 21).
238    pub partial_precision: bool,
239    /// `_centroid` (`D3DSPDM_MSAMPCENTROID`, bit 22).
240    pub centroid: bool,
241    /// The pixel 1.x result shift (bits 24 to 27 as a signed number): 1 `_x2`, 2 `_x4`, 3 `_x8`, -1 `_d2`, -2 `_d4`,
242    /// -3 `_d8`; 0 otherwise and in every other version.
243    pub shift: i8,
244    /// The index register, for a relatively addressed destination (`o[aL]` of a vertex 3.0 program).
245    pub relative: Option<Relative>,
246}
247
248/// A source operand.
249#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
250pub struct Source {
251    /// The word of the operand token.
252    pub word: usize,
253    /// The register read.
254    pub register: Register,
255    /// The lane of the register (0 x to 3 w) each of the operand's x, y, z and w reads: bits 16 to 23, two per lane.
256    pub swizzle: [u8; 4],
257    /// The source modifier.
258    pub modifier: Modifier,
259    /// The index register, for a relatively addressed source.
260    pub relative: Option<Relative>,
261}
262
263/// The comparison of `if_comp`, `break_comp` and `setp_comp` (`D3DSHADER_COMPARISON`), bits 16 to 18 of the instruction
264/// token.
265#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
266pub enum Comparison {
267    /// `_gt` (1).
268    Greater,
269    /// `_eq` (2).
270    Equal,
271    /// `_ge` (3).
272    GreaterEqual,
273    /// `_lt` (4).
274    Less,
275    /// `_ne` (5).
276    NotEqual,
277    /// `_le` (6).
278    LessEqual,
279}
280
281/// An instruction: everything but declarations, definitions, comments and `END`.
282#[derive(Clone, Debug, PartialEq, Eq)]
283pub struct Instruction {
284    /// The word of the instruction token, counted from the version token.
285    pub word: usize,
286    /// The opcode.
287    pub opcode: Opcode,
288    /// The opcode-specific controls, bits 16 to 23: for `tex` from pixel 1.4 on 0 `texld`, 1 `texldp` (projected) and 2
289    /// `texldb` (biased); for `if_comp`, `break_comp` and `setp_comp` the [`Comparison`]; 0 for every other opcode.
290    pub control: u8,
291    /// The co-issue flag of a pixel 1.x instruction (bit 30), written `+` before it.
292    pub coissue: bool,
293    /// The predicate an instruction is predicated on (bit 28 set): the predicate register `p0`, its swizzle and
294    /// [`Modifier::Not`] or none. Its token follows the destination's.
295    pub predicate: Option<Source>,
296    /// The destination; `None` for an opcode that has none. `texkill`'s is the register it tests.
297    pub destination: Option<Destination>,
298    /// The sources, in the order the stream writes them.
299    pub sources: Vec<Source>,
300}
301
302impl Instruction {
303    /// The comparison of `if_comp`, `break_comp` and `setp_comp`; `None` for other opcodes.
304    pub fn comparison(&self) -> Option<Comparison> {
305        if !matches!(self.opcode, Opcode::IfC | Opcode::BreakC | Opcode::SetP) {
306            return None;
307        }
308        Some(match self.control {
309            1 => Comparison::Greater,
310            2 => Comparison::Equal,
311            3 => Comparison::GreaterEqual,
312            4 => Comparison::Less,
313            5 => Comparison::NotEqual,
314            _ => Comparison::LessEqual,
315        })
316    }
317}
318
319/// A sampler's texture type (`D3DSAMPLER_TEXTURE_TYPE`), bits 27 to 30 of its declaration token.
320#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
321pub enum TextureType {
322    /// `dcl_2d` (2).
323    D2,
324    /// `dcl_cube` (3).
325    Cube,
326    /// `dcl_volume` (4).
327    Volume,
328}
329
330/// What a declaration token declares.
331#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
332pub enum Declared {
333    /// A sampler's texture type.
334    Sampler(TextureType),
335    /// Any other register's usage (`D3DDECLUSAGE`: 0 position, 1 blend weight, 2 blend indices, 3 normal, 4 point size,
336    /// 5 texture coordinate, 6 tangent, 7 binormal, 8 tessellation factor, 9 transformed position, 10 colour, 11 fog,
337    /// 12 depth, 13 sample; bits 0 to 3) and usage index (bits 16 to 19). A pixel 2.x program's `dcl t0` and `dcl v0`
338    /// store usage 0 and index 0, as does `dcl vPos`.
339    Semantic {
340        /// The usage.
341        usage: u8,
342        /// The usage index.
343        index: u8,
344    },
345}
346
347/// A `dcl`: the declaration token and the register declared.
348#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
349pub struct Declaration {
350    /// The word of the instruction token.
351    pub word: usize,
352    /// The declaration token, as stored.
353    pub token: u32,
354    /// What the declaration token says.
355    pub declared: Declared,
356    /// The register declared, its mask, and its modifiers (`_pp`, `_centroid`).
357    pub destination: Destination,
358}
359
360/// The literal of a definition.
361#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
362pub enum Literal {
363    /// `def`: four floats, as their bit patterns.
364    Float([u32; 4]),
365    /// `defi`: four integers.
366    Integer([i32; 4]),
367    /// `defb`: a boolean, as its word (`TRUE` is 1).
368    Bool(u32),
369}
370
371/// A `def`, `defi` or `defb`: a constant register and the literal it holds.
372#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
373pub struct Definition {
374    /// The word of the instruction token.
375    pub word: usize,
376    /// The register defined: a float, integer or boolean constant, as the opcode says.
377    pub destination: Destination,
378    /// The literal.
379    pub literal: Literal,
380}
381
382/// A comment: its words, without its token. The constant table is one, its first word the FourCC `CTAB`.
383#[derive(Clone, Debug, PartialEq, Eq)]
384pub struct Comment {
385    /// The word of the comment token.
386    pub word: usize,
387    /// The comment's words.
388    pub data: Vec<u32>,
389}
390
391/// One record of the stream.
392#[derive(Clone, Debug, PartialEq, Eq)]
393pub enum Item {
394    /// A comment.
395    Comment(Comment),
396    /// A `dcl`.
397    Declaration(Declaration),
398    /// A `def`, `defi` or `defb`.
399    Definition(Definition),
400    /// Any other instruction.
401    Instruction(Instruction),
402}
403
404impl Item {
405    /// The word of the record's token.
406    pub fn word(&self) -> usize {
407        match self {
408            Item::Comment(c) => c.word,
409            Item::Declaration(d) => d.word,
410            Item::Definition(d) => d.word,
411            Item::Instruction(i) => i.word,
412        }
413    }
414}
415
416/// A program read: its version, its records in stream order, its constant table and its debug information.
417#[derive(Clone, Debug, PartialEq, Eq)]
418pub struct Program {
419    /// The version token.
420    pub version: Version,
421    /// Every record between the version token and `END`, in stream order.
422    pub items: Vec<Item>,
423    /// The word of `END`.
424    pub end: usize,
425    /// The `CTAB` comment decoded; `None` when the program has none.
426    pub constants: Option<ConstantTable>,
427    /// The `DBUG` comment decoded (a `/Zi` build's); `None` when the program has none.
428    pub debug: Option<DebugInfo>,
429}
430
431impl Program {
432    /// The comments, in stream order.
433    pub fn comments(&self) -> impl Iterator<Item = &Comment> {
434        self.items.iter().filter_map(|i| match i {
435            Item::Comment(c) => Some(c),
436            _ => None,
437        })
438    }
439    /// The declarations, in stream order.
440    pub fn declarations(&self) -> impl Iterator<Item = &Declaration> {
441        self.items.iter().filter_map(|i| match i {
442            Item::Declaration(d) => Some(d),
443            _ => None,
444        })
445    }
446    /// The definitions, in stream order.
447    pub fn definitions(&self) -> impl Iterator<Item = &Definition> {
448        self.items.iter().filter_map(|i| match i {
449            Item::Definition(d) => Some(d),
450            _ => None,
451        })
452    }
453    /// The instructions, in stream order.
454    pub fn instructions(&self) -> impl Iterator<Item = &Instruction> {
455        self.items.iter().filter_map(|i| match i {
456            Item::Instruction(i) => Some(i),
457            _ => None,
458        })
459    }
460}
461
462/// Read a complete program: version token to `END`, with nothing after it. The bytes are little-endian words.
463pub fn read(bytes: &[u8]) -> Result<Program> {
464    collect(records(bytes)?)
465}
466
467/// Read the first program of `bytes`, which may hold more after it (a container's other records, say), and return it
468/// with its exact bytes, version token to `END`. `END` is found by reading every record, never by searching for it
469/// inside operands or comments.
470pub fn frame(bytes: &[u8]) -> Result<(Program, &[u8])> {
471    let program = collect(start(bytes, false)?)?;
472    let span = bytes
473        .get(..program.end.saturating_add(1).saturating_mul(4))
474        .ok_or_else(|| error(program.end, "END is past the buffer"))?;
475    Ok((program, span))
476}
477
478/// The records of a complete program, one at a time in stream order, for a caller that stops at the first record it
479/// cannot use, before the reader has read further (and refused, maybe, something later). The version is read first;
480/// a refusal ends the iteration, as does `END`, after which words left over are a refusal. [`read`] is these records
481/// collected.
482pub fn records(bytes: &[u8]) -> Result<Records<'_>> {
483    if !bytes.len().is_multiple_of(4) || bytes.len() > MAX_WORDS.saturating_mul(4) {
484        return Err(error(
485            0,
486            format!(
487                "token stream of {} bytes is not whole words or exceeds 1,048,576 words",
488                bytes.len()
489            ),
490        ));
491    }
492    start(bytes, true)
493}
494
495fn start(bytes: &[u8], whole: bool) -> Result<Records<'_>> {
496    let words = Words { bytes };
497    let token = words.get(0).ok_or_else(|| error(0, "no version token"))?;
498    let version = Version::from_token(token).ok_or_else(|| {
499        error(
500            0,
501            format!(
502                "version token {token:#010x} is not a Direct3D 9 vertex (0xfffe) or pixel (0xffff) program of \
503                 version 1.0 to 3.0"
504            ),
505        )
506    })?;
507    Ok(Records {
508        words,
509        version,
510        at: 1,
511        whole,
512        end: None,
513        done: false,
514        constants: None,
515        debug: None,
516    })
517}
518
519fn collect(mut records: Records<'_>) -> Result<Program> {
520    let mut items = Vec::new();
521    for item in records.by_ref() {
522        items.push(item?);
523    }
524    Ok(Program {
525        version: records.version,
526        items,
527        end: records.end.unwrap_or(0),
528        constants: records.constants,
529        debug: records.debug,
530    })
531}
532
533/// A program's records in stream order: see [`records`].
534#[derive(Debug)]
535pub struct Records<'a> {
536    words: Words<'a>,
537    version: Version,
538    /// The word of the next record's token.
539    at: usize,
540    /// True when the program is the whole buffer, so that words after `END` are a refusal.
541    whole: bool,
542    end: Option<usize>,
543    done: bool,
544    constants: Option<ConstantTable>,
545    debug: Option<DebugInfo>,
546}
547
548impl Records<'_> {
549    /// The program's version.
550    pub fn version(&self) -> Version {
551        self.version
552    }
553    /// The constant table, once the `CTAB` comment has been read.
554    pub fn constants(&self) -> Option<&ConstantTable> {
555        self.constants.as_ref()
556    }
557    /// The debug information, once the `DBUG` comment has been read.
558    pub fn debug(&self) -> Option<&DebugInfo> {
559        self.debug.as_ref()
560    }
561    /// The word of `END`, once it has been read.
562    pub fn end(&self) -> Option<usize> {
563        self.end
564    }
565}
566
567impl Iterator for Records<'_> {
568    type Item = Result<Item>;
569
570    fn next(&mut self) -> Option<Result<Item>> {
571        if self.done {
572            return None;
573        }
574        match self.record() {
575            Ok(Some(item)) => Some(Ok(item)),
576            Ok(None) => {
577                self.done = true;
578                let words = self.words.len();
579                (self.whole && self.at != words).then(|| {
580                    Err(error(
581                        self.at,
582                        format!("{} words after END", words.saturating_sub(self.at)),
583                    ))
584                })
585            }
586            Err(e) => {
587                self.done = true;
588                Some(Err(e))
589            }
590        }
591    }
592}
593
594/// The stream's words, read from the bytes as needed; a buffer's bytes after its last whole word are never read.
595#[derive(Debug)]
596struct Words<'a> {
597    bytes: &'a [u8],
598}
599
600impl Words<'_> {
601    fn len(&self) -> usize {
602        (self.bytes.len() / 4).min(MAX_WORDS)
603    }
604    fn get(&self, at: usize) -> Option<u32> {
605        if at >= MAX_WORDS {
606            return None;
607        }
608        let start = at.checked_mul(4)?;
609        let word: [u8; 4] = self.bytes.get(start..start.checked_add(4)?)?.try_into().ok()?;
610        Some(u32::from_le_bytes(word))
611    }
612}
613
614/// The bits of `word` from `shift` that `mask` keeps, which is at most 8 bits wide.
615fn bits(word: u32, shift: u32, mask: u32) -> u8 {
616    u8::try_from(word.checked_shr(shift).unwrap_or(0) & mask & 0xff).unwrap_or(u8::MAX)
617}
618
619/// The register an operand token names.
620fn register(token: u32, at: usize, version: Version) -> Result<Register> {
621    if token & 0x8000_0000 == 0 {
622        return Err(error(at, format!("operand token {token:#010x} lacks bit 31")));
623    }
624    if token & 0xc000 != 0 {
625        return Err(error(
626            at,
627            format!("operand token {token:#010x} sets reserved bits 14 to 15"),
628        ));
629    }
630    let code = ((token >> 28) & 7) | ((token >> 8) & 0x18);
631    let number = token & 0x7ff;
632    let (kind, last) =
633        RegisterType::of(code, version).map_err(|why| error(at, format!("register type {code} {why}")))?;
634    if last.is_some_and(|last| number > last) {
635        return Err(error(
636            at,
637            format!(
638                "register {kind:?} {number}, where the type has registers 0 to {}",
639                last.unwrap_or(0)
640            ),
641        ));
642    }
643    Ok(Register { kind, number })
644}
645
646/// Reads the operand tokens of one instruction, from the word after the instruction token up to `end` (the
647/// instruction's length from Shader Model 2 on; the stream's end in 1.x, whose instructions do not state theirs).
648struct Operands<'a> {
649    words: &'a Words<'a>,
650    at: usize,
651    end: usize,
652    /// The instruction token's word, which a truncation names.
653    instruction: usize,
654    version: Version,
655}
656
657impl Operands<'_> {
658    fn next(&mut self) -> Result<(usize, u32)> {
659        let at = self.at;
660        let token = (at < self.end)
661            .then(|| self.words.get(at))
662            .flatten()
663            .ok_or_else(|| {
664                error(
665                    self.instruction,
666                    format!(
667                        "instruction's operand span extends past {} (it ends at word {})",
668                        if self.end < self.words.len() {
669                            "its stated length"
670                        } else {
671                            "the stream"
672                        },
673                        self.end.min(self.words.len())
674                    ),
675                )
676            })?;
677        self.at = at.saturating_add(1);
678        Ok((at, token))
679    }
680
681    /// The relative-address token after an operand token with bit 13 set, or the implicit `a0.x` of vertex 1.x.
682    fn relative(&mut self, operand: usize, what: &str) -> Result<Relative> {
683        let version = self.version;
684        if version.major == 1 {
685            return Ok(Relative {
686                word: None,
687                register: Register {
688                    kind: RegisterType::Address,
689                    number: 0,
690                },
691                swizzle: [0; 4],
692            });
693        }
694        let (at, token) = self.next().map_err(|e| {
695            error(
696                operand,
697                format!(
698                    "relative addressing of {what} without its address token: {}",
699                    e.detail
700                ),
701            )
702        })?;
703        let register = register(token & !0x2000, at, version)?;
704        // type 3 is the address register `a0`, or `tN` in a pixel program, which Microsoft's disassembler lists as one
705        if !matches!(
706            register.kind,
707            RegisterType::Address | RegisterType::Texture | RegisterType::Loop
708        ) || token & 0x2000 != 0
709        {
710            return Err(error(
711                at,
712                format!(
713                    "relative address token of {what} names {register:?}{}, where it is the address register a0 or the \
714                     loop counter aL",
715                    if token & 0x2000 != 0 {
716                        " relatively addressed itself"
717                    } else {
718                        ""
719                    }
720                ),
721            ));
722        }
723        if (token >> 24) & 15 != 0 {
724            return Err(error(
725                at,
726                format!(
727                    "relative address token of {what} has source modifier {}, where it has none",
728                    (token >> 24) & 15
729                ),
730            ));
731        }
732        Ok(Relative {
733            word: Some(at),
734            register,
735            swizzle: [16, 18, 20, 22].map(|shift| bits(token, shift, 3)),
736        })
737    }
738
739    fn destination(&mut self) -> Result<Destination> {
740        let (at, token) = self.next()?;
741        let version = self.version;
742        let register = register(token & !0x2000, at, version)?;
743        let modifiers = (token >> 20) & 15;
744        if modifiers & 8 != 0 {
745            return Err(error(
746                at,
747                format!("destination {token:#010x} sets result modifier bit 23"),
748            ));
749        }
750        let shift = bits(token, 24, 15);
751        let shift = if shift >= 8 {
752            i8::try_from(i16::from(shift).saturating_sub(16)).unwrap_or(0)
753        } else {
754            i8::try_from(shift).unwrap_or(0)
755        };
756        // pixel 1.x's shifts are read in any version, as Microsoft's disassembler lists them; 4 to 12 are no shift
757        if !(-3..=3).contains(&shift) {
758            return Err(error(
759                at,
760                format!("destination {token:#010x} has result shift {shift}, where it is -3 to 3"),
761            ));
762        }
763        // relative addressing too, which in Shader Model 1 has no address token
764        let relative = if token & 0x2000 != 0 {
765            Some(self.relative(at, "a destination")?)
766        } else {
767            None
768        };
769        Ok(Destination {
770            word: at,
771            register,
772            mask: bits(token, 16, 15),
773            saturate: modifiers & 1 != 0,
774            partial_precision: modifiers & 2 != 0,
775            centroid: modifiers & 4 != 0,
776            shift,
777            relative,
778        })
779    }
780
781    fn source(&mut self) -> Result<Source> {
782        let (at, token) = self.next()?;
783        let version = self.version;
784        let register = register(token & !0x2000, at, version)?;
785        let modifier = Modifier::of((token >> 24) & 15).ok_or_else(|| {
786            error(
787                at,
788                format!("source modifier {} is not one of 0 to 13", (token >> 24) & 15),
789            )
790        })?;
791        let relative = if token & 0x2000 != 0 {
792            Some(self.relative(at, "a source")?)
793        } else {
794            None
795        };
796        Ok(Source {
797            word: at,
798            register,
799            swizzle: [16, 18, 20, 22].map(|shift| bits(token, shift, 3)),
800            modifier,
801            relative,
802        })
803    }
804}
805
806impl Records<'_> {
807    /// The next record, `None` at `END`.
808    fn record(&mut self) -> Result<Option<Item>> {
809        let version = self.version;
810        let words = &self.words;
811        let mut at = self.at;
812        let word = at;
813        let token = words.get(word).ok_or_else(|| {
814            error(
815                word,
816                if word >= MAX_WORDS {
817                    "the program exceeds 1,048,576 words without END"
818                } else {
819                    "missing END"
820                },
821            )
822        })?;
823        at = at.saturating_add(1);
824        if token == 0xffff {
825            self.end = Some(word);
826            self.at = at;
827            return Ok(None);
828        }
829        let op = token & 0xffff;
830        if op == 0xfffe {
831            if token & 0x8000_0000 != 0 {
832                return Err(error(word, "COMMENT reserved bit"));
833            }
834            let count = usize::try_from((token >> 16) & 0x7fff).unwrap_or(usize::MAX);
835            let end = at.saturating_add(count);
836            let data: Vec<u32> = (at..end).map_while(|n| words.get(n)).collect();
837            if data.len() != count {
838                return Err(error(
839                    word,
840                    format!(
841                        "instruction/comment span of {count} words extends past the stream's {} words",
842                        words.len()
843                    ),
844                ));
845            }
846            if let Some((&tag, rest)) = data.split_first() {
847                let bytes = || -> Vec<u8> { rest.iter().flat_map(|w| w.to_le_bytes()).collect() };
848                if tag == u32::from_le_bytes(*b"CTAB") {
849                    if self.constants.is_some() {
850                        return Err(error(word, "duplicate CTAB"));
851                    }
852                    self.constants = Some(crate::ctab::read(
853                        &bytes(),
854                        word.saturating_add(2),
855                        version.token(),
856                    )?);
857                } else if tag == u32::from_le_bytes(*b"DBUG") {
858                    if self.debug.is_some() {
859                        return Err(error(word, "duplicate DBUG"));
860                    }
861                    self.debug = Some(crate::debug::read(&bytes(), word.saturating_add(2))?);
862                }
863            }
864            self.at = end;
865            return Ok(Some(Item::Comment(Comment { word, data })));
866        }
867        let opcode = u16::try_from(op)
868            .ok()
869            .and_then(Opcode::from_code)
870            .ok_or_else(|| error(word, format!("opcode {op} is not a Direct3D 9 instruction")))?;
871        // an opcode outside its versions is read with the operands it takes there, as Microsoft's disassembler lists it
872        let sm1 = version.major == 1;
873        let length = usize::from(bits(token, 24, 15));
874        let shape = match (opcode, opcode.shape(version)) {
875            // 3.0's `sgn` reads one source, but Microsoft's assembler writes the three of 2.x (`sgn r0, c0, r1, r2`):
876            // the stated length tells which
877            (Opcode::Sgn, Shape::Operands { destination, .. }) if version.major == 3 && length == 4 => {
878                Shape::Operands {
879                    destination,
880                    sources: 3,
881                }
882            }
883            (_, shape) => shape,
884        };
885        let predicated = token & 0x1000_0000 != 0;
886        let coissue = token & 0x4000_0000 != 0;
887        let control = bits(token, 16, 0xff);
888        if token & 0xa000_0000 != 0 {
889            return Err(error(
890                word,
891                format!("instruction token {token:#010x} sets reserved bit 29 or 31"),
892            ));
893        }
894        // co-issue (pixel 1.x's) and predication (2.x's and 3.0's) are read in any version, as Microsoft's
895        // disassembler lists them
896        if shape == Shape::Phase && token != 0xfffd {
897            return Err(error(
898                word,
899                format!("phase token {token:#010x} has bits beyond the opcode"),
900            ));
901        }
902        let controlled = match opcode {
903            Opcode::Tex if !sm1 => (0..=2).contains(&control),
904            Opcode::IfC | Opcode::BreakC | Opcode::SetP => (1..=6).contains(&control),
905            _ => control == 0,
906        };
907        if !controlled {
908            return Err(error(
909                word,
910                format!(
911                    "{} has control bits {control:#x}, which it does not define",
912                    opcode.name()
913                ),
914            ));
915        }
916        let end = if sm1 {
917            words.len()
918        } else {
919            let end = at.saturating_add(length);
920            if end > words.len() {
921                return Err(error(
922                    word,
923                    format!(
924                        "instruction/comment span of {length} operands extends past the stream's {} words",
925                        words.len()
926                    ),
927                ));
928            }
929            end
930        };
931        let mut operands = Operands {
932            words,
933            at,
934            end,
935            instruction: word,
936            version,
937        };
938        let item = match shape {
939            Shape::Phase => Item::Instruction(Instruction {
940                word,
941                opcode,
942                control,
943                coissue,
944                predicate: None,
945                destination: None,
946                sources: Vec::new(),
947            }),
948            Shape::Declaration => {
949                if predicated {
950                    return Err(error(word, "predicated dcl"));
951                }
952                let (token_at, token) = operands.next()?;
953                let destination = operands.destination()?;
954                Item::Declaration(Declaration {
955                    word,
956                    token,
957                    declared: declared(token, token_at, destination.register)?,
958                    destination,
959                })
960            }
961            Shape::Definition { words: count } => {
962                if predicated {
963                    return Err(error(word, format!("predicated {}", opcode.name())));
964                }
965                let destination = operands.destination()?;
966                let expected = match opcode {
967                    Opcode::Def => RegisterType::Const,
968                    Opcode::DefI => RegisterType::ConstInt,
969                    _ => RegisterType::ConstBool,
970                };
971                if destination.register.kind != expected || destination.relative.is_some() {
972                    return Err(error(
973                        destination.word,
974                        format!(
975                            "{} defines {:?}, where it defines a {expected:?} register",
976                            opcode.name(),
977                            destination.register
978                        ),
979                    ));
980                }
981                let mut values = [0u32; 4];
982                for value in values.iter_mut().take(count) {
983                    *value = operands.next()?.1;
984                }
985                let literal = match opcode {
986                    Opcode::Def => Literal::Float(values),
987                    Opcode::DefI => Literal::Integer(values.map(|v| i32::from_le_bytes(v.to_le_bytes()))),
988                    _ => {
989                        let [value, ..] = values;
990                        Literal::Bool(value)
991                    }
992                };
993                Item::Definition(Definition {
994                    word,
995                    destination,
996                    literal,
997                })
998            }
999            Shape::Operands { destination, sources } => {
1000                let destination = if destination {
1001                    Some(operands.destination()?)
1002                } else {
1003                    None
1004                };
1005                let predicate = if predicated {
1006                    let p = operands.source()?;
1007                    if p.register.kind != RegisterType::Predicate
1008                        || !matches!(p.modifier, Modifier::None | Modifier::Not)
1009                    {
1010                        return Err(error(
1011                            p.word,
1012                            format!(
1013                                "the predicate token names {:?} with {:?}, where it is p0 or !p0",
1014                                p.register, p.modifier
1015                            ),
1016                        ));
1017                    }
1018                    Some(p)
1019                } else {
1020                    None
1021                };
1022                let mut read = Vec::with_capacity(sources);
1023                for _ in 0..sources {
1024                    read.push(operands.source()?);
1025                }
1026                Item::Instruction(Instruction {
1027                    word,
1028                    opcode,
1029                    control,
1030                    coissue,
1031                    predicate,
1032                    destination,
1033                    sources: read,
1034                })
1035            }
1036        };
1037        let used = operands.at.saturating_sub(at);
1038        if sm1 {
1039            // a 1.x instruction states no length; one that states one must state its own
1040            if length != 0 && length != used {
1041                return Err(error(
1042                    word,
1043                    format!(
1044                        "{} states {length} operand tokens, where its operands take {used}",
1045                        opcode.name()
1046                    ),
1047                ));
1048            }
1049        } else if used != length {
1050            return Err(error(
1051                word,
1052                format!(
1053                    "{} states {length} operand tokens, where its operands take {used}",
1054                    opcode.name()
1055                ),
1056            ));
1057        }
1058        self.at = operands.at;
1059        Ok(Some(item))
1060    }
1061}
1062
1063/// What a declaration token declares for `register`.
1064fn declared(token: u32, at: usize, register: Register) -> Result<Declared> {
1065    if token & 0x8000_0000 == 0 {
1066        return Err(error(at, format!("DCL token {token:#010x} lacks bit 31")));
1067    }
1068    if register.kind == RegisterType::Sampler {
1069        return Ok(Declared::Sampler(match token {
1070            0x9000_0000 => TextureType::D2,
1071            0x9800_0000 => TextureType::Cube,
1072            0xa000_0000 => TextureType::Volume,
1073            _ => {
1074                return Err(error(
1075                    at,
1076                    format!(
1077                        "DCL sampler texture type {token:#x}, where it is 0x90000000 (2d), 0x98000000 (cube) or \
1078                         0xa0000000 (volume)"
1079                    ),
1080                ));
1081            }
1082        }));
1083    }
1084    if token & !0x800f_000f != 0 {
1085        return Err(error(at, "DCL semantic reserved bits"));
1086    }
1087    let usage = bits(token, 0, 15);
1088    if usage > 13 {
1089        return Err(error(at, format!("DCL usage {usage}, where it is 0 to 13")));
1090    }
1091    Ok(Declared::Semantic {
1092        usage,
1093        index: bits(token, 16, 15),
1094    })
1095}