1use 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
35pub struct MeshAllocatorPlugin;
37
38#[derive(Resource)]
54pub struct MeshAllocator {
55 slabs: HashMap<SlabId, Slab>,
57
58 slab_layouts: HashMap<ElementLayout, Vec<SlabId>>,
63
64 mesh_id_to_vertex_slab: HashMap<AssetId<Mesh>, SlabId>,
66
67 mesh_id_to_index_slab: HashMap<AssetId<Mesh>, SlabId>,
69
70 next_slab_id: SlabId,
72
73 general_vertex_slabs_supported: bool,
80}
81
82#[derive(Resource)]
88pub struct MeshAllocatorSettings {
89 pub min_slab_size: u64,
93
94 pub max_slab_size: u64,
100
101 pub large_threshold: u64,
110
111 pub growth_factor: f64,
119}
120
121impl Default for MeshAllocatorSettings {
122 fn default() -> Self {
123 Self {
124 min_slab_size: 1024 * 1024,
126 max_slab_size: 1024 * 1024 * 512,
128 large_threshold: 1024 * 1024 * 256,
130 growth_factor: 1.5,
132 }
133 }
134}
135
136pub struct MeshBufferSlice<'a> {
139 pub buffer: &'a Buffer,
141
142 pub range: Range<u32>,
152}
153
154#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, Debug)]
156#[repr(transparent)]
157struct SlabId(u32);
158
159#[allow(clippy::large_enum_variant)]
161enum Slab {
162 General(GeneralSlab),
164 LargeObject(LargeObjectSlab),
166}
167
168struct GeneralSlab {
174 allocator: Allocator,
176
177 buffer: Option<Buffer>,
184
185 resident_allocations: HashMap<AssetId<Mesh>, SlabAllocation>,
189
190 pending_allocations: HashMap<AssetId<Mesh>, SlabAllocation>,
194
195 element_layout: ElementLayout,
197
198 slot_capacity: u32,
200}
201
202struct LargeObjectSlab {
209 buffer: Option<Buffer>,
213
214 element_layout: ElementLayout,
216}
217
218#[derive(Clone, Copy, PartialEq, Eq, Hash)]
220enum ElementClass {
221 Vertex,
223 Index,
225}
226
227#[derive(Clone, Copy, PartialEq, Eq, Hash)]
241struct ElementLayout {
242 class: ElementClass,
244
245 size: u64,
247
248 elements_per_slot: u32,
254}
255
256struct MeshAllocation {
258 slab_id: SlabId,
260 slab_allocation: SlabAllocation,
262}
263
264#[derive(Clone)]
266struct SlabAllocation {
267 allocation: Allocation,
269 slot_count: u32,
271}
272
273#[derive(Default, Deref, DerefMut)]
275struct SlabsToReallocate(HashMap<SlabId, SlabToReallocate>);
276
277#[derive(Default)]
280struct SlabToReallocate {
281 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 render_app.init_resource::<MeshAllocator>();
316 }
317}
318
319impl FromWorld for MeshAllocator {
320 fn from_world(world: &mut World) -> Self {
321 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
340pub 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 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 mesh_allocator.free_meshes(&extracted_meshes);
361}
362
363impl MeshAllocator {
364 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 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 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 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 for (mesh_id, mesh) in &extracted_meshes.extracted {
423 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 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 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 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 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 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 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 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 #[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 if let Some(size) = BufferSize::new((len as u64).next_multiple_of(slot_size)) {
546 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 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 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 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 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 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 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 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 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 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 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 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 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 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 let mut encoder = render_device.create_command_encoder(&CommandEncoderDescriptor {
805 label: Some("slab resize encoder"),
806 });
807
808 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 *src_slab_allocation = dest_slab_allocation.clone();
827 }
828
829 let command_buffer = encoder.finish();
830 render_queue.submit([command_buffer]);
831 }
832
833 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 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 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 fn try_grow(&mut self, settings: &MeshAllocatorSettings) -> Result<SlabToReallocate, ()> {
894 '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 return Err(());
905 }
906
907 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 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 continue 'grow;
931 }
932 }
933 }
934
935 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 continue 'grow;
945 }
946 }
947 }
948
949 return Ok(slab_to_grow);
950 }
951 }
952}
953
954impl ElementLayout {
955 fn new(class: ElementClass, size: u64) -> ElementLayout {
958 ElementLayout {
959 class,
960 size,
961 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 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 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 fn is_empty(&self) -> bool {
999 self.resident_allocations.is_empty() && self.pending_allocations.is_empty()
1000 }
1001}
1002
1003fn 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
1015fn 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}