Skip to main content

bevy_render/
uniform.rs

1use crate::{
2    render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType},
3    renderer::{RenderDevice, RenderQueue},
4    GpuResourceAppExt, Render, RenderApp, RenderSystems,
5};
6use bevy_app::{App, Plugin};
7use bevy_ecs::{component::Component, prelude::*};
8use core::{marker::PhantomData, ops::Deref};
9
10/// Stores the index of a uniform inside of [`ComponentUniforms`].
11#[derive(impl<C: Component> bevy_ecs::component::Component for DynamicUniformIndex<C>
    where Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::Table;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {}
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}Component)]
12pub struct DynamicUniformIndex<C: Component> {
13    index: u32,
14    marker: PhantomData<C>,
15}
16
17impl<C: Component> DynamicUniformIndex<C> {
18    #[inline]
19    pub fn index(&self) -> u32 {
20        self.index
21    }
22}
23
24/// This plugin prepares the components of the corresponding type for the GPU
25/// by transforming them into uniforms.
26///
27/// They can then be accessed from the [`ComponentUniforms`] resource.
28/// For referencing the newly created uniforms a [`DynamicUniformIndex`] is inserted
29/// for every processed entity.
30///
31/// Therefore it sets up the [`RenderSystems::Prepare`] step
32/// for the specified [`ExtractComponent`](`crate::extract_component::ExtractComponent`).
33pub struct UniformComponentPlugin<C>(PhantomData<fn() -> C>);
34
35impl<C> Default for UniformComponentPlugin<C> {
36    fn default() -> Self {
37        Self(PhantomData)
38    }
39}
40
41impl<C: Component + ShaderType + WriteInto + Clone> Plugin for UniformComponentPlugin<C> {
42    fn build(&self, app: &mut App) {
43        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
44            render_app
45                .init_gpu_resource::<ComponentUniforms<C>>()
46                .add_systems(
47                    Render,
48                    prepare_uniform_components::<C>.in_set(RenderSystems::PrepareResources),
49                );
50        }
51    }
52}
53
54/// Stores all uniforms of the component type.
55#[derive(impl<C: Component + ShaderType> bevy_ecs::component::Component for
    ComponentUniforms<C> where Self: ::core::marker::Send +
    ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::SparseSet;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {
        let resource_component_id =
            if let ::core::option::Option::Some(id) =
                    required_components.components_registrator().component_id::<ComponentUniforms<C>>()
                {
                id
            } else {
                required_components.components_registrator().register_component::<ComponentUniforms<C>>()
            };
        required_components.register_required::<bevy_ecs::resource::IsResource>(move
                ||
                bevy_ecs::resource::IsResource::new(resource_component_id));
    }
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}
impl<C: Component + ShaderType> bevy_ecs::resource::Resource for
    ComponentUniforms<C> where Self: ::core::marker::Send +
    ::core::marker::Sync + 'static {}Resource)]
56pub struct ComponentUniforms<C: Component + ShaderType> {
57    uniforms: DynamicUniformBuffer<C>,
58}
59
60impl<C: Component + ShaderType> Deref for ComponentUniforms<C> {
61    type Target = DynamicUniformBuffer<C>;
62
63    #[inline]
64    fn deref(&self) -> &Self::Target {
65        &self.uniforms
66    }
67}
68
69impl<C: Component + ShaderType> ComponentUniforms<C> {
70    #[inline]
71    pub fn uniforms(&self) -> &DynamicUniformBuffer<C> {
72        &self.uniforms
73    }
74}
75
76impl<C: Component + ShaderType> Default for ComponentUniforms<C> {
77    fn default() -> Self {
78        let mut uniforms = DynamicUniformBuffer::default();
79        uniforms.set_label(Some(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} ComponentUniforms buffer",
                core::any::type_name::<C>()))
    })format!(
80            "{} ComponentUniforms buffer",
81            core::any::type_name::<C>()
82        )));
83        Self { uniforms }
84    }
85}
86
87/// This system prepares all components of the corresponding component type.
88/// They are transformed into uniforms and stored in the [`ComponentUniforms`] resource.
89fn prepare_uniform_components<C>(
90    mut commands: Commands,
91    render_device: Res<RenderDevice>,
92    render_queue: Res<RenderQueue>,
93    mut component_uniforms: ResMut<ComponentUniforms<C>>,
94    components: Query<(Entity, &C)>,
95) where
96    C: Component + ShaderType + WriteInto + Clone,
97{
98    let components_iter = components.iter();
99    let count = components_iter.len();
100    let Some(mut writer) =
101        component_uniforms
102            .uniforms
103            .get_writer(count, &render_device, &render_queue)
104    else {
105        return;
106    };
107    let entities = components_iter
108        .map(|(entity, component)| {
109            (
110                entity,
111                DynamicUniformIndex::<C> {
112                    index: writer.write(component),
113                    marker: PhantomData,
114                },
115            )
116        })
117        .collect::<Vec<_>>();
118    commands.try_insert_batch(entities);
119}