bevy_render/mesh/
allocator.rs

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