1use super::*;
2
3fn inc(ib: &mut u32) -> u32 {
4 *ib += 1;
5 *ib - 1
6}
7
8mod image_cube_direction_to_arrayed;
9use image_cube_direction_to_arrayed::*;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12enum ImageOperation<T> {
13 Fetch(T),
14 Read(T),
15 Write(T),
16}
17
18impl<T> ImageOperation<T>
19where
20 T: Clone + Copy,
21{
22 fn get(&self) -> T {
23 match self {
24 ImageOperation::Fetch(v) | ImageOperation::Read(v) | ImageOperation::Write(v) => *v,
25 }
26 }
27
28 fn image_offset(&self) -> usize {
29 match self {
30 ImageOperation::Fetch(_) => 3,
31 ImageOperation::Read(_) => 3,
32 ImageOperation::Write(_) => 1,
33 }
34 }
35
36 fn coordinate_offset(&self) -> usize {
37 match self {
38 ImageOperation::Fetch(_) => 4,
39 ImageOperation::Read(_) => 4,
40 ImageOperation::Write(_) => 2,
41 }
42 }
43}
44
45pub fn storagecubepatch(
48 in_spv: &[u32],
49 corrections: &mut CorrectionMap,
50) -> Result<Vec<u32>, ()> {
51 let spv = in_spv.to_owned();
52
53 let mut instruction_bound = spv[SPV_HEADER_INSTRUCTION_BOUND_OFFSET];
54 let magic_number = spv[SPV_HEADER_MAGIC_NUM_OFFSET];
55
56 let spv_header = spv[0..SPV_HEADER_LENGTH].to_owned();
57
58 assert_eq!(magic_number, SPV_HEADER_MAGIC);
59
60 let mut instruction_inserts = vec![];
61 let word_inserts = vec![];
62
63 let spv = spv.into_iter().skip(SPV_HEADER_LENGTH).collect::<Vec<_>>();
64 let mut new_spv = spv.clone();
65
66 let mut op_type_image_idxs = vec![];
68 let mut op_type_pointer_idxs = vec![];
69 let mut op_variable_idxs = vec![];
70 let mut op_load_idxs = vec![];
71 let mut op_type_int_idxs = vec![];
72 let mut op_type_bool_idxs = vec![];
73 let mut op_type_vector_idxs = vec![];
74 let mut op_ext_inst_import_idxs = vec![];
75 let mut op_function_parameter_idxs = vec![];
76 let mut op_function_call_idxs = vec![];
77 let mut op_decorate_idxs = vec![];
78
79 let mut image_operation_idxs = vec![];
80
81 let mut spv_idx = 0;
82 while spv_idx < spv.len() {
83 let op = spv[spv_idx];
84 let word_count = hiword(op);
85 let instruction = loword(op);
86
87 match instruction {
88 SPV_INSTRUCTION_OP_TYPE_IMAGE => op_type_image_idxs.push(spv_idx),
89 SPV_INSTRUCTION_OP_TYPE_POINTER => op_type_pointer_idxs.push(spv_idx),
90 SPV_INSTRUCTION_OP_VARIABLE => op_variable_idxs.push(spv_idx),
91 SPV_INSTRUCTION_OP_LOAD => op_load_idxs.push(spv_idx),
92 SPV_INSTRUCTION_OP_TYPE_INT => op_type_int_idxs.push(spv_idx),
93 SPV_INSTRUCTION_OP_TYPE_BOOL => op_type_bool_idxs.push(spv_idx),
94 SPV_INSTRUCTION_OP_TYPE_VECTOR => op_type_vector_idxs.push(spv_idx),
95 SPV_INSTRUCTION_OP_EXT_INST_IMPORT => op_ext_inst_import_idxs.push(spv_idx),
96 SPV_INSTRUCTION_OP_FUNCTION_PARAMETER => op_function_parameter_idxs.push(spv_idx),
97 SPV_INSTRUCTION_OP_FUNCTION_CALL => op_function_call_idxs.push(spv_idx),
98 SPV_INSTRUCTION_OP_DECORATE => op_decorate_idxs.push(spv_idx),
99 SPV_INSTRUCTION_OP_IMAGE_FETCH => {
100 image_operation_idxs.push(ImageOperation::Fetch(spv_idx))
101 }
102 SPV_INSTRUCTION_OP_IMAGE_READ => {
103 image_operation_idxs.push(ImageOperation::Read(spv_idx))
104 }
105 SPV_INSTRUCTION_OP_IMAGE_WRITE => {
106 image_operation_idxs.push(ImageOperation::Write(spv_idx))
107 }
108 _ => {}
109 }
110
111 spv_idx += word_count as usize;
112 }
113
114 if op_type_vector_idxs.is_empty()
115 || op_type_image_idxs.is_empty()
116 || image_operation_idxs.is_empty()
117 {
118 return Ok(in_spv.to_vec());
119 }
120
121 let header_position = last_of_indices!(
122 op_type_int_idxs,
123 op_type_bool_idxs,
124 op_type_vector_idxs,
125 op_type_pointer_idxs
126 );
127
128 let mut header_insert = InstructionInsert {
130 previous_spv_idx: header_position.unwrap(),
131 instruction: vec![],
132 };
133
134 let bool_id = ensure_type_bool(
135 &spv,
136 &op_type_bool_idxs,
137 &mut instruction_bound,
138 &mut header_insert.instruction,
139 );
140 let bool_ptr_id = ensure_type_pointer(
141 &spv,
142 &op_type_pointer_idxs,
143 &mut instruction_bound,
144 &mut header_insert.instruction,
145 SPV_STORAGE_CLASS_FUNCTION,
146 bool_id,
147 );
148 let int32_id = ensure_type_int(
149 &spv,
150 &op_type_int_idxs,
151 &mut instruction_bound,
152 &mut header_insert.instruction,
153 32,
154 SPV_SIGNEDNESS_SIGNED,
155 );
156 let int32_ptr_id = ensure_type_pointer(
157 &spv,
158 &op_type_pointer_idxs,
159 &mut instruction_bound,
160 &mut header_insert.instruction,
161 SPV_STORAGE_CLASS_FUNCTION,
162 int32_id,
163 );
164 let v3int32_id = ensure_type_vector(
165 &spv,
166 &op_type_vector_idxs,
167 &mut instruction_bound,
168 &mut header_insert.instruction,
169 int32_id,
170 3,
171 );
172 let v3int32_ptr_id = ensure_type_pointer(
173 &spv,
174 &op_type_pointer_idxs,
175 &mut instruction_bound,
176 &mut header_insert.instruction,
177 SPV_STORAGE_CLASS_FUNCTION,
178 v3int32_id,
179 );
180 let v2int32_id = ensure_type_vector(
181 &spv,
182 &op_type_vector_idxs,
183 &mut instruction_bound,
184 &mut header_insert.instruction,
185 int32_id,
186 2,
187 );
188 let v2int32_ptr_id = ensure_type_pointer(
189 &spv,
190 &op_type_pointer_idxs,
191 &mut instruction_bound,
192 &mut header_insert.instruction,
193 SPV_STORAGE_CLASS_FUNCTION,
194 v2int32_id,
195 );
196 let glsl_std_id = ensure_ext_inst_import(
197 &spv,
198 &op_ext_inst_import_idxs,
199 &mut instruction_bound,
200 &mut header_insert.instruction,
201 |s| s.starts_with("GLSL.std."),
202 "GLSL.std.450",
203 );
204
205 let type_inputs = CubeDirectionTypeInputs {
207 int_id: int32_id,
208 v3int_id: v3int32_id,
209 v2int_id: v2int32_id,
210 bool_id,
211 ptr_v3int_id: v3int32_ptr_id,
212 ptr_int_id: int32_ptr_id,
213 ptr_bool_id: bool_ptr_id,
214 ptr_v2int_id: v2int32_ptr_id,
215 };
216 let (function_type_id, mut function_type_spv) =
217 image_cube_direction_to_arrayed_fn_type(&mut instruction_bound, type_inputs);
218 header_insert.instruction.append(&mut function_type_spv);
219
220 let (shared_constants, mut constants_spv) =
222 image_cube_direction_to_arrayed_constants_spv(&mut instruction_bound, int32_id);
223 header_insert.instruction.append(&mut constants_spv);
224
225 let (function_id, function_spv) = image_cube_direction_to_arrayed_spv(
227 &mut instruction_bound,
228 type_inputs,
229 function_type_id,
230 shared_constants,
231 glsl_std_id,
232 );
233 let mut function_definition_words = function_spv;
234
235 let type_image_ids = op_type_image_idxs
237 .iter()
238 .filter_map(|idx| {
239 let result_id = spv[idx + 1];
240 let dim = spv[idx + 3];
241 let arrayed = spv[idx + 5];
242 let sampled = spv[idx + 7];
244
245 if dim == SPV_DIMENSION_CUBE && arrayed == 1 && sampled == 2 {
246 panic!("imageCubeArray is not supported");
247 }
248
249 if dim == SPV_DIMENSION_CUBE && sampled == 2 {
251 new_spv[idx + 3] = SPV_DIMENSION_2D;
252 new_spv[idx + 5] = 1;
253 Some(result_id)
254 } else {
255 None
256 }
257 })
258 .collect::<Vec<_>>();
259
260 let type_pointer_ids = op_type_pointer_idxs
262 .iter()
263 .filter_map(|idx| {
264 let result_id = spv[idx + 1];
265 let underlying_type_id = spv[idx + 3];
266
267 type_image_ids
268 .contains(&underlying_type_id)
269 .then_some(result_id)
270 })
271 .collect::<Vec<_>>();
272 let loadable_ids = op_variable_idxs
273 .iter()
274 .chain(op_function_parameter_idxs.iter())
276 .filter_map(|idx| {
277 let result_id = spv[idx + 2];
278 let result_type_id = spv[idx + 1];
279 type_pointer_ids
280 .contains(&result_type_id)
281 .then_some(result_id)
282 })
283 .collect::<Vec<_>>();
284 let loaded_ids = op_load_idxs
285 .iter()
286 .filter_map(|idx| {
287 let result_id = spv[idx + 2];
288 let pointer_id = spv[idx + 3];
289
290 loadable_ids.contains(&pointer_id).then_some(result_id)
291 })
292 .collect::<Vec<_>>();
293
294 for operation_with_idx in image_operation_idxs.iter() {
296 let op_idx = operation_with_idx.get();
297 let op_word_count = hiword(spv[op_idx]) as usize;
298 let image_id = spv[op_idx + operation_with_idx.image_offset()];
299 let coord_id = spv[op_idx + operation_with_idx.coordinate_offset()];
300
301 if loaded_ids.contains(&image_id) {
302 let temp_id = inc(&mut instruction_bound);
305 instruction_inserts.push(InstructionInsert {
306 previous_spv_idx: get_function_label_index_of_instruction_index(&spv, op_idx),
307 instruction: vec![
308 encode_word(4, SPV_INSTRUCTION_OP_VARIABLE),
309 type_inputs.ptr_v3int_id,
310 temp_id,
311 SPV_STORAGE_CLASS_FUNCTION,
312 ],
313 });
314 let output_id = inc(&mut instruction_bound);
316 let mut new_instructions = vec![
317 encode_word(3, SPV_INSTRUCTION_OP_STORE),
318 temp_id,
319 coord_id,
320 encode_word(5, SPV_INSTRUCTION_OP_FUNCTION_CALL),
321 type_inputs.v3int_id,
322 output_id,
323 function_id,
324 temp_id,
325 ];
326 let cl = new_instructions.len();
327 new_instructions.extend_from_slice(&spv[op_idx..op_idx + op_word_count]);
328 new_instructions[cl + operation_with_idx.coordinate_offset()] = output_id;
329 instruction_inserts.push(InstructionInsert {
330 previous_spv_idx: op_idx,
331 instruction: new_instructions,
332 });
333
334 new_spv[op_idx..op_idx + op_word_count].fill(encode_word(1, SPV_INSTRUCTION_OP_NOP));
335 }
336 }
337
338 decorate(DecorateIn {
340 spv: &spv,
341 instruction_inserts: &mut vec![],
342 first_op_deocrate_idx: op_decorate_idxs.first().copied(),
343 op_decorate_idxs: &op_decorate_idxs,
344 affected_decorations: &loadable_ids
345 .iter()
346 .map(|id| AffectedDecoration {
347 original_res_id: *id,
348 new_res_ids: vec![*id],
349 correction_type: CorrectionType::ConvertStorageCube,
350 })
351 .collect::<Vec<_>>(),
352 corrections,
353 });
354
355 instruction_inserts.insert(0, header_insert);
357 insert_new_instructions(&spv, &mut new_spv, &word_inserts, &instruction_inserts);
358 new_spv.append(&mut function_definition_words);
359
360 prune_noops(&mut new_spv);
362
363 Ok(fuse_final(spv_header, new_spv, instruction_bound))
365}