diff --git a/crates/bevy_render/src/draw.rs b/crates/bevy_render/src/draw.rs index dddbcf6473..d667e03159 100644 --- a/crates/bevy_render/src/draw.rs +++ b/crates/bevy_render/src/draw.rs @@ -9,7 +9,7 @@ use crate::{ use bevy_asset::{Assets, Handle}; use bevy_property::Properties; use legion::{ - prelude::{Com, ComMut, Res}, + prelude::{ComMut, Res}, storage::Component, }; use std::{ops::Range, sync::Arc}; @@ -146,17 +146,17 @@ impl<'a> DrawContext<'a> { self.draw.render_commands.push(render_command); } - pub fn draw(&mut self, drawable: &T) { + pub fn draw(&mut self, drawable: &mut T) { drawable.draw(self); } } pub trait Drawable { - fn draw(&self, draw: &mut DrawContext); + fn draw(&mut self, draw: &mut DrawContext); } 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() { let pipeline = draw.pipelines.get(pipeline_handle).unwrap(); let layout = pipeline.get_layout().unwrap(); @@ -209,11 +209,11 @@ pub fn draw_system( render_resource_assignments: Res, render_resources: Res, mut draw: ComMut, - drawable: Com, + mut drawable: ComMut, ) { let context = &*render_resources.context; 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) { diff --git a/crates/bevy_render/src/render_resource/mod.rs b/crates/bevy_render/src/render_resource/mod.rs index 9e5c9d254f..4b6b0621bc 100644 --- a/crates/bevy_render/src/render_resource/mod.rs +++ b/crates/bevy_render/src/render_resource/mod.rs @@ -1,6 +1,7 @@ mod buffer; mod entities_waiting_for_assets; mod render_resource; +mod render_resource_set; mod render_resource_assignments; mod resource_info; mod systems; @@ -8,6 +9,7 @@ mod systems; pub use buffer::*; pub use entities_waiting_for_assets::*; pub use render_resource::*; +pub use render_resource_set::*; pub use render_resource_assignments::*; pub use resource_info::*; pub use systems::*; \ No newline at end of file diff --git a/crates/bevy_render/src/render_resource/render_resource_assignments.rs b/crates/bevy_render/src/render_resource/render_resource_assignments.rs index 47c40333f3..75d3c7ae6c 100644 --- a/crates/bevy_render/src/render_resource/render_resource_assignments.rs +++ b/crates/bevy_render/src/render_resource/render_resource_assignments.rs @@ -1,10 +1,9 @@ -use super::RenderResourceId; +use super::{RenderResourceId, RenderResourceSet, RenderResourceSetId}; use crate::pipeline::{BindGroupDescriptor, BindGroupDescriptorId, PipelineSpecialization}; use std::{ - collections::{hash_map::DefaultHasher, HashMap, HashSet}, + collections::{HashMap, HashSet}, hash::{Hash, Hasher}, ops::Range, - sync::Arc, }; 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, - pub dynamic_uniform_indices: Option>>, -} - #[derive(Eq, PartialEq, Debug)] pub enum RenderResourceSetStatus { Changed(RenderResourceSetId), @@ -103,7 +88,7 @@ impl RenderResourceAssignments { &mut self, bind_group_descriptor: &BindGroupDescriptor, ) -> 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 { let id = resource_set.id; 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, bind_group_descriptor: &BindGroupDescriptor, ) -> Option { - let mut hasher = DefaultHasher::new(); - let mut indices = Vec::new(); - let mut indexed_assignments = Vec::new(); + let mut render_resource_set_builder = RenderResourceSet::build(); for binding_descriptor in bind_group_descriptor.bindings.iter() { if let Some(assignment) = self.get(&binding_descriptor.name) { - indexed_assignments.push(IndexedRenderResourceAssignment { - assignment: 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); - } + render_resource_set_builder = render_resource_set_builder + .add_assignment(binding_descriptor.index, assignment.clone()); } else { return None; } } - Some(RenderResourceSet { - id: RenderResourceSetId(hasher.finish()), - indexed_assignments, - dynamic_uniform_indices: if indices.is_empty() { - None - } else { - Some(Arc::new(indices)) - }, - }) + Some(render_resource_set_builder.finish()) } } @@ -197,9 +161,6 @@ impl Default for RenderResourceAssignmentsId { } } -#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)] -pub struct RenderResourceSetId(u64); - #[cfg(test)] mod tests { use super::*; diff --git a/crates/bevy_render/src/render_resource/render_resource_set.rs b/crates/bevy_render/src/render_resource/render_resource_set.rs new file mode 100644 index 0000000000..175c124c1b --- /dev/null +++ b/crates/bevy_render/src/render_resource/render_resource_set.rs @@ -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, + pub dynamic_uniform_indices: Option>>, +} + +impl RenderResourceSet { + pub fn build() -> RenderResourceSetBuilder { + RenderResourceSetBuilder::default() + } +} + +#[derive(Default)] +pub struct RenderResourceSetBuilder { + pub indexed_assignments: Vec, + pub dynamic_uniform_indices: Vec, + 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, + ) -> 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, + 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)) + }, + } + } +}