bevy_render/mesh/
allocator.rs

1//! Manages mesh vertex and index buffers.
2
3use alloc::vec::Vec;
4use bevy_mesh::Indices;
5use core::{
6    fmt::{self, Display, Formatter},
7    ops::Range,
8};
9use nonmax::NonMaxU32;
10
11use bevy_app::{App, Plugin};
12use bevy_asset::AssetId;
13use bevy_derive::{Deref, DerefMut};
14use bevy_ecs::{
15    resource::Resource,
16    schedule::IntoScheduleConfigs as _,
17    system::{Res, ResMut},
18    world::{FromWorld, World},
19};
20use bevy_platform::collections::{hash_map::Entry, HashMap, HashSet};
21use bevy_utils::default;
22use offset_allocator::{Allocation, Allocator};
23use tracing::error;
24use wgpu::{
25    BufferDescriptor, BufferSize, BufferUsages, CommandEncoderDescriptor, DownlevelFlags,
26    COPY_BUFFER_ALIGNMENT,
27};
28
29use crate::{
30    mesh::{Mesh, MeshVertexBufferLayouts, RenderMesh},
31    render_asset::{prepare_assets, ExtractedAssets},
32    render_resource::Buffer,
33    renderer::{RenderAdapter, RenderDevice, RenderQueue},
34    Render, RenderApp, RenderSystems,
35};
36
37/// A plugin that manages GPU memory for mesh data.
38pub struct MeshAllocatorPlugin;
39
40/// Manages the assignment of mesh data to GPU buffers.
41///
42/// The Bevy renderer tries to pack vertex and index data for multiple meshes
43/// together so that multiple meshes can be drawn back-to-back without any
44/// rebinding. This resource manages these buffers.
45///
46/// Within each slab, or hardware buffer, the underlying allocation algorithm is
47/// [`offset_allocator`], a Rust port of Sebastian Aaltonen's hard-real-time C++
48/// `OffsetAllocator`. Slabs start small and then grow as their contents fill
49/// up, up to a maximum size limit. To reduce fragmentation, vertex and index
50/// buffers that are too large bypass this system and receive their own buffers.
51///
52/// The [`MeshAllocatorSettings`] allows you to tune the behavior of the
53/// allocator for better performance with your application. Most applications
54/// won't need to change the settings from their default values.
55#[derive(Resource)]
56pub struct MeshAllocator {
57    /// Holds all buffers and allocators.
58    slabs: HashMap<SlabId, Slab>,
59
60    /// Maps a layout to the slabs that hold elements of that layout.
61    ///
62    /// This is used when allocating, so that we can find the appropriate slab
63    /// to place an object in.
64    slab_layouts: HashMap<ElementLayout, Vec<SlabId>>,
65
66    /// Maps mesh asset IDs to the ID of the slabs that hold their vertex data.
67    mesh_id_to_vertex_slab: HashMap<AssetId<Mesh>, SlabId>,
68
69    /// Maps mesh asset IDs to the ID of the slabs that hold their index data.
70    mesh_id_to_index_slab: HashMap<AssetId<Mesh>, SlabId>,
71
72    /// The next slab ID to assign.
73    next_slab_id: SlabId,
74
75    /// Whether we can pack multiple vertex arrays into a single slab on this
76    /// platform.
77    ///
78    /// This corresponds to [`DownlevelFlags::BASE_VERTEX`], which is unset on
79    /// WebGL 2. On this platform, we must give each vertex array its own
80    /// buffer, because we can't adjust the first vertex when we perform a draw.
81    general_vertex_slabs_supported: bool,
82
83    /// Additional buffer usages to add to any vertex or index buffers created.
84    pub extra_buffer_usages: BufferUsages,
85}
86
87/// Tunable parameters that customize the behavior of the allocator.
88///
89/// Generally, these parameters adjust the tradeoff between memory fragmentation
90/// and performance. You can adjust them as desired for your application. Most
91/// applications can stick with the default values.
92#[derive(Resource)]
93pub struct MeshAllocatorSettings {
94    /// The minimum size of a slab (hardware buffer), in bytes.
95    ///
96    /// The default value is 1 MiB.
97    pub min_slab_size: u64,
98
99    /// The maximum size of a slab (hardware buffer), in bytes.
100    ///
101    /// When a slab reaches this limit, a new slab is created.
102    ///
103    /// The default value is 512 MiB.
104    pub max_slab_size: u64,
105
106    /// The maximum size of vertex or index data that can be placed in a general
107    /// slab, in bytes.
108    ///
109    /// If a mesh has vertex or index data that exceeds this size limit, that
110    /// data is placed in its own slab. This reduces fragmentation, but incurs
111    /// more CPU-side binding overhead when drawing the mesh.
112    ///
113    /// The default value is 256 MiB.
114    pub large_threshold: u64,
115
116    /// The factor by which we scale a slab when growing it.
117    ///
118    /// This value must be greater than 1. Higher values result in more
119    /// fragmentation but fewer expensive copy operations when growing the
120    /// buffer.
121    ///
122    /// The default value is 1.5.
123    pub growth_factor: f64,
124}
125
126impl Default for MeshAllocatorSettings {
127    fn default() -> Self {
128        Self {
129            // 1 MiB
130            min_slab_size: 1024 * 1024,
131            // 512 MiB
132            max_slab_size: 1024 * 1024 * 512,
133            // 256 MiB
134            large_threshold: 1024 * 1024 * 256,
135            // 1.5× growth
136            growth_factor: 1.5,
137        }
138    }
139}
140
141/// The hardware buffer that mesh data lives in, as well as the range within
142/// that buffer.
143pub struct MeshBufferSlice<'a> {
144    /// The buffer that the mesh data resides in.
145    pub buffer: &'a Buffer,
146
147    /// The range of elements within this buffer that the mesh data resides in,
148    /// measured in elements.
149    ///
150    /// This is not a byte range; it's an element range. For vertex data, this
151    /// is measured in increments of a single vertex. (Thus, if a vertex is 32
152    /// bytes long, then this range is in units of 32 bytes each.) For index
153    /// data, this is measured in increments of a single index value (2 or 4
154    /// bytes). Draw commands generally take their ranges in elements, not
155    /// bytes, so this is the most convenient unit in this case.
156    pub range: Range<u32>,
157}
158
159/// The index of a single slab.
160#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
161#[repr(transparent)]
162pub struct SlabId(pub NonMaxU32);
163
164/// Data for a single slab.
165#[expect(
166    clippy::large_enum_variant,
167    reason = "See https://github.com/bevyengine/bevy/issues/19220"
168)]
169enum Slab {
170    /// A slab that can contain multiple objects.
171    General(GeneralSlab),
172    /// A slab that contains a single object.
173    LargeObject(LargeObjectSlab),
174}
175
176impl Slab {
177    pub fn buffer_size(&self) -> u64 {
178        match self {
179            Self::General(gs) => gs.buffer.as_ref().map(|buffer| buffer.size()).unwrap_or(0),
180            Self::LargeObject(lo) => lo.buffer.as_ref().map(|buffer| buffer.size()).unwrap_or(0),
181        }
182    }
183}
184
185/// A resizable slab that can contain multiple objects.
186///
187/// This is the normal type of slab used for objects that are below the
188/// [`MeshAllocatorSettings::large_threshold`]. Slabs are divided into *slots*,
189/// which are described in detail in the [`ElementLayout`] documentation.
190struct GeneralSlab {
191    /// The [`Allocator`] that manages the objects in this slab.
192    allocator: Allocator,
193
194    /// The GPU buffer that backs this slab.
195    ///
196    /// This may be `None` if the buffer hasn't been created yet. We delay
197    /// creation of buffers until allocating all the meshes for a single frame,
198    /// so that we don't needlessly create and resize buffers when many meshes
199    /// load all at once.
200    buffer: Option<Buffer>,
201
202    /// Allocations that are on the GPU.
203    ///
204    /// The range is in slots.
205    resident_allocations: HashMap<AssetId<Mesh>, SlabAllocation>,
206
207    /// Allocations that are waiting to be uploaded to the GPU.
208    ///
209    /// The range is in slots.
210    pending_allocations: HashMap<AssetId<Mesh>, SlabAllocation>,
211
212    /// The layout of a single element (vertex or index).
213    element_layout: ElementLayout,
214
215    /// The size of this slab in slots.
216    current_slot_capacity: u32,
217}
218
219/// A slab that contains a single object.
220///
221/// Typically, this is for objects that exceed the
222/// [`MeshAllocatorSettings::large_threshold`]. This is also for objects that
223/// would ordinarily receive their own slab but can't because of platform
224/// limitations, most notably vertex arrays on WebGL 2.
225struct LargeObjectSlab {
226    /// The GPU buffer that backs this slab.
227    ///
228    /// This may be `None` if the buffer hasn't been created yet.
229    buffer: Option<Buffer>,
230
231    /// The layout of a single element (vertex or index).
232    element_layout: ElementLayout,
233}
234
235/// The type of element that a slab can store.
236#[derive(Clone, Copy, PartialEq, Eq, Hash)]
237enum ElementClass {
238    /// Data for a vertex.
239    Vertex,
240    /// A vertex index.
241    Index,
242}
243
244/// The results of [`GeneralSlab::grow_if_necessary`].
245enum SlabGrowthResult {
246    /// The mesh data already fits in the slab; the slab doesn't need to grow.
247    NoGrowthNeeded,
248    /// The slab needed to grow.
249    ///
250    /// The [`SlabToReallocate`] contains the old capacity of the slab.
251    NeededGrowth(SlabToReallocate),
252    /// The slab wanted to grow but couldn't because it hit its maximum size.
253    CantGrow,
254}
255
256/// Information about the size of individual elements (vertices or indices)
257/// within a slab.
258///
259/// Slab objects are allocated in units of *slots*. Usually, each element takes
260/// up one slot, and so elements and slots are equivalent. Occasionally,
261/// however, a slot may consist of 2 or even 4 elements. This occurs when the
262/// size of an element isn't divisible by [`COPY_BUFFER_ALIGNMENT`]. When we
263/// resize buffers, we perform GPU-to-GPU copies to shuffle the existing
264/// elements into their new positions, and such copies must be on
265/// [`COPY_BUFFER_ALIGNMENT`] boundaries. Slots solve this problem by
266/// guaranteeing that the size of an allocation quantum is divisible by both the
267/// size of an element and [`COPY_BUFFER_ALIGNMENT`], so we can relocate it
268/// freely.
269#[derive(Clone, Copy, PartialEq, Eq, Hash)]
270struct ElementLayout {
271    /// Either a vertex or an index.
272    class: ElementClass,
273
274    /// The size in bytes of a single element (vertex or index).
275    size: u64,
276
277    /// The number of elements that make up a single slot.
278    ///
279    /// Usually, this is 1, but it can be different if [`ElementLayout::size`]
280    /// isn't divisible by 4. See the comment in [`ElementLayout`] for more
281    /// details.
282    elements_per_slot: u32,
283}
284
285/// The location of an allocation and the slab it's contained in.
286struct MeshAllocation {
287    /// The ID of the slab.
288    slab_id: SlabId,
289    /// Holds the actual allocation.
290    slab_allocation: SlabAllocation,
291}
292
293/// An allocation within a slab.
294#[derive(Clone)]
295struct SlabAllocation {
296    /// The actual [`Allocator`] handle, needed to free the allocation.
297    allocation: Allocation,
298    /// The number of slots that this allocation takes up.
299    slot_count: u32,
300}
301
302/// Holds information about all slabs scheduled to be allocated or reallocated.
303#[derive(Default, Deref, DerefMut)]
304struct SlabsToReallocate(HashMap<SlabId, SlabToReallocate>);
305
306/// Holds information about a slab that's scheduled to be allocated or
307/// reallocated.
308#[derive(Default)]
309struct SlabToReallocate {
310    /// The capacity of the slab before we decided to grow it.
311    old_slot_capacity: u32,
312}
313
314impl Display for SlabId {
315    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
316        self.0.fmt(f)
317    }
318}
319
320impl Plugin for MeshAllocatorPlugin {
321    fn build(&self, app: &mut App) {
322        let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
323            return;
324        };
325
326        render_app
327            .init_resource::<MeshAllocatorSettings>()
328            .add_systems(
329                Render,
330                allocate_and_free_meshes
331                    .in_set(RenderSystems::PrepareAssets)
332                    .before(prepare_assets::<RenderMesh>),
333            );
334    }
335
336    fn finish(&self, app: &mut App) {
337        let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
338            return;
339        };
340
341        // The `RenderAdapter` isn't available until now, so we can't do this in
342        // [`Plugin::build`].
343        render_app.init_resource::<MeshAllocator>();
344    }
345}
346
347impl FromWorld for MeshAllocator {
348    fn from_world(world: &mut World) -> Self {
349        // Note whether we're on WebGL 2. In this case, we must give every
350        // vertex array its own slab.
351        let render_adapter = world.resource::<RenderAdapter>();
352        let general_vertex_slabs_supported = render_adapter
353            .get_downlevel_capabilities()
354            .flags
355            .contains(DownlevelFlags::BASE_VERTEX);
356
357        Self {
358            slabs: HashMap::default(),
359            slab_layouts: HashMap::default(),
360            mesh_id_to_vertex_slab: HashMap::default(),
361            mesh_id_to_index_slab: HashMap::default(),
362            next_slab_id: default(),
363            general_vertex_slabs_supported,
364            extra_buffer_usages: BufferUsages::empty(),
365        }
366    }
367}
368
369/// A system that processes newly-extracted or newly-removed meshes and writes
370/// their data into buffers or frees their data as appropriate.
371pub fn allocate_and_free_meshes(
372    mut mesh_allocator: ResMut<MeshAllocator>,
373    mesh_allocator_settings: Res<MeshAllocatorSettings>,
374    extracted_meshes: Res<ExtractedAssets<RenderMesh>>,
375    mut mesh_vertex_buffer_layouts: ResMut<MeshVertexBufferLayouts>,
376    render_device: Res<RenderDevice>,
377    render_queue: Res<RenderQueue>,
378) {
379    // Process removed or modified meshes.
380    mesh_allocator.free_meshes(&extracted_meshes);
381
382    // Process newly-added or modified meshes.
383    mesh_allocator.allocate_meshes(
384        &mesh_allocator_settings,
385        &extracted_meshes,
386        &mut mesh_vertex_buffer_layouts,
387        &render_device,
388        &render_queue,
389    );
390}
391
392impl MeshAllocator {
393    /// Returns the buffer and range within that buffer of the vertex data for
394    /// the mesh with the given ID.
395    ///
396    /// If the mesh wasn't allocated, returns None.
397    pub fn mesh_vertex_slice(&self, mesh_id: &AssetId<Mesh>) -> Option<MeshBufferSlice<'_>> {
398        self.mesh_slice_in_slab(mesh_id, *self.mesh_id_to_vertex_slab.get(mesh_id)?)
399    }
400
401    /// Returns the buffer and range within that buffer of the index data for
402    /// the mesh with the given ID.
403    ///
404    /// If the mesh has no index data or wasn't allocated, returns None.
405    pub fn mesh_index_slice(&self, mesh_id: &AssetId<Mesh>) -> Option<MeshBufferSlice<'_>> {
406        self.mesh_slice_in_slab(mesh_id, *self.mesh_id_to_index_slab.get(mesh_id)?)
407    }
408
409    /// Returns the IDs of the vertex buffer and index buffer respectively for
410    /// the mesh with the given ID.
411    ///
412    /// If the mesh wasn't allocated, or has no index data in the case of the
413    /// index buffer, the corresponding element in the returned tuple will be
414    /// None.
415    pub fn mesh_slabs(&self, mesh_id: &AssetId<Mesh>) -> (Option<SlabId>, Option<SlabId>) {
416        (
417            self.mesh_id_to_vertex_slab.get(mesh_id).cloned(),
418            self.mesh_id_to_index_slab.get(mesh_id).cloned(),
419        )
420    }
421
422    /// Get the number of allocated slabs
423    pub fn slab_count(&self) -> usize {
424        self.slabs.len()
425    }
426
427    /// Get the total size of all allocated slabs
428    pub fn slabs_size(&self) -> u64 {
429        self.slabs.iter().map(|slab| slab.1.buffer_size()).sum()
430    }
431
432    pub fn allocations(&self) -> usize {
433        self.mesh_id_to_index_slab.len()
434    }
435
436    /// Given a slab and a mesh with data located with it, returns the buffer
437    /// and range of that mesh data within the slab.
438    fn mesh_slice_in_slab(
439        &self,
440        mesh_id: &AssetId<Mesh>,
441        slab_id: SlabId,
442    ) -> Option<MeshBufferSlice<'_>> {
443        match self.slabs.get(&slab_id)? {
444            Slab::General(general_slab) => {
445                let slab_allocation = general_slab.resident_allocations.get(mesh_id)?;
446                Some(MeshBufferSlice {
447                    buffer: general_slab.buffer.as_ref()?,
448                    range: (slab_allocation.allocation.offset
449                        * general_slab.element_layout.elements_per_slot)
450                        ..((slab_allocation.allocation.offset + slab_allocation.slot_count)
451                            * general_slab.element_layout.elements_per_slot),
452                })
453            }
454
455            Slab::LargeObject(large_object_slab) => {
456                let buffer = large_object_slab.buffer.as_ref()?;
457                Some(MeshBufferSlice {
458                    buffer,
459                    range: 0..((buffer.size() / large_object_slab.element_layout.size) as u32),
460                })
461            }
462        }
463    }
464
465    /// Processes newly-loaded meshes, allocating room in the slabs for their
466    /// mesh data and performing upload operations as appropriate.
467    fn allocate_meshes(
468        &mut self,
469        mesh_allocator_settings: &MeshAllocatorSettings,
470        extracted_meshes: &ExtractedAssets<RenderMesh>,
471        mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts,
472        render_device: &RenderDevice,
473        render_queue: &RenderQueue,
474    ) {
475        let mut slabs_to_grow = SlabsToReallocate::default();
476
477        // Allocate.
478        for (mesh_id, mesh) in &extracted_meshes.extracted {
479            let vertex_buffer_size = mesh.get_vertex_buffer_size() as u64;
480            if vertex_buffer_size == 0 {
481                continue;
482            }
483            // Allocate vertex data. Note that we can only pack mesh vertex data
484            // together if the platform supports it.
485            let vertex_element_layout = ElementLayout::vertex(mesh_vertex_buffer_layouts, mesh);
486            if self.general_vertex_slabs_supported {
487                self.allocate(
488                    mesh_id,
489                    vertex_buffer_size,
490                    vertex_element_layout,
491                    &mut slabs_to_grow,
492                    mesh_allocator_settings,
493                );
494            } else {
495                self.allocate_large(mesh_id, vertex_element_layout);
496            }
497
498            // Allocate index data.
499            if let (Some(index_buffer_data), Some(index_element_layout)) =
500                (mesh.get_index_buffer_bytes(), ElementLayout::index(mesh))
501            {
502                self.allocate(
503                    mesh_id,
504                    index_buffer_data.len() as u64,
505                    index_element_layout,
506                    &mut slabs_to_grow,
507                    mesh_allocator_settings,
508                );
509            }
510        }
511
512        // Perform growth.
513        for (slab_id, slab_to_grow) in slabs_to_grow.0 {
514            self.reallocate_slab(render_device, render_queue, slab_id, slab_to_grow);
515        }
516
517        // Copy new mesh data in.
518        for (mesh_id, mesh) in &extracted_meshes.extracted {
519            self.copy_mesh_vertex_data(mesh_id, mesh, render_device, render_queue);
520            self.copy_mesh_index_data(mesh_id, mesh, render_device, render_queue);
521        }
522    }
523
524    /// Copies vertex array data from a mesh into the appropriate spot in the
525    /// slab.
526    fn copy_mesh_vertex_data(
527        &mut self,
528        mesh_id: &AssetId<Mesh>,
529        mesh: &Mesh,
530        render_device: &RenderDevice,
531        render_queue: &RenderQueue,
532    ) {
533        let Some(&slab_id) = self.mesh_id_to_vertex_slab.get(mesh_id) else {
534            return;
535        };
536
537        // Call the generic function.
538        self.copy_element_data(
539            mesh_id,
540            mesh.get_vertex_buffer_size(),
541            |slice| mesh.write_packed_vertex_buffer_data(slice),
542            BufferUsages::VERTEX,
543            slab_id,
544            render_device,
545            render_queue,
546        );
547    }
548
549    /// Copies index array data from a mesh into the appropriate spot in the
550    /// slab.
551    fn copy_mesh_index_data(
552        &mut self,
553        mesh_id: &AssetId<Mesh>,
554        mesh: &Mesh,
555        render_device: &RenderDevice,
556        render_queue: &RenderQueue,
557    ) {
558        let Some(&slab_id) = self.mesh_id_to_index_slab.get(mesh_id) else {
559            return;
560        };
561        let Some(index_data) = mesh.get_index_buffer_bytes() else {
562            return;
563        };
564
565        // Call the generic function.
566        self.copy_element_data(
567            mesh_id,
568            index_data.len(),
569            |slice| slice.copy_from_slice(index_data),
570            BufferUsages::INDEX,
571            slab_id,
572            render_device,
573            render_queue,
574        );
575    }
576
577    /// A generic function that copies either vertex or index data into a slab.
578    fn copy_element_data(
579        &mut self,
580        mesh_id: &AssetId<Mesh>,
581        len: usize,
582        fill_data: impl Fn(&mut [u8]),
583        buffer_usages: BufferUsages,
584        slab_id: SlabId,
585        render_device: &RenderDevice,
586        render_queue: &RenderQueue,
587    ) {
588        let Some(slab) = self.slabs.get_mut(&slab_id) else {
589            return;
590        };
591
592        match *slab {
593            Slab::General(ref mut general_slab) => {
594                let (Some(buffer), Some(allocated_range)) = (
595                    &general_slab.buffer,
596                    general_slab.pending_allocations.remove(mesh_id),
597                ) else {
598                    return;
599                };
600
601                let slot_size = general_slab.element_layout.slot_size();
602
603                // round up size to a multiple of the slot size to satisfy wgpu alignment requirements
604                if let Some(size) = BufferSize::new((len as u64).next_multiple_of(slot_size)) {
605                    // Write the data in.
606                    if let Some(mut buffer) = render_queue.write_buffer_with(
607                        buffer,
608                        allocated_range.allocation.offset as u64 * slot_size,
609                        size,
610                    ) {
611                        let slice = &mut buffer.as_mut()[..len];
612                        fill_data(slice);
613                    }
614                }
615
616                // Mark the allocation as resident.
617                general_slab
618                    .resident_allocations
619                    .insert(*mesh_id, allocated_range);
620            }
621
622            Slab::LargeObject(ref mut large_object_slab) => {
623                debug_assert!(large_object_slab.buffer.is_none());
624
625                // Create the buffer and its data in one go.
626                let buffer = render_device.create_buffer(&BufferDescriptor {
627                    label: Some(&format!(
628                        "large mesh slab {} ({}buffer)",
629                        slab_id,
630                        buffer_usages_to_str(buffer_usages)
631                    )),
632                    size: len as u64,
633                    usage: buffer_usages | BufferUsages::COPY_DST | self.extra_buffer_usages,
634                    mapped_at_creation: true,
635                });
636                {
637                    let slice = &mut buffer.slice(..).get_mapped_range_mut()[..len];
638                    fill_data(slice);
639                }
640                buffer.unmap();
641                large_object_slab.buffer = Some(buffer);
642            }
643        }
644    }
645
646    /// Frees allocations for meshes that were removed or modified this frame.
647    fn free_meshes(&mut self, extracted_meshes: &ExtractedAssets<RenderMesh>) {
648        let mut empty_slabs = <HashSet<_>>::default();
649
650        // TODO: Consider explicitly reusing allocations for changed meshes of the same size
651        let meshes_to_free = extracted_meshes
652            .removed
653            .iter()
654            .chain(extracted_meshes.modified.iter());
655
656        for mesh_id in meshes_to_free {
657            if let Some(slab_id) = self.mesh_id_to_vertex_slab.remove(mesh_id) {
658                self.free_allocation_in_slab(mesh_id, slab_id, &mut empty_slabs);
659            }
660            if let Some(slab_id) = self.mesh_id_to_index_slab.remove(mesh_id) {
661                self.free_allocation_in_slab(mesh_id, slab_id, &mut empty_slabs);
662            }
663        }
664
665        for empty_slab in empty_slabs {
666            self.slab_layouts.values_mut().for_each(|slab_ids| {
667                let idx = slab_ids.iter().position(|&slab_id| slab_id == empty_slab);
668                if let Some(idx) = idx {
669                    slab_ids.remove(idx);
670                }
671            });
672            self.slabs.remove(&empty_slab);
673        }
674    }
675
676    /// Given a slab and the ID of a mesh containing data in it, marks the
677    /// allocation as free.
678    ///
679    /// If this results in the slab becoming empty, this function adds the slab
680    /// to the `empty_slabs` set.
681    fn free_allocation_in_slab(
682        &mut self,
683        mesh_id: &AssetId<Mesh>,
684        slab_id: SlabId,
685        empty_slabs: &mut HashSet<SlabId>,
686    ) {
687        let Some(slab) = self.slabs.get_mut(&slab_id) else {
688            return;
689        };
690
691        match *slab {
692            Slab::General(ref mut general_slab) => {
693                let Some(slab_allocation) = general_slab
694                    .resident_allocations
695                    .remove(mesh_id)
696                    .or_else(|| general_slab.pending_allocations.remove(mesh_id))
697                else {
698                    return;
699                };
700
701                general_slab.allocator.free(slab_allocation.allocation);
702
703                if general_slab.is_empty() {
704                    empty_slabs.insert(slab_id);
705                }
706            }
707            Slab::LargeObject(_) => {
708                empty_slabs.insert(slab_id);
709            }
710        }
711    }
712
713    /// Allocates space for mesh data with the given byte size and layout in the
714    /// appropriate slab, creating that slab if necessary.
715    fn allocate(
716        &mut self,
717        mesh_id: &AssetId<Mesh>,
718        data_byte_len: u64,
719        layout: ElementLayout,
720        slabs_to_grow: &mut SlabsToReallocate,
721        settings: &MeshAllocatorSettings,
722    ) {
723        let data_element_count = data_byte_len.div_ceil(layout.size) as u32;
724        let data_slot_count = data_element_count.div_ceil(layout.elements_per_slot);
725
726        // If the mesh data is too large for a slab, give it a slab of its own.
727        if data_slot_count as u64 * layout.slot_size()
728            >= settings.large_threshold.min(settings.max_slab_size)
729        {
730            self.allocate_large(mesh_id, layout);
731        } else {
732            self.allocate_general(mesh_id, data_slot_count, layout, slabs_to_grow, settings);
733        }
734    }
735
736    /// Allocates space for mesh data with the given slot size and layout in the
737    /// appropriate general slab.
738    fn allocate_general(
739        &mut self,
740        mesh_id: &AssetId<Mesh>,
741        data_slot_count: u32,
742        layout: ElementLayout,
743        slabs_to_grow: &mut SlabsToReallocate,
744        settings: &MeshAllocatorSettings,
745    ) {
746        let candidate_slabs = self.slab_layouts.entry(layout).or_default();
747
748        // Loop through the slabs that accept elements of the appropriate type
749        // and try to allocate the mesh inside them. We go with the first one
750        // that succeeds.
751        let mut mesh_allocation = None;
752        for &slab_id in &*candidate_slabs {
753            let Some(Slab::General(slab)) = self.slabs.get_mut(&slab_id) else {
754                unreachable!("Slab not found")
755            };
756
757            let Some(allocation) = slab.allocator.allocate(data_slot_count) else {
758                continue;
759            };
760
761            // Try to fit the object in the slab, growing if necessary.
762            match slab.grow_if_necessary(allocation.offset + data_slot_count, settings) {
763                SlabGrowthResult::NoGrowthNeeded => {}
764                SlabGrowthResult::NeededGrowth(slab_to_reallocate) => {
765                    // If we already grew the slab this frame, don't replace the
766                    // `SlabToReallocate` entry. We want to keep the entry
767                    // corresponding to the size that the slab had at the start
768                    // of the frame, so that we can copy only the used portion
769                    // of the initial buffer to the new one.
770                    if let Entry::Vacant(vacant_entry) = slabs_to_grow.entry(slab_id) {
771                        vacant_entry.insert(slab_to_reallocate);
772                    }
773                }
774                SlabGrowthResult::CantGrow => continue,
775            }
776
777            mesh_allocation = Some(MeshAllocation {
778                slab_id,
779                slab_allocation: SlabAllocation {
780                    allocation,
781                    slot_count: data_slot_count,
782                },
783            });
784            break;
785        }
786
787        // If we still have no allocation, make a new slab.
788        if mesh_allocation.is_none() {
789            let new_slab_id = self.next_slab_id;
790            self.next_slab_id.0 = NonMaxU32::new(self.next_slab_id.0.get() + 1).unwrap_or_default();
791
792            let new_slab = GeneralSlab::new(
793                new_slab_id,
794                &mut mesh_allocation,
795                settings,
796                layout,
797                data_slot_count,
798            );
799
800            self.slabs.insert(new_slab_id, Slab::General(new_slab));
801            candidate_slabs.push(new_slab_id);
802            slabs_to_grow.insert(new_slab_id, SlabToReallocate::default());
803        }
804
805        let mesh_allocation = mesh_allocation.expect("Should have been able to allocate");
806
807        // Mark the allocation as pending. Don't copy it in just yet; further
808        // meshes loaded this frame may result in its final allocation location
809        // changing.
810        if let Some(Slab::General(general_slab)) = self.slabs.get_mut(&mesh_allocation.slab_id) {
811            general_slab
812                .pending_allocations
813                .insert(*mesh_id, mesh_allocation.slab_allocation);
814        };
815
816        self.record_allocation(mesh_id, mesh_allocation.slab_id, layout.class);
817    }
818
819    /// Allocates an object into its own dedicated slab.
820    fn allocate_large(&mut self, mesh_id: &AssetId<Mesh>, layout: ElementLayout) {
821        let new_slab_id = self.next_slab_id;
822        self.next_slab_id.0 = NonMaxU32::new(self.next_slab_id.0.get() + 1).unwrap_or_default();
823
824        self.record_allocation(mesh_id, new_slab_id, layout.class);
825
826        self.slabs.insert(
827            new_slab_id,
828            Slab::LargeObject(LargeObjectSlab {
829                buffer: None,
830                element_layout: layout,
831            }),
832        );
833    }
834
835    /// Reallocates a slab that needs to be resized, or allocates a new slab.
836    ///
837    /// This performs the actual growth operation that
838    /// [`GeneralSlab::grow_if_necessary`] scheduled. We do the growth in two
839    /// phases so that, if a slab grows multiple times in the same frame, only
840    /// one new buffer is reallocated, rather than reallocating the buffer
841    /// multiple times.
842    fn reallocate_slab(
843        &mut self,
844        render_device: &RenderDevice,
845        render_queue: &RenderQueue,
846        slab_id: SlabId,
847        slab_to_grow: SlabToReallocate,
848    ) {
849        let Some(Slab::General(slab)) = self.slabs.get_mut(&slab_id) else {
850            error!("Couldn't find slab {} to grow", slab_id);
851            return;
852        };
853
854        let old_buffer = slab.buffer.take();
855
856        let mut buffer_usages = BufferUsages::COPY_SRC | BufferUsages::COPY_DST;
857        match slab.element_layout.class {
858            ElementClass::Vertex => buffer_usages |= BufferUsages::VERTEX,
859            ElementClass::Index => buffer_usages |= BufferUsages::INDEX,
860        };
861
862        // Create the buffer.
863        let new_buffer = render_device.create_buffer(&BufferDescriptor {
864            label: Some(&format!(
865                "general mesh slab {} ({}buffer)",
866                slab_id,
867                buffer_usages_to_str(buffer_usages)
868            )),
869            size: slab.current_slot_capacity as u64 * slab.element_layout.slot_size(),
870            usage: buffer_usages | self.extra_buffer_usages,
871            mapped_at_creation: false,
872        });
873
874        slab.buffer = Some(new_buffer.clone());
875
876        let Some(old_buffer) = old_buffer else { return };
877
878        // In order to do buffer copies, we need a command encoder.
879        let mut encoder = render_device.create_command_encoder(&CommandEncoderDescriptor {
880            label: Some("slab resize encoder"),
881        });
882
883        // Copy the data from the old buffer into the new one.
884        encoder.copy_buffer_to_buffer(
885            &old_buffer,
886            0,
887            &new_buffer,
888            0,
889            slab_to_grow.old_slot_capacity as u64 * slab.element_layout.slot_size(),
890        );
891
892        let command_buffer = encoder.finish();
893        render_queue.submit([command_buffer]);
894    }
895
896    /// Records the location of the given newly-allocated mesh data in the
897    /// [`Self::mesh_id_to_vertex_slab`] or [`Self::mesh_id_to_index_slab`]
898    /// tables as appropriate.
899    fn record_allocation(
900        &mut self,
901        mesh_id: &AssetId<Mesh>,
902        slab_id: SlabId,
903        element_class: ElementClass,
904    ) {
905        match element_class {
906            ElementClass::Vertex => {
907                self.mesh_id_to_vertex_slab.insert(*mesh_id, slab_id);
908            }
909            ElementClass::Index => {
910                self.mesh_id_to_index_slab.insert(*mesh_id, slab_id);
911            }
912        }
913    }
914}
915
916impl GeneralSlab {
917    /// Creates a new growable slab big enough to hold a single element of
918    /// `data_slot_count` size with the given `layout`.
919    fn new(
920        new_slab_id: SlabId,
921        mesh_allocation: &mut Option<MeshAllocation>,
922        settings: &MeshAllocatorSettings,
923        layout: ElementLayout,
924        data_slot_count: u32,
925    ) -> GeneralSlab {
926        let initial_slab_slot_capacity = (settings.min_slab_size.div_ceil(layout.slot_size())
927            as u32)
928            .max(offset_allocator::ext::min_allocator_size(data_slot_count));
929        let max_slab_slot_capacity = (settings.max_slab_size.div_ceil(layout.slot_size()) as u32)
930            .max(offset_allocator::ext::min_allocator_size(data_slot_count));
931
932        let mut new_slab = GeneralSlab {
933            allocator: Allocator::new(max_slab_slot_capacity),
934            buffer: None,
935            resident_allocations: HashMap::default(),
936            pending_allocations: HashMap::default(),
937            element_layout: layout,
938            current_slot_capacity: initial_slab_slot_capacity,
939        };
940
941        // This should never fail.
942        if let Some(allocation) = new_slab.allocator.allocate(data_slot_count) {
943            *mesh_allocation = Some(MeshAllocation {
944                slab_id: new_slab_id,
945                slab_allocation: SlabAllocation {
946                    slot_count: data_slot_count,
947                    allocation,
948                },
949            });
950        }
951
952        new_slab
953    }
954
955    /// Checks to see if the size of this slab is at least `new_size_in_slots`
956    /// and grows the slab if it isn't.
957    ///
958    /// The returned [`SlabGrowthResult`] describes whether the slab needed to
959    /// grow and whether, if so, it was successful in doing so.
960    fn grow_if_necessary(
961        &mut self,
962        new_size_in_slots: u32,
963        settings: &MeshAllocatorSettings,
964    ) -> SlabGrowthResult {
965        // Is the slab big enough already?
966        let initial_slot_capacity = self.current_slot_capacity;
967        if self.current_slot_capacity >= new_size_in_slots {
968            return SlabGrowthResult::NoGrowthNeeded;
969        }
970
971        // Try to grow in increments of `MeshAllocatorSettings::growth_factor`
972        // until we're big enough.
973        while self.current_slot_capacity < new_size_in_slots {
974            let new_slab_slot_capacity =
975                ((self.current_slot_capacity as f64 * settings.growth_factor).ceil() as u32)
976                    .min((settings.max_slab_size / self.element_layout.slot_size()) as u32);
977            if new_slab_slot_capacity == self.current_slot_capacity {
978                // The slab is full.
979                return SlabGrowthResult::CantGrow;
980            }
981
982            self.current_slot_capacity = new_slab_slot_capacity;
983        }
984
985        // Tell our caller what we did.
986        SlabGrowthResult::NeededGrowth(SlabToReallocate {
987            old_slot_capacity: initial_slot_capacity,
988        })
989    }
990}
991
992impl ElementLayout {
993    /// Creates an [`ElementLayout`] for mesh data of the given class (vertex or
994    /// index) with the given byte size.
995    fn new(class: ElementClass, size: u64) -> ElementLayout {
996        const {
997            assert!(4 == COPY_BUFFER_ALIGNMENT);
998        }
999        // this is equivalent to `4 / gcd(4,size)` but lets us not implement gcd.
1000        // ping @atlv if above assert ever fails (likely never)
1001        let elements_per_slot = [1, 4, 2, 4][size as usize & 3];
1002        ElementLayout {
1003            class,
1004            size,
1005            // Make sure that slot boundaries begin and end on
1006            // `COPY_BUFFER_ALIGNMENT`-byte (4-byte) boundaries.
1007            elements_per_slot,
1008        }
1009    }
1010
1011    fn slot_size(&self) -> u64 {
1012        self.size * self.elements_per_slot as u64
1013    }
1014
1015    /// Creates the appropriate [`ElementLayout`] for the given mesh's vertex
1016    /// data.
1017    fn vertex(
1018        mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts,
1019        mesh: &Mesh,
1020    ) -> ElementLayout {
1021        let mesh_vertex_buffer_layout =
1022            mesh.get_mesh_vertex_buffer_layout(mesh_vertex_buffer_layouts);
1023        ElementLayout::new(
1024            ElementClass::Vertex,
1025            mesh_vertex_buffer_layout.0.layout().array_stride,
1026        )
1027    }
1028
1029    /// Creates the appropriate [`ElementLayout`] for the given mesh's index
1030    /// data.
1031    fn index(mesh: &Mesh) -> Option<ElementLayout> {
1032        let size = match mesh.indices()? {
1033            Indices::U16(_) => 2,
1034            Indices::U32(_) => 4,
1035        };
1036        Some(ElementLayout::new(ElementClass::Index, size))
1037    }
1038}
1039
1040impl GeneralSlab {
1041    /// Returns true if this slab is empty.
1042    fn is_empty(&self) -> bool {
1043        self.resident_allocations.is_empty() && self.pending_allocations.is_empty()
1044    }
1045}
1046
1047/// Returns a string describing the given buffer usages.
1048fn buffer_usages_to_str(buffer_usages: BufferUsages) -> &'static str {
1049    if buffer_usages.contains(BufferUsages::VERTEX) {
1050        "vertex "
1051    } else if buffer_usages.contains(BufferUsages::INDEX) {
1052        "index "
1053    } else {
1054        ""
1055    }
1056}