1use crate::proc::GlobalCtx;
4use crate::Handle;
5
6impl crate::proc::TypeResolution {
7 pub fn to_wgsl(&self, gctx: &GlobalCtx) -> String {
8 match *self {
9 crate::proc::TypeResolution::Handle(handle) => handle.to_wgsl(gctx),
10 crate::proc::TypeResolution::Value(ref inner) => inner.to_wgsl(gctx),
11 }
12 }
13}
14
15impl Handle<crate::Type> {
16 pub fn to_wgsl(self, gctx: &GlobalCtx) -> String {
20 let ty = &gctx.types[self];
21 match ty.name {
22 Some(ref name) => name.clone(),
23 None => ty.inner.to_wgsl(gctx),
24 }
25 }
26}
27
28impl crate::TypeInner {
29 pub fn to_wgsl(&self, gctx: &GlobalCtx) -> String {
37 use crate::TypeInner as Ti;
38
39 match *self {
40 Ti::Scalar(scalar) => scalar.to_wgsl(),
41 Ti::Vector { size, scalar } => {
42 format!("vec{}<{}>", size as u32, scalar.to_wgsl())
43 }
44 Ti::Matrix {
45 columns,
46 rows,
47 scalar,
48 } => {
49 format!(
50 "mat{}x{}<{}>",
51 columns as u32,
52 rows as u32,
53 scalar.to_wgsl(),
54 )
55 }
56 Ti::Atomic(scalar) => {
57 format!("atomic<{}>", scalar.to_wgsl())
58 }
59 Ti::Pointer { base, .. } => {
60 let name = base.to_wgsl(gctx);
61 format!("ptr<{name}>")
62 }
63 Ti::ValuePointer { scalar, .. } => {
64 format!("ptr<{}>", scalar.to_wgsl())
65 }
66 Ti::Array { base, size, .. } => {
67 let base = base.to_wgsl(gctx);
68 match size {
69 crate::ArraySize::Constant(size) => format!("array<{base}, {size}>"),
70 crate::ArraySize::Pending(_) => unreachable!(),
71 crate::ArraySize::Dynamic => format!("array<{base}>"),
72 }
73 }
74 Ti::Struct { .. } => {
75 "struct".to_string()
77 }
78 Ti::Image {
79 dim,
80 arrayed,
81 class,
82 } => {
83 let dim_suffix = match dim {
84 crate::ImageDimension::D1 => "_1d",
85 crate::ImageDimension::D2 => "_2d",
86 crate::ImageDimension::D3 => "_3d",
87 crate::ImageDimension::Cube => "_cube",
88 };
89 let array_suffix = if arrayed { "_array" } else { "" };
90
91 let class_suffix = match class {
92 crate::ImageClass::Sampled { multi: true, .. } => "_multisampled",
93 crate::ImageClass::Depth { multi: false } => "_depth",
94 crate::ImageClass::Depth { multi: true } => "_depth_multisampled",
95 crate::ImageClass::Sampled { multi: false, .. }
96 | crate::ImageClass::Storage { .. } => "",
97 };
98
99 let type_in_brackets = match class {
100 crate::ImageClass::Sampled { kind, .. } => {
101 let element_type = crate::Scalar { kind, width: 4 }.to_wgsl();
105 format!("<{element_type}>")
106 }
107 crate::ImageClass::Depth { multi: _ } => String::new(),
108 crate::ImageClass::Storage { format, access } => {
109 if access.contains(crate::StorageAccess::STORE) {
110 format!("<{},write>", format.to_wgsl())
111 } else {
112 format!("<{}>", format.to_wgsl())
113 }
114 }
115 };
116
117 format!("texture{class_suffix}{dim_suffix}{array_suffix}{type_in_brackets}")
118 }
119 Ti::Sampler { .. } => "sampler".to_string(),
120 Ti::AccelerationStructure => "acceleration_structure".to_string(),
121 Ti::RayQuery => "ray_query".to_string(),
122 Ti::BindingArray { base, size, .. } => {
123 let member_type = &gctx.types[base];
124 let base = member_type.name.as_deref().unwrap_or("unknown");
125 match size {
126 crate::ArraySize::Constant(size) => format!("binding_array<{base}, {size}>"),
127 crate::ArraySize::Pending(_) => unreachable!(),
128 crate::ArraySize::Dynamic => format!("binding_array<{base}>"),
129 }
130 }
131 }
132 }
133}
134
135impl crate::Scalar {
136 pub fn to_wgsl(self) -> String {
140 let prefix = match self.kind {
141 crate::ScalarKind::Sint => "i",
142 crate::ScalarKind::Uint => "u",
143 crate::ScalarKind::Float => "f",
144 crate::ScalarKind::Bool => return "bool".to_string(),
145 crate::ScalarKind::AbstractInt => return "{AbstractInt}".to_string(),
146 crate::ScalarKind::AbstractFloat => return "{AbstractFloat}".to_string(),
147 };
148 format!("{}{}", prefix, self.width * 8)
149 }
150}
151
152impl crate::StorageFormat {
153 pub const fn to_wgsl(self) -> &'static str {
154 use crate::StorageFormat as Sf;
155 match self {
156 Sf::R8Unorm => "r8unorm",
157 Sf::R8Snorm => "r8snorm",
158 Sf::R8Uint => "r8uint",
159 Sf::R8Sint => "r8sint",
160 Sf::R16Uint => "r16uint",
161 Sf::R16Sint => "r16sint",
162 Sf::R16Float => "r16float",
163 Sf::Rg8Unorm => "rg8unorm",
164 Sf::Rg8Snorm => "rg8snorm",
165 Sf::Rg8Uint => "rg8uint",
166 Sf::Rg8Sint => "rg8sint",
167 Sf::R32Uint => "r32uint",
168 Sf::R32Sint => "r32sint",
169 Sf::R32Float => "r32float",
170 Sf::Rg16Uint => "rg16uint",
171 Sf::Rg16Sint => "rg16sint",
172 Sf::Rg16Float => "rg16float",
173 Sf::Rgba8Unorm => "rgba8unorm",
174 Sf::Rgba8Snorm => "rgba8snorm",
175 Sf::Rgba8Uint => "rgba8uint",
176 Sf::Rgba8Sint => "rgba8sint",
177 Sf::Bgra8Unorm => "bgra8unorm",
178 Sf::Rgb10a2Uint => "rgb10a2uint",
179 Sf::Rgb10a2Unorm => "rgb10a2unorm",
180 Sf::Rg11b10Ufloat => "rg11b10float",
181 Sf::R64Uint => "r64uint",
182 Sf::Rg32Uint => "rg32uint",
183 Sf::Rg32Sint => "rg32sint",
184 Sf::Rg32Float => "rg32float",
185 Sf::Rgba16Uint => "rgba16uint",
186 Sf::Rgba16Sint => "rgba16sint",
187 Sf::Rgba16Float => "rgba16float",
188 Sf::Rgba32Uint => "rgba32uint",
189 Sf::Rgba32Sint => "rgba32sint",
190 Sf::Rgba32Float => "rgba32float",
191 Sf::R16Unorm => "r16unorm",
192 Sf::R16Snorm => "r16snorm",
193 Sf::Rg16Unorm => "rg16unorm",
194 Sf::Rg16Snorm => "rg16snorm",
195 Sf::Rgba16Unorm => "rgba16unorm",
196 Sf::Rgba16Snorm => "rgba16snorm",
197 }
198 }
199}
200
201mod tests {
202 #[test]
203 fn to_wgsl() {
204 use std::num::NonZeroU32;
205
206 let mut types = crate::UniqueArena::new();
207
208 let mytype1 = types.insert(
209 crate::Type {
210 name: Some("MyType1".to_string()),
211 inner: crate::TypeInner::Struct {
212 members: vec![],
213 span: 0,
214 },
215 },
216 Default::default(),
217 );
218 let mytype2 = types.insert(
219 crate::Type {
220 name: Some("MyType2".to_string()),
221 inner: crate::TypeInner::Struct {
222 members: vec![],
223 span: 0,
224 },
225 },
226 Default::default(),
227 );
228
229 let gctx = crate::proc::GlobalCtx {
230 types: &types,
231 constants: &crate::Arena::new(),
232 overrides: &crate::Arena::new(),
233 global_expressions: &crate::Arena::new(),
234 };
235 let array = crate::TypeInner::Array {
236 base: mytype1,
237 stride: 4,
238 size: crate::ArraySize::Constant(unsafe { NonZeroU32::new_unchecked(32) }),
239 };
240 assert_eq!(array.to_wgsl(&gctx), "array<MyType1, 32>");
241
242 let mat = crate::TypeInner::Matrix {
243 rows: crate::VectorSize::Quad,
244 columns: crate::VectorSize::Bi,
245 scalar: crate::Scalar::F64,
246 };
247 assert_eq!(mat.to_wgsl(&gctx), "mat2x4<f64>");
248
249 let ptr = crate::TypeInner::Pointer {
250 base: mytype2,
251 space: crate::AddressSpace::Storage {
252 access: crate::StorageAccess::default(),
253 },
254 };
255 assert_eq!(ptr.to_wgsl(&gctx), "ptr<MyType2>");
256
257 let img1 = crate::TypeInner::Image {
258 dim: crate::ImageDimension::D2,
259 arrayed: false,
260 class: crate::ImageClass::Sampled {
261 kind: crate::ScalarKind::Float,
262 multi: true,
263 },
264 };
265 assert_eq!(img1.to_wgsl(&gctx), "texture_multisampled_2d<f32>");
266
267 let img2 = crate::TypeInner::Image {
268 dim: crate::ImageDimension::Cube,
269 arrayed: true,
270 class: crate::ImageClass::Depth { multi: false },
271 };
272 assert_eq!(img2.to_wgsl(&gctx), "texture_depth_cube_array");
273
274 let img3 = crate::TypeInner::Image {
275 dim: crate::ImageDimension::D2,
276 arrayed: false,
277 class: crate::ImageClass::Depth { multi: true },
278 };
279 assert_eq!(img3.to_wgsl(&gctx), "texture_depth_multisampled_2d");
280
281 let array = crate::TypeInner::BindingArray {
282 base: mytype1,
283 size: crate::ArraySize::Constant(unsafe { NonZeroU32::new_unchecked(32) }),
284 };
285 assert_eq!(array.to_wgsl(&gctx), "binding_array<MyType1, 32>");
286 }
287}