diff options
Diffstat (limited to 'third_party/rust/naga/src/front/glsl/mod.rs')
-rw-r--r-- | third_party/rust/naga/src/front/glsl/mod.rs | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/third_party/rust/naga/src/front/glsl/mod.rs b/third_party/rust/naga/src/front/glsl/mod.rs new file mode 100644 index 0000000000..f28ff7b6ec --- /dev/null +++ b/third_party/rust/naga/src/front/glsl/mod.rs @@ -0,0 +1,235 @@ +/*! +Frontend for [GLSL][glsl] (OpenGL Shading Language). + +To begin, take a look at the documentation for the [`Parser`](Parser). + +# 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<T> = std::result::Result<T, Error>; + +/// Per-shader options passed to [`parse`](Parser::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<String, String>, +} + +impl From<ShaderStage> 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 trough the use of the + /// `#version` preprocessor directive. + pub version: u16, + /// The GLSL profile specified in the shader trough the use of the + /// `#version` preprocessor directive. + pub profile: Profile, + /// The shader stage in the pipeline, passed to the [`parse`](Parser::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<String>, +} + +impl ShaderMetadata { + fn reset(&mut self, stage: ShaderStage) { + self.version = 0; + self.profile = Profile::Core; + self.stage = stage; + self.workgroup_size = [if stage == ShaderStage::Compute { 1 } else { 0 }; 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 `Parser` is the central structure of the GLSL frontend. +/// +/// To instantiate a new `Parser` the [`Default`](Default) trait is used, so a +/// call to the associated function [`Parser::default`](Parser::default) will +/// return a new `Parser` instance. +/// +/// To parse a shader simply call the [`parse`](Parser::parse) method with a +/// [`Options`](Options) struct and a [`&str`](str) holding the glsl code. +/// +/// The `Parser` also provides the [`metadata`](Parser::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::{Parser, Options}; +/// +/// let glsl = r#" +/// #version 450 core +/// +/// void main() {} +/// "#; +/// +/// let mut parser = Parser::default(); +/// let options = Options::from(ShaderStage::Vertex); +/// parser.parse(&options, glsl); +/// ``` +/// +/// # Reusability +/// +/// If there's a need to parse more than one shader reusing the same `Parser` +/// instance may be beneficial since internal allocations will be reused. +/// +/// Calling the [`parse`](Parser::parse) method multiple times will reset the +/// `Parser` so no extra care is needed when reusing. +#[derive(Debug, Default)] +pub struct Parser { + meta: ShaderMetadata, + + lookup_function: FastHashMap<String, FunctionDeclaration>, + lookup_type: FastHashMap<String, Handle<Type>>, + + global_variables: Vec<(String, GlobalLookup)>, + + entry_args: Vec<EntryArg>, + + layouter: Layouter, + + errors: Vec<Error>, + + module: Module, +} + +impl Parser { + 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 `Parser` and different shaders are supported. + pub fn parse( + &mut self, + options: &Options, + source: &str, + ) -> std::result::Result<Module, Vec<Error>> { + 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 + } +} |