1use alloc::vec::Vec;
2
3use crate::{
4 arena::{Handle, UniqueArena},
5 Scalar,
6};
7
8use super::{Error, LookupExpression, LookupHelper as _};
9
10#[derive(Clone, Debug)]
11pub(super) struct LookupSampledImage {
12 image: Handle<crate::Expression>,
13 sampler: Handle<crate::Expression>,
14}
15
16bitflags::bitflags! {
17 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
19 pub struct SamplingFlags: u32 {
20 const REGULAR = 0x1;
22 const COMPARISON = 0x2;
24 }
25}
26
27impl super::BlockContext<'_> {
28 fn get_image_expr_ty(
29 &self,
30 handle: Handle<crate::Expression>,
31 ) -> Result<Handle<crate::Type>, Error> {
32 match self.expressions[handle] {
33 crate::Expression::GlobalVariable(handle) => {
34 Ok(self.module.global_variables[handle].ty)
35 }
36 crate::Expression::FunctionArgument(i) => Ok(self.arguments[i as usize].ty),
37 crate::Expression::Access { base, .. } => Ok(self.get_image_expr_ty(base)?),
38 ref other => Err(Error::InvalidImageExpression(other.clone())),
39 }
40 }
41}
42
43#[derive(Debug)]
45pub struct SamplingOptions {
46 pub project: bool,
49 pub compare: bool,
51}
52
53enum ExtraCoordinate {
54 ArrayLayer,
55 Projection,
56 Garbage,
57}
58
59fn extract_image_coordinates(
65 image_dim: crate::ImageDimension,
66 extra_coordinate: ExtraCoordinate,
67 base: Handle<crate::Expression>,
68 coordinate_ty: Handle<crate::Type>,
69 ctx: &mut super::BlockContext,
70) -> (Handle<crate::Expression>, Option<Handle<crate::Expression>>) {
71 let (given_size, kind) = match ctx.module.types[coordinate_ty].inner {
72 crate::TypeInner::Scalar(Scalar { kind, .. }) => (None, kind),
73 crate::TypeInner::Vector {
74 size,
75 scalar: Scalar { kind, .. },
76 } => (Some(size), kind),
77 ref other => unreachable!("Unexpected texture coordinate {:?}", other),
78 };
79
80 let required_size = image_dim.required_coordinate_size();
81 let required_ty = required_size.map(|size| {
82 ctx.module
83 .types
84 .get(&crate::Type {
85 name: None,
86 inner: crate::TypeInner::Vector {
87 size,
88 scalar: Scalar { kind, width: 4 },
89 },
90 })
91 .expect("Required coordinate type should have been set up by `parse_type_image`!")
92 });
93 let extra_expr = crate::Expression::AccessIndex {
94 base,
95 index: required_size.map_or(1, |size| size as u32),
96 };
97
98 let base_span = ctx.expressions.get_span(base);
99
100 match extra_coordinate {
101 ExtraCoordinate::ArrayLayer => {
102 let extracted = match required_size {
103 None => ctx
104 .expressions
105 .append(crate::Expression::AccessIndex { base, index: 0 }, base_span),
106 Some(size) => {
107 let mut components = Vec::with_capacity(size as usize);
108 for index in 0..size as u32 {
109 let comp = ctx
110 .expressions
111 .append(crate::Expression::AccessIndex { base, index }, base_span);
112 components.push(comp);
113 }
114 ctx.expressions.append(
115 crate::Expression::Compose {
116 ty: required_ty.unwrap(),
117 components,
118 },
119 base_span,
120 )
121 }
122 };
123 let array_index_f32 = ctx.expressions.append(extra_expr, base_span);
124 let array_index = ctx.expressions.append(
125 crate::Expression::As {
126 kind: crate::ScalarKind::Sint,
127 expr: array_index_f32,
128 convert: Some(4),
129 },
130 base_span,
131 );
132 (extracted, Some(array_index))
133 }
134 ExtraCoordinate::Projection => {
135 let projection = ctx.expressions.append(extra_expr, base_span);
136 let divided = match required_size {
137 None => {
138 let temp = ctx
139 .expressions
140 .append(crate::Expression::AccessIndex { base, index: 0 }, base_span);
141 ctx.expressions.append(
142 crate::Expression::Binary {
143 op: crate::BinaryOperator::Divide,
144 left: temp,
145 right: projection,
146 },
147 base_span,
148 )
149 }
150 Some(size) => {
151 let mut components = Vec::with_capacity(size as usize);
152 for index in 0..size as u32 {
153 let temp = ctx
154 .expressions
155 .append(crate::Expression::AccessIndex { base, index }, base_span);
156 let comp = ctx.expressions.append(
157 crate::Expression::Binary {
158 op: crate::BinaryOperator::Divide,
159 left: temp,
160 right: projection,
161 },
162 base_span,
163 );
164 components.push(comp);
165 }
166 ctx.expressions.append(
167 crate::Expression::Compose {
168 ty: required_ty.unwrap(),
169 components,
170 },
171 base_span,
172 )
173 }
174 };
175 (divided, None)
176 }
177 ExtraCoordinate::Garbage if given_size == required_size => (base, None),
178 ExtraCoordinate::Garbage => {
179 use crate::SwizzleComponent as Sc;
180 let cut_expr = match required_size {
181 None => crate::Expression::AccessIndex { base, index: 0 },
182 Some(size) => crate::Expression::Swizzle {
183 size,
184 vector: base,
185 pattern: [Sc::X, Sc::Y, Sc::Z, Sc::W],
186 },
187 };
188 (ctx.expressions.append(cut_expr, base_span), None)
189 }
190 }
191}
192
193pub(super) fn patch_comparison_type(
194 flags: SamplingFlags,
195 var: &mut crate::GlobalVariable,
196 arena: &mut UniqueArena<crate::Type>,
197) -> bool {
198 if !flags.contains(SamplingFlags::COMPARISON) {
199 return true;
200 }
201 if flags == SamplingFlags::all() {
202 return false;
203 }
204
205 log::debug!("Flipping comparison for {var:?}");
206 let original_ty = &arena[var.ty];
207 let original_ty_span = arena.get_span(var.ty);
208 let ty_inner = match original_ty.inner {
209 crate::TypeInner::Image {
210 class: crate::ImageClass::Sampled { multi, .. },
211 dim,
212 arrayed,
213 } => crate::TypeInner::Image {
214 class: crate::ImageClass::Depth { multi },
215 dim,
216 arrayed,
217 },
218 crate::TypeInner::Sampler { .. } => crate::TypeInner::Sampler { comparison: true },
219 ref other => unreachable!("Unexpected type for comparison mutation: {:?}", other),
220 };
221
222 let name = original_ty.name.clone();
223 var.ty = arena.insert(
224 crate::Type {
225 name,
226 inner: ty_inner,
227 },
228 original_ty_span,
229 );
230 true
231}
232
233impl<I: Iterator<Item = u32>> super::Frontend<I> {
234 pub(super) fn parse_image_couple(&mut self) -> Result<(), Error> {
235 let _result_type_id = self.next()?;
236 let result_id = self.next()?;
237 let image_id = self.next()?;
238 let sampler_id = self.next()?;
239 let image_lexp = self.lookup_expression.lookup(image_id)?;
240 let sampler_lexp = self.lookup_expression.lookup(sampler_id)?;
241 self.lookup_sampled_image.insert(
242 result_id,
243 LookupSampledImage {
244 image: image_lexp.handle,
245 sampler: sampler_lexp.handle,
246 },
247 );
248 Ok(())
249 }
250
251 pub(super) fn parse_image_uncouple(&mut self, block_id: spirv::Word) -> Result<(), Error> {
252 let result_type_id = self.next()?;
253 let result_id = self.next()?;
254 let sampled_image_id = self.next()?;
255 self.lookup_expression.insert(
256 result_id,
257 LookupExpression {
258 handle: self.lookup_sampled_image.lookup(sampled_image_id)?.image,
259 type_id: result_type_id,
260 block_id,
261 },
262 );
263 Ok(())
264 }
265
266 pub(super) fn parse_image_write(
267 &mut self,
268 words_left: u16,
269 ctx: &mut super::BlockContext,
270 emitter: &mut crate::proc::Emitter,
271 block: &mut crate::Block,
272 body_idx: usize,
273 ) -> Result<crate::Statement, Error> {
274 let image_id = self.next()?;
275 let coordinate_id = self.next()?;
276 let value_id = self.next()?;
277
278 let image_ops = if words_left != 0 { self.next()? } else { 0 };
279
280 if image_ops != 0 {
281 let other = spirv::ImageOperands::from_bits_truncate(image_ops);
282 log::warn!("Unknown image write ops {other:?}");
283 for _ in 1..words_left {
284 self.next()?;
285 }
286 }
287
288 let image_lexp = self.lookup_expression.lookup(image_id)?;
289 let image_ty = ctx.get_image_expr_ty(image_lexp.handle)?;
290
291 let coord_lexp = self.lookup_expression.lookup(coordinate_id)?;
292 let coord_handle =
293 self.get_expr_handle(coordinate_id, coord_lexp, ctx, emitter, block, body_idx);
294 let coord_type_handle = self.lookup_type.lookup(coord_lexp.type_id)?.handle;
295 let (coordinate, array_index) = match ctx.module.types[image_ty].inner {
296 crate::TypeInner::Image {
297 dim,
298 arrayed,
299 class: _,
300 } => extract_image_coordinates(
301 dim,
302 if arrayed {
303 ExtraCoordinate::ArrayLayer
304 } else {
305 ExtraCoordinate::Garbage
306 },
307 coord_handle,
308 coord_type_handle,
309 ctx,
310 ),
311 _ => return Err(Error::InvalidImage(image_ty)),
312 };
313
314 let value_lexp = self.lookup_expression.lookup(value_id)?;
315 let value = self.get_expr_handle(value_id, value_lexp, ctx, emitter, block, body_idx);
316 let value_type = self.lookup_type.lookup(value_lexp.type_id)?.handle;
317
318 let expanded_value = match ctx.module.types[value_type].inner {
320 crate::TypeInner::Scalar(_) => Some(crate::Expression::Splat {
321 value,
322 size: crate::VectorSize::Quad,
323 }),
324 crate::TypeInner::Vector { size, .. } => match size {
325 crate::VectorSize::Bi => Some(crate::Expression::Swizzle {
326 size: crate::VectorSize::Quad,
327 vector: value,
328 pattern: [
329 crate::SwizzleComponent::X,
330 crate::SwizzleComponent::Y,
331 crate::SwizzleComponent::Y,
332 crate::SwizzleComponent::Y,
333 ],
334 }),
335 crate::VectorSize::Tri => Some(crate::Expression::Swizzle {
336 size: crate::VectorSize::Quad,
337 vector: value,
338 pattern: [
339 crate::SwizzleComponent::X,
340 crate::SwizzleComponent::Y,
341 crate::SwizzleComponent::Z,
342 crate::SwizzleComponent::Z,
343 ],
344 }),
345 crate::VectorSize::Quad => None,
346 },
347 _ => return Err(Error::InvalidVectorType(value_type)),
348 };
349
350 let value_patched = if let Some(s) = expanded_value {
351 ctx.expressions.append(s, crate::Span::default())
352 } else {
353 value
354 };
355
356 Ok(crate::Statement::ImageStore {
357 image: image_lexp.handle,
358 coordinate,
359 array_index,
360 value: value_patched,
361 })
362 }
363
364 pub(super) fn parse_image_load(
365 &mut self,
366 mut words_left: u16,
367 ctx: &mut super::BlockContext,
368 emitter: &mut crate::proc::Emitter,
369 block: &mut crate::Block,
370 block_id: spirv::Word,
371 body_idx: usize,
372 ) -> Result<(), Error> {
373 let start = self.data_offset;
374 let result_type_id = self.next()?;
375 let result_id = self.next()?;
376 let image_id = self.next()?;
377 let coordinate_id = self.next()?;
378
379 let mut image_ops = if words_left != 0 {
380 words_left -= 1;
381 self.next()?
382 } else {
383 0
384 };
385
386 let mut sample = None;
387 let mut level = None;
388 while image_ops != 0 {
389 let bit = 1 << image_ops.trailing_zeros();
390 match spirv::ImageOperands::from_bits_truncate(bit) {
391 spirv::ImageOperands::LOD => {
392 let lod_expr = self.next()?;
393 let lod_lexp = self.lookup_expression.lookup(lod_expr)?;
394 let lod_handle =
395 self.get_expr_handle(lod_expr, lod_lexp, ctx, emitter, block, body_idx);
396 level = Some(lod_handle);
397 words_left -= 1;
398 }
399 spirv::ImageOperands::SAMPLE => {
400 let sample_expr = self.next()?;
401 let sample_handle = self.lookup_expression.lookup(sample_expr)?.handle;
402 sample = Some(sample_handle);
403 words_left -= 1;
404 }
405 other => {
406 log::warn!("Unknown image load op {other:?}");
407 for _ in 0..words_left {
408 self.next()?;
409 }
410 break;
411 }
412 }
413 image_ops ^= bit;
414 }
415
416 let image_lexp = self.lookup_expression.lookup(image_id)?;
419 let image_ty = ctx.get_image_expr_ty(image_lexp.handle)?;
420
421 let coord_lexp = self.lookup_expression.lookup(coordinate_id)?;
422 let coord_handle =
423 self.get_expr_handle(coordinate_id, coord_lexp, ctx, emitter, block, body_idx);
424 let coord_type_handle = self.lookup_type.lookup(coord_lexp.type_id)?.handle;
425 let (coordinate, array_index, is_depth) = match ctx.module.types[image_ty].inner {
426 crate::TypeInner::Image {
427 dim,
428 arrayed,
429 class,
430 } => {
431 let (coord, array_index) = extract_image_coordinates(
432 dim,
433 if arrayed {
434 ExtraCoordinate::ArrayLayer
435 } else {
436 ExtraCoordinate::Garbage
437 },
438 coord_handle,
439 coord_type_handle,
440 ctx,
441 );
442 (coord, array_index, class.is_depth())
443 }
444 _ => return Err(Error::InvalidImage(image_ty)),
445 };
446
447 let image_load_expr = crate::Expression::ImageLoad {
448 image: image_lexp.handle,
449 coordinate,
450 array_index,
451 sample,
452 level,
453 };
454 let image_load_handle = ctx
455 .expressions
456 .append(image_load_expr, self.span_from_with_op(start));
457
458 let handle = if is_depth {
459 let result_ty = self.lookup_type.lookup(result_type_id)?;
460 match ctx.module.types[result_ty.handle].inner {
462 crate::TypeInner::Vector { size, .. } => {
463 let splat_expr = crate::Expression::Splat {
464 size,
465 value: image_load_handle,
466 };
467 ctx.expressions
468 .append(splat_expr, self.span_from_with_op(start))
469 }
470 _ => image_load_handle,
471 }
472 } else {
473 image_load_handle
474 };
475
476 self.lookup_expression.insert(
477 result_id,
478 LookupExpression {
479 handle,
480 type_id: result_type_id,
481 block_id,
482 },
483 );
484 Ok(())
485 }
486
487 #[allow(clippy::too_many_arguments)]
488 pub(super) fn parse_image_sample(
489 &mut self,
490 mut words_left: u16,
491 options: SamplingOptions,
492 ctx: &mut super::BlockContext,
493 emitter: &mut crate::proc::Emitter,
494 block: &mut crate::Block,
495 block_id: spirv::Word,
496 body_idx: usize,
497 ) -> Result<(), Error> {
498 let start = self.data_offset;
499 let result_type_id = self.next()?;
500 let result_id = self.next()?;
501 let sampled_image_id = self.next()?;
502 let coordinate_id = self.next()?;
503 let dref_id = if options.compare {
504 Some(self.next()?)
505 } else {
506 None
507 };
508 let span = self.span_from_with_op(start);
509
510 let mut image_ops = if words_left != 0 {
511 words_left -= 1;
512 self.next()?
513 } else {
514 0
515 };
516
517 let mut level = crate::SampleLevel::Auto;
518 let mut offset = None;
519 while image_ops != 0 {
520 let bit = 1 << image_ops.trailing_zeros();
521 match spirv::ImageOperands::from_bits_truncate(bit) {
522 spirv::ImageOperands::BIAS => {
523 let bias_expr = self.next()?;
524 let bias_lexp = self.lookup_expression.lookup(bias_expr)?;
525 let bias_handle =
526 self.get_expr_handle(bias_expr, bias_lexp, ctx, emitter, block, body_idx);
527 level = crate::SampleLevel::Bias(bias_handle);
528 words_left -= 1;
529 }
530 spirv::ImageOperands::LOD => {
531 let lod_expr = self.next()?;
532 let lod_lexp = self.lookup_expression.lookup(lod_expr)?;
533 let lod_handle =
534 self.get_expr_handle(lod_expr, lod_lexp, ctx, emitter, block, body_idx);
535
536 let is_depth_image = {
537 let image_lexp = self.lookup_sampled_image.lookup(sampled_image_id)?;
538 let image_ty = ctx.get_image_expr_ty(image_lexp.image)?;
539 matches!(
540 ctx.module.types[image_ty].inner,
541 crate::TypeInner::Image {
542 class: crate::ImageClass::Depth { .. },
543 ..
544 }
545 )
546 };
547
548 level = if options.compare {
549 log::debug!("Assuming {lod_handle:?} is zero");
550 crate::SampleLevel::Zero
551 } else if is_depth_image {
552 log::debug!(
553 "Assuming level {lod_handle:?} converts losslessly to an integer"
554 );
555 let expr = crate::Expression::As {
556 expr: lod_handle,
557 kind: crate::ScalarKind::Sint,
558 convert: Some(4),
559 };
560 let s32_lod_handle = ctx.expressions.append(expr, span);
561 crate::SampleLevel::Exact(s32_lod_handle)
562 } else {
563 crate::SampleLevel::Exact(lod_handle)
564 };
565 words_left -= 1;
566 }
567 spirv::ImageOperands::GRAD => {
568 let grad_x_expr = self.next()?;
569 let grad_x_lexp = self.lookup_expression.lookup(grad_x_expr)?;
570 let grad_x_handle = self.get_expr_handle(
571 grad_x_expr,
572 grad_x_lexp,
573 ctx,
574 emitter,
575 block,
576 body_idx,
577 );
578 let grad_y_expr = self.next()?;
579 let grad_y_lexp = self.lookup_expression.lookup(grad_y_expr)?;
580 let grad_y_handle = self.get_expr_handle(
581 grad_y_expr,
582 grad_y_lexp,
583 ctx,
584 emitter,
585 block,
586 body_idx,
587 );
588 level = if options.compare {
589 log::debug!(
590 "Assuming gradients {grad_x_handle:?} and {grad_y_handle:?} are not greater than 1"
591 );
592 crate::SampleLevel::Zero
593 } else {
594 crate::SampleLevel::Gradient {
595 x: grad_x_handle,
596 y: grad_y_handle,
597 }
598 };
599 words_left -= 2;
600 }
601 spirv::ImageOperands::CONST_OFFSET => {
602 let offset_expr = self.next()?;
603 let offset_lexp = self.lookup_expression.lookup(offset_expr)?;
604 let offset_handle = self.get_expr_handle(
605 offset_expr,
606 offset_lexp,
607 ctx,
608 emitter,
609 block,
610 body_idx,
611 );
612 offset = Some(offset_handle);
613 words_left -= 1;
614 }
615 other => {
616 log::warn!("Unknown image sample operand {other:?}");
617 for _ in 0..words_left {
618 self.next()?;
619 }
620 break;
621 }
622 }
623 image_ops ^= bit;
624 }
625
626 let si_lexp = self.lookup_sampled_image.lookup(sampled_image_id)?;
627 let coord_lexp = self.lookup_expression.lookup(coordinate_id)?;
628 let coord_handle =
629 self.get_expr_handle(coordinate_id, coord_lexp, ctx, emitter, block, body_idx);
630 let coord_type_handle = self.lookup_type.lookup(coord_lexp.type_id)?.handle;
631
632 let sampling_bit = if options.compare {
633 SamplingFlags::COMPARISON
634 } else {
635 SamplingFlags::REGULAR
636 };
637
638 let image_ty = match ctx.expressions[si_lexp.image] {
639 crate::Expression::GlobalVariable(handle) => {
640 if let Some(flags) = self.handle_sampling.get_mut(&handle) {
641 *flags |= sampling_bit;
642 }
643
644 ctx.module.global_variables[handle].ty
645 }
646
647 crate::Expression::FunctionArgument(i) => {
648 ctx.parameter_sampling[i as usize] |= sampling_bit;
649 ctx.arguments[i as usize].ty
650 }
651
652 crate::Expression::Access { base, .. } => match ctx.expressions[base] {
653 crate::Expression::GlobalVariable(handle) => {
654 if let Some(flags) = self.handle_sampling.get_mut(&handle) {
655 *flags |= sampling_bit;
656 }
657
658 match ctx.module.types[ctx.module.global_variables[handle].ty].inner {
659 crate::TypeInner::BindingArray { base, .. } => base,
660 _ => return Err(Error::InvalidGlobalVar(ctx.expressions[base].clone())),
661 }
662 }
663
664 ref other => return Err(Error::InvalidGlobalVar(other.clone())),
665 },
666
667 ref other => return Err(Error::InvalidGlobalVar(other.clone())),
668 };
669
670 match ctx.expressions[si_lexp.sampler] {
671 crate::Expression::GlobalVariable(handle) => {
672 *self.handle_sampling.get_mut(&handle).unwrap() |= sampling_bit;
673 }
674
675 crate::Expression::FunctionArgument(i) => {
676 ctx.parameter_sampling[i as usize] |= sampling_bit;
677 }
678
679 crate::Expression::Access { base, .. } => match ctx.expressions[base] {
680 crate::Expression::GlobalVariable(handle) => {
681 *self.handle_sampling.get_mut(&handle).unwrap() |= sampling_bit;
682 }
683
684 ref other => return Err(Error::InvalidGlobalVar(other.clone())),
685 },
686
687 ref other => return Err(Error::InvalidGlobalVar(other.clone())),
688 }
689
690 let ((coordinate, array_index), depth_ref, is_depth) =
691 match ctx.module.types[image_ty].inner {
692 crate::TypeInner::Image {
693 dim,
694 arrayed,
695 class,
696 } => (
697 extract_image_coordinates(
698 dim,
699 if options.project {
700 ExtraCoordinate::Projection
701 } else if arrayed {
702 ExtraCoordinate::ArrayLayer
703 } else {
704 ExtraCoordinate::Garbage
705 },
706 coord_handle,
707 coord_type_handle,
708 ctx,
709 ),
710 {
711 match dref_id {
712 Some(id) => {
713 let expr_lexp = self.lookup_expression.lookup(id)?;
714 let mut expr = self
715 .get_expr_handle(id, expr_lexp, ctx, emitter, block, body_idx);
716
717 if options.project {
718 let required_size = dim.required_coordinate_size();
719 let right = ctx.expressions.append(
720 crate::Expression::AccessIndex {
721 base: coord_handle,
722 index: required_size.map_or(1, |size| size as u32),
723 },
724 crate::Span::default(),
725 );
726 expr = ctx.expressions.append(
727 crate::Expression::Binary {
728 op: crate::BinaryOperator::Divide,
729 left: expr,
730 right,
731 },
732 crate::Span::default(),
733 )
734 };
735 Some(expr)
736 }
737 None => None,
738 }
739 },
740 class.is_depth(),
741 ),
742 _ => return Err(Error::InvalidImage(image_ty)),
743 };
744
745 let expr = crate::Expression::ImageSample {
746 image: si_lexp.image,
747 sampler: si_lexp.sampler,
748 gather: None, coordinate,
750 array_index,
751 offset,
752 level,
753 depth_ref,
754 clamp_to_edge: false,
755 };
756 let image_sample_handle = ctx.expressions.append(expr, self.span_from_with_op(start));
757 let handle = if is_depth && depth_ref.is_none() {
758 let splat_expr = crate::Expression::Splat {
759 size: crate::VectorSize::Quad,
760 value: image_sample_handle,
761 };
762 ctx.expressions
763 .append(splat_expr, self.span_from_with_op(start))
764 } else {
765 image_sample_handle
766 };
767 self.lookup_expression.insert(
768 result_id,
769 LookupExpression {
770 handle,
771 type_id: result_type_id,
772 block_id,
773 },
774 );
775 Ok(())
776 }
777
778 pub(super) fn parse_image_query_size(
779 &mut self,
780 at_level: bool,
781 ctx: &mut super::BlockContext,
782 emitter: &mut crate::proc::Emitter,
783 block: &mut crate::Block,
784 block_id: spirv::Word,
785 body_idx: usize,
786 ) -> Result<(), Error> {
787 let start = self.data_offset;
788 let result_type_id = self.next()?;
789 let result_id = self.next()?;
790 let image_id = self.next()?;
791 let level = if at_level {
792 let level_id = self.next()?;
793 let level_lexp = self.lookup_expression.lookup(level_id)?;
794 Some(self.get_expr_handle(level_id, level_lexp, ctx, emitter, block, body_idx))
795 } else {
796 None
797 };
798
799 let image_lexp = self.lookup_expression.lookup(image_id)?;
803
804 let expr = crate::Expression::ImageQuery {
805 image: image_lexp.handle,
806 query: crate::ImageQuery::Size { level },
807 };
808
809 let result_type_handle = self.lookup_type.lookup(result_type_id)?.handle;
810 let maybe_scalar_kind = ctx.module.types[result_type_handle].inner.scalar_kind();
811
812 let expr = if maybe_scalar_kind == Some(crate::ScalarKind::Sint) {
813 crate::Expression::As {
814 expr: ctx.expressions.append(expr, self.span_from_with_op(start)),
815 kind: crate::ScalarKind::Sint,
816 convert: Some(4),
817 }
818 } else {
819 expr
820 };
821
822 self.lookup_expression.insert(
823 result_id,
824 LookupExpression {
825 handle: ctx.expressions.append(expr, self.span_from_with_op(start)),
826 type_id: result_type_id,
827 block_id,
828 },
829 );
830
831 Ok(())
832 }
833
834 pub(super) fn parse_image_query_other(
835 &mut self,
836 query: crate::ImageQuery,
837 ctx: &mut super::BlockContext,
838 block_id: spirv::Word,
839 ) -> Result<(), Error> {
840 let start = self.data_offset;
841 let result_type_id = self.next()?;
842 let result_id = self.next()?;
843 let image_id = self.next()?;
844
845 let image_lexp = self.lookup_expression.lookup(image_id)?.clone();
848
849 let expr = crate::Expression::ImageQuery {
850 image: image_lexp.handle,
851 query,
852 };
853
854 let result_type_handle = self.lookup_type.lookup(result_type_id)?.handle;
855 let maybe_scalar_kind = ctx.module.types[result_type_handle].inner.scalar_kind();
856
857 let expr = if maybe_scalar_kind == Some(crate::ScalarKind::Sint) {
858 crate::Expression::As {
859 expr: ctx.expressions.append(expr, self.span_from_with_op(start)),
860 kind: crate::ScalarKind::Sint,
861 convert: Some(4),
862 }
863 } else {
864 expr
865 };
866
867 self.lookup_expression.insert(
868 result_id,
869 LookupExpression {
870 handle: ctx.expressions.append(expr, self.span_from_with_op(start)),
871 type_id: result_type_id,
872 block_id,
873 },
874 );
875
876 Ok(())
877 }
878}