1use alloc::format;
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)]
154pub(super) enum ImageQuery {
155 Size,
156 SizeLevel,
157 NumLevels,
158 NumLayers,
159 NumSamples,
160}
161
162impl From<crate::ImageQuery> for ImageQuery {
163 fn from(q: crate::ImageQuery) -> Self {
164 use crate::ImageQuery as Iq;
165 match q {
166 Iq::Size { level: Some(_) } => ImageQuery::SizeLevel,
167 Iq::Size { level: None } => ImageQuery::Size,
168 Iq::NumLevels => ImageQuery::NumLevels,
169 Iq::NumLayers => ImageQuery::NumLayers,
170 Iq::NumSamples => ImageQuery::NumSamples,
171 }
172 }
173}
174
175pub(super) const IMAGE_STORAGE_LOAD_SCALAR_WRAPPER: &str = "LoadedStorageValueFrom";
176
177impl<W: Write> super::Writer<'_, W> {
178 pub(super) fn write_image_type(
179 &mut self,
180 dim: crate::ImageDimension,
181 arrayed: bool,
182 class: crate::ImageClass,
183 ) -> BackendResult {
184 let access_str = match class {
185 crate::ImageClass::Storage { .. } => "RW",
186 _ => "",
187 };
188 let dim_str = dim.to_hlsl_str();
189 let arrayed_str = if arrayed { "Array" } else { "" };
190 write!(self.out, "{access_str}Texture{dim_str}{arrayed_str}")?;
191 match class {
192 crate::ImageClass::Depth { multi } => {
193 let multi_str = if multi { "MS" } else { "" };
194 write!(self.out, "{multi_str}<float>")?
195 }
196 crate::ImageClass::Sampled { kind, multi } => {
197 let multi_str = if multi { "MS" } else { "" };
198 let scalar_kind_str = crate::Scalar { kind, width: 4 }.to_hlsl_str()?;
199 write!(self.out, "{multi_str}<{scalar_kind_str}4>")?
200 }
201 crate::ImageClass::Storage { format, .. } => {
202 let storage_format_str = format.to_hlsl_str();
203 write!(self.out, "<{storage_format_str}>")?
204 }
205 crate::ImageClass::External => {
206 unreachable!(
207 "external images should be handled by `write_global_external_texture`"
208 );
209 }
210 }
211 Ok(())
212 }
213
214 pub(super) fn write_wrapped_array_length_function_name(
215 &mut self,
216 query: WrappedArrayLength,
217 ) -> BackendResult {
218 let access_str = if query.writable { "RW" } else { "" };
219 write!(self.out, "NagaBufferLength{access_str}",)?;
220
221 Ok(())
222 }
223
224 pub(super) fn write_wrapped_array_length_function(
228 &mut self,
229 wal: WrappedArrayLength,
230 ) -> BackendResult {
231 use crate::back::INDENT;
232
233 const ARGUMENT_VARIABLE_NAME: &str = "buffer";
234 const RETURN_VARIABLE_NAME: &str = "ret";
235
236 write!(self.out, "uint ")?;
238 self.write_wrapped_array_length_function_name(wal)?;
239
240 write!(self.out, "(")?;
242 let access_str = if wal.writable { "RW" } else { "" };
243 writeln!(
244 self.out,
245 "{access_str}ByteAddressBuffer {ARGUMENT_VARIABLE_NAME})"
246 )?;
247 writeln!(self.out, "{{")?;
249
250 writeln!(self.out, "{INDENT}uint {RETURN_VARIABLE_NAME};")?;
252 writeln!(
253 self.out,
254 "{INDENT}{ARGUMENT_VARIABLE_NAME}.GetDimensions({RETURN_VARIABLE_NAME});"
255 )?;
256
257 writeln!(self.out, "{INDENT}return {RETURN_VARIABLE_NAME};")?;
259
260 writeln!(self.out, "}}")?;
262 writeln!(self.out)?;
264
265 Ok(())
266 }
267
268 fn write_convert_yuv_to_rgb_and_return(
276 &mut self,
277 level: crate::back::Level,
278 y: &str,
279 uv: &str,
280 params: &str,
281 ) -> BackendResult {
282 let l1 = level;
283 let l2 = l1.next();
284
285 writeln!(
289 self.out,
290 "{l1}float3 srcGammaRgb = mul(float4({y}, {uv}, 1.0), {params}.yuv_conversion_matrix).rgb;"
291 )?;
292
293 writeln!(
296 self.out,
297 "{l1}float3 srcLinearRgb = srcGammaRgb < {params}.src_tf.k * {params}.src_tf.b ?"
298 )?;
299 writeln!(self.out, "{l2}srcGammaRgb / {params}.src_tf.k :")?;
300 writeln!(self.out, "{l2}pow((srcGammaRgb + {params}.src_tf.a - 1.0) / {params}.src_tf.a, {params}.src_tf.g);")?;
301
302 writeln!(
306 self.out,
307 "{l1}float3 dstLinearRgb = mul(srcLinearRgb, {params}.gamut_conversion_matrix);"
308 )?;
309
310 writeln!(
313 self.out,
314 "{l1}float3 dstGammaRgb = dstLinearRgb < {params}.dst_tf.b ?"
315 )?;
316 writeln!(self.out, "{l2}{params}.dst_tf.k * dstLinearRgb :")?;
317 writeln!(self.out, "{l2}{params}.dst_tf.a * pow(dstLinearRgb, 1.0 / {params}.dst_tf.g) - ({params}.dst_tf.a - 1);")?;
318
319 writeln!(self.out, "{l1}return float4(dstGammaRgb, 1.0);")?;
320 Ok(())
321 }
322
323 pub(super) fn write_wrapped_image_load_function(
324 &mut self,
325 module: &crate::Module,
326 load: WrappedImageLoad,
327 ) -> BackendResult {
328 match load {
329 WrappedImageLoad {
330 class: crate::ImageClass::External,
331 } => {
332 let l1 = crate::back::Level(1);
333 let l2 = l1.next();
334 let l3 = l2.next();
335 let params_ty_name = &self.names
336 [&NameKey::Type(module.special_types.external_texture_params.unwrap())];
337 writeln!(self.out, "float4 {IMAGE_LOAD_EXTERNAL_FUNCTION}(")?;
338 writeln!(self.out, "{l1}Texture2D<float4> plane0,")?;
339 writeln!(self.out, "{l1}Texture2D<float4> plane1,")?;
340 writeln!(self.out, "{l1}Texture2D<float4> plane2,")?;
341 writeln!(self.out, "{l1}{params_ty_name} params,")?;
342 writeln!(self.out, "{l1}uint2 coords)")?;
343 writeln!(self.out, "{{")?;
344 writeln!(self.out, "{l1}uint2 plane0_size;")?;
345 writeln!(
346 self.out,
347 "{l1}plane0.GetDimensions(plane0_size.x, plane0_size.y);"
348 )?;
349 writeln!(
352 self.out,
353 "{l1}uint2 cropped_size = any(params.size) ? params.size : plane0_size;"
354 )?;
355 writeln!(self.out, "{l1}coords = min(coords, cropped_size - 1);")?;
356
357 writeln!(self.out, "{l1}float3x2 load_transform = float3x2(")?;
360 writeln!(self.out, "{l2}params.load_transform_0,")?;
361 writeln!(self.out, "{l2}params.load_transform_1,")?;
362 writeln!(self.out, "{l2}params.load_transform_2")?;
363 writeln!(self.out, "{l1});")?;
364 writeln!(self.out, "{l1}uint2 plane0_coords = uint2(round(mul(float3(coords, 1.0), load_transform)));")?;
365 writeln!(self.out, "{l1}if (params.num_planes == 1u) {{")?;
366 writeln!(
368 self.out,
369 "{l2}return plane0.Load(uint3(plane0_coords, 0u));"
370 )?;
371 writeln!(self.out, "{l1}}} else {{")?;
372
373 writeln!(self.out, "{l2}uint2 plane1_size;")?;
375 writeln!(
376 self.out,
377 "{l2}plane1.GetDimensions(plane1_size.x, plane1_size.y);"
378 )?;
379 writeln!(self.out, "{l2}uint2 plane1_coords = uint2(floor(float2(plane0_coords) * float2(plane1_size) / float2(plane0_size)));")?;
380
381 writeln!(
383 self.out,
384 "{l2}float y = plane0.Load(uint3(plane0_coords, 0u)).x;"
385 )?;
386
387 writeln!(self.out, "{l2}float2 uv;")?;
388 writeln!(self.out, "{l2}if (params.num_planes == 2u) {{")?;
389 writeln!(
391 self.out,
392 "{l3}uv = plane1.Load(uint3(plane1_coords, 0u)).xy;"
393 )?;
394 writeln!(self.out, "{l2}}} else {{")?;
395 writeln!(self.out, "{l3}uint2 plane2_size;")?;
397 writeln!(
398 self.out,
399 "{l3}plane2.GetDimensions(plane2_size.x, plane2_size.y);"
400 )?;
401 writeln!(self.out, "{l3}uint2 plane2_coords = uint2(floor(float2(plane0_coords) * float2(plane2_size) / float2(plane0_size)));")?;
402 writeln!(self.out, "{l3}uv = float2(plane1.Load(uint3(plane1_coords, 0u)).x, plane2.Load(uint3(plane2_coords, 0u)).x);")?;
403 writeln!(self.out, "{l2}}}")?;
404
405 self.write_convert_yuv_to_rgb_and_return(l2, "y", "uv", "params")?;
406
407 writeln!(self.out, "{l1}}}")?;
408 writeln!(self.out, "}}")?;
409 writeln!(self.out)?;
410 }
411 _ => {}
412 }
413
414 Ok(())
415 }
416
417 pub(super) fn write_wrapped_image_sample_function(
418 &mut self,
419 module: &crate::Module,
420 sample: WrappedImageSample,
421 ) -> BackendResult {
422 match sample {
423 WrappedImageSample {
424 class: crate::ImageClass::External,
425 clamp_to_edge: true,
426 } => {
427 let l1 = crate::back::Level(1);
428 let l2 = l1.next();
429 let l3 = l2.next();
430 let params_ty_name = &self.names
431 [&NameKey::Type(module.special_types.external_texture_params.unwrap())];
432 writeln!(
433 self.out,
434 "float4 {IMAGE_SAMPLE_BASE_CLAMP_TO_EDGE_FUNCTION}("
435 )?;
436 writeln!(self.out, "{l1}Texture2D<float4> plane0,")?;
437 writeln!(self.out, "{l1}Texture2D<float4> plane1,")?;
438 writeln!(self.out, "{l1}Texture2D<float4> plane2,")?;
439 writeln!(self.out, "{l1}{params_ty_name} params,")?;
440 writeln!(self.out, "{l1}SamplerState samp,")?;
441 writeln!(self.out, "{l1}float2 coords)")?;
442 writeln!(self.out, "{{")?;
443 writeln!(self.out, "{l1}float2 plane0_size;")?;
444 writeln!(
445 self.out,
446 "{l1}plane0.GetDimensions(plane0_size.x, plane0_size.y);"
447 )?;
448 writeln!(self.out, "{l1}float3x2 sample_transform = float3x2(")?;
449 writeln!(self.out, "{l2}params.sample_transform_0,")?;
450 writeln!(self.out, "{l2}params.sample_transform_1,")?;
451 writeln!(self.out, "{l2}params.sample_transform_2")?;
452 writeln!(self.out, "{l1});")?;
453 writeln!(
456 self.out,
457 "{l1}coords = mul(float3(coords, 1.0), sample_transform);"
458 )?;
459 writeln!(
467 self.out,
468 "{l1}float2 bounds_min = mul(float3(0.0, 0.0, 1.0), sample_transform);"
469 )?;
470 writeln!(
471 self.out,
472 "{l1}float2 bounds_max = mul(float3(1.0, 1.0, 1.0), sample_transform);"
473 )?;
474 writeln!(self.out, "{l1}float4 bounds = float4(min(bounds_min, bounds_max), max(bounds_min, bounds_max));")?;
475 writeln!(
476 self.out,
477 "{l1}float2 plane0_half_texel = float2(0.5, 0.5) / plane0_size;"
478 )?;
479 writeln!(
480 self.out,
481 "{l1}float2 plane0_coords = clamp(coords, bounds.xy + plane0_half_texel, bounds.zw - plane0_half_texel);"
482 )?;
483 writeln!(self.out, "{l1}if (params.num_planes == 1u) {{")?;
484 writeln!(
486 self.out,
487 "{l2}return plane0.SampleLevel(samp, plane0_coords, 0.0f);"
488 )?;
489 writeln!(self.out, "{l1}}} else {{")?;
490
491 writeln!(self.out, "{l2}float2 plane1_size;")?;
492 writeln!(
493 self.out,
494 "{l2}plane1.GetDimensions(plane1_size.x, plane1_size.y);"
495 )?;
496 writeln!(
497 self.out,
498 "{l2}float2 plane1_half_texel = float2(0.5, 0.5) / plane1_size;"
499 )?;
500 writeln!(
501 self.out,
502 "{l2}float2 plane1_coords = clamp(coords, bounds.xy + plane1_half_texel, bounds.zw - plane1_half_texel);"
503 )?;
504
505 writeln!(
507 self.out,
508 "{l2}float y = plane0.SampleLevel(samp, plane0_coords, 0.0f).x;"
509 )?;
510 writeln!(self.out, "{l2}float2 uv;")?;
511 writeln!(self.out, "{l2}if (params.num_planes == 2u) {{")?;
512 writeln!(
514 self.out,
515 "{l3}uv = plane1.SampleLevel(samp, plane1_coords, 0.0f).xy;"
516 )?;
517 writeln!(self.out, "{l2}}} else {{")?;
518 writeln!(self.out, "{l3}float2 plane2_size;")?;
520 writeln!(
521 self.out,
522 "{l3}plane2.GetDimensions(plane2_size.x, plane2_size.y);"
523 )?;
524 writeln!(
525 self.out,
526 "{l3}float2 plane2_half_texel = float2(0.5, 0.5) / plane2_size;"
527 )?;
528 writeln!(self.out, "{l3}float2 plane2_coords = clamp(coords, bounds.xy + plane2_half_texel, bounds.zw - plane2_half_texel);")?;
529 writeln!(self.out, "{l3}uv = float2(plane1.SampleLevel(samp, plane1_coords, 0.0f).x, plane2.SampleLevel(samp, plane2_coords, 0.0f).x);")?;
530 writeln!(self.out, "{l2}}}")?;
531
532 self.write_convert_yuv_to_rgb_and_return(l2, "y", "uv", "params")?;
533
534 writeln!(self.out, "{l1}}}")?;
535 writeln!(self.out, "}}")?;
536 writeln!(self.out)?;
537 }
538 WrappedImageSample {
539 class:
540 crate::ImageClass::Sampled {
541 kind: ScalarKind::Float,
542 multi: false,
543 },
544 clamp_to_edge: true,
545 } => {
546 writeln!(self.out, "float4 {IMAGE_SAMPLE_BASE_CLAMP_TO_EDGE_FUNCTION}(Texture2D<float4> tex, SamplerState samp, float2 coords) {{")?;
547 let l1 = crate::back::Level(1);
548 writeln!(self.out, "{l1}float2 size;")?;
549 writeln!(self.out, "{l1}tex.GetDimensions(size.x, size.y);")?;
550 writeln!(self.out, "{l1}float2 half_texel = float2(0.5, 0.5) / size;")?;
551 writeln!(
552 self.out,
553 "{l1}return tex.SampleLevel(samp, clamp(coords, half_texel, 1.0 - half_texel), 0.0);"
554 )?;
555 writeln!(self.out, "}}")?;
556 writeln!(self.out)?;
557 }
558 _ => {}
559 }
560
561 Ok(())
562 }
563
564 pub(super) fn write_wrapped_image_query_function_name(
565 &mut self,
566 query: WrappedImageQuery,
567 ) -> BackendResult {
568 let dim_str = query.dim.to_hlsl_str();
569 let class_str = match query.class {
570 crate::ImageClass::Sampled { multi: true, .. } => "MS",
571 crate::ImageClass::Depth { multi: true } => "DepthMS",
572 crate::ImageClass::Depth { multi: false } => "Depth",
573 crate::ImageClass::Sampled { multi: false, .. } => "",
574 crate::ImageClass::Storage { .. } => "RW",
575 crate::ImageClass::External => "External",
576 };
577 let arrayed_str = if query.arrayed { "Array" } else { "" };
578 let query_str = match query.query {
579 ImageQuery::Size => "Dimensions",
580 ImageQuery::SizeLevel => "MipDimensions",
581 ImageQuery::NumLevels => "NumLevels",
582 ImageQuery::NumLayers => "NumLayers",
583 ImageQuery::NumSamples => "NumSamples",
584 };
585
586 write!(self.out, "Naga{class_str}{query_str}{dim_str}{arrayed_str}")?;
587
588 Ok(())
589 }
590
591 pub(super) fn write_wrapped_image_query_function(
595 &mut self,
596 module: &crate::Module,
597 wiq: WrappedImageQuery,
598 expr_handle: Handle<crate::Expression>,
599 func_ctx: &FunctionCtx,
600 ) -> BackendResult {
601 use crate::{
602 back::{COMPONENTS, INDENT},
603 ImageDimension as IDim,
604 };
605
606 match wiq.class {
607 crate::ImageClass::External => {
608 if wiq.query != ImageQuery::Size {
609 return Err(super::Error::Custom(
610 "External images only support `Size` queries".into(),
611 ));
612 }
613
614 write!(self.out, "uint2 ")?;
615 self.write_wrapped_image_query_function_name(wiq)?;
616 let params_name = &self.names
617 [&NameKey::Type(module.special_types.external_texture_params.unwrap())];
618 writeln!(self.out, "(Texture2D<float4> plane0, Texture2D<float4> plane1, Texture2D<float4> plane2, {params_name} params) {{")?;
622 let l1 = crate::back::Level(1);
623 let l2 = l1.next();
624 writeln!(self.out, "{l1}if (any(params.size)) {{")?;
625 writeln!(self.out, "{l2}return params.size;")?;
626 writeln!(self.out, "{l1}}} else {{")?;
627 writeln!(self.out, "{l2}uint2 ret;")?;
629 writeln!(self.out, "{l2}plane0.GetDimensions(ret.x, ret.y);")?;
630 writeln!(self.out, "{l2}return ret;")?;
631 writeln!(self.out, "{l1}}}")?;
632 writeln!(self.out, "}}")?;
633 writeln!(self.out)?;
634 }
635 _ => {
636 const ARGUMENT_VARIABLE_NAME: &str = "tex";
637 const RETURN_VARIABLE_NAME: &str = "ret";
638 const MIP_LEVEL_PARAM: &str = "mip_level";
639
640 let ret_ty = func_ctx.resolve_type(expr_handle, &module.types);
642 self.write_value_type(module, ret_ty)?;
643 write!(self.out, " ")?;
644 self.write_wrapped_image_query_function_name(wiq)?;
645
646 write!(self.out, "(")?;
648 self.write_image_type(wiq.dim, wiq.arrayed, wiq.class)?;
650 write!(self.out, " {ARGUMENT_VARIABLE_NAME}")?;
651 if let ImageQuery::SizeLevel = wiq.query {
653 write!(self.out, ", uint {MIP_LEVEL_PARAM}")?;
654 }
655 writeln!(self.out, ")")?;
656
657 writeln!(self.out, "{{")?;
659
660 let array_coords = usize::from(wiq.arrayed);
661 let extra_coords = match wiq.class {
663 crate::ImageClass::Storage { .. } => 0,
664 crate::ImageClass::Sampled { .. } | crate::ImageClass::Depth { .. } => 1,
665 crate::ImageClass::External => unreachable!(),
666 };
667
668 let (ret_swizzle, number_of_out_params) = match wiq.query {
672 ImageQuery::Size | ImageQuery::SizeLevel => {
673 let ret = match wiq.dim {
674 IDim::D1 => "x",
675 IDim::D2 => "xy",
676 IDim::D3 => "xyz",
677 IDim::Cube => "xy",
678 };
679 (ret, ret.len() + array_coords + extra_coords)
680 }
681 ImageQuery::NumLevels | ImageQuery::NumSamples => {
682 match wiq.dim {
684 IDim::D1 => ("y", 2),
685 IDim::D3 => ("w", 4),
686 IDim::D2 | IDim::Cube => {
687 if wiq.arrayed {
688 ("w", 4)
689 } else {
690 ("z", 3)
691 }
692 }
693 }
694 }
695 ImageQuery::NumLayers => ("z", 3 + extra_coords),
697 };
698
699 writeln!(self.out, "{INDENT}uint4 {RETURN_VARIABLE_NAME};")?;
701 write!(self.out, "{INDENT}{ARGUMENT_VARIABLE_NAME}.GetDimensions(")?;
702 match wiq.query {
703 ImageQuery::SizeLevel => {
704 write!(self.out, "{MIP_LEVEL_PARAM}, ")?;
705 }
706 _ => match wiq.class {
707 crate::ImageClass::Sampled { multi: true, .. }
708 | crate::ImageClass::Depth { multi: true }
709 | crate::ImageClass::Storage { .. } => {}
710 _ => {
711 write!(self.out, "0, ")?;
713 }
714 },
715 }
716
717 for component in COMPONENTS[..number_of_out_params - 1].iter() {
718 write!(self.out, "{RETURN_VARIABLE_NAME}.{component}, ")?;
719 }
720
721 write!(
723 self.out,
724 "{}.{}",
725 RETURN_VARIABLE_NAME,
726 COMPONENTS[number_of_out_params - 1]
727 )?;
728
729 writeln!(self.out, ");")?;
730
731 writeln!(
733 self.out,
734 "{INDENT}return {RETURN_VARIABLE_NAME}.{ret_swizzle};"
735 )?;
736
737 writeln!(self.out, "}}")?;
739 writeln!(self.out)?;
741 }
742 }
743 Ok(())
744 }
745
746 pub(super) fn write_wrapped_constructor_function_name(
747 &mut self,
748 module: &crate::Module,
749 constructor: WrappedConstructor,
750 ) -> BackendResult {
751 let name = crate::TypeInner::hlsl_type_id(constructor.ty, module.to_ctx(), &self.names)?;
752 write!(self.out, "Construct{name}")?;
753 Ok(())
754 }
755
756 fn write_wrapped_constructor_function(
758 &mut self,
759 module: &crate::Module,
760 constructor: WrappedConstructor,
761 ) -> BackendResult {
762 use crate::back::INDENT;
763
764 const ARGUMENT_VARIABLE_NAME: &str = "arg";
765 const RETURN_VARIABLE_NAME: &str = "ret";
766
767 if let crate::TypeInner::Array { base, size, .. } = module.types[constructor.ty].inner {
769 write!(self.out, "typedef ")?;
770 self.write_type(module, constructor.ty)?;
771 write!(self.out, " ret_")?;
772 self.write_wrapped_constructor_function_name(module, constructor)?;
773 self.write_array_size(module, base, size)?;
774 writeln!(self.out, ";")?;
775
776 write!(self.out, "ret_")?;
777 self.write_wrapped_constructor_function_name(module, constructor)?;
778 } else {
779 self.write_type(module, constructor.ty)?;
780 }
781 write!(self.out, " ")?;
782 self.write_wrapped_constructor_function_name(module, constructor)?;
783
784 write!(self.out, "(")?;
786
787 let mut write_arg = |i, ty| -> BackendResult {
788 if i != 0 {
789 write!(self.out, ", ")?;
790 }
791 self.write_type(module, ty)?;
792 write!(self.out, " {ARGUMENT_VARIABLE_NAME}{i}")?;
793 if let crate::TypeInner::Array { base, size, .. } = module.types[ty].inner {
794 self.write_array_size(module, base, size)?;
795 }
796 Ok(())
797 };
798
799 match module.types[constructor.ty].inner {
800 crate::TypeInner::Struct { ref members, .. } => {
801 for (i, member) in members.iter().enumerate() {
802 write_arg(i, member.ty)?;
803 }
804 }
805 crate::TypeInner::Array {
806 base,
807 size: crate::ArraySize::Constant(size),
808 ..
809 } => {
810 for i in 0..size.get() as usize {
811 write_arg(i, base)?;
812 }
813 }
814 _ => unreachable!(),
815 };
816
817 write!(self.out, ")")?;
818
819 writeln!(self.out, " {{")?;
821
822 match module.types[constructor.ty].inner {
823 crate::TypeInner::Struct { ref members, .. } => {
824 let struct_name = &self.names[&NameKey::Type(constructor.ty)];
825 writeln!(
826 self.out,
827 "{INDENT}{struct_name} {RETURN_VARIABLE_NAME} = ({struct_name})0;"
828 )?;
829 for (i, member) in members.iter().enumerate() {
830 let field_name = &self.names[&NameKey::StructMember(constructor.ty, i as u32)];
831
832 match module.types[member.ty].inner {
833 crate::TypeInner::Matrix {
834 columns,
835 rows: crate::VectorSize::Bi,
836 ..
837 } if member.binding.is_none() => {
838 for j in 0..columns as u8 {
839 writeln!(
840 self.out,
841 "{INDENT}{RETURN_VARIABLE_NAME}.{field_name}_{j} = {ARGUMENT_VARIABLE_NAME}{i}[{j}];"
842 )?;
843 }
844 }
845 ref other => {
846 if let Some(super::writer::MatrixType {
850 columns,
851 rows: crate::VectorSize::Bi,
852 width,
853 }) = super::writer::get_inner_matrix_data(module, member.ty)
854 {
855 write!(
856 self.out,
857 "{}{}.{} = (__mat{}x2_f{}",
858 INDENT,
859 RETURN_VARIABLE_NAME,
860 field_name,
861 columns as u8,
862 width * 8
863 )?;
864 if let crate::TypeInner::Array { base, size, .. } = *other {
865 self.write_array_size(module, base, size)?;
866 }
867 writeln!(self.out, "){ARGUMENT_VARIABLE_NAME}{i};",)?;
868 } else {
869 writeln!(
870 self.out,
871 "{INDENT}{RETURN_VARIABLE_NAME}.{field_name} = {ARGUMENT_VARIABLE_NAME}{i};",
872 )?;
873 }
874 }
875 }
876 }
877 }
878 crate::TypeInner::Array {
879 base,
880 size: crate::ArraySize::Constant(size),
881 ..
882 } => {
883 write!(self.out, "{INDENT}")?;
884 self.write_type(module, base)?;
885 write!(self.out, " {RETURN_VARIABLE_NAME}")?;
886 self.write_array_size(module, base, crate::ArraySize::Constant(size))?;
887 write!(self.out, " = {{ ")?;
888 for i in 0..size.get() {
889 if i != 0 {
890 write!(self.out, ", ")?;
891 }
892 write!(self.out, "{ARGUMENT_VARIABLE_NAME}{i}")?;
893 }
894 writeln!(self.out, " }};",)?;
895 }
896 _ => unreachable!(),
897 }
898
899 writeln!(self.out, "{INDENT}return {RETURN_VARIABLE_NAME};")?;
901
902 writeln!(self.out, "}}")?;
904 writeln!(self.out)?;
906
907 Ok(())
908 }
909
910 fn write_loaded_scalar_to_storage_loaded_value(
913 &mut self,
914 scalar_type: crate::Scalar,
915 ) -> BackendResult {
916 const ARGUMENT_VARIABLE_NAME: &str = "arg";
917 const RETURN_VARIABLE_NAME: &str = "ret";
918
919 let zero;
920 let one;
921 match scalar_type.kind {
922 ScalarKind::Sint => {
923 assert_eq!(
924 scalar_type.width, 4,
925 "Scalar {scalar_type:?} is not a result from any storage format"
926 );
927 zero = "0";
928 one = "1";
929 }
930 ScalarKind::Uint => match scalar_type.width {
931 4 => {
932 zero = "0u";
933 one = "1u";
934 }
935 8 => {
936 zero = "0uL";
937 one = "1uL"
938 }
939 _ => unreachable!("Scalar {scalar_type:?} is not a result from any storage format"),
940 },
941 ScalarKind::Float => {
942 assert_eq!(
943 scalar_type.width, 4,
944 "Scalar {scalar_type:?} is not a result from any storage format"
945 );
946 zero = "0.0";
947 one = "1.0";
948 }
949 _ => unreachable!("Scalar {scalar_type:?} is not a result from any storage format"),
950 }
951
952 let ty = scalar_type.to_hlsl_str()?;
953 writeln!(
954 self.out,
955 "{ty}4 {IMAGE_STORAGE_LOAD_SCALAR_WRAPPER}{ty}({ty} {ARGUMENT_VARIABLE_NAME}) {{\
956 {ty}4 {RETURN_VARIABLE_NAME} = {ty}4({ARGUMENT_VARIABLE_NAME}, {zero}, {zero}, {one});\
957 return {RETURN_VARIABLE_NAME};\
958}}"
959 )?;
960
961 Ok(())
962 }
963
964 pub(super) fn write_wrapped_struct_matrix_get_function_name(
965 &mut self,
966 access: WrappedStructMatrixAccess,
967 ) -> BackendResult {
968 let name = &self.names[&NameKey::Type(access.ty)];
969 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
970 write!(self.out, "GetMat{field_name}On{name}")?;
971 Ok(())
972 }
973
974 pub(super) fn write_wrapped_struct_matrix_get_function(
976 &mut self,
977 module: &crate::Module,
978 access: WrappedStructMatrixAccess,
979 ) -> BackendResult {
980 use crate::back::INDENT;
981
982 const STRUCT_ARGUMENT_VARIABLE_NAME: &str = "obj";
983
984 let member = match module.types[access.ty].inner {
986 crate::TypeInner::Struct { ref members, .. } => &members[access.index as usize],
987 _ => unreachable!(),
988 };
989 let ret_ty = &module.types[member.ty].inner;
990 self.write_value_type(module, ret_ty)?;
991 write!(self.out, " ")?;
992 self.write_wrapped_struct_matrix_get_function_name(access)?;
993
994 write!(self.out, "(")?;
996 let struct_name = &self.names[&NameKey::Type(access.ty)];
997 write!(self.out, "{struct_name} {STRUCT_ARGUMENT_VARIABLE_NAME}")?;
998
999 writeln!(self.out, ") {{")?;
1001
1002 write!(self.out, "{INDENT}return ")?;
1004 self.write_value_type(module, ret_ty)?;
1005 write!(self.out, "(")?;
1006 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1007 match module.types[member.ty].inner {
1008 crate::TypeInner::Matrix { columns, .. } => {
1009 for i in 0..columns as u8 {
1010 if i != 0 {
1011 write!(self.out, ", ")?;
1012 }
1013 write!(self.out, "{STRUCT_ARGUMENT_VARIABLE_NAME}.{field_name}_{i}")?;
1014 }
1015 }
1016 _ => unreachable!(),
1017 }
1018 writeln!(self.out, ");")?;
1019
1020 writeln!(self.out, "}}")?;
1022 writeln!(self.out)?;
1024
1025 Ok(())
1026 }
1027
1028 pub(super) fn write_wrapped_struct_matrix_set_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, "SetMat{field_name}On{name}")?;
1035 Ok(())
1036 }
1037
1038 pub(super) fn write_wrapped_struct_matrix_set_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 const MATRIX_ARGUMENT_VARIABLE_NAME: &str = "mat";
1048
1049 write!(self.out, "void ")?;
1051 self.write_wrapped_struct_matrix_set_function_name(access)?;
1052
1053 write!(self.out, "(")?;
1055 let struct_name = &self.names[&NameKey::Type(access.ty)];
1056 write!(self.out, "{struct_name} {STRUCT_ARGUMENT_VARIABLE_NAME}, ")?;
1057 let member = match module.types[access.ty].inner {
1058 crate::TypeInner::Struct { ref members, .. } => &members[access.index as usize],
1059 _ => unreachable!(),
1060 };
1061 self.write_type(module, member.ty)?;
1062 write!(self.out, " {MATRIX_ARGUMENT_VARIABLE_NAME}")?;
1063 writeln!(self.out, ") {{")?;
1065
1066 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1067
1068 match module.types[member.ty].inner {
1069 crate::TypeInner::Matrix { columns, .. } => {
1070 for i in 0..columns as u8 {
1071 writeln!(
1072 self.out,
1073 "{INDENT}{STRUCT_ARGUMENT_VARIABLE_NAME}.{field_name}_{i} = {MATRIX_ARGUMENT_VARIABLE_NAME}[{i}];"
1074 )?;
1075 }
1076 }
1077 _ => unreachable!(),
1078 }
1079
1080 writeln!(self.out, "}}")?;
1082 writeln!(self.out)?;
1084
1085 Ok(())
1086 }
1087
1088 pub(super) fn write_wrapped_struct_matrix_set_vec_function_name(
1089 &mut self,
1090 access: WrappedStructMatrixAccess,
1091 ) -> BackendResult {
1092 let name = &self.names[&NameKey::Type(access.ty)];
1093 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1094 write!(self.out, "SetMatVec{field_name}On{name}")?;
1095 Ok(())
1096 }
1097
1098 pub(super) fn write_wrapped_struct_matrix_set_vec_function(
1100 &mut self,
1101 module: &crate::Module,
1102 access: WrappedStructMatrixAccess,
1103 ) -> BackendResult {
1104 use crate::back::INDENT;
1105
1106 const STRUCT_ARGUMENT_VARIABLE_NAME: &str = "obj";
1107 const VECTOR_ARGUMENT_VARIABLE_NAME: &str = "vec";
1108 const MATRIX_INDEX_ARGUMENT_VARIABLE_NAME: &str = "mat_idx";
1109
1110 write!(self.out, "void ")?;
1112 self.write_wrapped_struct_matrix_set_vec_function_name(access)?;
1113
1114 write!(self.out, "(")?;
1116 let struct_name = &self.names[&NameKey::Type(access.ty)];
1117 write!(self.out, "{struct_name} {STRUCT_ARGUMENT_VARIABLE_NAME}, ")?;
1118 let member = match module.types[access.ty].inner {
1119 crate::TypeInner::Struct { ref members, .. } => &members[access.index as usize],
1120 _ => unreachable!(),
1121 };
1122 let vec_ty = match module.types[member.ty].inner {
1123 crate::TypeInner::Matrix { rows, scalar, .. } => {
1124 crate::TypeInner::Vector { size: rows, scalar }
1125 }
1126 _ => unreachable!(),
1127 };
1128 self.write_value_type(module, &vec_ty)?;
1129 write!(
1130 self.out,
1131 " {VECTOR_ARGUMENT_VARIABLE_NAME}, uint {MATRIX_INDEX_ARGUMENT_VARIABLE_NAME}"
1132 )?;
1133
1134 writeln!(self.out, ") {{")?;
1136
1137 writeln!(
1138 self.out,
1139 "{INDENT}switch({MATRIX_INDEX_ARGUMENT_VARIABLE_NAME}) {{"
1140 )?;
1141
1142 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1143
1144 match module.types[member.ty].inner {
1145 crate::TypeInner::Matrix { columns, .. } => {
1146 for i in 0..columns as u8 {
1147 writeln!(
1148 self.out,
1149 "{INDENT}case {i}: {{ {STRUCT_ARGUMENT_VARIABLE_NAME}.{field_name}_{i} = {VECTOR_ARGUMENT_VARIABLE_NAME}; break; }}"
1150 )?;
1151 }
1152 }
1153 _ => unreachable!(),
1154 }
1155
1156 writeln!(self.out, "{INDENT}}}")?;
1157
1158 writeln!(self.out, "}}")?;
1160 writeln!(self.out)?;
1162
1163 Ok(())
1164 }
1165
1166 pub(super) fn write_wrapped_struct_matrix_set_scalar_function_name(
1167 &mut self,
1168 access: WrappedStructMatrixAccess,
1169 ) -> BackendResult {
1170 let name = &self.names[&NameKey::Type(access.ty)];
1171 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1172 write!(self.out, "SetMatScalar{field_name}On{name}")?;
1173 Ok(())
1174 }
1175
1176 pub(super) fn write_wrapped_struct_matrix_set_scalar_function(
1178 &mut self,
1179 module: &crate::Module,
1180 access: WrappedStructMatrixAccess,
1181 ) -> BackendResult {
1182 use crate::back::INDENT;
1183
1184 const STRUCT_ARGUMENT_VARIABLE_NAME: &str = "obj";
1185 const SCALAR_ARGUMENT_VARIABLE_NAME: &str = "scalar";
1186 const MATRIX_INDEX_ARGUMENT_VARIABLE_NAME: &str = "mat_idx";
1187 const VECTOR_INDEX_ARGUMENT_VARIABLE_NAME: &str = "vec_idx";
1188
1189 write!(self.out, "void ")?;
1191 self.write_wrapped_struct_matrix_set_scalar_function_name(access)?;
1192
1193 write!(self.out, "(")?;
1195 let struct_name = &self.names[&NameKey::Type(access.ty)];
1196 write!(self.out, "{struct_name} {STRUCT_ARGUMENT_VARIABLE_NAME}, ")?;
1197 let member = match module.types[access.ty].inner {
1198 crate::TypeInner::Struct { ref members, .. } => &members[access.index as usize],
1199 _ => unreachable!(),
1200 };
1201 let scalar_ty = match module.types[member.ty].inner {
1202 crate::TypeInner::Matrix { scalar, .. } => crate::TypeInner::Scalar(scalar),
1203 _ => unreachable!(),
1204 };
1205 self.write_value_type(module, &scalar_ty)?;
1206 write!(
1207 self.out,
1208 " {SCALAR_ARGUMENT_VARIABLE_NAME}, uint {MATRIX_INDEX_ARGUMENT_VARIABLE_NAME}, uint {VECTOR_INDEX_ARGUMENT_VARIABLE_NAME}"
1209 )?;
1210
1211 writeln!(self.out, ") {{")?;
1213
1214 writeln!(
1215 self.out,
1216 "{INDENT}switch({MATRIX_INDEX_ARGUMENT_VARIABLE_NAME}) {{"
1217 )?;
1218
1219 let field_name = &self.names[&NameKey::StructMember(access.ty, access.index)];
1220
1221 match module.types[member.ty].inner {
1222 crate::TypeInner::Matrix { columns, .. } => {
1223 for i in 0..columns as u8 {
1224 writeln!(
1225 self.out,
1226 "{INDENT}case {i}: {{ {STRUCT_ARGUMENT_VARIABLE_NAME}.{field_name}_{i}[{VECTOR_INDEX_ARGUMENT_VARIABLE_NAME}] = {SCALAR_ARGUMENT_VARIABLE_NAME}; break; }}"
1227 )?;
1228 }
1229 }
1230 _ => unreachable!(),
1231 }
1232
1233 writeln!(self.out, "{INDENT}}}")?;
1234
1235 writeln!(self.out, "}}")?;
1237 writeln!(self.out)?;
1239
1240 Ok(())
1241 }
1242
1243 pub(super) fn write_special_functions(&mut self, module: &crate::Module) -> BackendResult {
1245 for (type_key, struct_ty) in module.special_types.predeclared_types.iter() {
1246 match type_key {
1247 &crate::PredeclaredType::ModfResult { size, scalar }
1248 | &crate::PredeclaredType::FrexpResult { size, scalar } => {
1249 let arg_type_name_owner;
1250 let arg_type_name = if let Some(size) = size {
1251 arg_type_name_owner = format!(
1252 "{}{}",
1253 if scalar.width == 8 { "double" } else { "float" },
1254 size as u8
1255 );
1256 &arg_type_name_owner
1257 } else if scalar.width == 8 {
1258 "double"
1259 } else {
1260 "float"
1261 };
1262
1263 let (defined_func_name, called_func_name, second_field_name, sign_multiplier) =
1264 if matches!(type_key, &crate::PredeclaredType::ModfResult { .. }) {
1265 (super::writer::MODF_FUNCTION, "modf", "whole", "")
1266 } else {
1267 (
1268 super::writer::FREXP_FUNCTION,
1269 "frexp",
1270 "exp_",
1271 "sign(arg) * ",
1272 )
1273 };
1274
1275 let struct_name = &self.names[&NameKey::Type(*struct_ty)];
1276
1277 writeln!(
1278 self.out,
1279 "{struct_name} {defined_func_name}({arg_type_name} arg) {{
1280 {arg_type_name} other;
1281 {struct_name} result;
1282 result.fract = {sign_multiplier}{called_func_name}(arg, other);
1283 result.{second_field_name} = other;
1284 return result;
1285}}"
1286 )?;
1287 writeln!(self.out)?;
1288 }
1289 &crate::PredeclaredType::AtomicCompareExchangeWeakResult { .. } => {}
1290 }
1291 }
1292 if module.special_types.ray_desc.is_some() {
1293 self.write_ray_desc_from_ray_desc_constructor_function(module)?;
1294 }
1295
1296 Ok(())
1297 }
1298
1299 pub(super) fn write_wrapped_expression_functions(
1301 &mut self,
1302 module: &crate::Module,
1303 expressions: &crate::Arena<crate::Expression>,
1304 context: Option<&FunctionCtx>,
1305 ) -> BackendResult {
1306 for (handle, _) in expressions.iter() {
1307 match expressions[handle] {
1308 crate::Expression::Compose { ty, .. } => {
1309 match module.types[ty].inner {
1310 crate::TypeInner::Struct { .. } | crate::TypeInner::Array { .. } => {
1311 let constructor = WrappedConstructor { ty };
1312 if self.wrapped.insert(WrappedType::Constructor(constructor)) {
1313 self.write_wrapped_constructor_function(module, constructor)?;
1314 }
1315 }
1316 _ => {}
1317 };
1318 }
1319 crate::Expression::ImageLoad { image, .. } => {
1320 match *context.as_ref().unwrap().resolve_type(image, &module.types) {
1322 crate::TypeInner::Image {
1323 class: crate::ImageClass::Storage { format, .. },
1324 ..
1325 } => {
1326 if format.single_component() {
1327 let scalar: crate::Scalar = format.into();
1328 if self.wrapped.insert(WrappedType::ImageLoadScalar(scalar)) {
1329 self.write_loaded_scalar_to_storage_loaded_value(scalar)?;
1330 }
1331 }
1332 }
1333 _ => {}
1334 }
1335 }
1336 crate::Expression::RayQueryGetIntersection { committed, .. } => {
1337 if committed {
1338 if !self.written_committed_intersection {
1339 self.write_committed_intersection_function(module)?;
1340 self.written_committed_intersection = true;
1341 }
1342 } else if !self.written_candidate_intersection {
1343 self.write_candidate_intersection_function(module)?;
1344 self.written_candidate_intersection = true;
1345 }
1346 }
1347 _ => {}
1348 }
1349 }
1350 Ok(())
1351 }
1352
1353 pub(super) fn write_wrapped_zero_value_functions(
1357 &mut self,
1358 module: &crate::Module,
1359 expressions: &crate::Arena<crate::Expression>,
1360 ) -> BackendResult {
1361 for (handle, _) in expressions.iter() {
1362 if let crate::Expression::ZeroValue(ty) = expressions[handle] {
1363 let zero_value = WrappedZeroValue { ty };
1364 if self.wrapped.insert(WrappedType::ZeroValue(zero_value)) {
1365 self.write_wrapped_zero_value_function(module, zero_value)?;
1366 }
1367 }
1368 }
1369 Ok(())
1370 }
1371
1372 pub(super) fn write_wrapped_math_functions(
1373 &mut self,
1374 module: &crate::Module,
1375 func_ctx: &FunctionCtx,
1376 ) -> BackendResult {
1377 for (_, expression) in func_ctx.expressions.iter() {
1378 if let crate::Expression::Math {
1379 fun,
1380 arg,
1381 arg1: _arg1,
1382 arg2: _arg2,
1383 arg3: _arg3,
1384 } = *expression
1385 {
1386 let arg_ty = func_ctx.resolve_type(arg, &module.types);
1387
1388 match fun {
1389 crate::MathFunction::ExtractBits => {
1390 let scalar = arg_ty.scalar().unwrap();
1403 let components = arg_ty.components();
1404
1405 let wrapped = WrappedMath {
1406 fun,
1407 scalar,
1408 components,
1409 };
1410
1411 if !self.wrapped.insert(WrappedType::Math(wrapped)) {
1412 continue;
1413 }
1414
1415 self.write_value_type(module, arg_ty)?;
1417
1418 let scalar_width: u8 = scalar.width * 8;
1419
1420 writeln!(self.out, " {EXTRACT_BITS_FUNCTION}(")?;
1422 write!(self.out, " ")?;
1423 self.write_value_type(module, arg_ty)?;
1424 writeln!(self.out, " e,")?;
1425 writeln!(self.out, " uint offset,")?;
1426 writeln!(self.out, " uint count")?;
1427 writeln!(self.out, ") {{")?;
1428
1429 writeln!(self.out, " uint w = {scalar_width};")?;
1431 writeln!(self.out, " uint o = min(offset, w);")?;
1432 writeln!(self.out, " uint c = min(count, w - o);")?;
1433 writeln!(
1434 self.out,
1435 " return (c == 0 ? 0 : (e << (w - c - o)) >> (w - c));"
1436 )?;
1437
1438 writeln!(self.out, "}}")?;
1440 }
1441 crate::MathFunction::InsertBits => {
1442 let scalar = arg_ty.scalar().unwrap();
1445 let components = arg_ty.components();
1446
1447 let wrapped = WrappedMath {
1448 fun,
1449 scalar,
1450 components,
1451 };
1452
1453 if !self.wrapped.insert(WrappedType::Math(wrapped)) {
1454 continue;
1455 }
1456
1457 self.write_value_type(module, arg_ty)?;
1459
1460 let scalar_width: u8 = scalar.width * 8;
1461 let scalar_max: u64 = match scalar.width {
1462 1 => 0xFF,
1463 2 => 0xFFFF,
1464 4 => 0xFFFFFFFF,
1465 8 => 0xFFFFFFFFFFFFFFFF,
1466 _ => unreachable!(),
1467 };
1468
1469 writeln!(self.out, " {INSERT_BITS_FUNCTION}(")?;
1471 write!(self.out, " ")?;
1472 self.write_value_type(module, arg_ty)?;
1473 writeln!(self.out, " e,")?;
1474 write!(self.out, " ")?;
1475 self.write_value_type(module, arg_ty)?;
1476 writeln!(self.out, " newbits,")?;
1477 writeln!(self.out, " uint offset,")?;
1478 writeln!(self.out, " uint count")?;
1479 writeln!(self.out, ") {{")?;
1480
1481 writeln!(self.out, " uint w = {scalar_width}u;")?;
1483 writeln!(self.out, " uint o = min(offset, w);")?;
1484 writeln!(self.out, " uint c = min(count, w - o);")?;
1485
1486 writeln!(
1489 self.out,
1490 " uint mask = (({scalar_max}u >> ({scalar_width}u - c)) << o);"
1491 )?;
1492 writeln!(
1493 self.out,
1494 " return (c == 0 ? e : ((e & ~mask) | ((newbits << o) & mask)));"
1495 )?;
1496
1497 writeln!(self.out, "}}")?;
1499 }
1500 crate::MathFunction::Abs
1511 if matches!(arg_ty.scalar(), Some(crate::Scalar::I32)) =>
1512 {
1513 let scalar = arg_ty.scalar().unwrap();
1514 let components = arg_ty.components();
1515
1516 let wrapped = WrappedMath {
1517 fun,
1518 scalar,
1519 components,
1520 };
1521
1522 if !self.wrapped.insert(WrappedType::Math(wrapped)) {
1523 continue;
1524 }
1525
1526 self.write_value_type(module, arg_ty)?;
1527 write!(self.out, " {ABS_FUNCTION}(")?;
1528 self.write_value_type(module, arg_ty)?;
1529 writeln!(self.out, " val) {{")?;
1530
1531 let level = crate::back::Level(1);
1532 writeln!(
1533 self.out,
1534 "{level}return val >= 0 ? val : asint(-asuint(val));"
1535 )?;
1536 writeln!(self.out, "}}")?;
1537 writeln!(self.out)?;
1538 }
1539 _ => {}
1540 }
1541 }
1542 }
1543
1544 Ok(())
1545 }
1546
1547 pub(super) fn write_wrapped_unary_ops(
1548 &mut self,
1549 module: &crate::Module,
1550 func_ctx: &FunctionCtx,
1551 ) -> BackendResult {
1552 for (_, expression) in func_ctx.expressions.iter() {
1553 if let crate::Expression::Unary { op, expr } = *expression {
1554 let expr_ty = func_ctx.resolve_type(expr, &module.types);
1555 let Some((vector_size, scalar)) = expr_ty.vector_size_and_scalar() else {
1556 continue;
1557 };
1558 let wrapped = WrappedUnaryOp {
1559 op,
1560 ty: (vector_size, scalar),
1561 };
1562
1563 match (op, scalar) {
1572 (crate::UnaryOperator::Negate, crate::Scalar::I32) => {
1573 if !self.wrapped.insert(WrappedType::UnaryOp(wrapped)) {
1574 continue;
1575 }
1576
1577 self.write_value_type(module, expr_ty)?;
1578 write!(self.out, " {NEG_FUNCTION}(")?;
1579 self.write_value_type(module, expr_ty)?;
1580 writeln!(self.out, " val) {{")?;
1581
1582 let level = crate::back::Level(1);
1583 writeln!(self.out, "{level}return asint(-asuint(val));",)?;
1584 writeln!(self.out, "}}")?;
1585 writeln!(self.out)?;
1586 }
1587 _ => {}
1588 }
1589 }
1590 }
1591
1592 Ok(())
1593 }
1594
1595 pub(super) fn write_wrapped_binary_ops(
1596 &mut self,
1597 module: &crate::Module,
1598 func_ctx: &FunctionCtx,
1599 ) -> BackendResult {
1600 for (expr_handle, expression) in func_ctx.expressions.iter() {
1601 if let crate::Expression::Binary { op, left, right } = *expression {
1602 let expr_ty = func_ctx.resolve_type(expr_handle, &module.types);
1603 let left_ty = func_ctx.resolve_type(left, &module.types);
1604 let right_ty = func_ctx.resolve_type(right, &module.types);
1605
1606 match (op, expr_ty.scalar()) {
1607 (
1615 crate::BinaryOperator::Divide,
1616 Some(
1617 scalar @ crate::Scalar {
1618 kind: ScalarKind::Sint | ScalarKind::Uint,
1619 ..
1620 },
1621 ),
1622 ) => {
1623 let Some(left_wrapped_ty) = left_ty.vector_size_and_scalar() else {
1624 continue;
1625 };
1626 let Some(right_wrapped_ty) = right_ty.vector_size_and_scalar() else {
1627 continue;
1628 };
1629 let wrapped = WrappedBinaryOp {
1630 op,
1631 left_ty: left_wrapped_ty,
1632 right_ty: right_wrapped_ty,
1633 };
1634 if !self.wrapped.insert(WrappedType::BinaryOp(wrapped)) {
1635 continue;
1636 }
1637
1638 self.write_value_type(module, expr_ty)?;
1639 write!(self.out, " {DIV_FUNCTION}(")?;
1640 self.write_value_type(module, left_ty)?;
1641 write!(self.out, " lhs, ")?;
1642 self.write_value_type(module, right_ty)?;
1643 writeln!(self.out, " rhs) {{")?;
1644 let level = crate::back::Level(1);
1645 match scalar.kind {
1646 ScalarKind::Sint => {
1647 let min_val = match scalar.width {
1648 2 => crate::Literal::I16(i16::MIN),
1649 4 => crate::Literal::I32(i32::MIN),
1650 8 => crate::Literal::I64(i64::MIN),
1651 _ => {
1652 return Err(super::Error::UnsupportedScalar(scalar));
1653 }
1654 };
1655 write!(self.out, "{level}return lhs / (((lhs == ")?;
1656 self.write_literal(min_val)?;
1657 writeln!(self.out, " & rhs == -1) | (rhs == 0)) ? 1 : rhs);")?
1658 }
1659 ScalarKind::Uint => {
1660 writeln!(self.out, "{level}return lhs / (rhs == 0u ? 1u : rhs);")?
1661 }
1662 _ => unreachable!(),
1663 }
1664 writeln!(self.out, "}}")?;
1665 writeln!(self.out)?;
1666 }
1667 (
1680 crate::BinaryOperator::Modulo,
1681 Some(
1682 scalar @ crate::Scalar {
1683 kind: ScalarKind::Sint | ScalarKind::Uint | ScalarKind::Float,
1684 ..
1685 },
1686 ),
1687 ) => {
1688 let Some(left_wrapped_ty) = left_ty.vector_size_and_scalar() else {
1689 continue;
1690 };
1691 let Some(right_wrapped_ty) = right_ty.vector_size_and_scalar() else {
1692 continue;
1693 };
1694 let wrapped = WrappedBinaryOp {
1695 op,
1696 left_ty: left_wrapped_ty,
1697 right_ty: right_wrapped_ty,
1698 };
1699 if !self.wrapped.insert(WrappedType::BinaryOp(wrapped)) {
1700 continue;
1701 }
1702
1703 self.write_value_type(module, expr_ty)?;
1704 write!(self.out, " {MOD_FUNCTION}(")?;
1705 self.write_value_type(module, left_ty)?;
1706 write!(self.out, " lhs, ")?;
1707 self.write_value_type(module, right_ty)?;
1708 writeln!(self.out, " rhs) {{")?;
1709 let level = crate::back::Level(1);
1710 match scalar.kind {
1711 ScalarKind::Sint => {
1712 let min_val = match scalar.width {
1713 2 => crate::Literal::I16(i16::MIN),
1714 4 => crate::Literal::I32(i32::MIN),
1715 8 => crate::Literal::I64(i64::MIN),
1716 _ => {
1717 return Err(super::Error::UnsupportedScalar(scalar));
1718 }
1719 };
1720 write!(self.out, "{level}")?;
1721 self.write_value_type(module, right_ty)?;
1722 write!(self.out, " divisor = ((lhs == ")?;
1723 self.write_literal(min_val)?;
1724 writeln!(self.out, " & rhs == -1) | (rhs == 0)) ? 1 : rhs;")?;
1725 writeln!(
1726 self.out,
1727 "{level}return lhs - (lhs / divisor) * divisor;"
1728 )?
1729 }
1730 ScalarKind::Uint => {
1731 writeln!(self.out, "{level}return lhs % (rhs == 0u ? 1u : rhs);")?
1732 }
1733 ScalarKind::Float => {
1739 writeln!(self.out, "{level}return lhs - rhs * trunc(lhs / rhs);")?
1740 }
1741 _ => unreachable!(),
1742 }
1743 writeln!(self.out, "}}")?;
1744 writeln!(self.out)?;
1745 }
1746 _ => {}
1747 }
1748 }
1749 }
1750
1751 Ok(())
1752 }
1753
1754 fn write_wrapped_cast_functions(
1755 &mut self,
1756 module: &crate::Module,
1757 func_ctx: &FunctionCtx,
1758 ) -> BackendResult {
1759 for (_, expression) in func_ctx.expressions.iter() {
1760 if let crate::Expression::As {
1761 expr,
1762 kind,
1763 convert: Some(width),
1764 } = *expression
1765 {
1766 let src_ty = func_ctx.resolve_type(expr, &module.types);
1777 let Some((vector_size, src_scalar)) = src_ty.vector_size_and_scalar() else {
1778 continue;
1779 };
1780 let dst_scalar = crate::Scalar { kind, width };
1781 if src_scalar.kind != ScalarKind::Float
1782 || (dst_scalar.kind != ScalarKind::Sint && dst_scalar.kind != ScalarKind::Uint)
1783 {
1784 continue;
1785 }
1786
1787 let wrapped = WrappedCast {
1788 src_scalar,
1789 vector_size,
1790 dst_scalar,
1791 };
1792 if !self.wrapped.insert(WrappedType::Cast(wrapped)) {
1793 continue;
1794 }
1795
1796 let (src_ty, dst_ty) = match vector_size {
1797 None => (
1798 crate::TypeInner::Scalar(src_scalar),
1799 crate::TypeInner::Scalar(dst_scalar),
1800 ),
1801 Some(vector_size) => (
1802 crate::TypeInner::Vector {
1803 scalar: src_scalar,
1804 size: vector_size,
1805 },
1806 crate::TypeInner::Vector {
1807 scalar: dst_scalar,
1808 size: vector_size,
1809 },
1810 ),
1811 };
1812 let (min, max) =
1813 crate::proc::min_max_float_representable_by(src_scalar, dst_scalar);
1814 let cast_str = format!(
1815 "{}{}",
1816 dst_scalar.to_hlsl_str()?,
1817 vector_size
1818 .map(crate::common::vector_size_str)
1819 .unwrap_or(""),
1820 );
1821 let fun_name = match dst_scalar {
1822 crate::Scalar::I32 => F2I32_FUNCTION,
1823 crate::Scalar::U32 => F2U32_FUNCTION,
1824 crate::Scalar::I64 => F2I64_FUNCTION,
1825 crate::Scalar::U64 => F2U64_FUNCTION,
1826 _ => unreachable!(),
1827 };
1828 self.write_value_type(module, &dst_ty)?;
1829 write!(self.out, " {fun_name}(")?;
1830 self.write_value_type(module, &src_ty)?;
1831 writeln!(self.out, " value) {{")?;
1832 let level = crate::back::Level(1);
1833 write!(self.out, "{level}return {cast_str}(clamp(value, ")?;
1834 self.write_literal(min)?;
1835 write!(self.out, ", ")?;
1836 self.write_literal(max)?;
1837 writeln!(self.out, "));",)?;
1838 writeln!(self.out, "}}")?;
1839 writeln!(self.out)?;
1840 }
1841 }
1842 Ok(())
1843 }
1844
1845 pub(super) fn write_wrapped_functions(
1847 &mut self,
1848 module: &crate::Module,
1849 func_ctx: &FunctionCtx,
1850 ) -> BackendResult {
1851 self.write_wrapped_math_functions(module, func_ctx)?;
1852 self.write_wrapped_unary_ops(module, func_ctx)?;
1853 self.write_wrapped_binary_ops(module, func_ctx)?;
1854 self.write_wrapped_expression_functions(module, func_ctx.expressions, Some(func_ctx))?;
1855 self.write_wrapped_zero_value_functions(module, func_ctx.expressions)?;
1856 self.write_wrapped_cast_functions(module, func_ctx)?;
1857
1858 for (handle, _) in func_ctx.expressions.iter() {
1859 match func_ctx.expressions[handle] {
1860 crate::Expression::ArrayLength(expr) => {
1861 let global_expr = match func_ctx.expressions[expr] {
1862 crate::Expression::GlobalVariable(_) => expr,
1863 crate::Expression::AccessIndex { base, index: _ } => base,
1864 ref other => unreachable!("Array length of {:?}", other),
1865 };
1866 let global_var = match func_ctx.expressions[global_expr] {
1867 crate::Expression::GlobalVariable(var_handle) => {
1868 &module.global_variables[var_handle]
1869 }
1870 ref other => {
1871 return Err(super::Error::Unimplemented(format!(
1872 "Array length of base {other:?}"
1873 )))
1874 }
1875 };
1876 let storage_access = match global_var.space {
1877 crate::AddressSpace::Storage { access } => access,
1878 _ => crate::StorageAccess::default(),
1879 };
1880 let wal = WrappedArrayLength {
1881 writable: storage_access.contains(crate::StorageAccess::STORE),
1882 };
1883
1884 if self.wrapped.insert(WrappedType::ArrayLength(wal)) {
1885 self.write_wrapped_array_length_function(wal)?;
1886 }
1887 }
1888 crate::Expression::ImageLoad { image, .. } => {
1889 let class = match *func_ctx.resolve_type(image, &module.types) {
1890 crate::TypeInner::Image { class, .. } => class,
1891 _ => unreachable!(),
1892 };
1893 let wrapped = WrappedImageLoad { class };
1894 if self.wrapped.insert(WrappedType::ImageLoad(wrapped)) {
1895 self.write_wrapped_image_load_function(module, wrapped)?;
1896 }
1897 }
1898 crate::Expression::ImageSample {
1899 image,
1900 clamp_to_edge,
1901 ..
1902 } => {
1903 let class = match *func_ctx.resolve_type(image, &module.types) {
1904 crate::TypeInner::Image { class, .. } => class,
1905 _ => unreachable!(),
1906 };
1907 let wrapped = WrappedImageSample {
1908 class,
1909 clamp_to_edge,
1910 };
1911 if self.wrapped.insert(WrappedType::ImageSample(wrapped)) {
1912 self.write_wrapped_image_sample_function(module, wrapped)?;
1913 }
1914 }
1915 crate::Expression::ImageQuery { image, query } => {
1916 let wiq = match *func_ctx.resolve_type(image, &module.types) {
1917 crate::TypeInner::Image {
1918 dim,
1919 arrayed,
1920 class,
1921 } => WrappedImageQuery {
1922 dim,
1923 arrayed,
1924 class,
1925 query: query.into(),
1926 },
1927 _ => unreachable!("we only query images"),
1928 };
1929
1930 if self.wrapped.insert(WrappedType::ImageQuery(wiq)) {
1931 self.write_wrapped_image_query_function(module, wiq, handle, func_ctx)?;
1932 }
1933 }
1934 crate::Expression::Load { pointer } => {
1937 let pointer_space = func_ctx
1938 .resolve_type(pointer, &module.types)
1939 .pointer_space();
1940
1941 if let Some(crate::AddressSpace::Storage { .. }) = pointer_space {
1942 if let Some(ty) = func_ctx.info[handle].ty.handle() {
1943 write_wrapped_constructor(self, ty, module)?;
1944 }
1945 }
1946
1947 fn write_wrapped_constructor<W: Write>(
1948 writer: &mut super::Writer<'_, W>,
1949 ty: Handle<crate::Type>,
1950 module: &crate::Module,
1951 ) -> BackendResult {
1952 match module.types[ty].inner {
1953 crate::TypeInner::Struct { ref members, .. } => {
1954 for member in members {
1955 write_wrapped_constructor(writer, member.ty, module)?;
1956 }
1957
1958 let constructor = WrappedConstructor { ty };
1959 if writer.wrapped.insert(WrappedType::Constructor(constructor)) {
1960 writer
1961 .write_wrapped_constructor_function(module, constructor)?;
1962 }
1963 }
1964 crate::TypeInner::Array { base, .. } => {
1965 write_wrapped_constructor(writer, base, module)?;
1966
1967 let constructor = WrappedConstructor { ty };
1968 if writer.wrapped.insert(WrappedType::Constructor(constructor)) {
1969 writer
1970 .write_wrapped_constructor_function(module, constructor)?;
1971 }
1972 }
1973 _ => {}
1974 };
1975
1976 Ok(())
1977 }
1978 }
1979 crate::Expression::AccessIndex { base, index } => {
1984 let base_ty_res = &func_ctx.info[base].ty;
1985 let mut resolved = base_ty_res.inner_with(&module.types);
1986 let base_ty_handle = match *resolved {
1987 crate::TypeInner::Pointer { base, .. } => {
1988 resolved = &module.types[base].inner;
1989 Some(base)
1990 }
1991 _ => base_ty_res.handle(),
1992 };
1993 if let crate::TypeInner::Struct { ref members, .. } = *resolved {
1994 let member = &members[index as usize];
1995
1996 match module.types[member.ty].inner {
1997 crate::TypeInner::Matrix {
1998 rows: crate::VectorSize::Bi,
1999 ..
2000 } if member.binding.is_none() => {
2001 let ty = base_ty_handle.unwrap();
2002 let access = WrappedStructMatrixAccess { ty, index };
2003
2004 if self.wrapped.insert(WrappedType::StructMatrixAccess(access)) {
2005 self.write_wrapped_struct_matrix_get_function(module, access)?;
2006 self.write_wrapped_struct_matrix_set_function(module, access)?;
2007 self.write_wrapped_struct_matrix_set_vec_function(
2008 module, access,
2009 )?;
2010 self.write_wrapped_struct_matrix_set_scalar_function(
2011 module, access,
2012 )?;
2013 }
2014 }
2015 _ => {}
2016 }
2017 }
2018 }
2019 _ => {}
2020 };
2021 }
2022
2023 Ok(())
2024 }
2025
2026 pub(super) fn write_sampler_heaps(&mut self) -> BackendResult {
2028 if self.wrapped.sampler_heaps {
2029 return Ok(());
2030 }
2031
2032 writeln!(
2033 self.out,
2034 "SamplerState {}[2048]: register(s{}, space{});",
2035 super::writer::SAMPLER_HEAP_VAR,
2036 self.options.sampler_heap_target.standard_samplers.register,
2037 self.options.sampler_heap_target.standard_samplers.space
2038 )?;
2039 writeln!(
2040 self.out,
2041 "SamplerComparisonState {}[2048]: register(s{}, space{});",
2042 super::writer::COMPARISON_SAMPLER_HEAP_VAR,
2043 self.options
2044 .sampler_heap_target
2045 .comparison_samplers
2046 .register,
2047 self.options.sampler_heap_target.comparison_samplers.space
2048 )?;
2049
2050 self.wrapped.sampler_heaps = true;
2051
2052 Ok(())
2053 }
2054
2055 pub(super) fn write_wrapped_sampler_buffer(
2057 &mut self,
2058 key: super::SamplerIndexBufferKey,
2059 ) -> BackendResult {
2060 if self.wrapped.sampler_index_buffers.contains_key(&key) {
2067 return Ok(());
2068 };
2069
2070 self.write_sampler_heaps()?;
2071
2072 let sampler_array_name = self
2075 .namer
2076 .call(&format!("nagaGroup{}SamplerIndexArray", key.group));
2077
2078 let bind_target = match self.options.sampler_buffer_binding_map.get(&key) {
2079 Some(&bind_target) => bind_target,
2080 None if self.options.fake_missing_bindings => super::BindTarget {
2081 space: u8::MAX,
2082 register: key.group,
2083 binding_array_size: None,
2084 dynamic_storage_buffer_offsets_index: None,
2085 restrict_indexing: false,
2086 },
2087 None => {
2088 unreachable!("Sampler buffer of group {key:?} not bound to a register");
2089 }
2090 };
2091
2092 writeln!(
2093 self.out,
2094 "StructuredBuffer<uint> {sampler_array_name} : register(t{}, space{});",
2095 bind_target.register, bind_target.space
2096 )?;
2097
2098 self.wrapped
2099 .sampler_index_buffers
2100 .insert(key, sampler_array_name);
2101
2102 Ok(())
2103 }
2104
2105 pub(super) fn write_texture_coordinates(
2106 &mut self,
2107 kind: &str,
2108 coordinate: Handle<crate::Expression>,
2109 array_index: Option<Handle<crate::Expression>>,
2110 mip_level: Option<Handle<crate::Expression>>,
2111 module: &crate::Module,
2112 func_ctx: &FunctionCtx,
2113 ) -> BackendResult {
2114 let extra = array_index.is_some() as usize + (mip_level.is_some()) as usize;
2116 if extra == 0 {
2117 self.write_expr(module, coordinate, func_ctx)?;
2118 } else {
2119 let num_coords = match *func_ctx.resolve_type(coordinate, &module.types) {
2120 crate::TypeInner::Scalar { .. } => 1,
2121 crate::TypeInner::Vector { size, .. } => size as usize,
2122 _ => unreachable!(),
2123 };
2124 write!(self.out, "{}{}(", kind, num_coords + extra)?;
2125 self.write_expr(module, coordinate, func_ctx)?;
2126 if let Some(expr) = array_index {
2127 write!(self.out, ", ")?;
2128 self.write_expr(module, expr, func_ctx)?;
2129 }
2130 if let Some(expr) = mip_level {
2131 let cast_to_int = matches!(
2133 *func_ctx.resolve_type(expr, &module.types),
2134 crate::TypeInner::Scalar(crate::Scalar {
2135 kind: ScalarKind::Uint,
2136 ..
2137 })
2138 );
2139
2140 write!(self.out, ", ")?;
2141
2142 if cast_to_int {
2143 write!(self.out, "int(")?;
2144 }
2145
2146 self.write_expr(module, expr, func_ctx)?;
2147
2148 if cast_to_int {
2149 write!(self.out, ")")?;
2150 }
2151 }
2152 write!(self.out, ")")?;
2153 }
2154 Ok(())
2155 }
2156
2157 pub(super) fn write_mat_cx2_typedef_and_functions(
2158 &mut self,
2159 WrappedMatCx2 { columns, width }: WrappedMatCx2,
2160 ) -> BackendResult {
2161 use crate::back::INDENT;
2162
2163 let bit_width = width * 8;
2164 let type_name = crate::Scalar {
2165 kind: ScalarKind::Float,
2166 width,
2167 }
2168 .to_hlsl_str()?;
2169
2170 write!(self.out, "typedef struct {{ ")?;
2172 for i in 0..columns as u8 {
2173 write!(self.out, "{type_name}2 _{i}; ")?;
2174 }
2175 writeln!(self.out, "}} __mat{}x2_f{bit_width};", columns as u8)?;
2176
2177 writeln!(
2179 self.out,
2180 "{type_name}2 __get_col_of_mat{}x2_f{bit_width}(__mat{}x2_f{bit_width} mat, uint idx) {{",
2181 columns as u8, columns as u8
2182 )?;
2183 writeln!(self.out, "{INDENT}switch(idx) {{")?;
2184 for i in 0..columns as u8 {
2185 writeln!(self.out, "{INDENT}case {i}: {{ return mat._{i}; }}")?;
2186 }
2187 writeln!(self.out, "{INDENT}default: {{ return ({type_name}2)0; }}")?;
2188 writeln!(self.out, "{INDENT}}}")?;
2189 writeln!(self.out, "}}")?;
2190
2191 writeln!(
2193 self.out,
2194 "void __set_col_of_mat{}x2_f{bit_width}(__mat{}x2_f{bit_width} mat, uint idx, {type_name}2 value) {{",
2195 columns as u8, columns as u8
2196 )?;
2197 writeln!(self.out, "{INDENT}switch(idx) {{")?;
2198 for i in 0..columns as u8 {
2199 writeln!(self.out, "{INDENT}case {i}: {{ mat._{i} = value; break; }}")?;
2200 }
2201 writeln!(self.out, "{INDENT}}}")?;
2202 writeln!(self.out, "}}")?;
2203
2204 writeln!(
2206 self.out,
2207 "void __set_el_of_mat{}x2_f{bit_width}(__mat{}x2_f{bit_width} mat, uint idx, uint vec_idx, {type_name} value) {{",
2208 columns as u8, columns as u8
2209 )?;
2210 writeln!(self.out, "{INDENT}switch(idx) {{")?;
2211 for i in 0..columns as u8 {
2212 writeln!(
2213 self.out,
2214 "{INDENT}case {i}: {{ mat._{i}[vec_idx] = value; break; }}"
2215 )?;
2216 }
2217 writeln!(self.out, "{INDENT}}}")?;
2218 writeln!(self.out, "}}")?;
2219
2220 writeln!(self.out)?;
2221
2222 Ok(())
2223 }
2224
2225 pub(super) fn write_all_mat_cx2_typedefs_and_functions(
2226 &mut self,
2227 module: &crate::Module,
2228 ) -> BackendResult {
2229 for (handle, _) in module.global_variables.iter() {
2230 let global = &module.global_variables[handle];
2231
2232 if global.space == crate::AddressSpace::Uniform {
2233 if let Some(super::writer::MatrixType {
2234 columns,
2235 rows: crate::VectorSize::Bi,
2236 width,
2237 }) = super::writer::get_inner_matrix_data(module, global.ty)
2238 {
2239 let entry = WrappedMatCx2 { columns, width };
2240 if self.wrapped.insert(WrappedType::MatCx2(entry)) {
2241 self.write_mat_cx2_typedef_and_functions(entry)?;
2242 }
2243 }
2244 }
2245 }
2246
2247 for (_, ty) in module.types.iter() {
2248 if let crate::TypeInner::Struct { ref members, .. } = ty.inner {
2249 for member in members.iter() {
2250 if let crate::TypeInner::Array { .. } = module.types[member.ty].inner {
2251 if let Some(super::writer::MatrixType {
2252 columns,
2253 rows: crate::VectorSize::Bi,
2254 width,
2255 }) = super::writer::get_inner_matrix_data(module, member.ty)
2256 {
2257 let entry = WrappedMatCx2 { columns, width };
2258 if self.wrapped.insert(WrappedType::MatCx2(entry)) {
2259 self.write_mat_cx2_typedef_and_functions(entry)?;
2260 }
2261 }
2262 }
2263 }
2264 }
2265 }
2266
2267 Ok(())
2268 }
2269
2270 pub(super) fn write_wrapped_zero_value_function_name(
2271 &mut self,
2272 module: &crate::Module,
2273 zero_value: WrappedZeroValue,
2274 ) -> BackendResult {
2275 let name = crate::TypeInner::hlsl_type_id(zero_value.ty, module.to_ctx(), &self.names)?;
2276 write!(self.out, "ZeroValue{name}")?;
2277 Ok(())
2278 }
2279
2280 fn write_wrapped_zero_value_function(
2296 &mut self,
2297 module: &crate::Module,
2298 zero_value: WrappedZeroValue,
2299 ) -> BackendResult {
2300 use crate::back::INDENT;
2301
2302 if let crate::TypeInner::Array { base, size, .. } = module.types[zero_value.ty].inner {
2304 write!(self.out, "typedef ")?;
2305 self.write_type(module, zero_value.ty)?;
2306 write!(self.out, " ret_")?;
2307 self.write_wrapped_zero_value_function_name(module, zero_value)?;
2308 self.write_array_size(module, base, size)?;
2309 writeln!(self.out, ";")?;
2310
2311 write!(self.out, "ret_")?;
2312 self.write_wrapped_zero_value_function_name(module, zero_value)?;
2313 } else {
2314 self.write_type(module, zero_value.ty)?;
2315 }
2316 write!(self.out, " ")?;
2317 self.write_wrapped_zero_value_function_name(module, zero_value)?;
2318
2319 writeln!(self.out, "() {{")?;
2321
2322 write!(self.out, "{INDENT}return ")?;
2324 self.write_default_init(module, zero_value.ty)?;
2325 writeln!(self.out, ";")?;
2326
2327 writeln!(self.out, "}}")?;
2329 writeln!(self.out)?;
2331
2332 Ok(())
2333 }
2334}
2335
2336impl crate::StorageFormat {
2337 pub(super) const fn single_component(&self) -> bool {
2339 match *self {
2340 crate::StorageFormat::R16Float
2341 | crate::StorageFormat::R32Float
2342 | crate::StorageFormat::R8Unorm
2343 | crate::StorageFormat::R16Unorm
2344 | crate::StorageFormat::R8Snorm
2345 | crate::StorageFormat::R16Snorm
2346 | crate::StorageFormat::R8Uint
2347 | crate::StorageFormat::R16Uint
2348 | crate::StorageFormat::R32Uint
2349 | crate::StorageFormat::R8Sint
2350 | crate::StorageFormat::R16Sint
2351 | crate::StorageFormat::R32Sint
2352 | crate::StorageFormat::R64Uint => true,
2353 _ => false,
2354 }
2355 }
2356}