Skip to main content

bevy_render/batching/
gpu_preprocessing.rs

1//! Batching functionality when GPU preprocessing is in use.
2
3use alloc::sync::Arc;
4use core::{
5    any::TypeId,
6    marker::PhantomData,
7    mem,
8    ops::Range,
9    sync::atomic::{AtomicU32, Ordering},
10};
11
12use bevy_app::{App, Plugin};
13use bevy_derive::{Deref, DerefMut};
14use bevy_ecs::{
15    prelude::Entity,
16    query::{Has, With},
17    resource::Resource,
18    schedule::IntoScheduleConfigs as _,
19    system::{Query, Res, ResMut, StaticSystemParam},
20    world::{FromWorld, World},
21};
22use bevy_encase_derive::ShaderType;
23use bevy_log::{error, info_once};
24use bevy_math::UVec4;
25use bevy_platform::collections::{hash_map::Entry, HashMap, HashSet};
26use bevy_tasks::ComputeTaskPool;
27use bevy_utils::{default, TypeIdHashMap};
28use bytemuck::{Pod, Zeroable};
29use encase::{internal::WriteInto, ShaderSize};
30use nonmax::NonMaxU32;
31use static_assertions::assert_eq_size;
32use wgpu::{BindingResource, BufferUsages, DownlevelFlags, Features};
33
34use crate::{
35    occlusion_culling::OcclusionCulling,
36    render_phase::{
37        BinnedPhaseItem, BinnedRenderPhaseBatch, BinnedRenderPhaseBatchSet,
38        BinnedRenderPhaseBatchSets, CachedRenderPipelinePhaseItem, PhaseItem,
39        PhaseItemBatchSetKey as _, PhaseItemExtraIndex, RenderMultidrawableBatchSet,
40        SortedPhaseItem, SortedRenderPhase, UnbatchableBinnedEntityIndices, ViewBinnedRenderPhases,
41        ViewSortedRenderPhases,
42    },
43    render_resource::{
44        AtomicPod, AtomicRawBufferVec, AtomicSparseBufferVec, Buffer, GpuArrayBufferable,
45        PartialBufferVec, PipelineCache, RawBufferVec, SparseBufferUpdateBindGroups,
46        SparseBufferUpdateJobs, SparseBufferUpdatePipelines, UninitBufferVec,
47    },
48    renderer::{RenderAdapter, RenderAdapterInfo, RenderDevice, RenderQueue},
49    sync_world::{MainEntity, MainEntityHashMap},
50    view::{ExtractedView, NoIndirectDrawing, RetainedViewEntity},
51    GpuResourceAppExt, Render, RenderApp, RenderDebugFlags, RenderSystems,
52};
53
54use super::{BatchSetMeta, GetBatchData, GetFullBatchData};
55
56#[derive(Default)]
57pub struct BatchingPlugin {
58    /// Debugging flags that can optionally be set when constructing the renderer.
59    pub debug_flags: RenderDebugFlags,
60}
61
62impl Plugin for BatchingPlugin {
63    fn build(&self, app: &mut App) {
64        let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
65            return;
66        };
67
68        render_app
69            .insert_resource(IndirectParametersBuffersSettings {
70                allow_copies_from_indirect_parameter_buffers: self
71                    .debug_flags
72                    .contains(RenderDebugFlags::ALLOW_COPIES_FROM_INDIRECT_PARAMETERS),
73            })
74            .init_gpu_resource::<IndirectParametersBuffers>()
75            .allow_ambiguous_resource::<IndirectParametersBuffers>()
76            .init_gpu_resource::<SceneUnpackingBuffers>()
77            .init_gpu_resource::<IndirectParametersBuildJobs>()
78            .init_gpu_resource::<BuildIndirectParametersMetadata>()
79            .add_systems(
80                Render,
81                write_indirect_parameters_buffers.in_set(RenderSystems::PrepareResourcesFlush),
82            )
83            .add_systems(
84                Render,
85                (
86                    prepare_indirect_parameters_build_jobs,
87                    write_indirect_parameters_build_jobs,
88                )
89                    .chain()
90                    .in_set(RenderSystems::PrepareResourcesFlush),
91            )
92            .add_systems(
93                Render,
94                clear_indirect_parameters_buffers.in_set(RenderSystems::PrepareViews),
95            );
96    }
97
98    fn finish(&self, app: &mut App) {
99        let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
100            return;
101        };
102
103        render_app.init_gpu_resource::<GpuPreprocessingSupport>();
104    }
105}
106
107/// Records whether GPU preprocessing and/or GPU culling are supported on the
108/// device.
109///
110/// No GPU preprocessing is supported on WebGL because of the lack of compute
111/// shader support.  GPU preprocessing is supported on DirectX 12, but due to [a
112/// `wgpu` limitation] GPU culling is not.
113///
114/// [a `wgpu` limitation]: https://github.com/gfx-rs/wgpu/issues/2471
115#[derive(Clone, Copy, PartialEq, Resource)]
116pub struct GpuPreprocessingSupport {
117    /// The maximum amount of GPU preprocessing available on this platform.
118    pub max_supported_mode: GpuPreprocessingMode,
119}
120
121impl GpuPreprocessingSupport {
122    /// Returns true if this GPU preprocessing support level isn't `None`.
123    #[inline]
124    pub fn is_available(&self) -> bool {
125        self.max_supported_mode != GpuPreprocessingMode::None
126    }
127
128    /// Returns the given GPU preprocessing mode, capped to the current
129    /// preprocessing mode.
130    pub fn min(&self, mode: GpuPreprocessingMode) -> GpuPreprocessingMode {
131        match (self.max_supported_mode, mode) {
132            (GpuPreprocessingMode::None, _) | (_, GpuPreprocessingMode::None) => {
133                GpuPreprocessingMode::None
134            }
135            (mode, GpuPreprocessingMode::Culling) | (GpuPreprocessingMode::Culling, mode) => mode,
136            (GpuPreprocessingMode::PreprocessingOnly, GpuPreprocessingMode::PreprocessingOnly) => {
137                GpuPreprocessingMode::PreprocessingOnly
138            }
139        }
140    }
141
142    /// Returns true if GPU culling is supported on this platform.
143    pub fn is_culling_supported(&self) -> bool {
144        self.max_supported_mode == GpuPreprocessingMode::Culling
145    }
146}
147
148/// The amount of GPU preprocessing (compute and indirect draw) that we do.
149#[derive(Clone, Copy, PartialEq)]
150pub enum GpuPreprocessingMode {
151    /// No GPU preprocessing is in use at all.
152    ///
153    /// This is used when GPU compute isn't available.
154    None,
155
156    /// GPU preprocessing is in use, but GPU culling isn't.
157    ///
158    /// This is used when the [`NoIndirectDrawing`] component is present on the
159    /// camera.
160    PreprocessingOnly,
161
162    /// Both GPU preprocessing and GPU culling are in use.
163    ///
164    /// This is used by default.
165    Culling,
166}
167
168/// The GPU buffers holding the data needed to render batches.
169///
170/// For example, in the 3D PBR pipeline this holds `MeshUniform`s, which are the
171/// `BD` type parameter in that mode.
172///
173/// We have a separate *buffer data input* type (`BDI`) here, which a compute
174/// shader is expected to expand to the full buffer data (`BD`) type. GPU
175/// uniform building is generally faster and uses less system RAM to VRAM bus
176/// bandwidth, but only implemented for some pipelines (for example, not in the
177/// 2D pipeline at present) and only when compute shader is available.
178#[derive(Resource)]
179pub struct BatchedInstanceBuffers<BD, BDI>
180where
181    BD: GpuArrayBufferable + Sync + Send + 'static,
182    BDI: BufferDataInput,
183{
184    /// The uniform data inputs for the current frame.
185    ///
186    /// These are uploaded during the extraction phase.
187    pub current_input_buffer: InstanceInputUniformBuffer<BDI>,
188
189    /// The uniform data inputs for the previous frame.
190    ///
191    /// The indices don't generally line up between `current_input_buffer`
192    /// and `previous_input_buffer`, because, among other reasons, entities
193    /// can spawn or despawn between frames. Instead, each current buffer
194    /// data input uniform is expected to contain the index of the
195    /// corresponding buffer data input uniform in this list.
196    pub previous_input_buffer: PreviousInstanceInputUniformBuffer<BDI::Previous>,
197
198    /// The data needed to render buffers for each phase.
199    ///
200    /// The keys of this map are the type IDs of each phase: e.g. `Opaque3d`,
201    /// `AlphaMask3d`, etc.
202    pub phase_instance_buffers: TypeIdHashMap<UntypedPhaseBatchedInstanceBuffers<BD>>,
203}
204
205impl<BD, BDI> Default for BatchedInstanceBuffers<BD, BDI>
206where
207    BD: GpuArrayBufferable + Sync + Send + 'static,
208    BDI: BufferDataInput,
209{
210    fn default() -> Self {
211        BatchedInstanceBuffers {
212            current_input_buffer: InstanceInputUniformBuffer::new(),
213            previous_input_buffer: PreviousInstanceInputUniformBuffer::new(),
214            phase_instance_buffers: TypeIdHashMap::default(),
215        }
216    }
217}
218
219/// A trait that defines the data that we supply to the GPU for a single mesh
220/// instance (2D or 3D).
221///
222/// A compute shader is expected to expand this data to the full *buffer data*
223/// type. See [`BatchedInstanceBuffers`] for more detail.
224pub trait BufferDataInput: AtomicPod {
225    /// The type of the data that we supply for the GPU for the previous
226    type Previous: AtomicPod;
227}
228
229// We don't use GPU mesh preprocessing for the 2D pipeline, so we implement
230// `BufferDataInput` for the unit type here.
231impl BufferDataInput for () {
232    type Previous = ();
233}
234
235/// The GPU buffers holding the data needed to render batches for a single
236/// phase.
237///
238/// These are split out per phase so that we can run the phases in parallel.
239/// This is the version of the structure that has a type parameter, which
240/// enables Bevy's scheduler to run the batching operations for the different
241/// phases in parallel.
242///
243/// See the documentation for [`BatchedInstanceBuffers`] for more information.
244#[derive(Resource)]
245pub struct PhaseBatchedInstanceBuffers<PI, BD>
246where
247    PI: PhaseItem,
248    BD: GpuArrayBufferable + Sync + Send + 'static,
249{
250    /// The buffers for this phase.
251    pub buffers: UntypedPhaseBatchedInstanceBuffers<BD>,
252    phantom: PhantomData<PI>,
253}
254
255impl<PI, BD> Default for PhaseBatchedInstanceBuffers<PI, BD>
256where
257    PI: PhaseItem,
258    BD: GpuArrayBufferable + Sync + Send + 'static,
259{
260    fn default() -> Self {
261        PhaseBatchedInstanceBuffers {
262            buffers: UntypedPhaseBatchedInstanceBuffers::default(),
263            phantom: PhantomData,
264        }
265    }
266}
267
268/// The GPU buffers holding the data needed to render batches for a single
269/// phase, without a type parameter for that phase.
270///
271/// Since this structure doesn't have a type parameter, it can be placed in
272/// [`BatchedInstanceBuffers::phase_instance_buffers`].
273pub struct UntypedPhaseBatchedInstanceBuffers<BD>
274where
275    BD: GpuArrayBufferable + Sync + Send + 'static,
276{
277    /// A storage area for the buffer data that the GPU compute shader is
278    /// expected to write to.
279    ///
280    /// There will be one entry for each index.
281    pub data_buffer: UninitBufferVec<BD>,
282
283    /// The index of the buffer data in the current input buffer that
284    /// corresponds to each instance.
285    ///
286    /// This is keyed off each view. Each view has a separate buffer.
287    pub work_item_buffers: HashMap<RetainedViewEntity, PreprocessWorkItemBuffers>,
288
289    /// A buffer that holds the number of indexed meshes that weren't visible in
290    /// the previous frame, when GPU occlusion culling is in use.
291    ///
292    /// There's one set of [`LatePreprocessWorkItemIndirectParameters`] per
293    /// view. Bevy uses this value to determine how many threads to dispatch to
294    /// check meshes that weren't visible next frame to see if they became newly
295    /// visible this frame.
296    pub late_indexed_indirect_parameters_buffer:
297        RawBufferVec<LatePreprocessWorkItemIndirectParameters>,
298
299    /// A buffer that holds the number of non-indexed meshes that weren't
300    /// visible in the previous frame, when GPU occlusion culling is in use.
301    ///
302    /// There's one set of [`LatePreprocessWorkItemIndirectParameters`] per
303    /// view. Bevy uses this value to determine how many threads to dispatch to
304    /// check meshes that weren't visible next frame to see if they became newly
305    /// visible this frame.
306    pub late_non_indexed_indirect_parameters_buffer:
307        RawBufferVec<LatePreprocessWorkItemIndirectParameters>,
308}
309
310/// Holds the GPU buffer of instance input data, which is the data about each
311/// mesh instance that the CPU provides.
312///
313/// `BDI` is the *buffer data input* type, which the GPU mesh preprocessing
314/// shader is expected to expand to the full *buffer data* type.
315pub struct InstanceInputUniformBuffer<BDI>
316where
317    BDI: AtomicPod,
318{
319    /// The buffer containing the data that will be uploaded to the GPU.
320    buffer: AtomicSparseBufferVec<BDI>,
321
322    /// Indices of slots that are free within the buffer.
323    ///
324    /// When adding data, we preferentially overwrite these slots first before
325    /// growing the buffer itself.
326    free_uniform_indices: Vec<u32>,
327}
328
329impl<BDI> InstanceInputUniformBuffer<BDI>
330where
331    BDI: AtomicPod,
332{
333    /// Creates a new, empty buffer.
334    pub fn new() -> InstanceInputUniformBuffer<BDI> {
335        InstanceInputUniformBuffer {
336            buffer: AtomicSparseBufferVec::new(
337                BufferUsages::STORAGE,
338                Arc::from("instance input uniform buffer"),
339            ),
340            free_uniform_indices: vec![],
341        }
342    }
343
344    /// Clears the buffer and entity list out.
345    pub fn clear(&mut self) {
346        self.buffer.clear();
347        self.free_uniform_indices.clear();
348    }
349
350    /// Returns the [`AtomicSparseBufferVec`] corresponding to this input
351    /// uniform buffer.
352    #[inline]
353    pub fn buffer(&self) -> &AtomicSparseBufferVec<BDI> {
354        &self.buffer
355    }
356
357    /// Adds a new piece of buffered data to the uniform buffer and returns its
358    /// index.
359    pub fn add(&mut self, element: BDI) -> u32 {
360        match self.free_uniform_indices.pop() {
361            Some(uniform_index) => {
362                self.buffer.set(uniform_index, element);
363                uniform_index
364            }
365            None => self.buffer.push(element),
366        }
367    }
368
369    /// Removes a piece of buffered data from the uniform buffer.
370    ///
371    /// This simply marks the data as free.
372    pub fn remove(&mut self, uniform_index: u32) {
373        self.free_uniform_indices.push(uniform_index);
374    }
375
376    /// Returns the piece of buffered data at the given index.
377    ///
378    /// Returns [`None`] if the index is out of bounds or the data is removed.
379    pub fn get(&self, uniform_index: u32) -> Option<BDI> {
380        if uniform_index >= self.buffer.len() || self.free_uniform_indices.contains(&uniform_index)
381        {
382            None
383        } else {
384            Some(self.get_unchecked(uniform_index))
385        }
386    }
387
388    /// Returns the piece of buffered data at the given index.
389    /// Can return data that has previously been removed.
390    ///
391    /// # Panics
392    /// if `uniform_index` is not in bounds of [`Self::buffer`].
393    pub fn get_unchecked(&self, uniform_index: u32) -> BDI {
394        self.buffer.get(uniform_index)
395    }
396
397    /// Stores a piece of buffered data at the given index.
398    ///
399    /// # Panics
400    /// if `uniform_index` is not in bounds of [`Self::buffer`].
401    pub fn set(&self, uniform_index: u32, element: BDI) {
402        self.buffer.set(uniform_index, element);
403    }
404
405    // Ensures that the buffers are nonempty, which the GPU requires before an
406    // upload can take place.
407    pub fn ensure_nonempty(&mut self) {
408        if self.buffer.is_empty() {
409            self.buffer.push(default());
410        }
411    }
412
413    /// Returns the number of instances in this buffer.
414    pub fn len(&self) -> usize {
415        self.buffer.len() as usize
416    }
417
418    /// Returns true if this buffer has no instances or false if it contains any
419    /// instances.
420    pub fn is_empty(&self) -> bool {
421        self.buffer.is_empty()
422    }
423
424    /// Consumes this [`InstanceInputUniformBuffer`] and returns the raw buffer
425    /// ready to be uploaded to the GPU.
426    pub fn into_buffer(self) -> AtomicSparseBufferVec<BDI> {
427        self.buffer
428    }
429}
430
431impl<BDI> Default for InstanceInputUniformBuffer<BDI>
432where
433    BDI: AtomicPod,
434{
435    fn default() -> Self {
436        Self::new()
437    }
438}
439
440/// Stores the input uniforms for the previous frame.
441///
442/// This doesn't use a sparse buffer because it's cleared out every frame and
443/// only ever pushed onto. The length is stored in an atomic field, so multiple
444/// threads can push simultaneously.
445///
446/// The [`AtomicRawBufferVec`] serves as a backing store only. We reserve a
447/// large size, enough to hold all push operations that could possibly occur on
448/// the worker threads, and only synchronize the changed portion of the buffer
449/// to the GPU on each frame.
450pub struct PreviousInstanceInputUniformBuffer<BPDI>
451where
452    BPDI: AtomicPod,
453{
454    /// The buffer containing the data that will be uploaded to the GPU.
455    buffer: AtomicRawBufferVec<BPDI>,
456
457    /// The number of elements pushed since the last [`Self::reserve`].
458    atomic_len: AtomicU32,
459}
460
461impl<BPDI> PreviousInstanceInputUniformBuffer<BPDI>
462where
463    BPDI: AtomicPod,
464{
465    /// Creates a new, empty buffer.
466    pub fn new() -> PreviousInstanceInputUniformBuffer<BPDI> {
467        PreviousInstanceInputUniformBuffer {
468            buffer: AtomicRawBufferVec::with_label(
469                BufferUsages::STORAGE,
470                "previous instance input uniform buffer",
471            ),
472            atomic_len: AtomicU32::new(0),
473        }
474    }
475
476    /// Writes the buffer to the GPU.
477    fn write_buffer(&mut self, render_device: &RenderDevice, render_queue: &RenderQueue) {
478        // `Self::ensure_nonempty` must have been called first.
479        debug_assert!(!self.buffer.is_empty());
480        // Only write the modified portion of this buffer. Typically, that
481        // portion will be much smaller than the full size of the buffer.
482        self.buffer.write_buffer_range(
483            0..(self.atomic_len.load(Ordering::Relaxed) as usize).max(1),
484            render_device,
485            render_queue,
486        );
487    }
488
489    /// Clears out the buffer in preparation for a new frame.
490    pub fn clear(&mut self) {
491        // Don't actually clear the underlying buffer out, as then we'd have to
492        // grow it again and that would be slow.
493        self.atomic_len.store(0, Ordering::Relaxed);
494    }
495
496    /// Pre-allocates capacity for concurrent [`Self::push`] calls.
497    pub fn reserve(&mut self, capacity: u32) {
498        self.buffer.grow(capacity);
499        *self.atomic_len.get_mut() = 0;
500    }
501
502    /// Appends a value and returns its index. Thread-safe.
503    ///
504    /// [`Self::reserve`] must have been called first with sufficient capacity.
505    pub fn push(&self, value: BPDI) -> u32 {
506        let index = self.atomic_len.fetch_add(1, Ordering::Relaxed);
507        debug_assert!(
508            (index as usize) < self.buffer.len() as usize,
509            "push exceeded pre-allocated capacity"
510        );
511        self.buffer.set(index, value);
512        index
513    }
514
515    /// Pushes a dummy element onto the backing store of this buffer, if this
516    /// buffer is empty.
517    pub fn ensure_nonempty(&mut self) {
518        if self.buffer.is_empty() {
519            self.buffer.push(default());
520        }
521    }
522
523    /// Returns the GPU buffer, if allocated.
524    pub fn buffer(&self) -> Option<&Buffer> {
525        self.buffer.buffer()
526    }
527}
528
529impl<BPDI> Default for PreviousInstanceInputUniformBuffer<BPDI>
530where
531    BPDI: AtomicPod,
532{
533    fn default() -> Self {
534        Self::new()
535    }
536}
537
538/// The buffer of GPU preprocessing work items for a single view.
539#[cfg_attr(
540    not(target_arch = "wasm32"),
541    expect(
542        clippy::large_enum_variant,
543        reason = "See https://github.com/bevyengine/bevy/issues/19220"
544    )
545)]
546pub enum PreprocessWorkItemBuffers {
547    /// The work items we use if we aren't using indirect drawing.
548    ///
549    /// Because we don't have to separate indexed from non-indexed meshes in
550    /// direct mode, we only have a single buffer here.
551    Direct(RawBufferVec<PreprocessWorkItem>),
552
553    /// The buffer of work items we use if we are using indirect drawing.
554    ///
555    /// We need to separate out indexed meshes from non-indexed meshes in this
556    /// case because the indirect parameters for these two types of meshes have
557    /// different sizes.
558    Indirect {
559        /// The buffer of work items corresponding to indexed meshes.
560        indexed: PartialBufferVec<PreprocessWorkItem>,
561        /// The buffer of work items corresponding to non-indexed meshes.
562        non_indexed: PartialBufferVec<PreprocessWorkItem>,
563        /// The work item buffers we use when GPU occlusion culling is in use.
564        gpu_occlusion_culling: Option<GpuOcclusionCullingWorkItemBuffers>,
565    },
566}
567
568/// The work item buffers we use when GPU occlusion culling is in use.
569pub struct GpuOcclusionCullingWorkItemBuffers {
570    /// The buffer of work items corresponding to indexed meshes.
571    pub late_indexed: UninitBufferVec<PreprocessWorkItem>,
572    /// The buffer of work items corresponding to non-indexed meshes.
573    pub late_non_indexed: UninitBufferVec<PreprocessWorkItem>,
574    /// The offset into the
575    /// [`UntypedPhaseBatchedInstanceBuffers::late_indexed_indirect_parameters_buffer`]
576    /// where this view's indirect dispatch counts for indexed meshes live.
577    pub late_indirect_parameters_indexed_offset: u32,
578    /// The offset into the
579    /// [`UntypedPhaseBatchedInstanceBuffers::late_non_indexed_indirect_parameters_buffer`]
580    /// where this view's indirect dispatch counts for non-indexed meshes live.
581    pub late_indirect_parameters_non_indexed_offset: u32,
582}
583
584/// A GPU-side data structure that stores the number of workgroups to dispatch
585/// for the second phase of GPU occlusion culling.
586///
587/// The late mesh preprocessing phase checks meshes that weren't visible frame
588/// to determine if they're potentially visible this frame.
589#[derive(Clone, Copy, ShaderType, Pod, Zeroable)]
590#[repr(C)]
591pub struct LatePreprocessWorkItemIndirectParameters {
592    /// The number of workgroups to dispatch.
593    ///
594    /// This will be equal to `work_item_count / 64`, rounded *up*.
595    dispatch_x: u32,
596    /// The number of workgroups along the abstract Y axis to dispatch: always
597    /// 1.
598    dispatch_y: u32,
599    /// The number of workgroups along the abstract Z axis to dispatch: always
600    /// 1.
601    dispatch_z: u32,
602    /// The actual number of work items.
603    ///
604    /// The GPU indirect dispatch doesn't read this, but it's used internally to
605    /// determine the actual number of work items that exist in the late
606    /// preprocessing work item buffer.
607    work_item_count: u32,
608    /// Padding to 64-byte boundaries for some hardware.
609    pad: UVec4,
610}
611
612impl Default for LatePreprocessWorkItemIndirectParameters {
613    fn default() -> LatePreprocessWorkItemIndirectParameters {
614        LatePreprocessWorkItemIndirectParameters {
615            dispatch_x: 0,
616            dispatch_y: 1,
617            dispatch_z: 1,
618            work_item_count: 0,
619            pad: default(),
620        }
621    }
622}
623
624/// Returns the set of work item buffers for the given view, first creating it
625/// if necessary.
626///
627/// Bevy uses work item buffers to tell the mesh preprocessing compute shader
628/// which meshes are to be drawn.
629///
630/// You may need to call this function if you're implementing your own custom
631/// render phases. See the `specialized_mesh_pipeline` example.
632pub fn get_or_create_work_item_buffer<'a, I>(
633    work_item_buffers: &'a mut HashMap<RetainedViewEntity, PreprocessWorkItemBuffers>,
634    view: RetainedViewEntity,
635    no_indirect_drawing: bool,
636    enable_gpu_occlusion_culling: bool,
637) -> &'a mut PreprocessWorkItemBuffers
638where
639    I: 'static,
640{
641    let preprocess_work_item_buffers = match work_item_buffers.entry(view) {
642        Entry::Occupied(occupied_entry) => occupied_entry.into_mut(),
643        Entry::Vacant(vacant_entry) => {
644            if no_indirect_drawing {
645                vacant_entry.insert(PreprocessWorkItemBuffers::Direct(RawBufferVec::new(
646                    BufferUsages::STORAGE,
647                )))
648            } else {
649                vacant_entry.insert(PreprocessWorkItemBuffers::Indirect {
650                    indexed: PartialBufferVec::new(
651                        BufferUsages::STORAGE,
652                        "indexed preprocess work item buffer".to_owned(),
653                    ),
654                    non_indexed: PartialBufferVec::new(
655                        BufferUsages::STORAGE,
656                        "non-indexed preprocess work item buffer".to_owned(),
657                    ),
658                    // We fill this in below if `enable_gpu_occlusion_culling`
659                    // is set.
660                    gpu_occlusion_culling: None,
661                })
662            }
663        }
664    };
665
666    // Initialize the GPU occlusion culling buffers if necessary.
667    if let PreprocessWorkItemBuffers::Indirect {
668        ref mut gpu_occlusion_culling,
669        ..
670    } = *preprocess_work_item_buffers
671    {
672        match (
673            enable_gpu_occlusion_culling,
674            gpu_occlusion_culling.is_some(),
675        ) {
676            (false, false) | (true, true) => {}
677            (false, true) => {
678                *gpu_occlusion_culling = None;
679            }
680            (true, false) => {
681                *gpu_occlusion_culling = Some(GpuOcclusionCullingWorkItemBuffers {
682                    late_indexed: UninitBufferVec::new(BufferUsages::STORAGE),
683                    late_non_indexed: UninitBufferVec::new(BufferUsages::STORAGE),
684                    late_indirect_parameters_indexed_offset: 0,
685                    late_indirect_parameters_non_indexed_offset: 0,
686                });
687            }
688        }
689    }
690
691    preprocess_work_item_buffers
692}
693
694/// Initializes work item buffers for a phase in preparation for a new frame.
695pub fn init_work_item_buffers(
696    work_item_buffers: &mut PreprocessWorkItemBuffers,
697    late_indexed_indirect_parameters_buffer: &'_ mut RawBufferVec<
698        LatePreprocessWorkItemIndirectParameters,
699    >,
700    late_non_indexed_indirect_parameters_buffer: &'_ mut RawBufferVec<
701        LatePreprocessWorkItemIndirectParameters,
702    >,
703) {
704    // Add the offsets for indirect parameters that the late phase of mesh
705    // preprocessing writes to.
706    if let PreprocessWorkItemBuffers::Indirect {
707        gpu_occlusion_culling:
708            Some(GpuOcclusionCullingWorkItemBuffers {
709                ref mut late_indirect_parameters_indexed_offset,
710                ref mut late_indirect_parameters_non_indexed_offset,
711                ..
712            }),
713        ..
714    } = *work_item_buffers
715    {
716        *late_indirect_parameters_indexed_offset = late_indexed_indirect_parameters_buffer
717            .push(LatePreprocessWorkItemIndirectParameters::default())
718            as u32;
719        *late_indirect_parameters_non_indexed_offset = late_non_indexed_indirect_parameters_buffer
720            .push(LatePreprocessWorkItemIndirectParameters::default())
721            as u32;
722    }
723}
724
725impl PreprocessWorkItemBuffers {
726    /// Adds a new work item to the appropriate buffer.
727    ///
728    /// `indexed` specifies whether the work item corresponds to an indexed
729    /// mesh.
730    pub fn push(&mut self, indexed: bool, preprocess_work_item: PreprocessWorkItem) {
731        match *self {
732            PreprocessWorkItemBuffers::Direct(ref mut buffer) => {
733                buffer.push(preprocess_work_item);
734            }
735            PreprocessWorkItemBuffers::Indirect {
736                indexed: ref mut indexed_buffer,
737                non_indexed: ref mut non_indexed_buffer,
738                ref mut gpu_occlusion_culling,
739            } => {
740                if indexed {
741                    indexed_buffer.push_init(preprocess_work_item);
742                } else {
743                    non_indexed_buffer.push_init(preprocess_work_item);
744                }
745
746                if let Some(ref mut gpu_occlusion_culling) = *gpu_occlusion_culling {
747                    if indexed {
748                        gpu_occlusion_culling.late_indexed.add();
749                    } else {
750                        gpu_occlusion_culling.late_non_indexed.add();
751                    }
752                }
753            }
754        }
755    }
756
757    /// Clears out the GPU work item buffers in preparation for a new frame.
758    pub fn clear(&mut self) {
759        match *self {
760            PreprocessWorkItemBuffers::Direct(ref mut buffer) => {
761                buffer.clear();
762            }
763            PreprocessWorkItemBuffers::Indirect {
764                indexed: ref mut indexed_buffer,
765                non_indexed: ref mut non_indexed_buffer,
766                ref mut gpu_occlusion_culling,
767            } => {
768                indexed_buffer.clear();
769                non_indexed_buffer.clear();
770
771                if let Some(ref mut gpu_occlusion_culling) = *gpu_occlusion_culling {
772                    gpu_occlusion_culling.late_indexed.clear();
773                    gpu_occlusion_culling.late_non_indexed.clear();
774                    gpu_occlusion_culling.late_indirect_parameters_indexed_offset = 0;
775                    gpu_occlusion_culling.late_indirect_parameters_non_indexed_offset = 0;
776                }
777            }
778        }
779    }
780}
781
782/// One invocation of the preprocessing shader: i.e. one mesh instance in a
783/// view.
784#[derive(Clone, Copy, Default, Pod, Zeroable, ShaderType)]
785#[repr(C)]
786pub struct PreprocessWorkItem {
787    /// The index of the batch input data in the input buffer that the shader
788    /// reads from.
789    pub input_index: u32,
790
791    /// In direct mode, the index of the mesh uniform; in indirect mode, the
792    /// index of the [`IndirectParametersMetadata`].
793    ///
794    /// In indirect mode, this is the index of the
795    /// [`IndirectParametersMetadata`] in the
796    /// `IndirectParametersBuffers::indexed_metadata` or
797    /// `IndirectParametersBuffers::non_indexed_metadata`.
798    pub output_or_indirect_parameters_index: u32,
799}
800
801/// The `wgpu` indirect parameters structure that specifies a GPU draw command.
802///
803/// This is the variant for indexed meshes. We generate the instances of this
804/// structure in the `build_indirect_params.wgsl` compute shader.
805#[derive(Clone, Copy, Debug, Pod, Zeroable, ShaderType)]
806#[repr(C)]
807pub struct IndirectParametersIndexed {
808    /// The number of indices that this mesh has.
809    pub index_count: u32,
810    /// The number of instances we are to draw.
811    pub instance_count: u32,
812    /// The offset of the first index for this mesh in the index buffer slab.
813    pub first_index: u32,
814    /// The offset of the first vertex for this mesh in the vertex buffer slab.
815    pub base_vertex: u32,
816    /// The index of the first mesh instance in the `MeshUniform` buffer.
817    pub first_instance: u32,
818}
819
820/// The `wgpu` indirect parameters structure that specifies a GPU draw command.
821///
822/// This is the variant for non-indexed meshes. We generate the instances of
823/// this structure in the `build_indirect_params.wgsl` compute shader.
824#[derive(Clone, Copy, Debug, Pod, Zeroable, ShaderType)]
825#[repr(C)]
826pub struct IndirectParametersNonIndexed {
827    /// The number of vertices that this mesh has.
828    pub vertex_count: u32,
829    /// The number of instances we are to draw.
830    pub instance_count: u32,
831    /// The offset of the first vertex for this mesh in the vertex buffer slab.
832    pub base_vertex: u32,
833    /// The index of the first mesh instance in the `Mesh` buffer.
834    pub first_instance: u32,
835}
836
837impl MeshClassIndirectParameters for IndirectParametersIndexed {
838    fn debug_label() -> &'static str {
839        "indexed"
840    }
841}
842
843impl MeshClassIndirectParameters for IndirectParametersNonIndexed {
844    fn debug_label() -> &'static str {
845        "non-indexed"
846    }
847}
848
849/// A GPU type that specifies the range of batches that each
850/// `build_indirect_params` shader invocation is to process.
851///
852/// There's one `build_indirect_params` invocation per phase of each view.
853#[derive(Clone, Copy, Default, Debug, Pod, Zeroable, ShaderType)]
854#[repr(C)]
855pub struct IndirectParametersBuildJob {
856    /// The index of the first batch that this build operation is to process
857    /// (inclusive).
858    pub first_batch_index: u32,
859    /// The index of the last batch that this build operation is to process
860    /// (exclusive).
861    pub last_batch_index: u32,
862    // Padding to pad out to 256 bytes (the minimum dynamic uniform alignment on
863    // Metal).
864    pad_a: u32,
865    pad_b: u32,
866    pad_c: [UVec4; 15],
867}
868
869// The minimum dynamic uniform alignment on Metal is 256. Make sure that
870// `IndirectParametersBuildJob` has that size.
871assert_eq_size!(IndirectParametersBuildJob, [u8; 256]);
872
873impl IndirectParametersBuildJob {
874    /// Creates and returns a new [`IndirectParametersBuildJob`] for the given
875    /// range of batch indices.
876    pub fn new(batch_range: Range<u32>) -> Self {
877        Self {
878            first_batch_index: batch_range.start,
879            last_batch_index: batch_range.end,
880            pad_a: default(),
881            pad_b: default(),
882            pad_c: default(),
883        }
884    }
885}
886
887/// A structure, written and read on GPU, that records how many instances of
888/// each mesh are actually to be drawn.
889///
890/// The GPU mesh preprocessing shader increments the
891/// [`Self::early_instance_count`] and [`Self::late_instance_count`] as it
892/// determines that meshes are visible.  The indirect parameter building shader
893/// reads this metadata in order to construct the indirect draw parameters.
894///
895/// Each batch will have one instance of this structure.
896#[derive(Clone, Copy, Default, Pod, Zeroable, ShaderType)]
897#[repr(C)]
898pub struct IndirectParametersMetadata {
899    /// The index of the first instance of this mesh in the array of
900    /// `MeshUniform`s.
901    ///
902    /// Note that this is the *first* output index in this batch. Since each
903    /// instance of this structure refers to arbitrarily many instances, the
904    /// `MeshUniform`s corresponding to this batch span the indices
905    /// `base_output_index..(base_output_index + instance_count)`.
906    pub base_output_index: u32,
907
908    /// The index of the batch set that this batch belongs to in the
909    /// [`IndirectBatchSet`] buffer.
910    ///
911    /// A *batch set* is a set of meshes that may be multi-drawn together.
912    /// Multiple batches (and therefore multiple instances of
913    /// [`IndirectParametersMetadata`] structures) can be part of the same batch
914    /// set.
915    pub batch_set_index: u32,
916
917    /// The index of the first mesh in this batch in the array of
918    /// `MeshInputUniform`s.
919    pub mesh_index: u32,
920
921    /// The number of instances that were judged visible last frame.
922    ///
923    /// The uniform allocation pass sets this value to 0, and the mesh
924    /// preprocessing shader increments it as it culls mesh instances.
925    pub early_instance_count: u32,
926
927    /// The number of instances that have been judged potentially visible this
928    /// frame that weren't in the last frame's potentially visible set.
929    ///
930    /// The uniform allocation pass sets this value to 0, and the mesh
931    /// preprocessing shader increments it as it culls mesh instances.
932    pub late_instance_count: u32,
933}
934
935/// A structure, shared between CPU and GPU, that holds the number of on-GPU
936/// indirect draw commands for each *batch set*.
937///
938/// A *batch set* is a set of meshes that may be multi-drawn together.
939///
940/// If the current hardware and driver support `multi_draw_indirect_count`, the
941/// indirect parameters building shader increments
942/// [`Self::indirect_parameters_count`] as it generates indirect parameters. The
943/// `multi_draw_indirect_count` command reads
944/// [`Self::indirect_parameters_count`] in order to determine how many commands
945/// belong to each batch set.
946#[derive(Clone, Copy, Default, Pod, Zeroable, ShaderType)]
947#[repr(C)]
948pub struct IndirectBatchSet {
949    /// The number of indirect parameter commands (i.e. batches) in this batch
950    /// set.
951    ///
952    /// The CPU sets this value to 0 before uploading this structure to GPU. The
953    /// indirect parameters building shader increments this value as it creates
954    /// indirect parameters. Then the `multi_draw_indirect_count` command reads
955    /// this value in order to determine how many indirect draw commands to
956    /// process.
957    pub indirect_parameters_count: u32,
958
959    /// The offset within the `IndirectParametersBuffers::indexed_data` or
960    /// `IndirectParametersBuffers::non_indexed_data` of the first indirect draw
961    /// command for this batch set.
962    ///
963    /// The CPU fills out this value.
964    pub indirect_parameters_base: u32,
965}
966
967/// The buffers containing all the information that indirect draw commands
968/// (`multi_draw_indirect`, `multi_draw_indirect_count`) use to draw the scene.
969///
970/// In addition to the indirect draw buffers themselves, this structure contains
971/// the buffers that store [`IndirectParametersMetadata`], which are the
972/// structures that culling writes to so that the indirect parameter building
973/// pass can determine how many meshes are actually to be drawn.
974///
975/// These buffers will remain empty if indirect drawing isn't in use.
976#[derive(Resource, Deref, DerefMut, Default)]
977pub struct IndirectParametersBuffers {
978    /// A mapping from a phase type ID to the indirect parameters buffers for
979    /// that phase.
980    ///
981    /// Examples of phase type IDs are `Opaque3d` and `AlphaMask3d`.
982    #[deref]
983    pub buffers: TypeIdHashMap<UntypedPhaseIndirectParametersBuffers>,
984}
985
986/// Configuration for [`IndirectParametersBuffers`].
987#[derive(Resource)]
988pub struct IndirectParametersBuffersSettings {
989    /// If true, this sets the `COPY_SRC` flag on indirect draw parameters so
990    /// that they can be read back to CPU.
991    ///
992    /// This is a debugging feature that may reduce performance. It primarily
993    /// exists for the `occlusion_culling` example.
994    pub allow_copies_from_indirect_parameter_buffers: bool,
995}
996
997/// A resource, part of the render world, that stores the GPU buffer that
998/// specifies all the batch ranges that all invocations of the indirect
999/// parameters building shader are to process.
1000///
1001/// This is a dynamic uniform buffer that stores instances of
1002/// [`IndirectParametersBuildJob`]. We could have used immediates instead of a
1003/// dynamic uniform buffer, but we want this to work on WebGPU, where immediate
1004/// support can't be guaranteed.
1005#[derive(Resource)]
1006pub struct IndirectParametersBuildJobs {
1007    /// The [`RawBufferVec`] containing the jobs.
1008    ///
1009    /// Each job in this buffer must be aligned to
1010    /// [`wgpu::Limits::min_uniform_buffer_offset_alignment`] bytes.
1011    buffer: RawBufferVec<IndirectParametersBuildJob>,
1012}
1013
1014impl FromWorld for IndirectParametersBuildJobs {
1015    fn from_world(world: &mut World) -> IndirectParametersBuildJobs {
1016        debug_assert!(size_of::<IndirectParametersBuildJob>().is_multiple_of(
1017            world
1018                .resource::<RenderDevice>()
1019                .limits()
1020                .min_uniform_buffer_offset_alignment as usize
1021        ));
1022        IndirectParametersBuildJobs {
1023            buffer: RawBufferVec::new(
1024                BufferUsages::UNIFORM | BufferUsages::COPY_DST | BufferUsages::COPY_SRC,
1025            ),
1026        }
1027    }
1028}
1029
1030impl IndirectParametersBuildJobs {
1031    /// Pushes a new [`IndirectParametersBuildJob`] onto the buffer and returns
1032    /// the offset of the newly pushed job *in bytes*.
1033    fn push(&mut self, job: IndirectParametersBuildJob) -> u32 {
1034        let index = self.buffer.push(job);
1035        (index * size_of::<IndirectParametersBuildJob>()) as u32
1036    }
1037
1038    /// Clears out all jobs in preparation for a new frame.
1039    fn clear(&mut self) {
1040        self.buffer.clear();
1041    }
1042
1043    /// Returns the GPU buffer containing the jobs.
1044    pub fn buffer(&self) -> Option<&Buffer> {
1045        self.buffer.buffer()
1046    }
1047}
1048
1049/// GPU-side information needed to unpack bins belonging to a single batch set.
1050#[derive(Clone, Copy, Pod, Zeroable, ShaderType)]
1051#[repr(C)]
1052pub struct GpuBinUnpackingMetadata {
1053    /// The index of the first `PreprocessWorkItem` that the compute shader
1054    /// dispatch is to write to.
1055    base_output_work_item_index: u32,
1056    /// The index of the first GPU indirect parameters command for this batch
1057    /// set.
1058    base_indirect_parameters_index: u32,
1059    /// The number of binned mesh instances in the `binned_mesh_instances`
1060    /// array.
1061    binned_mesh_instance_count: u32,
1062    /// Padding.
1063    pad: [u32; 61],
1064}
1065
1066impl Default for GpuBinUnpackingMetadata {
1067    fn default() -> GpuBinUnpackingMetadata {
1068        GpuBinUnpackingMetadata {
1069            base_output_work_item_index: 0,
1070            base_indirect_parameters_index: 0,
1071            binned_mesh_instance_count: 0,
1072            pad: [0; _],
1073        }
1074    }
1075}
1076
1077/// Information about each bin in a batch set.
1078///
1079/// This is maintained by the CPU and cached for bins that don't change from
1080/// frame to frame.
1081#[derive(Clone, Copy, Pod, Zeroable, ShaderType)]
1082#[repr(C)]
1083pub struct GpuBinMetadata {
1084    /// The index of the indirect parameters for this bin, relative to the first
1085    /// indirect parameter index for the batch set.
1086    ///
1087    /// That is, the final indirect parameters index for this bin is
1088    /// `first_indirect_parameters_index` in the `UniformAllocationMetadata`
1089    /// plus this value.
1090    pub indirect_parameters_offset: u32,
1091
1092    /// The index of the bin that this metadata corresponds to.
1093    ///
1094    /// The GPU doesn't use this, but the CPU does in order to perform the
1095    /// reverse mapping from bin metadata index back to the bin. We could store
1096    /// this in a non-GPU-accessible buffer, but I figured the extra complexity
1097    /// wasn't worth it.
1098    pub bin_index: u32,
1099
1100    /// The number of mesh instances in this bin.
1101    pub instance_count: u32,
1102}
1103
1104/// Information needed to allocate `MeshUniform`s on the GPU.
1105#[derive(Clone, Copy, Pod, Zeroable, ShaderType)]
1106#[repr(C)]
1107pub struct GpuUniformAllocationMetadata {
1108    /// The index of this batch set in the `IndirectBatchSet` array.
1109    ///
1110    /// We write this into the `indirect_parameters_metadata`.
1111    pub batch_set_index: u32,
1112
1113    /// The number of bins (a.k.a. draws, a.k.a. batches) in this batch set.
1114    pub bin_count: u32,
1115
1116    /// The index of the first set of indirect parameters for this batch set.
1117    ///
1118    /// This is also the index of the first `IndirectParametersMetadata`, as
1119    /// that's a parallel array with the indirect parameters.
1120    pub first_indirect_parameters_index: u32,
1121
1122    /// The index of the first `MeshUniform` slot for this batch set.
1123    pub first_output_mesh_uniform_index: u32,
1124
1125    /// Padding.
1126    pub pad: [u32; 60],
1127}
1128
1129/// CPU-side information needed to construct the bind groups and issue the
1130/// dispatch for the `unpack_bins` and `allocate_uniforms` shaders, for a single
1131/// batch set.
1132///
1133/// Because those two shaders are always invoked together, we combine the
1134/// information together for efficiency's sake.
1135pub struct SceneUnpackingJob {
1136    /// The GPU buffer of `GpuRenderBinnedMeshInstance`s corresponding to the
1137    /// mesh instances that this batch set contains.
1138    ///
1139    /// This is used in the `unpack_bins` shader.
1140    pub render_binned_mesh_instance_buffer: Buffer,
1141    /// The GPU buffer that stores various metadata for each bin, including the
1142    /// indirect parameters offset and the instance count.
1143    ///
1144    /// This is used in both the `allocate_uniforms` and `unpack_bins` shaders.
1145    pub bin_metadata_buffer: Buffer,
1146    /// A temporary GPU buffer that stores the mesh uniform index of the last
1147    /// instance plus one for each workgroup (i.e. for each 256-bin chunk).
1148    ///
1149    /// This is accumulated in the second stage of the `allocate_uniforms`
1150    /// shader and written out in the third.
1151    pub fan_buffer: Buffer,
1152    /// A GPU buffer that maps the stable index of each bin to the index of the
1153    /// metadata in the [`Self::bin_metadata_buffer`].
1154    pub bin_index_to_bin_metadata_index_buffer: Buffer,
1155    /// The index of this batch set's [`GpuBinUnpackingMetadata`] in the
1156    /// [`SceneUnpackingBuffers::bin_unpacking_metadata`] buffer.
1157    pub bin_unpacking_metadata_index: BinUnpackingMetadataIndex,
1158    /// The index of this batch set's [`GpuUniformAllocationMetadata`] in the
1159    /// [`SceneUnpackingBuffers::uniform_allocation_metadata`] buffer.
1160    pub uniform_allocation_metadata_index: UniformAllocationMetadataIndex,
1161    /// The total number of mesh instances in this batch set.
1162    pub mesh_instance_count: u32,
1163    /// The total number of bins (i.e. draws, i.e. separate meshes) in this
1164    /// batch set.
1165    pub bin_count: u32,
1166}
1167
1168/// The buffers containing all the information that indirect draw commands use
1169/// to draw the scene, for a single phase.
1170///
1171/// This is the version of the structure that has a type parameter, so that the
1172/// batching for different phases can run in parallel.
1173///
1174/// See the [`IndirectParametersBuffers`] documentation for more information.
1175#[derive(Resource)]
1176pub struct PhaseIndirectParametersBuffers<PI>
1177where
1178    PI: PhaseItem,
1179{
1180    /// The indirect draw buffers for the phase.
1181    pub buffers: UntypedPhaseIndirectParametersBuffers,
1182    phantom: PhantomData<PI>,
1183}
1184
1185impl<PI> FromWorld for PhaseIndirectParametersBuffers<PI>
1186where
1187    PI: PhaseItem,
1188{
1189    fn from_world(world: &mut World) -> Self {
1190        let settings = world.resource::<IndirectParametersBuffersSettings>();
1191        PhaseIndirectParametersBuffers {
1192            buffers: UntypedPhaseIndirectParametersBuffers::new(
1193                settings.allow_copies_from_indirect_parameter_buffers,
1194            ),
1195            phantom: PhantomData,
1196        }
1197    }
1198}
1199
1200impl<PI> PhaseIndirectParametersBuffers<PI>
1201where
1202    PI: PhaseItem,
1203{
1204    /// Allocates a single set of indirect parameters in the appropriate buffer.
1205    fn allocate(&mut self, no_indirect_drawing: bool, item_is_indexed: bool) -> Option<u32> {
1206        if no_indirect_drawing {
1207            None
1208        } else if item_is_indexed {
1209            Some(self.buffers.indexed.allocate(1))
1210        } else {
1211            Some(self.buffers.non_indexed.allocate(1))
1212        }
1213    }
1214}
1215
1216/// The buffers containing all the information that indirect draw commands use
1217/// to draw the scene, for a single phase.
1218///
1219/// This is the version of the structure that doesn't have a type parameter, so
1220/// that it can be inserted into [`IndirectParametersBuffers::buffers`]
1221///
1222/// See the [`IndirectParametersBuffers`] documentation for more information.
1223pub struct UntypedPhaseIndirectParametersBuffers {
1224    /// Information that indirect draw commands use to draw indexed meshes in
1225    /// the scene.
1226    pub indexed: MeshClassIndirectParametersBuffers<IndirectParametersIndexed>,
1227    /// Information that indirect draw commands use to draw non-indexed meshes
1228    /// in the scene.
1229    pub non_indexed: MeshClassIndirectParametersBuffers<IndirectParametersNonIndexed>,
1230}
1231
1232impl UntypedPhaseIndirectParametersBuffers {
1233    /// Creates the indirect parameters buffers.
1234    pub fn new(
1235        allow_copies_from_indirect_parameter_buffers: bool,
1236    ) -> UntypedPhaseIndirectParametersBuffers {
1237        UntypedPhaseIndirectParametersBuffers {
1238            non_indexed: MeshClassIndirectParametersBuffers::new(
1239                allow_copies_from_indirect_parameter_buffers,
1240            ),
1241            indexed: MeshClassIndirectParametersBuffers::new(
1242                allow_copies_from_indirect_parameter_buffers,
1243            ),
1244        }
1245    }
1246
1247    /// Reserves space for `count` new batches.
1248    ///
1249    /// The `indexed` parameter specifies whether the meshes that these batches
1250    /// correspond to are indexed or not.
1251    pub fn allocate(&mut self, indexed: bool, count: u32) -> u32 {
1252        if indexed {
1253            self.indexed.allocate(count)
1254        } else {
1255            self.non_indexed.allocate(count)
1256        }
1257    }
1258
1259    /// Returns the number of batches currently allocated.
1260    ///
1261    /// The `indexed` parameter specifies whether the meshes that these batches
1262    /// correspond to are indexed or not.
1263    fn batch_count(&self, indexed: bool) -> usize {
1264        if indexed {
1265            self.indexed.batch_count()
1266        } else {
1267            self.non_indexed.batch_count()
1268        }
1269    }
1270
1271    /// Returns the number of batch sets currently allocated.
1272    ///
1273    /// The `indexed` parameter specifies whether the meshes that these batch
1274    /// sets correspond to are indexed or not.
1275    pub fn batch_set_count(&self, indexed: bool) -> usize {
1276        if indexed {
1277            self.indexed.batch_sets.len()
1278        } else {
1279            self.non_indexed.batch_sets.len()
1280        }
1281    }
1282
1283    /// Adds a new batch set to `Self::indexed_batch_sets` or
1284    /// `Self::non_indexed_batch_sets` as appropriate and updates the
1285    /// `view_to_indirect_parameters_batch_range`.
1286    ///
1287    /// `indexed` specifies whether the meshes that these batch sets correspond
1288    /// to are indexed or not. `retained_view_entity` specifies the view that
1289    /// this batch set is associated with. `indirect_parameters_base` specifies
1290    /// the offset within `Self::indexed_data` or `Self::non_indexed_data` of
1291    /// the first batch in this batch set.
1292    #[inline]
1293    pub fn add_batch_set(
1294        &mut self,
1295        indexed: bool,
1296        retained_view_entity: &RetainedViewEntity,
1297        indirect_parameters_range: Range<u32>,
1298    ) {
1299        if indexed {
1300            self.indexed.batch_sets.push(IndirectBatchSet {
1301                indirect_parameters_base: indirect_parameters_range.start,
1302                indirect_parameters_count: 0,
1303            });
1304            self.indexed
1305                .view_to_indirect_parameters_batch_ranges
1306                .entry(*retained_view_entity)
1307                .or_default()
1308                .push(indirect_parameters_range.clone());
1309        } else {
1310            self.non_indexed.batch_sets.push(IndirectBatchSet {
1311                indirect_parameters_base: indirect_parameters_range.start,
1312                indirect_parameters_count: 0,
1313            });
1314            self.non_indexed
1315                .view_to_indirect_parameters_batch_ranges
1316                .entry(*retained_view_entity)
1317                .or_default()
1318                .push(indirect_parameters_range.clone());
1319        }
1320    }
1321
1322    /// Returns the index that a newly-added batch set will have.
1323    ///
1324    /// The `indexed` parameter specifies whether the meshes in such a batch set
1325    /// are indexed or not.
1326    pub fn get_next_batch_set_index(&self, indexed: bool) -> Option<NonMaxU32> {
1327        NonMaxU32::new(self.batch_set_count(indexed) as u32)
1328    }
1329
1330    /// Clears out the buffers in preparation for a new frame.
1331    pub fn clear(&mut self) {
1332        self.indexed.clear();
1333        self.non_indexed.clear();
1334    }
1335}
1336
1337/// A resource, part of the render world, that holds all GPU buffers used for
1338/// the bin unpacking and uniform allocation shaders.
1339#[derive(Resource)]
1340pub struct SceneUnpackingBuffers {
1341    /// A buffer containing all the uniforms needed to run the uniform
1342    /// allocation compute shader for each batch set.
1343    pub uniform_allocation_metadata: RawBufferVec<GpuUniformAllocationMetadata>,
1344    /// A buffer containing all the uniforms needed to run the bin unpacking
1345    /// compute shader for each batch set.
1346    pub bin_unpacking_metadata: RawBufferVec<GpuBinUnpackingMetadata>,
1347    /// Per-view-phase buffers for the bin unpacking shader.
1348    pub view_phase_buffers: HashMap<SceneUnpackingBuffersKey, ViewPhaseSceneUnpackingBuffers>,
1349}
1350
1351impl Default for SceneUnpackingBuffers {
1352    fn default() -> Self {
1353        let mut uniform_allocation_metadata = RawBufferVec::new(BufferUsages::UNIFORM);
1354        uniform_allocation_metadata.set_label(Some("uniform allocation metadata buffer"));
1355        let mut bin_unpacking_metadata = RawBufferVec::new(BufferUsages::UNIFORM);
1356        bin_unpacking_metadata.set_label(Some("bin unpacking metadata buffer"));
1357        SceneUnpackingBuffers {
1358            uniform_allocation_metadata,
1359            bin_unpacking_metadata,
1360            view_phase_buffers: HashMap::default(),
1361        }
1362    }
1363}
1364
1365/// GPU buffers for the bin unpacking shader that are specific to each phase of
1366/// each view.
1367#[derive(Default)]
1368pub struct ViewPhaseSceneUnpackingBuffers {
1369    /// Metadata that describes each unpacking job, specific to indexed meshes.
1370    pub indexed_unpacking_jobs: Vec<SceneUnpackingJob>,
1371    /// Metadata that describes each unpacking job, specific to non-indexed
1372    /// meshes.
1373    pub non_indexed_unpacking_jobs: Vec<SceneUnpackingJob>,
1374}
1375
1376/// A key used to look up the bin unpacking buffers for a specific phase of a
1377/// specific view.
1378#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1379pub struct SceneUnpackingBuffersKey {
1380    /// The ID of the phase.
1381    pub phase: TypeId,
1382    /// The entity ID of the view.
1383    pub view: RetainedViewEntity,
1384}
1385
1386/// The index of the metadata corresponding to one bin unpacking job in the
1387/// [`SceneUnpackingBuffers::bin_unpacking_metadata`] buffer.
1388#[derive(Clone, Copy, Debug, Deref, DerefMut)]
1389pub struct BinUnpackingMetadataIndex(pub NonMaxU32);
1390
1391impl BinUnpackingMetadataIndex {
1392    /// Returns the byte offset within the
1393    /// [`SceneUnpackingBuffers::bin_unpacking_metadata`] buffer corresponding to
1394    /// this index.
1395    pub fn uniform_offset(&self) -> u32 {
1396        self.get() * size_of::<GpuBinUnpackingMetadata>() as u32
1397    }
1398}
1399
1400/// The index of the metadata corresponding to one uniform allocation job in the
1401/// [`SceneUnpackingBuffers::uniform_allocation_metadata`] buffer.
1402#[derive(Clone, Copy, Deref, DerefMut)]
1403pub struct UniformAllocationMetadataIndex(pub NonMaxU32);
1404
1405impl UniformAllocationMetadataIndex {
1406    /// Returns the byte offset within the
1407    /// [`SceneUnpackingBuffers::uniform_allocation_metadata`] buffer
1408    /// corresponding to this index.
1409    pub fn uniform_offset(&self) -> u32 {
1410        self.get() * size_of::<GpuUniformAllocationMetadata>() as u32
1411    }
1412}
1413
1414/// The buffers containing all the information that indirect draw commands use
1415/// to draw the scene, for a single mesh class (indexed or non-indexed), for a
1416/// single phase.
1417pub struct MeshClassIndirectParametersBuffers<IP>
1418where
1419    IP: Clone + ShaderSize + WriteInto,
1420{
1421    /// The GPU buffer that stores the indirect draw parameters for the meshes.
1422    ///
1423    /// The indirect parameters building shader writes to this buffer, while the
1424    /// `multi_draw_indirect` or `multi_draw_indirect_count` commands read from
1425    /// it to perform the draws.
1426    indirect_draw_parameters: UninitBufferVec<IP>,
1427
1428    /// The GPU buffer that holds data built by the GPU used to construct
1429    /// indirect draw parameters for meshes.
1430    ///
1431    /// The GPU mesh preprocessing shader writes to this buffer, and the
1432    /// indirect parameters building shader reads this buffer to construct the
1433    /// indirect draw parameters.
1434    metadata: PartialBufferVec<IndirectParametersMetadata>,
1435
1436    /// The GPU buffer that holds the number of indirect draw commands for each
1437    /// phase of each view, for meshes.
1438    ///
1439    /// The indirect parameters building shader writes to this buffer, and the
1440    /// `multi_draw_indirect_count` command reads from it in order to know how
1441    /// many indirect draw commands to process.
1442    batch_sets: RawBufferVec<IndirectBatchSet>,
1443
1444    /// A mapping from each view to the ranges of batch instances within the
1445    /// indirect parameters buffer for that view, render phase, and mesh class.
1446    view_to_indirect_parameters_batch_ranges: HashMap<RetainedViewEntity, Vec<Range<u32>>>,
1447}
1448
1449/// GPU-side indirect draw parameters for either indexed or non-indexed meshes.
1450pub trait MeshClassIndirectParameters: Clone + ShaderSize + WriteInto {
1451    /// Either the string "indexed" or "non-indexed".
1452    fn debug_label() -> &'static str;
1453}
1454
1455impl<IP> MeshClassIndirectParametersBuffers<IP>
1456where
1457    IP: MeshClassIndirectParameters,
1458{
1459    fn new(
1460        allow_copies_from_indirect_parameter_buffers: bool,
1461    ) -> MeshClassIndirectParametersBuffers<IP> {
1462        let mut indirect_parameter_buffer_usages = BufferUsages::STORAGE | BufferUsages::INDIRECT;
1463        if allow_copies_from_indirect_parameter_buffers {
1464            indirect_parameter_buffer_usages |= BufferUsages::COPY_SRC;
1465        }
1466
1467        MeshClassIndirectParametersBuffers {
1468            indirect_draw_parameters: UninitBufferVec::new(indirect_parameter_buffer_usages),
1469            metadata: PartialBufferVec::new(
1470                BufferUsages::STORAGE,
1471                format!("{} indirect parameters metadata buffer", IP::debug_label()),
1472            ),
1473            batch_sets: RawBufferVec::new(indirect_parameter_buffer_usages),
1474            view_to_indirect_parameters_batch_ranges: HashMap::new(),
1475        }
1476    }
1477
1478    /// Returns the GPU buffer that stores the indirect draw parameters for
1479    /// indexed meshes.
1480    ///
1481    /// The indirect parameters building shader writes to this buffer, while the
1482    /// `multi_draw_indirect` or `multi_draw_indirect_count` commands read from
1483    /// it to perform the draws.
1484    #[inline]
1485    pub fn data_buffer(&self) -> Option<&Buffer> {
1486        self.indirect_draw_parameters.buffer()
1487    }
1488
1489    /// Returns the GPU buffer that holds the GPU-constructed data used to
1490    /// construct indirect draw parameters for meshes.
1491    ///
1492    /// The GPU mesh preprocessing shader writes to this buffer, and the
1493    /// indirect parameters building shader reads this buffer to construct the
1494    /// indirect draw parameters.
1495    #[inline]
1496    pub fn metadata_buffer(&self) -> Option<&Buffer> {
1497        self.metadata.buffer()
1498    }
1499
1500    /// Returns the GPU buffer that holds the number of indirect draw commands
1501    /// for each phase of each view.
1502    ///
1503    /// The indirect parameters building shader writes to this buffer, and the
1504    /// `multi_draw_indirect_count` command reads from it in order to know how
1505    /// many indirect draw commands to process.
1506    #[inline]
1507    pub fn batch_sets_buffer(&self) -> Option<&Buffer> {
1508        self.batch_sets.buffer()
1509    }
1510
1511    /// Reserves space for `count` new batches.
1512    ///
1513    /// This allocates in the [`Self::metadata`] and
1514    /// [`Self::indirect_draw_parameters`] buffers.
1515    fn allocate(&mut self, count: u32) -> u32 {
1516        let length = self.indirect_draw_parameters.len();
1517        self.metadata.push_multiple_init(count as usize);
1518        for _ in 0..count {
1519            self.indirect_draw_parameters.add();
1520        }
1521        length as u32
1522    }
1523
1524    /// Sets the [`IndirectParametersMetadata`] for the mesh at the given index.
1525    pub fn set(&mut self, index: u32, value: IndirectParametersMetadata) {
1526        self.metadata.set(index as usize, value);
1527    }
1528
1529    /// Returns the number of batches corresponding to meshes that are currently
1530    /// allocated.
1531    #[inline]
1532    pub fn batch_count(&self) -> usize {
1533        self.indirect_draw_parameters.len()
1534    }
1535
1536    /// Clears out all the buffers in preparation for a new frame.
1537    pub fn clear(&mut self) {
1538        self.indirect_draw_parameters.clear();
1539        self.metadata.clear();
1540        self.batch_sets.clear();
1541        self.view_to_indirect_parameters_batch_ranges.clear();
1542    }
1543}
1544
1545impl FromWorld for GpuPreprocessingSupport {
1546    fn from_world(world: &mut World) -> Self {
1547        let adapter = world.resource::<RenderAdapter>();
1548        let device = world.resource::<RenderDevice>();
1549
1550        // Filter Android drivers that are incompatible with GPU preprocessing:
1551        // - We filter out Adreno 730 and earlier GPUs (except 720, as it's newer
1552        //   than 730).
1553        // - We filter out Mali GPUs with driver versions lower than 48.
1554        // - We limit Pixel 10 GPUs (all versions for now) to preprocessing only (no culling)
1555        fn is_non_supported_android_device(adapter_info: &RenderAdapterInfo) -> bool {
1556            crate::get_adreno_model(adapter_info).is_some_and(|model| model != 720 && model <= 730)
1557                || crate::get_mali_driver_version(adapter_info).is_some_and(|version| version < 48)
1558        }
1559        fn is_preprocessing_only_android_device(adapter_info: &RenderAdapterInfo) -> bool {
1560            crate::get_pixel10_driver_version(adapter_info).is_some()
1561        }
1562
1563        let culling_feature_support = device
1564            .features()
1565            .contains(Features::INDIRECT_FIRST_INSTANCE | Features::IMMEDIATES);
1566        // Depth downsampling for occlusion culling requires 12 textures
1567        // and the early occlusion culling pass requires 10 storage buffers
1568        let limit_support = device.limits().max_storage_textures_per_shader_stage >= 12 &&
1569            device.limits().max_storage_buffers_per_shader_stage >= 10 &&
1570            // Even if the adapter supports compute, we might be simulating a lack of
1571            // compute via device limits (see `WgpuSettingsPriority::WebGL2` and
1572            // `wgpu::Limits::downlevel_webgl2_defaults()`). This will have set all the
1573            // `max_compute_*` limits to zero, so we arbitrarily pick one as a canary.
1574            device.limits().max_compute_workgroup_storage_size != 0;
1575
1576        let downlevel_support = adapter
1577            .get_downlevel_capabilities()
1578            .flags
1579            .contains(DownlevelFlags::COMPUTE_SHADERS);
1580
1581        let adapter_info = RenderAdapterInfo::new(adapter.get_info());
1582
1583        let max_supported_mode = if device.limits().max_compute_workgroup_size_x == 0
1584            || is_non_supported_android_device(&adapter_info)
1585            || adapter_info.backend == wgpu::Backend::Gl
1586        {
1587            info_once!(
1588                "GPU preprocessing is not supported on this device. \
1589                Falling back to CPU preprocessing.",
1590            );
1591            GpuPreprocessingMode::None
1592        } else if !(culling_feature_support && limit_support && downlevel_support)
1593            || is_preprocessing_only_android_device(&adapter_info)
1594        {
1595            info_once!("Some GPU preprocessing are limited on this device.");
1596            GpuPreprocessingMode::PreprocessingOnly
1597        } else {
1598            info_once!("GPU preprocessing is fully supported on this device.");
1599            GpuPreprocessingMode::Culling
1600        };
1601
1602        GpuPreprocessingSupport { max_supported_mode }
1603    }
1604}
1605
1606impl<BD, BDI> BatchedInstanceBuffers<BD, BDI>
1607where
1608    BD: GpuArrayBufferable + Sync + Send + 'static,
1609    BDI: BufferDataInput,
1610{
1611    /// Creates new buffers.
1612    pub fn new() -> Self {
1613        Self::default()
1614    }
1615
1616    /// Clears out the buffers in preparation for a new frame.
1617    pub fn clear(&mut self) {
1618        for phase_instance_buffer in self.phase_instance_buffers.values_mut() {
1619            phase_instance_buffer.clear();
1620        }
1621    }
1622}
1623
1624impl<BD> UntypedPhaseBatchedInstanceBuffers<BD>
1625where
1626    BD: GpuArrayBufferable + Sync + Send + 'static,
1627{
1628    pub fn new() -> Self {
1629        UntypedPhaseBatchedInstanceBuffers {
1630            data_buffer: UninitBufferVec::new(BufferUsages::STORAGE),
1631            work_item_buffers: HashMap::default(),
1632            late_indexed_indirect_parameters_buffer: RawBufferVec::new(
1633                BufferUsages::STORAGE | BufferUsages::INDIRECT,
1634            ),
1635            late_non_indexed_indirect_parameters_buffer: RawBufferVec::new(
1636                BufferUsages::STORAGE | BufferUsages::INDIRECT,
1637            ),
1638        }
1639    }
1640
1641    /// Returns the binding of the buffer that contains the per-instance data.
1642    ///
1643    /// This buffer needs to be filled in via a compute shader.
1644    pub fn instance_data_binding(&self) -> Option<BindingResource<'_>> {
1645        self.data_buffer
1646            .buffer()
1647            .map(|buffer| buffer.as_entire_binding())
1648    }
1649
1650    /// Clears out the buffers in preparation for a new frame.
1651    pub fn clear(&mut self) {
1652        self.data_buffer.clear();
1653        self.late_indexed_indirect_parameters_buffer.clear();
1654        self.late_non_indexed_indirect_parameters_buffer.clear();
1655
1656        // Clear each individual set of buffers, but don't depopulate the hash
1657        // table. We want to avoid reallocating these vectors every frame.
1658        for view_work_item_buffers in self.work_item_buffers.values_mut() {
1659            view_work_item_buffers.clear();
1660        }
1661    }
1662}
1663
1664impl<BD> Default for UntypedPhaseBatchedInstanceBuffers<BD>
1665where
1666    BD: GpuArrayBufferable + Sync + Send + 'static,
1667{
1668    fn default() -> Self {
1669        Self::new()
1670    }
1671}
1672
1673/// Metadata that describes how to dispatch the indirect parameters building
1674/// shader.
1675#[derive(Resource, Default, Debug, Deref, DerefMut)]
1676pub struct BuildIndirectParametersMetadata(
1677    pub HashMap<RetainedViewEntity, ViewBuildIndirectParametersMetadata>,
1678);
1679
1680/// Metadata that describes how to dispatch the indirect parameters building
1681/// shader for a single view.
1682///
1683/// The embedded [`TypeIdHashMap`] maps the type ID of a render phase to the
1684/// indirect parameters building metadata for that phase.
1685#[derive(Default, Debug, Deref, DerefMut)]
1686pub struct ViewBuildIndirectParametersMetadata(
1687    pub TypeIdHashMap<PhaseBuildIndirectParametersMetadata>,
1688);
1689
1690/// Metadata that describes how to dispatch the indirect parameters building
1691/// shader for a single render phase in a single view.
1692#[derive(Clone, Default, Debug)]
1693pub struct PhaseBuildIndirectParametersMetadata {
1694    /// Metadata that describes how to dispatch the indirect parameters building
1695    /// shader for indexed meshes.
1696    ///
1697    /// There will be one such element for each invocation of the shader.
1698    pub indexed: Vec<MeshClassBuildIndirectParametersMetadata>,
1699
1700    /// Metadata that describes how to dispatch the indirect parameters building
1701    /// shader for non-indexed meshes.
1702    ///
1703    /// There will be one such element for each invocation of the shader.
1704    pub non_indexed: Vec<MeshClassBuildIndirectParametersMetadata>,
1705}
1706
1707/// Metadata that describes how to dispatch the indirect parameters building
1708/// shader for a single combination of render phase, view, and mesh class
1709/// (indexed or non-indexed).
1710#[derive(Clone, Copy, Default, Debug)]
1711pub struct MeshClassBuildIndirectParametersMetadata {
1712    /// The offset of the [`IndirectParametersBuildJob`] that describes the
1713    /// range of batch instances that this phase must prepare.
1714    ///
1715    /// This offset is in bytes, relative to the start of the
1716    /// [`IndirectParametersBuildJobs`] buffer.
1717    pub uniform_offset: u32,
1718
1719    /// The number of batches that this phase must prepare.
1720    ///
1721    /// We need this count to be stored here so that the render graph knows how
1722    /// many workgroups to dispatch.
1723    pub batch_count: u32,
1724}
1725
1726/// Information about a single render batch set that we're building up during a
1727/// sorted render phase.
1728struct SortedRenderBatchSet<F>
1729where
1730    F: GetBatchData,
1731{
1732    /// The index of the first phase item in this batch in the list of phase
1733    /// items.
1734    phase_item_start_index: u32,
1735
1736    /// The index of the first instance in this batch in the instance buffer.
1737    instance_start_index: u32,
1738
1739    /// True if the mesh in question has an index buffer; false otherwise.
1740    indexed: bool,
1741
1742    /// The ID of the view that this render phase is for.
1743    retained_view_entity: RetainedViewEntity,
1744
1745    /// The index of the indirect parameters for this batch in the
1746    /// [`IndirectParametersBuffers`].
1747    ///
1748    /// If CPU culling is being used, then this will be `None`.
1749    indirect_parameters_index_range: Option<Range<u32>>,
1750
1751    /// Metadata that can be used to determine whether an instance can be placed
1752    /// into this batch.
1753    ///
1754    /// If `None`, the item inside is unbatchable.
1755    meta: Option<(BatchSetMeta<F::BatchSetCompareData>, F::BatchCompareData)>,
1756}
1757
1758impl<F> SortedRenderBatchSet<F>
1759where
1760    F: GetBatchData,
1761{
1762    /// Finalizes this batch and updates the [`SortedRenderPhase`] with the
1763    /// appropriate indices.
1764    ///
1765    /// `instance_end_index` is the index of the last instance in this batch
1766    /// plus one.
1767    fn flush<I>(
1768        self,
1769        instance_end_index: u32,
1770        phase: &mut SortedRenderPhase<I>,
1771        phase_indirect_parameters_buffers: &mut UntypedPhaseIndirectParametersBuffers,
1772    ) where
1773        I: CachedRenderPipelinePhaseItem + SortedPhaseItem,
1774    {
1775        let (batch_range, batch_extra_index) =
1776            phase.items[self.phase_item_start_index as usize].batch_range_and_extra_index_mut();
1777        *batch_range = self.instance_start_index..instance_end_index;
1778        *batch_extra_index = match self.indirect_parameters_index_range {
1779            Some(ref indirect_parameters_index_range) => {
1780                PhaseItemExtraIndex::IndirectParametersIndex {
1781                    range: (*indirect_parameters_index_range).clone(),
1782                    batch_set_index: None,
1783                }
1784            }
1785            None => PhaseItemExtraIndex::None,
1786        };
1787        if let Some(ref indirect_parameters_index_range) = self.indirect_parameters_index_range {
1788            phase_indirect_parameters_buffers.add_batch_set(
1789                self.indexed,
1790                &self.retained_view_entity,
1791                indirect_parameters_index_range.clone(),
1792            );
1793        }
1794    }
1795}
1796
1797/// A system that runs early in extraction and clears out all the
1798/// [`BatchedInstanceBuffers`] for the frame.
1799///
1800/// We have to run this during extraction because, if GPU preprocessing is in
1801/// use, the extraction phase will write to the mesh input uniform buffers
1802/// directly, so the buffers need to be cleared before then.
1803pub fn clear_batched_gpu_instance_buffers<GFBD>(
1804    gpu_batched_instance_buffers: Option<
1805        ResMut<BatchedInstanceBuffers<GFBD::BufferData, GFBD::BufferInputData>>,
1806    >,
1807) where
1808    GFBD: GetFullBatchData,
1809{
1810    // Don't clear the entire table, because that would delete the buffers, and
1811    // we want to reuse those allocations.
1812    if let Some(mut gpu_batched_instance_buffers) = gpu_batched_instance_buffers {
1813        gpu_batched_instance_buffers.clear();
1814    }
1815}
1816
1817/// A system that removes GPU preprocessing work item buffers that correspond to
1818/// deleted [`ExtractedView`]s.
1819///
1820/// This is a separate system from [`clear_batched_gpu_instance_buffers`]
1821/// because [`ExtractedView`]s aren't created until after the extraction phase
1822/// is completed.
1823pub fn delete_old_work_item_buffers<GFBD>(
1824    mut gpu_batched_instance_buffers: ResMut<
1825        BatchedInstanceBuffers<GFBD::BufferData, GFBD::BufferInputData>,
1826    >,
1827    extracted_views: Query<&ExtractedView>,
1828) where
1829    GFBD: GetFullBatchData,
1830{
1831    let retained_view_entities: HashSet<_> = extracted_views
1832        .iter()
1833        .map(|extracted_view| extracted_view.retained_view_entity)
1834        .collect();
1835    for phase_instance_buffers in gpu_batched_instance_buffers
1836        .phase_instance_buffers
1837        .values_mut()
1838    {
1839        phase_instance_buffers
1840            .work_item_buffers
1841            .retain(|retained_view_entity, _| {
1842                retained_view_entities.contains(retained_view_entity)
1843            });
1844    }
1845}
1846
1847/// Batch the items in a sorted render phase, when GPU instance buffer building
1848/// is in use. This means comparing metadata needed to draw each phase item and
1849/// trying to combine the draws into a batch.
1850pub fn batch_and_prepare_sorted_render_phase<I, GFBD>(
1851    mut phase_batched_instance_buffers: ResMut<PhaseBatchedInstanceBuffers<I, GFBD::BufferData>>,
1852    mut phase_indirect_parameters_buffers: ResMut<PhaseIndirectParametersBuffers<I>>,
1853    mut sorted_render_phases: ResMut<ViewSortedRenderPhases<I>>,
1854    mut views: Query<(
1855        &ExtractedView,
1856        Has<NoIndirectDrawing>,
1857        Has<OcclusionCulling>,
1858    )>,
1859    system_param_item: StaticSystemParam<GFBD::Param>,
1860) where
1861    I: CachedRenderPipelinePhaseItem + SortedPhaseItem,
1862    GFBD: GetFullBatchData,
1863{
1864    // We only process GPU-built batch data in this function.
1865    let UntypedPhaseBatchedInstanceBuffers {
1866        ref mut data_buffer,
1867        ref mut work_item_buffers,
1868        ref mut late_indexed_indirect_parameters_buffer,
1869        ref mut late_non_indexed_indirect_parameters_buffer,
1870    } = phase_batched_instance_buffers.buffers;
1871
1872    for (extracted_view, no_indirect_drawing, gpu_occlusion_culling) in &mut views {
1873        let Some(phase) = sorted_render_phases.get_mut(&extracted_view.retained_view_entity) else {
1874            continue;
1875        };
1876
1877        // Create the work item buffer if necessary.
1878        let work_item_buffer = get_or_create_work_item_buffer::<I>(
1879            work_item_buffers,
1880            extracted_view.retained_view_entity,
1881            no_indirect_drawing,
1882            gpu_occlusion_culling,
1883        );
1884
1885        // Initialize those work item buffers in preparation for this new frame.
1886        init_work_item_buffers(
1887            work_item_buffer,
1888            late_indexed_indirect_parameters_buffer,
1889            late_non_indexed_indirect_parameters_buffer,
1890        );
1891
1892        // Walk through the list of phase items, building up batches as we go.
1893        let mut batch_set: Option<SortedRenderBatchSet<GFBD>> = None;
1894
1895        for current_index in 0..phase.items.len() {
1896            // Get the index of the input data, and comparison metadata, for
1897            // this entity.
1898            let item = &phase.items[current_index];
1899            let entity = item.main_entity();
1900            let item_is_indexed = item.indexed();
1901            let current_batch_input_index =
1902                GFBD::get_index_and_compare_data(&system_param_item, entity);
1903
1904            // Unpack that index and metadata. Note that it's possible for index
1905            // and/or metadata to not be present, which signifies that this
1906            // entity is unbatchable. In that case, we break the batch here.
1907            // If the index isn't present the item is not part of this pipeline and so will be skipped.
1908            let Some((current_input_index, current_meta)) = current_batch_input_index else {
1909                // Break a batch if we need to.
1910                if let Some(batch_set) = batch_set.take() {
1911                    batch_set.flush(
1912                        data_buffer.len() as u32,
1913                        phase,
1914                        &mut phase_indirect_parameters_buffers.buffers,
1915                    );
1916                }
1917
1918                continue;
1919            };
1920            let current_meta = if I::AUTOMATIC_BATCHING {
1921                current_meta.map(|(batch_set_meta, batch_meta)| {
1922                    (
1923                        BatchSetMeta::new(&phase.items[current_index], batch_set_meta),
1924                        batch_meta,
1925                    )
1926                })
1927            } else {
1928                None
1929            };
1930
1931            // Determine if this entity can be included in the batch we're
1932            // building up.
1933            let can_batch = match batch_set.as_ref() {
1934                None => SortedPhaseItemBatchability::BreakBatchSet,
1935                Some(batch_set) => match (&current_meta, &batch_set.meta) {
1936                    (
1937                        &Some((ref current_batch_set_key, ref current_bin_key)),
1938                        &Some((ref batch_set_key, ref bin_key)),
1939                    ) => {
1940                        if *current_batch_set_key == *batch_set_key {
1941                            if *current_bin_key == *bin_key {
1942                                SortedPhaseItemBatchability::BatchOk
1943                            } else if no_indirect_drawing {
1944                                // Without indirect drawing, different meshes need separate batch sets
1945                                SortedPhaseItemBatchability::BreakBatchSet
1946                            } else {
1947                                SortedPhaseItemBatchability::BreakBatch
1948                            }
1949                        } else {
1950                            SortedPhaseItemBatchability::BreakBatchSet
1951                        }
1952                    }
1953                    _ => SortedPhaseItemBatchability::BreakBatchSet,
1954                },
1955            };
1956
1957            // Make space in the data buffer for this instance.
1958            let output_index = data_buffer.add() as u32;
1959
1960            // If we can't batch, break the existing batch or batch set and make
1961            // a new one.
1962            match can_batch {
1963                SortedPhaseItemBatchability::BreakBatchSet => {
1964                    // Flush the existing batch set.
1965                    if let Some(batch_set) = batch_set.take() {
1966                        batch_set.flush(
1967                            output_index,
1968                            phase,
1969                            &mut phase_indirect_parameters_buffers.buffers,
1970                        );
1971                    }
1972
1973                    let indirect_parameters_index = phase_indirect_parameters_buffers
1974                        .allocate(no_indirect_drawing, item_is_indexed);
1975
1976                    // Start a new batch.
1977                    if let Some(indirect_parameters_index) = indirect_parameters_index {
1978                        GFBD::write_batch_indirect_parameters_metadata(
1979                            item_is_indexed,
1980                            output_index,
1981                            None,
1982                            &mut phase_indirect_parameters_buffers.buffers,
1983                            indirect_parameters_index,
1984                        );
1985                    }
1986
1987                    batch_set = Some(SortedRenderBatchSet {
1988                        phase_item_start_index: current_index as u32,
1989                        instance_start_index: output_index,
1990                        retained_view_entity: extracted_view.retained_view_entity,
1991                        indexed: item_is_indexed,
1992                        indirect_parameters_index_range: indirect_parameters_index
1993                            .map(|i| i..(i + 1)),
1994                        meta: current_meta,
1995                    });
1996                }
1997
1998                SortedPhaseItemBatchability::BreakBatch => {
1999                    // Allocate the indirect parameters.
2000                    let maybe_indirect_parameters_index = phase_indirect_parameters_buffers
2001                        .allocate(no_indirect_drawing, item_is_indexed);
2002
2003                    if let (&mut Some(ref mut batch_set), Some(indirect_parameters_index)) =
2004                        (&mut batch_set, maybe_indirect_parameters_index)
2005                    {
2006                        GFBD::write_batch_indirect_parameters_metadata(
2007                            item_is_indexed,
2008                            output_index,
2009                            None,
2010                            &mut phase_indirect_parameters_buffers.buffers,
2011                            indirect_parameters_index,
2012                        );
2013
2014                        batch_set.meta = current_meta;
2015
2016                        let indirect_parameters_index_range = batch_set
2017                            .indirect_parameters_index_range
2018                            .as_mut()
2019                            .expect("Can't allocate in a multidraw set if we aren't multidrawing");
2020                        debug_assert_eq!(
2021                            indirect_parameters_index,
2022                            indirect_parameters_index_range.end
2023                        );
2024                        indirect_parameters_index_range.end += 1;
2025                    }
2026                }
2027
2028                SortedPhaseItemBatchability::BatchOk => {}
2029            };
2030
2031            // Add a new preprocessing work item so that the preprocessing
2032            // shader will copy the per-instance data over.
2033            if let Some(batch_set) = batch_set.as_ref() {
2034                work_item_buffer.push(
2035                    item_is_indexed,
2036                    PreprocessWorkItem {
2037                        input_index: current_input_index.into(),
2038                        output_or_indirect_parameters_index: match (
2039                            no_indirect_drawing,
2040                            &batch_set.indirect_parameters_index_range,
2041                        ) {
2042                            (true, _) => output_index,
2043                            (false, Some(indirect_parameters_index_range)) => {
2044                                indirect_parameters_index_range.end - 1
2045                            }
2046                            (false, None) => 0,
2047                        },
2048                    },
2049                );
2050            }
2051        }
2052
2053        // Flush the final batch set if necessary.
2054        if let Some(batch_set) = batch_set.take() {
2055            batch_set.flush(
2056                data_buffer.len() as u32,
2057                phase,
2058                &mut phase_indirect_parameters_buffers.buffers,
2059            );
2060        }
2061    }
2062}
2063
2064/// How a single sorted phase item can be batched with the previous phase item.
2065#[derive(Clone, Copy, PartialEq)]
2066enum SortedPhaseItemBatchability {
2067    /// The item can be batched with the previous item.
2068    BatchOk,
2069    /// The item can't be batched with the previous item, but can still go in
2070    /// the same batch set.
2071    ///
2072    /// That is, the item can be multi-drawn with the previous item.
2073    BreakBatch,
2074    /// The item needs to create a new batch set.
2075    BreakBatchSet,
2076}
2077
2078/// Creates batches for a render phase that uses bins.
2079pub fn batch_and_prepare_binned_render_phase<BPI, GFBD>(
2080    mut phase_batched_instance_buffers: ResMut<PhaseBatchedInstanceBuffers<BPI, GFBD::BufferData>>,
2081    phase_indirect_parameters_buffers: ResMut<PhaseIndirectParametersBuffers<BPI>>,
2082    mut binned_render_phases: ResMut<ViewBinnedRenderPhases<BPI>>,
2083    mut views: Query<
2084        (
2085            &ExtractedView,
2086            Has<NoIndirectDrawing>,
2087            Has<OcclusionCulling>,
2088        ),
2089        With<ExtractedView>,
2090    >,
2091    param: StaticSystemParam<GFBD::Param>,
2092) where
2093    BPI: BinnedPhaseItem,
2094    GFBD: GetFullBatchData,
2095{
2096    let system_param_item = param.into_inner();
2097
2098    let phase_indirect_parameters_buffers = phase_indirect_parameters_buffers.into_inner();
2099
2100    let UntypedPhaseBatchedInstanceBuffers {
2101        ref mut data_buffer,
2102        ref mut work_item_buffers,
2103        ref mut late_indexed_indirect_parameters_buffer,
2104        ref mut late_non_indexed_indirect_parameters_buffer,
2105    } = phase_batched_instance_buffers.buffers;
2106
2107    // We have to prepare unbatchables and batchables before multidrawables.
2108    // This is because:
2109    //
2110    // 1. The `PreprocessWorkItem`s are stored in a `PartialBufferVec`.
2111    // 2. `PreprocessWorkItem`s corresponding to multidrawable mesh
2112    // instances are built on GPU via the `unpack_bins` shader.
2113    // 3. `PreprocessWorkItem`s corresponding to unbatchable and
2114    // batchable-but-not-multidrawable mesh instances are currently built on
2115    // the CPU.
2116    // 4. The `PartialBufferVec`s type enforces that CPU-initialized values
2117    // precede the uninitialized (i.e. GPU-initialized) ones.
2118    //
2119    // Thus, we have to make sure the preprocessing work items that the GPU will
2120    // build follow the preprocessing work items that the CPU built. We do so by
2121    // first preparing unbatchables and batchables for all views, then doing
2122    // another loop over the views to prepare multidrawables.
2123
2124    // Prepare unbatchables and batchables.
2125
2126    for (extracted_view, no_indirect_drawing, gpu_occlusion_culling) in &mut views {
2127        let Some(phase) = binned_render_phases.get_mut(&extracted_view.retained_view_entity) else {
2128            continue;
2129        };
2130
2131        // Create the work item buffer if necessary; otherwise, just mark it as
2132        // used this frame.
2133        let work_item_buffer = get_or_create_work_item_buffer::<BPI>(
2134            work_item_buffers,
2135            extracted_view.retained_view_entity,
2136            no_indirect_drawing,
2137            gpu_occlusion_culling,
2138        );
2139
2140        // Initialize those work item buffers in preparation for this new frame.
2141        init_work_item_buffers(
2142            work_item_buffer,
2143            late_indexed_indirect_parameters_buffer,
2144            late_non_indexed_indirect_parameters_buffer,
2145        );
2146
2147        // Prepare unbatchables.
2148
2149        for (key, unbatchables) in &mut phase.unbatchable_meshes {
2150            // Allocate the indirect parameters if necessary.
2151            let mut indirect_parameters_offset = if no_indirect_drawing {
2152                None
2153            } else if key.0.indexed() {
2154                Some(
2155                    phase_indirect_parameters_buffers
2156                        .buffers
2157                        .indexed
2158                        .allocate(unbatchables.entities.len() as u32),
2159                )
2160            } else {
2161                Some(
2162                    phase_indirect_parameters_buffers
2163                        .buffers
2164                        .non_indexed
2165                        .allocate(unbatchables.entities.len() as u32),
2166                )
2167            };
2168
2169            for main_entity in unbatchables.entities.keys() {
2170                let Some(input_index) = GFBD::get_binned_index(&system_param_item, *main_entity)
2171                else {
2172                    continue;
2173                };
2174                let output_index = data_buffer.add() as u32;
2175
2176                if let Some(ref mut indirect_parameters_index) = indirect_parameters_offset {
2177                    // We're in indirect mode, so add an indirect parameters
2178                    // index.
2179                    GFBD::write_batch_indirect_parameters_metadata(
2180                        key.0.indexed(),
2181                        output_index,
2182                        None,
2183                        &mut phase_indirect_parameters_buffers.buffers,
2184                        *indirect_parameters_index,
2185                    );
2186                    work_item_buffer.push(
2187                        key.0.indexed(),
2188                        PreprocessWorkItem {
2189                            input_index: input_index.into(),
2190                            output_or_indirect_parameters_index: *indirect_parameters_index,
2191                        },
2192                    );
2193                    unbatchables
2194                        .buffer_indices
2195                        .add(UnbatchableBinnedEntityIndices {
2196                            instance_index: *indirect_parameters_index,
2197                            extra_index: PhaseItemExtraIndex::IndirectParametersIndex {
2198                                range: *indirect_parameters_index..(*indirect_parameters_index + 1),
2199                                batch_set_index: None,
2200                            },
2201                        });
2202                    phase_indirect_parameters_buffers.buffers.add_batch_set(
2203                        key.0.indexed(),
2204                        &extracted_view.retained_view_entity,
2205                        *indirect_parameters_index..(*indirect_parameters_index + 1),
2206                    );
2207                    *indirect_parameters_index += 1;
2208                } else {
2209                    work_item_buffer.push(
2210                        key.0.indexed(),
2211                        PreprocessWorkItem {
2212                            input_index: input_index.into(),
2213                            output_or_indirect_parameters_index: output_index,
2214                        },
2215                    );
2216                    unbatchables
2217                        .buffer_indices
2218                        .add(UnbatchableBinnedEntityIndices {
2219                            instance_index: output_index,
2220                            extra_index: PhaseItemExtraIndex::None,
2221                        });
2222                }
2223            }
2224        }
2225
2226        // Prepare batchables.
2227
2228        for (key, bin) in &phase.batchable_meshes {
2229            let mut batch: Option<BinnedRenderPhaseBatch> = None;
2230            for (&main_entity, &input_index) in bin.entities() {
2231                let output_index = data_buffer.add() as u32;
2232
2233                match batch {
2234                    Some(ref mut batch) => {
2235                        batch.instance_range.end = output_index + 1;
2236
2237                        // Append to the current batch.
2238                        //
2239                        // If we're in indirect mode, then we write the first
2240                        // output index of this batch, so that we have a
2241                        // tightly-packed buffer if GPU culling discards some of
2242                        // the instances. Otherwise, we can just write the
2243                        // output index directly.
2244                        work_item_buffer.push(
2245                            key.0.indexed(),
2246                            PreprocessWorkItem {
2247                                input_index: *input_index,
2248                                output_or_indirect_parameters_index: match (
2249                                    no_indirect_drawing,
2250                                    &batch.extra_index,
2251                                ) {
2252                                    (true, _) => output_index,
2253                                    (
2254                                        false,
2255                                        PhaseItemExtraIndex::IndirectParametersIndex {
2256                                            range: indirect_parameters_range,
2257                                            ..
2258                                        },
2259                                    ) => indirect_parameters_range.start,
2260                                    (false, &PhaseItemExtraIndex::DynamicOffset(_))
2261                                    | (false, &PhaseItemExtraIndex::None) => 0,
2262                                },
2263                            },
2264                        );
2265                    }
2266
2267                    None if !no_indirect_drawing => {
2268                        // Start a new batch, in indirect mode.
2269                        let indirect_parameters_index = phase_indirect_parameters_buffers
2270                            .buffers
2271                            .allocate(key.0.indexed(), 1);
2272                        let batch_set_index = phase_indirect_parameters_buffers
2273                            .buffers
2274                            .get_next_batch_set_index(key.0.indexed());
2275
2276                        GFBD::write_batch_indirect_parameters_metadata(
2277                            key.0.indexed(),
2278                            output_index,
2279                            batch_set_index,
2280                            &mut phase_indirect_parameters_buffers.buffers,
2281                            indirect_parameters_index,
2282                        );
2283                        phase_indirect_parameters_buffers.buffers.add_batch_set(
2284                            key.0.indexed(),
2285                            &extracted_view.retained_view_entity,
2286                            indirect_parameters_index..(indirect_parameters_index + 1),
2287                        );
2288                        work_item_buffer.push(
2289                            key.0.indexed(),
2290                            PreprocessWorkItem {
2291                                input_index: *input_index,
2292                                output_or_indirect_parameters_index: indirect_parameters_index,
2293                            },
2294                        );
2295                        batch = Some(BinnedRenderPhaseBatch {
2296                            representative_entity: (Entity::PLACEHOLDER, main_entity),
2297                            instance_range: output_index..output_index + 1,
2298                            extra_index: PhaseItemExtraIndex::IndirectParametersIndex {
2299                                range: indirect_parameters_index..(indirect_parameters_index + 1),
2300                                batch_set_index,
2301                            },
2302                        });
2303                    }
2304
2305                    None => {
2306                        // Start a new batch, in direct mode.
2307                        work_item_buffer.push(
2308                            key.0.indexed(),
2309                            PreprocessWorkItem {
2310                                input_index: *input_index,
2311                                output_or_indirect_parameters_index: output_index,
2312                            },
2313                        );
2314                        batch = Some(BinnedRenderPhaseBatch {
2315                            representative_entity: (Entity::PLACEHOLDER, main_entity),
2316                            instance_range: output_index..output_index + 1,
2317                            extra_index: PhaseItemExtraIndex::None,
2318                        });
2319                    }
2320                }
2321            }
2322
2323            if let Some(batch) = batch {
2324                match phase.batch_sets {
2325                    BinnedRenderPhaseBatchSets::DynamicUniforms(_) => {
2326                        error!("Dynamic uniform batch sets shouldn't be used here");
2327                    }
2328                    BinnedRenderPhaseBatchSets::Direct(ref mut vec) => {
2329                        vec.push(batch);
2330                    }
2331                    BinnedRenderPhaseBatchSets::MultidrawIndirect(ref mut vec) => {
2332                        // The Bevy renderer will never mark a mesh as batchable
2333                        // but not multidrawable if multidraw is in use.
2334                        // However, custom render pipelines might do so, such as
2335                        // the `specialized_mesh_pipeline` example.
2336                        let batch_set_index = match batch.extra_index {
2337                            PhaseItemExtraIndex::IndirectParametersIndex {
2338                                batch_set_index: Some(batch_set_index),
2339                                ..
2340                            } => u32::from(batch_set_index),
2341                            _ => 0,
2342                        };
2343                        vec.push(BinnedRenderPhaseBatchSet {
2344                            first_batch: batch,
2345                            batch_count: 1,
2346                            bin_key: key.1.clone(),
2347                            index: batch_set_index,
2348                            // Unused.
2349                            first_work_item_index: 0,
2350                            // Unused.
2351                            first_indirect_parameters_index: 0,
2352                            // Unused.
2353                            first_output_mesh_uniform_index: 0,
2354                        });
2355                    }
2356                }
2357            }
2358        }
2359    }
2360
2361    // Prepare multidrawables.
2362
2363    for (extracted_view, _, _) in &mut views {
2364        // We should have created the work item buffer for the view in the loop
2365        // above.
2366        let (Some(phase), Some(work_item_buffer)) = (
2367            binned_render_phases.get_mut(&extracted_view.retained_view_entity),
2368            work_item_buffers.get_mut(&extracted_view.retained_view_entity),
2369        ) else {
2370            continue;
2371        };
2372
2373        // Only process multidrawables if we're drawing with multidraw indirect
2374        // in the first place.
2375        let (
2376            &mut BinnedRenderPhaseBatchSets::MultidrawIndirect(ref mut batch_sets),
2377            &mut PreprocessWorkItemBuffers::Indirect {
2378                indexed: ref mut indexed_work_item_buffer,
2379                non_indexed: ref mut non_indexed_work_item_buffer,
2380                gpu_occlusion_culling: ref mut gpu_occlusion_culling_buffers,
2381            },
2382        ) = (&mut phase.batch_sets, &mut *work_item_buffer)
2383        else {
2384            continue;
2385        };
2386
2387        // Initialize the state for both indexed and non-indexed meshes.
2388        let mut indexed_preparer: MultidrawableBatchSetPreparer<BPI, GFBD> =
2389            MultidrawableBatchSetPreparer::new(
2390                phase_indirect_parameters_buffers.buffers.batch_count(true) as u32,
2391                phase_indirect_parameters_buffers
2392                    .buffers
2393                    .indexed
2394                    .batch_sets
2395                    .len() as u32,
2396            );
2397        let mut non_indexed_preparer: MultidrawableBatchSetPreparer<BPI, GFBD> =
2398            MultidrawableBatchSetPreparer::new(
2399                phase_indirect_parameters_buffers.buffers.batch_count(false) as u32,
2400                phase_indirect_parameters_buffers
2401                    .buffers
2402                    .non_indexed
2403                    .batch_sets
2404                    .len() as u32,
2405            );
2406
2407        // Prepare each batch set.
2408        for (batch_set_key, bins) in &phase.multidrawable_meshes {
2409            if batch_set_key.indexed() {
2410                indexed_preparer.prepare_multidrawable_binned_batch_set(
2411                    bins,
2412                    data_buffer,
2413                    indexed_work_item_buffer,
2414                    &mut phase_indirect_parameters_buffers.buffers.indexed,
2415                    batch_sets,
2416                );
2417            } else {
2418                non_indexed_preparer.prepare_multidrawable_binned_batch_set(
2419                    bins,
2420                    data_buffer,
2421                    non_indexed_work_item_buffer,
2422                    &mut phase_indirect_parameters_buffers.buffers.non_indexed,
2423                    batch_sets,
2424                );
2425            }
2426        }
2427
2428        // Reserve space in the occlusion culling buffers, if necessary.
2429        if let Some(gpu_occlusion_culling_buffers) = gpu_occlusion_culling_buffers {
2430            gpu_occlusion_culling_buffers
2431                .late_indexed
2432                .add_multiple(indexed_preparer.work_item_count);
2433            gpu_occlusion_culling_buffers
2434                .late_non_indexed
2435                .add_multiple(non_indexed_preparer.work_item_count);
2436        }
2437
2438        // Record the batch ranges for this phase for the indirect batch set
2439        // building shader to use.
2440        indexed_preparer.flush_batch_range_to(
2441            &mut phase_indirect_parameters_buffers.buffers.indexed,
2442            extracted_view.retained_view_entity,
2443        );
2444        non_indexed_preparer.flush_batch_range_to(
2445            &mut phase_indirect_parameters_buffers.buffers.non_indexed,
2446            extracted_view.retained_view_entity,
2447        );
2448    }
2449}
2450
2451/// The state that [`batch_and_prepare_binned_render_phase`] uses to construct
2452/// multidrawable batch sets.
2453///
2454/// The [`batch_and_prepare_binned_render_phase`] system maintains two of these:
2455/// one for indexed meshes and one for non-indexed meshes.
2456struct MultidrawableBatchSetPreparer<BPI, GFBD>
2457where
2458    BPI: BinnedPhaseItem,
2459    GFBD: GetFullBatchData,
2460{
2461    /// The offset in the indirect parameters buffer at which the next indirect
2462    /// parameters will be written.
2463    indirect_parameters_index: u32,
2464    /// The starting offset in the indirect parameters buffers that we wrote (or
2465    /// are to write) the indirect parameters for the first batch set to.
2466    initial_indirect_parameters_index: u32,
2467    /// The number of batch sets we've built so far for this mesh class.
2468    batch_set_index: u32,
2469    /// The number of work items we've emitted so far for this mesh class.
2470    work_item_count: usize,
2471    phantom: PhantomData<(BPI, GFBD)>,
2472}
2473
2474impl<BPI, GFBD> MultidrawableBatchSetPreparer<BPI, GFBD>
2475where
2476    BPI: BinnedPhaseItem,
2477    GFBD: GetFullBatchData,
2478{
2479    /// Creates a new [`MultidrawableBatchSetPreparer`] that will start writing
2480    /// indirect parameters and batch sets at the given indices.
2481    #[inline]
2482    fn new(initial_indirect_parameters_index: u32, initial_batch_set_index: u32) -> Self {
2483        MultidrawableBatchSetPreparer {
2484            indirect_parameters_index: initial_indirect_parameters_index,
2485            initial_indirect_parameters_index,
2486            batch_set_index: initial_batch_set_index,
2487            work_item_count: 0,
2488            phantom: PhantomData,
2489        }
2490    }
2491
2492    /// Creates batch sets and writes the GPU data needed to draw all visible
2493    /// entities of one mesh class in the given batch set.
2494    ///
2495    /// The *mesh class* represents whether the mesh has indices or not.
2496    #[inline]
2497    fn prepare_multidrawable_binned_batch_set<IP>(
2498        &mut self,
2499        batch_set: &RenderMultidrawableBatchSet<BPI>,
2500        data_buffer: &mut UninitBufferVec<GFBD::BufferData>,
2501        work_item_buffer: &mut PartialBufferVec<PreprocessWorkItem>,
2502        mesh_class_buffers: &mut MeshClassIndirectParametersBuffers<IP>,
2503        batch_sets: &mut Vec<BinnedRenderPhaseBatchSet<BPI::BinKey>>,
2504    ) where
2505        IP: Clone + ShaderSize + WriteInto,
2506    {
2507        // Note that this function is O(1) and doesn't have any loops over the
2508        // meshes or mesh instances in this batch set. This is very important
2509        // for proper GPU-driven rendering, as we want to have no overhead on
2510        // the CPU for meshes that didn't change from the last frame.
2511
2512        let current_indexed_batch_set_index = self.batch_set_index;
2513        let current_output_index = data_buffer.len() as u32;
2514        let first_work_item_index = work_item_buffer.len() as u32;
2515
2516        let indirect_parameters_base = self.indirect_parameters_index;
2517
2518        // We're going to write the first entity into the batch set. Do this
2519        // here so that we can preload the bin into cache as a side effect.
2520        let Some((first_bin_key, first_bin_index)) = batch_set.bin_key_to_bin_index.iter().next()
2521        else {
2522            return;
2523        };
2524        let first_bin = batch_set
2525            .bin(*first_bin_index)
2526            .expect("At least one bin must be present in each batch set");
2527        let first_bin_len = first_bin.entity_to_binned_mesh_instance_index.len();
2528        let first_bin_entity = batch_set
2529            .representative_entity()
2530            .unwrap_or(MainEntity::from(Entity::PLACEHOLDER));
2531
2532        // Calculate where the indirect parameters metadata should go for this
2533        // batch set. The uniform allocation shader will create the actual
2534        // metadata.
2535        let bin_count = batch_set.bin_count();
2536        let first_metadata_index =
2537            mesh_class_buffers.metadata.push_multiple_uninit(bin_count) as u32;
2538
2539        // Next, reserve space for the mesh uniforms and work items that this
2540        // batch set will need.
2541        let first_output_mesh_uniform_index =
2542            data_buffer.add_multiple(batch_set.instance_count as usize) as u32;
2543        work_item_buffer.push_multiple_uninit(batch_set.instance_count as usize);
2544        self.work_item_count += batch_set.instance_count as usize;
2545
2546        // Reserve space for the bins in this batch set in the GPU buffers.
2547        let first_indirect_parameters_index = mesh_class_buffers
2548            .indirect_draw_parameters
2549            .add_multiple(bin_count) as u32;
2550        debug_assert_eq!(first_metadata_index, first_indirect_parameters_index);
2551
2552        // Write the information the GPU will need about this batch set.
2553        mesh_class_buffers.batch_sets.push(IndirectBatchSet {
2554            indirect_parameters_base,
2555            indirect_parameters_count: 0,
2556        });
2557
2558        self.indirect_parameters_index += bin_count as u32;
2559        self.batch_set_index += 1;
2560
2561        // Record the batch set. The render node later processes this record to
2562        // render the batches.
2563        batch_sets.push(BinnedRenderPhaseBatchSet {
2564            first_batch: BinnedRenderPhaseBatch {
2565                representative_entity: (Entity::PLACEHOLDER, first_bin_entity),
2566                instance_range: current_output_index..(current_output_index + first_bin_len as u32),
2567                extra_index: PhaseItemExtraIndex::maybe_indirect_parameters_index(NonMaxU32::new(
2568                    indirect_parameters_base,
2569                )),
2570            },
2571            bin_key: (*first_bin_key).clone(),
2572            batch_count: self.indirect_parameters_index - indirect_parameters_base,
2573            index: current_indexed_batch_set_index,
2574            first_work_item_index,
2575            first_indirect_parameters_index,
2576            first_output_mesh_uniform_index,
2577        });
2578    }
2579
2580    /// Writes the batch ranges for this phase and mesh class to the indirect
2581    /// parameters buffers for the indirect batch set building shader to use.
2582    fn flush_batch_range_to<IP>(
2583        &self,
2584        indirect_parameters_buffers: &mut MeshClassIndirectParametersBuffers<IP>,
2585        retained_view_entity: RetainedViewEntity,
2586    ) where
2587        IP: Clone + ShaderSize + WriteInto,
2588    {
2589        indirect_parameters_buffers
2590            .view_to_indirect_parameters_batch_ranges
2591            .entry(retained_view_entity)
2592            .or_default()
2593            .push(self.initial_indirect_parameters_index..self.indirect_parameters_index);
2594    }
2595}
2596
2597/// A system that gathers up the per-phase GPU buffers and inserts them into the
2598/// [`BatchedInstanceBuffers`] and [`IndirectParametersBuffers`] tables.
2599///
2600/// This runs after the [`batch_and_prepare_binned_render_phase`] or
2601/// [`batch_and_prepare_sorted_render_phase`] systems. It takes the per-phase
2602/// [`PhaseBatchedInstanceBuffers`] and [`PhaseIndirectParametersBuffers`]
2603/// resources and inserts them into the global [`BatchedInstanceBuffers`] and
2604/// [`IndirectParametersBuffers`] tables.
2605///
2606/// This system exists so that the [`batch_and_prepare_binned_render_phase`] and
2607/// [`batch_and_prepare_sorted_render_phase`] can run in parallel with one
2608/// another. If those two systems manipulated [`BatchedInstanceBuffers`] and
2609/// [`IndirectParametersBuffers`] directly, then they wouldn't be able to run in
2610/// parallel.
2611pub fn collect_buffers_for_phase<PI, GFBD>(
2612    mut phase_batched_instance_buffers: ResMut<PhaseBatchedInstanceBuffers<PI, GFBD::BufferData>>,
2613    mut phase_indirect_parameters_buffers: ResMut<PhaseIndirectParametersBuffers<PI>>,
2614    mut batched_instance_buffers: ResMut<
2615        BatchedInstanceBuffers<GFBD::BufferData, GFBD::BufferInputData>,
2616    >,
2617    mut indirect_parameters_buffers: ResMut<IndirectParametersBuffers>,
2618    indirect_parameters_buffers_settings: Res<IndirectParametersBuffersSettings>,
2619) where
2620    PI: PhaseItem,
2621    GFBD: GetFullBatchData + Send + Sync + 'static,
2622{
2623    // Insert the `PhaseBatchedInstanceBuffers` into the global table. Replace
2624    // the contents of the per-phase resource with the old batched instance
2625    // buffers in order to reuse allocations.
2626    let untyped_phase_batched_instance_buffers =
2627        mem::take(&mut phase_batched_instance_buffers.buffers);
2628    if let Some(mut old_untyped_phase_batched_instance_buffers) = batched_instance_buffers
2629        .phase_instance_buffers
2630        .insert(TypeId::of::<PI>(), untyped_phase_batched_instance_buffers)
2631    {
2632        old_untyped_phase_batched_instance_buffers.clear();
2633        phase_batched_instance_buffers.buffers = old_untyped_phase_batched_instance_buffers;
2634    }
2635
2636    // Insert the `PhaseIndirectParametersBuffers` into the global table.
2637    // Replace the contents of the per-phase resource with the old indirect
2638    // parameters buffers in order to reuse allocations.
2639    let untyped_phase_indirect_parameters_buffers = mem::replace(
2640        &mut phase_indirect_parameters_buffers.buffers,
2641        UntypedPhaseIndirectParametersBuffers::new(
2642            indirect_parameters_buffers_settings.allow_copies_from_indirect_parameter_buffers,
2643        ),
2644    );
2645    if let Some(mut old_untyped_phase_indirect_parameters_buffers) = indirect_parameters_buffers
2646        .insert(
2647            TypeId::of::<PI>(),
2648            untyped_phase_indirect_parameters_buffers,
2649        )
2650    {
2651        old_untyped_phase_indirect_parameters_buffers.clear();
2652        phase_indirect_parameters_buffers.buffers = old_untyped_phase_indirect_parameters_buffers;
2653    }
2654}
2655
2656/// A system, part of the render world, that gathers up the batch ranges from
2657/// [`IndirectParametersBuffers`] and prepares the
2658/// [`BuildIndirectParametersMetadata`] that describes the range of batches that
2659/// each indirect parameters building shader invocation is to process.
2660pub fn prepare_indirect_parameters_build_jobs(
2661    mut build_indirect_parameters_metadata: ResMut<BuildIndirectParametersMetadata>,
2662    mut indirect_parameters_build_jobs: ResMut<IndirectParametersBuildJobs>,
2663    indirect_parameters_buffers: Res<IndirectParametersBuffers>,
2664) {
2665    // Make sure to clear out the indirect parameters build jobs in preparation
2666    // for a new frame.
2667    indirect_parameters_build_jobs.clear();
2668    build_indirect_parameters_metadata.clear();
2669
2670    // Prepare the build jobs for all views.
2671    for (phase_type_id, phase_indirect_parameters_buffers) in indirect_parameters_buffers.iter() {
2672        // Prepare the indexed indirect parameters build jobs.
2673        for (retained_view_entity, indirect_parameters_ranges) in phase_indirect_parameters_buffers
2674            .indexed
2675            .view_to_indirect_parameters_batch_ranges
2676            .iter()
2677        {
2678            for indirect_parameters_range in indirect_parameters_ranges {
2679                let uniform_offset = indirect_parameters_build_jobs.push(
2680                    IndirectParametersBuildJob::new(indirect_parameters_range.clone()),
2681                );
2682                build_indirect_parameters_metadata
2683                    .entry(*retained_view_entity)
2684                    .or_default()
2685                    .entry(*phase_type_id)
2686                    .or_default()
2687                    .indexed
2688                    .push(MeshClassBuildIndirectParametersMetadata {
2689                        uniform_offset,
2690                        batch_count: indirect_parameters_range.end
2691                            - indirect_parameters_range.start,
2692                    });
2693            }
2694        }
2695
2696        // Prepare the non-indexed indirect parameters build jobs.
2697        for (retained_view_entity, indirect_parameters_ranges) in phase_indirect_parameters_buffers
2698            .non_indexed
2699            .view_to_indirect_parameters_batch_ranges
2700            .iter()
2701        {
2702            for indirect_parameters_range in indirect_parameters_ranges {
2703                let uniform_offset = indirect_parameters_build_jobs.push(
2704                    IndirectParametersBuildJob::new(indirect_parameters_range.clone()),
2705                );
2706                build_indirect_parameters_metadata
2707                    .entry(*retained_view_entity)
2708                    .or_default()
2709                    .entry(*phase_type_id)
2710                    .or_default()
2711                    .non_indexed
2712                    .push(MeshClassBuildIndirectParametersMetadata {
2713                        uniform_offset,
2714                        batch_count: indirect_parameters_range.end
2715                            - indirect_parameters_range.start,
2716                    });
2717            }
2718        }
2719    }
2720}
2721
2722/// A system that writes all instance buffers to the GPU.
2723pub fn write_batched_instance_buffers<GFBD>(
2724    render_device: Res<RenderDevice>,
2725    render_queue: Res<RenderQueue>,
2726    gpu_array_buffer: ResMut<BatchedInstanceBuffers<GFBD::BufferData, GFBD::BufferInputData>>,
2727    pipeline_cache: Res<PipelineCache>,
2728    mut bin_unpacking_buffers: ResMut<SceneUnpackingBuffers>,
2729    mut sparse_buffer_update_jobs: ResMut<SparseBufferUpdateJobs>,
2730    mut sparse_buffer_update_bind_groups: ResMut<SparseBufferUpdateBindGroups>,
2731    sparse_buffer_update_pipelines: Res<SparseBufferUpdatePipelines>,
2732) where
2733    GFBD: GetFullBatchData,
2734{
2735    let BatchedInstanceBuffers {
2736        current_input_buffer,
2737        previous_input_buffer,
2738        phase_instance_buffers,
2739    } = gpu_array_buffer.into_inner();
2740
2741    let render_device = &*render_device;
2742    let render_queue = &*render_queue;
2743
2744    let bin_unpacking_buffers = &mut *bin_unpacking_buffers;
2745
2746    ComputeTaskPool::get().scope(|scope| {
2747        scope.spawn(async {
2748            #[cfg(feature = "trace")]
2749            let _span = bevy_log::info_span!("write_current_input_buffers").entered();
2750            current_input_buffer
2751                .buffer
2752                .write_buffers(render_device, render_queue);
2753        });
2754        scope.spawn(async {
2755            #[cfg(feature = "trace")]
2756            let _span = bevy_log::info_span!("write_previous_input_buffers").entered();
2757            previous_input_buffer.write_buffer(render_device, render_queue);
2758        });
2759
2760        for phase_instance_buffers in phase_instance_buffers.values_mut() {
2761            let UntypedPhaseBatchedInstanceBuffers {
2762                ref mut data_buffer,
2763                ref mut work_item_buffers,
2764                ref mut late_indexed_indirect_parameters_buffer,
2765                ref mut late_non_indexed_indirect_parameters_buffer,
2766            } = *phase_instance_buffers;
2767
2768            scope.spawn(async {
2769                #[cfg(feature = "trace")]
2770                let _span = bevy_log::info_span!("write_phase_instance_buffers").entered();
2771                data_buffer.write_buffer(render_device);
2772                late_indexed_indirect_parameters_buffer.write_buffer(render_device, render_queue);
2773                late_non_indexed_indirect_parameters_buffer
2774                    .write_buffer(render_device, render_queue);
2775            });
2776
2777            for phase_work_item_buffers in work_item_buffers.values_mut() {
2778                scope.spawn(async {
2779                    #[cfg(feature = "trace")]
2780                    let _span = bevy_log::info_span!("write_work_item_buffers").entered();
2781                    match *phase_work_item_buffers {
2782                        PreprocessWorkItemBuffers::Direct(ref mut buffer_vec) => {
2783                            buffer_vec.write_buffer(render_device, render_queue);
2784                        }
2785                        PreprocessWorkItemBuffers::Indirect {
2786                            ref mut indexed,
2787                            ref mut non_indexed,
2788                            ref mut gpu_occlusion_culling,
2789                        } => {
2790                            indexed.write_buffer(render_device, render_queue);
2791                            non_indexed.write_buffer(render_device, render_queue);
2792
2793                            if let Some(GpuOcclusionCullingWorkItemBuffers {
2794                                ref mut late_indexed,
2795                                ref mut late_non_indexed,
2796                                late_indirect_parameters_indexed_offset: _,
2797                                late_indirect_parameters_non_indexed_offset: _,
2798                            }) = *gpu_occlusion_culling
2799                            {
2800                                if !late_indexed.is_empty() {
2801                                    late_indexed.write_buffer(render_device);
2802                                }
2803                                if !late_non_indexed.is_empty() {
2804                                    late_non_indexed.write_buffer(render_device);
2805                                }
2806                            }
2807                        }
2808                    }
2809                });
2810            }
2811        }
2812
2813        scope.spawn(async {
2814            bin_unpacking_buffers
2815                .bin_unpacking_metadata
2816                .write_buffer(render_device, render_queue);
2817        });
2818        scope.spawn(async {
2819            bin_unpacking_buffers
2820                .uniform_allocation_metadata
2821                .write_buffer(render_device, render_queue);
2822        });
2823    });
2824
2825    // Create the resources necessary to perform sparse uploads of the current
2826    // input buffer if necessary.
2827    current_input_buffer.buffer.prepare_to_populate_buffers(
2828        render_device,
2829        &pipeline_cache,
2830        &mut sparse_buffer_update_jobs,
2831        &mut sparse_buffer_update_bind_groups,
2832        &sparse_buffer_update_pipelines,
2833    );
2834}
2835
2836/// Writes the bin data for each render phase to the GPU.
2837///
2838/// The bin data consists of the IDs of the mesh instances, as well as the
2839/// metadata needed for the `unpack_bins` shader to unpack them.
2840pub fn write_binned_instance_buffers<BPI, GFBD>(
2841    mut views: Query<&ExtractedView>,
2842    mut view_binned_render_phases: ResMut<ViewBinnedRenderPhases<BPI>>,
2843    bin_unpacking_buffers: ResMut<SceneUnpackingBuffers>,
2844    render_device: Res<RenderDevice>,
2845    render_queue: Res<RenderQueue>,
2846) where
2847    BPI: BinnedPhaseItem,
2848    GFBD: GetFullBatchData,
2849{
2850    let bin_unpacking_buffers = bin_unpacking_buffers.into_inner();
2851
2852    let phase_type_id = TypeId::of::<BPI>();
2853
2854    // Record all the `RetainedViewEntity` keys that we saw so that we can
2855    // delete buffers corresponding to views that went away.
2856    let mut all_seen_view_entities = HashSet::new();
2857
2858    for extracted_view in &mut views {
2859        all_seen_view_entities.insert(extracted_view.retained_view_entity);
2860
2861        let Some(view_binned_render_phase) =
2862            view_binned_render_phases.get_mut(&extracted_view.retained_view_entity)
2863        else {
2864            continue;
2865        };
2866
2867        // Since we currently only perform GPU-side bin unpacking for multidrawn
2868        // batch sets, we bail out for all other types of batch sets.
2869        let BinnedRenderPhaseBatchSets::MultidrawIndirect(ref batch_sets) =
2870            view_binned_render_phase.batch_sets
2871        else {
2872            continue;
2873        };
2874
2875        // Get or create the bin unpacking buffers for this (view, phase)
2876        // combination.
2877        let view_phase_bin_unpacking_buffers = bin_unpacking_buffers
2878            .view_phase_buffers
2879            .entry(SceneUnpackingBuffersKey {
2880                phase: phase_type_id,
2881                view: extracted_view.retained_view_entity,
2882            })
2883            .or_default();
2884
2885        // Clear out the list of jobs.
2886        view_phase_bin_unpacking_buffers
2887            .indexed_unpacking_jobs
2888            .clear();
2889        view_phase_bin_unpacking_buffers
2890            .non_indexed_unpacking_jobs
2891            .clear();
2892
2893        // Our goal is to extract the output work item location and indirect
2894        // parameters info from the flat `batch_sets` list and to use it to
2895        // build each batch set's `GpuBinUnpackingMetadata`. To do that, we
2896        // first loop over each batch set in the `batch_set` list and add the
2897        // extracted entry to the
2898        // `representative_entity_to_batch_set_bin_unpacking_metadata` table.
2899
2900        // We use the *representative entity* as the key for the later loop to
2901        // find the `BatchSetBinUnpackingMetadata`, because it's a unique value
2902        // that can be fetched from the `BinnedRenderPhaseBatchSet`.
2903        let mut representative_entity_to_batch_set_scene_unpacking_metadata =
2904            MainEntityHashMap::default();
2905
2906        for batch_set in batch_sets {
2907            let main_entity = batch_set.first_batch.representative_entity.1;
2908            if *main_entity != Entity::PLACEHOLDER
2909                && let PhaseItemExtraIndex::IndirectParametersIndex {
2910                    range: ref indirect_parameters_range,
2911                    ..
2912                } = batch_set.first_batch.extra_index
2913            {
2914                // Record the batch set bin unpacking metadata for later passes
2915                // to use.
2916                representative_entity_to_batch_set_scene_unpacking_metadata.insert(
2917                    main_entity,
2918                    BatchSetSceneUnpackingMetadata {
2919                        base_output_work_item_index: batch_set.first_work_item_index,
2920                        base_indirect_parameters_index: indirect_parameters_range.start,
2921                        batch_set_index: batch_set.index,
2922                        first_indirect_parameters_index: batch_set.first_indirect_parameters_index,
2923                        first_output_mesh_uniform_index: batch_set.first_output_mesh_uniform_index,
2924                    },
2925                );
2926            }
2927        }
2928
2929        // Now loop over all the batch sets in the phase. Look up the
2930        // corresponding `BatchSetBinUnpackingMetadata`, and use it to prepare
2931        // the `GpuBinUnpackingMetadata` and the `BinUnpackingJob`s. Also, kick
2932        // off writes for all the associated GPU buffers that we'd been building
2933        // up in earlier phases.
2934        for (batch_set_key, batch_set) in view_binned_render_phase.multidrawable_meshes.iter_mut() {
2935            let Some(representative_entity) = batch_set.representative_entity() else {
2936                continue;
2937            };
2938            let Some(scene_unpacking_metadata) =
2939                representative_entity_to_batch_set_scene_unpacking_metadata
2940                    .get(&representative_entity)
2941            else {
2942                continue;
2943            };
2944
2945            // Write the various buffers to the GPU.
2946
2947            batch_set
2948                .gpu_buffers
2949                .render_binned_mesh_instance_buffer
2950                .write_buffer(&render_device, &render_queue);
2951            batch_set
2952                .gpu_buffers
2953                .bin_metadata_buffer
2954                .write_buffer(&render_device, &render_queue);
2955            batch_set
2956                .gpu_buffers
2957                .fan_buffer
2958                .write_buffer(&render_device);
2959            batch_set
2960                .gpu_buffers
2961                .bin_index_to_bin_metadata_index_buffer
2962                .write_buffer(&render_device, &render_queue);
2963
2964            let (
2965                Some(render_bin_entry_buffer),
2966                Some(bin_metadata_buffer),
2967                Some(fan_buffer),
2968                Some(bin_index_to_bin_metadata_index_buffer),
2969            ) = (
2970                batch_set
2971                    .gpu_buffers
2972                    .render_binned_mesh_instance_buffer
2973                    .buffer(),
2974                batch_set.gpu_buffers.bin_metadata_buffer.buffer(),
2975                batch_set.gpu_buffers.fan_buffer.buffer(),
2976                batch_set
2977                    .gpu_buffers
2978                    .bin_index_to_bin_metadata_index_buffer
2979                    .buffer(),
2980            )
2981            else {
2982                continue;
2983            };
2984
2985            let binned_mesh_instance_count = batch_set
2986                .gpu_buffers
2987                .render_binned_mesh_instance_buffer
2988                .len() as u32;
2989            let bin_count = batch_set.bin_count() as u32;
2990
2991            // Build up the `GpuBinUnpackingMetadata` for this batch set.
2992            let gpu_bin_unpacking_metadata_index = bin_unpacking_buffers
2993                .bin_unpacking_metadata
2994                .push(GpuBinUnpackingMetadata {
2995                    base_output_work_item_index: scene_unpacking_metadata
2996                        .base_output_work_item_index,
2997                    base_indirect_parameters_index: scene_unpacking_metadata
2998                        .base_indirect_parameters_index,
2999                    binned_mesh_instance_count,
3000                    pad: [0; _],
3001                });
3002
3003            // Build up the `GpuUniformAllocationMetadata` for this batch set.
3004            let gpu_uniform_allocation_metadata_index = bin_unpacking_buffers
3005                .uniform_allocation_metadata
3006                .push(GpuUniformAllocationMetadata {
3007                    batch_set_index: scene_unpacking_metadata.batch_set_index,
3008                    bin_count,
3009                    first_indirect_parameters_index: scene_unpacking_metadata
3010                        .first_indirect_parameters_index,
3011                    first_output_mesh_uniform_index: scene_unpacking_metadata
3012                        .first_output_mesh_uniform_index,
3013                    pad: [0; _],
3014                });
3015
3016            let (
3017                Some(gpu_bin_unpacking_metadata_index),
3018                Some(gpu_uniform_allocation_metadata_index),
3019            ) = (
3020                NonMaxU32::new(gpu_bin_unpacking_metadata_index as u32),
3021                NonMaxU32::new(gpu_uniform_allocation_metadata_index as u32),
3022            )
3023            else {
3024                continue;
3025            };
3026
3027            // Create the [`BinUnpackingJob`].
3028            let job = SceneUnpackingJob {
3029                render_binned_mesh_instance_buffer: render_bin_entry_buffer.clone(),
3030                bin_metadata_buffer: bin_metadata_buffer.clone(),
3031                fan_buffer: fan_buffer.clone(),
3032                bin_index_to_bin_metadata_index_buffer: bin_index_to_bin_metadata_index_buffer
3033                    .clone(),
3034                bin_unpacking_metadata_index: BinUnpackingMetadataIndex(
3035                    gpu_bin_unpacking_metadata_index,
3036                ),
3037                uniform_allocation_metadata_index: UniformAllocationMetadataIndex(
3038                    gpu_uniform_allocation_metadata_index,
3039                ),
3040                mesh_instance_count: binned_mesh_instance_count,
3041                bin_count,
3042            };
3043
3044            if batch_set_key.indexed() {
3045                view_phase_bin_unpacking_buffers
3046                    .indexed_unpacking_jobs
3047                    .push(job);
3048            } else {
3049                view_phase_bin_unpacking_buffers
3050                    .non_indexed_unpacking_jobs
3051                    .push(job);
3052            }
3053        }
3054    }
3055
3056    // Delete buffers corresponding to dead views.
3057    bin_unpacking_buffers
3058        .view_phase_buffers
3059        .retain(|bin_unpacking_buffers_key, _| {
3060            bin_unpacking_buffers_key.phase != phase_type_id
3061                || all_seen_view_entities.contains(&bin_unpacking_buffers_key.view)
3062        });
3063}
3064
3065/// Clears out the [`SceneUnpackingBuffers`] in preparation for a new frame.
3066pub fn clear_scene_unpacking_buffers(mut scene_unpacking_buffers: ResMut<SceneUnpackingBuffers>) {
3067    scene_unpacking_buffers.bin_unpacking_metadata.clear();
3068    scene_unpacking_buffers.uniform_allocation_metadata.clear();
3069}
3070
3071/// CPU-side metadata needed to drive the uniform allocation and bin unpacking
3072/// compute shaders for a single batch set.
3073struct BatchSetSceneUnpackingMetadata {
3074    /// The index of the first [`PreprocessWorkItem`] that the compute shader
3075    /// dispatch is to write to.
3076    base_output_work_item_index: u32,
3077    /// The index of the first GPU indirect parameters command for the batch
3078    /// set.
3079    base_indirect_parameters_index: u32,
3080    /// The index of the batch set in the `indirect_batch_sets` array.
3081    batch_set_index: u32,
3082    /// The index of the indirect parameters for the first bin in the indirect
3083    /// parameters buffer.
3084    first_indirect_parameters_index: u32,
3085    /// The index of the first `MeshUniform` in the mesh uniforms buffer.
3086    first_output_mesh_uniform_index: u32,
3087}
3088
3089pub fn clear_indirect_parameters_buffers(
3090    mut indirect_parameters_buffers: ResMut<IndirectParametersBuffers>,
3091) {
3092    for phase_indirect_parameters_buffers in indirect_parameters_buffers.values_mut() {
3093        phase_indirect_parameters_buffers.clear();
3094    }
3095}
3096
3097pub fn write_indirect_parameters_buffers(
3098    render_device: Res<RenderDevice>,
3099    render_queue: Res<RenderQueue>,
3100    mut indirect_parameters_buffers: ResMut<IndirectParametersBuffers>,
3101) {
3102    let render_device = &*render_device;
3103    let render_queue = &*render_queue;
3104    ComputeTaskPool::get().scope(|scope| {
3105        for phase_indirect_parameters_buffers in indirect_parameters_buffers.values_mut() {
3106            scope.spawn(async {
3107                #[cfg(feature = "trace")]
3108                let _span = bevy_log::info_span!("indexed_data").entered();
3109                phase_indirect_parameters_buffers
3110                    .indexed
3111                    .indirect_draw_parameters
3112                    .write_buffer(render_device);
3113            });
3114            scope.spawn(async {
3115                #[cfg(feature = "trace")]
3116                let _span = bevy_log::info_span!("non_indexed_data").entered();
3117                phase_indirect_parameters_buffers
3118                    .non_indexed
3119                    .indirect_draw_parameters
3120                    .write_buffer(render_device);
3121            });
3122
3123            scope.spawn(async {
3124                #[cfg(feature = "trace")]
3125                let _span = bevy_log::info_span!("indexed_cpu_metadata").entered();
3126                phase_indirect_parameters_buffers
3127                    .indexed
3128                    .metadata
3129                    .write_buffer(render_device, render_queue);
3130            });
3131            scope.spawn(async {
3132                #[cfg(feature = "trace")]
3133                let _span = bevy_log::info_span!("non_indexed_cpu_metadata").entered();
3134                phase_indirect_parameters_buffers
3135                    .non_indexed
3136                    .metadata
3137                    .write_buffer(render_device, render_queue);
3138            });
3139
3140            scope.spawn(async {
3141                #[cfg(feature = "trace")]
3142                let _span = bevy_log::info_span!("indexed_batch_sets").entered();
3143                phase_indirect_parameters_buffers
3144                    .indexed
3145                    .batch_sets
3146                    .write_buffer(render_device, render_queue);
3147            });
3148            scope.spawn(async {
3149                #[cfg(feature = "trace")]
3150                let _span = bevy_log::info_span!("non_indexed_batch_sets").entered();
3151                phase_indirect_parameters_buffers
3152                    .non_indexed
3153                    .batch_sets
3154                    .write_buffer(render_device, render_queue);
3155            });
3156        }
3157    });
3158}
3159
3160/// A render-world system that writes the dynamic uniform buffer containing all
3161/// [`IndirectParametersBuildJob`]s to the GPU.
3162pub fn write_indirect_parameters_build_jobs(
3163    render_device: Res<RenderDevice>,
3164    render_queue: Res<RenderQueue>,
3165    mut indirect_parameters_build_jobs: ResMut<IndirectParametersBuildJobs>,
3166) {
3167    indirect_parameters_build_jobs
3168        .buffer
3169        .write_buffer(&render_device, &render_queue);
3170}
3171
3172#[cfg(test)]
3173mod tests {
3174    use bytemuck::{Pod, Zeroable};
3175
3176    use crate::impl_atomic_pod;
3177
3178    use super::*;
3179
3180    #[derive(Clone, Copy, Default, PartialEq, Debug, Pod, Zeroable)]
3181    #[repr(C)]
3182    struct TestData(u32);
3183
3184    impl_atomic_pod!(TestData, TestDataBlob);
3185
3186    #[test]
3187    fn instance_buffer_correct_behavior() {
3188        let mut instance_buffer = InstanceInputUniformBuffer::new();
3189
3190        let index = instance_buffer.add(TestData(2));
3191        instance_buffer.remove(index);
3192        assert_eq!(instance_buffer.get_unchecked(index), TestData(2));
3193        assert_eq!(instance_buffer.get(index), None);
3194
3195        instance_buffer.add(TestData(5));
3196        assert_eq!(instance_buffer.buffer().len(), 1);
3197    }
3198}