dxbc_reader/controls.rs
1//! Typed views of the control bits of an opcode token: the bits 11 to 23 that [`Instruction::control`] and
2//! [`Declaration::control`] keep as stored, read as the fields the token format gives them for the opcodes that use them.
3//! Only the bits some program of the games read carries are named: the `precise` mask of an arithmetic instruction, the
4//! flags of a `sync`, the return type of `resinfo` and `sample_info`, the flags of `dcl_globalFlags`, and the values the
5//! geometry and tessellation declarations hold in their control bits or in the word after the token.
6use crate::decode::{Declaration, Declared, Instruction};
7
8/// The low byte of `v`.
9fn low8(v: u32) -> u8 {
10 let [byte, ..] = v.to_le_bytes();
11 byte
12}
13
14/// What a `sync` instruction waits for (control bits 0 to 3; the listing of Microsoft's disassembler adds a suffix for
15/// each: `_t`, `_g`, `_ugroup`, `_uglobal`).
16#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
17pub struct SyncFlags {
18 /// Bit 0: every thread of the group reaches the instruction first (`_t`).
19 pub threads_in_group: bool,
20 /// Bit 1: group shared memory accesses are complete (`_g`).
21 pub group_shared_memory: bool,
22 /// Bit 2: unordered-access view accesses are complete within the group (`_ugroup`).
23 pub uav_group: bool,
24 /// Bit 3: unordered-access view accesses are complete across all groups (`_uglobal`).
25 pub uav_global: bool,
26}
27
28/// The type a `resinfo` or `sample_info` instruction returns (the `_uint` and `_rcpfloat` suffixes of Microsoft's
29/// listing; none suffix is a float).
30#[derive(Clone, Copy, Debug, PartialEq, Eq)]
31pub enum InfoReturn {
32 /// A float.
33 Float,
34 /// The reciprocal of a float (`resinfo_rcpfloat`; the games' programs do not use it).
35 ReciprocalFloat,
36 /// An unsigned integer (`_uint`).
37 Uint,
38}
39
40/// The flags of a `dcl_globalFlags` declaration (its control bits). The names are the ones Microsoft's disassembler
41/// prints; the games' programs set bits 0 to 5.
42#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
43pub struct GlobalFlags {
44 /// Bit 0, `refactoringAllowed`.
45 pub refactoring_allowed: bool,
46 /// Bit 1, `enableDoublePrecisionFloatOps`.
47 pub double_precision: bool,
48 /// Bit 2, `forceEarlyDepthStencil`.
49 pub force_early_depth_stencil: bool,
50 /// Bit 3, `enableRawAndStructuredBuffers`.
51 pub raw_and_structured_buffers: bool,
52 /// Bit 4, `skipOptimization`.
53 pub skip_optimization: bool,
54 /// Bit 5, `enableMinimumPrecision`.
55 pub minimum_precision: bool,
56 /// The bits above bit 5, as stored (shifted down by six): bit 6 `enable11_1DoubleExtensions`, bit 7
57 /// `enable11_1ShaderExtensions`, bit 8 `allResourcesBound` (a Shader Model 5.1 program built with
58 /// `/all_resources_bound`); bits 9 to 12 have no name.
59 pub other: u32,
60}
61
62impl GlobalFlags {
63 /// The flags of the control bits `control` of a `dcl_globalFlags` declaration.
64 pub fn from_bits(control: u32) -> Self {
65 let bit = |n: u32| (control >> n) & 1 != 0;
66 GlobalFlags {
67 refactoring_allowed: bit(0),
68 double_precision: bit(1),
69 force_early_depth_stencil: bit(2),
70 raw_and_structured_buffers: bit(3),
71 skip_optimization: bit(4),
72 minimum_precision: bit(5),
73 other: control >> 6,
74 }
75 }
76}
77
78const RESINFO: u16 = 61;
79const SAMPLE_INFO: u16 = 111;
80const SYNC: u16 = 190;
81const GS_OUTPUT_TOPOLOGY: u16 = 92;
82const GS_INPUT_PRIMITIVE: u16 = 93;
83const GS_MAX_OUTPUT_VERTICES: u16 = 94;
84const INPUT_CONTROL_POINTS: u16 = 147;
85const OUTPUT_CONTROL_POINTS: u16 = 148;
86const TESS_DOMAIN: u16 = 149;
87const TESS_PARTITIONING: u16 = 150;
88const TESS_OUTPUT_PRIMITIVE: u16 = 151;
89const HS_MAX_TESS_FACTOR: u16 = 152;
90const HS_FORK_INSTANCES: u16 = 153;
91const HS_JOIN_INSTANCES: u16 = 154;
92
93impl Instruction {
94 /// The components the instruction is marked `precise` for (control bits 8 to 11, the token's bits 19 to 22): bit 0 x
95 /// to bit 3 w, zero where it is not marked. The compiler marks every instruction of a `precise` expression.
96 pub fn precise_mask(&self) -> u8 {
97 low8((self.control >> 8) & 15)
98 }
99
100 /// What a `sync` instruction waits for; `None` for any other instruction.
101 pub fn sync_flags(&self) -> Option<SyncFlags> {
102 (self.opcode == SYNC).then(|| {
103 let bit = |n: u32| (self.control >> n) & 1 != 0;
104 SyncFlags {
105 threads_in_group: bit(0),
106 group_shared_memory: bit(1),
107 uav_group: bit(2),
108 uav_global: bit(3),
109 }
110 })
111 }
112
113 /// The type a `resinfo` or `sample_info` returns; `None` for any other instruction, and for a return type the
114 /// token format does not define.
115 pub fn info_return(&self) -> Option<InfoReturn> {
116 match (self.opcode, self.control & 3) {
117 (RESINFO | SAMPLE_INFO, 0) => Some(InfoReturn::Float),
118 (RESINFO, 1) => Some(InfoReturn::ReciprocalFloat),
119 (RESINFO, 2) | (SAMPLE_INFO, 1) => Some(InfoReturn::Uint),
120 _ => None,
121 }
122 }
123}
124
125impl Declaration {
126 /// The flags of a `dcl_globalFlags` declaration; `None` for any other declaration.
127 pub fn global_flags(&self) -> Option<GlobalFlags> {
128 match self.kind {
129 Declared::GlobalFlags(bits) => Some(GlobalFlags::from_bits(bits)),
130 _ => None,
131 }
132 }
133
134 /// The value in the first word after the token of a declaration this reader does not type (the word of
135 /// `dcl_maxout`, `dcl_hs_max_tessfactor` and the phase instance counts).
136 fn first_word(&self, opcode: u16) -> Option<u32> {
137 match &self.kind {
138 Declared::Other { words, .. } if self.opcode == opcode => words.first().copied(),
139 _ => None,
140 }
141 }
142
143 /// The control value of the declaration `opcode`, `mask`ed.
144 fn control_value(&self, opcode: u16, mask: u32) -> Option<u32> {
145 (self.opcode == opcode).then_some(self.control & mask)
146 }
147
148 /// A geometry program's input primitive (`dcl_inputprimitive`; a `D3D_PRIMITIVE`: 1 point, 2 line, 3 triangle, 6 line
149 /// and 7 triangle with adjacency).
150 pub fn geometry_input_primitive(&self) -> Option<u32> {
151 self.control_value(GS_INPUT_PRIMITIVE, 63)
152 }
153
154 /// A geometry program's output topology (`dcl_outputtopology`; a `D3D_PRIMITIVE_TOPOLOGY`: 1 point list, 3 line strip,
155 /// 5 triangle strip).
156 pub fn geometry_output_topology(&self) -> Option<u32> {
157 self.control_value(GS_OUTPUT_TOPOLOGY, 63)
158 }
159
160 /// A geometry program's largest vertex count (`dcl_maxout`).
161 pub fn max_output_vertex_count(&self) -> Option<u32> {
162 self.first_word(GS_MAX_OUTPUT_VERTICES)
163 }
164
165 /// A hull or domain program's input control point count (`dcl_input_control_point_count`).
166 pub fn input_control_point_count(&self) -> Option<u32> {
167 self.control_value(INPUT_CONTROL_POINTS, 63)
168 }
169
170 /// A hull program's output control point count (`dcl_output_control_point_count`).
171 pub fn output_control_point_count(&self) -> Option<u32> {
172 self.control_value(OUTPUT_CONTROL_POINTS, 63)
173 }
174
175 /// The tessellator domain (`dcl_tessellator_domain`; a `D3D11_TESSELLATOR_DOMAIN`: 1 isoline, 2 triangle, 3 quad):
176 /// control bits 0 to 1, as `D3D11_SB_TESS_DOMAIN_MASK` and Microsoft's listing read it.
177 pub fn tessellator_domain(&self) -> Option<u32> {
178 self.control_value(TESS_DOMAIN, 3)
179 }
180
181 /// The tessellator partitioning (`dcl_tessellator_partitioning`; a `D3D11_TESSELLATOR_PARTITIONING`: 1 integer, 2 pow2,
182 /// 3 fractional odd, 4 fractional even).
183 pub fn tessellator_partitioning(&self) -> Option<u32> {
184 self.control_value(TESS_PARTITIONING, 7)
185 }
186
187 /// The tessellator output primitive (`dcl_tessellator_output_primitive`; a `D3D11_TESSELLATOR_OUTPUT_PRIMITIVE`: 1
188 /// point, 2 line, 3 triangle clockwise, 4 triangle counter-clockwise).
189 pub fn tessellator_output_primitive(&self) -> Option<u32> {
190 self.control_value(TESS_OUTPUT_PRIMITIVE, 7)
191 }
192
193 /// A hull program's largest tessellation factor (`dcl_hs_max_tessfactor`).
194 pub fn hull_max_tess_factor(&self) -> Option<f32> {
195 self.first_word(HS_MAX_TESS_FACTOR).map(f32::from_bits)
196 }
197
198 /// The instance count of a hull program's fork phase (`dcl_hs_fork_phase_instance_count`).
199 pub fn fork_phase_instance_count(&self) -> Option<u32> {
200 self.first_word(HS_FORK_INSTANCES)
201 }
202
203 /// The instance count of a hull program's join phase (`dcl_hs_join_phase_instance_count`).
204 pub fn join_phase_instance_count(&self) -> Option<u32> {
205 self.first_word(HS_JOIN_INSTANCES)
206 }
207}