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