1use super::*;
2
3type LeftRightOutput = (Option<Vec<u32>>, Option<Vec<u32>>);
4
5pub fn mirrorpatch(
11 left_spv: &[u32],
12 left_corrections: &mut CorrectionMap,
13 right_spv: &[u32],
14 right_corrections: &mut CorrectionMap,
15) -> Result<LeftRightOutput, ()> {
16 if left_corrections.sets.is_none() && right_corrections.sets.is_none() {
17 return Ok((None, None));
18 }
19
20 let mut left_affected_decorations = vec![];
21 let mut right_affected_decorations = vec![];
22
23 let mut left_instruction_bound = left_spv[SPV_HEADER_INSTRUCTION_BOUND_OFFSET];
24 let mut right_instruction_bound = right_spv[SPV_HEADER_INSTRUCTION_BOUND_OFFSET];
25
26 let left_corrections_map = left_corrections.sets.as_ref().cloned().unwrap_or_default();
27 let right_corrections_map = right_corrections.sets.as_ref().cloned().unwrap_or_default();
28
29 let mut scan_set_idxs = left_corrections_map
30 .keys()
31 .chain(right_corrections_map.keys())
32 .copied()
33 .collect::<Vec<_>>();
34
35 scan_set_idxs.dedup();
36
37 for set_idx in scan_set_idxs {
38 let left_bindings = left_corrections_map
39 .get(&set_idx)
40 .cloned()
41 .map(|v| v.bindings)
42 .unwrap_or_default();
43 let right_bindings = right_corrections_map
44 .get(&set_idx)
45 .cloned()
46 .map(|v| v.bindings)
47 .unwrap_or_default();
48
49 for (left_binding_idx, l) in left_bindings.iter() {
50 let r = right_bindings
51 .get(left_binding_idx)
52 .cloned()
53 .unwrap_or_default();
54
55 push_affected_decorations(
56 &mut right_affected_decorations,
57 &mut right_instruction_bound,
58 set_idx,
59 *left_binding_idx,
60 l,
61 &r,
62 );
63 }
64
65 for (right_binding_idx, r) in right_bindings.iter() {
66 let l = left_bindings
67 .get(right_binding_idx)
68 .cloned()
69 .unwrap_or_default();
70
71 push_affected_decorations(
72 &mut left_affected_decorations,
73 &mut left_instruction_bound,
74 set_idx,
75 *right_binding_idx,
76 r,
77 &l,
78 );
79 }
80 }
81
82 let l = (!left_affected_decorations.is_empty())
83 .then(|| {
84 patch_spv_decorations(
85 left_spv,
86 left_corrections,
87 left_instruction_bound,
88 &left_affected_decorations,
89 )
90 })
91 .transpose()?;
92 let r = (!right_affected_decorations.is_empty())
93 .then(|| {
94 patch_spv_decorations(
95 right_spv,
96 right_corrections,
97 right_instruction_bound,
98 &right_affected_decorations,
99 )
100 })
101 .transpose()?;
102 Ok((l, r))
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106struct NewVariable {
107 set: u32,
108 binding: u32,
109 new_res_id: u32,
110 correction_type: CorrectionType,
111}
112
113fn patch_spv_decorations(
114 in_spv: &[u32],
115 corrections: &mut CorrectionMap,
116 new_instruction_bound: u32,
117 affected_decorations: &[NewVariable],
118) -> Result<Vec<u32>, ()> {
119 let spv = in_spv.to_owned();
120
121 let instruction_bound = new_instruction_bound;
122 let magic_number = spv[SPV_HEADER_MAGIC_NUM_OFFSET];
123 let spv_header = spv[0..SPV_HEADER_LENGTH].to_owned();
124
125 assert_eq!(magic_number, SPV_HEADER_MAGIC);
126
127 let mut instruction_inserts: Vec<InstructionInsert> = vec![];
128
129 let spv = spv.into_iter().skip(SPV_HEADER_LENGTH).collect::<Vec<_>>();
130 let mut new_spv = spv.clone();
131
132 let mut op_decorate_idxs = vec![];
134 let mut op_variable_idxs = vec![];
135 let mut spv_idx = 0;
136 while spv_idx < spv.len() {
137 let op = spv[spv_idx];
138 let word_count = hiword(op);
139 let instruction = loword(op);
140
141 if instruction == SPV_INSTRUCTION_OP_DECORATE {
142 op_decorate_idxs.push(spv_idx)
143 }
144 if instruction == SPV_INSTRUCTION_OP_VARIABLE {
145 op_variable_idxs.push(spv_idx)
146 }
147
148 spv_idx += word_count as usize;
149 }
150 let first_op_deocrate_idx = op_decorate_idxs.first().copied();
151
152 let mut cached_original_variable_idxs = HashMap::new();
154 let affected_decorations = affected_decorations
155 .iter()
156 .map(|affected| {
157 let NewVariable {
159 set,
160 binding,
161 new_res_id,
162 correction_type,
163 } = *affected;
164 let original_variable_idx =
165 *if let Some(idx) = cached_original_variable_idxs.get(&(set, binding)) {
166 idx
167 } else {
168 let Some(original_variable_id) = op_decorate_idxs.iter().find_map(|&d_idx| {
169 let target_id = spv[d_idx + 1];
170 let decoration_id = spv[d_idx + 2];
171 let decoration_value = spv[d_idx + 3];
172 (decoration_id == SPV_DECORATION_DESCRIPTOR_SET
173 && decoration_value == set
174 && op_decorate_idxs.iter().any(|&idx| {
175 let binding_target_id = spv[idx + 1];
176 let decoration_id = spv[idx + 2];
177 let decoration_value = spv[idx + 3];
178 decoration_id == SPV_DECORATION_BINDING
179 && decoration_value == binding
180 && target_id == binding_target_id
181 }))
182 .then_some(target_id)
183 }) else {
184 return Err(in_spv.to_vec());
186 };
187 let idx = op_variable_idxs
188 .iter()
189 .find(|&idx| spv[idx + 2] == original_variable_id)
190 .unwrap();
191 cached_original_variable_idxs.insert((set, binding), idx);
192 idx
193 };
194
195 let original_variable_id = spv[original_variable_idx + 2];
197 let mut new_variable = Vec::new();
198 let word_count = hiword(spv[original_variable_idx]);
199 new_variable.extend_from_slice(
200 &spv[original_variable_idx..original_variable_idx + word_count as usize],
201 );
202 new_variable[2] = new_res_id;
203 instruction_inserts.push(InstructionInsert {
204 previous_spv_idx: original_variable_idx,
205 instruction: new_variable,
206 });
207
208 Ok(AffectedDecoration {
210 original_res_id: original_variable_id,
211 new_res_ids: vec![new_res_id],
212 correction_type,
213 })
214 })
215 .collect::<Result<Vec<_>, _>>();
216
217 let affected_decorations = match affected_decorations {
218 Ok(d) => d,
219 Err(spv) => return Ok(spv),
220 };
221
222 let DecorateOut {
224 descriptor_sets_to_correct,
225 } = util::decorate(DecorateIn {
226 spv: &spv,
227 instruction_inserts: &mut instruction_inserts,
228 first_op_deocrate_idx,
229 op_decorate_idxs: &op_decorate_idxs,
230 affected_decorations: &affected_decorations,
231 corrections,
232 });
233
234 insert_new_instructions(&spv, &mut new_spv, &[], &instruction_inserts);
236
237 util::correct_decorate(CorrectDecorateIn {
239 new_spv: &mut new_spv,
240 descriptor_sets_to_correct,
241 });
242
243 prune_noops(&mut new_spv);
245
246 Ok(fuse_final(spv_header, new_spv, instruction_bound))
248}
249
250fn push_affected_decorations(
251 new_variables: &mut Vec<NewVariable>,
252 instruction_bound: &mut u32,
253 set: u32,
254 binding: u32,
255 l: &CorrectionBinding,
256 r: &CorrectionBinding,
257) {
258 let mut ll = l
259 .corrections
260 .iter()
261 .map(Some)
262 .enumerate()
263 .collect::<Vec<_>>();
264
265 for r_correction in r.corrections.iter() {
266 let idx_ty = ll
267 .iter()
268 .find(|(_, correction)| Some(r_correction) == correction.as_ref().copied())
269 .copied();
270 if let Some((idx, _)) = idx_ty {
271 ll[idx].1 = None;
272 }
273 }
274
275 let mut offset = 0;
276 for (_, op) in ll {
277 if let Some(correction) = op {
278 *instruction_bound += 1;
279 let new_res_id = *instruction_bound - 1;
280 new_variables.push(NewVariable {
281 set,
282 binding: binding + offset,
283 new_res_id,
284 correction_type: *correction,
285 });
286 } else {
287 offset += 1;
288 }
289 }
290}
291
292#[test]
293fn test_push_affected_decorations() {
294 let l = CorrectionBinding {
295 corrections: vec![
296 CorrectionType::SplitCombined,
297 CorrectionType::SplitDrefRegular,
298 CorrectionType::SplitDrefRegular,
299 CorrectionType::SplitCombined,
300 CorrectionType::SplitDrefComparison,
301 ],
302 };
303
304 let r = CorrectionBinding {
305 corrections: vec![
306 CorrectionType::SplitDrefRegular,
307 CorrectionType::SplitDrefComparison,
308 ],
309 };
310
311 let mut affected = vec![];
312 push_affected_decorations(&mut affected, &mut 0, 0, 0, &l, &r);
313 assert_eq!(
314 affected,
315 vec![
316 NewVariable {
317 set: 0,
318 binding: 0,
319 new_res_id: 0,
320 correction_type: CorrectionType::SplitCombined,
321 },
322 NewVariable {
323 set: 0,
324 binding: 1,
325 new_res_id: 1,
326 correction_type: CorrectionType::SplitDrefRegular,
327 },
328 NewVariable {
329 set: 0,
330 binding: 1,
331 new_res_id: 2,
332 correction_type: CorrectionType::SplitCombined,
333 },
334 ]
335 );
336
337 let mut affected = vec![];
338 push_affected_decorations(&mut affected, &mut 0, 0, 0, &r, &l);
339 assert_eq!(affected, vec![]);
340}