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) {
// 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);
};

View file

@ -10,16 +10,19 @@ impl PipelineLayout {
}
}
#[derive(Hash)]
pub struct BindGroup {
pub bindings: Vec<Binding>
}
#[derive(Hash)]
pub struct Binding {
pub name: String,
pub bind_type: BindType,
// TODO: ADD SHADER STAGE VISIBILITY
}
#[derive(Hash)]
pub enum BindType {
Uniform {
dynamic: bool,
@ -39,11 +42,13 @@ pub enum BindType {
},
}
#[derive(Hash)]
pub struct UniformProperty {
pub name: String,
pub property_type: UniformPropertyType,
}
#[derive(Hash)]
pub enum UniformPropertyType {
// TODO: Add all types here
Int,
@ -56,7 +61,7 @@ pub enum UniformPropertyType {
Array(Box<UniformPropertyType>, usize),
}
#[derive(Copy, Clone)]
#[derive(Copy, Clone, Hash)]
pub enum TextureDimension {
D1,
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;
pub trait Renderer {
@ -7,8 +7,9 @@ pub trait Renderer {
fn process_render_graph(&mut self, render_graph: &RenderGraph, world: &mut World);
// TODO: swap out wgpu::BufferUsage for custom type
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 get_buffer_info(&self, name: &str) -> Option<&BufferInfo>;
fn get_resource_info(&self, name: &str) -> Option<&ResourceInfo>;
}
pub trait RenderPass {
@ -17,4 +18,5 @@ pub trait RenderPass {
fn set_index_buffer(&mut self, 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 setup_bind_groups(&mut self);
}

View file

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

View file

@ -7,6 +7,7 @@ use legion::prelude::*;
use zerocopy::AsBytes;
pub trait ResourceProvider {
fn initialize(&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);
}
@ -14,6 +15,10 @@ pub trait ResourceProvider {
pub struct 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 resize(&self, renderer: &mut dyn Renderer, world: &mut World, width: u32, height: u32) {
for (mut camera, local_to_world, _) in
@ -22,7 +27,7 @@ impl ResourceProvider for CameraResourceProvider {
camera.update(width, height);
let camera_matrix: [[f32; 4]; 4] =
(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(
resource_name::uniform::CAMERA,
camera_matrix.as_bytes(),

View file

@ -1,12 +1,16 @@
use crate::{
legion::prelude::*,
render::render_graph_2::{
resource_name, BindType, BufferInfo, PassDescriptor, PipelineDescriptor, RenderGraph,
resource_name, BindGroup, BindType, PassDescriptor, PipelineDescriptor, RenderGraph,
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 device: wgpu::Device,
@ -14,8 +18,11 @@ pub struct WgpuRenderer {
pub surface: Option<wgpu::Surface>,
pub swap_chain_descriptor: wgpu::SwapChainDescriptor,
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 resource_info: HashMap<String, ResourceInfo>,
pub bind_groups: HashMap<u64, wgpu::BindGroup>,
pub bind_group_layouts: HashMap<u64, wgpu::BindGroupLayout>,
}
impl WgpuRenderer {
@ -51,11 +58,15 @@ impl WgpuRenderer {
render_pipelines: HashMap::new(),
buffers: HashMap::new(),
textures: HashMap::new(),
resource_info: HashMap::new(),
bind_groups: HashMap::new(),
bind_group_layouts: HashMap::new(),
}
}
pub fn create_render_pipeline(
pipeline_descriptor: &PipelineDescriptor,
bind_group_layouts: &mut HashMap<u64, wgpu::BindGroupLayout>,
device: &wgpu::Device,
) -> wgpu::RenderPipeline {
let vertex_shader_module = pipeline_descriptor
@ -67,11 +78,12 @@ impl WgpuRenderer {
None => None,
};
let bind_group_layouts = pipeline_descriptor
.pipeline_layout
.bind_groups
.iter()
.map(|bind_group| {
// setup new bind group layouts
for bind_group in pipeline_descriptor.pipeline_layout.bind_groups.iter() {
let mut hasher = DefaultHasher::new();
bind_group.hash(&mut hasher);
let bind_group_id = hasher.finish();
if let None = bind_group_layouts.get(&bind_group_id) {
let bind_group_layout_binding = bind_group
.bindings
.iter()
@ -82,17 +94,32 @@ impl WgpuRenderer {
ty: (&binding.bind_type).into(),
})
.collect::<Vec<wgpu::BindGroupLayoutBinding>>();
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: bind_group_layout_binding.as_slice(),
})
let bind_group_layout =
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 {
bind_group_layouts: bind_group_layouts
.iter()
.collect::<Vec<&wgpu::BindGroupLayout>>()
.as_slice(),
bind_group_layouts: bind_group_layouts.as_slice()
});
let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
@ -198,6 +225,10 @@ impl WgpuRenderer {
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 {
@ -244,6 +275,7 @@ impl Renderer for WgpuRenderer {
if let None = self.render_pipelines.get(pass_pipeline) {
let render_pipeline = WgpuRenderer::create_render_pipeline(
pipeline_descriptor,
&mut self.bind_group_layouts,
&self.device,
);
self.render_pipelines
@ -275,25 +307,74 @@ impl Renderer for WgpuRenderer {
buffer_usage: wgpu::BufferUsage,
) {
let buffer = self.device.create_buffer_with_data(data, buffer_usage);
self.buffers.insert(
name.to_string(),
Buffer {
buffer,
buffer_info: BufferInfo {
buffer_usage,
size: data.len() as u64,
},
self.add_resource_info(
name,
ResourceInfo::Buffer {
buffer_usage,
size: data.len() as u64,
},
);
self.buffers.insert(name.to_string(), buffer);
}
fn get_buffer_info(&self, name: &str) -> Option<&BufferInfo> {
self.buffers.get(name).map(|b| &b.buffer_info)
fn get_resource_info(&self, name: &str) -> Option<&ResourceInfo> {
self.resource_info.get(name)
}
fn remove_buffer(&mut self, name: &str) {
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> {
@ -302,7 +383,7 @@ pub struct WgpuRenderPass<'a, 'b, 'c, 'd> {
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 {
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) {
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) {
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>) {
self.render_pass.draw_indexed(indices, base_vertex, instances);
fn draw_indexed(
&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,
}