render: initial SharedBuffer

This commit is contained in:
Carter Anderson 2020-06-13 18:37:02 -07:00
parent 6362b2a516
commit eed40fee9c
6 changed files with 137 additions and 13 deletions

View file

@ -1,8 +1,8 @@
use crate::{ use crate::{
pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineDescriptor}, pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineDescriptor},
render_resource::{ render_resource::{
RenderResourceAssignments, RenderResourceId, RenderResourceSet, RenderResourceSetId, BufferUsage, RenderResource, RenderResourceAssignment, RenderResourceAssignments,
ResourceInfo, RenderResourceId, RenderResourceSet, RenderResourceSetId, ResourceInfo, SharedBuffers,
}, },
renderer::{RenderResourceContext, RenderResources}, renderer::{RenderResourceContext, RenderResources},
}; };
@ -13,6 +13,7 @@ use legion::{
storage::Component, storage::Component,
}; };
use std::{ops::Range, sync::Arc}; use std::{ops::Range, sync::Arc};
use thiserror::Error;
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub enum RenderCommand { pub enum RenderCommand {
@ -83,12 +84,15 @@ impl Draw {
pipelines: &'a Assets<PipelineDescriptor>, pipelines: &'a Assets<PipelineDescriptor>,
render_resource_context: &'a dyn RenderResourceContext, render_resource_context: &'a dyn RenderResourceContext,
render_resource_assignments: &'a RenderResourceAssignments, render_resource_assignments: &'a RenderResourceAssignments,
shared_buffers: &'a SharedBuffers,
) -> DrawContext { ) -> DrawContext {
DrawContext { DrawContext {
draw: self, draw: self,
pipelines, pipelines,
render_resource_context, render_resource_context,
render_resource_assignments, render_resource_assignments,
shared_buffers,
current_pipeline: None,
} }
} }
@ -97,17 +101,59 @@ impl Draw {
} }
} }
#[derive(Debug, Error)]
pub enum DrawError {
#[error("Pipeline does not exist.")]
NonExistentPipeline,
#[error("No pipeline set")]
NoPipelineSet,
#[error("Pipeline has no layout")]
PipelineHasNoLayout,
#[error("Failed to get a buffer for the given RenderResource.")]
BufferAllocationFailure,
}
pub struct DrawContext<'a> { pub struct DrawContext<'a> {
pub draw: &'a mut Draw, pub draw: &'a mut Draw,
pub pipelines: &'a Assets<PipelineDescriptor>, pub pipelines: &'a Assets<PipelineDescriptor>,
pub render_resource_context: &'a dyn RenderResourceContext, pub render_resource_context: &'a dyn RenderResourceContext,
pub render_resource_assignments: &'a RenderResourceAssignments, pub render_resource_assignments: &'a RenderResourceAssignments,
pub shared_buffers: &'a SharedBuffers,
pub current_pipeline: Option<&'a PipelineDescriptor>,
} }
impl<'a> DrawContext<'a> { impl<'a> DrawContext<'a> {
pub fn set_pipeline(&mut self, pipeline: Handle<PipelineDescriptor>) { pub fn get_uniform_buffer<T: RenderResource>(
self.render_command(RenderCommand::SetPipeline { pipeline }); &self,
render_resource: &T,
) -> Result<RenderResourceAssignment, DrawError> {
self.get_buffer(render_resource, BufferUsage::UNIFORM)
} }
pub fn get_buffer<T: RenderResource>(
&self,
render_resource: &T,
buffer_usage: BufferUsage,
) -> Result<RenderResourceAssignment, DrawError> {
self.shared_buffers
.get_buffer(render_resource, buffer_usage)
.ok_or_else(|| DrawError::BufferAllocationFailure)
}
pub fn set_pipeline(
&mut self,
pipeline_handle: Handle<PipelineDescriptor>,
) -> Result<(), DrawError> {
let pipeline = self
.pipelines
.get(&pipeline_handle)
.ok_or_else(|| DrawError::NonExistentPipeline)?;
self.current_pipeline = Some(pipeline);
self.render_command(RenderCommand::SetPipeline {
pipeline: pipeline_handle,
});
Ok(())
}
pub fn set_vertex_buffer(&mut self, slot: u32, buffer: RenderResourceId, offset: u64) { pub fn set_vertex_buffer(&mut self, slot: u32, buffer: RenderResourceId, offset: u64) {
self.render_command(RenderCommand::SetVertexBuffer { self.render_command(RenderCommand::SetVertexBuffer {
slot, slot,
@ -146,21 +192,21 @@ impl<'a> DrawContext<'a> {
self.draw.render_commands.push(render_command); self.draw.render_commands.push(render_command);
} }
pub fn draw<T: Drawable>(&mut self, drawable: &mut T) { pub fn draw<T: Drawable>(&mut self, drawable: &mut T) -> Result<(), DrawError> {
drawable.draw(self); drawable.draw(self)
} }
} }
pub trait Drawable { pub trait Drawable {
fn draw(&mut self, draw: &mut DrawContext); fn draw(&mut self, draw: &mut DrawContext) -> Result<(), DrawError>;
} }
impl Drawable for RenderPipelines { impl Drawable for RenderPipelines {
fn draw(&mut self, draw: &mut DrawContext) { fn draw(&mut self, draw: &mut DrawContext) -> Result<(), DrawError> {
for pipeline_handle in self.compiled_pipelines.iter() { for pipeline_handle in self.compiled_pipelines.iter() {
let pipeline = draw.pipelines.get(pipeline_handle).unwrap(); let pipeline = draw.pipelines.get(pipeline_handle).unwrap();
let layout = pipeline.get_layout().unwrap(); let layout = pipeline.get_layout().unwrap();
draw.set_pipeline(*pipeline_handle); draw.set_pipeline(*pipeline_handle)?;
for bind_group in layout.bind_groups.iter() { for bind_group in layout.bind_groups.iter() {
if let Some(local_render_resource_set) = self if let Some(local_render_resource_set) = self
.render_resource_assignments .render_resource_assignments
@ -174,7 +220,6 @@ impl Drawable for RenderPipelines {
draw.set_bind_group(bind_group, global_render_resource_set); draw.set_bind_group(bind_group, global_render_resource_set);
} }
} }
let mut indices = 0..0; let mut indices = 0..0;
for (slot, vertex_buffer_descriptor) in for (slot, vertex_buffer_descriptor) in
layout.vertex_buffer_descriptors.iter().enumerate() layout.vertex_buffer_descriptors.iter().enumerate()
@ -201,6 +246,8 @@ impl Drawable for RenderPipelines {
draw.draw_indexed(indices, 0, 0..1); draw.draw_indexed(indices, 0, 0..1);
} }
Ok(())
} }
} }
@ -208,12 +255,18 @@ pub fn draw_system<T: Drawable + Component>(
pipelines: Res<Assets<PipelineDescriptor>>, pipelines: Res<Assets<PipelineDescriptor>>,
render_resource_assignments: Res<RenderResourceAssignments>, render_resource_assignments: Res<RenderResourceAssignments>,
render_resources: Res<RenderResources>, render_resources: Res<RenderResources>,
shared_buffers: Res<SharedBuffers>,
mut draw: ComMut<Draw>, mut draw: ComMut<Draw>,
mut drawable: ComMut<T>, mut drawable: ComMut<T>,
) { ) {
let context = &*render_resources.context; let context = &*render_resources.context;
let mut draw_context = draw.get_context(&pipelines, context, &render_resource_assignments); let mut draw_context = draw.get_context(
draw_context.draw(drawable.as_mut()); &pipelines,
context,
&render_resource_assignments,
&shared_buffers,
);
draw_context.draw(drawable.as_mut()).unwrap();
} }
pub fn clear_draw_system(mut draw: ComMut<Draw>) { pub fn clear_draw_system(mut draw: ComMut<Draw>) {

View file

@ -1,4 +1,5 @@
mod buffer; mod buffer;
mod shared_buffer;
mod render_resource; mod render_resource;
mod render_resource_set; mod render_resource_set;
mod render_resource_assignments; mod render_resource_assignments;
@ -6,6 +7,7 @@ mod resource_info;
mod systems; mod systems;
pub use buffer::*; pub use buffer::*;
pub use shared_buffer::*;
pub use render_resource::*; pub use render_resource::*;
pub use render_resource_set::*; pub use render_resource_set::*;
pub use render_resource_assignments::*; pub use render_resource_assignments::*;

View file

@ -95,6 +95,16 @@ impl_render_resource_bytes!(Vec2);
impl_render_resource_bytes!(Vec3); impl_render_resource_bytes!(Vec3);
impl_render_resource_bytes!(Vec4); impl_render_resource_bytes!(Vec4);
impl_render_resource_bytes!(Mat4); impl_render_resource_bytes!(Mat4);
impl_render_resource_bytes!(u8);
impl_render_resource_bytes!(u16);
impl_render_resource_bytes!(u32);
impl_render_resource_bytes!(u64);
impl_render_resource_bytes!(i8);
impl_render_resource_bytes!(i16);
impl_render_resource_bytes!(i32);
impl_render_resource_bytes!(i64);
impl_render_resource_bytes!(f32);
impl_render_resource_bytes!(f64);
impl<T> RenderResource for Vec<T> impl<T> RenderResource for Vec<T>
where where

View file

@ -59,6 +59,7 @@ pub enum RenderResourceSetStatus {
// PERF: if the assignments are scoped to a specific pipeline layout, then names could be replaced with indices here for a perf boost // PERF: if the assignments are scoped to a specific pipeline layout, then names could be replaced with indices here for a perf boost
#[derive(Eq, PartialEq, Debug, Default)] #[derive(Eq, PartialEq, Debug, Default)]
pub struct RenderResourceAssignments { pub struct RenderResourceAssignments {
// TODO: remove this. it shouldn't be needed anymore
pub id: RenderResourceAssignmentsId, pub id: RenderResourceAssignmentsId,
render_resources: HashMap<String, RenderResourceAssignment>, render_resources: HashMap<String, RenderResourceAssignment>,
vertex_buffers: HashMap<String, (RenderResourceId, Option<RenderResourceId>)>, vertex_buffers: HashMap<String, (RenderResourceId, Option<RenderResourceId>)>,

View file

@ -0,0 +1,58 @@
use super::{BufferInfo, RenderResource, RenderResourceAssignment, RenderResourceId};
use crate::{render_resource::BufferUsage, renderer::RenderResourceContext};
use legion::systems::Res;
use std::sync::{Arc, RwLock};
// TODO: Instead of allocating small "exact size" buffers each frame, this should use multiple large shared buffers and probably
// a long-living "cpu mapped" staging buffer. Im punting that for now because I don't know the best way to use wgpu's new async
// buffer mapping yet.
pub struct SharedBuffers {
render_resource_context: Box<dyn RenderResourceContext>,
buffers: Arc<RwLock<Vec<RenderResourceId>>>,
}
impl SharedBuffers {
pub fn new(render_resource_context: Box<dyn RenderResourceContext>) -> Self {
Self {
render_resource_context,
buffers: Default::default(),
}
}
pub fn get_buffer<T: RenderResource>(
&self,
render_resource: &T,
buffer_usage: BufferUsage,
) -> Option<RenderResourceAssignment> {
if let Some(size) = render_resource.buffer_byte_len() {
// PERF: this buffer will be slow
let buffer = self.render_resource_context.create_buffer_mapped(
BufferInfo { size, buffer_usage: buffer_usage | BufferUsage::COPY_SRC | BufferUsage::COPY_DST },
&mut |data, _renderer| {
render_resource.write_buffer_bytes(data);
},
);
self.buffers.write().unwrap().push(buffer);
Some(RenderResourceAssignment::Buffer {
resource: buffer,
range: 0..size as u64,
dynamic_index: None,
})
} else {
None
}
}
// TODO: remove this when this actually uses shared buffers
pub fn free_buffers(&self) {
let mut buffers = self.buffers.write().unwrap();
for buffer in buffers.drain(..) {
self.render_resource_context.remove_buffer(buffer)
}
}
}
// TODO: remove this when this actually uses shared buffers
pub fn free_shared_buffers_system(shared_buffers: Res<SharedBuffers>) {
shared_buffers.free_buffers();
}

View file

@ -12,7 +12,7 @@ use std::collections::HashSet;
pub const TEXTURE_ASSET_INDEX: usize = 0; pub const TEXTURE_ASSET_INDEX: usize = 0;
pub const SAMPLER_ASSET_INDEX: usize = 1; pub const SAMPLER_ASSET_INDEX: usize = 1;
#[derive(Default)] #[derive(Default, Clone)]
pub struct Texture { pub struct Texture {
pub data: Vec<u8>, pub data: Vec<u8>,
pub size: Vec2, pub size: Vec2,