more render_graph work

This commit is contained in:
Carter Anderson 2020-01-18 14:09:53 -08:00
parent d9bd2d4f15
commit 7a386b8b46
10 changed files with 550 additions and 213 deletions

View file

@ -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();

View file

@ -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>,
}

View 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()
}

View file

@ -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>,
}

View 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,
}

View file

@ -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
}

View 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)
)
*/

View 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);
}
}

View 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
})
}
)
}
}
}

View file

@ -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 {