wgsl_validator/
validation.rs1use 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}