1use alloc::format;
4use alloc::string::{String, ToString};
5
6pub trait ToWgsl: Sized {
19 fn to_wgsl(self) -> &'static str;
21}
22
23pub trait TryToWgsl: Sized {
37 fn try_to_wgsl(self) -> Option<&'static str>;
42
43 const DESCRIPTION: &'static str;
45
46 fn to_wgsl_for_diagnostics(self) -> String
57 where
58 Self: core::fmt::Debug + Copy,
59 {
60 match self.try_to_wgsl() {
61 Some(static_string) => static_string.to_string(),
62 None => format!("{{non-WGSL {} {self:?}}}", Self::DESCRIPTION),
63 }
64 }
65}
66
67impl TryToWgsl for crate::MathFunction {
68 const DESCRIPTION: &'static str = "math function";
69
70 fn try_to_wgsl(self) -> Option<&'static str> {
71 use crate::MathFunction as Mf;
72
73 Some(match self {
74 Mf::Abs => "abs",
75 Mf::Min => "min",
76 Mf::Max => "max",
77 Mf::Clamp => "clamp",
78 Mf::Saturate => "saturate",
79 Mf::Cos => "cos",
80 Mf::Cosh => "cosh",
81 Mf::Sin => "sin",
82 Mf::Sinh => "sinh",
83 Mf::Tan => "tan",
84 Mf::Tanh => "tanh",
85 Mf::Acos => "acos",
86 Mf::Asin => "asin",
87 Mf::Atan => "atan",
88 Mf::Atan2 => "atan2",
89 Mf::Asinh => "asinh",
90 Mf::Acosh => "acosh",
91 Mf::Atanh => "atanh",
92 Mf::Radians => "radians",
93 Mf::Degrees => "degrees",
94 Mf::Ceil => "ceil",
95 Mf::Floor => "floor",
96 Mf::Round => "round",
97 Mf::Fract => "fract",
98 Mf::Trunc => "trunc",
99 Mf::Modf => "modf",
100 Mf::Frexp => "frexp",
101 Mf::Ldexp => "ldexp",
102 Mf::Exp => "exp",
103 Mf::Exp2 => "exp2",
104 Mf::Log => "log",
105 Mf::Log2 => "log2",
106 Mf::Pow => "pow",
107 Mf::Dot => "dot",
108 Mf::Dot4I8Packed => "dot4I8Packed",
109 Mf::Dot4U8Packed => "dot4U8Packed",
110 Mf::Cross => "cross",
111 Mf::Distance => "distance",
112 Mf::Length => "length",
113 Mf::Normalize => "normalize",
114 Mf::FaceForward => "faceForward",
115 Mf::Reflect => "reflect",
116 Mf::Refract => "refract",
117 Mf::Sign => "sign",
118 Mf::Fma => "fma",
119 Mf::Mix => "mix",
120 Mf::Step => "step",
121 Mf::SmoothStep => "smoothstep",
122 Mf::Sqrt => "sqrt",
123 Mf::InverseSqrt => "inverseSqrt",
124 Mf::Transpose => "transpose",
125 Mf::Determinant => "determinant",
126 Mf::QuantizeToF16 => "quantizeToF16",
127 Mf::CountTrailingZeros => "countTrailingZeros",
128 Mf::CountLeadingZeros => "countLeadingZeros",
129 Mf::CountOneBits => "countOneBits",
130 Mf::ReverseBits => "reverseBits",
131 Mf::ExtractBits => "extractBits",
132 Mf::InsertBits => "insertBits",
133 Mf::FirstTrailingBit => "firstTrailingBit",
134 Mf::FirstLeadingBit => "firstLeadingBit",
135 Mf::Pack4x8snorm => "pack4x8snorm",
136 Mf::Pack4x8unorm => "pack4x8unorm",
137 Mf::Pack2x16snorm => "pack2x16snorm",
138 Mf::Pack2x16unorm => "pack2x16unorm",
139 Mf::Pack2x16float => "pack2x16float",
140 Mf::Pack4xI8 => "pack4xI8",
141 Mf::Pack4xU8 => "pack4xU8",
142 Mf::Pack4xI8Clamp => "pack4xI8Clamp",
143 Mf::Pack4xU8Clamp => "pack4xU8Clamp",
144 Mf::Unpack4x8snorm => "unpack4x8snorm",
145 Mf::Unpack4x8unorm => "unpack4x8unorm",
146 Mf::Unpack2x16snorm => "unpack2x16snorm",
147 Mf::Unpack2x16unorm => "unpack2x16unorm",
148 Mf::Unpack2x16float => "unpack2x16float",
149 Mf::Unpack4xI8 => "unpack4xI8",
150 Mf::Unpack4xU8 => "unpack4xU8",
151
152 Mf::Inverse | Mf::Outer => return None,
154 })
155 }
156}
157
158impl TryToWgsl for crate::BuiltIn {
159 const DESCRIPTION: &'static str = "builtin value";
160
161 fn try_to_wgsl(self) -> Option<&'static str> {
162 use crate::BuiltIn as Bi;
163 Some(match self {
164 Bi::Position { .. } => "position",
165 Bi::ViewIndex => "view_index",
166 Bi::InstanceIndex => "instance_index",
167 Bi::VertexIndex => "vertex_index",
168 Bi::ClipDistances => "clip_distances",
169 Bi::FragDepth => "frag_depth",
170 Bi::FrontFacing => "front_facing",
171 Bi::PrimitiveIndex => "primitive_index",
172 Bi::DrawIndex => "draw_index",
173 Bi::Barycentric { perspective: true } => "barycentric",
174 Bi::Barycentric { perspective: false } => "barycentric_no_perspective",
175 Bi::SampleIndex => "sample_index",
176 Bi::SampleMask => "sample_mask",
177 Bi::GlobalInvocationId => "global_invocation_id",
178 Bi::LocalInvocationId => "local_invocation_id",
179 Bi::LocalInvocationIndex => "local_invocation_index",
180 Bi::WorkGroupId => "workgroup_id",
181 Bi::NumWorkGroups => "num_workgroups",
182 Bi::NumSubgroups => "num_subgroups",
183 Bi::SubgroupId => "subgroup_id",
184 Bi::SubgroupSize => "subgroup_size",
185 Bi::SubgroupInvocationId => "subgroup_invocation_id",
186
187 Bi::MeshTaskSize => "mesh_task_size",
189 Bi::TriangleIndices => "triangle_indices",
190 Bi::LineIndices => "line_indices",
191 Bi::PointIndex => "point_index",
192 Bi::Vertices => "vertices",
193 Bi::Primitives => "primitives",
194 Bi::VertexCount => "vertex_count",
195 Bi::PrimitiveCount => "primitive_count",
196 Bi::CullPrimitive => "cull_primitive",
197
198 Bi::RayInvocationId => "ray_invocation_id",
199 Bi::NumRayInvocations => "num_ray_invocations",
200 Bi::InstanceCustomData => "instance_custom_data",
201 Bi::GeometryIndex => "geometry_index",
202 Bi::WorldRayOrigin => "world_ray_origin",
203 Bi::WorldRayDirection => "world_ray_direction",
204 Bi::ObjectRayOrigin => "object_ray_origin",
205 Bi::ObjectRayDirection => "object_ray_direction",
206 Bi::RayTmin => "ray_t_min",
207 Bi::RayTCurrentMax => "ray_t_current_max",
208 Bi::ObjectToWorld => "object_to_world",
209 Bi::WorldToObject => "world_to_object",
210 Bi::HitKind => "hit_kind",
211 Bi::HitBarycentrics => "hit_barycentrics",
212
213 Bi::BaseInstance
214 | Bi::BaseVertex
215 | Bi::CullDistance
216 | Bi::PointSize
217 | Bi::PointCoord
218 | Bi::WorkGroupSize => return None,
219 })
220 }
221}
222
223impl ToWgsl for crate::Interpolation {
224 fn to_wgsl(self) -> &'static str {
225 match self {
226 crate::Interpolation::Perspective => "perspective",
227 crate::Interpolation::Linear => "linear",
228 crate::Interpolation::Flat => "flat",
229 crate::Interpolation::PerVertex => "per_vertex",
230 }
231 }
232}
233
234impl ToWgsl for crate::Sampling {
235 fn to_wgsl(self) -> &'static str {
236 match self {
237 crate::Sampling::Center => "center",
238 crate::Sampling::Centroid => "centroid",
239 crate::Sampling::Sample => "sample",
240 crate::Sampling::First => "first",
241 crate::Sampling::Either => "either",
242 }
243 }
244}
245
246impl ToWgsl for crate::StorageFormat {
247 fn to_wgsl(self) -> &'static str {
248 use crate::StorageFormat as Sf;
249
250 match self {
251 Sf::R8Unorm => "r8unorm",
252 Sf::R8Snorm => "r8snorm",
253 Sf::R8Uint => "r8uint",
254 Sf::R8Sint => "r8sint",
255 Sf::R16Uint => "r16uint",
256 Sf::R16Sint => "r16sint",
257 Sf::R16Float => "r16float",
258 Sf::Rg8Unorm => "rg8unorm",
259 Sf::Rg8Snorm => "rg8snorm",
260 Sf::Rg8Uint => "rg8uint",
261 Sf::Rg8Sint => "rg8sint",
262 Sf::R32Uint => "r32uint",
263 Sf::R32Sint => "r32sint",
264 Sf::R32Float => "r32float",
265 Sf::Rg16Uint => "rg16uint",
266 Sf::Rg16Sint => "rg16sint",
267 Sf::Rg16Float => "rg16float",
268 Sf::Rgba8Unorm => "rgba8unorm",
269 Sf::Rgba8Snorm => "rgba8snorm",
270 Sf::Rgba8Uint => "rgba8uint",
271 Sf::Rgba8Sint => "rgba8sint",
272 Sf::Bgra8Unorm => "bgra8unorm",
273 Sf::Rgb10a2Uint => "rgb10a2uint",
274 Sf::Rgb10a2Unorm => "rgb10a2unorm",
275 Sf::Rg11b10Ufloat => "rg11b10ufloat",
276 Sf::R64Uint => "r64uint",
277 Sf::Rg32Uint => "rg32uint",
278 Sf::Rg32Sint => "rg32sint",
279 Sf::Rg32Float => "rg32float",
280 Sf::Rgba16Uint => "rgba16uint",
281 Sf::Rgba16Sint => "rgba16sint",
282 Sf::Rgba16Float => "rgba16float",
283 Sf::Rgba32Uint => "rgba32uint",
284 Sf::Rgba32Sint => "rgba32sint",
285 Sf::Rgba32Float => "rgba32float",
286 Sf::R16Unorm => "r16unorm",
287 Sf::R16Snorm => "r16snorm",
288 Sf::Rg16Unorm => "rg16unorm",
289 Sf::Rg16Snorm => "rg16snorm",
290 Sf::Rgba16Unorm => "rgba16unorm",
291 Sf::Rgba16Snorm => "rgba16snorm",
292 }
293 }
294}
295
296impl TryToWgsl for crate::Scalar {
297 const DESCRIPTION: &'static str = "scalar type";
298
299 fn try_to_wgsl(self) -> Option<&'static str> {
300 use crate::Scalar;
301
302 Some(match self {
303 Scalar::F16 => "f16",
304 Scalar::F32 => "f32",
305 Scalar::F64 => "f64",
306 Scalar::I16 => "i16",
307 Scalar::U16 => "u16",
308 Scalar::I32 => "i32",
309 Scalar::U32 => "u32",
310 Scalar::I64 => "i64",
311 Scalar::U64 => "u64",
312 Scalar::BOOL => "bool",
313 _ => return None,
314 })
315 }
316
317 fn to_wgsl_for_diagnostics(self) -> String {
318 match self.try_to_wgsl() {
319 Some(static_string) => static_string.to_string(),
320 None => match self.kind {
321 crate::ScalarKind::Sint
322 | crate::ScalarKind::Uint
323 | crate::ScalarKind::Float
324 | crate::ScalarKind::Bool => format!("{{non-WGSL scalar {self:?}}}"),
325 crate::ScalarKind::AbstractInt => "{AbstractInt}".to_string(),
326 crate::ScalarKind::AbstractFloat => "{AbstractFloat}".to_string(),
327 },
328 }
329 }
330}
331
332impl ToWgsl for crate::CooperativeRole {
333 fn to_wgsl(self) -> &'static str {
334 match self {
335 Self::A => "A",
336 Self::B => "B",
337 Self::C => "C",
338 }
339 }
340}
341
342impl ToWgsl for crate::ImageDimension {
343 fn to_wgsl(self) -> &'static str {
344 match self {
345 Self::D1 => "1d",
346 Self::D2 => "2d",
347 Self::D3 => "3d",
348 Self::Cube => "cube",
349 }
350 }
351}
352
353pub const fn address_space_str(
372 space: crate::AddressSpace,
373) -> (Option<&'static str>, Option<&'static str>) {
374 use crate::AddressSpace as As;
375
376 (
377 Some(match space {
378 As::Private => "private",
379 As::Uniform => "uniform",
380 As::Storage { access } => {
381 if access.contains(crate::StorageAccess::ATOMIC) {
382 return (Some("storage"), Some("atomic"));
383 } else if access.contains(crate::StorageAccess::STORE) {
384 return (Some("storage"), Some("read_write"));
385 } else {
386 "storage"
387 }
388 }
389 As::Immediate => "immediate",
390 As::WorkGroup => "workgroup",
391 As::Handle => return (None, None),
392 As::Function => "function",
393 As::TaskPayload => "task_payload",
394 As::IncomingRayPayload => "incoming_ray_payload",
395 As::RayPayload => "ray_payload",
396 }),
397 None,
398 )
399}