naga/front/glsl/
types.rs

1use alloc::format;
2
3use super::{context::Context, Error, ErrorKind, Result, Span};
4use crate::{
5    proc::ResolveContext, Expression, Handle, ImageClass, ImageDimension, Scalar, ScalarKind, Type,
6    TypeInner, VectorSize,
7};
8
9pub fn parse_type(type_name: &str) -> Option<Type> {
10    match type_name {
11        "bool" => Some(Type {
12            name: None,
13            inner: TypeInner::Scalar(Scalar::BOOL),
14        }),
15        "float16_t" => Some(Type {
16            name: None,
17            inner: TypeInner::Scalar(Scalar::F16),
18        }),
19        "float" => Some(Type {
20            name: None,
21            inner: TypeInner::Scalar(Scalar::F32),
22        }),
23        "double" => Some(Type {
24            name: None,
25            inner: TypeInner::Scalar(Scalar::F64),
26        }),
27        "int" => Some(Type {
28            name: None,
29            inner: TypeInner::Scalar(Scalar::I32),
30        }),
31        "uint" => Some(Type {
32            name: None,
33            inner: TypeInner::Scalar(Scalar::U32),
34        }),
35        "sampler" | "samplerShadow" => Some(Type {
36            name: None,
37            inner: TypeInner::Sampler {
38                comparison: type_name == "samplerShadow",
39            },
40        }),
41        word => {
42            fn kind_width_parse(ty: &str) -> Option<Scalar> {
43                Some(match ty {
44                    "" => Scalar::F32,
45                    "b" => Scalar::BOOL,
46                    "i" => Scalar::I32,
47                    "u" => Scalar::U32,
48                    "d" => Scalar::F64,
49                    "f16" => Scalar::F16,
50                    _ => return None,
51                })
52            }
53
54            fn size_parse(n: &str) -> Option<VectorSize> {
55                Some(match n {
56                    "2" => VectorSize::Bi,
57                    "3" => VectorSize::Tri,
58                    "4" => VectorSize::Quad,
59                    _ => return None,
60                })
61            }
62
63            let vec_parse = |word: &str| {
64                let mut iter = word.split("vec");
65
66                let kind = iter.next()?;
67                let size = iter.next()?;
68                let scalar = kind_width_parse(kind)?;
69                let size = size_parse(size)?;
70
71                Some(Type {
72                    name: None,
73                    inner: TypeInner::Vector { size, scalar },
74                })
75            };
76
77            let mat_parse = |word: &str| {
78                let mut iter = word.split("mat");
79
80                let kind = iter.next()?;
81                let size = iter.next()?;
82                let scalar = kind_width_parse(kind)?;
83
84                let (columns, rows) = if let Some(size) = size_parse(size) {
85                    (size, size)
86                } else {
87                    let mut iter = size.split('x');
88                    match (iter.next()?, iter.next()?, iter.next()) {
89                        (col, row, None) => (size_parse(col)?, size_parse(row)?),
90                        _ => return None,
91                    }
92                };
93
94                Some(Type {
95                    name: None,
96                    inner: TypeInner::Matrix {
97                        columns,
98                        rows,
99                        scalar,
100                    },
101                })
102            };
103
104            let texture_parse = |word: &str| {
105                let mut iter = word.split("texture");
106
107                let texture_kind = |ty| {
108                    Some(match ty {
109                        "" => ScalarKind::Float,
110                        "i" => ScalarKind::Sint,
111                        "u" => ScalarKind::Uint,
112                        _ => return None,
113                    })
114                };
115
116                let kind = iter.next()?;
117                let size = iter.next()?;
118                let kind = texture_kind(kind)?;
119
120                let sampled = |multi| ImageClass::Sampled { kind, multi };
121
122                let (dim, arrayed, class) = match size {
123                    "1D" => (ImageDimension::D1, false, sampled(false)),
124                    "1DArray" => (ImageDimension::D1, true, sampled(false)),
125                    "2D" => (ImageDimension::D2, false, sampled(false)),
126                    "2DArray" => (ImageDimension::D2, true, sampled(false)),
127                    "2DMS" => (ImageDimension::D2, false, sampled(true)),
128                    "2DMSArray" => (ImageDimension::D2, true, sampled(true)),
129                    "3D" => (ImageDimension::D3, false, sampled(false)),
130                    "Cube" => (ImageDimension::Cube, false, sampled(false)),
131                    "CubeArray" => (ImageDimension::Cube, true, sampled(false)),
132                    _ => return None,
133                };
134
135                Some(Type {
136                    name: None,
137                    inner: TypeInner::Image {
138                        dim,
139                        arrayed,
140                        class,
141                    },
142                })
143            };
144
145            let image_parse = |word: &str| {
146                let mut iter = word.split("image");
147
148                let texture_kind = |ty| {
149                    Some(match ty {
150                        "" => ScalarKind::Float,
151                        "i" => ScalarKind::Sint,
152                        "u" => ScalarKind::Uint,
153                        _ => return None,
154                    })
155                };
156
157                let kind = iter.next()?;
158                let size = iter.next()?;
159                // TODO: Check that the texture format and the kind match
160                let _ = texture_kind(kind)?;
161
162                let class = ImageClass::Storage {
163                    format: crate::StorageFormat::R8Uint,
164                    access: crate::StorageAccess::LOAD | crate::StorageAccess::STORE,
165                };
166
167                // TODO: glsl support multisampled storage images, naga doesn't
168                let (dim, arrayed) = match size {
169                    "1D" => (ImageDimension::D1, false),
170                    "1DArray" => (ImageDimension::D1, true),
171                    "2D" => (ImageDimension::D2, false),
172                    "2DArray" => (ImageDimension::D2, true),
173                    "3D" => (ImageDimension::D3, false),
174                    // Naga doesn't support cube images and it's usefulness
175                    // is questionable, so they won't be supported for now
176                    // "Cube" => (ImageDimension::Cube, false),
177                    // "CubeArray" => (ImageDimension::Cube, true),
178                    _ => return None,
179                };
180
181                Some(Type {
182                    name: None,
183                    inner: TypeInner::Image {
184                        dim,
185                        arrayed,
186                        class,
187                    },
188                })
189            };
190
191            vec_parse(word)
192                .or_else(|| mat_parse(word))
193                .or_else(|| texture_parse(word))
194                .or_else(|| image_parse(word))
195        }
196    }
197}
198
199pub const fn scalar_components(ty: &TypeInner) -> Option<Scalar> {
200    match *ty {
201        TypeInner::Scalar(scalar)
202        | TypeInner::Vector { scalar, .. }
203        | TypeInner::ValuePointer { scalar, .. }
204        | TypeInner::Matrix { scalar, .. } => Some(scalar),
205        _ => None,
206    }
207}
208
209pub const fn type_power(scalar: Scalar) -> Option<u32> {
210    Some(match scalar.kind {
211        ScalarKind::Sint => 0,
212        ScalarKind::Uint => 1,
213        ScalarKind::Float if scalar.width == 4 => 2,
214        ScalarKind::Float => 3,
215        ScalarKind::Bool | ScalarKind::AbstractInt | ScalarKind::AbstractFloat => return None,
216    })
217}
218
219impl Context<'_> {
220    /// Resolves the types of the expressions until `expr` (inclusive)
221    ///
222    /// This needs to be done before the [`typifier`] can be queried for
223    /// the types of the expressions in the range between the last grow and `expr`.
224    ///
225    /// # Note
226    ///
227    /// The `resolve_type*` methods (like [`resolve_type`]) automatically
228    /// grow the [`typifier`] so calling this method is not necessary when using
229    /// them.
230    ///
231    /// [`typifier`]: Context::typifier
232    /// [`resolve_type`]: Self::resolve_type
233    pub(crate) fn typifier_grow(&mut self, expr: Handle<Expression>, meta: Span) -> Result<()> {
234        let resolve_ctx = ResolveContext::with_locals(self.module, &self.locals, &self.arguments);
235
236        let typifier = if self.is_const {
237            &mut self.const_typifier
238        } else {
239            &mut self.typifier
240        };
241
242        let expressions = if self.is_const {
243            &self.module.global_expressions
244        } else {
245            &self.expressions
246        };
247
248        typifier
249            .grow(expr, expressions, &resolve_ctx)
250            .map_err(|error| Error {
251                kind: ErrorKind::SemanticError(format!("Can't resolve type: {error:?}").into()),
252                meta,
253            })
254    }
255
256    pub(crate) fn get_type(&self, expr: Handle<Expression>) -> &TypeInner {
257        let typifier = if self.is_const {
258            &self.const_typifier
259        } else {
260            &self.typifier
261        };
262
263        typifier.get(expr, &self.module.types)
264    }
265
266    /// Gets the type for the result of the `expr` expression
267    ///
268    /// Automatically grows the [`typifier`] to `expr` so calling
269    /// [`typifier_grow`] is not necessary
270    ///
271    /// [`typifier`]: Context::typifier
272    /// [`typifier_grow`]: Self::typifier_grow
273    pub(crate) fn resolve_type(
274        &mut self,
275        expr: Handle<Expression>,
276        meta: Span,
277    ) -> Result<&TypeInner> {
278        self.typifier_grow(expr, meta)?;
279        Ok(self.get_type(expr))
280    }
281
282    /// Gets the type handle for the result of the `expr` expression
283    ///
284    /// Automatically grows the [`typifier`] to `expr` so calling
285    /// [`typifier_grow`] is not necessary
286    ///
287    /// # Note
288    ///
289    /// Consider using [`resolve_type`] whenever possible
290    /// since it doesn't require adding each type to the [`types`] arena
291    /// and it doesn't need to mutably borrow the [`Parser`][Self]
292    ///
293    /// [`types`]: crate::Module::types
294    /// [`typifier`]: Context::typifier
295    /// [`typifier_grow`]: Self::typifier_grow
296    /// [`resolve_type`]: Self::resolve_type
297    pub(crate) fn resolve_type_handle(
298        &mut self,
299        expr: Handle<Expression>,
300        meta: Span,
301    ) -> Result<Handle<Type>> {
302        self.typifier_grow(expr, meta)?;
303
304        let typifier = if self.is_const {
305            &mut self.const_typifier
306        } else {
307            &mut self.typifier
308        };
309
310        Ok(typifier.register_type(expr, &mut self.module.types))
311    }
312
313    /// Invalidates the cached type resolution for `expr` forcing a recomputation
314    pub(crate) fn invalidate_expression(
315        &mut self,
316        expr: Handle<Expression>,
317        meta: Span,
318    ) -> Result<()> {
319        let resolve_ctx = ResolveContext::with_locals(self.module, &self.locals, &self.arguments);
320
321        let typifier = if self.is_const {
322            &mut self.const_typifier
323        } else {
324            &mut self.typifier
325        };
326
327        typifier
328            .invalidate(expr, &self.expressions, &resolve_ctx)
329            .map_err(|error| Error {
330                kind: ErrorKind::SemanticError(format!("Can't resolve type: {error:?}").into()),
331                meta,
332            })
333    }
334
335    pub(crate) fn lift_up_const_expression(
336        &mut self,
337        expr: Handle<Expression>,
338    ) -> Result<Handle<Expression>> {
339        let meta = self.expressions.get_span(expr);
340        let h = match self.expressions[expr] {
341            ref expr @ (Expression::Literal(_)
342            | Expression::Constant(_)
343            | Expression::ZeroValue(_)) => {
344                self.module.global_expressions.append(expr.clone(), meta)
345            }
346            Expression::Compose { ty, ref components } => {
347                let mut components = components.clone();
348                for component in &mut components {
349                    *component = self.lift_up_const_expression(*component)?;
350                }
351                self.module
352                    .global_expressions
353                    .append(Expression::Compose { ty, components }, meta)
354            }
355            Expression::Splat { size, value } => {
356                let value = self.lift_up_const_expression(value)?;
357                self.module
358                    .global_expressions
359                    .append(Expression::Splat { size, value }, meta)
360            }
361            _ => {
362                return Err(Error {
363                    kind: ErrorKind::SemanticError("Expression is not const-expression".into()),
364                    meta,
365                })
366            }
367        };
368        self.global_expression_kind_tracker
369            .insert(h, crate::proc::ExpressionKind::Const);
370        Ok(h)
371    }
372}