Skip to main content

wgsl_validator/
validation.rs

1use naga::{
2    front::wgsl,
3    valid::{Capabilities, ValidationFlags},
4};
5
6use crate::errors::WgslError;
7
8pub struct Validator {
9    validator: naga::valid::Validator,
10}
11
12impl Validator {
13    pub fn new() -> Self {
14        Self {
15            validator: naga::valid::Validator::new(ValidationFlags::all(), Capabilities::all()),
16        }
17    }
18
19    pub fn validate_wgsl(&mut self, shader: &str) -> Result<(), WgslError> {
20        let module =
21            wgsl::parse_str(shader).map_err(|err| WgslError::from_parse_err(err, shader))?;
22
23        if let Err(error) = self.validator.validate(&module) {
24            Err(WgslError::ValidationErr {
25                emitted: error.emit_to_string(shader),
26                src: shader.to_string(),
27                error,
28            })
29        } else {
30            Ok(())
31        }
32    }
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38
39    #[test]
40    fn correct_validation() -> Result<(), WgslError> {
41        let wgsl_source = r#"
42            @fragment
43            fn main_fs() -> @location(0) vec4<f32> {
44                return vec4<f32>(1.0, 1.0, 1.0, 1.0);
45            }
46        "#;
47        let mut validator = Validator::new();
48        validator.validate_wgsl(wgsl_source)
49    }
50
51    #[test]
52    fn incorrect_parsing() {
53        let wgsl_source = r#"
54            @invalid_entry
55            fn main_fs() -> @location(0) vec4<f32> {
56                return vec4<f32>(1.0, 1.0, 1.0, 1.0);
57            }
58        "#;
59        let mut validator = Validator::new();
60        assert!(validator.validate_wgsl(wgsl_source).is_err());
61    }
62
63    #[test]
64    fn incorrect_validation() {
65        let wgsl_source = r#"
66            @fragment
67            fn main_fs() -> @location(0) vec2<f32> {
68                return vec4<f32>(1.0, 1.0, 1.0, 1.0);
69            }
70        "#;
71        let mut validator = Validator::new();
72        assert!(validator.validate_wgsl(wgsl_source).is_err());
73    }
74
75    #[test]
76    fn correct_complex_validation() -> Result<(), WgslError> {
77        let wgsl_source = r#"
78            struct UBO
79            {
80                screen_size: vec2<f32>,
81                center: vec2<f32>,
82                scale: f32,
83                iteration_count: i32
84            }
85
86            @group(0) @binding(0) var palette: texture_2d<f32>;
87            @group(0) @binding(1) var paletteSampler: sampler;
88            @group(0) @binding(2) var<uniform> ubo: UBO;
89
90            struct Input
91            {
92                @builtin(position) fragcoord: vec4<f32>
93            }
94
95            struct Output
96            {
97                @location(0) color: vec4<f32>
98            }
99
100            @fragment
101            fn main(input: Input) -> Output
102            {
103                var coords: vec2<f32> = input.fragcoord.xy / ubo.screen_size;
104                var c: vec2<f32>;
105                c.x = (((ubo.screen_size.x / ubo.screen_size.y) * (coords.x - (0.5))) * ubo.scale) - (ubo.center.x / ubo.screen_size.y);
106                c.y = ((coords.y - (0.5)) * ubo.scale) - (ubo.center.y / ubo.screen_size.y);
107                var z: vec2<f32> = c;
108                var i: i32 = 0;
109                while (i < ubo.iteration_count)
110                {
111                    var x: f32 = ((z.x * z.x) - (z.y * z.y)) + c.x;
112                    var y: f32 = ((z.y * z.x) + (z.x * z.y)) + c.y;
113                    if (((x * x) + (y * y)) > (4.0))
114                    {
115                        break;
116                    }
117
118                    z.x = x;
119                    z.y = y;
120                    i += 1;
121                }
122
123                var u: f32;
124                if (i < ubo.iteration_count)
125                {
126                    u = (f32(i)) / (100.0);
127                }
128                else
129                {
130                    u = 0.0;
131                }
132
133                var output: Output;
134                output.color = textureSample(palette, paletteSampler, vec2<f32>(u, 0.0));
135                return output;
136            }
137        "#;
138        let mut validator = Validator::new();
139        validator.validate_wgsl(wgsl_source)
140    }
141}