mirror of
https://github.com/bevyengine/bevy
synced 2024-12-23 11:33:06 +00:00
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>
59 lines
1.9 KiB
Rust
59 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);
|
|
}
|