Skip to content

Commit

Permalink
Updated shader generation pipeline.
Browse files Browse the repository at this point in the history
  • Loading branch information
facundo-villa committed Sep 29, 2023
1 parent 479e7d3 commit ebdc7cc
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 46 deletions.
7 changes: 4 additions & 3 deletions assets/cube.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"type": "raw",
"vertex": "shaders/vertex.glsl",
"fragment": "shaders/fragment.glsl"
"type": "Surface",
"shaders": {
"Fragment": "shaders/fragment.besl"
}
}
2 changes: 1 addition & 1 deletion assets/shaders/fragment.besl
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
main: fn () -> void {
out_color = get_debug_color(in_instance_index);
out_color = vec4f(1.0, 0.0, 0.0, 1.0);
}
3 changes: 0 additions & 3 deletions assets/shaders/fragment.glsl

This file was deleted.

4 changes: 0 additions & 4 deletions assets/shaders/vertex.besl

This file was deleted.

5 changes: 5 additions & 0 deletions assets/shaders/visibility/material_count.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
void main() {
uint material_index = pixel;

material_count[material_index] += 1;
}
66 changes: 66 additions & 0 deletions assets/shaders/visibility/material_start.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// All threads in the same group will share the same atomic result.
shared uint atomic;

#define WAVE_SIZE 32
#define WAVE_SIZE_BASE uint(log2(WAVE_SIZE))

layout(buffer_reference, std430, binding = 0) readonly buffer MaterialStartPassInfo {
uint entryCount;
uint treeDepth;
uint treeOffsets[];
};

layout(buffer_reference, std430, binding = 0) coherent buffer TreeBuffer {
uint tree[];
};

layout(local_size_x = WAVE_SIZE) in;
void main() {
uint groupId = gl_WorkGroupID.x;
uint localThreadId = gl_LocalInvocationIndex;

// A buffer of atomics initialized to 0.
atomicsBuffer = [];

for (int i = 0; i < treeDepth; ++i) {
// The global thread ID is unique for all threads launched and corresponds to two elements in the tree layer below.
uint globalThreadId = (groupId << WAVE_SIZE_BASE) + localThreadId;
uint readOffset = treeOffsets[i];
uint writeOffset = treeOffsets[i + 1];

// This thread is only valid if the tree has one or two elements in the layer below that this thread should sum up.
bool validThread = globalThreadId < materialStartPassInfo.entryCount;

if (validThread) {
// Sum the two elements in the previous layer and write them for the current layer.
uint elementReadOffset = readOffset + (globalThreadId * 2);
uint elementWriteOffset = readOffset + globalThreadId;
tree[elementWriteOffset] = tree[elementReadOffset + 0] + tree[elementReadOffset + 1];
}

uint weight = 0;

if (validThread) {
weight = tree[treeOffsets[i] + globalThreadId];
}

uint sum = subgroupExclusiveAdd(weight) + weight;

// The last thread in the wave will write the sum.
if (localThreadId == WAVE_SIZE - 1) {
tree[treeOffsets[i + 1] + groupId] = sum;
}

// Sync to ensure that the atomic for this thread group has been updated and will be visible for all threads in the group.
groupMemoryBarrier(); barrier(); memoryBarrier();

// Two thread groups wrote to the same atomic, only the last one to write survives for the next tree layer.
if (atomic < 1) {
return;
}

// Sync to make sure that all threads within a group have finished reading the value of `atomic`.
// This is needed because it will be modified again in the next iteration.
groupMemoryBarrier(); barrier();
}
}
3 changes: 3 additions & 0 deletions assets/shaders/visibility/visibility/fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
void main() {
out_material_index = 0;
}
File renamed without changes.
4 changes: 2 additions & 2 deletions assets/visibility.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@
"data_type": "u32",
"interpolation": "flat"
},
"out_color": {
"out_material_index": {
"type": "out",
"data_type": "vec4f"
"data_type": "u32"
}
}
}
117 changes: 85 additions & 32 deletions src/resource_manager/material_resource_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ impl MaterialResourcerHandler {

}
}

fn default_vertex_shader() -> &'static str {
"void main() { gl_Position = pc.camera.view_projection * pc.meshes[gl_InstanceIndex].model * vec4(in_position, 1.0); out_instance_index = gl_InstanceIndex; }"
}

fn default_fragment_shader() -> &'static str {
"void main() { out_color = get_debug_color(in_instance_index); }"
}
}

impl ResourceHandler for MaterialResourcerHandler {
Expand All @@ -32,27 +40,7 @@ impl ResourceHandler for MaterialResourcerHandler {
}

fn process(&self, bytes: &[u8]) -> Result<Vec<(Document, Vec<u8>)>, String> {
let material_json = json::parse(std::str::from_utf8(&bytes).unwrap()).unwrap();

let _t = material_json["type"].as_str().unwrap();
let vertex = material_json["vertex"].as_str().unwrap();
let fragment = material_json["fragment"].as_str().unwrap();

fn treat_shader(path: &str, stage: &str) -> Result<(Document, Vec<u8>), String> {
let arlp = "assets/".to_string() + path;

let shader_node = if path.ends_with(".glsl") {
let shader_code = std::fs::read_to_string(&arlp).unwrap();
jspd::lexer::Node {
node: jspd::lexer::Nodes::GLSL { code: shader_code },
}
} else if path.ends_with(".besl") {
let shader_code = std::fs::read_to_string(&arlp).unwrap();
jspd::compile_to_jspd(&shader_code).unwrap()
} else {
panic!("Unknown shader type");
};

fn treat_shader(shader_node: jspd::lexer::Node, path: &str, stage: &str,) -> Result<(Document, Vec<u8>), String> {
let common = crate::rendering::common_shader_generator::CommonShaderGenerator::new();

let visibility = crate::rendering::visibility_shader_generator::VisibilityShaderGenerator::new();
Expand Down Expand Up @@ -116,23 +104,88 @@ impl ResourceHandler for MaterialResourcerHandler {
Ok((resource, Vec::from(result_shader_bytes)))
}

let a = treat_shader(vertex, "Vertex")?;
let b = treat_shader(fragment, "Fragment")?;
let material_json = json::parse(std::str::from_utf8(&bytes).unwrap()).unwrap();

fn produce_shader(material_json: &json::JsonValue, stage: &str) -> ((Document, Vec<u8>), String) {
let shader_option = match &material_json["shaders"][stage] {
json::JsonValue::Null => { None }
json::JsonValue::Short(path) => {
let arlp = "assets/".to_string() + path.as_str();

if path.ends_with(".glsl") {
let shader_code = std::fs::read_to_string(&arlp).unwrap();
Some((jspd::lexer::Node {
node: jspd::lexer::Nodes::GLSL { code: shader_code },
}, path.to_string()))
} else if path.ends_with(".besl") {
let shader_code = std::fs::read_to_string(&arlp).unwrap();
Some((jspd::compile_to_jspd(&shader_code).unwrap(), path.to_string()))
} else {
None
}
}
json::JsonValue::String(path) => {
let arlp = "assets/".to_string() + path.as_str();

if path.ends_with(".glsl") {
let shader_code = std::fs::read_to_string(&arlp).unwrap();
Some((jspd::lexer::Node {
node: jspd::lexer::Nodes::GLSL { code: shader_code },
}, path.to_string()))
} else if path.ends_with(".besl") {
let shader_code = std::fs::read_to_string(&arlp).unwrap();
Some((jspd::compile_to_jspd(&shader_code).unwrap(), path.to_string()))
} else {
None
}
}
_ => {
error!("Invalid {stage} shader");
None
}
};

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

let shader_node = jspd::lexer::Node {
node: jspd::lexer::Nodes::GLSL { code: default_shader.to_string() },
};

(treat_shader(shader_node, "", stage).unwrap(), "".to_string())
}
}

let mut shaders = if let json::JsonValue::Short(s) = material_json["type"] {
if s.as_str() == "Raw" {
material_json["shaders"].entries().map(|(s_type, s)| {
let shader = produce_shader(&material_json, s_type);
shader
}).collect::<Vec<_>>()
} else {
vec![produce_shader(&material_json, "Vertex"), produce_shader(&material_json, "Fragment")]
}
} else {
vec![produce_shader(&material_json, "Vertex"), produce_shader(&material_json, "Fragment")]
};

let required_resources = shaders.iter().map(|s| polodb_core::bson::doc! { "path": s.1.clone() }).collect::<Vec<_>>();

let material_resource_document = polodb_core::bson::doc!{
"class": "Material",
"required_resources": [
{
"path": vertex,
},
{
"path": fragment,
}
],
"required_resources": required_resources,
"resource": {}
};

Ok(vec![a, b, (material_resource_document, Vec::new())])
shaders.push(((material_resource_document.clone(), Vec::new()), "".to_string()));

Ok(shaders.iter().map(|s| s.0.clone()).collect::<Vec<_>>())
}

fn get_deserializer(&self) -> Box<dyn Fn(&polodb_core::bson::Document) -> Box<dyn std::any::Any> + Send> {
Expand Down
11 changes: 10 additions & 1 deletion src/shader_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,16 @@ impl ShaderGenerator {
lexer::Expressions::Literal{ value } => {
string.push_str(&format!("{value}"));
}
_ => todo!()
lexer::Expressions::Member { name } => {
string.push_str(&format!("{name}", name = name));
}
lexer::Expressions::Accessor { left, right } => {
process_node(Some(&mut string), left, compilation_settings, program_state);

string.push_str(&format!(".",));

process_node(Some(&mut string), right, compilation_settings, program_state);
}
}
}
lexer::Nodes::GLSL { code } => {
Expand Down
42 changes: 42 additions & 0 deletions tests/gi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#![feature(const_mut_refs)]

use byte_engine::{application::Application, Vec3f, input_manager, Vector3, orchestrator::{Component, EntityHandle, self, System,}, render_domain::{Mesh, MeshParameters}, math};
use maths_rs::prelude::{MatTranslate, MatScale, MatInverse};

#[ignore]
#[test]
fn gi() {
let mut app = byte_engine::application::GraphicsApplication::new("Gallery Shooter");
app.initialize(std::env::args());

let orchestrator = app.get_mut_orchestrator();

orchestrator.spawn(byte_engine::camera::Camera {
position: Vec3f::new(0.0, 0.5, -1.0),
direction: Vec3f::new(0.0, -0.1, 0.9),
fov: 90.0,
aspect_ratio: 1.0,
aperture: 0.0,
focus_distance: 0.0,
});

let _floor: EntityHandle<Mesh> = orchestrator.spawn(Mesh{ resource_id: "Box", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.0, -0.25, 0.0)), });
let _a: EntityHandle<Mesh> = orchestrator.spawn(Mesh{ resource_id: "Box", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.0, 0.25, 2.0)) * maths_rs::Mat4f::from_scale(Vec3f::new(0.5, 0.5, 0.5)), });
let _b: EntityHandle<Mesh> = orchestrator.spawn(Mesh{ resource_id: "Box", transform: maths_rs::Mat4f::from_translation(Vec3f::new(-0.8, 0.17, 1.7)) * maths_rs::Mat4f::from_scale(Vec3f::new(0.34, 0.34, 0.34)), });
let _c: EntityHandle<Mesh> = orchestrator.spawn(Mesh{ resource_id: "Box", transform: maths_rs::Mat4f::from_translation(Vec3f::new(0.7, 0.13, 1.8)) * maths_rs::Mat4f::from_scale(Vec3f::new(0.26, 0.26, 0.26)), });

app.do_loop();

app.deinitialize();
}

struct Player {
mesh: EntityHandle<Mesh>,
camera: EntityHandle<byte_engine::camera::Camera>,
}

impl orchestrator::Entity for Player {}

impl Component for Player {
// type Parameters<'a> = EntityHandle<input_manager::Action<Vec3f>>;
}

0 comments on commit ebdc7cc

Please sign in to comment.