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 } if format.single_component() => {
1326 let scalar: crate::Scalar = format.into();
1327 if self.wrapped.insert(WrappedType::ImageLoadScalar(scalar)) {
1328 self.write_loaded_scalar_to_storage_loaded_value(scalar)?;
1329 }
1330 }
1331 _ => {}
1332 }
1333 }
1334 crate::Expression::RayQueryGetIntersection { committed, .. } => {
1335 if committed {
1336 if !self.written_committed_intersection {
1337 self.write_committed_intersection_function(module)?;
1338 self.written_committed_intersection = true;
1339 }
1340 } else if !self.written_candidate_intersection {
1341 self.write_candidate_intersection_function(module)?;
1342 self.written_candidate_intersection = true;
1343 }
1344 }
1345 _ => {}
1346 }
1347 }
1348 Ok(())
1349 }
1350
1351 pub(super) fn write_wrapped_zero_value_functions(
1355 &mut self,
1356 module: &crate::Module,
1357 expressions: &crate::Arena<crate::Expression>,
1358 ) -> BackendResult {
1359 for (handle, _) in expressions.iter() {
1360 if let crate::Expression::ZeroValue(ty) = expressions[handle] {
1361 let zero_value = WrappedZeroValue { ty };
1362 if self.wrapped.insert(WrappedType::ZeroValue(zero_value)) {
1363 self.write_wrapped_zero_value_function(module, zero_value)?;
1364 }
1365 }
1366 }
1367 Ok(())
1368 }
1369
1370 pub(super) fn write_wrapped_math_functions(
1371 &mut self,
1372 module: &crate::Module,
1373 func_ctx: &FunctionCtx,
1374 ) -> BackendResult {
1375 for (_, expression) in func_ctx.expressions.iter() {
1376 if let crate::Expression::Math {
1377 fun,
1378 arg,
1379 arg1: _arg1,
1380 arg2: _arg2,
1381 arg3: _arg3,
1382 } = *expression
1383 {
1384 let arg_ty = func_ctx.resolve_type(arg, &module.types);
1385
1386 match fun {
1387 crate::MathFunction::ExtractBits => {
1388 let scalar = arg_ty.scalar().unwrap();
1401 let components = arg_ty.components();
1402
1403 let wrapped = WrappedMath {
1404 fun,
1405 scalar,
1406 components,
1407 };
1408
1409 if !self.wrapped.insert(WrappedType::Math(wrapped)) {
1410 continue;
1411 }
1412
1413 self.write_value_type(module, arg_ty)?;
1415
1416 let scalar_width: u8 = scalar.width * 8;
1417
1418 writeln!(self.out, " {EXTRACT_BITS_FUNCTION}(")?;
1420 write!(self.out, " ")?;
1421 self.write_value_type(module, arg_ty)?;
1422 writeln!(self.out, " e,")?;
1423 writeln!(self.out, " uint offset,")?;
1424 writeln!(self.out, " uint count")?;
1425 writeln!(self.out, ") {{")?;
1426
1427 writeln!(self.out, " uint w = {scalar_width};")?;
1429 writeln!(self.out, " uint o = min(offset, w);")?;
1430 writeln!(self.out, " uint c = min(count, w - o);")?;
1431 writeln!(
1432 self.out,
1433 " return (c == 0 ? 0 : (e << (w - c - o)) >> (w - c));"
1434 )?;
1435
1436 writeln!(self.out, "}}")?;
1438 }
1439 crate::MathFunction::InsertBits => {
1440 let scalar = arg_ty.scalar().unwrap();
1443 let components = arg_ty.components();
1444
1445 let wrapped = WrappedMath {
1446 fun,
1447 scalar,
1448 components,
1449 };
1450
1451 if !self.wrapped.insert(WrappedType::Math(wrapped)) {
1452 continue;
1453 }
1454
1455 self.write_value_type(module, arg_ty)?;
1457
1458 let scalar_width: u8 = scalar.width * 8;
1459 let scalar_max: u64 = match scalar.width {
1460 1 => 0xFF,
1461 2 => 0xFFFF,
1462 4 => 0xFFFFFFFF,
1463 8 => 0xFFFFFFFFFFFFFFFF,
1464 _ => unreachable!(),
1465 };
1466
1467 writeln!(self.out, " {INSERT_BITS_FUNCTION}(")?;
1469 write!(self.out, " ")?;
1470 self.write_value_type(module, arg_ty)?;
1471 writeln!(self.out, " e,")?;
1472 write!(self.out, " ")?;
1473 self.write_value_type(module, arg_ty)?;
1474 writeln!(self.out, " newbits,")?;
1475 writeln!(self.out, " uint offset,")?;
1476 writeln!(self.out, " uint count")?;
1477 writeln!(self.out, ") {{")?;
1478
1479 writeln!(self.out, " uint w = {scalar_width}u;")?;
1481 writeln!(self.out, " uint o = min(offset, w);")?;
1482 writeln!(self.out, " uint c = min(count, w - o);")?;
1483
1484 writeln!(
1487 self.out,
1488 " uint mask = (({scalar_max}u >> ({scalar_width}u - c)) << o);"
1489 )?;
1490 writeln!(
1491 self.out,
1492 " return (c == 0 ? e : ((e & ~mask) | ((newbits << o) & mask)));"
1493 )?;
1494
1495 writeln!(self.out, "}}")?;
1497 }
1498 crate::MathFunction::Abs
1509 if matches!(arg_ty.scalar(), Some(crate::Scalar::I32)) =>
1510 {
1511 let scalar = arg_ty.scalar().unwrap();
1512 let components = arg_ty.components();
1513
1514 let wrapped = WrappedMath {
1515 fun,
1516 scalar,
1517 components,
1518 };
1519
1520 if !self.wrapped.insert(WrappedType::Math(wrapped)) {
1521 continue;
1522 }
1523
1524 self.write_value_type(module, arg_ty)?;
1525 write!(self.out, " {ABS_FUNCTION}(")?;
1526 self.write_value_type(module, arg_ty)?;
1527 writeln!(self.out, " val) {{")?;
1528
1529 let level = crate::back::Level(1);
1530 writeln!(
1531 self.out,
1532 "{level}return val >= 0 ? val : asint(-asuint(val));"
1533 )?;
1534 writeln!(self.out, "}}")?;
1535 writeln!(self.out)?;
1536 }
1537 _ => {}
1538 }
1539 }
1540 }
1541
1542 Ok(())
1543 }
1544
1545 pub(super) fn write_wrapped_unary_ops(
1546 &mut self,
1547 module: &crate::Module,
1548 func_ctx: &FunctionCtx,
1549 ) -> BackendResult {
1550 for (_, expression) in func_ctx.expressions.iter() {
1551 if let crate::Expression::Unary { op, expr } = *expression {
1552 let expr_ty = func_ctx.resolve_type(expr, &module.types);
1553 let Some((vector_size, scalar)) = expr_ty.vector_size_and_scalar() else {
1554 continue;
1555 };
1556 let wrapped = WrappedUnaryOp {
1557 op,
1558 ty: (vector_size, scalar),
1559 };
1560
1561 match (op, scalar) {
1570 (crate::UnaryOperator::Negate, crate::Scalar::I32) => {
1571 if !self.wrapped.insert(WrappedType::UnaryOp(wrapped)) {
1572 continue;
1573 }
1574
1575 self.write_value_type(module, expr_ty)?;
1576 write!(self.out, " {NEG_FUNCTION}(")?;
1577 self.write_value_type(module, expr_ty)?;
1578 writeln!(self.out, " val) {{")?;
1579
1580 let level = crate::back::Level(1);
1581 writeln!(self.out, "{level}return asint(-asuint(val));",)?;
1582 writeln!(self.out, "}}")?;
1583 writeln!(self.out)?;
1584 }
1585 _ => {}
1586 }
1587 }
1588 }
1589
1590 Ok(())
1591 }
1592
1593 pub(super) fn write_wrapped_binary_ops(
1594 &mut self,
1595 module: &crate::Module,
1596 func_ctx: &FunctionCtx,
1597 ) -> BackendResult {
1598 for (expr_handle, expression) in func_ctx.expressions.iter() {
1599 if let crate::Expression::Binary { op, left, right } = *expression {
1600 let expr_ty = func_ctx.resolve_type(expr_handle, &module.types);
1601 let left_ty = func_ctx.resolve_type(left, &module.types);
1602 let right_ty = func_ctx.resolve_type(right, &module.types);
1603
1604 match (op, expr_ty.scalar()) {
1605 (
1613 crate::BinaryOperator::Divide,
1614 Some(
1615 scalar @ crate::Scalar {
1616 kind: ScalarKind::Sint | ScalarKind::Uint,
1617 ..
1618 },
1619 ),
1620 ) => {
1621 let Some(left_wrapped_ty) = left_ty.vector_size_and_scalar() else {
1622 continue;
1623 };
1624 let Some(right_wrapped_ty) = right_ty.vector_size_and_scalar() else {
1625 continue;
1626 };
1627 let wrapped = WrappedBinaryOp {
1628 op,
1629 left_ty: left_wrapped_ty,
1630 right_ty: right_wrapped_ty,
1631 };
1632 if !self.wrapped.insert(WrappedType::BinaryOp(wrapped)) {
1633 continue;
1634 }
1635
1636 self.write_value_type(module, expr_ty)?;
1637 write!(self.out, " {DIV_FUNCTION}(")?;
1638 self.write_value_type(module, left_ty)?;
1639 write!(self.out, " lhs, ")?;
1640 self.write_value_type(module, right_ty)?;
1641 writeln!(self.out, " rhs) {{")?;
1642 let level = crate::back::Level(1);
1643 match scalar.kind {
1644 ScalarKind::Sint => {
1645 let min_val = match scalar.width {
1646 2 => crate::Literal::I16(i16::MIN),
1647 4 => crate::Literal::I32(i32::MIN),
1648 8 => crate::Literal::I64(i64::MIN),
1649 _ => {
1650 return Err(super::Error::UnsupportedScalar(scalar));
1651 }
1652 };
1653 write!(self.out, "{level}return lhs / (((lhs == ")?;
1654 self.write_literal(min_val)?;
1655 writeln!(self.out, " & rhs == -1) | (rhs == 0)) ? 1 : rhs);")?
1656 }
1657 ScalarKind::Uint => {
1658 writeln!(self.out, "{level}return lhs / (rhs == 0u ? 1u : rhs);")?
1659 }
1660 _ => unreachable!(),
1661 }
1662 writeln!(self.out, "}}")?;
1663 writeln!(self.out)?;
1664 }
1665 (
1678 crate::BinaryOperator::Modulo,
1679 Some(
1680 scalar @ crate::Scalar {
1681 kind: ScalarKind::Sint | ScalarKind::Uint | ScalarKind::Float,
1682 ..
1683 },
1684 ),
1685 ) => {
1686 let Some(left_wrapped_ty) = left_ty.vector_size_and_scalar() else {
1687 continue;
1688 };
1689 let Some(right_wrapped_ty) = right_ty.vector_size_and_scalar() else {
1690 continue;
1691 };
1692 let wrapped = WrappedBinaryOp {
1693 op,
1694 left_ty: left_wrapped_ty,
1695 right_ty: right_wrapped_ty,
1696 };
1697 if !self.wrapped.insert(WrappedType::BinaryOp(wrapped)) {
1698 continue;
1699 }
1700
1701 self.write_value_type(module, expr_ty)?;
1702 write!(self.out, " {MOD_FUNCTION}(")?;
1703 self.write_value_type(module, left_ty)?;
1704 write!(self.out, " lhs, ")?;
1705 self.write_value_type(module, right_ty)?;
1706 writeln!(self.out, " rhs) {{")?;
1707 let level = crate::back::Level(1);
1708 match scalar.kind {
1709 ScalarKind::Sint => {
1710 let min_val = match scalar.width {
1711 2 => crate::Literal::I16(i16::MIN),
1712 4 => crate::Literal::I32(i32::MIN),
1713 8 => crate::Literal::I64(i64::MIN),
1714 _ => {
1715 return Err(super::Error::UnsupportedScalar(scalar));
1716 }
1717 };
1718 write!(self.out, "{level}")?;
1719 self.write_value_type(module, right_ty)?;
1720 write!(self.out, " divisor = ((lhs == ")?;
1721 self.write_literal(min_val)?;
1722 writeln!(self.out, " & rhs == -1) | (rhs == 0)) ? 1 : rhs;")?;
1723 writeln!(
1724 self.out,
1725 "{level}return lhs - (lhs / divisor) * divisor;"
1726 )?
1727 }
1728 ScalarKind::Uint => {
1729 writeln!(self.out, "{level}return lhs % (rhs == 0u ? 1u : rhs);")?
1730 }
1731 ScalarKind::Float => {
1737 writeln!(self.out, "{level}return lhs - rhs * trunc(lhs / rhs);")?
1738 }
1739 _ => unreachable!(),
1740 }
1741 writeln!(self.out, "}}")?;
1742 writeln!(self.out)?;
1743 }
1744 _ => {}
1745 }
1746 }
1747 }
1748
1749 Ok(())
1750 }
1751
1752 fn write_wrapped_cast_functions(
1753 &mut self,
1754 module: &crate::Module,
1755 func_ctx: &FunctionCtx,
1756 ) -> BackendResult {
1757 for (_, expression) in func_ctx.expressions.iter() {
1758 if let crate::Expression::As {
1759 expr,
1760 kind,
1761 convert: Some(width),
1762 } = *expression
1763 {
1764 let src_ty = func_ctx.resolve_type(expr, &module.types);
1775 let Some((vector_size, src_scalar)) = src_ty.vector_size_and_scalar() else {
1776 continue;
1777 };
1778 let dst_scalar = crate::Scalar { kind, width };
1779 if src_scalar.kind != ScalarKind::Float
1780 || (dst_scalar.kind != ScalarKind::Sint && dst_scalar.kind != ScalarKind::Uint)
1781 {
1782 continue;
1783 }
1784
1785 let wrapped = WrappedCast {
1786 src_scalar,
1787 vector_size,
1788 dst_scalar,
1789 };
1790 if !self.wrapped.insert(WrappedType::Cast(wrapped)) {
1791 continue;
1792 }
1793
1794 let (src_ty, dst_ty) = match vector_size {
1795 None => (
1796 crate::TypeInner::Scalar(src_scalar),
1797 crate::TypeInner::Scalar(dst_scalar),
1798 ),
1799 Some(vector_size) => (
1800 crate::TypeInner::Vector {
1801 scalar: src_scalar,
1802 size: vector_size,
1803 },
1804 crate::TypeInner::Vector {
1805 scalar: dst_scalar,
1806 size: vector_size,
1807 },
1808 ),
1809 };
1810 let (min, max) =
1811 crate::proc::min_max_float_representable_by(src_scalar, dst_scalar);
1812 let cast_str = format!(
1813 "{}{}",
1814 dst_scalar.to_hlsl_str()?,
1815 vector_size
1816 .map(crate::common::vector_size_str)
1817 .unwrap_or(""),
1818 );
1819 let fun_name = match dst_scalar {
1820 crate::Scalar::I32 => F2I32_FUNCTION,
1821 crate::Scalar::U32 => F2U32_FUNCTION,
1822 crate::Scalar::I64 => F2I64_FUNCTION,
1823 crate::Scalar::U64 => F2U64_FUNCTION,
1824 _ => unreachable!(),
1825 };
1826 self.write_value_type(module, &dst_ty)?;
1827 write!(self.out, " {fun_name}(")?;
1828 self.write_value_type(module, &src_ty)?;
1829 writeln!(self.out, " value) {{")?;
1830 let level = crate::back::Level(1);
1831 write!(self.out, "{level}return {cast_str}(clamp(value, ")?;
1832 self.write_literal(min)?;
1833 write!(self.out, ", ")?;
1834 self.write_literal(max)?;
1835 writeln!(self.out, "));",)?;
1836 writeln!(self.out, "}}")?;
1837 writeln!(self.out)?;
1838 }
1839 }
1840 Ok(())
1841 }
1842
1843 pub(super) fn write_wrapped_functions(
1845 &mut self,
1846 module: &crate::Module,
1847 func_ctx: &FunctionCtx,
1848 ) -> BackendResult {
1849 self.write_wrapped_math_functions(module, func_ctx)?;
1850 self.write_wrapped_unary_ops(module, func_ctx)?;
1851 self.write_wrapped_binary_ops(module, func_ctx)?;
1852 self.write_wrapped_expression_functions(module, func_ctx.expressions, Some(func_ctx))?;
1853 self.write_wrapped_zero_value_functions(module, func_ctx.expressions)?;
1854 self.write_wrapped_cast_functions(module, func_ctx)?;
1855
1856 for (handle, _) in func_ctx.expressions.iter() {
1857 match func_ctx.expressions[handle] {
1858 crate::Expression::ArrayLength(expr) => {
1859 let global_expr = match func_ctx.expressions[expr] {
1860 crate::Expression::GlobalVariable(_) => expr,
1861 crate::Expression::AccessIndex { base, index: _ } => base,
1862 ref other => unreachable!("Array length of {:?}", other),
1863 };
1864 let global_var = match func_ctx.expressions[global_expr] {
1865 crate::Expression::GlobalVariable(var_handle) => {
1866 &module.global_variables[var_handle]
1867 }
1868 ref other => {
1869 return Err(super::Error::Unimplemented(format!(
1870 "Array length of base {other:?}"
1871 )))
1872 }
1873 };
1874 let storage_access = match global_var.space {
1875 crate::AddressSpace::Storage { access } => access,
1876 _ => crate::StorageAccess::default(),
1877 };
1878 let wal = WrappedArrayLength {
1879 writable: storage_access.contains(crate::StorageAccess::STORE),
1880 };
1881
1882 if self.wrapped.insert(WrappedType::ArrayLength(wal)) {
1883 self.write_wrapped_array_length_function(wal)?;
1884 }
1885 }
1886 crate::Expression::ImageLoad { image, .. } => {
1887 let class = match *func_ctx.resolve_type(image, &module.types) {
1888 crate::TypeInner::Image { class, .. } => class,
1889 _ => unreachable!(),
1890 };
1891 let wrapped = WrappedImageLoad { class };
1892 if self.wrapped.insert(WrappedType::ImageLoad(wrapped)) {
1893 self.write_wrapped_image_load_function(module, wrapped)?;
1894 }
1895 }
1896 crate::Expression::ImageSample {
1897 image,
1898 clamp_to_edge,
1899 ..
1900 } => {
1901 let class = match *func_ctx.resolve_type(image, &module.types) {
1902 crate::TypeInner::Image { class, .. } => class,
1903 _ => unreachable!(),
1904 };
1905 let wrapped = WrappedImageSample {
1906 class,
1907 clamp_to_edge,
1908 };
1909 if self.wrapped.insert(WrappedType::ImageSample(wrapped)) {
1910 self.write_wrapped_image_sample_function(module, wrapped)?;
1911 }
1912 }
1913 crate::Expression::ImageQuery { image, query } => {
1914 let wiq = match *func_ctx.resolve_type(image, &module.types) {
1915 crate::TypeInner::Image {
1916 dim,
1917 arrayed,
1918 class,
1919 } => WrappedImageQuery {
1920 dim,
1921 arrayed,
1922 class,
1923 query: query.into(),
1924 },
1925 _ => unreachable!("we only query images"),
1926 };
1927
1928 if self.wrapped.insert(WrappedType::ImageQuery(wiq)) {
1929 self.write_wrapped_image_query_function(module, wiq, handle, func_ctx)?;
1930 }
1931 }
1932 crate::Expression::Load { pointer } => {
1935 let pointer_space = func_ctx
1936 .resolve_type(pointer, &module.types)
1937 .pointer_space();
1938
1939 if let Some(crate::AddressSpace::Storage { .. }) = pointer_space {
1940 if let Some(ty) = func_ctx.info[handle].ty.handle() {
1941 write_wrapped_constructor(self, ty, module)?;
1942 }
1943 }
1944
1945 fn write_wrapped_constructor<W: Write>(
1946 writer: &mut super::Writer<'_, W>,
1947 ty: Handle<crate::Type>,
1948 module: &crate::Module,
1949 ) -> BackendResult {
1950 match module.types[ty].inner {
1951 crate::TypeInner::Struct { ref members, .. } => {
1952 for member in members {
1953 write_wrapped_constructor(writer, member.ty, module)?;
1954 }
1955
1956 let constructor = WrappedConstructor { ty };
1957 if writer.wrapped.insert(WrappedType::Constructor(constructor)) {
1958 writer
1959 .write_wrapped_constructor_function(module, constructor)?;
1960 }
1961 }
1962 crate::TypeInner::Array { base, .. } => {
1963 write_wrapped_constructor(writer, base, module)?;
1964
1965 let constructor = WrappedConstructor { ty };
1966 if writer.wrapped.insert(WrappedType::Constructor(constructor)) {
1967 writer
1968 .write_wrapped_constructor_function(module, constructor)?;
1969 }
1970 }
1971 _ => {}
1972 };
1973
1974 Ok(())
1975 }
1976 }
1977 crate::Expression::AccessIndex { base, index } => {
1982 let base_ty_res = &func_ctx.info[base].ty;
1983 let mut resolved = base_ty_res.inner_with(&module.types);
1984 let base_ty_handle = match *resolved {
1985 crate::TypeInner::Pointer { base, .. } => {
1986 resolved = &module.types[base].inner;
1987 Some(base)
1988 }
1989 _ => base_ty_res.handle(),
1990 };
1991 if let crate::TypeInner::Struct { ref members, .. } = *resolved {
1992 let member = &members[index as usize];
1993
1994 match module.types[member.ty].inner {
1995 crate::TypeInner::Matrix {
1996 rows: crate::VectorSize::Bi,
1997 ..
1998 } if member.binding.is_none() => {
1999 let ty = base_ty_handle.unwrap();
2000 let access = WrappedStructMatrixAccess { ty, index };
2001
2002 if self.wrapped.insert(WrappedType::StructMatrixAccess(access)) {
2003 self.write_wrapped_struct_matrix_get_function(module, access)?;
2004 self.write_wrapped_struct_matrix_set_function(module, access)?;
2005 self.write_wrapped_struct_matrix_set_vec_function(
2006 module, access,
2007 )?;
2008 self.write_wrapped_struct_matrix_set_scalar_function(
2009 module, access,
2010 )?;
2011 }
2012 }
2013 _ => {}
2014 }
2015 }
2016 }
2017 _ => {}
2018 };
2019 }
2020
2021 Ok(())
2022 }
2023
2024 pub(super) fn write_sampler_heaps(&mut self) -> BackendResult {
2026 if self.wrapped.sampler_heaps {
2027 return Ok(());
2028 }
2029
2030 writeln!(
2031 self.out,
2032 "SamplerState {}[2048]: register(s{}, space{});",
2033 super::writer::SAMPLER_HEAP_VAR,
2034 self.options.sampler_heap_target.standard_samplers.register,
2035 self.options.sampler_heap_target.standard_samplers.space
2036 )?;
2037 writeln!(
2038 self.out,
2039 "SamplerComparisonState {}[2048]: register(s{}, space{});",
2040 super::writer::COMPARISON_SAMPLER_HEAP_VAR,
2041 self.options
2042 .sampler_heap_target
2043 .comparison_samplers
2044 .register,
2045 self.options.sampler_heap_target.comparison_samplers.space
2046 )?;
2047
2048 self.wrapped.sampler_heaps = true;
2049
2050 Ok(())
2051 }
2052
2053 pub(super) fn write_wrapped_sampler_buffer(
2055 &mut self,
2056 key: super::SamplerIndexBufferKey,
2057 ) -> BackendResult {
2058 if self.wrapped.sampler_index_buffers.contains_key(&key) {
2065 return Ok(());
2066 };
2067
2068 self.write_sampler_heaps()?;
2069
2070 let sampler_array_name = self
2073 .namer
2074 .call(&format!("nagaGroup{}SamplerIndexArray", key.group));
2075
2076 let bind_target = match self.options.sampler_buffer_binding_map.get(&key) {
2077 Some(&bind_target) => bind_target,
2078 None if self.options.fake_missing_bindings => super::BindTarget {
2079 space: u8::MAX,
2080 register: key.group,
2081 binding_array_size: None,
2082 dynamic_storage_buffer_offsets_index: None,
2083 restrict_indexing: false,
2084 },
2085 None => {
2086 unreachable!("Sampler buffer of group {key:?} not bound to a register");
2087 }
2088 };
2089
2090 writeln!(
2091 self.out,
2092 "StructuredBuffer<uint> {sampler_array_name} : register(t{}, space{});",
2093 bind_target.register, bind_target.space
2094 )?;
2095
2096 self.wrapped
2097 .sampler_index_buffers
2098 .insert(key, sampler_array_name);
2099
2100 Ok(())
2101 }
2102
2103 pub(super) fn write_texture_coordinates(
2104 &mut self,
2105 kind: &str,
2106 coordinate: Handle<crate::Expression>,
2107 array_index: Option<Handle<crate::Expression>>,
2108 mip_level: Option<Handle<crate::Expression>>,
2109 module: &crate::Module,
2110 func_ctx: &FunctionCtx,
2111 ) -> BackendResult {
2112 let extra = array_index.is_some() as usize + (mip_level.is_some()) as usize;
2114 if extra == 0 {
2115 self.write_expr(module, coordinate, func_ctx)?;
2116 } else {
2117 let num_coords = match *func_ctx.resolve_type(coordinate, &module.types) {
2118 crate::TypeInner::Scalar { .. } => 1,
2119 crate::TypeInner::Vector { size, .. } => size as usize,
2120 _ => unreachable!(),
2121 };
2122 write!(self.out, "{}{}(", kind, num_coords + extra)?;
2123 self.write_expr(module, coordinate, func_ctx)?;
2124 if let Some(expr) = array_index {
2125 write!(self.out, ", ")?;
2126 self.write_expr(module, expr, func_ctx)?;
2127 }
2128 if let Some(expr) = mip_level {
2129 let cast_to_int = matches!(
2131 *func_ctx.resolve_type(expr, &module.types),
2132 crate::TypeInner::Scalar(crate::Scalar {
2133 kind: ScalarKind::Uint,
2134 ..
2135 })
2136 );
2137
2138 write!(self.out, ", ")?;
2139
2140 if cast_to_int {
2141 write!(self.out, "int(")?;
2142 }
2143
2144 self.write_expr(module, expr, func_ctx)?;
2145
2146 if cast_to_int {
2147 write!(self.out, ")")?;
2148 }
2149 }
2150 write!(self.out, ")")?;
2151 }
2152 Ok(())
2153 }
2154
2155 pub(super) fn write_mat_cx2_typedef_and_functions(
2156 &mut self,
2157 WrappedMatCx2 { columns, width }: WrappedMatCx2,
2158 ) -> BackendResult {
2159 use crate::back::INDENT;
2160
2161 let bit_width = width * 8;
2162 let type_name = crate::Scalar {
2163 kind: ScalarKind::Float,
2164 width,
2165 }
2166 .to_hlsl_str()?;
2167
2168 write!(self.out, "typedef struct {{ ")?;
2170 for i in 0..columns as u8 {
2171 write!(self.out, "{type_name}2 _{i}; ")?;
2172 }
2173 writeln!(self.out, "}} __mat{}x2_f{bit_width};", columns as u8)?;
2174
2175 writeln!(
2177 self.out,
2178 "{type_name}2 __get_col_of_mat{}x2_f{bit_width}(__mat{}x2_f{bit_width} mat, uint idx) {{",
2179 columns as u8, columns as u8
2180 )?;
2181 writeln!(self.out, "{INDENT}switch(idx) {{")?;
2182 for i in 0..columns as u8 {
2183 writeln!(self.out, "{INDENT}case {i}: {{ return mat._{i}; }}")?;
2184 }
2185 writeln!(self.out, "{INDENT}default: {{ return ({type_name}2)0; }}")?;
2186 writeln!(self.out, "{INDENT}}}")?;
2187 writeln!(self.out, "}}")?;
2188
2189 writeln!(
2191 self.out,
2192 "void __set_col_of_mat{}x2_f{bit_width}(__mat{}x2_f{bit_width} mat, uint idx, {type_name}2 value) {{",
2193 columns as u8, columns as u8
2194 )?;
2195 writeln!(self.out, "{INDENT}switch(idx) {{")?;
2196 for i in 0..columns as u8 {
2197 writeln!(self.out, "{INDENT}case {i}: {{ mat._{i} = value; break; }}")?;
2198 }
2199 writeln!(self.out, "{INDENT}}}")?;
2200 writeln!(self.out, "}}")?;
2201
2202 writeln!(
2204 self.out,
2205 "void __set_el_of_mat{}x2_f{bit_width}(__mat{}x2_f{bit_width} mat, uint idx, uint vec_idx, {type_name} value) {{",
2206 columns as u8, columns as u8
2207 )?;
2208 writeln!(self.out, "{INDENT}switch(idx) {{")?;
2209 for i in 0..columns as u8 {
2210 writeln!(
2211 self.out,
2212 "{INDENT}case {i}: {{ mat._{i}[vec_idx] = value; break; }}"
2213 )?;
2214 }
2215 writeln!(self.out, "{INDENT}}}")?;
2216 writeln!(self.out, "}}")?;
2217
2218 writeln!(self.out)?;
2219
2220 Ok(())
2221 }
2222
2223 pub(super) fn write_all_mat_cx2_typedefs_and_functions(
2224 &mut self,
2225 module: &crate::Module,
2226 ) -> BackendResult {
2227 for (handle, _) in module.global_variables.iter() {
2228 let global = &module.global_variables[handle];
2229
2230 if global.space == crate::AddressSpace::Uniform {
2231 if let Some(super::writer::MatrixType {
2232 columns,
2233 rows: crate::VectorSize::Bi,
2234 width,
2235 }) = super::writer::get_inner_matrix_data(module, global.ty)
2236 {
2237 let entry = WrappedMatCx2 { columns, width };
2238 if self.wrapped.insert(WrappedType::MatCx2(entry)) {
2239 self.write_mat_cx2_typedef_and_functions(entry)?;
2240 }
2241 }
2242 }
2243 }
2244
2245 for (_, ty) in module.types.iter() {
2246 if let crate::TypeInner::Struct { ref members, .. } = ty.inner {
2247 for member in members.iter() {
2248 if let crate::TypeInner::Array { .. } = module.types[member.ty].inner {
2249 if let Some(super::writer::MatrixType {
2250 columns,
2251 rows: crate::VectorSize::Bi,
2252 width,
2253 }) = super::writer::get_inner_matrix_data(module, member.ty)
2254 {
2255 let entry = WrappedMatCx2 { columns, width };
2256 if self.wrapped.insert(WrappedType::MatCx2(entry)) {
2257 self.write_mat_cx2_typedef_and_functions(entry)?;
2258 }
2259 }
2260 }
2261 }
2262 }
2263 }
2264
2265 Ok(())
2266 }
2267
2268 pub(super) fn write_wrapped_zero_value_function_name(
2269 &mut self,
2270 module: &crate::Module,
2271 zero_value: WrappedZeroValue,
2272 ) -> BackendResult {
2273 let name = crate::TypeInner::hlsl_type_id(zero_value.ty, module.to_ctx(), &self.names)?;
2274 write!(self.out, "ZeroValue{name}")?;
2275 Ok(())
2276 }
2277
2278 fn write_wrapped_zero_value_function(
2294 &mut self,
2295 module: &crate::Module,
2296 zero_value: WrappedZeroValue,
2297 ) -> BackendResult {
2298 use crate::back::INDENT;
2299
2300 if let crate::TypeInner::Array { base, size, .. } = module.types[zero_value.ty].inner {
2302 write!(self.out, "typedef ")?;
2303 self.write_type(module, zero_value.ty)?;
2304 write!(self.out, " ret_")?;
2305 self.write_wrapped_zero_value_function_name(module, zero_value)?;
2306 self.write_array_size(module, base, size)?;
2307 writeln!(self.out, ";")?;
2308
2309 write!(self.out, "ret_")?;
2310 self.write_wrapped_zero_value_function_name(module, zero_value)?;
2311 } else {
2312 self.write_type(module, zero_value.ty)?;
2313 }
2314 write!(self.out, " ")?;
2315 self.write_wrapped_zero_value_function_name(module, zero_value)?;
2316
2317 writeln!(self.out, "() {{")?;
2319
2320 write!(self.out, "{INDENT}return ")?;
2322 self.write_default_init(module, zero_value.ty)?;
2323 writeln!(self.out, ";")?;
2324
2325 writeln!(self.out, "}}")?;
2327 writeln!(self.out)?;
2329
2330 Ok(())
2331 }
2332}
2333
2334impl crate::StorageFormat {
2335 pub(super) const fn single_component(&self) -> bool {
2337 match *self {
2338 crate::StorageFormat::R16Float
2339 | crate::StorageFormat::R32Float
2340 | crate::StorageFormat::R8Unorm
2341 | crate::StorageFormat::R16Unorm
2342 | crate::StorageFormat::R8Snorm
2343 | crate::StorageFormat::R16Snorm
2344 | crate::StorageFormat::R8Uint
2345 | crate::StorageFormat::R16Uint
2346 | crate::StorageFormat::R32Uint
2347 | crate::StorageFormat::R8Sint
2348 | crate::StorageFormat::R16Sint
2349 | crate::StorageFormat::R32Sint
2350 | crate::StorageFormat::R64Uint => true,
2351 _ => false,
2352 }
2353 }
2354}