bevy_render/
gpu_component_array_buffer.rs

1use crate::{
2    render_resource::{GpuArrayBuffer, GpuArrayBufferable},
3    renderer::{RenderDevice, RenderQueue},
4    Render, RenderApp, RenderSet,
5};
6use bevy_app::{App, Plugin};
7use bevy_ecs::{
8    prelude::{Component, Entity},
9    schedule::IntoSystemConfigs,
10    system::{Commands, Query, Res, ResMut},
11};
12use core::marker::PhantomData;
13
14/// This plugin prepares the components of the corresponding type for the GPU
15/// by storing them in a [`GpuArrayBuffer`].
16pub struct GpuComponentArrayBufferPlugin<C: Component + GpuArrayBufferable>(PhantomData<C>);
17
18impl<C: Component + GpuArrayBufferable> Plugin for GpuComponentArrayBufferPlugin<C> {
19    fn build(&self, app: &mut App) {
20        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
21            render_app.add_systems(
22                Render,
23                prepare_gpu_component_array_buffers::<C>.in_set(RenderSet::PrepareResources),
24            );
25        }
26    }
27
28    fn finish(&self, app: &mut App) {
29        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
30            render_app.insert_resource(GpuArrayBuffer::<C>::new(
31                render_app.world().resource::<RenderDevice>(),
32            ));
33        }
34    }
35}
36
37impl<C: Component + GpuArrayBufferable> Default for GpuComponentArrayBufferPlugin<C> {
38    fn default() -> Self {
39        Self(PhantomData::<C>)
40    }
41}
42
43fn prepare_gpu_component_array_buffers<C: Component + GpuArrayBufferable>(
44    mut commands: Commands,
45    render_device: Res<RenderDevice>,
46    render_queue: Res<RenderQueue>,
47    mut gpu_array_buffer: ResMut<GpuArrayBuffer<C>>,
48    components: Query<(Entity, &C)>,
49) {
50    gpu_array_buffer.clear();
51
52    let entities = components
53        .iter()
54        .map(|(entity, component)| (entity, gpu_array_buffer.push(component.clone())))
55        .collect::<Vec<_>>();
56    commands.insert_or_spawn_batch(entities);
57
58    gpu_array_buffer.write_buffer(&render_device, &render_queue);
59}