Skip to main content

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