[glsl-in] Multi entry points - address comments

This commit is contained in:
Pelle Johnsen
2021-02-17 11:23:36 +00:00
committed by Dzmitry Malyshau
parent 1861fca4ba
commit 408002815f
15 changed files with 132 additions and 109 deletions

View File

@@ -105,30 +105,42 @@ fn main() {
#[cfg(feature = "glsl-in")]
"vert" => {
let input = fs::read_to_string(&args[1]).unwrap();
let mut entry_points = naga::FastHashMap::default();
entry_points.insert("main".to_string(), naga::ShaderStage::Vertex);
naga::front::glsl::parse_str(
&input,
vec![("main".to_string(), naga::ShaderStage::Vertex)],
Default::default(),
&naga::front::glsl::Options {
entry_points,
defines: Default::default(),
},
)
.unwrap_pretty()
}
#[cfg(feature = "glsl-in")]
"frag" => {
let input = fs::read_to_string(&args[1]).unwrap();
let mut entry_points = naga::FastHashMap::default();
entry_points.insert("main".to_string(), naga::ShaderStage::Fragment);
naga::front::glsl::parse_str(
&input,
vec![("main".to_string(), naga::ShaderStage::Fragment)],
Default::default(),
&naga::front::glsl::Options {
entry_points,
defines: Default::default(),
},
)
.unwrap_pretty()
}
#[cfg(feature = "glsl-in")]
"comp" => {
let input = fs::read_to_string(&args[1]).unwrap();
let mut entry_points = naga::FastHashMap::default();
entry_points.insert("main".to_string(), naga::ShaderStage::Compute);
naga::front::glsl::parse_str(
&input,
vec![("main".to_string(), naga::ShaderStage::Compute)],
Default::default(),
&naga::front::glsl::Options {
entry_points,
defines: Default::default(),
},
)
.unwrap_pretty()
}

View File

@@ -7,10 +7,10 @@ use crate::{
};
#[derive(Debug)]
pub struct Program {
pub struct Program<'a> {
pub version: u16,
pub profile: Profile,
pub entry_points: Vec<(String, ShaderStage)>,
pub entry_points: &'a FastHashMap<String, ShaderStage>,
pub lookup_function: FastHashMap<String, Handle<Function>>,
pub lookup_type: FastHashMap<String, Handle<Type>>,
pub lookup_global_variables: FastHashMap<String, Handle<GlobalVariable>>,
@@ -19,8 +19,8 @@ pub struct Program {
pub module: Module,
}
impl Program {
pub fn new(entry_points: Vec<(String, ShaderStage)>) -> Program {
impl<'a> Program<'a> {
pub fn new(entry_points: &'a FastHashMap<String, ShaderStage>) -> Program<'a> {
Program {
version: 0,
profile: Profile::Core,
@@ -42,10 +42,6 @@ impl Program {
}
}
pub fn has_stage(&self, stage: ShaderStage) -> bool {
self.entry_points.iter().any(|(_, s)| *s == stage)
}
pub fn binary_expr(
&mut self,
op: BinaryOperator,

View File

@@ -17,8 +17,6 @@ pub enum ErrorKind {
UnknownField(TokenMetadata, String),
#[cfg(feature = "glsl-validate")]
VariableAlreadyDeclared(String),
#[cfg(feature = "glsl-validate")]
VariableNotAvailable(String),
ExpectedConstant,
SemanticError(Cow<'static, str>),
PreprocessorError(String),
@@ -49,10 +47,6 @@ impl fmt::Display for ErrorKind {
ErrorKind::VariableAlreadyDeclared(val) => {
write!(f, "Variable {} already declared in current scope", val)
}
#[cfg(feature = "glsl-validate")]
ErrorKind::VariableNotAvailable(val) => {
write!(f, "Variable {} not available in this stage", val)
}
ErrorKind::ExpectedConstant => write!(f, "Expected constant"),
ErrorKind::SemanticError(msg) => write!(f, "Semantic error: {}", msg),
ErrorKind::PreprocessorError(val) => write!(f, "Preprocessor error: {}", val),

View File

@@ -6,7 +6,7 @@ use crate::{
use super::{ast::*, error::ErrorKind};
impl Program {
impl Program<'_> {
pub fn function_call(&mut self, fc: FunctionCall) -> Result<ExpressionRule, ErrorKind> {
match fc.kind {
FunctionCallKind::TypeConstructor(ty) => {
@@ -282,15 +282,15 @@ impl Program {
f
}
pub fn declare_function(&mut self, f: Function) {
let stage = if let Some(ref name) = f.name {
self.entry_points
.iter()
.find_map(|(n, s)| if *name == *n { Some(*s) } else { None })
} else {
None
};
let name = f.name.clone().unwrap();
pub fn declare_function(&mut self, f: Function) -> Result<(), ErrorKind> {
let name = f
.name
.clone()
.ok_or_else(|| ErrorKind::SemanticError("Unnamed function".into()))?;
let stage = self
.entry_points
.iter()
.find_map(|(n, s)| if *name == *n { Some(*s) } else { None });
if let Some(stage) = stage {
self.module.entry_points.insert(
(stage, name),
@@ -304,5 +304,6 @@ impl Program {
let handle = self.module.functions.append(f);
self.lookup_function.insert(name, handle);
}
Ok(())
}
}

View File

@@ -1,5 +1,6 @@
use super::parser::Token;
use super::{preprocess::LinePreProcessor, token::TokenMetadata, types::parse_type};
use crate::FastHashMap;
use std::{iter::Enumerate, str::Lines};
fn _consume_str<'a>(input: &'a str, what: &str) -> Option<&'a str> {
@@ -23,7 +24,7 @@ pub struct Lexer<'a> {
line: usize,
offset: usize,
inside_comment: bool,
pub pp: LinePreProcessor,
pp: LinePreProcessor,
}
impl<'a> Lexer<'a> {
@@ -324,14 +325,14 @@ impl<'a> Lexer<'a> {
}
}
pub fn new(input: &'a str) -> Self {
pub fn new(input: &'a str, defines: &FastHashMap<String, String>) -> Self {
let mut lexer = Lexer {
lines: input.lines().enumerate(),
input: "".to_string(),
line: 0,
offset: 0,
inside_comment: false,
pp: LinePreProcessor::new(),
pp: LinePreProcessor::new(defines),
};
lexer.next_line();
lexer

View File

@@ -2,8 +2,10 @@ use super::{lex::Lexer, parser::Token::*, token::TokenMetadata};
#[test]
fn tokens() {
let defines = crate::FastHashMap::default();
// line comments
let mut lex = Lexer::new("void main // myfunction\n//()\n{}");
let mut lex = Lexer::new("void main // myfunction\n//()\n{}", &defines);
assert_eq!(
lex.next().unwrap(),
Void(TokenMetadata {
@@ -38,7 +40,7 @@ fn tokens() {
assert_eq!(lex.next(), None);
// multi line comment
let mut lex = Lexer::new("void main /* comment [] {}\n/**\n{}*/{}");
let mut lex = Lexer::new("void main /* comment [] {}\n/**\n{}*/{}", &defines);
assert_eq!(
lex.next().unwrap(),
Void(TokenMetadata {
@@ -73,7 +75,7 @@ fn tokens() {
assert_eq!(lex.next(), None);
// identifiers
let mut lex = Lexer::new("id123_OK 92No æNoø No¾ No好");
let mut lex = Lexer::new("id123_OK 92No æNoø No¾ No好", &defines);
assert_eq!(
lex.next().unwrap(),
Identifier((
@@ -177,7 +179,7 @@ fn tokens() {
assert_eq!(lex.next(), None);
// version
let mut lex = Lexer::new("#version 890 core");
let mut lex = Lexer::new("#version 890 core", &defines);
assert_eq!(
lex.next().unwrap(),
Version(TokenMetadata {
@@ -208,7 +210,10 @@ fn tokens() {
assert_eq!(lex.next(), None);
// operators
let mut lex = Lexer::new("+ - * | & % / += -= *= |= &= %= /= ++ -- || && ^^");
let mut lex = Lexer::new(
"+ - * | & % / += -= *= |= &= %= /= ++ -- || && ^^",
&defines,
);
assert_eq!(
lex.next().unwrap(),
Plus(TokenMetadata {
@@ -345,7 +350,7 @@ fn tokens() {
assert_eq!(lex.next(), None);
// float constants
let mut lex = Lexer::new("120.0 130.0lf 140.0Lf 150.0LF");
let mut lex = Lexer::new("120.0 130.0lf 140.0Lf 150.0LF", &defines);
assert_eq!(
lex.next().unwrap(),
FloatConstant((
@@ -389,7 +394,7 @@ fn tokens() {
assert_eq!(lex.next(), None);
// Integer constants
let mut lex = Lexer::new("120 130u 140U 150 0x1f 0xf2U 0xF1u");
let mut lex = Lexer::new("120 130u 140U 150 0x1f 0xf2U 0xF1u", &defines);
assert_eq!(
lex.next().unwrap(),
IntConstant((

View File

@@ -23,15 +23,15 @@ mod token;
mod types;
mod variables;
pub fn parse_str(
source: &str,
entry_points: Vec<(String, ShaderStage)>,
defines: FastHashMap<String, String>,
) -> Result<Module, ParseError> {
let mut program = Program::new(entry_points);
pub struct Options {
pub entry_points: FastHashMap<String, ShaderStage>,
pub defines: FastHashMap<String, String>,
}
let mut lex = Lexer::new(source);
lex.pp.defines = defines;
pub fn parse_str(source: &str, options: &Options) -> Result<Module, ParseError> {
let mut program = Program::new(&options.entry_points);
let lex = Lexer::new(source, &options.defines);
let mut parser = parser::Parser::new(&mut program);
for token in lex {
parser.parse(token)?;

View File

@@ -14,8 +14,8 @@ pomelo! {
};
}
%token #[derive(Debug)] #[cfg_attr(test, derive(PartialEq))] pub enum Token {};
%parser pub struct Parser<'a> {};
%extra_argument &'a mut Program;
%parser pub struct Parser<'a, 'b> {};
%extra_argument &'a mut Program<'b>;
%extra_token TokenMetadata;
%error ErrorKind;
%syntax_error {
@@ -1063,7 +1063,7 @@ pomelo! {
translation_unit ::= translation_unit external_declaration;
external_declaration ::= function_definition(f) {
extra.declare_function(f)
extra.declare_function(f)?
}
external_declaration ::= declaration(d) {
if let Some(d) = d {

View File

@@ -4,9 +4,13 @@ use super::lex::Lexer;
use super::parser;
use crate::ShaderStage;
fn parse_program(source: &str, stage: ShaderStage) -> Result<Program, ErrorKind> {
let mut program = Program::new(vec![("".to_string(), stage)]);
let lex = Lexer::new(source);
fn parse_program<'a>(
source: &str,
entry_points: &'a crate::FastHashMap<String, ShaderStage>,
) -> Result<Program<'a>, ErrorKind> {
let mut program = Program::new(entry_points);
let defines = crate::FastHashMap::default();
let lex = Lexer::new(source, &defines);
let mut parser = parser::Parser::new(&mut program);
for token in lex {
@@ -18,11 +22,13 @@ fn parse_program(source: &str, stage: ShaderStage) -> Result<Program, ErrorKind>
#[test]
fn version() {
let mut entry_points = crate::FastHashMap::default();
entry_points.insert("".to_string(), ShaderStage::Vertex);
// invalid versions
assert_eq!(
format!(
"{:?}",
parse_program("#version 99000", ShaderStage::Vertex)
parse_program("#version 99000", &entry_points)
.err()
.unwrap()
),
@@ -32,9 +38,7 @@ fn version() {
assert_eq!(
format!(
"{:?}",
parse_program("#version 449", ShaderStage::Vertex)
.err()
.unwrap()
parse_program("#version 449", &entry_points).err().unwrap()
),
"InvalidVersion(TokenMetadata { line: 0, chars: 9..12 }, 449)"
);
@@ -42,7 +46,7 @@ fn version() {
assert_eq!(
format!(
"{:?}",
parse_program("#version 450 smart", ShaderStage::Vertex)
parse_program("#version 450 smart", &entry_points)
.err()
.unwrap()
),
@@ -52,7 +56,7 @@ fn version() {
assert_eq!(
format!(
"{:?}",
parse_program("#version 450\nvoid f(){} #version 450", ShaderStage::Vertex)
parse_program("#version 450\nvoid f(){} #version 450", &entry_points)
.err()
.unwrap()
),
@@ -60,19 +64,19 @@ fn version() {
);
// valid versions
let program = parse_program(" # version 450\nvoid main() {}", ShaderStage::Vertex).unwrap();
let program = parse_program(" # version 450\nvoid main() {}", &entry_points).unwrap();
assert_eq!(
format!("{:?}", (program.version, program.profile)),
"(450, Core)"
);
let program = parse_program("#version 450\nvoid main() {}", ShaderStage::Vertex).unwrap();
let program = parse_program("#version 450\nvoid main() {}", &entry_points).unwrap();
assert_eq!(
format!("{:?}", (program.version, program.profile)),
"(450, Core)"
);
let program = parse_program("#version 450 core\nvoid main() {}", ShaderStage::Vertex).unwrap();
let program = parse_program("#version 450 core\nvoid main() {}", &entry_points).unwrap();
assert_eq!(
format!("{:?}", (program.version, program.profile)),
"(450, Core)"
@@ -81,6 +85,9 @@ fn version() {
#[test]
fn control_flow() {
let mut entry_points = crate::FastHashMap::default();
entry_points.insert("".to_string(), ShaderStage::Vertex);
let _program = parse_program(
r#"
# version 450
@@ -92,7 +99,7 @@ fn control_flow() {
}
}
"#,
ShaderStage::Vertex,
&entry_points,
)
.unwrap();
@@ -105,7 +112,7 @@ fn control_flow() {
}
}
"#,
ShaderStage::Vertex,
&entry_points,
)
.unwrap();
@@ -127,7 +134,7 @@ fn control_flow() {
}
}
"#,
ShaderStage::Vertex,
&entry_points,
)
.unwrap();
let _program = parse_program(
@@ -143,7 +150,7 @@ fn control_flow() {
} while(x >= 4)
}
"#,
ShaderStage::Vertex,
&entry_points,
)
.unwrap();
@@ -158,13 +165,16 @@ fn control_flow() {
return x;
}
"#,
ShaderStage::Vertex,
&entry_points,
)
.unwrap();
}
#[test]
fn textures() {
let mut entry_points = crate::FastHashMap::default();
entry_points.insert("".to_string(), ShaderStage::Fragment);
let _program = parse_program(
r#"
#version 450
@@ -176,13 +186,16 @@ fn textures() {
o_color = texture(sampler2D(tex, tex_sampler), v_uv);
}
"#,
ShaderStage::Fragment,
&entry_points,
)
.unwrap();
}
#[test]
fn functions() {
let mut entry_points = crate::FastHashMap::default();
entry_points.insert("".to_string(), ShaderStage::Vertex);
// TODO: Add support for function prototypes
// parse_program(
// r#"
@@ -205,7 +218,7 @@ fn functions() {
void main() {}
"#,
ShaderStage::Vertex,
&entry_points,
)
.unwrap();
@@ -216,7 +229,7 @@ fn functions() {
void main() {}
"#,
ShaderStage::Vertex,
&entry_points,
)
.unwrap();
@@ -227,7 +240,7 @@ fn functions() {
return p.x;
}
"#,
ShaderStage::Vertex,
&entry_points,
)
.unwrap();
}
@@ -236,6 +249,9 @@ fn functions() {
fn constants() {
use crate::{Constant, ConstantInner, ScalarValue};
let mut entry_points = crate::FastHashMap::default();
entry_points.insert("".to_string(), ShaderStage::Vertex);
let program = parse_program(
r#"
# version 450
@@ -243,7 +259,7 @@ fn constants() {
float global = a;
const flat float b = a;
"#,
ShaderStage::Vertex,
&entry_points,
)
.unwrap();

View File

@@ -20,16 +20,16 @@ pub struct IfState {
#[derive(Clone, Debug)]
pub struct LinePreProcessor {
pub defines: FastHashMap<String, String>,
defines: FastHashMap<String, String>,
if_stack: Vec<IfState>,
inside_comment: bool,
in_preprocess: bool,
}
impl LinePreProcessor {
pub fn new() -> Self {
pub fn new(defines: &FastHashMap<String, String>) -> Self {
LinePreProcessor {
defines: FastHashMap::default(),
defines: defines.clone(),
if_stack: vec![],
inside_comment: false,
in_preprocess: false,

View File

@@ -11,13 +11,13 @@ pub struct PreProcessor<'a> {
}
impl<'a> PreProcessor<'a> {
pub fn new(input: &'a str) -> Self {
pub fn new(input: &'a str, defines: crate::FastHashMap<String, String>) -> Self {
let mut lexer = PreProcessor {
lines: input.lines().enumerate(),
input: "".to_string(),
line: 0,
offset: 0,
line_pp: LinePreProcessor::new(),
line_pp: LinePreProcessor::new(&defines),
};
lexer.next_line();
lexer
@@ -69,6 +69,7 @@ fn preprocess() {
let mut pp = PreProcessor::new(
"void main my_\
func",
Default::default(),
);
assert_eq!(pp.process().unwrap(), "void main my_func");
@@ -76,6 +77,7 @@ fn preprocess() {
let mut pp = PreProcessor::new(
"#version 450 core\n\
void main()",
Default::default(),
);
assert_eq!(pp.process().unwrap(), "#version 450 core\nvoid main()");
@@ -83,6 +85,7 @@ fn preprocess() {
let mut pp = PreProcessor::new(
"#define FOO 42 \n\
fun=FOO",
Default::default(),
);
assert_eq!(pp.process().unwrap(), "\nfun=42");
@@ -99,6 +102,7 @@ fn preprocess() {
mm=49\n\
#endif\n\
done=1",
Default::default(),
);
assert_eq!(
pp.process().unwrap(),
@@ -133,6 +137,7 @@ fn preprocess() {
mm=49\n\
#endif\n\
done=1",
Default::default(),
);
assert_eq!(
pp.process().unwrap(),
@@ -166,6 +171,7 @@ fn preprocess() {
nofoo=66\n\
#endif\n\
done=1",
Default::default(),
);
assert_eq!(
pp.process().unwrap(),
@@ -183,6 +189,7 @@ fn preprocess() {
let mut pp = PreProcessor::new(
"#define FOO 42//1234\n\
fun=FOO",
Default::default(),
);
assert_eq!(pp.process().unwrap(), "\nfun=42");
@@ -192,6 +199,7 @@ fn preprocess() {
#define FOO 88\n\
end of comment*/ /* one more comment */ #define FOO 56\n\
fun=FOO",
Default::default(),
);
assert_eq!(pp.process().unwrap(), "\nfun=56");
@@ -201,6 +209,7 @@ fn preprocess() {
foo=42\n\
#endif\n\
#endif",
Default::default(),
);
assert_eq!(pp.process(), Err(Error::UnmatchedEndif));
@@ -213,6 +222,7 @@ fn preprocess() {
#else\n\
bad=true\n\
#endif",
Default::default(),
);
assert_eq!(pp.process(), Err(Error::UnmatchedElse));
}

View File

@@ -1,13 +1,13 @@
use crate::{
Binding, BuiltIn, Expression, GlobalVariable, Handle, ScalarKind, ShaderStage, StorageAccess,
StorageClass, Type, TypeInner, VectorSize,
Binding, BuiltIn, Expression, GlobalVariable, Handle, ScalarKind, StorageAccess, StorageClass,
Type, TypeInner, VectorSize,
};
use super::ast::*;
use super::error::ErrorKind;
use super::token::TokenMetadata;
impl Program {
impl Program<'_> {
pub fn lookup_variable(&mut self, name: &str) -> Result<Option<Handle<Expression>>, ErrorKind> {
if let Some(local_var) = self.context.lookup_local_var(name) {
return Ok(Some(local_var));
@@ -20,10 +20,6 @@ impl Program {
}
match name {
"gl_Position" => {
#[cfg(feature = "glsl-validate")]
if !self.has_stage(ShaderStage::Vertex) {
return Err(ErrorKind::VariableNotAvailable(name.into()));
};
let h = self.module.global_variables.append(GlobalVariable {
name: Some(name.into()),
class: StorageClass::Output,
@@ -50,10 +46,6 @@ impl Program {
Ok(Some(exp))
}
"gl_VertexIndex" => {
#[cfg(feature = "glsl-validate")]
if !self.has_stage(ShaderStage::Vertex) {
return Err(ErrorKind::VariableNotAvailable(name.into()));
};
let h = self.module.global_variables.append(GlobalVariable {
name: Some(name.into()),
class: StorageClass::Input,
@@ -86,10 +78,6 @@ impl Program {
Ok(Some(expr))
}
"gl_InstanceIndex" => {
#[cfg(feature = "glsl-validate")]
if !self.has_stage(ShaderStage::Vertex) {
return Err(ErrorKind::VariableNotAvailable(name.into()));
};
let h = self.module.global_variables.append(GlobalVariable {
name: Some(name.into()),
class: StorageClass::Input,

View File

@@ -1,8 +1,5 @@
(
spv_version: (1, 0),
spv_capabilities: [ Shader ],
mtl_bindings: {
(stage: Fragment, group: 0, binding: 0): (texture: Some(0)),
(stage: Fragment, group: 0, binding: 1): (sampler: Some(0)),
}
mtl_bindings: {}
)

View File

@@ -14,10 +14,14 @@ fn check_glsl(name: &str) {
panic!("Unknown extension in {:?}", name)
};
let mut entry_points = naga::FastHashMap::default();
entry_points.insert("main".to_string(), stage);
match naga::front::glsl::parse_str(
&input,
vec![("main".to_string(), stage)],
Default::default(),
&naga::front::glsl::Options {
entry_points,
defines: Default::default(),
},
) {
Ok(m) => match naga::proc::Validator::new().validate(&m) {
Ok(_analysis) => (),

View File

@@ -249,7 +249,7 @@ fn convert_spv_shadow() {
}
#[cfg(feature = "glsl-in")]
fn convert_glsl(name: &str, entry_points: Vec<(String, naga::ShaderStage)>) {
fn convert_glsl(name: &str, entry_points: naga::FastHashMap<String, naga::ShaderStage>) {
let params = match std::fs::read_to_string(format!("tests/in/{}{}", name, ".param.ron")) {
Ok(string) => ron::de::from_str(&string).expect("Couldn't find param file"),
Err(_) => Parameters::default(),
@@ -258,8 +258,10 @@ fn convert_glsl(name: &str, entry_points: Vec<(String, naga::ShaderStage)>) {
let module = naga::front::glsl::parse_str(
&std::fs::read_to_string(format!("tests/in/{}{}", name, ".glsl"))
.expect("Couldn't find glsl file"),
entry_points,
Default::default(),
&naga::front::glsl::Options {
entry_points,
defines: Default::default(),
},
)
.unwrap();
naga::proc::Validator::new().validate(&module).unwrap();
@@ -281,11 +283,8 @@ fn convert_glsl(name: &str, entry_points: Vec<(String, naga::ShaderStage)>) {
#[cfg(feature = "glsl-in")]
#[test]
fn convert_glsl_quad() {
convert_glsl(
"quad-glsl",
vec![
("vert_main".to_string(), naga::ShaderStage::Vertex),
("frag_main".to_string(), naga::ShaderStage::Fragment),
],
);
let mut entry_points = naga::FastHashMap::default();
entry_points.insert("vert_main".to_string(), naga::ShaderStage::Vertex);
entry_points.insert("frag_main".to_string(), naga::ShaderStage::Fragment);
convert_glsl("quad-glsl", entry_points);
}