 4f1d9a6315
			
		
	
	
		4f1d9a6315
		
			
		
	
	
	
	
		
			
			This is a continuation of this PR: #8062 # Objective - Reorder render schedule sets to allow data preparation when phase item order is known to support improved batching - Part of the batching/instancing etc plan from here: https://github.com/bevyengine/bevy/issues/89#issuecomment-1379249074 - The original idea came from @inodentry and proved to be a good one. Thanks! - Refactor `bevy_sprite` and `bevy_ui` to take advantage of the new ordering ## Solution - Move `Prepare` and `PrepareFlush` after `PhaseSortFlush` - Add a `PrepareAssets` set that runs in parallel with other systems and sets in the render schedule. - Put prepare_assets systems in the `PrepareAssets` set - If explicit dependencies are needed on Mesh or Material RenderAssets then depend on the appropriate system. - Add `ManageViews` and `ManageViewsFlush` sets between `ExtractCommands` and Queue - Move `queue_mesh*_bind_group` to the Prepare stage - Rename them to `prepare_` - Put systems that prepare resources (buffers, textures, etc.) into a `PrepareResources` set inside `Prepare` - Put the `prepare_..._bind_group` systems into a `PrepareBindGroup` set after `PrepareResources` - Move `prepare_lights` to the `ManageViews` set - `prepare_lights` creates views and this must happen before `Queue` - This system needs refactoring to stop handling all responsibilities - Gather lights, sort, and create shadow map views. Store sorted light entities in a resource - Remove `BatchedPhaseItem` - Replace `batch_range` with `batch_size` representing how many items to skip after rendering the item or to skip the item entirely if `batch_size` is 0. - `queue_sprites` has been split into `queue_sprites` for queueing phase items and `prepare_sprites` for batching after the `PhaseSort` - `PhaseItem`s are still inserted in `queue_sprites` - After sorting adjacent compatible sprite phase items are accumulated into `SpriteBatch` components on the first entity of each batch, containing a range of vertex indices. The associated `PhaseItem`'s `batch_size` is updated appropriately. - `SpriteBatch` items are then drawn skipping over the other items in the batch based on the value in `batch_size` - A very similar refactor was performed on `bevy_ui` --- ## Changelog Changed: - Reordered and reworked render app schedule sets. The main change is that data is extracted, queued, sorted, and then prepared when the order of data is known. - Refactor `bevy_sprite` and `bevy_ui` to take advantage of the reordering. ## Migration Guide - Assets such as materials and meshes should now be created in `PrepareAssets` e.g. `prepare_assets<Mesh>` - Queueing entities to `RenderPhase`s continues to be done in `Queue` e.g. `queue_sprites` - Preparing resources (textures, buffers, etc.) should now be done in `PrepareResources`, e.g. `prepare_prepass_textures`, `prepare_mesh_uniforms` - Prepare bind groups should now be done in `PrepareBindGroups` e.g. `prepare_mesh_bind_group` - Any batching or instancing can now be done in `Prepare` where the order of the phase items is known e.g. `prepare_sprites` ## Next Steps - Introduce some generic mechanism to ensure items that can be batched are grouped in the phase item order, currently you could easily have `[sprite at z 0, mesh at z 0, sprite at z 0]` preventing batching. - Investigate improved orderings for building the MeshUniform buffer - Implementing batching across the rest of bevy --------- Co-authored-by: Robert Swain <robert.swain@gmail.com> Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
		
			
				
	
	
		
			60 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			60 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use crate::{
 | |
|     render_resource::{GpuArrayBuffer, GpuArrayBufferable},
 | |
|     renderer::{RenderDevice, RenderQueue},
 | |
|     Render, RenderApp, RenderSet,
 | |
| };
 | |
| use bevy_app::{App, Plugin};
 | |
| use bevy_ecs::{
 | |
|     prelude::{Component, Entity},
 | |
|     schedule::IntoSystemConfigs,
 | |
|     system::{Commands, Query, Res, ResMut},
 | |
| };
 | |
| use std::marker::PhantomData;
 | |
| 
 | |
| /// This plugin prepares the components of the corresponding type for the GPU
 | |
| /// by storing them in a [`GpuArrayBuffer`].
 | |
| pub struct GpuComponentArrayBufferPlugin<C: Component + GpuArrayBufferable>(PhantomData<C>);
 | |
| 
 | |
| impl<C: Component + GpuArrayBufferable> Plugin for GpuComponentArrayBufferPlugin<C> {
 | |
|     fn build(&self, app: &mut App) {
 | |
|         if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
 | |
|             render_app.add_systems(
 | |
|                 Render,
 | |
|                 prepare_gpu_component_array_buffers::<C>.in_set(RenderSet::PrepareResources),
 | |
|             );
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     fn finish(&self, app: &mut App) {
 | |
|         if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
 | |
|             render_app.insert_resource(GpuArrayBuffer::<C>::new(
 | |
|                 render_app.world.resource::<RenderDevice>(),
 | |
|             ));
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<C: Component + GpuArrayBufferable> Default for GpuComponentArrayBufferPlugin<C> {
 | |
|     fn default() -> Self {
 | |
|         Self(PhantomData::<C>)
 | |
|     }
 | |
| }
 | |
| 
 | |
| fn prepare_gpu_component_array_buffers<C: Component + GpuArrayBufferable>(
 | |
|     mut commands: Commands,
 | |
|     render_device: Res<RenderDevice>,
 | |
|     render_queue: Res<RenderQueue>,
 | |
|     mut gpu_array_buffer: ResMut<GpuArrayBuffer<C>>,
 | |
|     components: Query<(Entity, &C)>,
 | |
| ) {
 | |
|     gpu_array_buffer.clear();
 | |
| 
 | |
|     let entities = components
 | |
|         .iter()
 | |
|         .map(|(entity, component)| (entity, gpu_array_buffer.push(component.clone())))
 | |
|         .collect::<Vec<_>>();
 | |
|     commands.insert_or_spawn_batch(entities);
 | |
| 
 | |
|     gpu_array_buffer.write_buffer(&render_device, &render_queue);
 | |
| }
 |