diff --git a/core/src/render/mod.rs b/core/src/render/mod.rs index d368ffb..834cc8c 100644 --- a/core/src/render/mod.rs +++ b/core/src/render/mod.rs @@ -22,6 +22,10 @@ pub use primitive::*; const PRELUDE: &str = include_str!("./shader/prelude.wgsl"); +fn module_source(wgsl: &str) -> String { + format!("{PRELUDE}\n{wgsl}") +} + pub struct UiRenderNode { shared_layout: BindGroupLayout, shared_group: BindGroup, @@ -222,7 +226,7 @@ impl UiRenderNode { ) -> RenderPipeline { let module = device.create_shader_module(ShaderModuleDescriptor { label: Some(label), - source: ShaderSource::Wgsl(format!("{PRELUDE}\n{wgsl}").into()), + source: ShaderSource::Wgsl(module_source(wgsl).into()), }); device.create_render_pipeline(&RenderPipelineDescriptor { label: Some(label), @@ -401,3 +405,35 @@ impl ListBuffers { } } } + +#[cfg(test)] +mod tests { + use super::module_source; + use wgpu::naga::{ + front::wgsl, + valid::{Capabilities, ValidationFlags, Validator}, + }; + + /// Every shader file, composed as the renderer composes it, parses and + /// validates with no device -- so an edit that breaks one fails here and + /// not in the first window opened. + #[test] + fn every_shader_validates() { + let dir = concat!(env!("CARGO_MANIFEST_DIR"), "/src/render/shader"); + let mut checked = 0; + for entry in std::fs::read_dir(dir).unwrap() { + let path = entry.unwrap().path(); + if path.extension().is_none_or(|e| e != "wgsl") || path.ends_with("prelude.wgsl") { + continue; + } + let source = module_source(&std::fs::read_to_string(&path).unwrap()); + let module = wgsl::parse_str(&source) + .unwrap_or_else(|e| panic!("{}: {}", path.display(), e.emit_to_string(&source))); + Validator::new(ValidationFlags::all(), Capabilities::all()) + .validate(&module) + .unwrap_or_else(|e| panic!("{}: {e:?}", path.display())); + checked += 1; + } + assert!(checked > 0, "no shaders found in {dir}"); + } +} diff --git a/core/src/render/shader/rect.wgsl b/core/src/render/shader/rect.wgsl index 5a01564..6d8694d 100644 --- a/core/src/render/shader/rect.wgsl +++ b/core/src/render/shader/rect.wgsl @@ -34,6 +34,6 @@ fn distance_from_rect(pixel_pos: vec2, rect_center: vec2, rect_corner: // vec from center to pixel let p = pixel_pos - rect_center; // vec from inner rect corner to pixel - let q = px(p) - (rect_corner - radius); + let q = abs(p) - (rect_corner - radius); return length(max(q, vec2(0.0))) - radius; }