shader_sense/validator/validator.rs
1//! Validator trait implemented for all languages.
2use std::path::Path;
3
4#[cfg(not(target_os = "wasi"))]
5use crate::validator::dxc::Dxc;
6use crate::{
7 shader::{ShaderParams, ShaderStage, ShadingLanguage},
8 shader_error::{ShaderDiagnosticList, ShaderError},
9 validator::{glslang::Glslang, naga::Naga},
10};
11
12/// Default include callback for [`Validator::validate_shader`]
13pub fn default_include_callback(path: &Path) -> Option<String> {
14 Some(std::fs::read_to_string(path).unwrap())
15}
16
17/// Trait that all validator must implement to validate files.
18pub trait ValidatorImpl {
19 fn validate_shader(
20 &self,
21 shader_content: &str,
22 file_path: &Path,
23 params: &ShaderParams,
24 include_callback: &mut dyn FnMut(&Path) -> Option<String>,
25 ) -> Result<ShaderDiagnosticList, ShaderError>;
26
27 fn support(&self, shader_stage: ShaderStage) -> bool;
28
29 fn get_file_name(&self, path: &Path) -> String {
30 String::from(path.file_name().unwrap().to_string_lossy())
31 }
32}
33
34/// Validator main entry point. Create this struct in order to validate shader
35///
36/// Run
37/// ```
38/// use shader_sense::validator::validator::Validator;
39/// use shader_sense::shader::ShaderParams;
40/// use std::path::Path;
41/// let shader_path = Path::new("./test/hlsl/ok.hlsl");
42/// let shader_content = std::fs::read_to_string(shader_path).unwrap();
43/// let validator = Validator::hlsl();
44/// validator.validate_shader(
45/// &shader_content,
46/// shader_path,
47/// &ShaderParams::default(),
48/// &mut |path: &Path| {
49/// Some(std::fs::read_to_string(path).unwrap())
50/// }
51/// ).unwrap();
52/// ```
53pub struct Validator {
54 imp: Box<dyn ValidatorImpl>,
55}
56impl Validator {
57 /// Create a validator for Glsl.
58 /// It will use glslang directly.
59 pub fn glsl() -> Self {
60 Self {
61 imp: Box::new(Glslang::glsl()),
62 }
63 }
64 /// Create a validator for Hlsl.
65 /// It will use DXC if it is available and fallback on glslang if its not supported.
66 /// Note that glslang support for HLSL is not as advanced as dxc.
67 pub fn hlsl() -> Self {
68 Self {
69 #[cfg(not(target_os = "wasi"))]
70 imp: match Dxc::new(Dxc::find_dxc_library()) {
71 Ok(dxc) => Box::new(dxc),
72 Err(_) => Box::new(Glslang::hlsl()), // Failed to instantiate dxc. Fallback to glslang.
73 },
74 #[cfg(target_os = "wasi")]
75 imp: Box::new(Glslang::hlsl()),
76 }
77 }
78 /// Create a validator for Wgsl.
79 /// It will use naga directly.
80 pub fn wgsl() -> Self {
81 Self {
82 imp: Box::new(Naga::new()),
83 }
84 }
85 /// Create a validator from the given [`ShadingLanguage`]
86 pub fn from_shading_language(shading_language: ShadingLanguage) -> Self {
87 match shading_language {
88 ShadingLanguage::Wgsl => Self::wgsl(),
89 ShadingLanguage::Hlsl => Self::hlsl(),
90 ShadingLanguage::Glsl => Self::glsl(),
91 }
92 }
93 /// Validate a shader and return the diagnostic list, or an error if the process failed.
94 /// If diagnostic list is empty, no error were found.
95 /// You can handle how your file will be loaded.
96 /// The include callback is being passed the already processed absolute canonicalized path of the include.
97 pub fn validate_shader(
98 &self,
99 shader_content: &str,
100 file_path: &Path,
101 params: &ShaderParams,
102 include_callback: &mut dyn FnMut(&Path) -> Option<String>, // TODO: Check if we cant pass a ref instead of a copy here.
103 ) -> Result<ShaderDiagnosticList, ShaderError> {
104 self.imp
105 .validate_shader(shader_content, file_path, params, include_callback)
106 }
107}