Skip to content

Commit

Permalink
Improved material asset handler and GLSL shader generation.
Browse files Browse the repository at this point in the history
  • Loading branch information
facundo-villa committed Feb 22, 2024
1 parent d2f85fd commit 43ee9ae
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 88 deletions.
62 changes: 37 additions & 25 deletions jspd/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,28 +31,7 @@ impl Deref for NodeReference {
}

pub(super) fn lex(node: &parser::Node, parser_program: &parser::ProgramState) -> Result<NodeReference, LexError> {
let float = Node::r#struct("float".to_string(), Vec::new());

let vec3f = Node::r#struct("vec3f".to_string(), vec![
Node::member("x".to_string(), float.clone()),
Node::member("y".to_string(), float.clone()),
Node::member("z".to_string(), float.clone()),
]);

let vec4f = Node::r#struct("vec4f".to_string(), vec![
Node::member("x".to_string(), float.clone()),
Node::member("y".to_string(), float.clone()),
Node::member("z".to_string(), float.clone()),
Node::member("w".to_string(), float.clone()),
]);

let root = Node::scope("root".to_string(), vec![
float,
vec3f,
vec4f,
]);

lex_with_root(root, node, parser_program)
lex_with_root(Node::root(), node, parser_program)
}

pub(super) fn lex_with_root(root: NodeReference, node: &parser::Node, parser_program: &parser::ProgramState) -> Result<NodeReference, LexError> {
Expand Down Expand Up @@ -83,6 +62,31 @@ impl Node {
NodeReference(Rc::new(RefCell::new(node)))
}

pub fn root() -> NodeReference {
let float = Node::r#struct("float".to_string(), Vec::new());

let vec3f = Node::r#struct("vec3f".to_string(), vec![
Node::member("x".to_string(), float.clone()),
Node::member("y".to_string(), float.clone()),
Node::member("z".to_string(), float.clone()),
]);

let vec4f = Node::r#struct("vec4f".to_string(), vec![
Node::member("x".to_string(), float.clone()),
Node::member("y".to_string(), float.clone()),
Node::member("z".to_string(), float.clone()),
Node::member("w".to_string(), float.clone()),
]);

let root = Node::scope("root".to_string(), vec![
float,
vec3f,
vec4f,
]);

root
}

pub fn scope(name: String, children: Vec<NodeReference>) -> NodeReference {
let mut node = Node {
parent: None,
Expand Down Expand Up @@ -145,11 +149,11 @@ impl Node {
})
}

