naga/back/hlsl/
conv.rs

1use crate::common;
2
3use alloc::{borrow::Cow, format, string::String};
4
5use super::Error;
6use crate::proc::Alignment;
7
8impl crate::ScalarKind {
9    pub(super) fn to_hlsl_cast(self) -> &'static str {
10        match self {
11            Self::Float => "asfloat",
12            Self::Sint => "asint",
13            Self::Uint => "asuint",
14            Self::Bool | Self::AbstractInt | Self::AbstractFloat => unreachable!(),
15        }
16    }
17}
18
19impl crate::Scalar {
20    /// Helper function that returns scalar related strings
21    ///
22    /// <https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-scalar>
23    pub(super) const fn to_hlsl_str(self) -> Result<&'static str, Error> {
24        match self.kind {
25            crate::ScalarKind::Sint => match self.width {
26                4 => Ok("int"),
27                8 => Ok("int64_t"),
28                _ => Err(Error::UnsupportedScalar(self)),
29            },
30            crate::ScalarKind::Uint => match self.width {
31                4 => Ok("uint"),
32                8 => Ok("uint64_t"),
33                _ => Err(Error::UnsupportedScalar(self)),
34            },
35            crate::ScalarKind::Float => match self.width {
36                2 => Ok("half"),
37                4 => Ok("float"),
38                8 => Ok("double"),
39                _ => Err(Error::UnsupportedScalar(self)),
40            },
41            crate::ScalarKind::Bool => Ok("bool"),
42            crate::ScalarKind::AbstractInt | crate::ScalarKind::AbstractFloat => {
43                Err(Error::UnsupportedScalar(self))
44            }
45        }
46    }
47}
48
49impl crate::TypeInner {
50    pub(super) const fn is_matrix(&self) -> bool {
51        match *self {
52            Self::Matrix { .. } => true,
53            _ => false,
54        }
55    }
56
57    pub(super) fn size_hlsl(&self, gctx: crate::proc::GlobalCtx) -> Result<u32, Error> {
58        match *self {
59            Self::Matrix {
60                columns,
61                rows,
62                scalar,
63            } => {
64                let stride = Alignment::from(rows) * scalar.width as u32;
65                let last_row_size = rows as u32 * scalar.width as u32;
66                Ok(((columns as u32 - 1) * stride) + last_row_size)
67            }
68            Self::Array { base, size, stride } => {
69                let count = match size.resolve(gctx)? {
70                    crate::proc::IndexableLength::Known(size) => size,
71                    // A dynamically-sized array has to have at least one element
72                    crate::proc::IndexableLength::Dynamic => 1,
73                };
74                let last_el_size = gctx.types[base].inner.size_hlsl(gctx)?;
75                Ok(((count - 1) * stride) + last_el_size)
76            }
77            _ => Ok(self.size(gctx)),
78        }
79    }
80
81    /// Used to generate the name of the wrapped type constructor
82    pub(super) fn hlsl_type_id<'a>(
83        base: crate::Handle<crate::Type>,
84        gctx: crate::proc::GlobalCtx,
85        names: &'a crate::FastHashMap<crate::proc::NameKey, String>,
86    ) -> Result<Cow<'a, str>, Error> {
87        Ok(match gctx.types[base].inner {
88            crate::TypeInner::Scalar(scalar) => Cow::Borrowed(scalar.to_hlsl_str()?),
89            crate::TypeInner::Vector { size, scalar } => Cow::Owned(format!(
90                "{}{}",
91                scalar.to_hlsl_str()?,
92                common::vector_size_str(size)
93            )),
94            crate::TypeInner::Matrix {
95                columns,
96                rows,
97                scalar,
98            } => Cow::Owned(format!(
99                "{}{}x{}",
100                scalar.to_hlsl_str()?,
101                common::vector_size_str(columns),
102                common::vector_size_str(rows),
103            )),
104            crate::TypeInner::Array {
105                base,
106                size: crate::ArraySize::Constant(size),
107                ..
108            } => Cow::Owned(format!(
109                "array{size}_{}_",
110                Self::hlsl_type_id(base, gctx, names)?
111            )),
112            crate::TypeInner::Struct { .. } => {
113                Cow::Borrowed(&names[&crate::proc::NameKey::Type(base)])
114            }
115            _ => unreachable!(),
116        })
117    }
118}
119
120impl crate::StorageFormat {
121    pub(super) const fn to_hlsl_str(self) -> &'static str {
122        match self {
123            Self::R16Float | Self::R32Float => "float",
124            Self::R8Unorm | Self::R16Unorm => "unorm float",
125            Self::R8Snorm | Self::R16Snorm => "snorm float",
126            Self::R8Uint | Self::R16Uint | Self::R32Uint => "uint",
127            Self::R8Sint | Self::R16Sint | Self::R32Sint => "int",
128            Self::R64Uint => "uint64_t",
129
130            Self::Rg16Float | Self::Rg32Float => "float4",
131            Self::Rg8Unorm | Self::Rg16Unorm => "unorm float4",
132            Self::Rg8Snorm | Self::Rg16Snorm => "snorm float4",
133
134            Self::Rg8Sint | Self::Rg16Sint | Self::Rg32Uint => "int4",
135            Self::Rg8Uint | Self::Rg16Uint | Self::Rg32Sint => "uint4",
136
137            Self::Rg11b10Ufloat => "float4",
138
139            Self::Rgba16Float | Self::Rgba32Float => "float4",
140            Self::Rgba8Unorm | Self::Bgra8Unorm | Self::Rgba16Unorm | Self::Rgb10a2Unorm => {
141                "unorm float4"
142            }
143            Self::Rgba8Snorm | Self::Rgba16Snorm => "snorm float4",
144
145            Self::Rgba8Uint | Self::Rgba16Uint | Self::Rgba32Uint | Self::Rgb10a2Uint => "uint4",
146            Self::Rgba8Sint | Self::Rgba16Sint | Self::Rgba32Sint => "int4",
147        }
148    }
149}
150
151impl crate::BuiltIn {
152    pub(super) fn to_hlsl_str(self) -> Result<&'static str, Error> {
153        Ok(match self {
154            Self::Position { .. } => "SV_Position",
155            // vertex
156            Self::ClipDistance => "SV_ClipDistance",
157            Self::CullDistance => "SV_CullDistance",
158            Self::InstanceIndex => "SV_InstanceID",
159            Self::VertexIndex => "SV_VertexID",
160            // fragment
161            Self::FragDepth => "SV_Depth",
162            Self::FrontFacing => "SV_IsFrontFace",
163            Self::PrimitiveIndex => "SV_PrimitiveID",
164            Self::SampleIndex => "SV_SampleIndex",
165            Self::SampleMask => "SV_Coverage",
166            // compute
167            Self::GlobalInvocationId => "SV_DispatchThreadID",
168            Self::LocalInvocationId => "SV_GroupThreadID",
169            Self::LocalInvocationIndex => "SV_GroupIndex",
170            Self::WorkGroupId => "SV_GroupID",
171            // The specific semantic we use here doesn't matter, because references
172            // to this field will get replaced with references to `SPECIAL_CBUF_VAR`
173            // in `Writer::write_expr`.
174            Self::NumWorkGroups => "SV_GroupID",
175            // These builtins map to functions
176            Self::SubgroupSize
177            | Self::SubgroupInvocationId
178            | Self::NumSubgroups
179            | Self::SubgroupId => unreachable!(),
180            Self::BaseInstance | Self::BaseVertex | Self::WorkGroupSize => {
181                return Err(Error::Unimplemented(format!("builtin {self:?}")))
182            }
183            Self::PointSize | Self::ViewIndex | Self::PointCoord | Self::DrawID => {
184                return Err(Error::Custom(format!("Unsupported builtin {self:?}")))
185            }
186        })
187    }
188}
189
190impl crate::Interpolation {
191    /// Return the string corresponding to the HLSL interpolation qualifier.
192    pub(super) const fn to_hlsl_str(self) -> Option<&'static str> {
193        match self {
194            // Would be "linear", but it's the default interpolation in SM4 and up
195            // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-struct#interpolation-modifiers-introduced-in-shader-model-4
196            Self::Perspective => None,
197            Self::Linear => Some("noperspective"),
198            Self::Flat => Some("nointerpolation"),
199        }
200    }
201}
202
203impl crate::Sampling {
204    /// Return the HLSL auxiliary qualifier for the given sampling value.
205    pub(super) const fn to_hlsl_str(self) -> Option<&'static str> {
206        match self {
207            Self::Center | Self::First | Self::Either => None,
208            Self::Centroid => Some("centroid"),
209            Self::Sample => Some("sample"),
210        }
211    }
212}
213
214impl crate::AtomicFunction {
215    /// Return the HLSL suffix for the `InterlockedXxx` method.
216    pub(super) const fn to_hlsl_suffix(self) -> &'static str {
217        match self {
218            Self::Add | Self::Subtract => "Add",
219            Self::And => "And",
220            Self::InclusiveOr => "Or",
221            Self::ExclusiveOr => "Xor",
222            Self::Min => "Min",
223            Self::Max => "Max",
224            Self::Exchange { compare: None } => "Exchange",
225            Self::Exchange { .. } => "CompareExchange",
226        }
227    }
228}