render graph bind groups

This commit is contained in:
Carter Anderson 2020-01-25 16:33:26 -08:00
parent bcd7dae0ec
commit a2d0d937e0
6 changed files with 161 additions and 48 deletions

View File

@ -40,7 +40,7 @@ pub fn mesh_draw_target(world: &World, render_pass: &mut dyn RenderPass) {
} }
if let Some(mesh_asset) = mesh_storage.get(mesh.id) { if let Some(mesh_asset) = mesh_storage.get(mesh.id) {
// pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]); render_pass.setup_bind_groups();
render_pass.draw_indexed(0..mesh_asset.indices.len() as u32, 0, 0..1); render_pass.draw_indexed(0..mesh_asset.indices.len() as u32, 0, 0..1);
}; };

View File

@ -10,16 +10,19 @@ impl PipelineLayout {
} }
} }
#[derive(Hash)]
pub struct BindGroup { pub struct BindGroup {
pub bindings: Vec<Binding> pub bindings: Vec<Binding>
} }
#[derive(Hash)]
pub struct Binding { pub struct Binding {
pub name: String, pub name: String,
pub bind_type: BindType, pub bind_type: BindType,
// TODO: ADD SHADER STAGE VISIBILITY // TODO: ADD SHADER STAGE VISIBILITY
} }
#[derive(Hash)]
pub enum BindType { pub enum BindType {
Uniform { Uniform {
dynamic: bool, dynamic: bool,
@ -39,11 +42,13 @@ pub enum BindType {
}, },
} }
#[derive(Hash)]
pub struct UniformProperty { pub struct UniformProperty {
pub name: String, pub name: String,
pub property_type: UniformPropertyType, pub property_type: UniformPropertyType,
} }
#[derive(Hash)]
pub enum UniformPropertyType { pub enum UniformPropertyType {
// TODO: Add all types here // TODO: Add all types here
Int, Int,
@ -56,7 +61,7 @@ pub enum UniformPropertyType {
Array(Box<UniformPropertyType>, usize), Array(Box<UniformPropertyType>, usize),
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone, Hash)]
pub enum TextureDimension { pub enum TextureDimension {
D1, D1,
D2, D2,

View File

@ -1,4 +1,4 @@
use crate::{legion::prelude::*, render::render_graph_2::{RenderGraph, BufferInfo, PipelineDescriptor}}; use crate::{legion::prelude::*, render::render_graph_2::{RenderGraph, ResourceInfo, PipelineDescriptor, BindGroup}};
use std::ops::Range; use std::ops::Range;
pub trait Renderer { pub trait Renderer {
@ -7,8 +7,9 @@ pub trait Renderer {
fn process_render_graph(&mut self, render_graph: &RenderGraph, world: &mut World); fn process_render_graph(&mut self, render_graph: &RenderGraph, world: &mut World);
// TODO: swap out wgpu::BufferUsage for custom type // TODO: swap out wgpu::BufferUsage for custom type
fn create_buffer_with_data(&mut self, name: &str, data: &[u8], buffer_usage: wgpu::BufferUsage); fn create_buffer_with_data(&mut self, name: &str, data: &[u8], buffer_usage: wgpu::BufferUsage);
fn setup_bind_group(&mut self, bind_group: &BindGroup) -> u64;
fn remove_buffer(&mut self, name: &str); fn remove_buffer(&mut self, name: &str);
fn get_buffer_info(&self, name: &str) -> Option<&BufferInfo>; fn get_resource_info(&self, name: &str) -> Option<&ResourceInfo>;
} }
pub trait RenderPass { pub trait RenderPass {
@ -17,4 +18,5 @@ pub trait RenderPass {
fn set_index_buffer(&mut self, name: &str, offset: u64); fn set_index_buffer(&mut self, name: &str, offset: u64);
fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64); fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64);
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>); fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
fn setup_bind_groups(&mut self);
} }

View File

@ -1,7 +1,7 @@
// pub type ResourceId = u64; pub enum ResourceInfo {
Buffer {
pub struct BufferInfo { size: u64,
pub size: u64, buffer_usage: wgpu::BufferUsage,
pub buffer_usage: wgpu::BufferUsage, // pub layout: Option<
// pub layout: Option< },
} }

View File

@ -7,6 +7,7 @@ use legion::prelude::*;
use zerocopy::AsBytes; use zerocopy::AsBytes;
pub trait ResourceProvider { pub trait ResourceProvider {
fn initialize(&self, renderer: &mut dyn Renderer, world: &mut World);
fn update(&self, renderer: &mut dyn Renderer, world: &mut World); fn update(&self, renderer: &mut dyn Renderer, world: &mut World);
fn resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32); fn resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32);
} }
@ -14,6 +15,10 @@ pub trait ResourceProvider {
pub struct CameraResourceProvider; pub struct CameraResourceProvider;
impl ResourceProvider for CameraResourceProvider { impl ResourceProvider for CameraResourceProvider {
fn initialize(&self, renderer: &mut dyn Renderer, world: &mut World) {
// TODO: create real buffer here
}
fn update(&self, _renderer: &mut dyn Renderer, _world: &mut World) {} fn update(&self, _renderer: &mut dyn Renderer, _world: &mut World) {}
fn resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32) { fn resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32) {
for (mut camera, local_to_world, _) in for (mut camera, local_to_world, _) in
@ -22,7 +27,7 @@ impl ResourceProvider for CameraResourceProvider {
camera.update(width, height); camera.update(width, height);
let camera_matrix: [[f32; 4]; 4] = let camera_matrix: [[f32; 4]; 4] =
(camera.view_matrix * local_to_world.0).to_cols_array_2d(); (camera.view_matrix * local_to_world.0).to_cols_array_2d();
// TODO: use staging buffer? // TODO: use staging buffer here
renderer.create_buffer_with_data( renderer.create_buffer_with_data(
resource_name::uniform::CAMERA, resource_name::uniform::CAMERA,
camera_matrix.as_bytes(), camera_matrix.as_bytes(),

View File

@ -1,12 +1,16 @@
use crate::{ use crate::{
legion::prelude::*, legion::prelude::*,
render::render_graph_2::{ render::render_graph_2::{
resource_name, BindType, BufferInfo, PassDescriptor, PipelineDescriptor, RenderGraph, resource_name, BindGroup, BindType, PassDescriptor, PipelineDescriptor, RenderGraph,
RenderPass, RenderPassColorAttachmentDescriptor, RenderPass, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor, Renderer, TextureDimension, RenderPassDepthStencilAttachmentDescriptor, Renderer, ResourceInfo, TextureDimension,
}, },
}; };
use std::{collections::HashMap, ops::Deref}; use std::{
collections::{hash_map::DefaultHasher, HashMap},
hash::{Hash, Hasher},
ops::Deref,
};
pub struct WgpuRenderer { pub struct WgpuRenderer {
pub device: wgpu::Device, pub device: wgpu::Device,
@ -14,8 +18,11 @@ pub struct WgpuRenderer {
pub surface: Option<wgpu::Surface>, pub surface: Option<wgpu::Surface>,
pub swap_chain_descriptor: wgpu::SwapChainDescriptor, pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
pub render_pipelines: HashMap<String, wgpu::RenderPipeline>, pub render_pipelines: HashMap<String, wgpu::RenderPipeline>,
pub buffers: HashMap<String, Buffer<wgpu::Buffer>>, pub buffers: HashMap<String, wgpu::Buffer>,
pub textures: HashMap<String, wgpu::TextureView>, pub textures: HashMap<String, wgpu::TextureView>,
pub resource_info: HashMap<String, ResourceInfo>,
pub bind_groups: HashMap<u64, wgpu::BindGroup>,
pub bind_group_layouts: HashMap<u64, wgpu::BindGroupLayout>,
} }
impl WgpuRenderer { impl WgpuRenderer {
@ -51,11 +58,15 @@ impl WgpuRenderer {
render_pipelines: HashMap::new(), render_pipelines: HashMap::new(),
buffers: HashMap::new(), buffers: HashMap::new(),
textures: HashMap::new(), textures: HashMap::new(),
resource_info: HashMap::new(),
bind_groups: HashMap::new(),
bind_group_layouts: HashMap::new(),
} }
} }
pub fn create_render_pipeline( pub fn create_render_pipeline(
pipeline_descriptor: &PipelineDescriptor, pipeline_descriptor: &PipelineDescriptor,
bind_group_layouts: &mut HashMap<u64, wgpu::BindGroupLayout>,
device: &wgpu::Device, device: &wgpu::Device,
) -> wgpu::RenderPipeline { ) -> wgpu::RenderPipeline {
let vertex_shader_module = pipeline_descriptor let vertex_shader_module = pipeline_descriptor
@ -67,11 +78,12 @@ impl WgpuRenderer {
None => None, None => None,
}; };
let bind_group_layouts = pipeline_descriptor // setup new bind group layouts
.pipeline_layout for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter() {
.bind_groups let mut hasher = DefaultHasher::new();
.iter() bind_group.hash(&mut hasher);
.map(|bind_group| { let bind_group_id = hasher.finish();
if let None = bind_group_layouts.get(&bind_group_id) {
let bind_group_layout_binding = bind_group let bind_group_layout_binding = bind_group
.bindings .bindings
.iter() .iter()
@ -82,17 +94,32 @@ impl WgpuRenderer {
ty: (&binding.bind_type).into(), ty: (&binding.bind_type).into(),
}) })
.collect::<Vec<wgpu::BindGroupLayoutBinding>>(); .collect::<Vec<wgpu::BindGroupLayoutBinding>>();
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { let bind_group_layout =
bindings: bind_group_layout_binding.as_slice(), device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
}) bindings: bind_group_layout_binding.as_slice(),
});
bind_group_layouts.insert(bind_group_id, bind_group_layout);
}
}
// collect bind group layout references
let bind_group_layouts = pipeline_descriptor
.pipeline_layout
.bind_groups
.iter()
.map(|bind_group| {
let mut hasher = DefaultHasher::new();
bind_group.hash(&mut hasher);
let bind_group_id = hasher.finish();
bind_group_layouts.get(&bind_group_id).unwrap()
}) })
.collect::<Vec<wgpu::BindGroupLayout>>(); .collect::<Vec<&wgpu::BindGroupLayout>>();
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: bind_group_layouts bind_group_layouts: bind_group_layouts.as_slice()
.iter()
.collect::<Vec<&wgpu::BindGroupLayout>>()
.as_slice(),
}); });
let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor { let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
@ -198,6 +225,10 @@ impl WgpuRenderer {
stencil_store_op: depth_stencil_attachment_descriptor.stencil_store_op, stencil_store_op: depth_stencil_attachment_descriptor.stencil_store_op,
} }
} }
fn add_resource_info(&mut self, name: &str, resource_info: ResourceInfo) {
self.resource_info.insert(name.to_string(), resource_info);
}
} }
impl Renderer for WgpuRenderer { impl Renderer for WgpuRenderer {
@ -244,6 +275,7 @@ impl Renderer for WgpuRenderer {
if let None = self.render_pipelines.get(pass_pipeline) { if let None = self.render_pipelines.get(pass_pipeline) {
let render_pipeline = WgpuRenderer::create_render_pipeline( let render_pipeline = WgpuRenderer::create_render_pipeline(
pipeline_descriptor, pipeline_descriptor,
&mut self.bind_group_layouts,
&self.device, &self.device,
); );
self.render_pipelines self.render_pipelines
@ -275,25 +307,74 @@ impl Renderer for WgpuRenderer {
buffer_usage: wgpu::BufferUsage, buffer_usage: wgpu::BufferUsage,
) { ) {
let buffer = self.device.create_buffer_with_data(data, buffer_usage); let buffer = self.device.create_buffer_with_data(data, buffer_usage);
self.buffers.insert( self.add_resource_info(
name.to_string(), name,
Buffer { ResourceInfo::Buffer {
buffer, buffer_usage,
buffer_info: BufferInfo { size: data.len() as u64,
buffer_usage,
size: data.len() as u64,
},
}, },
); );
self.buffers.insert(name.to_string(), buffer);
} }
fn get_buffer_info(&self, name: &str) -> Option<&BufferInfo> { fn get_resource_info(&self, name: &str) -> Option<&ResourceInfo> {
self.buffers.get(name).map(|b| &b.buffer_info) self.resource_info.get(name)
} }
fn remove_buffer(&mut self, name: &str) { fn remove_buffer(&mut self, name: &str) {
self.buffers.remove(name); self.buffers.remove(name);
} }
fn setup_bind_group(&mut self, bind_group: &BindGroup) -> u64 {
// TODO: cache hash result in bind_group?
let mut hasher = DefaultHasher::new();
bind_group.hash(&mut hasher);
let bind_group_id = hasher.finish();
// TODO: setup bind group layout
if let None = self.bind_groups.get(&bind_group_id) {
let bindings = bind_group
.bindings
.iter()
.enumerate()
.map(|(i, b)| wgpu::Binding {
binding: i as u32,
resource: match &b.bind_type {
BindType::Uniform {
dynamic,
properties,
} => {
let resource_info = self.resource_info.get(&b.name).unwrap();
if let ResourceInfo::Buffer { size, buffer_usage } = resource_info {
let buffer = self.buffers.get(&b.name).unwrap();
wgpu::BindingResource::Buffer {
buffer: buffer,
range: 0..*size,
}
} else {
panic!("expected a Buffer resource");
}
}
_ => panic!("unsupported bind type"),
},
})
.collect::<Vec<wgpu::Binding>>();
let bind_group_layout = self.bind_group_layouts.get(&bind_group_id).unwrap();
let bind_group_descriptor = wgpu::BindGroupDescriptor {
layout: bind_group_layout,
bindings: bindings.as_slice(),
};
let bind_group = self.device.create_bind_group(&bind_group_descriptor);
// let bind
self.bind_groups.insert(bind_group_id, bind_group);
}
bind_group_id
}
} }
pub struct WgpuRenderPass<'a, 'b, 'c, 'd> { pub struct WgpuRenderPass<'a, 'b, 'c, 'd> {
@ -302,7 +383,7 @@ pub struct WgpuRenderPass<'a, 'b, 'c, 'd> {
pub renderer: &'d mut WgpuRenderer, pub renderer: &'d mut WgpuRenderer,
} }
impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c,'d> { impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c, 'd> {
fn get_renderer(&mut self) -> &mut dyn Renderer { fn get_renderer(&mut self) -> &mut dyn Renderer {
self.renderer self.renderer
} }
@ -313,16 +394,41 @@ impl<'a, 'b, 'c, 'd> RenderPass for WgpuRenderPass<'a, 'b, 'c,'d> {
fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64) { fn set_vertex_buffer(&mut self, start_slot: u32, name: &str, offset: u64) {
let buffer = self.renderer.buffers.get(name).unwrap(); let buffer = self.renderer.buffers.get(name).unwrap();
self.render_pass.set_vertex_buffers(start_slot, &[(&buffer.buffer, offset)]); self.render_pass
.set_vertex_buffers(start_slot, &[(&buffer, offset)]);
} }
fn set_index_buffer(&mut self, name: &str, offset: u64) { fn set_index_buffer(&mut self, name: &str, offset: u64) {
let buffer = self.renderer.buffers.get(name).unwrap(); let buffer = self.renderer.buffers.get(name).unwrap();
self.render_pass.set_index_buffer(&buffer.buffer, offset); self.render_pass.set_index_buffer(&buffer, offset);
} }
fn draw_indexed(&mut self, indices: core::ops::Range<u32>, base_vertex: i32, instances: core::ops::Range<u32>) { fn draw_indexed(
self.render_pass.draw_indexed(indices, base_vertex, instances); &mut self,
indices: core::ops::Range<u32>,
base_vertex: i32,
instances: core::ops::Range<u32>,
) {
self.render_pass
.draw_indexed(indices, base_vertex, instances);
}
// TODO: maybe move setup to renderer.setup_bind_groups(&pipeline_desc);
fn setup_bind_groups(&mut self) {
for (i, bind_group) in self
.pipeline_descriptor
.pipeline_layout
.bind_groups
.iter()
.enumerate()
{
let id = self.renderer.setup_bind_group(bind_group);
self.render_pass.set_bind_group(
i as u32,
self.renderer.bind_groups.get(&id).unwrap(),
&[],
);
}
} }
} }
@ -364,8 +470,3 @@ impl From<&BindType> for wgpu::BindingType {
} }
} }
} }
pub struct Buffer<T> {
pub buffer: T,
pub buffer_info: BufferInfo,
}