pub fn binding(name: String, r#type: BindingTypes, set: u32, binding: u32, read: bool, write: bool) -> NodeReference {
pub fn binding(name: &str, r#type: BindingTypes, set: u32, binding: u32, read: bool, write: bool) -> NodeReference {
Self::internal_new(Node {
parent: None,
node: Nodes::Binding {
name,
name: name.to_string(),
r#type,
set,
binding,
Expand Down Expand Up @@ -297,11 +301,19 @@ impl Node {

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BindingTypes {
Buffer,
Buffer {
r#type: NodeReference,
},
CombinedImageSampler,
Image,
}

impl BindingTypes {
pub fn buffer(r#type: NodeReference) -> BindingTypes {
BindingTypes::Buffer{ r#type }
}
}

#[derive(Clone, Debug,)]
pub enum Nodes {
Null,
Expand Down
82 changes: 37 additions & 45 deletions resource_management/src/asset/material_asset_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{borrow::Borrow, cell::RefCell, ops::Deref};

use smol::future::FutureExt;

use crate::{resource::material_resource_handler::ProgramGenerator, types::{AlphaMode, Material, Model, Property, Shader, ShaderTypes, Value, Variant, VariantVariable}, GenericResourceSerialization, ProcessedResources};
use crate::{resource::material_resource_handler::ProgramGenerator, shader_generation::{ShaderGenerationSettings, ShaderGenerator}, types::{AlphaMode, Material, Model, Property, Shader, ShaderTypes, Value, Variant, VariantVariable}, GenericResourceSerialization, ProcessedResources};

use super::{asset_handler::AssetHandler, AssetResolver, StorageBackend};

Expand Down Expand Up @@ -43,7 +43,7 @@ impl AssetHandler for MaterialAssetHandler {
let generator = self.generator.as_ref().unwrap();

let mut required_resources = asset_json["shaders"].entries().filter_map(|(s_type, shader_json)| {
smol::block_on(produce_shader(generator.deref(), asset_resolver, &material_domain, &asset_json, &shader_json, s_type))
smol::block_on(transform_shader(generator.deref(), asset_resolver, storage_backend, &material_domain, &asset_json, &shader_json, s_type))
}).collect::<Vec<_>>();

for variable in asset_json["variables"].members() {
Expand Down Expand Up @@ -93,50 +93,26 @@ impl AssetHandler for MaterialAssetHandler {
}
}

async fn produce_shader(generator: &dyn ProgramGenerator, asset_resolver: &dyn AssetResolver, domain: &str, material: &json::JsonValue, shader_json: &json::JsonValue, stage: &str) -> Option<ProcessedResources> {
async fn transform_shader(generator: &dyn ProgramGenerator, asset_resolver: &dyn AssetResolver, storage_backend: &dyn StorageBackend, domain: &str, material: &json::JsonValue, shader_json: &json::JsonValue, stage: &str) -> Option<ProcessedResources> {
let path = shader_json.as_str()?;
let (arlp, format) = asset_resolver.resolve(&path).await?;

let shader_code = std::str::from_utf8(&arlp).unwrap().to_string();

let root_scope = jspd::Node::root();

let parent_scope = generator.transform(root_scope);

let shader_option = if format == "glsl" {
todo!();
Some((jspd::lexer::Node::glsl(shader_code), path.to_string()))
} else if format == "besl" {
Some((jspd::compile_to_jspd(&shader_code, None).unwrap(), path.to_string()))
Some((jspd::compile_to_jspd(&shader_code, Some(parent_scope.clone())).unwrap(), path.to_string()))
} else {
None
};

if let Some((shader, path)) = shader_option {
Some(treat_shader(generator, &path, domain, stage, material, &shader,)?.unwrap())
} else {
let default_shader = match stage {
"Vertex" => default_vertex_shader(),
"Fragment" => default_fragment_shader(),
_ => { panic!("Invalid shader stage") }
};

let shader_node = jspd::lexer::Node::glsl(default_shader.to_string());

Some(treat_shader(generator, "", domain, stage, material, &shader_node,)?.unwrap())
}
}

fn treat_shader(generator: &dyn ProgramGenerator, path: &str, domain: &str, stage: &str, material: &json::JsonValue, shader_node: &jspd::NodeReference,) -> Option<Result<ProcessedResources, String>> {
let visibility = generator;

let main = match RefCell::borrow(&shader_node).node() {
jspd::Nodes::Scope { children, .. } => {
children[0].clone()
}
_ => {
return Some(Err("Invalid shader".to_string()));
}
};

let glsl = String::new();

log::debug!("Generated shader: {}", &glsl);
let glsl = ShaderGenerator::new().minified(!cfg!(debug_assertions)).compilation().generate_glsl_shader(&ShaderGenerationSettings::new(stage), &RefCell::borrow(&parent_scope).get_child("main").unwrap());

let compiler = shaderc::Compiler::new().unwrap();
let mut options = shaderc::CompileOptions::new().unwrap();
Expand All @@ -161,7 +137,7 @@ fn treat_shader(generator: &dyn ProgramGenerator, path: &str, domain: &str, stag
let error_string = err.to_string();
let error_string = ghi::shader_compilation::format_glslang_error(path, &error_string, &glsl).unwrap_or(error_string);
log::error!("Error compiling shader:\n{}", error_string);
return Some(Err(err.to_string()));
return None;
}
};

Expand All @@ -182,7 +158,9 @@ fn treat_shader(generator: &dyn ProgramGenerator, path: &str, domain: &str, stag
stage,
});

Some(Ok(ProcessedResources::Generated((resource, Vec::from(result_shader_bytes)))))
storage_backend.store(resource, result_shader_bytes);

None
}

fn default_vertex_shader() -> &'static str {
Expand All @@ -195,6 +173,8 @@ fn default_fragment_shader() -> &'static str {

#[cfg(test)]
mod tests {
use std::cell::RefCell;

use super::{MaterialAssetHandler};
use crate::{asset::{asset_handler::AssetHandler, tests::{TestAssetResolver, TestStorageBackend}}, resource::material_resource_handler::ProgramGenerator};

Expand All @@ -216,8 +196,10 @@ mod tests {
}

impl ProgramGenerator for TestShaderGenerator {
fn transform(&self, children: Vec<std::rc::Rc<jspd::Node>>) -> (&'static str, jspd::Node) {
todo!()
fn transform(&self, scope: jspd::NodeReference) -> jspd::NodeReference {
let vec4f = RefCell::borrow(&scope).get_child("vec4f").unwrap();
RefCell::borrow_mut(&scope).add_children(vec![jspd::Node::binding("material",jspd::BindingTypes::buffer(jspd::Node::r#struct("Material".to_string(), vec![jspd::Node::member("color".to_string(), vec4f)])), 0, 0, true, false)]);
scope
}
}

Expand All @@ -231,7 +213,7 @@ mod tests {
"domain": "World",
"type": "Surface",
"shaders": {
"Fragment": "shaders/fragment.besl"
"Fragment": "fragment.besl"
},
"variables": [
{
Expand All @@ -246,24 +228,34 @@ mod tests {
asset_resolver.add_file(url, material_json.as_bytes());

let shader_file = "main: fn () -> void {
out_color = color;
material;
}";

asset_resolver.add_file("shaders/fragment.besl", shader_file.as_bytes());
asset_resolver.add_file("fragment.besl", shader_file.as_bytes());

let doc = json::object! {
"url": url,
};

let result = smol::block_on(asset_handler.load(&asset_resolver, &storage_backend, &url, &doc)).expect("Image asset handler did not handle asset");
smol::block_on(asset_handler.load(&asset_resolver, &storage_backend, &url, &doc)).expect("Image asset handler did not handle asset").expect("Failed to load material");

let generated_resources = storage_backend.get_resources();

assert_eq!(generated_resources.len(), 2);

let resource = &generated_resources[0];
let shader = &generated_resources[0];

assert_eq!(shader.url, "fragment.besl");
assert_eq!(shader.class, "Shader");

let shader_glsl = storage_backend.get_resource_data_by_name("fragment.besl").expect("Expected shader data");
let shader_glsl = String::from_utf8_lossy(&shader_glsl);

assert!(shader_glsl.contains("material"));

let material = &generated_resources[1];

assert_eq!(resource.url, "material.json");
assert_eq!(resource.class, "Material");
assert_eq!(material.url, "material.json");
assert_eq!(material.class, "Material");
}
}
4 changes: 4 additions & 0 deletions resource_management/src/asset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ pub mod tests {
pub fn get_resources(&self) -> Vec<GenericResourceSerialization> {
self.resources.lock().unwrap().iter().map(|x| x.0.clone()).collect()
}

pub fn get_resource_data_by_name(&self, name: &str) -> Option<Box<[u8]>> {
Some(self.resources.lock().unwrap().iter().find(|x| x.0.url == name)?.1.clone())
}
}

impl StorageBackend for TestStorageBackend {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct MaterialResourcerHandler {}

pub trait ProgramGenerator: Sync + Send {
/// Transforms a program.
fn transform(&self, children: Vec<std::rc::Rc<jspd::Node>>) -> (&'static str, jspd::Node);
fn transform(&self, scope: jspd::NodeReference) -> jspd::NodeReference;
}

impl MaterialResourcerHandler {
Expand Down
Loading

0 comments on commit 43ee9ae

Please sign in to comment.