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/// The minimum precision of an operand (`D3DSP_MIN_PRECISION`, bits 14 to 15 of a destination or source token), which
227/// fxc writes in a feature level 9 program's Direct3D 9 part for a `min16float` value. Microsoft's listing writes it
228/// after the operand: `{min16f}`, `{min2_8f}`, nothing for 3. A relative-address or predicate token's bits 14 to 15
229/// mean nothing; it ignores them.
230#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
231pub enum Precision {
232    /// 0, the precision of the register (`D3DMP_DEFAULT`).
233    #[default]
234    Default,
235    /// 1, at least 16 bits (`D3DMP_16`, `{min16f}`).
236    Min16,
237    /// 2, at least 2.8 fixed point (`D3DMP_2_8`, `{min2_8f}`).
238    Min2_8,
239    /// 3, which `d3d9types.h` does not name and the listing writes nothing for.
240    Unnamed,
241}
242
243impl Precision {
244    /// The precision of an operand token's bits 14 to 15.
245    pub fn of(token: u32) -> Self {
246        match (token >> 14) & 3 {
247            0 => Precision::Default,
248            1 => Precision::Min16,
249            2 => Precision::Min2_8,
250            _ => Precision::Unnamed,
251        }
252    }
253}
254
255/// A destination operand.
256#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
257pub struct Destination {
258    /// The word of the operand token.
259    pub word: usize,
260    /// The register written.
261    pub register: Register,
262    /// The lanes written, bit 0 x to bit 3 w (bits 16 to 19); a declaration's lanes declared.
263    pub mask: u8,
264    /// `_sat` (`D3DSPDM_SATURATE`, bit 20).
265    pub saturate: bool,
266    /// `_pp` (`D3DSPDM_PARTIALPRECISION`, bit 21).
267    pub partial_precision: bool,
268    /// `_centroid` (`D3DSPDM_MSAMPCENTROID`, bit 22).
269    pub centroid: bool,
270    /// The pixel 1.x result shift (bits 24 to 27 as a signed number): 1 `_x2`, 2 `_x4`, 3 `_x8`, -1 `_d2`, -2 `_d4`,
271    /// -3 `_d8`; 0 otherwise and in every other version.
272    pub shift: i8,
273    /// The index register, for a relatively addressed destination (`o[aL]` of a vertex 3.0 program).
274    pub relative: Option<Relative>,
275    /// The minimum precision, bits 14 to 15.
276    pub precision: Precision,
277}
278
279/// A source operand.
280#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
281pub struct Source {
282    /// The word of the operand token.
283    pub word: usize,
284    /// The register read.
285    pub register: Register,
286    /// 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.
287    pub swizzle: [u8; 4],
288    /// The source modifier.
289    pub modifier: Modifier,
290    /// The index register, for a relatively addressed source.
291    pub relative: Option<Relative>,
292    /// The minimum precision, bits 14 to 15 (of a predicate, nothing the listing writes).
293    pub precision: Precision,
294}
295
296/// The comparison of `if_comp`, `break_comp` and `setp_comp` (`D3DSHADER_COMPARISON`), bits 16 to 18 of the instruction
297/// token.
298#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
299pub enum Comparison {
300    /// `_gt` (1).
301    Greater,
302    /// `_eq` (2).
303    Equal,
304    /// `_ge` (3).
305    GreaterEqual,
306    /// `_lt` (4).
307    Less,
308    /// `_ne` (5).
309    NotEqual,
310    /// `_le` (6).
311    LessEqual,
312}
313
314/// An instruction: everything but declarations, definitions, comments and `END`.
315#[derive(Clone, Debug, PartialEq, Eq)]
316pub struct Instruction {
317    /// The word of the instruction token, counted from the version token.
318    pub word: usize,
319    /// The opcode.
320    pub opcode: Opcode,
321    /// The opcode-specific controls, bits 16 to 23: for `tex` from pixel 1.4 on 0 `texld`, 1 `texldp` (projected) and 2
322    /// `texldb` (biased); for `if_comp`, `break_comp` and `setp_comp` the [`Comparison`]; 0 for every other opcode.
323    pub control: u8,
324    /// The co-issue flag of a pixel 1.x instruction (bit 30), written `+` before it.
325    pub coissue: bool,
326    /// The predicate an instruction is predicated on (bit 28 set): the predicate register `p0`, its swizzle and
327    /// [`Modifier::Not`] or none. Its token follows the destination's.
328    pub predicate: Option<Source>,
329    /// The destination; `None` for an opcode that has none. `texkill`'s is the register it tests.
330    pub destination: Option<Destination>,
331    /// The sources, in the order the stream writes them.
332    pub sources: Vec<Source>,
333}
334
335impl Instruction {
336    /// The comparison of `if_comp`, `break_comp` and `setp_comp`; `None` for other opcodes.
337    pub fn comparison(&self) -> Option<Comparison> {
338        if !matches!(self.opcode, Opcode::IfC | Opcode::BreakC | Opcode::SetP) {
339            return None;
340        }
341        Some(match self.control {
342            1 => Comparison::Greater,
343            2 => Comparison::Equal,
344            3 => Comparison::GreaterEqual,
345            4 => Comparison::Less,
346            5 => Comparison::NotEqual,
347            _ => Comparison::LessEqual,
348        })
349    }
350}
351
352/// A sampler's texture type (`D3DSAMPLER_TEXTURE_TYPE`), bits 27 to 30 of its declaration token.
353#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
354pub enum TextureType {
355    /// `dcl_2d` (2).
356    D2,
357    /// `dcl_cube` (3).
358    Cube,
359    /// `dcl_volume` (4).
360    Volume,
361}
362
363/// What a declaration token declares.
364#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
365pub enum Declared {
366    /// A sampler's texture type.
367    Sampler(TextureType),
368    /// Any other register's usage (`D3DDECLUSAGE`: 0 position, 1 blend weight, 2 blend indices, 3 normal, 4 point size,
369    /// 5 texture coordinate, 6 tangent, 7 binormal, 8 tessellation factor, 9 transformed position, 10 colour, 11 fog,
370    /// 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`
371    /// store usage 0 and index 0, as does `dcl vPos`.
372    Semantic {
373        /// The usage.
374        usage: u8,
375        /// The usage index.
376        index: u8,
377    },
378}
379
380/// A `dcl`: the declaration token and the register declared.
381#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
382pub struct Declaration {
383    /// The word of the instruction token.
384    pub word: usize,
385    /// The declaration token, as stored.
386    pub token: u32,
387    /// What the declaration token says.
388    pub declared: Declared,
389    /// The register declared, its mask, and its modifiers (`_pp`, `_centroid`).
390    pub destination: Destination,
391}
392
393/// The literal of a definition.
394#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
395pub enum Literal {
396    /// `def`: four floats, as their bit patterns.
397    Float([u32; 4]),
398    /// `defi`: four integers.
399    Integer([i32; 4]),
400    /// `defb`: a boolean, as its word (`TRUE` is 1).
401    Bool(u32),
402}
403
404/// A `def`, `defi` or `defb`: a constant register and the literal it holds.
405#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
406pub struct Definition {
407    /// The word of the instruction token.
408    pub word: usize,
409    /// The register defined: a float, integer or boolean constant, as the opcode says.
410    pub destination: Destination,
411    /// The literal.
412    pub literal: Literal,
413}
414
415/// A comment: its words, without its token. The constant table is one, its first word the FourCC `CTAB`.
416#[derive(Clone, Debug, PartialEq, Eq)]
417pub struct Comment {
418    /// The word of the comment token.
419    pub word: usize,
420    /// The comment's words.
421    pub data: Vec<u32>,
422}
423
424/// One record of the stream.
425#[derive(Clone, Debug, PartialEq, Eq)]
426pub enum Item {
427    /// A comment.
428    Comment(Comment),
429    /// A `dcl`.
430    Declaration(Declaration),
431    /// A `def`, `defi` or `defb`.
432    Definition(Definition),
433    /// Any other instruction.
434    Instruction(Instruction),
435}
436
437impl Item {
438    /// The word of the record's token.
439    pub fn word(&self) -> usize {
440        match self {
441            Item::Comment(c) => c.word,
442            Item::Declaration(d) => d.word,
443            Item::Definition(d) => d.word,
444            Item::Instruction(i) => i.word,
445        }
446    }
447}
448
449/// A program read: its version, its records in stream order, its constant table and its debug information.
450#[derive(Clone, Debug, PartialEq, Eq)]
451pub struct Program {
452    /// The version token.
453    pub version: Version,
454    /// Every record between the version token and `END`, in stream order.
455    pub items: Vec<Item>,
456    /// The word of `END`.
457    pub end: usize,
458    /// The `CTAB` comment decoded; `None` when the program has none.
459    pub constants: Option<ConstantTable>,
460    /// The `DBUG` comment decoded (a `/Zi` build's); `None` when the program has none.
461    pub debug: Option<DebugInfo>,
462}
463
464impl Program {
465    /// The comments, in stream order.
466    pub fn comments(&self) -> impl Iterator<Item = &Comment> {
467        self.items.iter().filter_map(|i| match i {
468            Item::Comment(c) => Some(c),
469            _ => None,
470        })
471    }
472    /// The declarations, in stream order.
473    pub fn declarations(&self) -> impl Iterator<Item = &Declaration> {
474        self.items.iter().filter_map(|i| match i {
475            Item::Declaration(d) => Some(d),
476            _ => None,
477        })
478    }
479    /// The definitions, in stream order.
480    pub fn definitions(&self) -> impl Iterator<Item = &Definition> {
481        self.items.iter().filter_map(|i| match i {
482            Item::Definition(d) => Some(d),
483            _ => None,
484        })
485    }
486    /// The instructions, in stream order.
487    pub fn instructions(&self) -> impl Iterator<Item = &Instruction> {
488        self.items.iter().filter_map(|i| match i {
489            Item::Instruction(i) => Some(i),
490            _ => None,
491        })
492    }
493}
494
495/// Read a complete program: version token to `END`, with nothing after it. The bytes are little-endian words.
496pub fn read(bytes: &[u8]) -> Result<Program> {
497    collect(records(bytes)?)
498}
499
500/// Read the first program of `bytes`, which may hold more after it (a container's other records, say), and return it
501/// with its exact bytes, version token to `END`. `END` is found by reading every record, never by searching for it
502/// inside operands or comments.
503pub fn frame(bytes: &[u8]) -> Result<(Program, &[u8])> {
504    let program = collect(start(bytes, false)?)?;
505    let span = bytes
506        .get(..program.end.saturating_add(1).saturating_mul(4))
507        .ok_or_else(|| error(program.end, "END is past the buffer"))?;
508    Ok((program, span))
509}
510
511/// The records of a complete program, one at a time in stream order, for a caller that stops at the first record it
512/// cannot use, before the reader has read further (and refused, maybe, something later). The version is read first;
513/// a refusal ends the iteration, as does `END`, after which words left over are a refusal. [`read`] is these records
514/// collected.
515pub fn records(bytes: &[u8]) -> Result<Records<'_>> {
516    if !bytes.len().is_multiple_of(4) || bytes.len() > MAX_WORDS.saturating_mul(4) {
517        return Err(error(
518            0,
519            format!(
520                "token stream of {} bytes is not whole words or exceeds 1,048,576 words",
521                bytes.len()
522            ),
523        ));
524    }
525    start(bytes, true)
526}
527
528fn start(bytes: &[u8], whole: bool) -> Result<Records<'_>> {
529    let words = Words { bytes };
530    let token = words.get(0).ok_or_else(|| error(0, "no version token"))?;
531    let version = Version::from_token(token).ok_or_else(|| {
532        error(
533            0,
534            format!(
535                "version token {token:#010x} is not a Direct3D 9 vertex (0xfffe) or pixel (0xffff) program of \
536                 version 1.0 to 3.0"
537            ),
538        )
539    })?;
540    Ok(Records {
541        words,
542        version,
543        at: 1,
544        whole,
545        end: None,
546        done: false,
547        constants: None,
548        debug: None,
549    })
550}
551
552fn collect(mut records: Records<'_>) -> Result<Program> {
553    let mut items = Vec::new();
554    for item in records.by_ref() {
555        items.push(item?);
556    }
557    Ok(Program {
558        version: records.version,
559        items,
560        end: records.end.unwrap_or(0),
561        constants: records.constants,
562        debug: records.debug,
563    })
564}
565
566/// A program's records in stream order: see [`records`].
567#[derive(Debug)]
568pub struct Records<'a> {
569    words: Words<'a>,
570    version: Version,
571    /// The word of the next record's token.
572    at: usize,
573    /// True when the program is the whole buffer, so that words after `END` are a refusal.
574    whole: bool,
575    end: Option<usize>,
576    done: bool,
577    constants: Option<ConstantTable>,
578    debug: Option<DebugInfo>,
579}
580
581impl Records<'_> {
582    /// The program's version.
583    pub fn version(&self) -> Version {
584        self.version
585    }
586    /// The constant table, once the `CTAB` comment has been read.
587    pub fn constants(&self) -> Option<&ConstantTable> {
588        self.constants.as_ref()
589    }
590    /// The debug information, once the `DBUG` comment has been read.
591    pub fn debug(&self) -> Option<&DebugInfo> {
592        self.debug.as_ref()
593    }
594    /// The word of `END`, once it has been read.
595    pub fn end(&self) -> Option<usize> {
596        self.end
597    }
598}
599
600impl Iterator for Records<'_> {
601    type Item = Result<Item>;
602
603    fn next(&mut self) -> Option<Result<Item>> {
604        if self.done {
605            return None;
606        }
607        match self.record() {
608            Ok(Some(item)) => Some(Ok(item)),
609            Ok(None) => {
610                self.done = true;
611                let words = self.words.len();
612                (self.whole && self.at != words).then(|| {
613                    Err(error(
614                        self.at,
615                        format!("{} words after END", words.saturating_sub(self.at)),
616                    ))
617                })
618            }
619            Err(e) => {
620                self.done = true;
621                Some(Err(e))
622            }
623        }
624    }
625}
626
627/// The stream's words, read from the bytes as needed; a buffer's bytes after its last whole word are never read.
628#[derive(Debug)]
629struct Words<'a> {
630    bytes: &'a [u8],
631}
632
633impl Words<'_> {
634    fn len(&self) -> usize {
635        (self.bytes.len() / 4).min(MAX_WORDS)
636    }
637    fn get(&self, at: usize) -> Option<u32> {
638        if at >= MAX_WORDS {
639            return None;
640        }
641        let start = at.checked_mul(4)?;
642        let word: [u8; 4] = self.bytes.get(start..start.checked_add(4)?)?.try_into().ok()?;
643        Some(u32::from_le_bytes(word))
644    }
645}
646
647/// The bits of `word` from `shift` that `mask` keeps, which is at most 8 bits wide.
648fn bits(word: u32, shift: u32, mask: u32) -> u8 {
649    u8::try_from(word.checked_shr(shift).unwrap_or(0) & mask & 0xff).unwrap_or(u8::MAX)
650}
651
652/// The register an operand token names (its bits 14 to 15, a precision, are the caller's).
653fn register(token: u32, at: usize, version: Version) -> Result<Register> {
654    if token & 0x8000_0000 == 0 {
655        return Err(error(at, format!("operand token {token:#010x} lacks bit 31")));
656    }
657    let code = ((token >> 28) & 7) | ((token >> 8) & 0x18);
658    let number = token & 0x7ff;
659    let (kind, last) =
660        RegisterType::of(code, version).map_err(|why| error(at, format!("register type {code} {why}")))?;
661    if last.is_some_and(|last| number > last) {
662        return Err(error(
663            at,
664            format!(
665                "register {kind:?} {number}, where the type has registers 0 to {}",
666                last.unwrap_or(0)
667            ),
668        ));
669    }
670    Ok(Register { kind, number })
671}
672
673/// Reads the operand tokens of one instruction, from the word after the instruction token up to `end` (the
674/// instruction's length from Shader Model 2 on; the stream's end in 1.x, whose instructions do not state theirs).
675struct Operands<'a> {
676    words: &'a Words<'a>,
677    at: usize,
678    end: usize,
679    /// The instruction token's word, which a truncation names.
680    instruction: usize,
681    version: Version,
682}
683
684impl Operands<'_> {
685    fn next(&mut self) -> Result<(usize, u32)> {
686        let at = self.at;
687        let token = (at < self.end)
688            .then(|| self.words.get(at))
689            .flatten()
690            .ok_or_else(|| {
691                error(
692                    self.instruction,
693                    format!(
694                        "instruction's operand span extends past {} (it ends at word {})",
695                        if self.end < self.words.len() {
696                            "its stated length"
697                        } else {
698                            "the stream"
699                        },
700                        self.end.min(self.words.len())
701                    ),
702                )
703            })?;
704        self.at = at.saturating_add(1);
705        Ok((at, token))
706    }
707
708    /// The relative-address token after an operand token with bit 13 set, or the implicit `a0.x` of vertex 1.x.
709    fn relative(&mut self, operand: usize, what: &str) -> Result<Relative> {
710        let version = self.version;
711        if version.major == 1 {
712            return Ok(Relative {
713                word: None,
714                register: Register {
715                    kind: RegisterType::Address,
716                    number: 0,
717                },
718                swizzle: [0; 4],
719            });
720        }
721        let (at, token) = self.next().map_err(|e| {
722            error(
723                operand,
724                format!(
725                    "relative addressing of {what} without its address token: {}",
726                    e.detail
727                ),
728            )
729        })?;
730        let register = register(token & !0x2000, at, version)?;
731        // type 3 is the address register `a0`, or `tN` in a pixel program, which Microsoft's disassembler lists as one
732        if !matches!(
733            register.kind,
734            RegisterType::Address | RegisterType::Texture | RegisterType::Loop
735        ) || token & 0x2000 != 0
736        {
737            return Err(error(
738                at,
739                format!(
740                    "relative address token of {what} names {register:?}{}, where it is the address register a0 or the \
741                     loop counter aL",
742                    if token & 0x2000 != 0 {
743                        " relatively addressed itself"
744                    } else {
745                        ""
746                    }
747                ),
748            ));
749        }
750        if (token >> 24) & 15 != 0 {
751            return Err(error(
752                at,
753                format!(
754                    "relative address token of {what} has source modifier {}, where it has none",
755                    (token >> 24) & 15
756                ),
757            ));
758        }
759        Ok(Relative {
760            word: Some(at),
761            register,
762            swizzle: [16, 18, 20, 22].map(|shift| bits(token, shift, 3)),
763        })
764    }
765
766    fn destination(&mut self) -> Result<Destination> {
767        let (at, token) = self.next()?;
768        let version = self.version;
769        let register = register(token & !0x2000, at, version)?;
770        let modifiers = (token >> 20) & 15;
771        if modifiers & 8 != 0 {
772            return Err(error(
773                at,
774                format!("destination {token:#010x} sets result modifier bit 23"),
775            ));
776        }
777        let shift = bits(token, 24, 15);
778        let shift = if shift >= 8 {
779            i8::try_from(i16::from(shift).saturating_sub(16)).unwrap_or(0)
780        } else {
781            i8::try_from(shift).unwrap_or(0)
782        };
783        // pixel 1.x's shifts are read in any version, as Microsoft's disassembler lists them; 4 to 12 are no shift
784        if !(-3..=3).contains(&shift) {
785            return Err(error(
786                at,
787                format!("destination {token:#010x} has result shift {shift}, where it is -3 to 3"),
788            ));
789        }
790        // relative addressing too, which in Shader Model 1 has no address token
791        let relative = if token & 0x2000 != 0 {
792            Some(self.relative(at, "a destination")?)
793        } else {
794            None
795        };
796        Ok(Destination {
797            word: at,
798            register,
799            mask: bits(token, 16, 15),
800            saturate: modifiers & 1 != 0,
801            partial_precision: modifiers & 2 != 0,
802            centroid: modifiers & 4 != 0,
803            shift,
804            relative,
805            precision: Precision::of(token),
806        })
807    }
808
809    fn source(&mut self) -> Result<Source> {
810        let (at, token) = self.next()?;
811        let version = self.version;
812        let register = register(token & !0x2000, at, version)?;
813        let modifier = Modifier::of((token >> 24) & 15).ok_or_else(|| {
814            error(
815                at,
816                format!("source modifier {} is not one of 0 to 13", (token >> 24) & 15),
817            )
818        })?;
819        let relative = if token & 0x2000 != 0 {
820            Some(self.relative(at, "a source")?)
821        } else {
822            None
823        };
824        Ok(Source {
825            word: at,
826            register,
827            swizzle: [16, 18, 20, 22].map(|shift| bits(token, shift, 3)),
828            modifier,
829            relative,
830            precision: Precision::of(token),
831        })
832    }
833}
834
835impl Records<'_> {
836    /// The next record, `None` at `END`.
837    fn record(&mut self) -> Result<Option<Item>> {
838        let version = self.version;
839        let words = &self.words;
840        let mut at = self.at;
841        let word = at;
842        let token = words.get(word).ok_or_else(|| {
843            error(
844                word,
845                if word >= MAX_WORDS {
846                    "the program exceeds 1,048,576 words without END"
847                } else {
848                    "missing END"
849                },
850            )
851        })?;
852        at = at.saturating_add(1);
853        if token == 0xffff {
854            self.end = Some(word);
855            self.at = at;
856            return Ok(None);
857        }
858        let op = token & 0xffff;
859        if op == 0xfffe {
860            if token & 0x8000_0000 != 0 {
861                return Err(error(word, "COMMENT reserved bit"));
862            }
863            let count = usize::try_from((token >> 16) & 0x7fff).unwrap_or(usize::MAX);
864            let end = at.saturating_add(count);
865            let data: Vec<u32> = (at..end).map_while(|n| words.get(n)).collect();
866            if data.len() != count {
867                return Err(error(
868                    word,
869                    format!(
870                        "instruction/comment span of {count} words extends past the stream's {} words",
871                        words.len()
872                    ),
873                ));
874            }
875            if let Some((&tag, rest)) = data.split_first() {
876                let bytes = || -> Vec<u8> { rest.iter().flat_map(|w| w.to_le_bytes()).collect() };
877                if tag == u32::from_le_bytes(*b"CTAB") {
878                    if self.constants.is_some() {
879                        return Err(error(word, "duplicate CTAB"));
880                    }
881                    self.constants = Some(crate::ctab::read(
882                        &bytes(),
883                        word.saturating_add(2),
884                        version.token(),
885                    )?);
886                } else if tag == u32::from_le_bytes(*b"DBUG") {
887                    if self.debug.is_some() {
888                        return Err(error(word, "duplicate DBUG"));
889                    }
890                    self.debug = Some(crate::debug::read(&bytes(), word.saturating_add(2))?);
891                }
892            }
893            self.at = end;
894            return Ok(Some(Item::Comment(Comment { word, data })));
895        }
896        let opcode = u16::try_from(op)
897            .ok()
898            .and_then(Opcode::from_code)
899            .ok_or_else(|| error(word, format!("opcode {op} is not a Direct3D 9 instruction")))?;
900        // an opcode outside its versions is read with the operands it takes there, as Microsoft's disassembler lists it
901        let sm1 = version.major == 1;
902        let length = usize::from(bits(token, 24, 15));
903        let shape = match (opcode, opcode.shape(version)) {
904            // 3.0's `sgn` reads one source, but Microsoft's assembler writes the three of 2.x (`sgn r0, c0, r1, r2`):
905            // the stated length tells which
906            (Opcode::Sgn, Shape::Operands { destination, .. }) if version.major == 3 && length == 4 => {
907                Shape::Operands {
908                    destination,
909                    sources: 3,
910                }
911            }
912            (_, shape) => shape,
913        };
914        let predicated = token & 0x1000_0000 != 0;
915        let coissue = token & 0x4000_0000 != 0;
916        let control = bits(token, 16, 0xff);
917        if token & 0xa000_0000 != 0 {
918            return Err(error(
919                word,
920                format!("instruction token {token:#010x} sets reserved bit 29 or 31"),
921            ));
922        }
923        // co-issue (pixel 1.x's) and predication (2.x's and 3.0's) are read in any version, as Microsoft's
924        // disassembler lists them
925        if shape == Shape::Phase && token != 0xfffd {
926            return Err(error(
927                word,
928                format!("phase token {token:#010x} has bits beyond the opcode"),
929            ));
930        }
931        let controlled = match opcode {
932            Opcode::Tex if !sm1 => (0..=2).contains(&control),
933            Opcode::IfC | Opcode::BreakC | Opcode::SetP => (1..=6).contains(&control),
934            _ => control == 0,
935        };
936        if !controlled {
937            return Err(error(
938                word,
939                format!(
940                    "{} has control bits {control:#x}, which it does not define",
941                    opcode.name()
942                ),
943            ));
944        }
945        let end = if sm1 {
946            words.len()
947        } else {
948            let end = at.saturating_add(length);
949            if end > words.len() {
950                return Err(error(
951                    word,
952                    format!(
953                        "instruction/comment span of {length} operands extends past the stream's {} words",
954                        words.len()
955                    ),
956                ));
957            }
958            end
959        };
960        let mut operands = Operands {
961            words,
962            at,
963            end,
964            instruction: word,
965            version,
966        };
967        let item = match shape {
968            Shape::Phase => Item::Instruction(Instruction {
969                word,
970                opcode,
971                control,
972                coissue,
973                predicate: None,
974                destination: None,
975                sources: Vec::new(),
976            }),
977            Shape::Declaration => {
978                if predicated {
979                    return Err(error(word, "predicated dcl"));
980                }
981                let (token_at, token) = operands.next()?;
982                let destination = operands.destination()?;
983                Item::Declaration(Declaration {
984                    word,
985                    token,
986                    declared: declared(token, token_at, destination.register)?,
987                    destination,
988                })
989            }
990            Shape::Definition { words: count } => {
991                if predicated {
992                    return Err(error(word, format!("predicated {}", opcode.name())));
993                }
994                let destination = operands.destination()?;
995                let expected = match opcode {
996                    Opcode::Def => RegisterType::Const,
997                    Opcode::DefI => RegisterType::ConstInt,
998                    _ => RegisterType::ConstBool,
999                };
1000                if destination.register.kind != expected || destination.relative.is_some() {
1001                    return Err(error(
1002                        destination.word,
1003                        format!(
1004                            "{} defines {:?}, where it defines a {expected:?} register",
1005                            opcode.name(),
1006                            destination.register
1007                        ),
1008                    ));
1009                }
1010                let mut values = [0u32; 4];
1011                for value in values.iter_mut().take(count) {
1012                    *value = operands.next()?.1;
1013                }
1014                let literal = match opcode {
1015                    Opcode::Def => Literal::Float(values),
1016                    Opcode::DefI => Literal::Integer(values.map(|v| i32::from_le_bytes(v.to_le_bytes()))),
1017                    _ => {
1018                        let [value, ..] = values;
1019                        Literal::Bool(value)
1020                    }
1021                };
1022                Item::Definition(Definition {
1023                    word,
1024                    destination,
1025                    literal,
1026                })
1027            }
1028            Shape::Operands { destination, sources } => {
1029                let destination = if destination {
1030                    Some(operands.destination()?)
1031                } else {
1032                    None
1033                };
1034                let predicate = if predicated {
1035                    let p = operands.source()?;
1036                    if p.register.kind != RegisterType::Predicate
1037                        || !matches!(p.modifier, Modifier::None | Modifier::Not)
1038                    {
1039                        return Err(error(
1040                            p.word,
1041                            format!(
1042                                "the predicate token names {:?} with {:?}, where it is p0 or !p0",
1043                                p.register, p.modifier
1044                            ),
1045                        ));
1046                    }
1047                    Some(p)
1048                } else {
1049                    None
1050                };
1051                let mut read = Vec::with_capacity(sources);
1052                for _ in 0..sources {
1053                    read.push(operands.source()?);
1054                }
1055                Item::Instruction(Instruction {
1056                    word,
1057                    opcode,
1058                    control,
1059                    coissue,
1060                    predicate,
1061                    destination,
1062                    sources: read,
1063                })
1064            }
1065        };
1066        let used = operands.at.saturating_sub(at);
1067        if sm1 {
1068            // a 1.x instruction states no length; one that states one must state its own
1069            if length != 0 && length != used {
1070                return Err(error(
1071                    word,
1072                    format!(
1073                        "{} states {length} operand tokens, where its operands take {used}",
1074                        opcode.name()
1075                    ),
1076                ));
1077            }
1078        } else if used != length {
1079            return Err(error(
1080                word,
1081                format!(
1082                    "{} states {length} operand tokens, where its operands take {used}",
1083                    opcode.name()
1084                ),
1085            ));
1086        }
1087        self.at = operands.at;
1088        Ok(Some(item))
1089    }
1090}
1091
1092/// What a declaration token declares for `register`.
1093fn declared(token: u32, at: usize, register: Register) -> Result<Declared> {
1094    if token & 0x8000_0000 == 0 {
1095        return Err(error(at, format!("DCL token {token:#010x} lacks bit 31")));
1096    }
1097    if register.kind == RegisterType::Sampler {
1098        return Ok(Declared::Sampler(match token {
1099            0x9000_0000 => TextureType::D2,
1100            0x9800_0000 => TextureType::Cube,
1101            0xa000_0000 => TextureType::Volume,
1102            _ => {
1103                return Err(error(
1104                    at,
1105                    format!(
1106                        "DCL sampler texture type {token:#x}, where it is 0x90000000 (2d), 0x98000000 (cube) or \
1107                         0xa0000000 (volume)"
1108                    ),
1109                ));
1110            }
1111        }));
1112    }
1113    if token & !0x800f_000f != 0 {
1114        return Err(error(at, "DCL semantic reserved bits"));
1115    }
1116    let usage = bits(token, 0, 15);
1117    if usage > 13 {
1118        return Err(error(at, format!("DCL usage {usage}, where it is 0 to 13")));
1119    }
1120    Ok(Declared::Semantic {
1121        usage,
1122        index: bits(token, 16, 15),
1123    })
1124}