1use alloc::{format, string::String};
30use core::fmt::Write;
31
32use super::{
33 super::FunctionCtx,
34 writer::{
35 ABS_FUNCTION, DIV_FUNCTION, EXTRACT_BITS_FUNCTION, F2I32_FUNCTION, F2I64_FUNCTION,
36 F2U32_FUNCTION, F2U64_FUNCTION, IMAGE_LOAD_EXTERNAL_FUNCTION,
37 IMAGE_SAMPLE_BASE_CLAMP_TO_EDGE_FUNCTION, INSERT_BITS_FUNCTION, MOD_FUNCTION, NEG_FUNCTION,
38 },
39 BackendResult, WrappedType,
40};
41use crate::{arena::Handle, proc::NameKey, ScalarKind};
42
43#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
44pub(super) struct WrappedArrayLength {
45 pub(super) writable: bool,
46}
47
48#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
49pub(super) struct WrappedImageLoad {
50 pub(super) class: crate::ImageClass,
51}
52
53#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
54pub(super) struct WrappedImageSample {
55 pub(super) class: crate::ImageClass,
56 pub(super) clamp_to_edge: bool,
57}
58
59#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
60pub(super) struct WrappedImageQuery {
61 pub(super) dim: crate::ImageDimension,
62 pub(super) arrayed: bool,
63 pub(super) class: crate::ImageClass,
64 pub(super) query: ImageQuery,
65}
66
67#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
68pub(super) struct WrappedConstructor {
69 pub(super) ty: Handle<crate::Type>,
70}
71
72#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
73pub(super) struct WrappedStructMatrixAccess {
74 pub(super) ty: Handle<crate::Type>,
75 pub(super) index: u32,
76}
77
78#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
79pub(super) struct WrappedMatCx2 {
80 pub(super) columns: crate::VectorSize,
81 pub(super) width: u8,
82}
83
84#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
85pub(super) struct WrappedMath {
86 pub(super) fun: crate::MathFunction,
87 pub(super) scalar: crate::Scalar,
88 pub(super) components: Option<u32>,
89}
90
91#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
92pub(super) struct WrappedZeroValue {
93 pub(super) ty: Handle<crate::Type>,
94}
95
96#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
97pub(super) struct WrappedUnaryOp {
98 pub(super) op: crate::UnaryOperator,
99 pub(super) ty: (Option<crate::VectorSize>, crate::Scalar),
102}
103
104#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
105pub(super) struct WrappedBinaryOp {
106 pub(super) op: crate::BinaryOperator,
107 pub(super) left_ty: (Option<crate::VectorSize>, crate::Scalar),
110 pub(super) right_ty: (Option<crate::VectorSize>, crate::Scalar),
111}
112
113#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
114pub(super) struct WrappedCast {
115 pub(super) vector_size: Option<crate::VectorSize>,
118 pub(super) src_scalar: crate::Scalar,
119 pub(super) dst_scalar: crate::Scalar,
120}
121
122#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
125pub(super) struct WrappedBitcast {
126 pub(super) src: (Option<crate::VectorSize>, crate::Scalar),
127 pub(super) dst: (Option<crate::VectorSize>, crate::Scalar),
128}
129
130impl WrappedBitcast {
131 pub(super) fn new(src_ty: &crate::TypeInner, dst_ty: &crate::TypeInner) -> Option<Self> {
134 let src = src_ty.vector_size_and_scalar()?;
135 let dst = dst_ty.vector_size_and_scalar()?;
136 (src.0 != dst.0 || src.1.width != dst.1.width).then_some(Self { src, dst })
137 }
138
139 pub(super) fn function_name(&self) -> Result<String, super::Error> {
140 let type_name = |(size, scalar): (Option<crate::VectorSize>, crate::Scalar)| {
141 Ok::<_, super::Error>(format!(
142 "{}{}",
143 scalar.to_hlsl_str()?,
144 size.map(crate::common::vector_size_str).unwrap_or("")
145 ))
146 };
147 Ok(format!(
148 "naga_bitcast_{}_to_{}",
149 type_name(self.src)?,
150 type_name(self.dst)?
151 ))
152 }
153}
154
155#[derive(Clone, Copy, Debug, Hash, Eq, Ord, PartialEq, PartialOrd)]
187pub(super) enum ImageQuery {
188 Size,
189 SizeLevel,
190 NumLevels,
191 NumLayers,
192 NumSamples,
193}
194
195impl From<crate::ImageQuery> for ImageQuery {
196 fn from(q: crate::ImageQuery) -> Self {
197 use crate::ImageQuery as Iq;
198 match q {
199 Iq::Size { level: Some(_) } => ImageQuery::SizeLevel,
200 Iq::Size { level: None } => ImageQuery::Size,
201 Iq::NumLevels => ImageQuery::NumLevels,
202 Iq::NumLayers => ImageQuery::NumLayers,
203 Iq::NumSamples => ImageQuery::NumSamples,
204 }
205 }
206}
207
208pub(super) const IMAGE_STORAGE_LOAD_SCALAR_WRAPPER: &str = "LoadedStorageValueFrom";
209
210impl<W: Write> super::Writer<'_, W> {
211 pub(super) fn write_image_type(
212 &mut self,
213 dim: crate::ImageDimension,
214 arrayed: bool,
215 class: crate::ImageClass,
216 ) -> BackendResult {
217 let access_str = match class {
218 crate::ImageClass::Storage { .. } => "RW",
219 _ => "",
220 };
221 let dim_str = dim.to_hlsl_str();
222 let arrayed_str = if arrayed { "Array" } else { "" };
223 write!(self.out, "{access_str}Texture{dim_str}{arrayed_str}")?;
224 match class {
225 crate::ImageClass::Depth { multi } => {
226 let multi_str = if multi { "MS" } else { "" };
227 write!(self.out, "{multi_str}<float>")?
228 }
229 crate::ImageClass::Sampled { kind, multi } => {
230 let multi_str = if multi { "MS" } else { "" };
231 let scalar_kind_str = crate::Scalar { kind, width: 4 }.to_hlsl_str()?;
232 write!(self.out, "{multi_str}<{scalar_kind_str}4>")?
233 }
234 crate::ImageClass::Storage { format, .. } => {
235 let storage_format_str = format.to_hlsl_str();
236 write!(self.out, "<{storage_format_str}>")?
237 }
238 crate::ImageClass::External => {
239 unreachable!(
240 "external images should be handled by `write_global_external_texture`"
241 );
242 }
243 }
244 Ok(())
245 }
246
247 pub(super) fn write_wrapped_array_length_function_name(
248 &mut self,
249 query: WrappedArrayLength,
250 ) -> BackendResult {
251 let access_str = if query.writable { "RW" } else { "" };
252 write!(self.out, "NagaBufferLength{access_str}",)?;
253
254 Ok(())
255 }
256
257 pub(super) fn write_wrapped_array_length_function(
261 &mut self,
262 wal: WrappedArrayLength,
263 ) -> BackendResult {
264 use crate::back::INDENT;
265
266 const ARGUMENT_VARIABLE_NAME: &str = "buffer";
267 const RETURN_VARIABLE_NAME: &str = "ret";
268
269 write!(self.out, "uint ")?;
271 self.write_wrapped_array_length_function_name(wal)?;
272
273 write!(self.out, "(")?;
275 let access_str = if wal.writable { "RW" } else { "" };
276 writeln!(
277 self.out,
278 "{access_str}ByteAddressBuffer {ARGUMENT_VARIABLE_NAME})"
279 )?;
280 writeln!(self.out, "{{")?;
282
283 writeln!(self.out, "{INDENT}uint {RETURN_VARIABLE_NAME};")?;
285 writeln!(
286 self.out,
287 "{INDENT}{ARGUMENT_VARIABLE_NAME}.GetDimensions({RETURN_VARIABLE_NAME});"
288 )?;
289
290 writeln!(self.out, "{INDENT}return {RETURN_VARIABLE_NAME};")?;
292
293 writeln!(self.out, "}}")?;
295 writeln!(self.out)?;
297
298 Ok(())
299 }
300
301 fn write_convert_yuv_to_rgb_and_return(
309 &mut self,
310 level: crate::back::Level,
311 y: &str,
312 uv: &str,
313 params: &str,
314 ) -> BackendResult {
315 let l1 = level;
316 let l2 = l1.next();
317
318 writeln!(
322 self.out,
323 "{l1}float3 srcGammaRgb = mul(float4({y}, {uv}, 1.0), {params}.yuv_conversion_matrix).rgb;"
324 )?;
325
326 writeln!(
329 self.out,
330 "{l1}float3 srcLinearRgb = srcGammaRgb < {params}.src_tf.k * {params}.src_tf.b ?"
331 )?;
332 writeln!(self.out, "{l2}srcGammaRgb / {params}.src_tf.k :")?;
333 writeln!(self.out, "{l2}pow((srcGammaRgb + {params}.src_tf.a - 1.0) / {params}.src_tf.a, {params}.src_tf.g);")?;
334
335 writeln!(
339 self.out,
340 "{l1}float3 dstLinearRgb = mul(srcLinearRgb, {params}.gamut_conversion_matrix);"
341 )?;
342
343 writeln!(
346 self.out,
347 "{l1}float3 dstGammaRgb = dstLinearRgb < {params}.dst_tf.b ?"
348 )?;
349 writeln!(self.out, "{l2}{params}.dst_tf.k * dstLinearRgb :")?;
350 writeln!(self.out, "{l2}{params}.dst_tf.a * pow(dstLinearRgb, 1.0 / {params}.dst_tf.g) - ({params}.dst_tf.a - 1);")?;
351
352 writeln!(self.out, "{l1}return float4(dstGammaRgb, 1.0);")?;
353 Ok(())
354 }
355
356 pub(super) fn write_wrapped_image_load_function(
357 &mut self,
358 module: &crate::Module,
359 load: WrappedImageLoad,
360 ) -> BackendResult {
361 match load {
362 WrappedImageLoad {
363 class: crate::ImageClass::External,
364 } => {
365 let l1 = crate::back::Level(1);
366 let l2 = l1.next();
367 let l3 = l2.next();
368 let params_ty_name = &self.names
369 [&NameKey::Type(module.special_types.external_texture_params.unwrap())];
370 writeln!(self.out, "float4 {IMAGE_LOAD_EXTERNAL_FUNCTION}(")?;
371 writeln!(self.out, "{l1}Texture2D<float4> plane0,")?;
372 writeln!(self.out, "{l1}Texture2D<float4> plane1,")?;
373 writeln!(self.out, "{l1}Texture2D<float4> plane2,")?;
374 writeln!(self.out, "{l1}{params_ty_name} params,")?;
375 writeln!(self.out, "{l1}uint2 coords)")?;
376 writeln!(self.out, "{{")?;
377 writeln!(self.out, "{l1}uint2 plane0_size;")?;
378 writeln!(
379 self.out,
380 "{l1}plane0.GetDimensions(plane0_size.x, plane0_size.y);"
381 )?;
382 writeln!(
385 self.out,
386 "{l1}uint2 cropped_size = any(params.size) ? params.size : plane0_size;"
387 )?;
388 writeln!(self.out, "{l1}coords = min(coords, cropped_size - 1);")?;
389
390 writeln!(self.out, "{l1}float3x2 load_transform = float3x2(")?;
393 writeln!(self.out, "{l2}params.load_transform_0,")?;
394 writeln!(self.out, "{l2}params.load_transform_1,")?;
395 writeln!(self.out, "{l2}params.load_transform_2")?;
396 writeln!(self.out, "{l1});")?;
397 writeln!(self.out, "{l1}uint2 plane0_coords = uint2(round(mul(float3(coords, 1.0), load_transform)));")?;
398 writeln!(self.out, "{l1}if (params.num_planes == 1u) {{")?;
399 writeln!(
401 self.out,
402 "{l2}return plane0.Load(uint3(plane0_coords, 0u));"
403 )?;
404 writeln!(self.out, "{l1}}} else {{")?;
405
406 writeln!(self.out, "{l2}uint2 plane1_size;")?;
408 writeln!(
409 self.out,
410 "{l2}plane1.GetDimensions(plane1_size.x, plane1_size.y);"
411 )?;
412 writeln!(self.out, "{l2}uint2 plane1_coords = uint2(floor(float2(plane0_coords) * float2(plane1_size) / float2(plane0_size)));")?;
413
414 writeln!(
416 self.out,
417 "{l2}float y = plane0.Load(uint3(plane0_coords, 0u)).x;"
418 )?;
419
420 writeln!(self.out, "{l2}float2 uv;")?;
421 writeln!(self.out, "{l2}if (params.num_planes == 2u) {{")?;
422 writeln!(
424 self.out,
425 "{l3}uv = plane1.Load(uint3(plane1_coords, 0u)).xy;"
426 )?;
427 writeln!(self.out, "{l2}}} else {{")?;
428 writeln!(self.out, "{l3}uint2 plane2_size;")?;
430 writeln!(
431 self.out,
432 "{l3}plane2.GetDimensions(plane2_size.x, plane2_size.y);"
433 )?;
434 writeln!(self.out, "{l3}uint2 plane2_coords = uint2(floor(float2(plane0_coords) * float2(plane2_size) / float2(plane0_size)));")?;
435 writeln!(self.out, "{l3}uv = float2(plane1.Load(uint3(plane1_coords, 0u)).x, plane2.Load(uint3(plane2_coords, 0u)).x);")?;
436 writeln!(self.out, "{l2}}}")?;
437
438 self.write_convert_yuv_to_rgb_and_return(l2, "y", "uv", "params")?;
439
440 writeln!(self.out, "{l1}}}")?;
441 writeln!(self.out, "}}")?;
442 writeln!(self.out)?;
443 }
444 _ => {}
445 }
446
447 Ok(())
448 }
449
450 pub(super) fn write_wrapped_image_sample_function(
451 &mut self,
452 module: &crate::Module,
453 sample: WrappedImageSample,
454 ) -> BackendResult {
455 match sample {
456 WrappedImageSample {
457 class: crate::ImageClass::External,
458 clamp_to_edge: true,
459 } => {
460 let l1 = crate::back::Level(1);
461 let l2 = l1.next();
462 let l3 = l2.next();
463 let params_ty_name = &self.names
464 [&NameKey::Type(module.special_types.external_texture_params.unwrap())];
465 writeln!(
466 self.out,
467 "float4 {IMAGE_SAMPLE_BASE_CLAMP_TO_EDGE_FUNCTION}("
468 )?;
469 writeln!(self.out, "{l1}Texture2D<float4> plane0,")?;
470 writeln!(self.out, "{l1}Texture2D<float4> plane1,")?;
471 writeln!(self.out, "{l1}Texture2D<float4> plane2,")?;
472 writeln!(self.out, "{l1}{params_ty_name} params,")?;
473 writeln!(self.out, "{l1}SamplerState samp,")?;
474 writeln!(self.out, "{l1}float2 coords)")?;
475 writeln!(self.out, "{{")?;
476 writeln!(self.out, "{l1}float2 plane0_size;")?;
477 writeln!(
478 self.out,
479 "{l1}plane0.GetDimensions(plane0_size.x, plane0_size.y);"
480 )?;
481 writeln!(self.out, "{l1}float3x2 sample_transform = float3x2(")?;
482 writeln!(self.out, "{l2}params.sample_transform_0,")?;
483 writeln!(self.out, "{l2}params.sample_transform_1,")?;
484 writeln!(self.out, "{l2}params.sample_transform_2")?;
485 writeln!(self.out, "{l1});")?;
486 writeln!(
489 self.out,
490 "{l1}coords = mul(float3(coords, 1.0), sample_transform);"
491 )?;
492 writeln!(
500 self.out,
501 "{l1}float2 bounds_min = mul(float3(0.0, 0.0, 1.0), sample_transform);"
502 )?;
503 writeln!(
504 self.out,
505 "{l1}float2 bounds_max = mul(float3(1.0, 1.0, 1.0), sample_transform);"
506 )?;
507 writeln!(self.out, "{l1}float4 bounds = float4(min(bounds_min, bounds_max), max(bounds_min, bounds_max));")?;
508 writeln!(
509 self.out,
510 "{l1}float2 plane0_half_texel = float2(0.5, 0.5) / plane0_size;"
511 )?;
512 writeln!(
513 self.out,
514 "{l1}float2 plane0_coords = clamp(coords, bounds.xy + plane0_half_texel, bounds.zw - plane0_half_texel);"
515 )?;
516 writeln!(self.out, "{l1}if (params.num_planes == 1u) {{")?;
517 writeln!(
519 self.out,
520 "{l2}return plane0.SampleLevel(samp, plane0_coords, 0.0f);"
521 )?;
522 writeln!(self.out, "{l1}}} else {{")?;
523
524 writeln!(self.out, "{l2}float2 plane1_size;")?;
525 writeln!(
526 self.out,
527 "{l2}plane1.GetDimensions(plane1_size.x, plane1_size.y);"
528 )?;
529 writeln!(
530 self.out,
531 "{l2}float2 plane1_half_texel = float2(0.5, 0.5) / plane1_size;"
532 )?;
533 writeln!(
534 self.out,
535 "{l2}float2 plane1_coords = clamp(coords, bounds.xy + plane1_half_texel, bounds.zw - plane1_half_texel);"
536 )?;
537
538 writeln!(
540 self.out,
541 "{l2}float y = plane0.SampleLevel(samp, plane0_coords, 0.0f).x;"
542 )?;
543 writeln!(self.out, "{l2}float2 uv;")?;
544 writeln!(self.out, "{l2}if (params.num_planes == 2u) {{")?;
545 writeln!(
547 self.out,
548 "{l3}uv = plane1.SampleLevel(samp, plane1_coords, 0.0f).xy;"
549 )?;
550 writeln!(self.out, "{l2}}} else {{")?;
551 writeln!(self.out, "{l3}float2 plane2_size;")?;
553 writeln!(
554 self.out,
555 "{l3}plane2.GetDimensions(plane2_size.x, plane2_size.y);"
556 )?;
557 writeln!(
558 self.out,
559 "{l3}float2 plane2_half_texel = float2(0.5, 0.5) / plane2_size;"
560 )?;
561 writeln!(self.out, "{l3}float2 plane2_coords = clamp(coords, bounds.xy + plane2_half_texel, bounds.zw - plane2_half_texel);")?;
562 writeln!(self.out, "{l3}uv = float2(plane1.SampleLevel(samp, plane1_coords, 0.0f).x, plane2.SampleLevel(samp, plane2_coords, 0.0f).x);")?;
563 writeln!(self.out, "{l2}}}")?;
564
565 self.write_convert_yuv_to_rgb_and_return(l2, "y", "uv", "params")?;
566
567 writeln!(self.out, "{l1}}}")?;
568 writeln!(self.out, "}}")?;
569 writeln!(self.out)?;
570 }
571 WrappedImageSample {
572 class:
573 crate::ImageClass::Sampled {
574 kind: ScalarKind::Float,
575 multi: false,
576 },
577 clamp_to_edge: true,
578 } => {
579 writeln!(self.out, "float4 {IMAGE_SAMPLE_BASE_CLAMP_TO_EDGE_FUNCTION}(Texture2D<float4> tex, SamplerState samp, float2 coords) {{")?;
580 let l1 = crate::back::Level(1);
581 writeln!(self.out, "{l1}float2 size;")?;
582 writeln!(self.out, "{l1}tex.GetDimensions(size.x, size.y);")?;
583 writeln!(self.out, "{l1}float2 half_texel = float2(0.5, 0.5) / size;")?;
584 writeln!(
585 self.out,
586 "{l1}return tex.SampleLevel(samp, clamp(coords, half_texel, 1.0 - half_texel), 0.0);"
587 )?;
588 writeln!(self.out, "}}")?;
589 writeln!(self.out)?;
590 }
591 _ => {}
592 }
593
594 Ok(())
595 }
596
597 pub(super) fn write_wrapped_image_query_function_name(
598 &mut self,
599 query: WrappedImageQuery,
600 ) -> BackendResult {
601 let dim_str = query.dim.to_hlsl_str();
602 let class_str = match query.class {
603 crate::ImageClass::Sampled { multi: true, .. } => "MS",
604 crate::ImageClass::Depth { multi: true } => "DepthMS",
605 crate::ImageClass::Depth { multi: false } => "Depth",
606 crate::ImageClass::Sampled { multi: false, .. } => "",
607 crate::ImageClass::Storage { .. } => "RW",
608 crate::ImageClass::External => "External",
609 };
610 let arrayed_str = if query.arrayed { "Array" } else { "" };
611 let query_str = match query.query {
612 ImageQuery::Size => "Dimensions",
613 ImageQuery::SizeLevel => "MipDimensions",
614 ImageQuery::NumLevels => "NumLevels",
615 ImageQuery::NumLayers => "NumLayers",
616 ImageQuery::NumSamples => "NumSamples",
617 };
618
619 write!(self.out, "Naga{class_str}{query_str}{dim_str}{arrayed_str}")?;
620
621 Ok(())
622 }
623
624 pub(super) fn write_wrapped_image_query_function(
628 &mut self,
629 module: &crate::Module,
630 wiq: WrappedImageQuery,
631 expr_handle: Handle<crate::Expression>,
632 func_ctx: &FunctionCtx,
633 ) -> BackendResult {
634 use crate::{
635 back::{COMPONENTS, INDENT},
636 ImageDimension as IDim,
637 };
638
639 match wiq.class {
640 crate::ImageClass::External => {
641 if wiq.query != ImageQuery::Size {
642 return Err(super::Error::Custom(
643 "External images only support `Size` queries".into(),
644 ));
645 }
646
647 write!(self.out, "uint2 ")?;
648 self.write_wrapped_image_query_function_name(wiq)?;
649 let params_name = &self.names
650 [&NameKey::Type(module.special_types.external_texture_params.unwrap())];
651 writeln!(self.out, "(Texture2D<float4> plane0, Texture2D<float4> plane1, Texture2D<float4> plane2, {params_name} params) {{")?;
655 let l1 = crate::back::Level(1);
656 let l2 = l1.next();
657 writeln!(self.out, "{l1}if (any(params.size)) {{")?;
658 writeln!(self.out, "{l2}return params.size;")?;
659 writeln!(self.out, "{l1}}} else {{")?;
660 writeln!(self.out, "{l2}uint2 ret;")?;
662 writeln!(self.out, "{l2}plane0.GetDimensions(ret.x, ret.y);")?;
663 writeln!(self.out, "{l2}return ret;")?;
664 writeln!(self.out, "{l1}}}")?;
665 writeln!(self.out, "}}")?;
666 writeln!(self.out)?;
667 }
668 _ => {
669 const ARGUMENT_VARIABLE_NAME: &str = "tex";
670 const RETURN_VARIABLE_NAME: &str = "ret";
671 const MIP_LEVEL_PARAM: &str = "mip_level";
672
673 let ret_ty = func_ctx.resolve_type(expr_handle, &module.types);
675 self.write_value_type(module, ret_ty)?;
676 write!(self.out, " ")?;
677 self.write_wrapped_image_query_function_name(wiq)?;
678
679 write!(self.out, "(")?;
681 self.write_image_type(wiq.dim, wiq.arrayed, wiq.class)?;
683 write!(self.out, " {ARGUMENT_VARIABLE_NAME}")?;
684 if let ImageQuery::SizeLevel = wiq.query {
686 write!(self.out, ", uint {MIP_LEVEL_PARAM}")?;
687 }
688 writeln!(self.out, ")")?;
689
690 writeln!(self.out, "{{")?;
692
693 let array_coords = usize::from(wiq.arrayed);
694 let extra_coords = match wiq.class {
696 crate::ImageClass::Storage { .. } => 0,
697 crate::ImageClass::Sampled { .. } | crate::ImageClass::Depth { .. } => 1,
698 crate::ImageClass::External => unreachable!(),
699 };
700
701 let (ret_swizzle, number_of_out_params) = match wiq.query {
705 ImageQuery::Size | ImageQuery::SizeLevel => {
706 let ret = match wiq.dim {
707 IDim::D1 => "x",
708 IDim::D2 => "xy",
709 IDim::D3 => "xyz",
710 IDim::Cube => "xy",
711 };
712 (ret, ret.len() + array_coords + extra_coords)
713 }
714 ImageQuery::NumLevels | ImageQuery::NumSamples => {
715 match wiq.dim {
717 IDim::D1 => ("y", 2),
718 IDim::D3 => ("w", 4),
719 IDim::D2 | IDim::Cube => {
720 if wiq.arrayed {
721 ("w", 4)
722 } else {
723 ("z", 3)
724 }
725 }
726 }
727 }
728 ImageQuery::NumLayers => ("z", 3 + extra_coords),
730 };
731
732 writeln!(self.out, "{INDENT}uint4 {RETURN_VARIABLE_NAME};")?;
734 write!(self.out, "{INDENT}{ARGUMENT_VARIABLE_NAME}.GetDimensions(")?;
735 match wiq.query {
736 ImageQuery::SizeLevel => {
737 write!(self.out, "{MIP_LEVEL_PARAM}, ")?;
738 }
739 _ => match wiq.class {
740 crate::ImageClass::Sampled { multi: true, .. }
741 | crate::ImageClass::Depth { multi: true }
742 | crate::ImageClass::Storage { .. } => {}
743 _ => {
744 write!(self.out, "0, ")?;
746 }
747 },
748 }
749
750 for component in COMPONENTS[..number_of_out_params - 1].iter() {
751 write!(self.out, "{RETURN_VARIABLE_NAME}.{component}, ")?;
752 }
753
754 write!(
756 self.out,
757 "{}.{}",
758 RETURN_VARIABLE_NAME,
759 COMPONENTS[number_of_out_params - 1]
760 )?;
761
762 writeln!(self.out, ");")?;
763
764 writeln!(
766 self.out,
767 "{INDENT}return {RETURN_VARIABLE_NAME}.{ret_swizzle};"
768 )?;
769
770 writeln!(self.out, "}}")?;
772 writeln!(self.out)?;
774 }
775 }
776 Ok(())
777 }
778
779 pub(super) fn write_wrapped_constructors_for_type(
787 &mut self,
788 module: &crate::Module,
789 ty: Handle<crate::Type>,
790 ) -> BackendResult {
791 match module.types[ty].inner {
792 crate::TypeInner::Struct { ref members, .. } => {
793 for member in members {
794 self.write_wrapped_constructors_for_type(module, member.ty)?;
795 }
796 }
797 crate::TypeInner::Array { base, .. } => {
798 self.write_wrapped_constructors_for_type(module, base)?;
799 }
800 _ => return Ok(()),
801 }
802
803 let constructor = WrappedConstructor { ty };
804 if self.wrapped.insert(WrappedType::Constructor(constructor)) {
805 self.write_wrapped_constructor_function(module, constructor)?;
806 }
807 Ok(())
808 }
809
810 pub(super) fn write_wrapped_constructor_function_name(
811 &mut self,
812 module: &crate::Module,
813 constructor: WrappedConstructor,
814 ) -> BackendResult {
815 let name = crate::TypeInner::hlsl_type_id(constructor.ty, module.to_ctx(), &self.names)?;
816 write!(self.out, "Construct{name}")?;
817 Ok(())
818 }
819
820 fn write_wrapped_constructor_function(
822 &mut self,
823 module: &crate::Module,
824 constructor: WrappedConstructor,
825 ) -> BackendResult {
826 use crate::back::INDENT;
827
828 const ARGUMENT_VARIABLE_NAME: &str = "arg";
829 const RETURN_VARIABLE_NAME: &str = "ret";
830
831 if let crate::TypeInner::Array { base, size, .. } = module.types[constructor.ty].inner {
833 write!(self.out, "typedef ")?;
834 self.write_type(module, constructor.ty)?;
835 write!(self.out, " ret_")?;
836 self.write_wrapped_constructor_function_name(module, constructor)?;
837 self.write_array_size(module, base, size)?;
838 writeln!(self.out, ";")?;
839
840 write!(self.out, "ret_")?;
841 self.write_wrapped_constructor_function_name(module, constructor)?;
842 } else {
843 self.write_type(module, constructor.ty)?;
844 }
845 write!(self.out, " ")?;
846 self.write_wrapped_constructor_function_name(module, constructor)?;
847
848 write!(self.out, "(")?;
850
851 let mut write_arg = |i, ty| -> BackendResult {
852 if i != 0 {
853 write!(self.out, ", ")?;
854 }
855 self.write_type(module, ty)?;
856 write!(self.out, " {ARGUMENT_VARIABLE_NAME}{i}")?;
857 if let crate::TypeInner::Array { base, size, .. } = module.types[ty].inner {
858 self.write_array_size(module, base, size)?;
859 }
860 Ok(())
861 };
862
863 match module.types[constructor.ty].inner {
864 crate::TypeInner::Struct { ref members, .. } => {
865 for (i, member) in members.iter().enumerate() {
866 write_arg(i, member.ty)?;
867 }
868 }
869 crate::TypeInner::Array {
870 base,
871 size: crate::ArraySize::Constant(size),
872 ..
873 } => {
874 for i in 0..size.get() as usize {
875 write_arg(i, base)?;
876 }
877 }
878 _ => unreachable!(),
879 };
880
881 write!(self.out, ")")?;
882
883 writeln!(self.out, " {{")?;
885
886 match module.types[constructor.ty].inner {
887 crate::TypeInner::Struct { ref members, .. } => {
888 let struct_name = &self.names[&NameKey::Type(constructor.ty)];
889 writeln!(
890 self.out,
891 "{INDENT}{struct_name} {RETURN_VARIABLE_NAME} = ({struct_name})0;"
892 )?;
893 for (i, member) in members.iter().enumerate() {
894 let field_name = &self.names[&NameKey::StructMember(constructor.ty, i as u32)];
895
896 match module.types[member.ty].inner {
897 crate::TypeInner::Matrix {
898 columns,
899 rows: crate::VectorSize::Bi,
900 ..
901 } if member.binding.is_none() => {
902 for j in 0..columns as u8 {
903 writeln!(
904 self.out,
905 "{INDENT}{RETURN_VARIABLE_NAME}.{field_name}_{j} = {ARGUMENT_VARIABLE_NAME}{i}[{j}];"
906 )?;
907 }
908 }
909 ref other => {
910 if let Some(super::writer::MatrixType {
914 columns,
915 rows: crate::VectorSize::Bi,
916 width,
917 }) = super::writer::get_inner_matrix_data(module, member.ty)
918 {
919 write!(
920 self.out,
921 "{}{}.{} = (__mat{}x2_f{}",
922 INDENT,
923 RETURN_VARIABLE_NAME,
924 field_name,
925 columns as u8,
926 width * 8
927 )?;
928 if let crate::TypeInner::Array { base, size, .. } = *other {
929 self.write_array_size(module, base, size)?;
930 }
931 writeln!(self.out, "){ARGUMENT_VARIABLE_NAME}{i};",)?;
932 } else {
933 writeln!(
934 self.out,
935 "{INDENT}{RETURN_VARIABLE_NAME}.{field_name} = {ARGUMENT_VARIABLE_NAME}{i};",
936 )?;
937 }
938 }
939 }
940 }
941 }
942 crate::TypeInner::Array {
943 base,
944 size: crate::ArraySize::Constant(size),
945 ..
946 } => {
947 write!(self.out, "{INDENT}")?;
948 self.write_type(module, base)?;
949 write!(self.out, " {RETURN_VARIABLE_NAME}")?;
950 self.write_array_size(module, base, crate::ArraySize::Constant(size))?;
951 write!(self.out, " = {{ ")?;
952 for i in 0..size.get() {
953 if i != 0 {
954 write!(self.out, ", ")?;
955 }
956 write!(self.out, "{ARGUMENT_VARIABLE_NAME}{i}")?;
957 }
958 writeln!(self.out, " }};",)?;
959 }
960 _ => unreachable!(),
961 }
962
963 writeln!(self.out, "{INDENT}return {RETURN_VARIABLE_NAME};")?;
965
966 writeln!(self.out, "}}")?;
968 writeln!(self.out)?;
970
971 Ok(())
972 }
973
974 fn write_loaded_scalar_to_storage_loaded_value(
977 &mut self,
978 scalar_type: crate::Scalar,
979 ) -> BackendResult {
980 const ARGUMENT_VARIABLE_NAME: &str = "arg";
981 const RETURN_VARIABLE_NAME: &str = "ret";
982
983 let zero;
984 let one;
985 match scalar_type.kind {
986 ScalarKind::Sint => {
987 assert_eq!(
988 scalar_type.width, 4,
989 "Scalar {scalar_type:?} is not a result from any storage format"
990 );
991 zero = "0";
992 one = "1";
993 }
994 ScalarKind::Uint => match scalar_type.width {
995 4 => {
996 zero = "0u";
997 one = "1u";
998 }
999 8 => {
1000 zero = "0uL";
1001 one = "1uL"
1002 }
1003 _ => unreachable!("Scalar {scalar_type:?} is not a result from any storage format"),
1004 },
1005 ScalarKind::Float => {
1006 assert_eq!(
1007 scalar_type.width, 4,
1008 "Scalar {scalar_type:?} is not a result from any storage format"
1009 );
1010 zero = "0.0";
1011 one = "1.0";
1012 }
1013 _ => unreachable!("Scalar {scalar_type:?} is not a result from any storage format"),
1014 }
1015
1016 let ty = scalar_type.to_hlsl_str()?;
1017 writeln!(
1018 self.out,
1019 "{ty}4 {IMAGE_STORAGE_LOAD_SCALAR_WRAPPER}{ty}({ty} {ARGUMENT_VARIABLE_NAME}) {{\
1020 {ty}4 {RETURN_VARIABLE_NAME} = {ty}4({ARGUMENT_VARIABLE_NAME}, {zero}, {zero}, {one});\
1021 return {RETURN_VARIABLE_NAME};\
1022}}"
1023 )?;
1024
1025 Ok(())
1026 }
1027
1028 pub(super) fn write_wrapped_struct_matrix_get_function_name(
1029 &mut self,
1030 access: WrappedStructMatrixAccess,
1031 ) -> BackendResult {
1032 let name = &self.names[&NameKey::Type(access.ty)];
1033 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1034 write!(self.out, "GetMat{field_name}On{name}")?;
1035 Ok(())
1036 }
1037
1038 pub(super) fn write_wrapped_struct_matrix_get_function(
1040 &mut self,
1041 module: &crate::Module,
1042 access: WrappedStructMatrixAccess,
1043 ) -> BackendResult {
1044 use crate::back::INDENT;
1045
1046 const STRUCT_ARGUMENT_VARIABLE_NAME: &str = "obj";
1047
1048 let member = match module.types[access.ty].inner {
1050 crate::TypeInner::Struct { ref members, .. } => &members[access.index as usize],
1051 _ => unreachable!(),
1052 };
1053 let ret_ty = &module.types[member.ty].inner;
1054 self.write_value_type(module, ret_ty)?;
1055 write!(self.out, " ")?;
1056 self.write_wrapped_struct_matrix_get_function_name(access)?;
1057
1058 write!(self.out, "(")?;
1060 let struct_name = &self.names[&NameKey::Type(access.ty)];
1061 write!(self.out, "{struct_name} {STRUCT_ARGUMENT_VARIABLE_NAME}")?;
1062
1063 writeln!(self.out, ") {{")?;
1065
1066 write!(self.out, "{INDENT}return ")?;
1068 self.write_value_type(module, ret_ty)?;
1069 write!(self.out, "(")?;
1070 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1071 match module.types[member.ty].inner {
1072 crate::TypeInner::Matrix { columns, .. } => {
1073 for i in 0..columns as u8 {
1074 if i != 0 {
1075 write!(self.out, ", ")?;
1076 }
1077 write!(self.out, "{STRUCT_ARGUMENT_VARIABLE_NAME}.{field_name}_{i}")?;
1078 }
1079 }
1080 _ => unreachable!(),
1081 }
1082 writeln!(self.out, ");")?;
1083
1084 writeln!(self.out, "}}")?;
1086 writeln!(self.out)?;
1088
1089 Ok(())
1090 }
1091
1092 pub(super) fn write_wrapped_struct_matrix_set_function_name(
1093 &mut self,
1094 access: WrappedStructMatrixAccess,
1095 ) -> BackendResult {
1096 let name = &self.names[&NameKey::Type(access.ty)];
1097 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1098 write!(self.out, "SetMat{field_name}On{name}")?;
1099 Ok(())
1100 }
1101
1102 pub(super) fn write_wrapped_struct_matrix_set_function(
1104 &mut self,
1105 module: &crate::Module,
1106 access: WrappedStructMatrixAccess,
1107 ) -> BackendResult {
1108 use crate::back::INDENT;
1109
1110 const STRUCT_ARGUMENT_VARIABLE_NAME: &str = "obj";
1111 const MATRIX_ARGUMENT_VARIABLE_NAME: &str = "mat";
1112
1113 write!(self.out, "void ")?;
1115 self.write_wrapped_struct_matrix_set_function_name(access)?;
1116
1117 write!(self.out, "(")?;
1119 let struct_name = &self.names[&NameKey::Type(access.ty)];
1120 write!(self.out, "{struct_name} {STRUCT_ARGUMENT_VARIABLE_NAME}, ")?;
1121 let member = match module.types[access.ty].inner {
1122 crate::TypeInner::Struct { ref members, .. } => &members[access.index as usize],
1123 _ => unreachable!(),
1124 };
1125 self.write_type(module, member.ty)?;
1126 write!(self.out, " {MATRIX_ARGUMENT_VARIABLE_NAME}")?;
1127 writeln!(self.out, ") {{")?;
1129
1130 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1131
1132 match module.types[member.ty].inner {
1133 crate::TypeInner::Matrix { columns, .. } => {
1134 for i in 0..columns as u8 {
1135 writeln!(
1136 self.out,
1137 "{INDENT}{STRUCT_ARGUMENT_VARIABLE_NAME}.{field_name}_{i} = {MATRIX_ARGUMENT_VARIABLE_NAME}[{i}];"
1138 )?;
1139 }
1140 }
1141 _ => unreachable!(),
1142 }
1143
1144 writeln!(self.out, "}}")?;
1146 writeln!(self.out)?;
1148
1149 Ok(())
1150 }
1151
1152 pub(super) fn write_wrapped_struct_matrix_set_vec_function_name(
1153 &mut self,
1154 access: WrappedStructMatrixAccess,
1155 ) -> BackendResult {
1156 let name = &self.names[&NameKey::Type(access.ty)];
1157 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1158 write!(self.out, "SetMatVec{field_name}On{name}")?;
1159 Ok(())
1160 }
1161
1162 pub(super) fn write_wrapped_struct_matrix_set_vec_function(
1164 &mut self,
1165 module: &crate::Module,
1166 access: WrappedStructMatrixAccess,
1167 ) -> BackendResult {
1168 use crate::back::INDENT;
1169
1170 const STRUCT_ARGUMENT_VARIABLE_NAME: &str = "obj";
1171 const VECTOR_ARGUMENT_VARIABLE_NAME: &str = "vec";
1172 const MATRIX_INDEX_ARGUMENT_VARIABLE_NAME: &str = "mat_idx";
1173
1174 write!(self.out, "void ")?;
1176 self.write_wrapped_struct_matrix_set_vec_function_name(access)?;
1177
1178 write!(self.out, "(")?;
1180 let struct_name = &self.names[&NameKey::Type(access.ty)];
1181 write!(self.out, "{struct_name} {STRUCT_ARGUMENT_VARIABLE_NAME}, ")?;
1182 let member = match module.types[access.ty].inner {
1183 crate::TypeInner::Struct { ref members, .. } => &members[access.index as usize],
1184 _ => unreachable!(),
1185 };
1186 let vec_ty = match module.types[member.ty].inner {
1187 crate::TypeInner::Matrix { rows, scalar, .. } => {
1188 crate::TypeInner::Vector { size: rows, scalar }
1189 }
1190 _ => unreachable!(),
1191 };
1192 self.write_value_type(module, &vec_ty)?;
1193 write!(
1194 self.out,
1195 " {VECTOR_ARGUMENT_VARIABLE_NAME}, uint {MATRIX_INDEX_ARGUMENT_VARIABLE_NAME}"
1196 )?;
1197
1198 writeln!(self.out, ") {{")?;
1200
1201 writeln!(
1202 self.out,
1203 "{INDENT}switch({MATRIX_INDEX_ARGUMENT_VARIABLE_NAME}) {{"
1204 )?;
1205
1206 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1207
1208 match module.types[member.ty].inner {
1209 crate::TypeInner::Matrix { columns, .. } => {
1210 for i in 0..columns as u8 {
1211 writeln!(
1212 self.out,
1213 "{INDENT}case {i}: {{ {STRUCT_ARGUMENT_VARIABLE_NAME}.{field_name}_{i} = {VECTOR_ARGUMENT_VARIABLE_NAME}; break; }}"
1214 )?;
1215 }
1216 }
1217 _ => unreachable!(),
1218 }
1219
1220 writeln!(self.out, "{INDENT}}}")?;
1221
1222 writeln!(self.out, "}}")?;
1224 writeln!(self.out)?;
1226
1227 Ok(())
1228 }
1229
1230 pub(super) fn write_wrapped_struct_matrix_set_scalar_function_name(
1231 &mut self,
1232 access: WrappedStructMatrixAccess,
1233 ) -> BackendResult {
1234 let name = &self.names[&NameKey::Type(access.ty)];
1235 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1236 write!(self.out, "SetMatScalar{field_name}On{name}")?;
1237 Ok(())
1238 }
1239
1240 pub(super) fn write_wrapped_struct_matrix_set_scalar_function(
1242 &mut self,
1243 module: &crate::Module,
1244 access: WrappedStructMatrixAccess,
1245 ) -> BackendResult {
1246 use crate::back::INDENT;
1247
1248 const STRUCT_ARGUMENT_VARIABLE_NAME: &str = "obj";
1249 const SCALAR_ARGUMENT_VARIABLE_NAME: &str = "scalar";
1250 const MATRIX_INDEX_ARGUMENT_VARIABLE_NAME: &str = "mat_idx";
1251 const VECTOR_INDEX_ARGUMENT_VARIABLE_NAME: &str = "vec_idx";
1252
1253 write!(self.out, "void ")?;
1255 self.write_wrapped_struct_matrix_set_scalar_function_name(access)?;
1256
1257 write!(self.out, "(")?;
1259 let struct_name = &self.names[&NameKey::Type(access.ty)];
1260 write!(self.out, "{struct_name} {STRUCT_ARGUMENT_VARIABLE_NAME}, ")?;
1261 let member = match module.types[access.ty].inner {
1262 crate::TypeInner::Struct { ref members, .. } => &members[access.index as usize],
1263 _ => unreachable!(),
1264 };
1265 let scalar_ty = match module.types[member.ty].inner {
1266 crate::TypeInner::Matrix { scalar, .. } => crate::TypeInner::Scalar(scalar),
1267 _ => unreachable!(),
1268 };
1269 self.write_value_type(module, &scalar_ty)?;
1270 write!(
1271 self.out,
1272 " {SCALAR_ARGUMENT_VARIABLE_NAME}, uint {MATRIX_INDEX_ARGUMENT_VARIABLE_NAME}, uint {VECTOR_INDEX_ARGUMENT_VARIABLE_NAME}"
1273 )?;
1274
1275 writeln!(self.out, ") {{")?;
1277
1278 writeln!(
1279 self.out,
1280 "{INDENT}switch({MATRIX_INDEX_ARGUMENT_VARIABLE_NAME}) {{"
1281 )?;
1282
1283 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1284
1285 match module.types[member.ty].inner {
1286 crate::TypeInner::Matrix { columns, .. } => {
1287 for i in 0..columns as u8 {
1288 writeln!(
1289 self.out,
1290 "{INDENT}case {i}: {{ {STRUCT_ARGUMENT_VARIABLE_NAME}.{field_name}_{i}[{VECTOR_INDEX_ARGUMENT_VARIABLE_NAME}] = {SCALAR_ARGUMENT_VARIABLE_NAME}; break; }}"
1291 )?;
1292 }
1293 }
1294 _ => unreachable!(),
1295 }
1296
1297 writeln!(self.out, "{INDENT}}}")?;
1298
1299 writeln!(self.out, "}}")?;
1301 writeln!(self.out)?;
1303
1304 Ok(())
1305 }
1306
1307 pub(super) fn write_special_functions(&mut self, module: &crate::Module) -> BackendResult {
1309 for (type_key, struct_ty) in module.special_types.predeclared_types.iter() {
1310 match type_key {
1311 &crate::PredeclaredType::ModfResult { size, scalar }
1312 | &crate::PredeclaredType::FrexpResult { size, scalar } => {
1313 let arg_type_name_owner;
1314 let arg_type_name = if let Some(size) = size {
1315 arg_type_name_owner = format!(
1316 "{}{}",
1317 if scalar.width == 8 { "double" } else { "float" },
1318 size as u8
1319 );
1320 &arg_type_name_owner
1321 } else if scalar.width == 8 {
1322 "double"
1323 } else {
1324 "float"
1325 };
1326
1327 let (defined_func_name, called_func_name, second_field_name, sign_multiplier) =
1328 if matches!(type_key, &crate::PredeclaredType::ModfResult { .. }) {
1329 (super::writer::MODF_FUNCTION, "modf", "whole", "")
1330 } else {
1331 (
1332 super::writer::FREXP_FUNCTION,
1333 "frexp",
1334 "exp_",
1335 "sign(arg) * ",
1336 )
1337 };
1338
1339 let struct_name = &self.names[&NameKey::Type(*struct_ty)];
1340
1341 writeln!(
1342 self.out,
1343 "{struct_name} {defined_func_name}({arg_type_name} arg) {{
1344 {arg_type_name} other;
1345 {struct_name} result;
1346 result.fract = {sign_multiplier}{called_func_name}(arg, other);
1347 result.{second_field_name} = other;
1348 return result;
1349}}"
1350 )?;
1351 writeln!(self.out)?;
1352 }
1353 &crate::PredeclaredType::AtomicCompareExchangeWeakResult { .. } => {}
1354 }
1355 }
1356 if module.special_types.ray_desc.is_some() {
1357 self.write_ray_desc_from_ray_desc_constructor_function(module)?;
1358 }
1359
1360 Ok(())
1361 }
1362
1363 pub(super) fn write_wrapped_expression_functions(
1365 &mut self,
1366 module: &crate::Module,
1367 expressions: &crate::Arena<crate::Expression>,
1368 context: Option<&FunctionCtx>,
1369 ) -> BackendResult {
1370 for (handle, _) in expressions.iter() {
1371 match expressions[handle] {
1372 crate::Expression::Compose { ty, .. } => {
1373 match module.types[ty].inner {
1374 crate::TypeInner::Struct { .. } | crate::TypeInner::Array { .. } => {
1375 let constructor = WrappedConstructor { ty };
1376 if self.wrapped.insert(WrappedType::Constructor(constructor)) {
1377 self.write_wrapped_constructor_function(module, constructor)?;
1378 }
1379 }
1380 _ => {}
1381 };
1382 }
1383 crate::Expression::ImageLoad { image, .. } => {
1384 match *context.as_ref().unwrap().resolve_type(image, &module.types) {
1386 crate::TypeInner::Image {
1387 class: crate::ImageClass::Storage { format, .. },
1388 ..
1389 } if format.single_component() => {
1390 let scalar: crate::Scalar = format.into();
1391 if self.wrapped.insert(WrappedType::ImageLoadScalar(scalar)) {
1392 self.write_loaded_scalar_to_storage_loaded_value(scalar)?;
1393 }
1394 }
1395 _ => {}
1396 }
1397 }
1398 crate::Expression::RayQueryGetIntersection { committed, .. } => {
1399 if committed {
1400 if !self.written_committed_intersection {
1401 self.write_committed_intersection_function(module)?;
1402 self.written_committed_intersection = true;
1403 }
1404 } else if !self.written_candidate_intersection {
1405 self.write_candidate_intersection_function(module)?;
1406 self.written_candidate_intersection = true;
1407 }
1408 }
1409 _ => {}
1410 }
1411 }
1412 Ok(())
1413 }
1414
1415 pub(super) fn write_wrapped_zero_value_functions(
1419 &mut self,
1420 module: &crate::Module,
1421 expressions: &crate::Arena<crate::Expression>,
1422 ) -> BackendResult {
1423 for (handle, _) in expressions.iter() {
1424 if let crate::Expression::ZeroValue(ty) = expressions[handle] {
1425 let zero_value = WrappedZeroValue { ty };
1426 if self.wrapped.insert(WrappedType::ZeroValue(zero_value)) {
1427 self.write_wrapped_zero_value_function(module, zero_value)?;
1428 }
1429 }
1430 }
1431 Ok(())
1432 }
1433
1434 pub(super) fn write_wrapped_math_functions(
1435 &mut self,
1436 module: &crate::Module,
1437 func_ctx: &FunctionCtx,
1438 ) -> BackendResult {
1439 for (_, expression) in func_ctx.expressions.iter() {
1440 if let crate::Expression::Math {
1441 fun,
1442 arg,
1443 arg1: _arg1,
1444 arg2: _arg2,
1445 arg3: _arg3,
1446 } = *expression
1447 {
1448 let arg_ty = func_ctx.resolve_type(arg, &module.types);
1449
1450 match fun {
1451 crate::MathFunction::ExtractBits => {
1452 let scalar = arg_ty.scalar().unwrap();
1465 let components = arg_ty.components();
1466
1467 let wrapped = WrappedMath {
1468 fun,
1469 scalar,
1470 components,
1471 };
1472
1473 if !self.wrapped.insert(WrappedType::Math(wrapped)) {
1474 continue;
1475 }
1476
1477 self.write_value_type(module, arg_ty)?;
1479
1480 let scalar_width: u8 = scalar.width * 8;
1481
1482 writeln!(self.out, " {EXTRACT_BITS_FUNCTION}(")?;
1484 write!(self.out, " ")?;
1485 self.write_value_type(module, arg_ty)?;
1486 writeln!(self.out, " e,")?;
1487 writeln!(self.out, " uint offset,")?;
1488 writeln!(self.out, " uint count")?;
1489 writeln!(self.out, ") {{")?;
1490
1491 writeln!(self.out, " uint w = {scalar_width};")?;
1493 writeln!(self.out, " uint o = min(offset, w);")?;
1494 writeln!(self.out, " uint c = min(count, w - o);")?;
1495 writeln!(
1496 self.out,
1497 " return (c == 0 ? 0 : (e << (w - c - o)) >> (w - c));"
1498 )?;
1499
1500 writeln!(self.out, "}}")?;
1502 }
1503 crate::MathFunction::InsertBits => {
1504 let scalar = arg_ty.scalar().unwrap();
1507 let components = arg_ty.components();
1508
1509 let wrapped = WrappedMath {
1510 fun,
1511 scalar,
1512 components,
1513 };
1514
1515 if !self.wrapped.insert(WrappedType::Math(wrapped)) {
1516 continue;
1517 }
1518
1519 self.write_value_type(module, arg_ty)?;
1521
1522 let scalar_width: u8 = scalar.width * 8;
1523 let scalar_max: u64 = match scalar.width {
1524 1 => 0xFF,
1525 2 => 0xFFFF,
1526 4 => 0xFFFFFFFF,
1527 8 => 0xFFFFFFFFFFFFFFFF,
1528 _ => unreachable!(),
1529 };
1530
1531 writeln!(self.out, " {INSERT_BITS_FUNCTION}(")?;
1533 write!(self.out, " ")?;
1534 self.write_value_type(module, arg_ty)?;
1535 writeln!(self.out, " e,")?;
1536 write!(self.out, " ")?;
1537 self.write_value_type(module, arg_ty)?;
1538 writeln!(self.out, " newbits,")?;
1539 writeln!(self.out, " uint offset,")?;
1540 writeln!(self.out, " uint count")?;
1541 writeln!(self.out, ") {{")?;
1542
1543 writeln!(self.out, " uint w = {scalar_width}u;")?;
1545 writeln!(self.out, " uint o = min(offset, w);")?;
1546 writeln!(self.out, " uint c = min(count, w - o);")?;
1547
1548 writeln!(
1551 self.out,
1552 " uint mask = (({scalar_max}u >> ({scalar_width}u - c)) << o);"
1553 )?;
1554 writeln!(
1555 self.out,
1556 " return (c == 0 ? e : ((e & ~mask) | ((newbits << o) & mask)));"
1557 )?;
1558
1559 writeln!(self.out, "}}")?;
1561 }
1562 crate::MathFunction::Abs
1573 if matches!(arg_ty.scalar(), Some(crate::Scalar::I32)) =>
1574 {
1575 let scalar = arg_ty.scalar().unwrap();
1576 let components = arg_ty.components();
1577
1578 let wrapped = WrappedMath {
1579 fun,
1580 scalar,
1581 components,
1582 };
1583
1584 if !self.wrapped.insert(WrappedType::Math(wrapped)) {
1585 continue;
1586 }
1587
1588 self.write_value_type(module, arg_ty)?;
1589 write!(self.out, " {ABS_FUNCTION}(")?;
1590 self.write_value_type(module, arg_ty)?;
1591 writeln!(self.out, " val) {{")?;
1592
1593 let level = crate::back::Level(1);
1594 writeln!(
1595 self.out,
1596 "{level}return val >= 0 ? val : asint(-asuint(val));"
1597 )?;
1598 writeln!(self.out, "}}")?;
1599 writeln!(self.out)?;
1600 }
1601 _ => {}
1602 }
1603 }
1604 }
1605
1606 Ok(())
1607 }
1608
1609 pub(super) fn write_wrapped_unary_ops(
1610 &mut self,
1611 module: &crate::Module,
1612 func_ctx: &FunctionCtx,
1613 ) -> BackendResult {
1614 for (_, expression) in func_ctx.expressions.iter() {
1615 if let crate::Expression::Unary { op, expr } = *expression {
1616 let expr_ty = func_ctx.resolve_type(expr, &module.types);
1617 let Some((vector_size, scalar)) = expr_ty.vector_size_and_scalar() else {
1618 continue;
1619 };
1620 let wrapped = WrappedUnaryOp {
1621 op,
1622 ty: (vector_size, scalar),
1623 };
1624
1625 match (op, scalar) {
1634 (crate::UnaryOperator::Negate, crate::Scalar::I32) => {
1635 if !self.wrapped.insert(WrappedType::UnaryOp(wrapped)) {
1636 continue;
1637 }
1638
1639 self.write_value_type(module, expr_ty)?;
1640 write!(self.out, " {NEG_FUNCTION}(")?;
1641 self.write_value_type(module, expr_ty)?;
1642 writeln!(self.out, " val) {{")?;
1643
1644 let level = crate::back::Level(1);
1645 writeln!(self.out, "{level}return asint(-asuint(val));",)?;
1646 writeln!(self.out, "}}")?;
1647 writeln!(self.out)?;
1648 }
1649 _ => {}
1650 }
1651 }
1652 }
1653
1654 Ok(())
1655 }
1656
1657 pub(super) fn write_wrapped_binary_ops(
1658 &mut self,
1659 module: &crate::Module,
1660 func_ctx: &FunctionCtx,
1661 ) -> BackendResult {
1662 for (expr_handle, expression) in func_ctx.expressions.iter() {
1663 if let crate::Expression::Binary { op, left, right } = *expression {
1664 let expr_ty = func_ctx.resolve_type(expr_handle, &module.types);
1665 let left_ty = func_ctx.resolve_type(left, &module.types);
1666 let right_ty = func_ctx.resolve_type(right, &module.types);
1667
1668 match (op, expr_ty.scalar()) {
1669 (
1677 crate::BinaryOperator::Divide,
1678 Some(
1679 scalar @ crate::Scalar {
1680 kind: ScalarKind::Sint | ScalarKind::Uint,
1681 ..
1682 },
1683 ),
1684 ) => {
1685 let Some(left_wrapped_ty) = left_ty.vector_size_and_scalar() else {
1686 continue;
1687 };
1688 let Some(right_wrapped_ty) = right_ty.vector_size_and_scalar() else {
1689 continue;
1690 };
1691 let wrapped = WrappedBinaryOp {
1692 op,
1693 left_ty: left_wrapped_ty,
1694 right_ty: right_wrapped_ty,
1695 };
1696 if !self.wrapped.insert(WrappedType::BinaryOp(wrapped)) {
1697 continue;
1698 }
1699
1700 self.write_value_type(module, expr_ty)?;
1701 write!(self.out, " {DIV_FUNCTION}(")?;
1702 self.write_value_type(module, left_ty)?;
1703 write!(self.out, " lhs, ")?;
1704 self.write_value_type(module, right_ty)?;
1705 writeln!(self.out, " rhs) {{")?;
1706 let level = crate::back::Level(1);
1707 match scalar.kind {
1708 ScalarKind::Sint => {
1709 let min_val = match scalar.width {
1710 2 => crate::Literal::I16(i16::MIN),
1711 4 => crate::Literal::I32(i32::MIN),
1712 8 => crate::Literal::I64(i64::MIN),
1713 _ => {
1714 return Err(super::Error::UnsupportedScalar(scalar));
1715 }
1716 };
1717 write!(self.out, "{level}return lhs / (((lhs == ")?;
1718 self.write_literal(min_val)?;
1719 writeln!(self.out, " & rhs == -1) | (rhs == 0)) ? 1 : rhs);")?
1720 }
1721 ScalarKind::Uint => {
1722 writeln!(self.out, "{level}return lhs / (rhs == 0u ? 1u : rhs);")?
1723 }
1724 _ => unreachable!(),
1725 }
1726 writeln!(self.out, "}}")?;
1727 writeln!(self.out)?;
1728 }
1729 (
1742 crate::BinaryOperator::Modulo,
1743 Some(
1744 scalar @ crate::Scalar {
1745 kind: ScalarKind::Sint | ScalarKind::Uint | ScalarKind::Float,
1746 ..
1747 },
1748 ),
1749 ) => {
1750 let Some(left_wrapped_ty) = left_ty.vector_size_and_scalar() else {
1751 continue;
1752 };
1753 let Some(right_wrapped_ty) = right_ty.vector_size_and_scalar() else {
1754 continue;
1755 };
1756 let wrapped = WrappedBinaryOp {
1757 op,
1758 left_ty: left_wrapped_ty,
1759 right_ty: right_wrapped_ty,
1760 };
1761 if !self.wrapped.insert(WrappedType::BinaryOp(wrapped)) {
1762 continue;
1763 }
1764
1765 self.write_value_type(module, expr_ty)?;
1766 write!(self.out, " {MOD_FUNCTION}(")?;
1767 self.write_value_type(module, left_ty)?;
1768 write!(self.out, " lhs, ")?;
1769 self.write_value_type(module, right_ty)?;
1770 writeln!(self.out, " rhs) {{")?;
1771 let level = crate::back::Level(1);
1772 match scalar.kind {
1773 ScalarKind::Sint => {
1774 let min_val = match scalar.width {
1775 2 => crate::Literal::I16(i16::MIN),
1776 4 => crate::Literal::I32(i32::MIN),
1777 8 => crate::Literal::I64(i64::MIN),
1778 _ => {
1779 return Err(super::Error::UnsupportedScalar(scalar));
1780 }
1781 };
1782 write!(self.out, "{level}")?;
1783 self.write_value_type(module, right_ty)?;
1784 write!(self.out, " divisor = ((lhs == ")?;
1785 self.write_literal(min_val)?;
1786 writeln!(self.out, " & rhs == -1) | (rhs == 0)) ? 1 : rhs;")?;
1787 writeln!(
1788 self.out,
1789 "{level}return lhs - (lhs / divisor) * divisor;"
1790 )?
1791 }
1792 ScalarKind::Uint => {
1793 writeln!(self.out, "{level}return lhs % (rhs == 0u ? 1u : rhs);")?
1794 }
1795 ScalarKind::Float => {
1801 writeln!(self.out, "{level}return lhs - rhs * trunc(lhs / rhs);")?
1802 }
1803 _ => unreachable!(),
1804 }
1805 writeln!(self.out, "}}")?;
1806 writeln!(self.out)?;
1807 }
1808 _ => {}
1809 }
1810 }
1811 }
1812
1813 Ok(())
1814 }
1815
1816 fn write_wrapped_cast_functions(
1817 &mut self,
1818 module: &crate::Module,
1819 func_ctx: &FunctionCtx,
1820 ) -> BackendResult {
1821 for (_, expression) in func_ctx.expressions.iter() {
1822 if let crate::Expression::As {
1823 expr,
1824 target: dst_scalar,
1825 } = *expression
1826 {
1827 let src_ty = func_ctx.resolve_type(expr, &module.types);
1838 let Some((vector_size, src_scalar)) = src_ty.vector_size_and_scalar() else {
1839 continue;
1840 };
1841 if src_scalar.kind != ScalarKind::Float
1842 || (dst_scalar.kind != ScalarKind::Sint && dst_scalar.kind != ScalarKind::Uint)
1843 {
1844 continue;
1845 }
1846
1847 let wrapped = WrappedCast {
1848 src_scalar,
1849 vector_size,
1850 dst_scalar,
1851 };
1852 if !self.wrapped.insert(WrappedType::Cast(wrapped)) {
1853 continue;
1854 }
1855
1856 let (src_ty, dst_ty) = match vector_size {
1857 None => (
1858 crate::TypeInner::Scalar(src_scalar),
1859 crate::TypeInner::Scalar(dst_scalar),
1860 ),
1861 Some(vector_size) => (
1862 crate::TypeInner::Vector {
1863 scalar: src_scalar,
1864 size: vector_size,
1865 },
1866 crate::TypeInner::Vector {
1867 scalar: dst_scalar,
1868 size: vector_size,
1869 },
1870 ),
1871 };
1872 let (min, max) =
1873 crate::proc::min_max_float_representable_by(src_scalar, dst_scalar);
1874 let cast_str = format!(
1875 "{}{}",
1876 dst_scalar.to_hlsl_str()?,
1877 vector_size
1878 .map(crate::common::vector_size_str)
1879 .unwrap_or(""),
1880 );
1881 let fun_name = match dst_scalar {
1882 crate::Scalar::I32 => F2I32_FUNCTION,
1883 crate::Scalar::U32 => F2U32_FUNCTION,
1884 crate::Scalar::I64 => F2I64_FUNCTION,
1885 crate::Scalar::U64 => F2U64_FUNCTION,
1886 _ => unreachable!(),
1887 };
1888 self.write_value_type(module, &dst_ty)?;
1889 write!(self.out, " {fun_name}(")?;
1890 self.write_value_type(module, &src_ty)?;
1891 writeln!(self.out, " value) {{")?;
1892 let level = crate::back::Level(1);
1893 write!(self.out, "{level}return {cast_str}(clamp(value, ")?;
1894 self.write_literal(min)?;
1895 write!(self.out, ", ")?;
1896 self.write_literal(max)?;
1897 writeln!(self.out, "));",)?;
1898 writeln!(self.out, "}}")?;
1899 writeln!(self.out)?;
1900 }
1901 }
1902 Ok(())
1903 }
1904
1905 fn write_wrapped_bitcast_functions(
1908 &mut self,
1909 module: &crate::Module,
1910 func_ctx: &FunctionCtx,
1911 ) -> BackendResult {
1912 use crate::ScalarKind as Sk;
1913
1914 for (_, expression) in func_ctx.expressions.iter() {
1915 let crate::Expression::Bitcast { expr, ty } = *expression else {
1916 continue;
1917 };
1918 let src_ty = func_ctx.resolve_type(expr, &module.types);
1919 let dst_ty = &module.types[ty].inner;
1920 let Some(wrapped) = WrappedBitcast::new(src_ty, dst_ty) else {
1921 continue;
1922 };
1923 if !self.wrapped.insert(WrappedType::Bitcast(wrapped)) {
1924 continue;
1925 }
1926
1927 let fun_name = wrapped.function_name()?;
1928 self.write_value_type(module, dst_ty)?;
1929 write!(self.out, " {fun_name}(")?;
1930 self.write_value_type(module, src_ty)?;
1931 writeln!(self.out, " value) {{")?;
1932 let level = crate::back::Level(1);
1933
1934 match (wrapped.src, wrapped.dst) {
1935 ((Some(src_size), crate::Scalar::F16), (dst_size, dst)) if dst.width == 4 => {
1937 writeln!(
1938 self.out,
1939 "{level}uint16_t{} bits = asuint16(value);",
1940 src_size as u8
1941 )?;
1942 let word =
1943 |lo: &str, hi: &str| format!("(uint(bits.{lo}) | (uint(bits.{hi}) << 16))");
1944 let packed = if dst_size.is_none() {
1945 word("x", "y")
1946 } else {
1947 format!("uint2({}, {})", word("x", "y"), word("z", "w"))
1948 };
1949 if dst.kind == Sk::Uint {
1950 writeln!(self.out, "{level}return {packed};")?;
1951 } else {
1952 writeln!(
1953 self.out,
1954 "{level}return {}({packed});",
1955 dst.kind.to_hlsl_cast()
1956 )?;
1957 }
1958 }
1959 ((src_size, src), (Some(dst_size), crate::Scalar::F16)) if src.width == 4 => {
1961 let (bits_ty, words) = match src_size {
1962 None => ("uint", &[""][..]),
1963 Some(_) => ("uint2", &[".x", ".y"][..]),
1964 };
1965 if src.kind == Sk::Uint {
1966 writeln!(self.out, "{level}{bits_ty} bits = value;")?;
1967 } else {
1968 writeln!(self.out, "{level}{bits_ty} bits = asuint(value);")?;
1969 }
1970 write!(
1971 self.out,
1972 "{level}return asfloat16(uint16_t{}(",
1973 dst_size as u8
1974 )?;
1975 for (i, word) in words.iter().enumerate() {
1976 if i != 0 {
1977 write!(self.out, ", ")?;
1978 }
1979 write!(
1980 self.out,
1981 "uint16_t(bits{word} & 0xFFFFu), uint16_t(bits{word} >> 16)"
1982 )?;
1983 }
1984 writeln!(self.out, "));")?;
1985 }
1986 _ => {
1987 return Err(super::Error::Unimplemented(format!(
1988 "bitcast from {src_ty:?} to {dst_ty:?}"
1989 )))
1990 }
1991 }
1992 writeln!(self.out, "}}")?;
1993 writeln!(self.out)?;
1994 }
1995 Ok(())
1996 }
1997
1998 pub(super) fn write_wrapped_functions(
2000 &mut self,
2001 module: &crate::Module,
2002 func_ctx: &FunctionCtx,
2003 ) -> BackendResult {
2004 self.write_wrapped_math_functions(module, func_ctx)?;
2005 self.write_wrapped_unary_ops(module, func_ctx)?;
2006 self.write_wrapped_binary_ops(module, func_ctx)?;
2007 self.write_wrapped_expression_functions(module, func_ctx.expressions, Some(func_ctx))?;
2008 self.write_wrapped_zero_value_functions(module, func_ctx.expressions)?;
2009 self.write_wrapped_cast_functions(module, func_ctx)?;
2010 self.write_wrapped_bitcast_functions(module, func_ctx)?;
2011
2012 for (handle, _) in func_ctx.expressions.iter() {
2013 match func_ctx.expressions[handle] {
2014 crate::Expression::ArrayLength(expr) => {
2015 let global_expr = match func_ctx.expressions[expr] {
2016 crate::Expression::GlobalVariable(_) => expr,
2017 crate::Expression::AccessIndex { base, index: _ } => base,
2018 ref other => unreachable!("Array length of {:?}", other),
2019 };
2020 let global_var = match func_ctx.expressions[global_expr] {
2021 crate::Expression::GlobalVariable(var_handle) => {
2022 &module.global_variables[var_handle]
2023 }
2024 ref other => {
2025 return Err(super::Error::Unimplemented(format!(
2026 "Array length of base {other:?}"
2027 )))
2028 }
2029 };
2030 let storage_access = match global_var.space {
2031 crate::AddressSpace::Storage { access } => access,
2032 _ => crate::StorageAccess::default(),
2033 };
2034 let wal = WrappedArrayLength {
2035 writable: storage_access.contains(crate::StorageAccess::STORE),
2036 };
2037
2038 if self.wrapped.insert(WrappedType::ArrayLength(wal)) {
2039 self.write_wrapped_array_length_function(wal)?;
2040 }
2041 }
2042 crate::Expression::ImageLoad { image, .. } => {
2043 let class = match *func_ctx.resolve_type(image, &module.types) {
2044 crate::TypeInner::Image { class, .. } => class,
2045 _ => unreachable!(),
2046 };
2047 let wrapped = WrappedImageLoad { class };
2048 if self.wrapped.insert(WrappedType::ImageLoad(wrapped)) {
2049 self.write_wrapped_image_load_function(module, wrapped)?;
2050 }
2051 }
2052 crate::Expression::ImageSample {
2053 image,
2054 clamp_to_edge,
2055 ..
2056 } => {
2057 let class = match *func_ctx.resolve_type(image, &module.types) {
2058 crate::TypeInner::Image { class, .. } => class,
2059 _ => unreachable!(),
2060 };
2061 let wrapped = WrappedImageSample {
2062 class,
2063 clamp_to_edge,
2064 };
2065 if self.wrapped.insert(WrappedType::ImageSample(wrapped)) {
2066 self.write_wrapped_image_sample_function(module, wrapped)?;
2067 }
2068 }
2069 crate::Expression::ImageQuery { image, query } => {
2070 let wiq = match *func_ctx.resolve_type(image, &module.types) {
2071 crate::TypeInner::Image {
2072 dim,
2073 arrayed,
2074 class,
2075 } => WrappedImageQuery {
2076 dim,
2077 arrayed,
2078 class,
2079 query: query.into(),
2080 },
2081 _ => unreachable!("we only query images"),
2082 };
2083
2084 if self.wrapped.insert(WrappedType::ImageQuery(wiq)) {
2085 self.write_wrapped_image_query_function(module, wiq, handle, func_ctx)?;
2086 }
2087 }
2088 crate::Expression::Load { pointer } => {
2091 let pointer_space = func_ctx
2092 .resolve_type(pointer, &module.types)
2093 .pointer_space();
2094
2095 if let Some(crate::AddressSpace::Storage { .. }) = pointer_space {
2096 if let Some(ty) = func_ctx.info[handle].ty.handle() {
2097 self.write_wrapped_constructors_for_type(module, ty)?;
2098 }
2099 }
2100 }
2101 crate::Expression::AccessIndex { base, index } => {
2106 let base_ty_res = &func_ctx.info[base].ty;
2107 let mut resolved = base_ty_res.inner_with(&module.types);
2108 let base_ty_handle = match *resolved {
2109 crate::TypeInner::Pointer { base, .. } => {
2110 resolved = &module.types[base].inner;
2111 Some(base)
2112 }
2113 _ => base_ty_res.handle(),
2114 };
2115 if let crate::TypeInner::Struct { ref members, .. } = *resolved {
2116 let member = &members[index as usize];
2117
2118 match module.types[member.ty].inner {
2119 crate::TypeInner::Matrix {
2120 rows: crate::VectorSize::Bi,
2121 ..
2122 } if member.binding.is_none() => {
2123 let ty = base_ty_handle.unwrap();
2124 let access = WrappedStructMatrixAccess { ty, index };
2125
2126 if self.wrapped.insert(WrappedType::StructMatrixAccess(access)) {
2127 self.write_wrapped_struct_matrix_get_function(module, access)?;
2128 self.write_wrapped_struct_matrix_set_function(module, access)?;
2129 self.write_wrapped_struct_matrix_set_vec_function(
2130 module, access,
2131 )?;
2132 self.write_wrapped_struct_matrix_set_scalar_function(
2133 module, access,
2134 )?;
2135 }
2136 }
2137 _ => {}
2138 }
2139 }
2140 }
2141 _ => {}
2142 };
2143 }
2144
2145 Ok(())
2146 }
2147
2148 pub(super) fn write_sampler_heaps(&mut self) -> BackendResult {
2150 if self.wrapped.sampler_heaps {
2151 return Ok(());
2152 }
2153
2154 writeln!(
2155 self.out,
2156 "SamplerState {}[2048]: register(s{}, space{});",
2157 super::writer::SAMPLER_HEAP_VAR,
2158 self.options.sampler_heap_target.standard_samplers.register,
2159 self.options.sampler_heap_target.standard_samplers.space
2160 )?;
2161 writeln!(
2162 self.out,
2163 "SamplerComparisonState {}[2048]: register(s{}, space{});",
2164 super::writer::COMPARISON_SAMPLER_HEAP_VAR,
2165 self.options
2166 .sampler_heap_target
2167 .comparison_samplers
2168 .register,
2169 self.options.sampler_heap_target.comparison_samplers.space
2170 )?;
2171
2172 self.wrapped.sampler_heaps = true;
2173
2174 Ok(())
2175 }
2176
2177 pub(super) fn write_wrapped_sampler_buffer(
2179 &mut self,
2180 key: super::SamplerIndexBufferKey,
2181 ) -> BackendResult {
2182 if self.wrapped.sampler_index_buffers.contains_key(&key) {
2189 return Ok(());
2190 };
2191
2192 self.write_sampler_heaps()?;
2193
2194 let sampler_array_name = self
2197 .namer
2198 .call(&format!("nagaGroup{}SamplerIndexArray", key.group));
2199
2200 let bind_target = match self.options.sampler_buffer_binding_map.get(&key) {
2201 Some(&bind_target) => bind_target,
2202 None if self.options.fake_missing_bindings => super::BindTarget {
2203 space: u8::MAX,
2204 register: key.group,
2205 binding_array_size: None,
2206 dynamic_storage_buffer_offsets_index: None,
2207 restrict_indexing: false,
2208 },
2209 None => {
2210 unreachable!("Sampler buffer of group {key:?} not bound to a register");
2211 }
2212 };
2213
2214 writeln!(
2215 self.out,
2216 "StructuredBuffer<uint> {sampler_array_name} : register(t{}, space{});",
2217 bind_target.register, bind_target.space
2218 )?;
2219
2220 self.wrapped
2221 .sampler_index_buffers
2222 .insert(key, sampler_array_name);
2223
2224 Ok(())
2225 }
2226
2227 pub(super) fn write_texture_coordinates(
2228 &mut self,
2229 kind: &str,
2230 coordinate: Handle<crate::Expression>,
2231 array_index: Option<Handle<crate::Expression>>,
2232 mip_level: Option<Handle<crate::Expression>>,
2233 module: &crate::Module,
2234 func_ctx: &FunctionCtx,
2235 ) -> BackendResult {
2236 let extra = array_index.is_some() as usize + (mip_level.is_some()) as usize;
2238 if extra == 0 {
2239 self.write_expr(module, coordinate, func_ctx)?;
2240 } else {
2241 let num_coords = match *func_ctx.resolve_type(coordinate, &module.types) {
2242 crate::TypeInner::Scalar { .. } => 1,
2243 crate::TypeInner::Vector { size, .. } => size as usize,
2244 _ => unreachable!(),
2245 };
2246 write!(self.out, "{}{}(", kind, num_coords + extra)?;
2247 self.write_expr(module, coordinate, func_ctx)?;
2248 if let Some(expr) = array_index {
2249 write!(self.out, ", ")?;
2250 self.write_expr(module, expr, func_ctx)?;
2251 }
2252 if let Some(expr) = mip_level {
2253 let cast_to_int = matches!(
2255 *func_ctx.resolve_type(expr, &module.types),
2256 crate::TypeInner::Scalar(crate::Scalar {
2257 kind: ScalarKind::Uint,
2258 ..
2259 })
2260 );
2261
2262 write!(self.out, ", ")?;
2263
2264 if cast_to_int {
2265 write!(self.out, "int(")?;
2266 }
2267
2268 self.write_expr(module, expr, func_ctx)?;
2269
2270 if cast_to_int {
2271 write!(self.out, ")")?;
2272 }
2273 }
2274 write!(self.out, ")")?;
2275 }
2276 Ok(())
2277 }
2278
2279 pub(super) fn write_mat_cx2_typedef_and_functions(
2280 &mut self,
2281 WrappedMatCx2 { columns, width }: WrappedMatCx2,
2282 ) -> BackendResult {
2283 use crate::back::INDENT;
2284
2285 let bit_width = width * 8;
2286 let type_name = crate::Scalar {
2287 kind: ScalarKind::Float,
2288 width,
2289 }
2290 .to_hlsl_str()?;
2291
2292 write!(self.out, "typedef struct {{ ")?;
2294 for i in 0..columns as u8 {
2295 write!(self.out, "{type_name}2 _{i}; ")?;
2296 }
2297 writeln!(self.out, "}} __mat{}x2_f{bit_width};", columns as u8)?;
2298
2299 writeln!(
2301 self.out,
2302 "{type_name}2 __get_col_of_mat{}x2_f{bit_width}(__mat{}x2_f{bit_width} mat, uint idx) {{",
2303 columns as u8, columns as u8
2304 )?;
2305 writeln!(self.out, "{INDENT}switch(idx) {{")?;
2306 for i in 0..columns as u8 {
2307 writeln!(self.out, "{INDENT}case {i}: {{ return mat._{i}; }}")?;
2308 }
2309 writeln!(self.out, "{INDENT}default: {{ return ({type_name}2)0; }}")?;
2310 writeln!(self.out, "{INDENT}}}")?;
2311 writeln!(self.out, "}}")?;
2312
2313 writeln!(
2315 self.out,
2316 "void __set_col_of_mat{}x2_f{bit_width}(__mat{}x2_f{bit_width} mat, uint idx, {type_name}2 value) {{",
2317 columns as u8, columns as u8
2318 )?;
2319 writeln!(self.out, "{INDENT}switch(idx) {{")?;
2320 for i in 0..columns as u8 {
2321 writeln!(self.out, "{INDENT}case {i}: {{ mat._{i} = value; break; }}")?;
2322 }
2323 writeln!(self.out, "{INDENT}}}")?;
2324 writeln!(self.out, "}}")?;
2325
2326 writeln!(
2328 self.out,
2329 "void __set_el_of_mat{}x2_f{bit_width}(__mat{}x2_f{bit_width} mat, uint idx, uint vec_idx, {type_name} value) {{",
2330 columns as u8, columns as u8
2331 )?;
2332 writeln!(self.out, "{INDENT}switch(idx) {{")?;
2333 for i in 0..columns as u8 {
2334 writeln!(
2335 self.out,
2336 "{INDENT}case {i}: {{ mat._{i}[vec_idx] = value; break; }}"
2337 )?;
2338 }
2339 writeln!(self.out, "{INDENT}}}")?;
2340 writeln!(self.out, "}}")?;
2341
2342 writeln!(self.out)?;
2343
2344 Ok(())
2345 }
2346
2347 pub(super) fn write_all_mat_cx2_typedefs_and_functions(
2348 &mut self,
2349 module: &crate::Module,
2350 ) -> BackendResult {
2351 for (handle, _) in module.global_variables.iter() {
2352 let global = &module.global_variables[handle];
2353
2354 if global.space == crate::AddressSpace::Uniform {
2355 if let Some(super::writer::MatrixType {
2356 columns,
2357 rows: crate::VectorSize::Bi,
2358 width,
2359 }) = super::writer::get_inner_matrix_data(module, global.ty)
2360 {
2361 let entry = WrappedMatCx2 { columns, width };
2362 if self.wrapped.insert(WrappedType::MatCx2(entry)) {
2363 self.write_mat_cx2_typedef_and_functions(entry)?;
2364 }
2365 }
2366 }
2367 }
2368
2369 for (_, ty) in module.types.iter() {
2370 if let crate::TypeInner::Struct { ref members, .. } = ty.inner {
2371 for member in members.iter() {
2372 if let crate::TypeInner::Array { .. } = module.types[member.ty].inner {
2373 if let Some(super::writer::MatrixType {
2374 columns,
2375 rows: crate::VectorSize::Bi,
2376 width,
2377 }) = super::writer::get_inner_matrix_data(module, member.ty)
2378 {
2379 let entry = WrappedMatCx2 { columns, width };
2380 if self.wrapped.insert(WrappedType::MatCx2(entry)) {
2381 self.write_mat_cx2_typedef_and_functions(entry)?;
2382 }
2383 }
2384 }
2385 }
2386 }
2387 }
2388
2389 Ok(())
2390 }
2391
2392 pub(super) fn write_wrapped_zero_value_function_name(
2393 &mut self,
2394 module: &crate::Module,
2395 zero_value: WrappedZeroValue,
2396 ) -> BackendResult {
2397 let name = crate::TypeInner::hlsl_type_id(zero_value.ty, module.to_ctx(), &self.names)?;
2398 write!(self.out, "ZeroValue{name}")?;
2399 Ok(())
2400 }
2401
2402 fn write_wrapped_zero_value_function(
2418 &mut self,
2419 module: &crate::Module,
2420 zero_value: WrappedZeroValue,
2421 ) -> BackendResult {
2422 use crate::back::INDENT;
2423
2424 if let crate::TypeInner::Array { base, size, .. } = module.types[zero_value.ty].inner {
2426 write!(self.out, "typedef ")?;
2427 self.write_type(module, zero_value.ty)?;
2428 write!(self.out, " ret_")?;
2429 self.write_wrapped_zero_value_function_name(module, zero_value)?;
2430 self.write_array_size(module, base, size)?;
2431 writeln!(self.out, ";")?;
2432
2433 write!(self.out, "ret_")?;
2434 self.write_wrapped_zero_value_function_name(module, zero_value)?;
2435 } else {
2436 self.write_type(module, zero_value.ty)?;
2437 }
2438 write!(self.out, " ")?;
2439 self.write_wrapped_zero_value_function_name(module, zero_value)?;
2440
2441 writeln!(self.out, "() {{")?;
2443
2444 write!(self.out, "{INDENT}return ")?;
2446 self.write_default_init(module, zero_value.ty)?;
2447 writeln!(self.out, ";")?;
2448
2449 writeln!(self.out, "}}")?;
2451 writeln!(self.out)?;
2453
2454 Ok(())
2455 }
2456}
2457
2458impl crate::StorageFormat {
2459 pub(super) const fn single_component(&self) -> bool {
2461 match *self {
2462 crate::StorageFormat::R16Float
2463 | crate::StorageFormat::R32Float
2464 | crate::StorageFormat::R8Unorm
2465 | crate::StorageFormat::R16Unorm
2466 | crate::StorageFormat::R8Snorm
2467 | crate::StorageFormat::R16Snorm
2468 | crate::StorageFormat::R8Uint
2469 | crate::StorageFormat::R16Uint
2470 | crate::StorageFormat::R32Uint
2471 | crate::StorageFormat::R8Sint
2472 | crate::StorageFormat::R16Sint
2473 | crate::StorageFormat::R32Sint
2474 | crate::StorageFormat::R64Uint => true,
2475 _ => false,
2476 }
2477 }
2478}