/*! Frontend for [GLSL][glsl] (OpenGL Shading Language). To begin, take a look at the documentation for the [`Frontend`]. # Supported versions ## Vulkan - 440 (partial) - 450 - 460 [glsl]: https://www.khronos.org/registry/OpenGL/index_gl.php */ pub use ast::{Precision, Profile}; pub use error::{Error, ErrorKind, ExpectedToken}; pub use token::TokenValue; use crate::{proc::Layouter, FastHashMap, FastHashSet, Handle, Module, ShaderStage, Span, Type}; use ast::{EntryArg, FunctionDeclaration, GlobalLookup}; use parser::ParsingContext; mod ast; mod builtins; mod constants; mod context; mod error; mod functions; mod lex; mod offset; mod parser; #[cfg(test)] mod parser_tests; mod token; mod types; mod variables; type Result = std::result::Result; /// Per-shader options passed to [`parse`](Frontend::parse). /// /// The [`From`](From) trait is implemented for [`ShaderStage`](ShaderStage) to /// provide a quick way to create a Options instance. /// ```rust /// # use naga::ShaderStage; /// # use naga::front::glsl::Options; /// Options::from(ShaderStage::Vertex); /// ``` #[derive(Debug)] pub struct Options { /// The shader stage in the pipeline. pub stage: ShaderStage, /// Preprocesor definitions to be used, akin to having /// ```glsl /// #define key value /// ``` /// for each key value pair in the map. pub defines: FastHashMap, } impl From for Options { fn from(stage: ShaderStage) -> Self { Options { stage, defines: FastHashMap::default(), } } } /// Additional information about the GLSL shader. /// /// Stores additional information about the GLSL shader which might not be /// stored in the shader [`Module`](Module). #[derive(Debug)] pub struct ShaderMetadata { /// The GLSL version specified in the shader through the use of the /// `#version` preprocessor directive. pub version: u16, /// The GLSL profile specified in the shader through the use of the /// `#version` preprocessor directive. pub profile: Profile, /// The shader stage in the pipeline, passed to the [`parse`](Frontend::parse) /// method via the [`Options`](Options) struct. pub stage: ShaderStage, /// The workgroup size for compute shaders, defaults to `[1; 3]` for /// compute shaders and `[0; 3]` for non compute shaders. pub workgroup_size: [u32; 3], /// Whether or not early fragment tests where requested by the shader. /// Defaults to `false`. pub early_fragment_tests: bool, /// The shader can request extensions via the /// `#extension` preprocessor directive, in the directive a behavior /// parameter is used to control whether the extension should be disabled, /// warn on usage, enabled if possible or required. /// /// This field only stores extensions which were required or requested to /// be enabled if possible and they are supported. pub extensions: FastHashSet, } impl ShaderMetadata { fn reset(&mut self, stage: ShaderStage) { self.version = 0; self.profile = Profile::Core; self.stage = stage; self.workgroup_size = [u32::from(stage == ShaderStage::Compute); 3]; self.early_fragment_tests = false; self.extensions.clear(); } } impl Default for ShaderMetadata { fn default() -> Self { ShaderMetadata { version: 0, profile: Profile::Core, stage: ShaderStage::Vertex, workgroup_size: [0; 3], early_fragment_tests: false, extensions: FastHashSet::default(), } } } /// The `Frontend` is the central structure of the GLSL frontend. /// /// To instantiate a new `Frontend` the [`Default`](Default) trait is used, so a /// call to the associated function [`Frontend::default`](Frontend::default) will /// return a new `Frontend` instance. /// /// To parse a shader simply call the [`parse`](Frontend::parse) method with a /// [`Options`](Options) struct and a [`&str`](str) holding the glsl code. /// /// The `Frontend` also provides the [`metadata`](Frontend::metadata) to get some /// further information about the previously parsed shader, like version and /// extensions used (see the documentation for /// [`ShaderMetadata`](ShaderMetadata) to see all the returned information) /// /// # Example usage /// ```rust /// use naga::ShaderStage; /// use naga::front::glsl::{Frontend, Options}; /// /// let glsl = r#" /// #version 450 core /// /// void main() {} /// "#; /// /// let mut frontend = Frontend::default(); /// let options = Options::from(ShaderStage::Vertex); /// frontend.parse(&options, glsl); /// ``` /// /// # Reusability /// /// If there's a need to parse more than one shader reusing the same `Frontend` /// instance may be beneficial since internal allocations will be reused. /// /// Calling the [`parse`](Frontend::parse) method multiple times will reset the /// `Frontend` so no extra care is needed when reusing. #[derive(Debug, Default)] pub struct Frontend { meta: ShaderMetadata, lookup_function: FastHashMap, lookup_type: FastHashMap>, global_variables: Vec<(String, GlobalLookup)>, entry_args: Vec, layouter: Layouter, errors: Vec, module: Module, } impl Frontend { fn reset(&mut self, stage: ShaderStage) { self.meta.reset(stage); self.lookup_function.clear(); self.lookup_type.clear(); self.global_variables.clear(); self.entry_args.clear(); self.layouter.clear(); // This is necessary because if the last parsing errored out, the module // wouldn't have been taken self.module = Module::default(); } /// Parses a shader either outputting a shader [`Module`](Module) or a list /// of [`Error`](Error)s. /// /// Multiple calls using the same `Frontend` and different shaders are supported. pub fn parse( &mut self, options: &Options, source: &str, ) -> std::result::Result> { self.reset(options.stage); let lexer = lex::Lexer::new(source, &options.defines); let mut ctx = ParsingContext::new(lexer); if let Err(e) = ctx.parse(self) { self.errors.push(e); } if self.errors.is_empty() { Ok(std::mem::take(&mut self.module)) } else { Err(std::mem::take(&mut self.errors)) } } /// Returns additional information about the parsed shader which might not be /// stored in the [`Module`](Module), see the documentation for /// [`ShaderMetadata`](ShaderMetadata) for more information about the /// returned data. /// /// # Notes /// /// Following an unsuccessful parsing the state of the returned information /// is undefined, it might contain only partial information about the /// current shader, the previous shader or both. pub const fn metadata(&self) -> &ShaderMetadata { &self.meta } }