RenderResourceSet builder pattern

This commit is contained in:
Carter Anderson 2020-06-10 15:45:33 -07:00
parent e8e3e3c20f
commit 3c3449b719
4 changed files with 126 additions and 53 deletions

View file

@ -9,7 +9,7 @@ use crate::{
use bevy_asset::{Assets, Handle}; use bevy_asset::{Assets, Handle};
use bevy_property::Properties; use bevy_property::Properties;
use legion::{ use legion::{
prelude::{Com, ComMut, Res}, prelude::{ComMut, Res},
storage::Component, storage::Component,
}; };
use std::{ops::Range, sync::Arc}; use std::{ops::Range, sync::Arc};
@ -146,17 +146,17 @@ 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: &T) { pub fn draw<T: Drawable>(&mut self, drawable: &mut T) {
drawable.draw(self); drawable.draw(self);
} }
} }
pub trait Drawable { pub trait Drawable {
fn draw(&self, draw: &mut DrawContext); fn draw(&mut self, draw: &mut DrawContext);
} }
impl Drawable for RenderPipelines { impl Drawable for RenderPipelines {
fn draw(&self, draw: &mut DrawContext) { fn draw(&mut self, draw: &mut DrawContext) {
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();
@ -209,11 +209,11 @@ pub fn draw_system<T: Drawable + Component>(
render_resource_assignments: Res<RenderResourceAssignments>, render_resource_assignments: Res<RenderResourceAssignments>,
render_resources: Res<RenderResources>, render_resources: Res<RenderResources>,
mut draw: ComMut<Draw>, mut draw: ComMut<Draw>,
drawable: Com<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(&pipelines, context, &render_resource_assignments);
draw_context.draw(drawable.as_ref()); draw_context.draw(drawable.as_mut());
} }
pub fn clear_draw_system(mut draw: ComMut<Draw>) { pub fn clear_draw_system(mut draw: ComMut<Draw>) {

View file

@ -1,6 +1,7 @@
mod buffer; mod buffer;
mod entities_waiting_for_assets; mod entities_waiting_for_assets;
mod render_resource; mod render_resource;
mod render_resource_set;
mod render_resource_assignments; mod render_resource_assignments;
mod resource_info; mod resource_info;
mod systems; mod systems;
@ -8,6 +9,7 @@ mod systems;
pub use buffer::*; pub use buffer::*;
pub use entities_waiting_for_assets::*; pub use entities_waiting_for_assets::*;
pub use render_resource::*; pub use render_resource::*;
pub use render_resource_set::*;
pub use render_resource_assignments::*; pub use render_resource_assignments::*;
pub use resource_info::*; pub use resource_info::*;
pub use systems::*; pub use systems::*;

View file

@ -1,10 +1,9 @@
use super::RenderResourceId; use super::{RenderResourceId, RenderResourceSet, RenderResourceSetId};
use crate::pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineSpecialization}; use crate::pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineSpecialization};
use std::{ use std::{
collections::{hash_map::DefaultHasher, HashMap, HashSet}, collections::{HashMap, HashSet},
hash::{Hash, Hasher}, hash::{Hash, Hasher},
ops::Range, ops::Range,
sync::Arc,
}; };
use uuid::Uuid; use uuid::Uuid;
@ -29,20 +28,6 @@ impl RenderResourceAssignment {
} }
} }
#[derive(Eq, PartialEq, Debug)]
pub struct IndexedRenderResourceAssignment {
pub index: u32,
pub assignment: RenderResourceAssignment,
}
// TODO: consider renaming this to BindGroup for parity with renderer terminology
#[derive(Eq, PartialEq, Debug)]
pub struct RenderResourceSet {
pub id: RenderResourceSetId,
pub indexed_assignments: Vec<IndexedRenderResourceAssignment>,
pub dynamic_uniform_indices: Option<Arc<Vec<u32>>>,
}
#[derive(Eq, PartialEq, Debug)] #[derive(Eq, PartialEq, Debug)]
pub enum RenderResourceSetStatus { pub enum RenderResourceSetStatus {
Changed(RenderResourceSetId), Changed(RenderResourceSetId),
@ -103,7 +88,7 @@ impl RenderResourceAssignments {
&mut self, &mut self,
bind_group_descriptor: &BindGroupDescriptor, bind_group_descriptor: &BindGroupDescriptor,
) -> RenderResourceSetStatus { ) -> RenderResourceSetStatus {
let resource_set = self.generate_render_resource_set(bind_group_descriptor); let resource_set = self.build_render_resource_set(bind_group_descriptor);
if let Some(resource_set) = resource_set { if let Some(resource_set) = resource_set {
let id = resource_set.id; let id = resource_set.id;
self.render_resource_sets.insert(id, resource_set); self.render_resource_sets.insert(id, resource_set);
@ -149,42 +134,21 @@ impl RenderResourceAssignments {
}) })
} }
fn generate_render_resource_set( fn build_render_resource_set(
&self, &self,
bind_group_descriptor: &BindGroupDescriptor, bind_group_descriptor: &BindGroupDescriptor,
) -> Option<RenderResourceSet> { ) -> Option<RenderResourceSet> {
let mut hasher = DefaultHasher::new(); let mut render_resource_set_builder = RenderResourceSet::build();
let mut indices = Vec::new();
let mut indexed_assignments = Vec::new();
for binding_descriptor in bind_group_descriptor.bindings.iter() { for binding_descriptor in bind_group_descriptor.bindings.iter() {
if let Some(assignment) = self.get(&binding_descriptor.name) { if let Some(assignment) = self.get(&binding_descriptor.name) {
indexed_assignments.push(IndexedRenderResourceAssignment { render_resource_set_builder = render_resource_set_builder
assignment: assignment.clone(), .add_assignment(binding_descriptor.index, assignment.clone());
index: binding_descriptor.index,
});
let resource = assignment.get_resource();
resource.hash(&mut hasher);
if let RenderResourceAssignment::Buffer {
dynamic_index: Some(index),
..
} = assignment
{
indices.push(*index);
}
} else { } else {
return None; return None;
} }
} }
Some(RenderResourceSet { Some(render_resource_set_builder.finish())
id: RenderResourceSetId(hasher.finish()),
indexed_assignments,
dynamic_uniform_indices: if indices.is_empty() {
None
} else {
Some(Arc::new(indices))
},
})
} }
} }
@ -197,9 +161,6 @@ impl Default for RenderResourceAssignmentsId {
} }
} }
#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)]
pub struct RenderResourceSetId(u64);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -0,0 +1,110 @@
use super::{RenderResourceAssignment, RenderResourceId};
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
ops::Range,
sync::Arc,
};
#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)]
pub struct RenderResourceSetId(pub u64);
#[derive(Eq, PartialEq, Debug)]
pub struct IndexedRenderResourceAssignment {
pub index: u32,
pub assignment: RenderResourceAssignment,
}
// TODO: consider renaming this to BindGroup for parity with renderer terminology
#[derive(Eq, PartialEq, Debug)]
pub struct RenderResourceSet {
pub id: RenderResourceSetId,
pub indexed_assignments: Vec<IndexedRenderResourceAssignment>,
pub dynamic_uniform_indices: Option<Arc<Vec<u32>>>,
}
impl RenderResourceSet {
pub fn build() -> RenderResourceSetBuilder {
RenderResourceSetBuilder::default()
}
}
#[derive(Default)]
pub struct RenderResourceSetBuilder {
pub indexed_assignments: Vec<IndexedRenderResourceAssignment>,
pub dynamic_uniform_indices: Vec<u32>,
pub hasher: DefaultHasher,
}
impl RenderResourceSetBuilder {
pub fn add_assignment(mut self, index: u32, assignment: RenderResourceAssignment) -> Self {
if let RenderResourceAssignment::Buffer {
dynamic_index: Some(dynamic_index),
..
} = assignment
{
self.dynamic_uniform_indices.push(dynamic_index);
}
let resource = assignment.get_resource();
resource.hash(&mut self.hasher);
self.indexed_assignments
.push(IndexedRenderResourceAssignment { index, assignment });
self
}
pub fn add_texture(self, index: u32, render_resource: RenderResourceId) -> Self {
self.add_assignment(index, RenderResourceAssignment::Texture(render_resource))
}
pub fn add_sampler(self, index: u32, render_resource: RenderResourceId) -> Self {
self.add_assignment(index, RenderResourceAssignment::Sampler(render_resource))
}
pub fn add_buffer(
self,
index: u32,
render_resource: RenderResourceId,
range: Range<u64>,
) -> Self {
self.add_assignment(
index,
RenderResourceAssignment::Buffer {
resource: render_resource,
range,
dynamic_index: None,
},
)
}
pub fn add_dynamic_buffer(
self,
index: u32,
render_resource: RenderResourceId,
range: Range<u64>,
dynamic_index: u32,
) -> Self {
self.add_assignment(
index,
RenderResourceAssignment::Buffer {
resource: render_resource,
range,
dynamic_index: Some(dynamic_index),
},
)
}
pub fn finish(mut self) -> RenderResourceSet {
// this sort ensures that RenderResourceSets are insertion-order independent
self.indexed_assignments.sort_by_key(|i| i.index);
RenderResourceSet {
id: RenderResourceSetId(self.hasher.finish()),
indexed_assignments: self.indexed_assignments,
dynamic_uniform_indices: if self.dynamic_uniform_indices.is_empty() {
None
} else {
Some(Arc::new(self.dynamic_uniform_indices))
},
}
}
}