mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
more render_graph work
This commit is contained in:
parent
d9bd2d4f15
commit
7a386b8b46
10 changed files with 550 additions and 213 deletions
|
@ -6,7 +6,7 @@ use winit::{
|
|||
|
||||
use legion::prelude::*;
|
||||
|
||||
use crate::{core::Time, render::*};
|
||||
use crate::{core::Time, render::*, app::AppBuilder};
|
||||
|
||||
pub struct App {
|
||||
pub universe: Universe,
|
||||
|
@ -30,6 +30,10 @@ impl App {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn build() -> AppBuilder {
|
||||
AppBuilder::new()
|
||||
}
|
||||
|
||||
fn update(&mut self) {
|
||||
if let Some(mut time) = self.world.resources.get_mut::<Time>() {
|
||||
time.start();
|
||||
|
|
|
@ -18,6 +18,8 @@ pub enum MeshType {
|
|||
pub struct Mesh {
|
||||
pub vertices: Vec<Vertex>,
|
||||
pub indices: Vec<u16>,
|
||||
|
||||
// TODO: remove me
|
||||
pub vertex_buffer: Option<Buffer>,
|
||||
pub index_buffer: Option<Buffer>,
|
||||
}
|
||||
|
|
52
src/render/render_graph_2/example.rs
Normal file
52
src/render/render_graph_2/example.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
use crate::render::{render_graph_2::*, shader::{Shader, ShaderStage}, Vertex};
|
||||
|
||||
fn build_example_graph() -> RenderGraph {
|
||||
// TODO: read this from swap chain
|
||||
let swap_chain_color_format = wgpu::TextureFormat::Bgra8UnormSrgb;
|
||||
RenderGraph::build()
|
||||
.add_pass(
|
||||
"main",
|
||||
PassDescriptor {
|
||||
color_attachments: Vec::new(),
|
||||
depth_stencil_attachment: None,
|
||||
sample_count: 1,
|
||||
},
|
||||
)
|
||||
.add_pipeline(
|
||||
"forward",
|
||||
PipelineDescriptor::build(Shader::from_glsl(
|
||||
include_str!("../passes/forward/forward.vert"),
|
||||
ShaderStage::Vertex,
|
||||
))
|
||||
.with_fragment_shader(Shader::from_glsl(
|
||||
include_str!("../passes/forward/forward.vert"),
|
||||
ShaderStage::Fragment,
|
||||
))
|
||||
.with_rasterization_state(wgpu::RasterizationStateDescriptor {
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: wgpu::CullMode::Back,
|
||||
depth_bias: 0,
|
||||
depth_bias_slope_scale: 0.0,
|
||||
depth_bias_clamp: 0.0,
|
||||
})
|
||||
.with_depth_stencil_state(wgpu::DepthStencilStateDescriptor {
|
||||
format: wgpu::TextureFormat::Depth32Float,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::Less,
|
||||
stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE,
|
||||
stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE,
|
||||
stencil_read_mask: 0,
|
||||
stencil_write_mask: 0,
|
||||
})
|
||||
.with_color_state(wgpu::ColorStateDescriptor {
|
||||
format: swap_chain_color_format,
|
||||
color_blend: wgpu::BlendDescriptor::REPLACE,
|
||||
alpha_blend: wgpu::BlendDescriptor::REPLACE,
|
||||
write_mask: wgpu::ColorWrite::ALL,
|
||||
})
|
||||
.with_vertex_buffer_descriptor(Vertex::get_vertex_buffer_descriptor())
|
||||
.with_draw_target(mesh_draw_target)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
}
|
|
@ -1,77 +1,19 @@
|
|||
mod pipeline;
|
||||
mod pass;
|
||||
mod renderer;
|
||||
mod shader;
|
||||
mod render_graph;
|
||||
mod example;
|
||||
|
||||
|
||||
pub use pipeline::*;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{asset::Texture, legion::{prelude::{Entity, World}, borrow::{Ref, RefMap}}, render::Albedo};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub enum ShaderValue<'a> {
|
||||
Int(u32),
|
||||
Float(f32),
|
||||
Vec4(Vec4),
|
||||
Texture(&'a Handle<Texture>),
|
||||
}
|
||||
|
||||
type ShaderMaterialSelector = fn(Entity, &World) -> Option<RefMap<&dyn ShaderMaterial>>;
|
||||
pub struct ShaderMaterials {
|
||||
// used for distinguishing
|
||||
pub materials: Vec<ShaderMaterialSelector>
|
||||
}
|
||||
|
||||
impl<'a> ShaderMaterials {
|
||||
pub fn new() -> Self {
|
||||
ShaderMaterials {
|
||||
materials: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, selector: ShaderMaterialSelector) {
|
||||
self.materials.push(selector);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ShaderMaterial {
|
||||
fn iter_properties(&self) -> std::slice::Iter<&'static str> ;
|
||||
fn get_property(&self, name: &str) -> Option<ShaderValue>;
|
||||
fn get_selector(&self) -> ShaderMaterialSelector;
|
||||
}
|
||||
|
||||
pub struct StandardMaterial {
|
||||
pub albedo: Albedo
|
||||
}
|
||||
|
||||
// create this from a derive macro
|
||||
const STANDARD_MATERIAL_PROPERTIES: &[&str] = &["albedo"];
|
||||
impl ShaderMaterial for StandardMaterial {
|
||||
fn iter_properties(&self) -> std::slice::Iter<&'static str> {
|
||||
STANDARD_MATERIAL_PROPERTIES.iter()
|
||||
}
|
||||
fn get_property(&self, name: &str) -> Option<ShaderValue> {
|
||||
match name {
|
||||
"albedo" => Some(match self.albedo {
|
||||
Albedo::Color(color) => ShaderValue::Vec4(color),
|
||||
Albedo::Texture(ref texture) => ShaderValue::Texture(texture)
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn get_selector(&self) -> ShaderMaterialSelector {
|
||||
|entity, world| {
|
||||
world.get_component::<Self>(entity).map(
|
||||
|c: Ref<StandardMaterial>| {
|
||||
c.map_into(|s| {
|
||||
s as &dyn ShaderMaterial
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use pass::*;
|
||||
pub use renderer::*;
|
||||
pub use shader::*;
|
||||
pub use render_graph::*;
|
||||
|
||||
// a named graphics resource provided by a resource provider
|
||||
struct Resource {
|
||||
pub struct Resource {
|
||||
resource_type: ResourceType,
|
||||
name: String,
|
||||
}
|
||||
|
@ -79,7 +21,7 @@ struct Resource {
|
|||
// a resource type
|
||||
enum ResourceType {
|
||||
Texture,
|
||||
Uniform,
|
||||
Buffer,
|
||||
Sampler,
|
||||
}
|
||||
|
||||
|
@ -90,81 +32,4 @@ enum ResourceType {
|
|||
// if there are no resources in use, dont run allocate resource provider resources on gpu
|
||||
trait ResourceProvider {
|
||||
fn get_resources(&self) -> &[Resource];
|
||||
}
|
||||
|
||||
// holds on to passes, pipeline descriptions, instances
|
||||
// passes: shadow, forward
|
||||
struct RenderGraph {
|
||||
pipeline_definitions: HashMap<String, PipelineDefinition>,
|
||||
pipeline_instances: HashMap<String, wgpu::RenderPipeline>,
|
||||
}
|
||||
|
||||
struct RenderGraphBuilder {
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
RenderGraph::build()
|
||||
.AddPass("forward", Pass {
|
||||
|
||||
})
|
||||
.AddPipeline(Pipeline::build()
|
||||
.with_vertex_shader("pbr.vert")
|
||||
.with_fragment_shader("pbr.frag")
|
||||
.with_vertex_layout(Vertex::get_layout()) // maybe someday reflect this using spirv-reflect
|
||||
.with_uniform_binding("camera_resource", "shader_camera") // if a uniform is not bound directly, and no uniforms are set on entity, produce an error
|
||||
.with_texture_binding("some_texture", "shader_texture") // if a uniform is not bound directly, and no uniforms are set on entity, produce an error
|
||||
.with_draw_target(MeshDrawTarget)
|
||||
.with_draw_target(InstancedMeshDrawTarget)
|
||||
)
|
||||
.AddPipeline(Pipeline::build()
|
||||
.with_vertex_shader("ui.vert")
|
||||
.with_fragment_shader("ui.frag")
|
||||
.with_vertex_layout(Vertex::get_layout())
|
||||
.with_draw_target(UiDrawTarget)
|
||||
)
|
||||
.AddPass("shadow", Pass {
|
||||
render_target: Null
|
||||
depth_target: DepthTexture (TextureView)
|
||||
})
|
||||
.AddPipeline(Pipeline::build()
|
||||
.with_vertex_shader("pbr.vert")
|
||||
.with_fragment_shader("pbr.frag")
|
||||
.with_vertex_layout(Vertex::get_layout())
|
||||
.with_draw_target(ShadowedMeshDrawTarget)
|
||||
.with_draw_target(ShadowedInstancedMeshDrawTarget)
|
||||
)
|
||||
*/
|
||||
|
||||
pub struct RenderPassColorAttachmentDescription {
|
||||
/// The actual color attachment.
|
||||
pub attachment: String,
|
||||
|
||||
/// The resolve target for this color attachment, if any.
|
||||
pub resolve_target: Option<String>,
|
||||
|
||||
/// The beginning-of-pass load operation for this color attachment.
|
||||
pub load_op: wgpu::LoadOp,
|
||||
|
||||
/// The end-of-pass store operation for this color attachment.
|
||||
pub store_op: wgpu::StoreOp,
|
||||
|
||||
/// The color that will be assigned to every pixel of this attachment when cleared.
|
||||
pub clear_color: wgpu::Color,
|
||||
}
|
||||
|
||||
pub struct RenderPassDepthStencilAttachmentDescription {
|
||||
pub attachment: String,
|
||||
pub depth_load_op: wgpu::LoadOp,
|
||||
pub depth_store_op: wgpu::StoreOp,
|
||||
pub clear_depth: f32,
|
||||
pub stencil_load_op: wgpu::LoadOp,
|
||||
pub stencil_store_op: wgpu::StoreOp,
|
||||
pub clear_stencil: u32,
|
||||
}
|
||||
|
||||
// A set of pipeline bindings and draw calls with color and depth outputs
|
||||
struct Pass {
|
||||
color_attachments: Vec<RenderPassColorAttachmentDescription>,
|
||||
depth_stencil_attachment: Option<RenderPassDepthStencilAttachmentDescription>,
|
||||
}
|
33
src/render/render_graph_2/pass.rs
Normal file
33
src/render/render_graph_2/pass.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
pub struct RenderPassColorAttachmentDescriptor {
|
||||
/// The actual color attachment.
|
||||
pub attachment: String,
|
||||
|
||||
/// The resolve target for this color attachment, if any.
|
||||
pub resolve_target: Option<String>,
|
||||
|
||||
/// The beginning-of-pass load operation for this color attachment.
|
||||
pub load_op: wgpu::LoadOp,
|
||||
|
||||
/// The end-of-pass store operation for this color attachment.
|
||||
pub store_op: wgpu::StoreOp,
|
||||
|
||||
/// The color that will be assigned to every pixel of this attachment when cleared.
|
||||
pub clear_color: wgpu::Color,
|
||||
}
|
||||
|
||||
pub struct RenderPassDepthStencilAttachmentDescriptor {
|
||||
pub attachment: String,
|
||||
pub depth_load_op: wgpu::LoadOp,
|
||||
pub depth_store_op: wgpu::StoreOp,
|
||||
pub clear_depth: f32,
|
||||
pub stencil_load_op: wgpu::LoadOp,
|
||||
pub stencil_store_op: wgpu::StoreOp,
|
||||
pub clear_stencil: u32,
|
||||
}
|
||||
|
||||
// A set of pipeline bindings and draw calls with color and depth outputs
|
||||
pub struct PassDescriptor {
|
||||
pub color_attachments: Vec<RenderPassColorAttachmentDescriptor>,
|
||||
pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachmentDescriptor>,
|
||||
pub sample_count: u32,
|
||||
}
|
|
@ -1,22 +1,15 @@
|
|||
use crate::{
|
||||
legion::prelude::World,
|
||||
render::shader::{Shader, ShaderStages},
|
||||
use crate::render::{
|
||||
render_graph_2::DrawTarget,
|
||||
shader::{Shader, ShaderStages},
|
||||
};
|
||||
|
||||
// A set of draw calls. ex: get + draw meshes, get + draw instanced meshes, draw ui meshes, etc
|
||||
// Mesh target
|
||||
// trait DrawTarget {
|
||||
// fn draw(device: &wgpu::Device);
|
||||
// }
|
||||
type DrawTarget = fn(world: &World, device: &wgpu::Device);
|
||||
|
||||
pub struct VertexBufferDefinition {
|
||||
pub struct VertexBufferDescriptor {
|
||||
pub stride: wgpu::BufferAddress,
|
||||
pub step_mode: wgpu::InputStepMode,
|
||||
pub attributes: Vec<wgpu::VertexAttributeDescriptor>,
|
||||
}
|
||||
|
||||
impl<'a> Into<wgpu::VertexBufferDescriptor<'a>> for &'a VertexBufferDefinition {
|
||||
impl<'a> Into<wgpu::VertexBufferDescriptor<'a>> for &'a VertexBufferDescriptor {
|
||||
fn into(self) -> wgpu::VertexBufferDescriptor<'a> {
|
||||
wgpu::VertexBufferDescriptor {
|
||||
step_mode: self.step_mode,
|
||||
|
@ -26,7 +19,7 @@ impl<'a> Into<wgpu::VertexBufferDescriptor<'a>> for &'a VertexBufferDefinition {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct PipelineDefinition {
|
||||
pub struct PipelineDescriptor {
|
||||
pub draw_targets: Vec<DrawTarget>,
|
||||
pub shader_stages: ShaderStages,
|
||||
pub rasterization_state: Option<wgpu::RasterizationStateDescriptor>,
|
||||
|
@ -44,7 +37,7 @@ pub struct PipelineDefinition {
|
|||
pub index_format: wgpu::IndexFormat,
|
||||
|
||||
/// The format of any vertex buffers used with this pipeline.
|
||||
pub vertex_buffer_definitions: Vec<VertexBufferDefinition>,
|
||||
pub vertex_buffer_descriptors: Vec<VertexBufferDescriptor>,
|
||||
|
||||
/// The number of samples calculated per pixel (for MSAA).
|
||||
pub sample_count: u32,
|
||||
|
@ -60,14 +53,14 @@ pub struct PipelineDefinition {
|
|||
pub alpha_to_coverage_enabled: bool,
|
||||
}
|
||||
|
||||
impl PipelineDefinition {
|
||||
impl PipelineDescriptor {
|
||||
fn new(vertex_shader: Shader) -> Self {
|
||||
PipelineDefinition {
|
||||
PipelineDescriptor {
|
||||
color_states: Vec::new(),
|
||||
depth_stencil_state: None,
|
||||
draw_targets: Vec::new(),
|
||||
shader_stages: ShaderStages::new(vertex_shader),
|
||||
vertex_buffer_definitions: Vec::new(),
|
||||
vertex_buffer_descriptors: Vec::new(),
|
||||
rasterization_state: Some(wgpu::RasterizationStateDescriptor {
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: wgpu::CullMode::Back,
|
||||
|
@ -84,64 +77,29 @@ impl PipelineDefinition {
|
|||
}
|
||||
}
|
||||
|
||||
impl PipelineDefinition {
|
||||
pub fn create_render_pipeline(&self, device: &wgpu::Device) -> wgpu::RenderPipeline {
|
||||
let vertex_shader_module = self.shader_stages.vertex.create_shader_module(device);
|
||||
let fragment_shader_module = match self.shader_stages.fragment {
|
||||
Some(ref fragment_shader) => Some(fragment_shader.create_shader_module(device)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
bind_group_layouts: &[],
|
||||
});
|
||||
let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
|
||||
layout: &pipeline_layout,
|
||||
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
||||
module: &vertex_shader_module,
|
||||
entry_point: &self.shader_stages.vertex.entry_point,
|
||||
},
|
||||
fragment_stage: match self.shader_stages.fragment {
|
||||
Some(ref fragment_shader) => Some(wgpu::ProgrammableStageDescriptor {
|
||||
entry_point: &fragment_shader.entry_point,
|
||||
module: fragment_shader_module.as_ref().unwrap(),
|
||||
}),
|
||||
None => None,
|
||||
},
|
||||
rasterization_state: self.rasterization_state.clone(),
|
||||
primitive_topology: self.primitive_topology,
|
||||
color_states: &self.color_states,
|
||||
depth_stencil_state: self.depth_stencil_state.clone(),
|
||||
index_format: self.index_format,
|
||||
vertex_buffers: &self
|
||||
.vertex_buffer_definitions
|
||||
.iter()
|
||||
.map(|v| v.into())
|
||||
.collect::<Vec<wgpu::VertexBufferDescriptor>>(),
|
||||
sample_count: self.sample_count,
|
||||
sample_mask: self.sample_mask,
|
||||
alpha_to_coverage_enabled: self.alpha_to_coverage_enabled,
|
||||
};
|
||||
|
||||
device.create_render_pipeline(&render_pipeline_descriptor)
|
||||
}
|
||||
|
||||
impl PipelineDescriptor {
|
||||
pub fn build(vertex_shader: Shader) -> PipelineBuilder {
|
||||
PipelineBuilder::new(vertex_shader)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PipelineBuilder {
|
||||
pipeline: PipelineDefinition,
|
||||
pipeline: PipelineDescriptor,
|
||||
vertex_buffer_descriptor_offset: u64,
|
||||
}
|
||||
|
||||
impl PipelineBuilder {
|
||||
pub fn new(vertex_shader: Shader) -> Self {
|
||||
PipelineBuilder {
|
||||
pipeline: PipelineDefinition::new(vertex_shader),
|
||||
pipeline: PipelineDescriptor::new(vertex_shader),
|
||||
vertex_buffer_descriptor_offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(self) -> PipelineDescriptor {
|
||||
self.pipeline
|
||||
}
|
||||
|
||||
pub fn with_fragment_shader(mut self, fragment_shader: Shader) -> Self {
|
||||
self.pipeline.shader_stages.fragment = Some(fragment_shader);
|
||||
self
|
||||
|
@ -152,7 +110,10 @@ impl PipelineBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn with_depth_stencil_state(mut self, depth_stencil_state: wgpu::DepthStencilStateDescriptor) -> Self {
|
||||
pub fn with_depth_stencil_state(
|
||||
mut self,
|
||||
depth_stencil_state: wgpu::DepthStencilStateDescriptor,
|
||||
) -> Self {
|
||||
if let Some(_) = self.pipeline.depth_stencil_state {
|
||||
panic!("Depth stencil state has already been set");
|
||||
}
|
||||
|
@ -160,8 +121,21 @@ impl PipelineBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn with_vertex_buffer_definition(mut self, vertex_buffer_definition: VertexBufferDefinition) -> Self {
|
||||
self.pipeline.vertex_buffer_definitions.push(vertex_buffer_definition);
|
||||
pub fn with_vertex_buffer_descriptor(
|
||||
mut self,
|
||||
mut vertex_buffer_descriptor: VertexBufferDescriptor,
|
||||
) -> Self {
|
||||
let mut offset = 0;
|
||||
for attribute in vertex_buffer_descriptor.attributes.iter_mut() {
|
||||
offset += attribute.offset;
|
||||
attribute.offset += self.vertex_buffer_descriptor_offset;
|
||||
}
|
||||
|
||||
self.vertex_buffer_descriptor_offset += offset;
|
||||
|
||||
self.pipeline
|
||||
.vertex_buffer_descriptors
|
||||
.push(vertex_buffer_descriptor);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -175,7 +149,10 @@ impl PipelineBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn with_rasterization_state(mut self, rasterization_state: wgpu::RasterizationStateDescriptor) -> Self {
|
||||
pub fn with_rasterization_state(
|
||||
mut self,
|
||||
rasterization_state: wgpu::RasterizationStateDescriptor,
|
||||
) -> Self {
|
||||
self.pipeline.rasterization_state = Some(rasterization_state);
|
||||
self
|
||||
}
|
||||
|
|
98
src/render/render_graph_2/render_graph.rs
Normal file
98
src/render/render_graph_2/render_graph.rs
Normal file
|
@ -0,0 +1,98 @@
|
|||
use crate::render::render_graph_2::{PassDescriptor, PipelineDescriptor};
|
||||
use std::collections::HashMap;
|
||||
|
||||
// holds on to passes, pipeline descriptions, instances
|
||||
// passes: shadow, forward
|
||||
pub struct RenderGraph {
|
||||
pub pipeline_descriptors: HashMap<String, PipelineDescriptor>,
|
||||
pub pass_descriptors: HashMap<String, PassDescriptor>,
|
||||
pub pass_pipelines: HashMap<String, Vec<String>>,
|
||||
}
|
||||
|
||||
impl Default for RenderGraph {
|
||||
fn default() -> Self {
|
||||
RenderGraph {
|
||||
pipeline_descriptors: HashMap::new(),
|
||||
pass_descriptors: HashMap::new(),
|
||||
pass_pipelines: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderGraph {
|
||||
pub fn build() -> RenderGraphBuilder {
|
||||
RenderGraphBuilder {
|
||||
render_graph: RenderGraph::default(),
|
||||
current_pass: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RenderGraphBuilder {
|
||||
render_graph: RenderGraph,
|
||||
current_pass: Option<String>,
|
||||
}
|
||||
|
||||
impl RenderGraphBuilder {
|
||||
pub fn add_pass(mut self, name: &str, pass: PassDescriptor) -> Self {
|
||||
self.current_pass = Some(name.to_string());
|
||||
self.render_graph
|
||||
.pass_descriptors
|
||||
.insert(name.to_string(), pass);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_pipeline(mut self, name: &str, pipeline: PipelineDescriptor) -> Self {
|
||||
self.render_graph
|
||||
.pipeline_descriptors
|
||||
.insert(name.to_string(), pipeline);
|
||||
|
||||
if let Some(current_pass) = self.current_pass.as_ref() {
|
||||
if let None = self.render_graph.pass_pipelines.get(current_pass) {
|
||||
self.render_graph.pass_pipelines.insert(current_pass.to_string(), Vec::new());
|
||||
}
|
||||
|
||||
let pass_pipelines = self.render_graph.pass_pipelines.get_mut(current_pass).unwrap();
|
||||
pass_pipelines.push(name.to_string());
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> RenderGraph {
|
||||
self.render_graph
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
RenderGraph::build()
|
||||
.AddPass("forward", Pass {
|
||||
|
||||
})
|
||||
.AddPipeline(Pipeline::build()
|
||||
.with_vertex_shader("pbr.vert")
|
||||
.with_fragment_shader("pbr.frag")
|
||||
.add_vertex_layout(Vertex::get_layout()) // maybe someday reflect this using spirv-reflect
|
||||
.add_uniform_binding("camera_resource", "shader_camera") // if a uniform is not bound directly, and no uniforms are set on entity, produce an error
|
||||
.add_texture_binding("some_texture", "shader_texture") // if a uniform is not bound directly, and no uniforms are set on entity, produce an error
|
||||
.add_draw_target(MeshDrawTarget)
|
||||
.add_draw_target(InstancedMeshDrawTarget)
|
||||
)
|
||||
.AddPipeline(Pipeline::build()
|
||||
.with_vertex_shader("ui.vert")
|
||||
.with_fragment_shader("ui.frag")
|
||||
.with_vertex_layout(Vertex::get_layout())
|
||||
.with_draw_target(UiDrawTarget)
|
||||
)
|
||||
.AddPass("shadow", Pass {
|
||||
render_target: Null
|
||||
depth_target: DepthTexture (TextureView)
|
||||
})
|
||||
.AddPipeline(Pipeline::build()
|
||||
.with_vertex_shader("pbr.vert")
|
||||
.with_fragment_shader("pbr.frag")
|
||||
.with_vertex_layout(Vertex::get_layout())
|
||||
.with_draw_target(ShadowedMeshDrawTarget)
|
||||
.with_draw_target(ShadowedInstancedMeshDrawTarget)
|
||||
)
|
||||
*/
|
212
src/render/render_graph_2/renderer.rs
Normal file
212
src/render/render_graph_2/renderer.rs
Normal file
|
@ -0,0 +1,212 @@
|
|||
use crate::{
|
||||
asset::{AssetStorage, Handle, Mesh},
|
||||
legion::prelude::*,
|
||||
render::{
|
||||
render_graph_2::{PipelineDescriptor, PassDescriptor, RenderGraph, ShaderMaterials},
|
||||
Instanced,
|
||||
},
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use zerocopy::AsBytes;
|
||||
|
||||
// A set of draw calls. ex: get + draw meshes, get + draw instanced meshes, draw ui meshes, etc
|
||||
// Mesh target
|
||||
// trait DrawTarget {
|
||||
// fn draw(device: &wgpu::Device);
|
||||
// }
|
||||
pub type DrawTarget =
|
||||
fn(world: &World, render_pass: &mut dyn RenderPass);
|
||||
|
||||
pub fn mesh_draw_target(
|
||||
world: &World,
|
||||
render_pass: &mut dyn RenderPass,
|
||||
) {
|
||||
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||
let mut last_mesh_id = None;
|
||||
let mesh_query =
|
||||
<(Read<ShaderMaterials>, Read<Handle<Mesh>>)>::query().filter(!component::<Instanced>());
|
||||
for (material, mesh) in mesh_query.iter(world) {
|
||||
let current_mesh_id = mesh.id;
|
||||
|
||||
let mut should_load_mesh = last_mesh_id == None;
|
||||
if let Some(last) = last_mesh_id {
|
||||
should_load_mesh = last != current_mesh_id;
|
||||
}
|
||||
|
||||
if should_load_mesh {
|
||||
if let Some(mesh_asset) = mesh_storage.get(mesh.id) {
|
||||
// render_pass.load_mesh(mesh.id, mesh_asset);
|
||||
// render_pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0);
|
||||
// render_pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]);
|
||||
};
|
||||
}
|
||||
|
||||
if let Some(ref mesh_asset) = mesh_storage.get(mesh.id) {
|
||||
// pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]);
|
||||
// pass.draw_indexed(0..mesh_asset.indices.len() as u32, 0, 0..1);
|
||||
};
|
||||
|
||||
last_mesh_id = Some(current_mesh_id);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Renderer {
|
||||
fn resize(&mut self, world: &mut World, width: u32, height: u32);
|
||||
fn process_render_graph(&mut self, render_graph: &RenderGraph, world: &mut World);
|
||||
fn load_mesh(&mut self, asset_id: usize, mesh: &Mesh);
|
||||
}
|
||||
|
||||
pub struct WgpuRenderer {
|
||||
pub device: wgpu::Device,
|
||||
pub surface: wgpu::Surface,
|
||||
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
|
||||
pub render_pipelines: HashMap<String, wgpu::RenderPipeline>,
|
||||
pub buffers: HashMap<String, wgpu::Buffer>,
|
||||
}
|
||||
|
||||
impl WgpuRenderer {
|
||||
pub fn create_render_pipeline(
|
||||
pipeline_descriptor: &PipelineDescriptor,
|
||||
device: &wgpu::Device,
|
||||
) -> wgpu::RenderPipeline {
|
||||
let vertex_shader_module = pipeline_descriptor
|
||||
.shader_stages
|
||||
.vertex
|
||||
.create_shader_module(device);
|
||||
let fragment_shader_module = match pipeline_descriptor.shader_stages.fragment {
|
||||
Some(ref fragment_shader) => Some(fragment_shader.create_shader_module(device)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
bind_group_layouts: &[],
|
||||
});
|
||||
let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
|
||||
layout: &pipeline_layout,
|
||||
vertex_stage: wgpu::ProgrammableStageDescriptor {
|
||||
module: &vertex_shader_module,
|
||||
entry_point: &pipeline_descriptor.shader_stages.vertex.entry_point,
|
||||
},
|
||||
fragment_stage: match pipeline_descriptor.shader_stages.fragment {
|
||||
Some(ref fragment_shader) => Some(wgpu::ProgrammableStageDescriptor {
|
||||
entry_point: &fragment_shader.entry_point,
|
||||
module: fragment_shader_module.as_ref().unwrap(),
|
||||
}),
|
||||
None => None,
|
||||
},
|
||||
rasterization_state: pipeline_descriptor.rasterization_state.clone(),
|
||||
primitive_topology: pipeline_descriptor.primitive_topology,
|
||||
color_states: &pipeline_descriptor.color_states,
|
||||
depth_stencil_state: pipeline_descriptor.depth_stencil_state.clone(),
|
||||
index_format: pipeline_descriptor.index_format,
|
||||
vertex_buffers: &pipeline_descriptor
|
||||
.vertex_buffer_descriptors
|
||||
.iter()
|
||||
.map(|v| v.into())
|
||||
.collect::<Vec<wgpu::VertexBufferDescriptor>>(),
|
||||
sample_count: pipeline_descriptor.sample_count,
|
||||
sample_mask: pipeline_descriptor.sample_mask,
|
||||
alpha_to_coverage_enabled: pipeline_descriptor.alpha_to_coverage_enabled,
|
||||
};
|
||||
|
||||
device.create_render_pipeline(&render_pipeline_descriptor)
|
||||
}
|
||||
|
||||
pub fn create_render_pass<'a>(
|
||||
pass_descriptor: &PassDescriptor,
|
||||
encoder: &'a mut wgpu::CommandEncoder,
|
||||
frame: &'a wgpu::SwapChainOutput,
|
||||
) -> wgpu::RenderPass<'a> {
|
||||
// TODO: fill this in
|
||||
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
color_attachments: &[],
|
||||
depth_stencil_attachment: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderer for WgpuRenderer {
|
||||
fn resize(&mut self, world: &mut World, width: u32, height: u32) {
|
||||
let swap_chain = self
|
||||
.device
|
||||
.create_swap_chain(&self.surface, &self.swap_chain_descriptor);
|
||||
self.swap_chain_descriptor.width = width;
|
||||
self.swap_chain_descriptor.height = height;
|
||||
|
||||
// WgpuRenderer can't own swap_chain without creating lifetime ergonomics issues
|
||||
world.resources.insert(swap_chain);
|
||||
}
|
||||
|
||||
fn process_render_graph(&mut self, render_graph: &RenderGraph, world: &mut World) {
|
||||
let mut swap_chain = world.resources.get_mut::<wgpu::SwapChain>().unwrap();
|
||||
let frame = swap_chain
|
||||
.get_next_texture()
|
||||
.expect("Timeout when acquiring next swap chain texture");
|
||||
|
||||
let mut encoder = self
|
||||
.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 });
|
||||
|
||||
for (pass_name, pass_descriptor) in render_graph.pass_descriptors.iter() {
|
||||
let mut render_pass =
|
||||
WgpuRenderer::create_render_pass(pass_descriptor, &mut encoder, &frame);
|
||||
if let Some(pass_pipelines) = render_graph.pass_pipelines.get(pass_name) {
|
||||
for pass_pipeline in pass_pipelines.iter() {
|
||||
if let Some(pipeline_descriptor) =
|
||||
render_graph.pipeline_descriptors.get(pass_pipeline)
|
||||
{
|
||||
if let None = self.render_pipelines.get(pass_pipeline) {
|
||||
let render_pipeline = WgpuRenderer::create_render_pipeline(
|
||||
pipeline_descriptor,
|
||||
&self.device,
|
||||
);
|
||||
self.render_pipelines
|
||||
.insert(pass_pipeline.to_string(), render_pipeline);
|
||||
}
|
||||
|
||||
let mut render_pass = WgpuRenderPass {
|
||||
render_pass: &mut render_pass,
|
||||
renderer: &self,
|
||||
};
|
||||
for draw_target in pipeline_descriptor.draw_targets.iter() {
|
||||
draw_target(world, &mut render_pass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn load_mesh(&mut self, asset_id: usize, mesh: &Mesh) {
|
||||
if let None = mesh.vertex_buffer {
|
||||
self.buffers.insert(
|
||||
format!("meshv{}", asset_id),
|
||||
self.device
|
||||
.create_buffer_with_data(mesh.vertices.as_bytes(), wgpu::BufferUsage::VERTEX),
|
||||
);
|
||||
}
|
||||
|
||||
if let None = mesh.index_buffer {
|
||||
self.buffers.insert(
|
||||
format!("meshi{}", asset_id),
|
||||
self.device
|
||||
.create_buffer_with_data(mesh.indices.as_bytes(), wgpu::BufferUsage::INDEX),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RenderPass {
|
||||
fn set_index_buffer(&mut self, buffer: &wgpu::Buffer, offset: wgpu::BufferAddress);
|
||||
}
|
||||
|
||||
pub struct WgpuRenderPass<'a, 'b, 'c> {
|
||||
pub render_pass: &'b mut wgpu::RenderPass<'a>,
|
||||
pub renderer: &'c WgpuRenderer,
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c> RenderPass for WgpuRenderPass<'a, 'b, 'c> {
|
||||
fn set_index_buffer(&mut self, buffer: &wgpu::Buffer, offset: wgpu::BufferAddress) {
|
||||
self.render_pass.set_index_buffer(buffer, offset);
|
||||
}
|
||||
}
|
66
src/render/render_graph_2/shader.rs
Normal file
66
src/render/render_graph_2/shader.rs
Normal file
|
@ -0,0 +1,66 @@
|
|||
use crate::prelude::*;
|
||||
use crate::{asset::Texture, legion::{prelude::{Entity, World}, borrow::{Ref, RefMap}}, render::Albedo};
|
||||
|
||||
|
||||
pub enum ShaderValue<'a> {
|
||||
Int(u32),
|
||||
Float(f32),
|
||||
Vec4(Vec4),
|
||||
Texture(&'a Handle<Texture>),
|
||||
}
|
||||
|
||||
pub type ShaderMaterialSelector = fn(Entity, &World) -> Option<RefMap<&dyn ShaderMaterial>>;
|
||||
pub struct ShaderMaterials {
|
||||
// used for distinguishing
|
||||
pub materials: Vec<ShaderMaterialSelector>
|
||||
}
|
||||
|
||||
impl<'a> ShaderMaterials {
|
||||
pub fn new() -> Self {
|
||||
ShaderMaterials {
|
||||
materials: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, selector: ShaderMaterialSelector) {
|
||||
self.materials.push(selector);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ShaderMaterial {
|
||||
fn iter_properties(&self) -> std::slice::Iter<&'static str> ;
|
||||
fn get_property(&self, name: &str) -> Option<ShaderValue>;
|
||||
fn get_selector(&self) -> ShaderMaterialSelector;
|
||||
}
|
||||
|
||||
pub struct StandardMaterial {
|
||||
pub albedo: Albedo
|
||||
}
|
||||
|
||||
// create this from a derive macro
|
||||
const STANDARD_MATERIAL_PROPERTIES: &[&str] = &["albedo"];
|
||||
impl ShaderMaterial for StandardMaterial {
|
||||
fn iter_properties(&self) -> std::slice::Iter<&'static str> {
|
||||
STANDARD_MATERIAL_PROPERTIES.iter()
|
||||
}
|
||||
fn get_property(&self, name: &str) -> Option<ShaderValue> {
|
||||
match name {
|
||||
"albedo" => Some(match self.albedo {
|
||||
Albedo::Color(color) => ShaderValue::Vec4(color),
|
||||
Albedo::Texture(ref texture) => ShaderValue::Texture(texture)
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn get_selector(&self) -> ShaderMaterialSelector {
|
||||
|entity, world| {
|
||||
world.get_component::<Self>(entity).map(
|
||||
|c: Ref<StandardMaterial>| {
|
||||
c.map_into(|s| {
|
||||
s as &dyn ShaderMaterial
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
use std::convert::From;
|
||||
use zerocopy::{AsBytes, FromBytes};
|
||||
use crate::render::render_graph_2::VertexBufferDescriptor;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, AsBytes, FromBytes)]
|
||||
|
@ -9,6 +10,33 @@ pub struct Vertex {
|
|||
pub uv: [f32; 2],
|
||||
}
|
||||
|
||||
impl Vertex {
|
||||
// TODO: generate from macro
|
||||
pub fn get_vertex_buffer_descriptor() -> VertexBufferDescriptor {
|
||||
VertexBufferDescriptor {
|
||||
stride: std::mem::size_of::<Vertex>() as u64,
|
||||
step_mode: wgpu::InputStepMode::Vertex,
|
||||
attributes: vec![
|
||||
wgpu::VertexAttributeDescriptor {
|
||||
format: wgpu::VertexFormat::Float4,
|
||||
offset: 0,
|
||||
shader_location: 0,
|
||||
},
|
||||
wgpu::VertexAttributeDescriptor {
|
||||
format: wgpu::VertexFormat::Float4,
|
||||
offset: 4 * 4,
|
||||
shader_location: 1,
|
||||
},
|
||||
wgpu::VertexAttributeDescriptor {
|
||||
format: wgpu::VertexFormat::Float2,
|
||||
offset: 8 * 4,
|
||||
shader_location: 2,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<([f32; 4], [f32; 4], [f32; 2])> for Vertex {
|
||||
fn from((position, normal, uv): ([f32; 4], [f32; 4], [f32; 2])) -> Self {
|
||||
Vertex {
|
||||
|
|
Loading…
Reference in a new issue