mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 20:53:53 +00:00
render: initial SharedBuffer
This commit is contained in:
parent
6362b2a516
commit
eed40fee9c
6 changed files with 137 additions and 13 deletions
|
@ -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>) {
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>)>,
|
||||||
|
|
58
crates/bevy_render/src/render_resource/shared_buffer.rs
Normal file
58
crates/bevy_render/src/render_resource/shared_buffer.rs
Normal 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();
|
||||||
|
}
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue