From aa81ecaa1f50a3cbb543de4978364d4aa4813282 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sat, 28 Nov 2020 22:59:04 -0800 Subject: [PATCH 01/14] only update global transforms when they (or their ancestors) have changed --- .../src/transform_propagate_system.rs | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/crates/bevy_transform/src/transform_propagate_system.rs b/crates/bevy_transform/src/transform_propagate_system.rs index 05e335edbf0e6..6afe20a2368a2 100644 --- a/crates/bevy_transform/src/transform_propagate_system.rs +++ b/crates/bevy_transform/src/transform_propagate_system.rs @@ -3,22 +3,29 @@ use bevy_ecs::prelude::*; pub fn transform_propagate_system( mut root_query: Query< - (Option<&Children>, &Transform, &mut GlobalTransform), + (Entity, Option<&Children>, &Transform, &mut GlobalTransform), (Without, With), >, mut transform_query: Query<(&Transform, &mut GlobalTransform), With>, + changed_transform_query: Query>, children_query: Query, (With, With)>, ) { - for (children, transform, mut global_transform) in root_query.iter_mut() { - *global_transform = GlobalTransform::from(*transform); + for (entity, children, transform, mut global_transform) in root_query.iter_mut() { + let mut changed = false; + if changed_transform_query.get(entity).is_ok() { + *global_transform = GlobalTransform::from(*transform); + changed = true; + } if let Some(children) = children { for child in children.0.iter() { propagate_recursive( &global_transform, + &changed_transform_query, &mut transform_query, &children_query, *child, + changed, ); } } @@ -27,13 +34,19 @@ pub fn transform_propagate_system( fn propagate_recursive( parent: &GlobalTransform, + changed_transform_query: &Query>, transform_query: &mut Query<(&Transform, &mut GlobalTransform), With>, children_query: &Query, (With, With)>, entity: Entity, + mut changed: bool, ) { + changed |= changed_transform_query.get(entity).is_ok(); + let global_matrix = { if let Ok((transform, mut global_transform)) = transform_query.get_mut(entity) { - *global_transform = parent.mul_transform(*transform); + if changed { + *global_transform = parent.mul_transform(*transform); + } *global_transform } else { return; @@ -42,7 +55,14 @@ fn propagate_recursive( if let Ok(Some(children)) = children_query.get(entity) { for child in children.0.iter() { - propagate_recursive(&global_matrix, transform_query, children_query, *child); + propagate_recursive( + &global_matrix, + changed_transform_query, + transform_query, + children_query, + *child, + changed, + ); } } } From 17683dc04a5282b11e58038e9e79107cd82b86fe Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sat, 28 Nov 2020 22:59:28 -0800 Subject: [PATCH 02/14] only update render resource nodes when they have changed (quality check plz) --- .../src/render_graph/nodes/render_resources_node.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs b/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs index 0235c7407240d..e18b040e18e29 100644 --- a/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs @@ -10,7 +10,7 @@ use crate::{ }; use bevy_asset::{Asset, Assets, Handle, HandleId}; -use bevy_ecs::{Commands, Entity, IntoSystem, Local, Query, Res, ResMut, Resources, System, World}; +use bevy_ecs::{Changed, Commands, Entity, IntoSystem, Local, Query, Res, ResMut, Resources, System, World}; use bevy_utils::HashMap; use renderer::{AssetRenderResourceBindings, BufferId, RenderResourceType, RenderResources}; use std::{hash::Hash, marker::PhantomData, ops::DerefMut}; @@ -421,7 +421,7 @@ impl Default for RenderResourcesNodeState { fn render_resources_node_system( mut state: Local>, render_resource_context: Res>, - mut query: Query<(Entity, &T, &Draw, &mut RenderPipelines)>, + mut query: Query<(Entity, &T, &Draw, &mut RenderPipelines), Changed>, ) { let state = state.deref_mut(); let uniform_buffer_arrays = &mut state.uniform_buffer_arrays; From 7f0e97c369912cd5f65977f9851da390c60e5890 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sat, 28 Nov 2020 23:00:01 -0800 Subject: [PATCH 03/14] only update entity mesh specialization when mesh (or mesh component) has changed --- crates/bevy_render/src/mesh/mesh.rs | 108 ++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 30 deletions(-) diff --git a/crates/bevy_render/src/mesh/mesh.rs b/crates/bevy_render/src/mesh/mesh.rs index 8536868fdab1f..3abada1dc7406 100644 --- a/crates/bevy_render/src/mesh/mesh.rs +++ b/crates/bevy_render/src/mesh/mesh.rs @@ -5,13 +5,13 @@ use crate::{ use bevy_app::prelude::{EventReader, Events}; use bevy_asset::{AssetEvent, Assets, Handle}; use bevy_core::AsBytes; -use bevy_ecs::{Local, Query, Res}; +use bevy_ecs::{Changed, Entity, Local, Mut, Query, QuerySet, Res, With}; use bevy_math::*; use bevy_reflect::TypeUuid; use std::borrow::Cow; use crate::pipeline::{InputStepMode, VertexAttributeDescriptor, VertexBufferDescriptor}; -use bevy_utils::HashMap; +use bevy_utils::{HashMap, HashSet}; pub const INDEX_BUFFER_ASSET_INDEX: u64 = 0; pub const VERTEX_ATTRIBUTE_BUFFER_ID: u64 = 10; @@ -320,9 +320,16 @@ fn remove_current_mesh_resources( remove_resource_save(render_resource_context, handle, INDEX_BUFFER_ASSET_INDEX); } +#[derive(Default)] +pub struct MeshEntities { + entities: HashSet, + waiting: HashSet, +} + #[derive(Default)] pub struct MeshResourceProviderState { mesh_event_reader: EventReader>, + mesh_entities: HashMap, MeshEntities>, } pub fn mesh_resource_provider_system( @@ -330,7 +337,10 @@ pub fn mesh_resource_provider_system( render_resource_context: Res>, meshes: Res>, mesh_events: Res>>, - mut query: Query<(&Handle, &mut RenderPipelines)>, + mut queries: QuerySet<( + Query<&mut RenderPipelines, With>>, + Query<(Entity, &Handle, &mut RenderPipelines), Changed>>, + )>, ) { let mut changed_meshes = bevy_utils::HashSet::>::default(); let render_resource_context = &**render_resource_context; @@ -383,39 +393,77 @@ pub fn mesh_resource_provider_system( )), VERTEX_ATTRIBUTE_BUFFER_ID, ); + + if let Some(mesh_entities) = state.mesh_entities.get_mut(changed_mesh_handle) { + for entity in mesh_entities.waiting.drain() { + if let Ok(render_pipelines) = queries.q0_mut().get_mut(entity) { + mesh_entities.entities.insert(entity); + update_entity_mesh( + render_resource_context, + mesh, + changed_mesh_handle, + entity, + render_pipelines, + ); + } + } + } } } // handover buffers to pipeline - for (handle, mut render_pipelines) in query.iter_mut() { + for (entity, handle, render_pipelines) in queries.q1_mut().iter_mut() { + let mesh_entities = state + .mesh_entities + .entry(handle.clone_weak()) + .or_insert_with(MeshEntities::default); if let Some(mesh) = meshes.get(handle) { - for render_pipeline in render_pipelines.pipelines.iter_mut() { - render_pipeline.specialization.primitive_topology = mesh.primitive_topology; - // TODO: don't allocate a new vertex buffer descriptor for every entity - render_pipeline.specialization.vertex_buffer_descriptor = - mesh.get_vertex_buffer_descriptor(); - render_pipeline.specialization.index_format = mesh - .indices() - .map(|i| i.into()) - .unwrap_or(IndexFormat::Uint32); - } + mesh_entities.entities.insert(entity); + mesh_entities.waiting.remove(&entity); + update_entity_mesh( + render_resource_context, + mesh, + handle, + entity, + render_pipelines, + ); + } else { + mesh_entities.waiting.insert(entity); + } + } +} - if let Some(RenderResourceId::Buffer(index_buffer_resource)) = - render_resource_context.get_asset_resource(handle, INDEX_BUFFER_ASSET_INDEX) - { - // set index buffer into binding - render_pipelines - .bindings - .set_index_buffer(index_buffer_resource); - } +fn update_entity_mesh( + render_resource_context: &dyn RenderResourceContext, + mesh: &Mesh, + handle: &Handle, + entity: Entity, + mut render_pipelines: Mut, +) { + for render_pipeline in render_pipelines.pipelines.iter_mut() { + render_pipeline.specialization.primitive_topology = mesh.primitive_topology; + // TODO: don't allocate a new vertex buffer descriptor for every entity + render_pipeline.specialization.vertex_buffer_descriptor = + mesh.get_vertex_buffer_descriptor(); + render_pipeline.specialization.index_format = mesh + .indices() + .map(|i| i.into()) + .unwrap_or(IndexFormat::Uint32); + } - if let Some(RenderResourceId::Buffer(vertex_attribute_buffer_resource)) = - render_resource_context.get_asset_resource(handle, VERTEX_ATTRIBUTE_BUFFER_ID) - { - // set index buffer into binding - render_pipelines.bindings.vertex_attribute_buffer = - Some(vertex_attribute_buffer_resource); - } - } + if let Some(RenderResourceId::Buffer(index_buffer_resource)) = + render_resource_context.get_asset_resource(handle, INDEX_BUFFER_ASSET_INDEX) + { + // set index buffer into binding + render_pipelines + .bindings + .set_index_buffer(index_buffer_resource); + } + + if let Some(RenderResourceId::Buffer(vertex_attribute_buffer_resource)) = + render_resource_context.get_asset_resource(handle, VERTEX_ATTRIBUTE_BUFFER_ID) + { + // set index buffer into binding + render_pipelines.bindings.vertex_attribute_buffer = Some(vertex_attribute_buffer_resource); } } From 73e0a8eb31b1b50576f2460de8f67bc495f593d8 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sat, 28 Nov 2020 23:04:16 -0800 Subject: [PATCH 04/14] only update sprite size when changed --- crates/bevy_sprite/src/sprite.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/crates/bevy_sprite/src/sprite.rs b/crates/bevy_sprite/src/sprite.rs index 7d63c1a5ca0c3..8d99713d02458 100644 --- a/crates/bevy_sprite/src/sprite.rs +++ b/crates/bevy_sprite/src/sprite.rs @@ -1,6 +1,6 @@ use crate::ColorMaterial; use bevy_asset::{Assets, Handle}; -use bevy_ecs::{Query, Res}; +use bevy_ecs::{Changed, Query, Res}; use bevy_math::Vec2; use bevy_reflect::{Reflect, ReflectDeserialize, TypeUuid}; use bevy_render::{renderer::RenderResources, texture::Texture}; @@ -41,7 +41,7 @@ impl Sprite { pub fn sprite_system( materials: Res>, textures: Res>, - mut query: Query<(&mut Sprite, &Handle)>, + mut query: Query<(&mut Sprite, &Handle), Changed>, ) { for (mut sprite, handle) in query.iter_mut() { match sprite.resize_mode { @@ -50,7 +50,11 @@ pub fn sprite_system( let material = materials.get(handle).unwrap(); if let Some(ref texture_handle) = material.texture { if let Some(texture) = textures.get(texture_handle) { - sprite.size = texture.size.as_vec3().truncate(); + let texture_size = texture.size.as_vec3().truncate(); + // only set sprite size if it has changed (this check prevents change detection from triggering) + if sprite.size != texture_size { + sprite.size = texture_size; + } } } } From 5bf731d3eccdaa59da3950b7ba822702d6648c20 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sun, 29 Nov 2020 13:50:38 -0800 Subject: [PATCH 05/14] remove stale bind groups --- .../headless_render_resource_context.rs | 3 + .../render_resource_bindings.rs | 10 +-- .../src/renderer/render_resource_context.rs | 1 + .../renderer/wgpu_render_resource_context.rs | 4 ++ crates/bevy_wgpu/src/wgpu_render_pass.rs | 4 ++ crates/bevy_wgpu/src/wgpu_renderer.rs | 2 +- crates/bevy_wgpu/src/wgpu_resources.rs | 66 +++++++++++++++++++ 7 files changed, 81 insertions(+), 9 deletions(-) diff --git a/crates/bevy_render/src/renderer/headless_render_resource_context.rs b/crates/bevy_render/src/renderer/headless_render_resource_context.rs index 03e3177f4c636..055b2f9a68e00 100644 --- a/crates/bevy_render/src/renderer/headless_render_resource_context.rs +++ b/crates/bevy_render/src/renderer/headless_render_resource_context.rs @@ -152,4 +152,7 @@ impl RenderResourceContext for HeadlessRenderResourceContext { fn get_specialized_shader(&self, shader: &Shader, _macros: Option<&[String]>) -> Shader { shader.clone() } + + fn remove_stale_bind_groups(&self) { + } } diff --git a/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs b/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs index a09dfe86a6cbf..d6467f95aa8ee 100644 --- a/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs +++ b/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs @@ -158,14 +158,8 @@ impl RenderResourceBindings { .expect("RenderResourceSet was just changed, so it should exist"); render_resource_context.create_bind_group(bind_group_descriptor.id, bind_group); } - // TODO: Don't re-create bind groups if they havent changed. this will require cleanup of orphan bind groups and - // removal of global context.clear_bind_groups() - // PERF: see above - BindGroupStatus::Unchanged(id) => { - let bind_group = self - .get_bind_group(id) - .expect("RenderResourceSet was just changed, so it should exist"); - render_resource_context.create_bind_group(bind_group_descriptor.id, bind_group); + BindGroupStatus::Unchanged(_id) => { + // don't re-create unchanged bind groups } BindGroupStatus::NoMatch => { // ignore unchanged / unmatched render resource sets diff --git a/crates/bevy_render/src/renderer/render_resource_context.rs b/crates/bevy_render/src/renderer/render_resource_context.rs index 3e49b0bccafa4..f398c64a6e133 100644 --- a/crates/bevy_render/src/renderer/render_resource_context.rs +++ b/crates/bevy_render/src/renderer/render_resource_context.rs @@ -62,6 +62,7 @@ pub trait RenderResourceContext: Downcast + Send + Sync + 'static { bind_group: &BindGroup, ); fn clear_bind_groups(&self); + fn remove_stale_bind_groups(&self); /// Reflects the pipeline layout from its shaders. /// /// If `bevy_conventions` is true, it will be assumed that the shader follows "bevy shader conventions". These allow diff --git a/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs b/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs index 136eaa51a064e..114752dbcc646 100644 --- a/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs +++ b/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs @@ -522,6 +522,10 @@ impl RenderResourceContext for WgpuRenderResourceContext { self.resources.bind_groups.write().clear(); } + fn remove_stale_bind_groups(&self) { + self.resources.remove_stale_bind_groups(); + } + fn get_buffer_info(&self, buffer: BufferId) -> Option { self.resources.buffer_infos.read().get(&buffer).cloned() } diff --git a/crates/bevy_wgpu/src/wgpu_render_pass.rs b/crates/bevy_wgpu/src/wgpu_render_pass.rs index ee94b0189986c..60a9139c85089 100644 --- a/crates/bevy_wgpu/src/wgpu_render_pass.rs +++ b/crates/bevy_wgpu/src/wgpu_render_pass.rs @@ -74,6 +74,10 @@ impl<'a> RenderPass for WgpuRenderPass<'a> { } else { EMPTY }; + self.wgpu_resources + .used_bind_group_sender + .send(bind_group) + .unwrap(); trace!( "set bind group {:?} {:?}: {:?}", diff --git a/crates/bevy_wgpu/src/wgpu_renderer.rs b/crates/bevy_wgpu/src/wgpu_renderer.rs index 7b39c2f5e6559..2db458901d915 100644 --- a/crates/bevy_wgpu/src/wgpu_renderer.rs +++ b/crates/bevy_wgpu/src/wgpu_renderer.rs @@ -115,6 +115,6 @@ impl WgpuRenderer { let render_resource_context = resources.get::>().unwrap(); render_resource_context.drop_all_swap_chain_textures(); - render_resource_context.clear_bind_groups(); + render_resource_context.remove_stale_bind_groups(); } } diff --git a/crates/bevy_wgpu/src/wgpu_resources.rs b/crates/bevy_wgpu/src/wgpu_resources.rs index f36f3644882a3..aa3e76c6beb37 100644 --- a/crates/bevy_wgpu/src/wgpu_resources.rs +++ b/crates/bevy_wgpu/src/wgpu_resources.rs @@ -7,6 +7,7 @@ use bevy_render::{ }; use bevy_utils::HashMap; use bevy_window::WindowId; +use crossbeam_channel::{Receiver, Sender, TryRecvError}; use parking_lot::{RwLock, RwLockReadGuard}; use std::sync::Arc; @@ -45,6 +46,7 @@ pub struct WgpuResourcesReadLock<'a> { pub render_pipelines: RwLockReadGuard<'a, HashMap, wgpu::RenderPipeline>>, pub bind_groups: RwLockReadGuard<'a, HashMap>, + pub used_bind_group_sender: Sender, } impl<'a> WgpuResourcesReadLock<'a> { @@ -55,6 +57,7 @@ impl<'a> WgpuResourcesReadLock<'a> { swap_chain_frames: &self.swap_chain_frames, render_pipelines: &self.render_pipelines, bind_groups: &self.bind_groups, + used_bind_group_sender: &self.used_bind_group_sender, } } } @@ -67,6 +70,7 @@ pub struct WgpuResourceRefs<'a> { pub swap_chain_frames: &'a HashMap, pub render_pipelines: &'a HashMap, wgpu::RenderPipeline>, pub bind_groups: &'a HashMap, + pub used_bind_group_sender: &'a Sender, } #[derive(Default, Clone, Debug)] @@ -85,6 +89,7 @@ pub struct WgpuResources { pub bind_groups: Arc>>, pub bind_group_layouts: Arc>>, pub asset_resources: Arc>>, + pub bind_group_counter: BindGroupCounter, } impl WgpuResources { @@ -95,6 +100,7 @@ impl WgpuResources { swap_chain_frames: self.swap_chain_frames.read(), render_pipelines: self.render_pipelines.read(), bind_groups: self.bind_groups.read(), + used_bind_group_sender: self.bind_group_counter.used_bind_group_sender.clone(), } } @@ -109,4 +115,64 @@ impl WgpuResources { false } } + + pub fn remove_stale_bind_groups(&self) { + let mut bind_groups = self.bind_groups.write(); + self.bind_group_counter + .remove_stale_bind_groups(&mut bind_groups); + } +} + +#[derive(Clone, Debug)] +pub struct BindGroupCounter { + pub used_bind_group_sender: Sender, + pub used_bind_group_receiver: Receiver, + pub bind_group_usage_counts: Arc>>, +} + +impl BindGroupCounter { + pub fn remove_stale_bind_groups( + &self, + bind_groups: &mut HashMap, + ) { + let mut bind_group_usage_counts = self.bind_group_usage_counts.write(); + loop { + let bind_group = match self.used_bind_group_receiver.try_recv() { + Ok(bind_group) => bind_group, + Err(TryRecvError::Empty) => break, + Err(TryRecvError::Disconnected) => panic!("used bind group channel disconnected"), + }; + + let count = bind_group_usage_counts.entry(bind_group).or_insert(0); + // free every two frames + *count = 2; + } + + for info in bind_groups.values_mut() { + info.bind_groups.retain(|id, _| { + let retain = { + // if a value hasn't been counted yet, give it two frames of leeway + let count = bind_group_usage_counts.entry(*id).or_insert(2); + *count -= 1; + *count > 0 + }; + if !retain { + bind_group_usage_counts.remove(&id); + } + + retain + }) + } + } +} + +impl Default for BindGroupCounter { + fn default() -> Self { + let (send, recv) = crossbeam_channel::unbounded(); + BindGroupCounter { + used_bind_group_sender: send, + used_bind_group_receiver: recv, + bind_group_usage_counts: Default::default(), + } + } } From b5e2afe7ee29cce96ad70ab5fbd9af7dd6fa72e3 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sun, 29 Nov 2020 14:13:21 -0800 Subject: [PATCH 06/14] fix setting size of loading sprites --- crates/bevy_sprite/src/sprite.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_sprite/src/sprite.rs b/crates/bevy_sprite/src/sprite.rs index 8d99713d02458..3fe94f51a88b3 100644 --- a/crates/bevy_sprite/src/sprite.rs +++ b/crates/bevy_sprite/src/sprite.rs @@ -41,7 +41,7 @@ impl Sprite { pub fn sprite_system( materials: Res>, textures: Res>, - mut query: Query<(&mut Sprite, &Handle), Changed>, + mut query: Query<(&mut Sprite, &Handle)>, ) { for (mut sprite, handle) in query.iter_mut() { match sprite.resize_mode { From e6932e2cdba72f858ee2aee0baaae28f143bc293 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sun, 29 Nov 2020 16:22:19 -0800 Subject: [PATCH 07/14] store unmatched render resource binding results --- .../src/renderer/render_resource/render_resource_bindings.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs b/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs index d6467f95aa8ee..336a63b6cc2b4 100644 --- a/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs +++ b/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs @@ -120,6 +120,7 @@ impl RenderResourceBindings { self.bind_group_descriptors.insert(descriptor.id, Some(id)); BindGroupStatus::Changed(id) } else { + self.bind_group_descriptors.insert(descriptor.id, None); BindGroupStatus::NoMatch } } From 3de220111e0f864a4c7974ddfad689cfff787a3c Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sun, 29 Nov 2020 17:02:28 -0800 Subject: [PATCH 08/14] reduce state changes --- .../src/render_graph/nodes/pass_node.rs | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/crates/bevy_render/src/render_graph/nodes/pass_node.rs b/crates/bevy_render/src/render_graph/nodes/pass_node.rs index d0c130d14c45f..8067997ba848f 100644 --- a/crates/bevy_render/src/render_graph/nodes/pass_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/pass_node.rs @@ -244,7 +244,9 @@ where for render_command in draw.render_commands.iter() { match render_command { RenderCommand::SetPipeline { pipeline } => { - // TODO: Filter pipelines + if draw_state.is_pipeline_set(pipeline.clone_weak()) { + continue; + } render_pass.set_pipeline(pipeline); let descriptor = pipelines.get(pipeline).unwrap(); draw_state.set_pipeline(pipeline, descriptor); @@ -290,18 +292,27 @@ where offset, slot, } => { + if draw_state.is_vertex_buffer_set(*slot, *buffer, *offset) { + continue; + } render_pass.set_vertex_buffer(*slot, *buffer, *offset); - draw_state.set_vertex_buffer(*slot, *buffer); + draw_state.set_vertex_buffer(*slot, *buffer, *offset); } RenderCommand::SetIndexBuffer { buffer, offset } => { + if draw_state.is_index_buffer_set(*buffer, *offset) { + continue; + } render_pass.set_index_buffer(*buffer, *offset); - draw_state.set_index_buffer(*buffer) + draw_state.set_index_buffer(*buffer, *offset) } RenderCommand::SetBindGroup { index, bind_group, dynamic_uniform_indices, } => { + if dynamic_uniform_indices.is_none() && draw_state.is_bind_group_set(*index, *bind_group) { + continue; + } let pipeline = pipelines.get(draw_state.pipeline.as_ref().unwrap()).unwrap(); let layout = pipeline.get_layout().unwrap(); let bind_group_descriptor = layout.get_bind_group(*index).unwrap(); @@ -329,8 +340,8 @@ where struct DrawState { pipeline: Option>, bind_groups: Vec>, - vertex_buffers: Vec>, - index_buffer: Option, + vertex_buffers: Vec>, + index_buffer: Option<(BufferId, u64)>, } impl DrawState { @@ -338,12 +349,24 @@ impl DrawState { self.bind_groups[index as usize] = Some(bind_group); } - pub fn set_vertex_buffer(&mut self, index: u32, buffer: BufferId) { - self.vertex_buffers[index as usize] = Some(buffer); + pub fn is_bind_group_set(&self, index: u32, bind_group: BindGroupId) -> bool { + self.bind_groups[index as usize] == Some(bind_group) + } + + pub fn set_vertex_buffer(&mut self, index: u32, buffer: BufferId, offset: u64) { + self.vertex_buffers[index as usize] = Some((buffer, offset)); } - pub fn set_index_buffer(&mut self, buffer: BufferId) { - self.index_buffer = Some(buffer); + pub fn is_vertex_buffer_set(&self, index: u32, buffer: BufferId, offset: u64) -> bool { + self.vertex_buffers[index as usize] == Some((buffer, offset)) + } + + pub fn set_index_buffer(&mut self, buffer: BufferId, offset: u64) { + self.index_buffer = Some((buffer, offset)); + } + + pub fn is_index_buffer_set(&self, buffer: BufferId, offset: u64) -> bool { + self.index_buffer == Some((buffer, offset)) } pub fn can_draw(&self) -> bool { @@ -355,6 +378,10 @@ impl DrawState { self.can_draw() && self.index_buffer.is_some() } + pub fn is_pipeline_set(&self, pipeline: Handle) -> bool { + self.pipeline == Some(pipeline) + } + pub fn set_pipeline( &mut self, handle: &Handle, From e9f94df5ef6d045df7574034a5df64d40fe015ce Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sun, 29 Nov 2020 17:16:30 -0800 Subject: [PATCH 09/14] cargo fmt + clippy --- crates/bevy_ecs/src/core/world_builder.rs | 12 ++++++ crates/bevy_render/src/mesh/mesh.rs | 10 +---- .../nodes/render_resources_node.rs | 4 +- .../headless_render_resource_context.rs | 3 +- crates/bevy_sprite/src/sprite.rs | 2 +- .../src/hierarchy/world_child_builder.rs | 9 +++++ .../src/transform_propagate_system.rs | 40 +++++++++++-------- 7 files changed, 50 insertions(+), 30 deletions(-) diff --git a/crates/bevy_ecs/src/core/world_builder.rs b/crates/bevy_ecs/src/core/world_builder.rs index 18c450583160c..ef99ca8a885f3 100644 --- a/crates/bevy_ecs/src/core/world_builder.rs +++ b/crates/bevy_ecs/src/core/world_builder.rs @@ -62,4 +62,16 @@ impl<'a> WorldBuilder<'a> { self.current_entity = Some(self.world.spawn(components)); self } + + pub fn current_entity(&self) -> Option { + self.current_entity + } + + pub fn for_current_entity(&mut self, f: impl FnOnce(Entity)) -> &mut Self { + let current_entity = self + .current_entity + .expect("The 'current entity' is not set. You should spawn an entity first."); + f(current_entity); + self + } } diff --git a/crates/bevy_render/src/mesh/mesh.rs b/crates/bevy_render/src/mesh/mesh.rs index 3abada1dc7406..fc3f82355d78d 100644 --- a/crates/bevy_render/src/mesh/mesh.rs +++ b/crates/bevy_render/src/mesh/mesh.rs @@ -402,7 +402,6 @@ pub fn mesh_resource_provider_system( render_resource_context, mesh, changed_mesh_handle, - entity, render_pipelines, ); } @@ -420,13 +419,7 @@ pub fn mesh_resource_provider_system( if let Some(mesh) = meshes.get(handle) { mesh_entities.entities.insert(entity); mesh_entities.waiting.remove(&entity); - update_entity_mesh( - render_resource_context, - mesh, - handle, - entity, - render_pipelines, - ); + update_entity_mesh(render_resource_context, mesh, handle, render_pipelines); } else { mesh_entities.waiting.insert(entity); } @@ -437,7 +430,6 @@ fn update_entity_mesh( render_resource_context: &dyn RenderResourceContext, mesh: &Mesh, handle: &Handle, - entity: Entity, mut render_pipelines: Mut, ) { for render_pipeline in render_pipelines.pipelines.iter_mut() { diff --git a/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs b/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs index e18b040e18e29..84800b8c3d5be 100644 --- a/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs @@ -10,7 +10,9 @@ use crate::{ }; use bevy_asset::{Asset, Assets, Handle, HandleId}; -use bevy_ecs::{Changed, Commands, Entity, IntoSystem, Local, Query, Res, ResMut, Resources, System, World}; +use bevy_ecs::{ + Changed, Commands, Entity, IntoSystem, Local, Query, Res, ResMut, Resources, System, World, +}; use bevy_utils::HashMap; use renderer::{AssetRenderResourceBindings, BufferId, RenderResourceType, RenderResources}; use std::{hash::Hash, marker::PhantomData, ops::DerefMut}; diff --git a/crates/bevy_render/src/renderer/headless_render_resource_context.rs b/crates/bevy_render/src/renderer/headless_render_resource_context.rs index 055b2f9a68e00..f1b0a08cf4a2c 100644 --- a/crates/bevy_render/src/renderer/headless_render_resource_context.rs +++ b/crates/bevy_render/src/renderer/headless_render_resource_context.rs @@ -153,6 +153,5 @@ impl RenderResourceContext for HeadlessRenderResourceContext { shader.clone() } - fn remove_stale_bind_groups(&self) { - } + fn remove_stale_bind_groups(&self) {} } diff --git a/crates/bevy_sprite/src/sprite.rs b/crates/bevy_sprite/src/sprite.rs index 3fe94f51a88b3..b5c3c836d5235 100644 --- a/crates/bevy_sprite/src/sprite.rs +++ b/crates/bevy_sprite/src/sprite.rs @@ -1,6 +1,6 @@ use crate::ColorMaterial; use bevy_asset::{Assets, Handle}; -use bevy_ecs::{Changed, Query, Res}; +use bevy_ecs::{Query, Res}; use bevy_math::Vec2; use bevy_reflect::{Reflect, ReflectDeserialize, TypeUuid}; use bevy_render::{renderer::RenderResources, texture::Texture}; diff --git a/crates/bevy_transform/src/hierarchy/world_child_builder.rs b/crates/bevy_transform/src/hierarchy/world_child_builder.rs index 8f1dc84528fe6..b2122fe135f5c 100644 --- a/crates/bevy_transform/src/hierarchy/world_child_builder.rs +++ b/crates/bevy_transform/src/hierarchy/world_child_builder.rs @@ -52,6 +52,15 @@ impl<'a, 'b> WorldChildBuilder<'a, 'b> { pub fn current_entity(&self) -> Option { self.world_builder.current_entity } + + pub fn for_current_entity(&mut self, f: impl FnOnce(Entity)) -> &mut Self { + let current_entity = self + .world_builder + .current_entity + .expect("The 'current entity' is not set. You should spawn an entity first."); + f(current_entity); + self + } } pub trait BuildWorldChildren { diff --git a/crates/bevy_transform/src/transform_propagate_system.rs b/crates/bevy_transform/src/transform_propagate_system.rs index 6afe20a2368a2..27dc9ef2be7ac 100644 --- a/crates/bevy_transform/src/transform_propagate_system.rs +++ b/crates/bevy_transform/src/transform_propagate_system.rs @@ -70,7 +70,7 @@ fn propagate_recursive( #[cfg(test)] mod test { use super::*; - use crate::hierarchy::{parent_update_system, BuildChildren}; + use crate::hierarchy::{parent_update_system, BuildChildren, BuildWorldChildren}; use bevy_ecs::{Resources, Schedule, World}; use bevy_math::Vec3; @@ -85,30 +85,36 @@ mod test { schedule.add_system_to_stage("update", transform_propagate_system); // Root entity - let parent = world.spawn(( + world.spawn(( Transform::from_translation(Vec3::new(1.0, 0.0, 0.0)), GlobalTransform::identity(), )); - let children = world - .spawn_batch(vec![ - ( - Transform::from_translation(Vec3::new(0.0, 2.0, 0.)), - Parent(parent), - GlobalTransform::identity(), - ), - ( - Transform::from_translation(Vec3::new(0.0, 0.0, 3.)), - Parent(parent), - GlobalTransform::identity(), - ), - ]) - .collect::>(); + + let mut children = Vec::new(); + world + .build() + .spawn(( + Transform::from_translation(Vec3::new(1.0, 0.0, 0.0)), + GlobalTransform::identity(), + )) + .with_children(|parent| { + parent + .spawn(( + Transform::from_translation(Vec3::new(0.0, 2.0, 0.)), + GlobalTransform::identity(), + )) + .for_current_entity(|entity| children.push(entity)) + .spawn(( + Transform::from_translation(Vec3::new(0.0, 0.0, 3.)), + GlobalTransform::identity(), + )) + .for_current_entity(|entity| children.push(entity)); + }); // we need to run the schedule two times because components need to be filled in // to resolve this problem in code, just add the correct components, or use Commands // which adds all of the components needed with the correct state (see next test) schedule.initialize(&mut world, &mut resources); schedule.run(&mut world, &mut resources); - schedule.run(&mut world, &mut resources); assert_eq!( *world.get::(children[0]).unwrap(), From e3e86d578a769028010798ca678598d6accc2c1b Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 30 Nov 2020 19:13:26 -0800 Subject: [PATCH 10/14] remove cached "NoMatch" results when new bindings are added to RenderResourceBindings --- .../src/renderer/render_resource/render_resource_bindings.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs b/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs index 336a63b6cc2b4..0ae21b65c35f0 100644 --- a/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs +++ b/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs @@ -99,6 +99,9 @@ impl RenderResourceBindings { self.dirty_bind_groups.insert(*id); } } + } else { + // unmatched bind group descriptors might now match + self.bind_group_descriptors.retain(|_, value| value.is_some()); } } From 832ad387e6a52ae4e8ebe492e5f9e73ad03e2253 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 30 Nov 2020 19:21:06 -0800 Subject: [PATCH 11/14] inline current_entity in world_builder --- crates/bevy_ecs/src/core/world_builder.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_ecs/src/core/world_builder.rs b/crates/bevy_ecs/src/core/world_builder.rs index ef99ca8a885f3..18590683a25c1 100644 --- a/crates/bevy_ecs/src/core/world_builder.rs +++ b/crates/bevy_ecs/src/core/world_builder.rs @@ -63,6 +63,7 @@ impl<'a> WorldBuilder<'a> { self } + #[inline] pub fn current_entity(&self) -> Option { self.current_entity } From 384204ed93b9dd1f973e64305c360f4e1ba72bc0 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 30 Nov 2020 20:10:27 -0800 Subject: [PATCH 12/14] try creating bind groups even when they havent changed --- .../renderer/render_resource/render_resource_bindings.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs b/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs index 0ae21b65c35f0..ed6fa78eb1c6b 100644 --- a/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs +++ b/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs @@ -162,8 +162,13 @@ impl RenderResourceBindings { .expect("RenderResourceSet was just changed, so it should exist"); render_resource_context.create_bind_group(bind_group_descriptor.id, bind_group); } - BindGroupStatus::Unchanged(_id) => { - // don't re-create unchanged bind groups + BindGroupStatus::Unchanged(id) => { + // PERF: this is only required because RenderResourceContext::remove_stale_bind_groups doesn't inform RenderResourceBindings + // when a stale bind group has been removed + let bind_group = self + .get_bind_group(id) + .expect("RenderResourceSet was just changed, so it should exist"); + render_resource_context.create_bind_group(bind_group_descriptor.id, bind_group); } BindGroupStatus::NoMatch => { // ignore unchanged / unmatched render resource sets From 99b808e80b2ae6c56b2c1e8c92de44bbb69ff810 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 30 Nov 2020 22:14:45 -0800 Subject: [PATCH 13/14] render_resources_node: update all entities when resized --- .../nodes/render_resources_node.rs | 233 ++++++++++-------- 1 file changed, 136 insertions(+), 97 deletions(-) diff --git a/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs b/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs index 84800b8c3d5be..c5eca4e6d664d 100644 --- a/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs +++ b/crates/bevy_render/src/render_graph/nodes/render_resources_node.rs @@ -11,7 +11,8 @@ use crate::{ use bevy_asset::{Asset, Assets, Handle, HandleId}; use bevy_ecs::{ - Changed, Commands, Entity, IntoSystem, Local, Query, Res, ResMut, Resources, System, World, + Changed, Commands, Entity, IntoSystem, Local, Query, QuerySet, Res, ResMut, Resources, System, + World, }; use bevy_utils::HashMap; use renderer::{AssetRenderResourceBindings, BufferId, RenderResourceType, RenderResources}; @@ -82,13 +83,14 @@ impl BufferArray { } } - pub fn resize(&mut self, render_resource_context: &dyn RenderResourceContext) { + pub fn resize(&mut self, render_resource_context: &dyn RenderResourceContext) -> bool { if self.len <= self.buffer_capacity { - return; + return false; } self.allocate_buffer(render_resource_context); // TODO: allow shrinking + true } pub fn allocate_buffer(&mut self, render_resource_context: &dyn RenderResourceContext) { @@ -191,12 +193,29 @@ where } /// Resize BufferArray buffers if they aren't large enough - fn resize_buffer_arrays(&mut self, render_resource_context: &dyn RenderResourceContext) { + fn resize_buffer_arrays( + &mut self, + render_resource_context: &dyn RenderResourceContext, + ) -> bool { + let mut resized = false; for buffer_array in self.buffer_arrays.iter_mut() { if let Some(buffer_array) = buffer_array { - buffer_array.resize(render_resource_context); + resized |= buffer_array.resize(render_resource_context); } } + + resized + } + + fn set_required_staging_buffer_size_to_max(&mut self) { + let mut new_size = 0; + for buffer_array in self.buffer_arrays.iter() { + if let Some(buffer_array) = buffer_array { + new_size += buffer_array.item_size * buffer_array.len; + } + } + + self.required_staging_buffer_size = new_size; } /// Update the staging buffer to provide enough space to copy data to target buffers. @@ -240,91 +259,83 @@ where staging_buffer: &mut [u8], ) { for (i, render_resource) in uniforms.iter().enumerate() { - match render_resource.resource_type() { - Some(RenderResourceType::Buffer) => { - let size = render_resource.buffer_byte_len().unwrap(); - let render_resource_name = uniforms.get_render_resource_name(i).unwrap(); - let aligned_size = - render_resource_context.get_aligned_uniform_size(size, false); - let buffer_array = self.buffer_arrays[i].as_mut().unwrap(); - let range = 0..aligned_size as u64; - let (target_buffer, target_offset) = if dynamic_uniforms { - let binding = buffer_array.get_binding(id).unwrap(); - let dynamic_index = if let RenderResourceBinding::Buffer { - dynamic_index: Some(dynamic_index), - .. - } = binding - { - dynamic_index - } else { - panic!("dynamic index should always be set"); - }; - render_resource_bindings.set(render_resource_name, binding); - (buffer_array.buffer.unwrap(), dynamic_index) + if let Some(RenderResourceType::Buffer) = render_resource.resource_type() { + let size = render_resource.buffer_byte_len().unwrap(); + let render_resource_name = uniforms.get_render_resource_name(i).unwrap(); + let aligned_size = render_resource_context.get_aligned_uniform_size(size, false); + let buffer_array = self.buffer_arrays[i].as_mut().unwrap(); + let range = 0..aligned_size as u64; + let (target_buffer, target_offset) = if dynamic_uniforms { + let binding = buffer_array.get_binding(id).unwrap(); + let dynamic_index = if let RenderResourceBinding::Buffer { + dynamic_index: Some(dynamic_index), + .. + } = binding + { + dynamic_index } else { - let mut matching_buffer = None; - if let Some(binding) = render_resource_bindings.get(render_resource_name) { - let buffer_id = binding.get_buffer().unwrap(); - if let Some(BufferInfo { - size: current_size, .. - }) = render_resource_context.get_buffer_info(buffer_id) - { - if aligned_size == current_size { - matching_buffer = Some(buffer_id); - } else { - render_resource_context.remove_buffer(buffer_id); - } + panic!("dynamic index should always be set"); + }; + render_resource_bindings.set(render_resource_name, binding); + (buffer_array.buffer.unwrap(), dynamic_index) + } else { + let mut matching_buffer = None; + if let Some(binding) = render_resource_bindings.get(render_resource_name) { + let buffer_id = binding.get_buffer().unwrap(); + if let Some(BufferInfo { + size: current_size, .. + }) = render_resource_context.get_buffer_info(buffer_id) + { + if aligned_size == current_size { + matching_buffer = Some(buffer_id); + } else { + render_resource_context.remove_buffer(buffer_id); } } + } - let resource = if let Some(matching_buffer) = matching_buffer { - matching_buffer - } else { - let mut usage = BufferUsage::UNIFORM; - if let Some(render_resource_hints) = - uniforms.get_render_resource_hints(i) - { - if render_resource_hints.contains(RenderResourceHints::BUFFER) { - usage = BufferUsage::STORAGE - } + let resource = if let Some(matching_buffer) = matching_buffer { + matching_buffer + } else { + let mut usage = BufferUsage::UNIFORM; + if let Some(render_resource_hints) = uniforms.get_render_resource_hints(i) { + if render_resource_hints.contains(RenderResourceHints::BUFFER) { + usage = BufferUsage::STORAGE } + } - let buffer = render_resource_context.create_buffer(BufferInfo { - size: aligned_size, - buffer_usage: BufferUsage::COPY_DST | usage, - ..Default::default() - }); - - render_resource_bindings.set( - render_resource_name, - RenderResourceBinding::Buffer { - buffer, - range, - dynamic_index: None, - }, - ); - buffer - }; - - (resource, 0) + let buffer = render_resource_context.create_buffer(BufferInfo { + size: aligned_size, + buffer_usage: BufferUsage::COPY_DST | usage, + ..Default::default() + }); + + render_resource_bindings.set( + render_resource_name, + RenderResourceBinding::Buffer { + buffer, + range, + dynamic_index: None, + }, + ); + buffer }; - render_resource.write_buffer_bytes( - &mut staging_buffer[self.current_staging_buffer_offset - ..(self.current_staging_buffer_offset + size)], - ); + (resource, 0) + }; - self.queued_buffer_writes.push(QueuedBufferWrite { - buffer: target_buffer, - target_offset: target_offset as usize, - source_offset: self.current_staging_buffer_offset, - size, - }); - self.current_staging_buffer_offset += size; - } - Some(RenderResourceType::Texture) => { /* ignore textures */ } - Some(RenderResourceType::Sampler) => { /* ignore samplers */ } - None => { /* ignore None */ } + render_resource.write_buffer_bytes( + &mut staging_buffer[self.current_staging_buffer_offset + ..(self.current_staging_buffer_offset + size)], + ); + + self.queued_buffer_writes.push(QueuedBufferWrite { + buffer: target_buffer, + target_offset: target_offset as usize, + source_offset: self.current_staging_buffer_offset, + size, + }); + self.current_staging_buffer_offset += size; } } } @@ -423,22 +434,25 @@ impl Default for RenderResourcesNodeState { fn render_resources_node_system( mut state: Local>, render_resource_context: Res>, - mut query: Query<(Entity, &T, &Draw, &mut RenderPipelines), Changed>, + mut queries: QuerySet<( + Query<(Entity, &T, &Draw, &mut RenderPipelines), Changed>, + Query<(Entity, &T, &Draw, &mut RenderPipelines)>, + )>, ) { let state = state.deref_mut(); let uniform_buffer_arrays = &mut state.uniform_buffer_arrays; let render_resource_context = &**render_resource_context; uniform_buffer_arrays.begin_update(); // initialize uniform buffer arrays using the first RenderResources - if let Some((_, first, _, _)) = query.iter_mut().next() { + if let Some((_, first, _, _)) = queries.q0_mut().iter_mut().next() { uniform_buffer_arrays.initialize(first, render_resource_context); } - for entity in query.removed::() { + for entity in queries.q0().removed::() { uniform_buffer_arrays.remove_bindings(*entity); } - for (entity, uniforms, draw, mut render_pipelines) in query.iter_mut() { + for (entity, uniforms, draw, mut render_pipelines) in queries.q0_mut().iter_mut() { if !draw.is_visible { continue; } @@ -451,7 +465,10 @@ fn render_resources_node_system( ) } - uniform_buffer_arrays.resize_buffer_arrays(render_resource_context); + let resized = uniform_buffer_arrays.resize_buffer_arrays(render_resource_context); + if resized { + uniform_buffer_arrays.set_required_staging_buffer_size_to_max() + } uniform_buffer_arrays.resize_staging_buffer(render_resource_context); if let Some(staging_buffer) = state.uniform_buffer_arrays.staging_buffer { @@ -460,19 +477,41 @@ fn render_resources_node_system( staging_buffer, 0..state.uniform_buffer_arrays.staging_buffer_size as u64, &mut |mut staging_buffer, _render_resource_context| { - for (entity, uniforms, draw, mut render_pipelines) in query.iter_mut() { - if !draw.is_visible { - continue; + // if the buffer array was resized, write all entities to the new buffer, otherwise only write changes + if resized { + for (entity, uniforms, draw, mut render_pipelines) in + queries.q1_mut().iter_mut() + { + if !draw.is_visible { + continue; + } + + state.uniform_buffer_arrays.write_uniform_buffers( + entity, + &uniforms, + state.dynamic_uniforms, + render_resource_context, + &mut render_pipelines.bindings, + &mut staging_buffer, + ); } + } else { + for (entity, uniforms, draw, mut render_pipelines) in + queries.q0_mut().iter_mut() + { + if !draw.is_visible { + continue; + } - state.uniform_buffer_arrays.write_uniform_buffers( - entity, - &uniforms, - state.dynamic_uniforms, - render_resource_context, - &mut render_pipelines.bindings, - &mut staging_buffer, - ); + state.uniform_buffer_arrays.write_uniform_buffers( + entity, + &uniforms, + state.dynamic_uniforms, + render_resource_context, + &mut render_pipelines.bindings, + &mut staging_buffer, + ); + } } }, ); From ea5f41f0b8f9c5dbf1f068a53f3ea7b0fb42cae5 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 30 Nov 2020 22:16:00 -0800 Subject: [PATCH 14/14] fmt --- .../src/renderer/render_resource/render_resource_bindings.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs b/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs index ed6fa78eb1c6b..3b8c232b2ce3e 100644 --- a/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs +++ b/crates/bevy_render/src/renderer/render_resource/render_resource_bindings.rs @@ -101,7 +101,8 @@ impl RenderResourceBindings { } } else { // unmatched bind group descriptors might now match - self.bind_group_descriptors.retain(|_, value| value.is_some()); + self.bind_group_descriptors + .retain(|_, value| value.is_some()); } } @@ -164,7 +165,7 @@ impl RenderResourceBindings { } BindGroupStatus::Unchanged(id) => { // PERF: this is only required because RenderResourceContext::remove_stale_bind_groups doesn't inform RenderResourceBindings - // when a stale bind group has been removed + // when a stale bind group has been removed let bind_group = self .get_bind_group(id) .expect("RenderResourceSet was just changed, so it should exist");