1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! Read raw Direct3D 9 `ps_3_0` and `vs_3_0` shader tokens and their CTAB constant table, and lift them to an
//! [`iridia::Program`].
//!
//! The input is the token stream a Direct3D 9 compiler writes, version token to `END` (no container). The tokens are
//! read by [`d3d9_reader`], which reads every Direct3D 9 version as stored; this crate keeps the `vs_3_0` and `ps_3_0`
//! subset it lifts. [`read`] decodes
//! it into declarations, instructions, immediate definitions, every comment and the CTAB (creator, target, flags, named
//! register allocations, types and raw defaults). [`lift`] turns it into a `naga::Module` with an interface, which can
//! then be validated and written as WGSL ([`iridia::emit::wgsl`]). No translated text and no native compiler is needed.
//!
//! The reader is bounded: straight-line float arithmetic (`mov`, `add`, `sub`, `mad`, `mul`, `rcp`, `rsq`, `dp3`, `dp4`,
//! `min`, `max`, `exp`, `log`, `lrp`, `frc`, `pow`, `abs`, `nrm`, `sincos`), `nop`, `dcl` and `def`; pixel programs also
//! have `cmp`, `dp2add`, `texld` (plain, projected or biased) and `texkill`, with 2D, cube or volume textures; vertex
//! programs keep their declared inputs and outputs and the clip position, and have `slt`, `sge`, the address register
//! `a0` (`mova`, which rounds a half away from zero) and float constants addressed relative to it (`c[a0.x + N]`, zero outside the 256
//! constant registers). Source swizzles, negation, absolute value and destination masks and saturation are kept. Vertex
//! texture fetch, point size, other models, control flow, loop counters, predication and modifiers outside this subset
//! are refused by name and word offset ([`Error`]).
//!
//! The float constant bank is `cb0`, an array of raw `vec4<u32>` rows: register `cN` is byte offset `16 * N`, and a
//! `def` overrides it locally. Sampler `sN` becomes a texture at `tN` and a sampler at `sN`. Vertex register banks are
//! bounded to 16 inputs, 32 temporaries, 12 outputs and 256 float constants.
//!
//! Beyond [`lift`]: [`frame`] finds the program in a buffer that holds more than one, [`sampler_states`] maps a sampler
//! state (`D3DSAMP` state/value pairs) to the interface vocabulary, and [`project`], [`reencode`] and
//! [`project_vertex_output`] derive new programs from the original (a register's value at a chosen instruction, a
//! vertex output as a pixel program).
//!
//! # Example
//!
//! A `ps_3_0` program written as tokens: `def c0, 1, 2, 3, 4` and `mov oC0, c0`.
//!
//! ```
//! let words: [u32; 11] = [
//! 0xffff_0300, // ps_3_0
//! 0x0500_0051, 0xa00f_0000, 0x3f80_0000, 0x4000_0000, 0x4040_0000, 0x4080_0000, // def c0, 1, 2, 3, 4
//! 0x0200_0001, 0x800f_0800, 0xa0e4_0000, // mov oC0, c0
//! 0x0000_ffff, // end
//! ];
//! let bytes: Vec<u8> = words.iter().flat_map(|w| w.to_le_bytes()).collect();
//!
//! let program = iridia_d3d9::lift(&bytes)?;
//! assert_eq!(program.stage, iridia::Stage::Pixel);
//! program.validate().expect("a lifted program validates");
//! assert!(iridia::emit::wgsl(&program)?.contains("@fragment"));
//!
//! // anything outside the subset is refused, with its word offset
//! let mut other_model = bytes.clone();
//! other_model[..4].copy_from_slice(&0xffff_0200u32.to_le_bytes()); // ps_2_0
//! assert!(iridia_d3d9::lift(&other_model).is_err());
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! ```
//!
//! Token layout: Microsoft's [instruction](https://learn.microsoft.com/windows-hardware/drivers/display/instruction-token),
//! [source](https://learn.microsoft.com/windows-hardware/drivers/display/source-parameter-token) and
//! [destination](https://learn.microsoft.com/windows-hardware/drivers/display/destination-parameter-token) tokens;
//! [the VS register reference](https://learn.microsoft.com/windows/win32/direct3dhlsl/dx9-graphics-reference-asm-vs-registers-vs-3-0)
//! and [output declarations](https://learn.microsoft.com/windows/win32/direct3dhlsl/dcl-usage-outut-register---vs) define
//! their layout. Arithmetic follows the [ps_3_0 instruction reference](https://learn.microsoft.com/windows/win32/direct3dhlsl/dx9-graphics-reference-asm-ps-instructions-ps-3-0).
// Run the examples in the README as doc tests.
;
pub use sampler_states;
pub use ;
pub use ;
/// A refusal states the word offset in the raw token stream and the unsupported or malformed feature.
pub type Error = Refusal;
/// The result of every function in this crate: `Ok` or a refusal that names the word offset.
pub type Result<T> = Result;
pub
/// Increment when the same tokens lift differently. Hand-worked fixtures gate this version.
pub const LIFTER_VERSION: u32 = 3;
/// Lift one complete `ps_3_0` or `vs_3_0` program; trailing bytes and unknown features are errors.
/// A register value immediately after one original instruction. `lanes` order is the projected RGB order.
/// The word offset must identify an instruction, and all three distinct temporary lanes must be initialized.
/// Pixel-only: lift the original instruction prefix through `cut`, returning its selected lanes as RGB and alpha one.
/// Prior discards remain; subsequent operations/discards are excluded. This is a derived program, whose notes
/// name the cut, whose lifter identity includes the projection, and whose source hash still identifies the complete original bytecode. No meaning is assigned
/// to the chosen value: recognizing a useful cut is the caller's responsibility.
/// Pixel-only: lift the complete original program, replacing just the cut's three register lanes with the new float3
/// input `DERIVED_RGB0` (signature register 31). This runs the original downstream operations, including
/// normalization and discards, rather than a rewritten equation. Other register lanes and the prefix remain.
/// An original input v31 is refused. The caller supplies projected RGB in that new input's xyz lanes.
/// Frame the first raw SM3 vertex or pixel program in a container's remaining bytes.
/// Returns its stage and exact bytes through END; subsequent container metadata is not consumed.
/// `d3d9-reader` reads every record up to END, so END is never searched for inside operands or comments; an
/// operation the lifter does not support is retained as bytecode for [`lift`] to refuse.
/// Project selected lanes of a declared `vs_3_0` output into a derived invocation program.
///
/// The complete original program must lift successfully. A backwards register/lane slice retains only the
/// writes that reach the selected output. It preserves original arithmetic, swizzles, masks and local DEF values;
/// it does not interpret the output semantic. The result is pixel-stage IR for an independent invocation,
/// with original vertex inputs and constant-register bindings. Target0 keeps selected lanes in their original
/// RGBA positions; other lanes are explicitly placeholder (0,0,0,1). Other original outputs are excluded.
/// Full original source hash, a distinct lifter identity and a derivation note keep this separate from the VS.
/// Its original declarations remain in the interface; `used` and graph dependencies describe actual reads.