1use 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
37pub struct MeshAllocatorPlugin;
39
40#[derive(Resource)]
56pub struct MeshAllocator {
57 slabs: HashMap<SlabId, Slab>,
59
60 slab_layouts: HashMap<ElementLayout, Vec<SlabId>>,
65
66 mesh_id_to_vertex_slab: HashMap<AssetId<Mesh>, SlabId>,
68
69 mesh_id_to_index_slab: HashMap<AssetId<Mesh>, SlabId>,
71
72 next_slab_id: SlabId,
74
75 general_vertex_slabs_supported: bool,
82
83 pub extra_buffer_usages: BufferUsages,
85}
86
87#[derive(Resource)]
93pub struct MeshAllocatorSettings {
94 pub min_slab_size: u64,
98
99 pub max_slab_size: u64,
105
106 pub large_threshold: u64,
115
116 pub growth_factor: f64,
124}
125
126impl Default for MeshAllocatorSettings {
127 fn default() -> Self {
128 Self {
129 min_slab_size: 1024 * 1024,
131 max_slab_size: 1024 * 1024 * 512,
133 large_threshold: 1024 * 1024 * 256,
135 growth_factor: 1.5,
137 }
138 }
139}
140
141pub struct MeshBufferSlice<'a> {
144 pub buffer: &'a Buffer,
146
147 pub range: Range<u32>,
157}
158
159#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
161#[repr(transparent)]
162pub struct SlabId(pub NonMaxU32);
163
164#[expect(
166 clippy::large_enum_variant,
167 reason = "See https://github.com/bevyengine/bevy/issues/19220"
168)]
169enum Slab {
170 General(GeneralSlab),
172 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
185struct GeneralSlab {
191 allocator: Allocator,
193
194 buffer: Option<Buffer>,
201
202 resident_allocations: HashMap<AssetId<Mesh>, SlabAllocation>,
206
207 pending_allocations: HashMap<AssetId<Mesh>, SlabAllocation>,
211
212 element_layout: ElementLayout,
214
215 current_slot_capacity: u32,
217}
218
219struct LargeObjectSlab {
226 buffer: Option<Buffer>,
230
231 element_layout: ElementLayout,
233}
234
235#[derive(Clone, Copy, PartialEq, Eq, Hash)]
237enum ElementClass {
238 Vertex,
240 Index,
242}
243
244enum SlabGrowthResult {
246 NoGrowthNeeded,
248 NeededGrowth(SlabToReallocate),
252 CantGrow,
254}
255
256#[derive(Clone, Copy, PartialEq, Eq, Hash)]
270struct ElementLayout {
271 class: ElementClass,
273
274 size: u64,
276
277 elements_per_slot: u32,
283}
284
285struct MeshAllocation {
287 slab_id: SlabId,
289 slab_allocation: SlabAllocation,
291}
292
293#[derive(Clone)]
295struct SlabAllocation {
296 allocation: Allocation,
298 slot_count: u32,
300}
301
302#[derive(Default, Deref, DerefMut)]
304struct SlabsToReallocate(HashMap<SlabId, SlabToReallocate>);
305
306#[derive(Default)]
309struct SlabToReallocate {
310 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 render_app.init_resource::<MeshAllocator>();
344 }
345}
346
347impl FromWorld for MeshAllocator {
348 fn from_world(world: &mut World) -> Self {
349 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
369pub 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 mesh_allocator.free_meshes(&extracted_meshes);
381
382 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 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 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 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 pub fn slab_count(&self) -> usize {
424 self.slabs.len()
425 }
426
427 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 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 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 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 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 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 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 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 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 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 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 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 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 if let Some(size) = BufferSize::new((len as u64).next_multiple_of(slot_size)) {
605 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 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 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 fn free_meshes(&mut self, extracted_meshes: &ExtractedAssets<RenderMesh>) {
648 let mut empty_slabs = <HashSet<_>>::default();
649
650 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 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 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 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 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 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 match slab.grow_if_necessary(allocation.offset + data_slot_count, settings) {
763 SlabGrowthResult::NoGrowthNeeded => {}
764 SlabGrowthResult::NeededGrowth(slab_to_reallocate) => {
765 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 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 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 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 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 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 let mut encoder = render_device.create_command_encoder(&CommandEncoderDescriptor {
880 label: Some("slab resize encoder"),
881 });
882
883 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 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 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 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 fn grow_if_necessary(
961 &mut self,
962 new_size_in_slots: u32,
963 settings: &MeshAllocatorSettings,
964 ) -> SlabGrowthResult {
965 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 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 return SlabGrowthResult::CantGrow;
980 }
981
982 self.current_slot_capacity = new_slab_slot_capacity;
983 }
984
985 SlabGrowthResult::NeededGrowth(SlabToReallocate {
987 old_slot_capacity: initial_slot_capacity,
988 })
989 }
990}
991
992impl ElementLayout {
993 fn new(class: ElementClass, size: u64) -> ElementLayout {
996 const {
997 assert!(4 == COPY_BUFFER_ALIGNMENT);
998 }
999 let elements_per_slot = [1, 4, 2, 4][size as usize & 3];
1002 ElementLayout {
1003 class,
1004 size,
1005 elements_per_slot,
1008 }
1009 }
1010
1011 fn slot_size(&self) -> u64 {
1012 self.size * self.elements_per_slot as u64
1013 }
1014
1015 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 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 fn is_empty(&self) -> bool {
1043 self.resident_allocations.is_empty() && self.pending_allocations.is_empty()
1044 }
1045}
1046
1047fn 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}