1use alloc::{vec, vec::Vec};
2
3use super::{
4 ast::{
5 BuiltinVariations, FunctionDeclaration, FunctionKind, Overload, ParameterInfo,
6 ParameterQualifier,
7 },
8 context::Context,
9 Error, ErrorKind, Frontend, Result,
10};
11use crate::{
12 BinaryOperator, DerivativeAxis as Axis, DerivativeControl as Ctrl, Expression, Handle,
13 ImageClass, ImageDimension as Dim, ImageQuery, MathFunction, Module, RelationalFunction,
14 SampleLevel, Scalar, ScalarKind as Sk, Span, Type, TypeInner, UnaryOperator, VectorSize,
15};
16
17impl crate::ScalarKind {
18 const fn dummy_storage_format(&self) -> crate::StorageFormat {
19 match *self {
20 Sk::Sint => crate::StorageFormat::R16Sint,
21 Sk::Uint => crate::StorageFormat::R16Uint,
22 _ => crate::StorageFormat::R16Float,
23 }
24 }
25}
26
27impl Module {
28 fn add_builtin(&mut self, args: Vec<TypeInner>, builtin: MacroCall) -> Overload {
30 let mut parameters = Vec::with_capacity(args.len());
31 let mut parameters_info = Vec::with_capacity(args.len());
32
33 for arg in args {
34 parameters.push(self.types.insert(
35 Type {
36 name: None,
37 inner: arg,
38 },
39 Span::default(),
40 ));
41 parameters_info.push(ParameterInfo {
42 qualifier: ParameterQualifier::In,
43 depth: false,
44 });
45 }
46
47 Overload {
48 parameters,
49 parameters_info,
50 kind: FunctionKind::Macro(builtin),
51 defined: false,
52 internal: true,
53 void: false,
54 }
55 }
56}
57
58const fn make_coords_arg(number_of_components: usize, kind: Sk) -> TypeInner {
59 let scalar = Scalar { kind, width: 4 };
60
61 match number_of_components {
62 1 => TypeInner::Scalar(scalar),
63 _ => TypeInner::Vector {
64 size: match number_of_components {
65 2 => VectorSize::Bi,
66 3 => VectorSize::Tri,
67 _ => VectorSize::Quad,
68 },
69 scalar,
70 },
71 }
72}
73
74pub fn inject_builtin(
79 declaration: &mut FunctionDeclaration,
80 module: &mut Module,
81 name: &str,
82 mut variations: BuiltinVariations,
83) {
84 log::trace!(
85 "{} variations: {:?} {:?}",
86 name,
87 variations,
88 declaration.variations
89 );
90 variations.remove(declaration.variations);
92 declaration.variations |= variations;
93
94 if variations.contains(BuiltinVariations::STANDARD) {
95 inject_standard_builtins(declaration, module, name)
96 }
97
98 if variations.contains(BuiltinVariations::DOUBLE) {
99 inject_double_builtin(declaration, module, name)
100 }
101
102 match name {
103 "texture"
104 | "textureGrad"
105 | "textureGradOffset"
106 | "textureLod"
107 | "textureLodOffset"
108 | "textureOffset"
109 | "textureProj"
110 | "textureProjGrad"
111 | "textureProjGradOffset"
112 | "textureProjLod"
113 | "textureProjLodOffset"
114 | "textureProjOffset" => {
115 let f = |kind, dim, arrayed, multi, shadow| {
116 for bits in 0..=0b11 {
117 let variant = bits & 0b1 != 0;
118 let bias = bits & 0b10 != 0;
119
120 let (proj, offset, level_type) = match name {
121 "texture" => (false, false, TextureLevelType::None),
123 "textureGrad" => (false, false, TextureLevelType::Grad),
125 "textureGradOffset" => (false, true, TextureLevelType::Grad),
127 "textureLod" => (false, false, TextureLevelType::Lod),
129 "textureLodOffset" => (false, true, TextureLevelType::Lod),
131 "textureOffset" => (false, true, TextureLevelType::None),
133 "textureProj" => (true, false, TextureLevelType::None),
135 "textureProjGrad" => (true, false, TextureLevelType::Grad),
137 "textureProjGradOffset" => (true, true, TextureLevelType::Grad),
139 "textureProjLod" => (true, false, TextureLevelType::Lod),
141 "textureProjLodOffset" => (true, true, TextureLevelType::Lod),
143 "textureProjOffset" => (true, true, TextureLevelType::None),
145 _ => unreachable!(),
146 };
147
148 let builtin = MacroCall::Texture {
149 proj,
150 offset,
151 shadow,
152 level_type,
153 };
154
155 let grad = level_type == TextureLevelType::Grad;
157 let lod = level_type == TextureLevelType::Lod;
158
159 let supports_variant = proj && !shadow;
160 if variant && !supports_variant {
161 continue;
162 }
163
164 if bias && !matches!(level_type, TextureLevelType::None) {
165 continue;
166 }
167
168 if proj && (arrayed || dim == Dim::Cube) {
170 continue;
171 }
172
173 if dim == Dim::Cube && offset {
175 continue;
176 }
177
178 if (lod || bias) && arrayed && shadow && dim == Dim::D2 {
180 continue;
181 }
182
183 if bias && shadow {
185 continue;
186 }
187
188 let class = match shadow {
189 true => ImageClass::Depth { multi },
190 false => ImageClass::Sampled { kind, multi },
191 };
192
193 let image = TypeInner::Image {
194 dim,
195 arrayed,
196 class,
197 };
198
199 let num_coords_from_dim = image_dims_to_coords_size(dim).min(3);
200 let mut num_coords = num_coords_from_dim;
201
202 if shadow && proj {
203 num_coords = 4;
204 } else if dim == Dim::D1 && shadow {
205 num_coords = 3;
206 } else if shadow {
207 num_coords += 1;
208 } else if proj {
209 if variant && num_coords == 4 {
210 continue;
212 } else if variant {
213 num_coords = 4;
214 } else {
215 num_coords += 1;
216 }
217 }
218
219 if !(dim == Dim::D1 && shadow) {
220 num_coords += arrayed as usize;
221 }
222
223 if num_coords >= 5 {
227 if lod || grad || offset || proj || bias {
228 continue;
229 }
230 debug_assert!(dim == Dim::Cube && shadow && arrayed);
231 }
232 debug_assert!(num_coords <= 5);
233
234 let vector = make_coords_arg(num_coords, Sk::Float);
235 let mut args = vec![image, vector];
236
237 if num_coords == 5 {
238 args.push(TypeInner::Scalar(Scalar::F32));
239 }
240
241 match level_type {
242 TextureLevelType::Lod => {
243 args.push(TypeInner::Scalar(Scalar::F32));
244 }
245 TextureLevelType::Grad => {
246 args.push(make_coords_arg(num_coords_from_dim, Sk::Float));
247 args.push(make_coords_arg(num_coords_from_dim, Sk::Float));
248 }
249 TextureLevelType::None => {}
250 };
251
252 if offset {
253 args.push(make_coords_arg(num_coords_from_dim, Sk::Sint));
254 }
255
256 if bias {
257 args.push(TypeInner::Scalar(Scalar::F32));
258 }
259
260 declaration
261 .overloads
262 .push(module.add_builtin(args, builtin));
263 }
264 };
265
266 texture_args_generator(TextureArgsOptions::SHADOW | variations.into(), f)
267 }
268 "textureSize" => {
269 let f = |kind, dim, arrayed, multi, shadow| {
270 let class = match shadow {
271 true => ImageClass::Depth { multi },
272 false => ImageClass::Sampled { kind, multi },
273 };
274
275 let image = TypeInner::Image {
276 dim,
277 arrayed,
278 class,
279 };
280
281 let mut args = vec![image];
282
283 if !multi {
284 args.push(TypeInner::Scalar(Scalar::I32))
285 }
286
287 declaration
288 .overloads
289 .push(module.add_builtin(args, MacroCall::TextureSize { arrayed }))
290 };
291
292 texture_args_generator(
293 TextureArgsOptions::SHADOW | TextureArgsOptions::MULTI | variations.into(),
294 f,
295 )
296 }
297 "textureQueryLevels" => {
298 let f = |kind, dim, arrayed, multi, shadow| {
299 let class = match shadow {
300 true => ImageClass::Depth { multi },
301 false => ImageClass::Sampled { kind, multi },
302 };
303
304 let image = TypeInner::Image {
305 dim,
306 arrayed,
307 class,
308 };
309
310 declaration
311 .overloads
312 .push(module.add_builtin(vec![image], MacroCall::TextureQueryLevels))
313 };
314
315 texture_args_generator(TextureArgsOptions::SHADOW | variations.into(), f)
316 }
317 "texelFetch" | "texelFetchOffset" => {
318 let offset = "texelFetchOffset" == name;
319 let f = |kind, dim, arrayed, multi, _shadow| {
320 if let Dim::Cube = dim {
322 return;
323 }
324
325 let image = TypeInner::Image {
326 dim,
327 arrayed,
328 class: ImageClass::Sampled { kind, multi },
329 };
330
331 let dim_value = image_dims_to_coords_size(dim);
332 let coordinates = make_coords_arg(dim_value + arrayed as usize, Sk::Sint);
333
334 let mut args = vec![image, coordinates, TypeInner::Scalar(Scalar::I32)];
335
336 if offset {
337 args.push(make_coords_arg(dim_value, Sk::Sint));
338 }
339
340 declaration
341 .overloads
342 .push(module.add_builtin(args, MacroCall::ImageLoad { multi }))
343 };
344
345 texture_args_generator(TextureArgsOptions::MULTI | variations.into(), f)
347 }
348 "imageSize" => {
349 let f = |kind: Sk, dim, arrayed, _, _| {
350 if dim == Dim::Cube {
353 return;
354 }
355
356 let image = TypeInner::Image {
357 dim,
358 arrayed,
359 class: ImageClass::Storage {
360 format: kind.dummy_storage_format(),
361 access: crate::StorageAccess::empty(),
362 },
363 };
364
365 declaration
366 .overloads
367 .push(module.add_builtin(vec![image], MacroCall::TextureSize { arrayed }))
368 };
369
370 texture_args_generator(variations.into(), f)
371 }
372 "imageLoad" => {
373 let f = |kind: Sk, dim, arrayed, _, _| {
374 if dim == Dim::Cube {
377 return;
378 }
379
380 let image = TypeInner::Image {
381 dim,
382 arrayed,
383 class: ImageClass::Storage {
384 format: kind.dummy_storage_format(),
385 access: crate::StorageAccess::LOAD,
386 },
387 };
388
389 let dim_value = image_dims_to_coords_size(dim);
390 let mut coord_size = dim_value + arrayed as usize;
391 if Dim::Cube == dim && arrayed {
397 coord_size = 3
398 }
399 let coordinates = make_coords_arg(coord_size, Sk::Sint);
400
401 let args = vec![image, coordinates];
402
403 declaration
404 .overloads
405 .push(module.add_builtin(args, MacroCall::ImageLoad { multi: false }))
406 };
407
408 texture_args_generator(variations.into(), f)
410 }
411 "imageStore" => {
412 let f = |kind: Sk, dim, arrayed, _, _| {
413 if dim == Dim::Cube {
416 return;
417 }
418
419 let image = TypeInner::Image {
420 dim,
421 arrayed,
422 class: ImageClass::Storage {
423 format: kind.dummy_storage_format(),
424 access: crate::StorageAccess::STORE,
425 },
426 };
427
428 let dim_value = image_dims_to_coords_size(dim);
429 let mut coord_size = dim_value + arrayed as usize;
430 if Dim::Cube == dim && arrayed {
436 coord_size = 3
437 }
438 let coordinates = make_coords_arg(coord_size, Sk::Sint);
439
440 let args = vec![
441 image,
442 coordinates,
443 TypeInner::Vector {
444 size: VectorSize::Quad,
445 scalar: Scalar { kind, width: 4 },
446 },
447 ];
448
449 let mut overload = module.add_builtin(args, MacroCall::ImageStore);
450 overload.void = true;
451 declaration.overloads.push(overload)
452 };
453
454 texture_args_generator(variations.into(), f)
456 }
457 _ => {}
458 }
459}
460
461fn inject_standard_builtins(
463 declaration: &mut FunctionDeclaration,
464 module: &mut Module,
465 name: &str,
466) {
467 let anykind_sampler = if name.starts_with("sampler") {
469 Some((name, Sk::Float))
470 } else if name.starts_with("usampler") {
471 Some((&name[1..], Sk::Uint))
472 } else if name.starts_with("isampler") {
473 Some((&name[1..], Sk::Sint))
474 } else {
475 None
476 };
477 if let Some((sampler, kind)) = anykind_sampler {
478 match sampler {
479 "sampler1D" | "sampler1DArray" | "sampler2D" | "sampler2DArray" | "sampler2DMS"
480 | "sampler2DMSArray" | "sampler3D" | "samplerCube" | "samplerCubeArray" => {
481 declaration.overloads.push(module.add_builtin(
482 vec![
483 TypeInner::Image {
484 dim: match sampler {
485 "sampler1D" | "sampler1DArray" => Dim::D1,
486 "sampler2D" | "sampler2DArray" | "sampler2DMS"
487 | "sampler2DMSArray" => Dim::D2,
488 "sampler3D" => Dim::D3,
489 _ => Dim::Cube,
490 },
491 arrayed: matches!(
492 sampler,
493 "sampler1DArray"
494 | "sampler2DArray"
495 | "sampler2DMSArray"
496 | "samplerCubeArray"
497 ),
498 class: ImageClass::Sampled {
499 kind,
500 multi: matches!(sampler, "sampler2DMS" | "sampler2DMSArray"),
501 },
502 },
503 TypeInner::Sampler { comparison: false },
504 ],
505 MacroCall::Sampler,
506 ));
507 return;
508 }
509 _ => (),
510 }
511 }
512
513 match name {
514 "sampler1DShadow"
516 | "sampler1DArrayShadow"
517 | "sampler2DShadow"
518 | "sampler2DArrayShadow"
519 | "samplerCubeShadow"
520 | "samplerCubeArrayShadow" => {
521 let dim = match name {
522 "sampler1DShadow" | "sampler1DArrayShadow" => Dim::D1,
523 "sampler2DShadow" | "sampler2DArrayShadow" => Dim::D2,
524 _ => Dim::Cube,
525 };
526 let arrayed = matches!(
527 name,
528 "sampler1DArrayShadow" | "sampler2DArrayShadow" | "samplerCubeArrayShadow"
529 );
530
531 for i in 0..2 {
532 let ty = TypeInner::Image {
533 dim,
534 arrayed,
535 class: match i {
536 0 => ImageClass::Sampled {
537 kind: Sk::Float,
538 multi: false,
539 },
540 _ => ImageClass::Depth { multi: false },
541 },
542 };
543
544 declaration.overloads.push(module.add_builtin(
545 vec![ty, TypeInner::Sampler { comparison: true }],
546 MacroCall::SamplerShadow,
547 ))
548 }
549 }
550 "sin" | "exp" | "exp2" | "sinh" | "cos" | "cosh" | "tan" | "tanh" | "acos" | "asin"
551 | "log" | "log2" | "radians" | "degrees" | "asinh" | "acosh" | "atanh"
552 | "floatBitsToInt" | "floatBitsToUint" | "dFdx" | "dFdxFine" | "dFdxCoarse" | "dFdy"
553 | "dFdyFine" | "dFdyCoarse" | "fwidth" | "fwidthFine" | "fwidthCoarse" => {
554 for bits in 0..0b100 {
557 let size = match bits {
558 0b00 => None,
559 0b01 => Some(VectorSize::Bi),
560 0b10 => Some(VectorSize::Tri),
561 _ => Some(VectorSize::Quad),
562 };
563 let scalar = Scalar::F32;
564
565 declaration.overloads.push(module.add_builtin(
566 vec![match size {
567 Some(size) => TypeInner::Vector { size, scalar },
568 None => TypeInner::Scalar(scalar),
569 }],
570 match name {
571 "sin" => MacroCall::MathFunction(MathFunction::Sin),
572 "exp" => MacroCall::MathFunction(MathFunction::Exp),
573 "exp2" => MacroCall::MathFunction(MathFunction::Exp2),
574 "sinh" => MacroCall::MathFunction(MathFunction::Sinh),
575 "cos" => MacroCall::MathFunction(MathFunction::Cos),
576 "cosh" => MacroCall::MathFunction(MathFunction::Cosh),
577 "tan" => MacroCall::MathFunction(MathFunction::Tan),
578 "tanh" => MacroCall::MathFunction(MathFunction::Tanh),
579 "acos" => MacroCall::MathFunction(MathFunction::Acos),
580 "asin" => MacroCall::MathFunction(MathFunction::Asin),
581 "log" => MacroCall::MathFunction(MathFunction::Log),
582 "log2" => MacroCall::MathFunction(MathFunction::Log2),
583 "asinh" => MacroCall::MathFunction(MathFunction::Asinh),
584 "acosh" => MacroCall::MathFunction(MathFunction::Acosh),
585 "atanh" => MacroCall::MathFunction(MathFunction::Atanh),
586 "radians" => MacroCall::MathFunction(MathFunction::Radians),
587 "degrees" => MacroCall::MathFunction(MathFunction::Degrees),
588 "floatBitsToInt" => MacroCall::BitCast(Sk::Sint),
589 "floatBitsToUint" => MacroCall::BitCast(Sk::Uint),
590 "dFdxCoarse" => MacroCall::Derivate(Axis::X, Ctrl::Coarse),
591 "dFdyCoarse" => MacroCall::Derivate(Axis::Y, Ctrl::Coarse),
592 "fwidthCoarse" => MacroCall::Derivate(Axis::Width, Ctrl::Coarse),
593 "dFdxFine" => MacroCall::Derivate(Axis::X, Ctrl::Fine),
594 "dFdyFine" => MacroCall::Derivate(Axis::Y, Ctrl::Fine),
595 "fwidthFine" => MacroCall::Derivate(Axis::Width, Ctrl::Fine),
596 "dFdx" => MacroCall::Derivate(Axis::X, Ctrl::None),
597 "dFdy" => MacroCall::Derivate(Axis::Y, Ctrl::None),
598 "fwidth" => MacroCall::Derivate(Axis::Width, Ctrl::None),
599 _ => unreachable!(),
600 },
601 ))
602 }
603 }
604 "intBitsToFloat" | "uintBitsToFloat" => {
605 for bits in 0..0b100 {
608 let size = match bits {
609 0b00 => None,
610 0b01 => Some(VectorSize::Bi),
611 0b10 => Some(VectorSize::Tri),
612 _ => Some(VectorSize::Quad),
613 };
614 let scalar = match name {
615 "intBitsToFloat" => Scalar::I32,
616 _ => Scalar::U32,
617 };
618
619 declaration.overloads.push(module.add_builtin(
620 vec![match size {
621 Some(size) => TypeInner::Vector { size, scalar },
622 None => TypeInner::Scalar(scalar),
623 }],
624 MacroCall::BitCast(Sk::Float),
625 ))
626 }
627 }
628 "pow" => {
629 for bits in 0..0b100 {
632 let size = match bits {
633 0b00 => None,
634 0b01 => Some(VectorSize::Bi),
635 0b10 => Some(VectorSize::Tri),
636 _ => Some(VectorSize::Quad),
637 };
638 let scalar = Scalar::F32;
639 let ty = || match size {
640 Some(size) => TypeInner::Vector { size, scalar },
641 None => TypeInner::Scalar(scalar),
642 };
643
644 declaration.overloads.push(
645 module
646 .add_builtin(vec![ty(), ty()], MacroCall::MathFunction(MathFunction::Pow)),
647 )
648 }
649 }
650 "abs" | "sign" => {
651 for bits in 0..0b1000 {
655 let size = match bits & 0b11 {
656 0b00 => None,
657 0b01 => Some(VectorSize::Bi),
658 0b10 => Some(VectorSize::Tri),
659 _ => Some(VectorSize::Quad),
660 };
661 let scalar = match bits >> 2 {
662 0b0 => Scalar::F32,
663 _ => Scalar::I32,
664 };
665
666 let args = vec![match size {
667 Some(size) => TypeInner::Vector { size, scalar },
668 None => TypeInner::Scalar(scalar),
669 }];
670
671 declaration.overloads.push(module.add_builtin(
672 args,
673 MacroCall::MathFunction(match name {
674 "abs" => MathFunction::Abs,
675 "sign" => MathFunction::Sign,
676 _ => unreachable!(),
677 }),
678 ))
679 }
680 }
681 "bitCount" | "bitfieldReverse" | "bitfieldExtract" | "bitfieldInsert" | "findLSB"
682 | "findMSB" => {
683 let fun = match name {
684 "bitCount" => MathFunction::CountOneBits,
685 "bitfieldReverse" => MathFunction::ReverseBits,
686 "bitfieldExtract" => MathFunction::ExtractBits,
687 "bitfieldInsert" => MathFunction::InsertBits,
688 "findLSB" => MathFunction::FirstTrailingBit,
689 "findMSB" => MathFunction::FirstLeadingBit,
690 _ => unreachable!(),
691 };
692
693 let mc = match fun {
694 MathFunction::ExtractBits => MacroCall::BitfieldExtract,
695 MathFunction::InsertBits => MacroCall::BitfieldInsert,
696 _ => MacroCall::MathFunction(fun),
697 };
698
699 for bits in 0..0b1000 {
703 let scalar = match bits & 0b1 {
704 0b0 => Scalar::I32,
705 _ => Scalar::U32,
706 };
707 let size = match bits >> 1 {
708 0b00 => None,
709 0b01 => Some(VectorSize::Bi),
710 0b10 => Some(VectorSize::Tri),
711 _ => Some(VectorSize::Quad),
712 };
713
714 let ty = || match size {
715 Some(size) => TypeInner::Vector { size, scalar },
716 None => TypeInner::Scalar(scalar),
717 };
718
719 let mut args = vec![ty()];
720
721 match fun {
722 MathFunction::ExtractBits => {
723 args.push(TypeInner::Scalar(Scalar::I32));
724 args.push(TypeInner::Scalar(Scalar::I32));
725 }
726 MathFunction::InsertBits => {
727 args.push(ty());
728 args.push(TypeInner::Scalar(Scalar::I32));
729 args.push(TypeInner::Scalar(Scalar::I32));
730 }
731 _ => {}
732 }
733
734 let mc = if scalar.kind == Sk::Uint {
736 match mc {
737 MacroCall::MathFunction(MathFunction::FirstTrailingBit) => {
738 MacroCall::FindLsbUint
739 }
740 MacroCall::MathFunction(MathFunction::FirstLeadingBit) => {
741 MacroCall::FindMsbUint
742 }
743 mc => mc,
744 }
745 } else {
746 mc
747 };
748
749 declaration.overloads.push(module.add_builtin(args, mc))
750 }
751 }
752 "packSnorm4x8" | "packUnorm4x8" | "packSnorm2x16" | "packUnorm2x16" | "packHalf2x16" => {
753 let fun = match name {
754 "packSnorm4x8" => MathFunction::Pack4x8snorm,
755 "packUnorm4x8" => MathFunction::Pack4x8unorm,
756 "packSnorm2x16" => MathFunction::Pack2x16unorm,
757 "packUnorm2x16" => MathFunction::Pack2x16snorm,
758 "packHalf2x16" => MathFunction::Pack2x16float,
759 _ => unreachable!(),
760 };
761
762 let ty = match fun {
763 MathFunction::Pack4x8snorm | MathFunction::Pack4x8unorm => TypeInner::Vector {
764 size: VectorSize::Quad,
765 scalar: Scalar::F32,
766 },
767 MathFunction::Pack2x16unorm
768 | MathFunction::Pack2x16snorm
769 | MathFunction::Pack2x16float => TypeInner::Vector {
770 size: VectorSize::Bi,
771 scalar: Scalar::F32,
772 },
773 _ => unreachable!(),
774 };
775
776 let args = vec![ty];
777
778 declaration
779 .overloads
780 .push(module.add_builtin(args, MacroCall::MathFunction(fun)));
781 }
782 "unpackSnorm4x8" | "unpackUnorm4x8" | "unpackSnorm2x16" | "unpackUnorm2x16"
783 | "unpackHalf2x16" => {
784 let fun = match name {
785 "unpackSnorm4x8" => MathFunction::Unpack4x8snorm,
786 "unpackUnorm4x8" => MathFunction::Unpack4x8unorm,
787 "unpackSnorm2x16" => MathFunction::Unpack2x16snorm,
788 "unpackUnorm2x16" => MathFunction::Unpack2x16unorm,
789 "unpackHalf2x16" => MathFunction::Unpack2x16float,
790 _ => unreachable!(),
791 };
792
793 let args = vec![TypeInner::Scalar(Scalar::U32)];
794
795 declaration
796 .overloads
797 .push(module.add_builtin(args, MacroCall::MathFunction(fun)));
798 }
799 "atan" => {
800 for bits in 0..0b1000 {
804 let fun = match bits & 0b1 {
805 0b0 => MathFunction::Atan,
806 _ => MathFunction::Atan2,
807 };
808 let size = match bits >> 1 {
809 0b00 => None,
810 0b01 => Some(VectorSize::Bi),
811 0b10 => Some(VectorSize::Tri),
812 _ => Some(VectorSize::Quad),
813 };
814 let scalar = Scalar::F32;
815 let ty = || match size {
816 Some(size) => TypeInner::Vector { size, scalar },
817 None => TypeInner::Scalar(scalar),
818 };
819
820 let mut args = vec![ty()];
821
822 if fun == MathFunction::Atan2 {
823 args.push(ty())
824 }
825
826 declaration
827 .overloads
828 .push(module.add_builtin(args, MacroCall::MathFunction(fun)))
829 }
830 }
831 "all" | "any" | "not" => {
832 for bits in 0..0b11 {
835 let size = match bits {
836 0b00 => VectorSize::Bi,
837 0b01 => VectorSize::Tri,
838 _ => VectorSize::Quad,
839 };
840
841 let args = vec![TypeInner::Vector {
842 size,
843 scalar: Scalar::BOOL,
844 }];
845
846 let fun = match name {
847 "all" => MacroCall::Relational(RelationalFunction::All),
848 "any" => MacroCall::Relational(RelationalFunction::Any),
849 "not" => MacroCall::Unary(UnaryOperator::LogicalNot),
850 _ => unreachable!(),
851 };
852
853 declaration.overloads.push(module.add_builtin(args, fun))
854 }
855 }
856 "lessThan" | "greaterThan" | "lessThanEqual" | "greaterThanEqual" => {
857 for bits in 0..0b1001 {
858 let (size, scalar) = match bits {
859 0b0000 => (VectorSize::Bi, Scalar::F32),
860 0b0001 => (VectorSize::Tri, Scalar::F32),
861 0b0010 => (VectorSize::Quad, Scalar::F32),
862 0b0011 => (VectorSize::Bi, Scalar::I32),
863 0b0100 => (VectorSize::Tri, Scalar::I32),
864 0b0101 => (VectorSize::Quad, Scalar::I32),
865 0b0110 => (VectorSize::Bi, Scalar::U32),
866 0b0111 => (VectorSize::Tri, Scalar::U32),
867 _ => (VectorSize::Quad, Scalar::U32),
868 };
869
870 let ty = || TypeInner::Vector { size, scalar };
871 let args = vec![ty(), ty()];
872
873 let fun = MacroCall::Binary(match name {
874 "lessThan" => BinaryOperator::Less,
875 "greaterThan" => BinaryOperator::Greater,
876 "lessThanEqual" => BinaryOperator::LessEqual,
877 "greaterThanEqual" => BinaryOperator::GreaterEqual,
878 _ => unreachable!(),
879 });
880
881 declaration.overloads.push(module.add_builtin(args, fun))
882 }
883 }
884 "equal" | "notEqual" => {
885 for bits in 0..0b1100 {
886 let (size, scalar) = match bits {
887 0b0000 => (VectorSize::Bi, Scalar::F32),
888 0b0001 => (VectorSize::Tri, Scalar::F32),
889 0b0010 => (VectorSize::Quad, Scalar::F32),
890 0b0011 => (VectorSize::Bi, Scalar::I32),
891 0b0100 => (VectorSize::Tri, Scalar::I32),
892 0b0101 => (VectorSize::Quad, Scalar::I32),
893 0b0110 => (VectorSize::Bi, Scalar::U32),
894 0b0111 => (VectorSize::Tri, Scalar::U32),
895 0b1000 => (VectorSize::Quad, Scalar::U32),
896 0b1001 => (VectorSize::Bi, Scalar::BOOL),
897 0b1010 => (VectorSize::Tri, Scalar::BOOL),
898 _ => (VectorSize::Quad, Scalar::BOOL),
899 };
900
901 let ty = || TypeInner::Vector { size, scalar };
902 let args = vec![ty(), ty()];
903
904 let fun = MacroCall::Binary(match name {
905 "equal" => BinaryOperator::Equal,
906 "notEqual" => BinaryOperator::NotEqual,
907 _ => unreachable!(),
908 });
909
910 declaration.overloads.push(module.add_builtin(args, fun))
911 }
912 }
913 "min" | "max" => {
914 for bits in 0..0b11100 {
918 let scalar = match bits & 0b11 {
919 0b00 => Scalar::F32,
920 0b01 => Scalar::I32,
921 0b10 => Scalar::U32,
922 _ => continue,
923 };
924 let (size, second_size) = match bits >> 2 {
925 0b000 => (None, None),
926 0b001 => (Some(VectorSize::Bi), None),
927 0b010 => (Some(VectorSize::Tri), None),
928 0b011 => (Some(VectorSize::Quad), None),
929 0b100 => (Some(VectorSize::Bi), Some(VectorSize::Bi)),
930 0b101 => (Some(VectorSize::Tri), Some(VectorSize::Tri)),
931 _ => (Some(VectorSize::Quad), Some(VectorSize::Quad)),
932 };
933
934 let args = vec![
935 match size {
936 Some(size) => TypeInner::Vector { size, scalar },
937 None => TypeInner::Scalar(scalar),
938 },
939 match second_size {
940 Some(size) => TypeInner::Vector { size, scalar },
941 None => TypeInner::Scalar(scalar),
942 },
943 ];
944
945 let fun = match name {
946 "max" => MacroCall::Splatted(MathFunction::Max, size, 1),
947 "min" => MacroCall::Splatted(MathFunction::Min, size, 1),
948 _ => unreachable!(),
949 };
950
951 declaration.overloads.push(module.add_builtin(args, fun))
952 }
953 }
954 "mix" => {
955 for bits in 0..0b10011 {
962 let size = match bits & 0b11 {
963 0b00 => Some(VectorSize::Bi),
964 0b01 => Some(VectorSize::Tri),
965 0b10 => Some(VectorSize::Quad),
966 _ => None,
967 };
968 let (scalar, splatted, boolean) = match bits >> 2 {
969 0b000 => (Scalar::I32, false, true),
970 0b001 => (Scalar::U32, false, true),
971 0b010 => (Scalar::F32, false, true),
972 0b011 => (Scalar::F32, false, false),
973 _ => (Scalar::F32, true, false),
974 };
975
976 let ty = |scalar| match size {
977 Some(size) => TypeInner::Vector { size, scalar },
978 None => TypeInner::Scalar(scalar),
979 };
980 let args = vec![
981 ty(scalar),
982 ty(scalar),
983 match (boolean, splatted) {
984 (true, _) => ty(Scalar::BOOL),
985 (_, false) => TypeInner::Scalar(scalar),
986 _ => ty(scalar),
987 },
988 ];
989
990 declaration.overloads.push(module.add_builtin(
991 args,
992 match boolean {
993 true => MacroCall::MixBoolean,
994 false => MacroCall::Splatted(MathFunction::Mix, size, 2),
995 },
996 ))
997 }
998 }
999 "clamp" => {
1000 for bits in 0..0b11011 {
1008 let scalar = match bits & 0b11 {
1009 0b00 => Scalar::F32,
1010 0b01 => Scalar::I32,
1011 0b10 => Scalar::U32,
1012 _ => continue,
1013 };
1014 let size = match (bits >> 2) & 0b11 {
1015 0b00 => Some(VectorSize::Bi),
1016 0b01 => Some(VectorSize::Tri),
1017 0b10 => Some(VectorSize::Quad),
1018 _ => None,
1019 };
1020 let splatted = bits & 0b10000 == 0b10000;
1021
1022 let base_ty = || match size {
1023 Some(size) => TypeInner::Vector { size, scalar },
1024 None => TypeInner::Scalar(scalar),
1025 };
1026 let limit_ty = || match splatted {
1027 true => TypeInner::Scalar(scalar),
1028 false => base_ty(),
1029 };
1030
1031 let args = vec![base_ty(), limit_ty(), limit_ty()];
1032
1033 declaration
1034 .overloads
1035 .push(module.add_builtin(args, MacroCall::Clamp(size)))
1036 }
1037 }
1038 "barrier" => declaration
1039 .overloads
1040 .push(module.add_builtin(Vec::new(), MacroCall::Barrier)),
1041 _ => inject_common_builtin(declaration, module, name, 4),
1043 }
1044}
1045
1046fn inject_double_builtin(declaration: &mut FunctionDeclaration, module: &mut Module, name: &str) {
1048 match name {
1049 "abs" | "sign" => {
1050 for bits in 0..0b100 {
1053 let size = match bits {
1054 0b00 => None,
1055 0b01 => Some(VectorSize::Bi),
1056 0b10 => Some(VectorSize::Tri),
1057 _ => Some(VectorSize::Quad),
1058 };
1059 let scalar = Scalar::F64;
1060
1061 let args = vec![match size {
1062 Some(size) => TypeInner::Vector { size, scalar },
1063 None => TypeInner::Scalar(scalar),
1064 }];
1065
1066 declaration.overloads.push(module.add_builtin(
1067 args,
1068 MacroCall::MathFunction(match name {
1069 "abs" => MathFunction::Abs,
1070 "sign" => MathFunction::Sign,
1071 _ => unreachable!(),
1072 }),
1073 ))
1074 }
1075 }
1076 "min" | "max" => {
1077 for bits in 0..0b111 {
1080 let (size, second_size) = match bits {
1081 0b000 => (None, None),
1082 0b001 => (Some(VectorSize::Bi), None),
1083 0b010 => (Some(VectorSize::Tri), None),
1084 0b011 => (Some(VectorSize::Quad), None),
1085 0b100 => (Some(VectorSize::Bi), Some(VectorSize::Bi)),
1086 0b101 => (Some(VectorSize::Tri), Some(VectorSize::Tri)),
1087 _ => (Some(VectorSize::Quad), Some(VectorSize::Quad)),
1088 };
1089 let scalar = Scalar::F64;
1090
1091 let args = vec![
1092 match size {
1093 Some(size) => TypeInner::Vector { size, scalar },
1094 None => TypeInner::Scalar(scalar),
1095 },
1096 match second_size {
1097 Some(size) => TypeInner::Vector { size, scalar },
1098 None => TypeInner::Scalar(scalar),
1099 },
1100 ];
1101
1102 let fun = match name {
1103 "max" => MacroCall::Splatted(MathFunction::Max, size, 1),
1104 "min" => MacroCall::Splatted(MathFunction::Min, size, 1),
1105 _ => unreachable!(),
1106 };
1107
1108 declaration.overloads.push(module.add_builtin(args, fun))
1109 }
1110 }
1111 "mix" => {
1112 for bits in 0..0b1011 {
1119 let size = match bits & 0b11 {
1120 0b00 => Some(VectorSize::Quad),
1121 0b01 => Some(VectorSize::Bi),
1122 0b10 => Some(VectorSize::Tri),
1123 _ => None,
1124 };
1125 let scalar = Scalar::F64;
1126 let (splatted, boolean) = match bits >> 2 {
1127 0b00 => (false, false),
1128 0b01 => (false, true),
1129 _ => (true, false),
1130 };
1131
1132 let ty = |scalar| match size {
1133 Some(size) => TypeInner::Vector { size, scalar },
1134 None => TypeInner::Scalar(scalar),
1135 };
1136 let args = vec![
1137 ty(scalar),
1138 ty(scalar),
1139 match (boolean, splatted) {
1140 (true, _) => ty(Scalar::BOOL),
1141 (_, false) => TypeInner::Scalar(scalar),
1142 _ => ty(scalar),
1143 },
1144 ];
1145
1146 declaration.overloads.push(module.add_builtin(
1147 args,
1148 match boolean {
1149 true => MacroCall::MixBoolean,
1150 false => MacroCall::Splatted(MathFunction::Mix, size, 2),
1151 },
1152 ))
1153 }
1154 }
1155 "clamp" => {
1156 for bits in 0..0b111 {
1163 let scalar = Scalar::F64;
1164 let size = match bits & 0b11 {
1165 0b00 => Some(VectorSize::Bi),
1166 0b01 => Some(VectorSize::Tri),
1167 0b10 => Some(VectorSize::Quad),
1168 _ => None,
1169 };
1170 let splatted = bits & 0b100 == 0b100;
1171
1172 let base_ty = || match size {
1173 Some(size) => TypeInner::Vector { size, scalar },
1174 None => TypeInner::Scalar(scalar),
1175 };
1176 let limit_ty = || match splatted {
1177 true => TypeInner::Scalar(scalar),
1178 false => base_ty(),
1179 };
1180
1181 let args = vec![base_ty(), limit_ty(), limit_ty()];
1182
1183 declaration
1184 .overloads
1185 .push(module.add_builtin(args, MacroCall::Clamp(size)))
1186 }
1187 }
1188 "lessThan" | "greaterThan" | "lessThanEqual" | "greaterThanEqual" | "equal"
1189 | "notEqual" => {
1190 let scalar = Scalar::F64;
1191 for bits in 0..0b11 {
1192 let size = match bits {
1193 0b00 => VectorSize::Bi,
1194 0b01 => VectorSize::Tri,
1195 _ => VectorSize::Quad,
1196 };
1197
1198 let ty = || TypeInner::Vector { size, scalar };
1199 let args = vec![ty(), ty()];
1200
1201 let fun = MacroCall::Binary(match name {
1202 "lessThan" => BinaryOperator::Less,
1203 "greaterThan" => BinaryOperator::Greater,
1204 "lessThanEqual" => BinaryOperator::LessEqual,
1205 "greaterThanEqual" => BinaryOperator::GreaterEqual,
1206 "equal" => BinaryOperator::Equal,
1207 "notEqual" => BinaryOperator::NotEqual,
1208 _ => unreachable!(),
1209 });
1210
1211 declaration.overloads.push(module.add_builtin(args, fun))
1212 }
1213 }
1214 _ => inject_common_builtin(declaration, module, name, 8),
1216 }
1217}
1218
1219fn inject_common_builtin(
1221 declaration: &mut FunctionDeclaration,
1222 module: &mut Module,
1223 name: &str,
1224 float_width: crate::Bytes,
1225) {
1226 let float_scalar = Scalar {
1227 kind: Sk::Float,
1228 width: float_width,
1229 };
1230 match name {
1231 "ceil" | "round" | "roundEven" | "floor" | "fract" | "trunc" | "sqrt" | "inversesqrt"
1232 | "normalize" | "length" | "isinf" | "isnan" => {
1233 for bits in 0..0b100 {
1236 let size = match bits {
1237 0b00 => None,
1238 0b01 => Some(VectorSize::Bi),
1239 0b10 => Some(VectorSize::Tri),
1240 _ => Some(VectorSize::Quad),
1241 };
1242
1243 let args = vec![match size {
1244 Some(size) => TypeInner::Vector {
1245 size,
1246 scalar: float_scalar,
1247 },
1248 None => TypeInner::Scalar(float_scalar),
1249 }];
1250
1251 let fun = match name {
1252 "ceil" => MacroCall::MathFunction(MathFunction::Ceil),
1253 "round" | "roundEven" => MacroCall::MathFunction(MathFunction::Round),
1254 "floor" => MacroCall::MathFunction(MathFunction::Floor),
1255 "fract" => MacroCall::MathFunction(MathFunction::Fract),
1256 "trunc" => MacroCall::MathFunction(MathFunction::Trunc),
1257 "sqrt" => MacroCall::MathFunction(MathFunction::Sqrt),
1258 "inversesqrt" => MacroCall::MathFunction(MathFunction::InverseSqrt),
1259 "normalize" => MacroCall::MathFunction(MathFunction::Normalize),
1260 "length" => MacroCall::MathFunction(MathFunction::Length),
1261 "isinf" => MacroCall::Relational(RelationalFunction::IsInf),
1262 "isnan" => MacroCall::Relational(RelationalFunction::IsNan),
1263 _ => unreachable!(),
1264 };
1265
1266 declaration.overloads.push(module.add_builtin(args, fun))
1267 }
1268 }
1269 "dot" | "reflect" | "distance" | "ldexp" => {
1270 for bits in 0..0b100 {
1273 let size = match bits {
1274 0b00 => None,
1275 0b01 => Some(VectorSize::Bi),
1276 0b10 => Some(VectorSize::Tri),
1277 _ => Some(VectorSize::Quad),
1278 };
1279 let ty = |scalar| match size {
1280 Some(size) => TypeInner::Vector { size, scalar },
1281 None => TypeInner::Scalar(scalar),
1282 };
1283
1284 let fun = match name {
1285 "dot" => MacroCall::MathFunction(MathFunction::Dot),
1286 "reflect" => MacroCall::MathFunction(MathFunction::Reflect),
1287 "distance" => MacroCall::MathFunction(MathFunction::Distance),
1288 "ldexp" => MacroCall::MathFunction(MathFunction::Ldexp),
1289 _ => unreachable!(),
1290 };
1291
1292 let second_scalar = match fun {
1293 MacroCall::MathFunction(MathFunction::Ldexp) => Scalar::I32,
1294 _ => float_scalar,
1295 };
1296
1297 declaration
1298 .overloads
1299 .push(module.add_builtin(vec![ty(float_scalar), ty(second_scalar)], fun))
1300 }
1301 }
1302 "transpose" => {
1303 for bits in 0..0b1001 {
1306 let (rows, columns) = match bits {
1307 0b0000 => (VectorSize::Bi, VectorSize::Bi),
1308 0b0001 => (VectorSize::Bi, VectorSize::Tri),
1309 0b0010 => (VectorSize::Bi, VectorSize::Quad),
1310 0b0011 => (VectorSize::Tri, VectorSize::Bi),
1311 0b0100 => (VectorSize::Tri, VectorSize::Tri),
1312 0b0101 => (VectorSize::Tri, VectorSize::Quad),
1313 0b0110 => (VectorSize::Quad, VectorSize::Bi),
1314 0b0111 => (VectorSize::Quad, VectorSize::Tri),
1315 _ => (VectorSize::Quad, VectorSize::Quad),
1316 };
1317
1318 declaration.overloads.push(module.add_builtin(
1319 vec![TypeInner::Matrix {
1320 columns,
1321 rows,
1322 scalar: float_scalar,
1323 }],
1324 MacroCall::MathFunction(MathFunction::Transpose),
1325 ))
1326 }
1327 }
1328 "inverse" | "determinant" => {
1329 for bits in 0..0b11 {
1332 let (rows, columns) = match bits {
1333 0b00 => (VectorSize::Bi, VectorSize::Bi),
1334 0b01 => (VectorSize::Tri, VectorSize::Tri),
1335 _ => (VectorSize::Quad, VectorSize::Quad),
1336 };
1337
1338 let args = vec![TypeInner::Matrix {
1339 columns,
1340 rows,
1341 scalar: float_scalar,
1342 }];
1343
1344 declaration.overloads.push(module.add_builtin(
1345 args,
1346 MacroCall::MathFunction(match name {
1347 "inverse" => MathFunction::Inverse,
1348 "determinant" => MathFunction::Determinant,
1349 _ => unreachable!(),
1350 }),
1351 ))
1352 }
1353 }
1354 "mod" | "step" => {
1355 for bits in 0..0b111 {
1358 let (size, second_size) = match bits {
1359 0b000 => (None, None),
1360 0b001 => (Some(VectorSize::Bi), None),
1361 0b010 => (Some(VectorSize::Tri), None),
1362 0b011 => (Some(VectorSize::Quad), None),
1363 0b100 => (Some(VectorSize::Bi), Some(VectorSize::Bi)),
1364 0b101 => (Some(VectorSize::Tri), Some(VectorSize::Tri)),
1365 _ => (Some(VectorSize::Quad), Some(VectorSize::Quad)),
1366 };
1367
1368 let mut args = Vec::with_capacity(2);
1369 let step = name == "step";
1370
1371 for i in 0..2 {
1372 let maybe_size = match i == step as u32 {
1373 true => size,
1374 false => second_size,
1375 };
1376
1377 args.push(match maybe_size {
1378 Some(size) => TypeInner::Vector {
1379 size,
1380 scalar: float_scalar,
1381 },
1382 None => TypeInner::Scalar(float_scalar),
1383 })
1384 }
1385
1386 let fun = match name {
1387 "mod" => MacroCall::Mod(size),
1388 "step" => MacroCall::Splatted(MathFunction::Step, size, 0),
1389 _ => unreachable!(),
1390 };
1391
1392 declaration.overloads.push(module.add_builtin(args, fun))
1393 }
1394 }
1395 "cross" => {
1398 let args = vec![
1399 TypeInner::Vector {
1400 size: VectorSize::Tri,
1401 scalar: float_scalar,
1402 },
1403 TypeInner::Vector {
1404 size: VectorSize::Tri,
1405 scalar: float_scalar,
1406 },
1407 ];
1408
1409 declaration
1410 .overloads
1411 .push(module.add_builtin(args, MacroCall::MathFunction(MathFunction::Cross)))
1412 }
1413 "outerProduct" => {
1414 for bits in 0..0b1001 {
1417 let (size1, size2) = match bits {
1418 0b0000 => (VectorSize::Bi, VectorSize::Bi),
1419 0b0001 => (VectorSize::Bi, VectorSize::Tri),
1420 0b0010 => (VectorSize::Bi, VectorSize::Quad),
1421 0b0011 => (VectorSize::Tri, VectorSize::Bi),
1422 0b0100 => (VectorSize::Tri, VectorSize::Tri),
1423 0b0101 => (VectorSize::Tri, VectorSize::Quad),
1424 0b0110 => (VectorSize::Quad, VectorSize::Bi),
1425 0b0111 => (VectorSize::Quad, VectorSize::Tri),
1426 _ => (VectorSize::Quad, VectorSize::Quad),
1427 };
1428
1429 let args = vec![
1430 TypeInner::Vector {
1431 size: size1,
1432 scalar: float_scalar,
1433 },
1434 TypeInner::Vector {
1435 size: size2,
1436 scalar: float_scalar,
1437 },
1438 ];
1439
1440 declaration
1441 .overloads
1442 .push(module.add_builtin(args, MacroCall::MathFunction(MathFunction::Outer)))
1443 }
1444 }
1445 "faceforward" | "fma" => {
1446 for bits in 0..0b100 {
1449 let size = match bits {
1450 0b00 => None,
1451 0b01 => Some(VectorSize::Bi),
1452 0b10 => Some(VectorSize::Tri),
1453 _ => Some(VectorSize::Quad),
1454 };
1455
1456 let ty = || match size {
1457 Some(size) => TypeInner::Vector {
1458 size,
1459 scalar: float_scalar,
1460 },
1461 None => TypeInner::Scalar(float_scalar),
1462 };
1463 let args = vec![ty(), ty(), ty()];
1464
1465 let fun = match name {
1466 "faceforward" => MacroCall::MathFunction(MathFunction::FaceForward),
1467 "fma" => MacroCall::MathFunction(MathFunction::Fma),
1468 _ => unreachable!(),
1469 };
1470
1471 declaration.overloads.push(module.add_builtin(args, fun))
1472 }
1473 }
1474 "refract" => {
1475 for bits in 0..0b100 {
1478 let size = match bits {
1479 0b00 => None,
1480 0b01 => Some(VectorSize::Bi),
1481 0b10 => Some(VectorSize::Tri),
1482 _ => Some(VectorSize::Quad),
1483 };
1484
1485 let ty = || match size {
1486 Some(size) => TypeInner::Vector {
1487 size,
1488 scalar: float_scalar,
1489 },
1490 None => TypeInner::Scalar(float_scalar),
1491 };
1492 let args = vec![ty(), ty(), TypeInner::Scalar(Scalar::F32)];
1493 declaration
1494 .overloads
1495 .push(module.add_builtin(args, MacroCall::MathFunction(MathFunction::Refract)))
1496 }
1497 }
1498 "smoothstep" => {
1499 for bits in 0..0b1000 {
1502 let splatted = bits & 0b1 == 0b1;
1503 let size = match bits >> 1 {
1504 0b00 => None,
1505 0b01 => Some(VectorSize::Bi),
1506 0b10 => Some(VectorSize::Tri),
1507 _ => Some(VectorSize::Quad),
1508 };
1509
1510 if splatted && size.is_none() {
1511 continue;
1512 }
1513
1514 let base_ty = || match size {
1515 Some(size) => TypeInner::Vector {
1516 size,
1517 scalar: float_scalar,
1518 },
1519 None => TypeInner::Scalar(float_scalar),
1520 };
1521 let ty = || match splatted {
1522 true => TypeInner::Scalar(float_scalar),
1523 false => base_ty(),
1524 };
1525 declaration.overloads.push(module.add_builtin(
1526 vec![ty(), ty(), base_ty()],
1527 MacroCall::SmoothStep { splatted: size },
1528 ))
1529 }
1530 }
1531 _ => {}
1533 }
1534}
1535
1536#[derive(Clone, Copy, PartialEq, Debug)]
1537pub enum TextureLevelType {
1538 None,
1539 Lod,
1540 Grad,
1541}
1542
1543#[derive(Clone, Copy, PartialEq, Debug)]
1545pub enum MacroCall {
1546 Sampler,
1547 SamplerShadow,
1548 Texture {
1549 proj: bool,
1550 offset: bool,
1551 shadow: bool,
1552 level_type: TextureLevelType,
1553 },
1554 TextureSize {
1555 arrayed: bool,
1556 },
1557 TextureQueryLevels,
1558 ImageLoad {
1559 multi: bool,
1560 },
1561 ImageStore,
1562 MathFunction(MathFunction),
1563 FindLsbUint,
1564 FindMsbUint,
1565 BitfieldExtract,
1566 BitfieldInsert,
1567 Relational(RelationalFunction),
1568 Unary(UnaryOperator),
1569 Binary(BinaryOperator),
1570 Mod(Option<VectorSize>),
1571 Splatted(MathFunction, Option<VectorSize>, usize),
1572 MixBoolean,
1573 Clamp(Option<VectorSize>),
1574 BitCast(Sk),
1575 Derivate(Axis, Ctrl),
1576 Barrier,
1577 SmoothStep {
1580 splatted: Option<VectorSize>,
1582 },
1583}
1584
1585impl MacroCall {
1586 pub fn call(
1589 &self,
1590 frontend: &mut Frontend,
1591 ctx: &mut Context,
1592 args: &mut [Handle<Expression>],
1593 meta: Span,
1594 ) -> Result<Option<Handle<Expression>>> {
1595 Ok(Some(match *self {
1596 MacroCall::Sampler => {
1597 ctx.samplers.insert(args[0], args[1]);
1598 args[0]
1599 }
1600 MacroCall::SamplerShadow => {
1601 sampled_to_depth(ctx, args[0], meta, &mut frontend.errors);
1602 ctx.invalidate_expression(args[0], meta)?;
1603 ctx.samplers.insert(args[0], args[1]);
1604 args[0]
1605 }
1606 MacroCall::Texture {
1607 proj,
1608 offset,
1609 shadow,
1610 level_type,
1611 } => {
1612 let mut coords = args[1];
1613
1614 if proj {
1615 let size = match *ctx.resolve_type(coords, meta)? {
1616 TypeInner::Vector { size, .. } => size,
1617 _ => unreachable!(),
1618 };
1619 let mut right = ctx.add_expression(
1620 Expression::AccessIndex {
1621 base: coords,
1622 index: size as u32 - 1,
1623 },
1624 Span::default(),
1625 )?;
1626 let left = if let VectorSize::Bi = size {
1627 ctx.add_expression(
1628 Expression::AccessIndex {
1629 base: coords,
1630 index: 0,
1631 },
1632 Span::default(),
1633 )?
1634 } else {
1635 let size = match size {
1636 VectorSize::Tri => VectorSize::Bi,
1637 _ => VectorSize::Tri,
1638 };
1639 right = ctx.add_expression(
1640 Expression::Splat { size, value: right },
1641 Span::default(),
1642 )?;
1643 ctx.vector_resize(size, coords, Span::default())?
1644 };
1645 coords = ctx.add_expression(
1646 Expression::Binary {
1647 op: BinaryOperator::Divide,
1648 left,
1649 right,
1650 },
1651 Span::default(),
1652 )?;
1653 }
1654
1655 let extra = args.get(2).copied();
1656 let comps = frontend.coordinate_components(ctx, args[0], coords, extra, meta)?;
1657
1658 let mut num_args = 2;
1659
1660 if comps.used_extra {
1661 num_args += 1;
1662 };
1663
1664 let mut level = match level_type {
1666 TextureLevelType::None => SampleLevel::Auto,
1667
1668 TextureLevelType::Lod => {
1669 num_args += 1;
1670
1671 if shadow {
1672 log::warn!("Assuming LOD {:?} is zero", args[2],);
1673
1674 SampleLevel::Zero
1675 } else {
1676 SampleLevel::Exact(args[2])
1677 }
1678 }
1679
1680 TextureLevelType::Grad => {
1681 num_args += 2;
1682
1683 if shadow {
1684 log::warn!(
1685 "Assuming gradients {:?} and {:?} are not greater than 1",
1686 args[2],
1687 args[3],
1688 );
1689 SampleLevel::Zero
1690 } else {
1691 SampleLevel::Gradient {
1692 x: args[2],
1693 y: args[3],
1694 }
1695 }
1696 }
1697 };
1698
1699 let texture_offset = match offset {
1700 true => {
1701 let offset_arg = args[num_args];
1702 num_args += 1;
1703 Some(offset_arg)
1704 }
1705 false => None,
1706 };
1707
1708 if let TextureLevelType::None = level_type {
1710 level = args
1711 .get(num_args)
1712 .copied()
1713 .map_or(SampleLevel::Auto, SampleLevel::Bias);
1714 }
1715
1716 texture_call(ctx, args[0], level, comps, texture_offset, meta)?
1717 }
1718
1719 MacroCall::TextureSize { arrayed } => {
1720 let mut expr = ctx.add_expression(
1721 Expression::ImageQuery {
1722 image: args[0],
1723 query: ImageQuery::Size {
1724 level: args.get(1).copied(),
1725 },
1726 },
1727 Span::default(),
1728 )?;
1729
1730 if arrayed {
1731 let mut components = Vec::with_capacity(4);
1732
1733 let size = match *ctx.resolve_type(expr, meta)? {
1734 TypeInner::Vector { size: ori_size, .. } => {
1735 for index in 0..(ori_size as u32) {
1736 components.push(ctx.add_expression(
1737 Expression::AccessIndex { base: expr, index },
1738 Span::default(),
1739 )?)
1740 }
1741
1742 match ori_size {
1743 VectorSize::Bi => VectorSize::Tri,
1744 _ => VectorSize::Quad,
1745 }
1746 }
1747 _ => {
1748 components.push(expr);
1749 VectorSize::Bi
1750 }
1751 };
1752
1753 components.push(ctx.add_expression(
1754 Expression::ImageQuery {
1755 image: args[0],
1756 query: ImageQuery::NumLayers,
1757 },
1758 Span::default(),
1759 )?);
1760
1761 let ty = ctx.module.types.insert(
1762 Type {
1763 name: None,
1764 inner: TypeInner::Vector {
1765 size,
1766 scalar: Scalar::U32,
1767 },
1768 },
1769 Span::default(),
1770 );
1771
1772 expr = ctx.add_expression(Expression::Compose { components, ty }, meta)?
1773 }
1774
1775 ctx.add_expression(
1776 Expression::As {
1777 expr,
1778 kind: Sk::Sint,
1779 convert: Some(4),
1780 },
1781 Span::default(),
1782 )?
1783 }
1784 MacroCall::TextureQueryLevels => {
1785 let expr = ctx.add_expression(
1786 Expression::ImageQuery {
1787 image: args[0],
1788 query: ImageQuery::NumLevels,
1789 },
1790 Span::default(),
1791 )?;
1792
1793 ctx.add_expression(
1794 Expression::As {
1795 expr,
1796 kind: Sk::Sint,
1797 convert: Some(4),
1798 },
1799 Span::default(),
1800 )?
1801 }
1802 MacroCall::ImageLoad { multi } => {
1803 let comps = frontend.coordinate_components(ctx, args[0], args[1], None, meta)?;
1804 let (sample, level) = match (multi, args.get(2)) {
1805 (_, None) => (None, None),
1806 (true, Some(&arg)) => (Some(arg), None),
1807 (false, Some(&arg)) => (None, Some(arg)),
1808 };
1809 ctx.add_expression(
1810 Expression::ImageLoad {
1811 image: args[0],
1812 coordinate: comps.coordinate,
1813 array_index: comps.array_index,
1814 sample,
1815 level,
1816 },
1817 Span::default(),
1818 )?
1819 }
1820 MacroCall::ImageStore => {
1821 let comps = frontend.coordinate_components(ctx, args[0], args[1], None, meta)?;
1822 ctx.emit_restart();
1823 ctx.body.push(
1824 crate::Statement::ImageStore {
1825 image: args[0],
1826 coordinate: comps.coordinate,
1827 array_index: comps.array_index,
1828 value: args[2],
1829 },
1830 meta,
1831 );
1832 return Ok(None);
1833 }
1834 MacroCall::MathFunction(fun) => ctx.add_expression(
1835 Expression::Math {
1836 fun,
1837 arg: args[0],
1838 arg1: args.get(1).copied(),
1839 arg2: args.get(2).copied(),
1840 arg3: args.get(3).copied(),
1841 },
1842 Span::default(),
1843 )?,
1844 mc @ (MacroCall::FindLsbUint | MacroCall::FindMsbUint) => {
1845 let fun = match mc {
1846 MacroCall::FindLsbUint => MathFunction::FirstTrailingBit,
1847 MacroCall::FindMsbUint => MathFunction::FirstLeadingBit,
1848 _ => unreachable!(),
1849 };
1850 let res = ctx.add_expression(
1851 Expression::Math {
1852 fun,
1853 arg: args[0],
1854 arg1: None,
1855 arg2: None,
1856 arg3: None,
1857 },
1858 Span::default(),
1859 )?;
1860 ctx.add_expression(
1861 Expression::As {
1862 expr: res,
1863 kind: Sk::Sint,
1864 convert: Some(4),
1865 },
1866 Span::default(),
1867 )?
1868 }
1869 MacroCall::BitfieldInsert => {
1870 let conv_arg_2 = ctx.add_expression(
1871 Expression::As {
1872 expr: args[2],
1873 kind: Sk::Uint,
1874 convert: Some(4),
1875 },
1876 Span::default(),
1877 )?;
1878 let conv_arg_3 = ctx.add_expression(
1879 Expression::As {
1880 expr: args[3],
1881 kind: Sk::Uint,
1882 convert: Some(4),
1883 },
1884 Span::default(),
1885 )?;
1886 ctx.add_expression(
1887 Expression::Math {
1888 fun: MathFunction::InsertBits,
1889 arg: args[0],
1890 arg1: Some(args[1]),
1891 arg2: Some(conv_arg_2),
1892 arg3: Some(conv_arg_3),
1893 },
1894 Span::default(),
1895 )?
1896 }
1897 MacroCall::BitfieldExtract => {
1898 let conv_arg_1 = ctx.add_expression(
1899 Expression::As {
1900 expr: args[1],
1901 kind: Sk::Uint,
1902 convert: Some(4),
1903 },
1904 Span::default(),
1905 )?;
1906 let conv_arg_2 = ctx.add_expression(
1907 Expression::As {
1908 expr: args[2],
1909 kind: Sk::Uint,
1910 convert: Some(4),
1911 },
1912 Span::default(),
1913 )?;
1914 ctx.add_expression(
1915 Expression::Math {
1916 fun: MathFunction::ExtractBits,
1917 arg: args[0],
1918 arg1: Some(conv_arg_1),
1919 arg2: Some(conv_arg_2),
1920 arg3: None,
1921 },
1922 Span::default(),
1923 )?
1924 }
1925 MacroCall::Relational(fun) => ctx.add_expression(
1926 Expression::Relational {
1927 fun,
1928 argument: args[0],
1929 },
1930 Span::default(),
1931 )?,
1932 MacroCall::Unary(op) => {
1933 ctx.add_expression(Expression::Unary { op, expr: args[0] }, Span::default())?
1934 }
1935 MacroCall::Binary(op) => ctx.add_expression(
1936 Expression::Binary {
1937 op,
1938 left: args[0],
1939 right: args[1],
1940 },
1941 Span::default(),
1942 )?,
1943 MacroCall::Mod(size) => {
1944 ctx.implicit_splat(&mut args[1], meta, size)?;
1945
1946 let div = ctx.add_expression(
1949 Expression::Binary {
1950 op: BinaryOperator::Divide,
1951 left: args[0],
1952 right: args[1],
1953 },
1954 Span::default(),
1955 )?;
1956 let floor = ctx.add_expression(
1957 Expression::Math {
1958 fun: MathFunction::Floor,
1959 arg: div,
1960 arg1: None,
1961 arg2: None,
1962 arg3: None,
1963 },
1964 Span::default(),
1965 )?;
1966 let mult = ctx.add_expression(
1967 Expression::Binary {
1968 op: BinaryOperator::Multiply,
1969 left: floor,
1970 right: args[1],
1971 },
1972 Span::default(),
1973 )?;
1974 ctx.add_expression(
1975 Expression::Binary {
1976 op: BinaryOperator::Subtract,
1977 left: args[0],
1978 right: mult,
1979 },
1980 Span::default(),
1981 )?
1982 }
1983 MacroCall::Splatted(fun, size, i) => {
1984 ctx.implicit_splat(&mut args[i], meta, size)?;
1985
1986 ctx.add_expression(
1987 Expression::Math {
1988 fun,
1989 arg: args[0],
1990 arg1: args.get(1).copied(),
1991 arg2: args.get(2).copied(),
1992 arg3: args.get(3).copied(),
1993 },
1994 Span::default(),
1995 )?
1996 }
1997 MacroCall::MixBoolean => ctx.add_expression(
1998 Expression::Select {
1999 condition: args[2],
2000 accept: args[1],
2001 reject: args[0],
2002 },
2003 Span::default(),
2004 )?,
2005 MacroCall::Clamp(size) => {
2006 ctx.implicit_splat(&mut args[1], meta, size)?;
2007 ctx.implicit_splat(&mut args[2], meta, size)?;
2008
2009 ctx.add_expression(
2010 Expression::Math {
2011 fun: MathFunction::Clamp,
2012 arg: args[0],
2013 arg1: args.get(1).copied(),
2014 arg2: args.get(2).copied(),
2015 arg3: args.get(3).copied(),
2016 },
2017 Span::default(),
2018 )?
2019 }
2020 MacroCall::BitCast(kind) => ctx.add_expression(
2021 Expression::As {
2022 expr: args[0],
2023 kind,
2024 convert: None,
2025 },
2026 Span::default(),
2027 )?,
2028 MacroCall::Derivate(axis, ctrl) => ctx.add_expression(
2029 Expression::Derivative {
2030 axis,
2031 ctrl,
2032 expr: args[0],
2033 },
2034 Span::default(),
2035 )?,
2036 MacroCall::Barrier => {
2037 ctx.emit_restart();
2038 ctx.body.push(
2039 crate::Statement::ControlBarrier(crate::Barrier::all()),
2040 meta,
2041 );
2042 return Ok(None);
2043 }
2044 MacroCall::SmoothStep { splatted } => {
2045 ctx.implicit_splat(&mut args[0], meta, splatted)?;
2046 ctx.implicit_splat(&mut args[1], meta, splatted)?;
2047
2048 ctx.add_expression(
2049 Expression::Math {
2050 fun: MathFunction::SmoothStep,
2051 arg: args[0],
2052 arg1: args.get(1).copied(),
2053 arg2: args.get(2).copied(),
2054 arg3: None,
2055 },
2056 Span::default(),
2057 )?
2058 }
2059 }))
2060 }
2061}
2062
2063fn texture_call(
2064 ctx: &mut Context,
2065 image: Handle<Expression>,
2066 level: SampleLevel,
2067 comps: CoordComponents,
2068 offset: Option<Handle<Expression>>,
2069 meta: Span,
2070) -> Result<Handle<Expression>> {
2071 if let Some(sampler) = ctx.samplers.get(&image).copied() {
2072 let mut array_index = comps.array_index;
2073
2074 if let Some(ref mut array_index_expr) = array_index {
2075 ctx.conversion(array_index_expr, meta, Scalar::I32)?;
2076 }
2077
2078 Ok(ctx.add_expression(
2079 Expression::ImageSample {
2080 image,
2081 sampler,
2082 gather: None, coordinate: comps.coordinate,
2084 array_index,
2085 offset,
2086 level,
2087 depth_ref: comps.depth_ref,
2088 clamp_to_edge: false,
2089 },
2090 meta,
2091 )?)
2092 } else {
2093 Err(Error {
2094 kind: ErrorKind::SemanticError("Bad call".into()),
2095 meta,
2096 })
2097 }
2098}
2099
2100#[derive(Debug)]
2104struct CoordComponents {
2105 coordinate: Handle<Expression>,
2106 depth_ref: Option<Handle<Expression>>,
2107 array_index: Option<Handle<Expression>>,
2108 used_extra: bool,
2109}
2110
2111impl Frontend {
2112 fn coordinate_components(
2114 &mut self,
2115 ctx: &mut Context,
2116 image: Handle<Expression>,
2117 coord: Handle<Expression>,
2118 extra: Option<Handle<Expression>>,
2119 meta: Span,
2120 ) -> Result<CoordComponents> {
2121 if let TypeInner::Image {
2122 dim,
2123 arrayed,
2124 class,
2125 } = *ctx.resolve_type(image, meta)?
2126 {
2127 let image_size = match dim {
2128 Dim::D1 => None,
2129 Dim::D2 => Some(VectorSize::Bi),
2130 Dim::D3 => Some(VectorSize::Tri),
2131 Dim::Cube => Some(VectorSize::Tri),
2132 };
2133 let coord_size = match *ctx.resolve_type(coord, meta)? {
2134 TypeInner::Vector { size, .. } => Some(size),
2135 _ => None,
2136 };
2137 let (shadow, storage) = match class {
2138 ImageClass::Depth { .. } => (true, false),
2139 ImageClass::Storage { .. } => (false, true),
2140 ImageClass::Sampled { .. } => (false, false),
2141 };
2142
2143 let coordinate = match (image_size, coord_size) {
2144 (Some(size), Some(coord_s)) if size != coord_s => {
2145 ctx.vector_resize(size, coord, Span::default())?
2146 }
2147 (None, Some(_)) => ctx.add_expression(
2148 Expression::AccessIndex {
2149 base: coord,
2150 index: 0,
2151 },
2152 Span::default(),
2153 )?,
2154 _ => coord,
2155 };
2156
2157 let mut coord_index = image_size.map_or(1, |s| s as u32);
2158
2159 let array_index = if arrayed && !(storage && dim == Dim::Cube) {
2160 let index = coord_index;
2161 coord_index += 1;
2162
2163 Some(ctx.add_expression(
2164 Expression::AccessIndex { base: coord, index },
2165 Span::default(),
2166 )?)
2167 } else {
2168 None
2169 };
2170 let mut used_extra = false;
2171 let depth_ref = match shadow {
2172 true => {
2173 let index = coord_index;
2174
2175 if index == 4 {
2176 used_extra = true;
2177 extra
2178 } else {
2179 Some(ctx.add_expression(
2180 Expression::AccessIndex { base: coord, index },
2181 Span::default(),
2182 )?)
2183 }
2184 }
2185 false => None,
2186 };
2187
2188 Ok(CoordComponents {
2189 coordinate,
2190 depth_ref,
2191 array_index,
2192 used_extra,
2193 })
2194 } else {
2195 self.errors.push(Error {
2196 kind: ErrorKind::SemanticError("Type is not an image".into()),
2197 meta,
2198 });
2199
2200 Ok(CoordComponents {
2201 coordinate: coord,
2202 depth_ref: None,
2203 array_index: None,
2204 used_extra: false,
2205 })
2206 }
2207 }
2208}
2209
2210pub fn sampled_to_depth(
2213 ctx: &mut Context,
2214 image: Handle<Expression>,
2215 meta: Span,
2216 errors: &mut Vec<Error>,
2217) {
2218 let ty = match ctx[image] {
2220 Expression::GlobalVariable(handle) => &mut ctx.module.global_variables.get_mut(handle).ty,
2221 Expression::FunctionArgument(i) => {
2222 ctx.parameters_info[i as usize].depth = true;
2224 &mut ctx.arguments[i as usize].ty
2226 }
2227 _ => {
2228 return errors.push(Error {
2230 kind: ErrorKind::SemanticError("Not a valid texture expression".into()),
2231 meta,
2232 });
2233 }
2234 };
2235
2236 match ctx.module.types[*ty].inner {
2237 TypeInner::Image {
2239 class,
2240 dim,
2241 arrayed,
2242 } => match class {
2243 ImageClass::Sampled { multi, .. } => {
2244 *ty = ctx.module.types.insert(
2245 Type {
2246 name: None,
2247 inner: TypeInner::Image {
2248 dim,
2249 arrayed,
2250 class: ImageClass::Depth { multi },
2251 },
2252 },
2253 Span::default(),
2254 )
2255 }
2256 ImageClass::Depth { .. } => {}
2257 ImageClass::Storage { .. } => errors.push(Error {
2259 kind: ErrorKind::SemanticError("Not a texture".into()),
2260 meta,
2261 }),
2262 },
2263 _ => errors.push(Error {
2264 kind: ErrorKind::SemanticError("Not a texture".into()),
2265 meta,
2266 }),
2267 };
2268
2269 let ty = *ty;
2271
2272 if let Expression::FunctionArgument(i) = ctx[image] {
2275 ctx.parameters[i as usize] = ty;
2276 }
2277}
2278
2279bitflags::bitflags! {
2280 struct TextureArgsOptions: u32 {
2282 const MULTI = 1 << 0;
2284 const SHADOW = 1 << 1;
2286 const STANDARD = 1 << 2;
2288 const CUBE_ARRAY = 1 << 3;
2290 const D2_MULTI_ARRAY = 1 << 4;
2292 }
2293}
2294
2295impl From<BuiltinVariations> for TextureArgsOptions {
2296 fn from(variations: BuiltinVariations) -> Self {
2297 let mut options = TextureArgsOptions::empty();
2298 if variations.contains(BuiltinVariations::STANDARD) {
2299 options |= TextureArgsOptions::STANDARD
2300 }
2301 if variations.contains(BuiltinVariations::CUBE_TEXTURES_ARRAY) {
2302 options |= TextureArgsOptions::CUBE_ARRAY
2303 }
2304 if variations.contains(BuiltinVariations::D2_MULTI_TEXTURES_ARRAY) {
2305 options |= TextureArgsOptions::D2_MULTI_ARRAY
2306 }
2307 options
2308 }
2309}
2310
2311fn texture_args_generator(
2321 options: TextureArgsOptions,
2322 mut f: impl FnMut(crate::ScalarKind, Dim, bool, bool, bool),
2323) {
2324 for kind in [Sk::Float, Sk::Uint, Sk::Sint].iter().copied() {
2325 for dim in [Dim::D1, Dim::D2, Dim::D3, Dim::Cube].iter().copied() {
2326 for arrayed in [false, true].iter().copied() {
2327 if dim == Dim::Cube && arrayed {
2328 if !options.contains(TextureArgsOptions::CUBE_ARRAY) {
2329 continue;
2330 }
2331 } else if Dim::D2 == dim
2332 && options.contains(TextureArgsOptions::MULTI)
2333 && arrayed
2334 && options.contains(TextureArgsOptions::D2_MULTI_ARRAY)
2335 {
2336 f(kind, dim, arrayed, true, false);
2338 } else if !options.contains(TextureArgsOptions::STANDARD) {
2339 continue;
2340 }
2341
2342 f(kind, dim, arrayed, false, false);
2343
2344 if let Dim::D3 = dim {
2348 break;
2349 }
2350
2351 if Dim::D2 == dim && options.contains(TextureArgsOptions::MULTI) && !arrayed {
2352 f(kind, dim, arrayed, true, false);
2354 }
2355
2356 if Sk::Float == kind && options.contains(TextureArgsOptions::SHADOW) {
2357 f(kind, dim, arrayed, false, true);
2359 }
2360 }
2361 }
2362 }
2363}
2364
2365const fn image_dims_to_coords_size(dim: Dim) -> usize {
2368 match dim {
2369 Dim::D1 => 1,
2370 Dim::D2 => 2,
2371 _ => 3,
2372 }
2373}