mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 20:23:28 +00:00
render graph bind groups
This commit is contained in:
parent
bcd7dae0ec
commit
a2d0d937e0
6 changed files with 161 additions and 48 deletions
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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<
|
||||
},
|
||||
}
|
|
@ -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(),
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue