1use alloc::borrow::Cow;
4use bevy_mesh::Indices;
5
6use bevy_app::{App, Plugin};
7use bevy_asset::AssetId;
8use bevy_derive::{Deref, DerefMut};
9use bevy_ecs::{
10 resource::Resource,
11 schedule::IntoScheduleConfigs as _,
12 system::{Res, ResMut},
13 world::{FromWorld, World},
14};
15use wgpu::{BufferUsages, DownlevelFlags, COPY_BUFFER_ALIGNMENT};
16
17#[cfg(feature = "morph")]
18use bevy_mesh::morph::MorphAttributes;
19
20use crate::{
21 mesh::{Mesh, MeshVertexBufferLayouts, RenderMesh},
22 render_asset::{prepare_assets, ExtractedAssets},
23 renderer::{RenderAdapter, RenderDevice, RenderQueue},
24 slab_allocator::{
25 Slab, SlabAllocationBufferSlice, SlabAllocator, SlabAllocatorSettings, SlabId, SlabItem,
26 SlabItemLayout,
27 },
28 GpuResourceAppExt, Render, RenderApp, RenderSystems,
29};
30
31pub struct MeshAllocatorPlugin;
33
34#[derive(Resource, Deref, DerefMut)]
45pub struct MeshAllocator {
46 #[deref]
48 slab_allocator: SlabAllocator<MeshSlabItem>,
49
50 general_vertex_slabs_supported: bool,
57}
58
59#[derive(Resource, Deref, DerefMut)]
65pub struct MeshAllocatorSettings {
66 #[deref]
67 pub slab_allocator_settings: SlabAllocatorSettings,
68
69 pub extra_buffer_usages: BufferUsages,
71}
72
73impl Default for MeshAllocatorSettings {
74 fn default() -> MeshAllocatorSettings {
75 MeshAllocatorSettings {
76 slab_allocator_settings: SlabAllocatorSettings::default(),
77 extra_buffer_usages: BufferUsages::empty(),
78 }
79 }
80}
81
82#[cfg(feature = "morph")]
87static MORPH_ATTRIBUTE_ELEMENT_LAYOUT: ElementLayout = ElementLayout {
88 class: ElementClass::MorphTarget,
89 size: size_of::<MorphAttributes>() as u64,
90 elements_per_slot: 1,
91};
92
93pub type MeshSlabId = SlabId<MeshSlabItem>;
95
96pub type MeshBufferSlice<'a> = SlabAllocationBufferSlice<'a, MeshSlabItem>;
99
100pub struct MeshSlabItem;
103
104impl SlabItem for MeshSlabItem {
105 type Key = MeshAllocationKey;
106 type Layout = ElementLayout;
107 fn label() -> Cow<'static, str> {
108 "mesh".into()
109 }
110}
111
112#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
114pub struct MeshSlabs {
115 pub vertex_slab_id: MeshSlabId,
117 pub index_slab_id: Option<MeshSlabId>,
119 #[cfg(feature = "morph")]
122 pub morph_target_slab_id: Option<MeshSlabId>,
123}
124
125impl Slab<MeshSlabItem> {
126 #[cfg(feature = "morph")]
128 pub fn element_class(&self) -> ElementClass {
129 self.element_layout().class
130 }
131}
132
133#[derive(Clone, Copy, PartialEq, Eq, Hash)]
135pub struct MeshAllocationKey {
136 pub mesh_id: AssetId<Mesh>,
138 pub class: ElementClass,
140}
141
142impl MeshAllocationKey {
143 pub fn new(mesh_id: AssetId<Mesh>, class: ElementClass) -> Self {
146 Self { mesh_id, class }
147 }
148}
149
150#[derive(Clone, Copy, PartialEq, Eq, Hash)]
152pub enum ElementClass {
153 Vertex,
155 Index,
157 #[cfg(feature = "morph")]
158 MorphTarget,
160}
161
162#[derive(Clone, Copy, PartialEq, Eq, Hash)]
176pub struct ElementLayout {
177 class: ElementClass,
179
180 size: u64,
182
183 elements_per_slot: u32,
189}
190
191impl Plugin for MeshAllocatorPlugin {
192 fn build(&self, app: &mut App) {
193 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
194 return;
195 };
196
197 render_app
198 .init_resource::<MeshAllocatorSettings>()
199 .add_systems(
200 Render,
201 allocate_and_free_meshes
202 .in_set(RenderSystems::PrepareAssets)
203 .before(prepare_assets::<RenderMesh>),
204 );
205 }
206
207 fn finish(&self, app: &mut App) {
208 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
209 return;
210 };
211
212 render_app.init_gpu_resource::<MeshAllocator>();
215 }
216}
217
218impl FromWorld for MeshAllocator {
219 fn from_world(world: &mut World) -> Self {
220 let render_adapter = world.resource::<RenderAdapter>();
223 let general_vertex_slabs_supported = render_adapter
224 .get_downlevel_capabilities()
225 .flags
226 .contains(DownlevelFlags::BASE_VERTEX);
227
228 let mesh_allocator_settings = world.resource::<MeshAllocatorSettings>();
231 let mut slab_allocator = SlabAllocator::new();
232 slab_allocator.extra_buffer_usages |= mesh_allocator_settings.extra_buffer_usages;
233
234 Self {
235 slab_allocator,
236 general_vertex_slabs_supported,
237 }
238 }
239}
240
241pub fn allocate_and_free_meshes(
244 mut mesh_allocator: ResMut<MeshAllocator>,
245 mesh_allocator_settings: Res<MeshAllocatorSettings>,
246 extracted_meshes: Res<ExtractedAssets<RenderMesh>>,
247 mut mesh_vertex_buffer_layouts: ResMut<MeshVertexBufferLayouts>,
248 render_device: Res<RenderDevice>,
249 render_queue: Res<RenderQueue>,
250) {
251 mesh_allocator.free_meshes(&extracted_meshes);
253
254 mesh_allocator.allocate_meshes(
256 &mesh_allocator_settings,
257 &extracted_meshes,
258 &mut mesh_vertex_buffer_layouts,
259 &render_device,
260 &render_queue,
261 );
262}
263
264impl MeshAllocator {
265 pub fn mesh_vertex_slice(&self, mesh_id: &AssetId<Mesh>) -> Option<MeshBufferSlice<'_>> {
270 self.slab_allocation_slice(
271 &MeshAllocationKey::new(*mesh_id, ElementClass::Vertex),
272 *self.mesh_id_to_vertex_slab(mesh_id)?,
273 )
274 }
275
276 pub fn mesh_index_slice(&self, mesh_id: &AssetId<Mesh>) -> Option<MeshBufferSlice<'_>> {
281 self.slab_allocation_slice(
282 &MeshAllocationKey::new(*mesh_id, ElementClass::Index),
283 *self.mesh_id_to_index_slab(mesh_id)?,
284 )
285 }
286
287 #[cfg(feature = "morph")]
292 pub fn mesh_morph_target_slice(&self, mesh_id: &AssetId<Mesh>) -> Option<MeshBufferSlice<'_>> {
293 self.slab_allocation_slice(
294 &MeshAllocationKey::new(*mesh_id, ElementClass::MorphTarget),
295 *self.mesh_id_to_morph_target_slab(mesh_id)?,
296 )
297 }
298
299 pub fn mesh_slabs(&self, mesh_id: &AssetId<Mesh>) -> Option<MeshSlabs> {
306 Some(MeshSlabs {
307 vertex_slab_id: self.mesh_id_to_vertex_slab(mesh_id).cloned()?,
308 index_slab_id: self.mesh_id_to_index_slab(mesh_id).cloned(),
309 #[cfg(feature = "morph")]
310 morph_target_slab_id: self.mesh_id_to_morph_target_slab(mesh_id).cloned(),
311 })
312 }
313
314 pub fn index_allocation_count(&self) -> usize {
317 self.key_to_slab
318 .keys()
319 .filter(|key| key.class == ElementClass::Index)
320 .count()
321 }
322
323 fn mesh_id_to_vertex_slab(&self, mesh_id: &AssetId<Mesh>) -> Option<&SlabId<MeshSlabItem>> {
326 self.key_to_slab
327 .get(&MeshAllocationKey::new(*mesh_id, ElementClass::Vertex))
328 }
329
330 fn mesh_id_to_index_slab(&self, mesh_id: &AssetId<Mesh>) -> Option<&SlabId<MeshSlabItem>> {
333 self.key_to_slab
334 .get(&MeshAllocationKey::new(*mesh_id, ElementClass::Index))
335 }
336
337 #[cfg(feature = "morph")]
340 fn mesh_id_to_morph_target_slab(
341 &self,
342 mesh_id: &AssetId<Mesh>,
343 ) -> Option<&SlabId<MeshSlabItem>> {
344 self.key_to_slab
345 .get(&MeshAllocationKey::new(*mesh_id, ElementClass::MorphTarget))
346 }
347
348 #[cfg(feature = "morph")]
350 pub fn morph_target_slabs(&self) -> impl Iterator<Item = MeshSlabId> {
351 self.slabs.iter().filter_map(|(slab_id, slab)| {
352 if matches!(slab.element_class(), ElementClass::MorphTarget) {
353 Some(*slab_id)
354 } else {
355 None
356 }
357 })
358 }
359
360 fn allocate_meshes(
363 &mut self,
364 mesh_allocator_settings: &MeshAllocatorSettings,
365 extracted_meshes: &ExtractedAssets<RenderMesh>,
366 mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts,
367 render_device: &RenderDevice,
368 render_queue: &RenderQueue,
369 ) {
370 let mut allocation_stage = self.slab_allocator.stage_allocation();
371
372 for (mesh_id, mesh) in &extracted_meshes.extracted {
374 let vertex_buffer_size = mesh.get_vertex_buffer_size() as u64;
375 if vertex_buffer_size == 0 {
376 continue;
377 }
378
379 let vertex_element_layout = ElementLayout::vertex(mesh_vertex_buffer_layouts, mesh);
382 if self.general_vertex_slabs_supported {
383 allocation_stage.allocate(
384 &MeshAllocationKey::new(*mesh_id, ElementClass::Vertex),
385 vertex_buffer_size,
386 vertex_element_layout,
387 mesh_allocator_settings,
388 );
389 } else {
390 allocation_stage.allocate_large(
391 &MeshAllocationKey::new(*mesh_id, ElementClass::Vertex),
392 vertex_element_layout,
393 );
394 }
395
396 if let (Some(index_buffer_data), Some(index_element_layout)) =
398 (mesh.get_index_buffer_bytes(), ElementLayout::index(mesh))
399 {
400 allocation_stage.allocate(
401 &MeshAllocationKey::new(*mesh_id, ElementClass::Index),
402 index_buffer_data.len() as u64,
403 index_element_layout,
404 mesh_allocator_settings,
405 );
406 }
407
408 #[cfg(feature = "morph")]
410 if let Some(morph_targets) = mesh.get_morph_targets() {
411 allocation_stage.allocate(
412 &MeshAllocationKey::new(*mesh_id, ElementClass::MorphTarget),
413 morph_targets.len() as u64 * size_of::<MorphAttributes>() as u64,
414 MORPH_ATTRIBUTE_ELEMENT_LAYOUT,
415 mesh_allocator_settings,
416 );
417 }
418 }
419
420 allocation_stage.commit(render_device, render_queue);
422
423 for (mesh_id, mesh) in &extracted_meshes.extracted {
425 self.copy_mesh_vertex_data(mesh_id, mesh, render_device, render_queue);
426 self.copy_mesh_index_data(mesh_id, mesh, render_device, render_queue);
427 #[cfg(feature = "morph")]
428 self.copy_mesh_morph_target_data(mesh_id, mesh, render_device, render_queue);
429 }
430 }
431
432 fn copy_mesh_vertex_data(
435 &mut self,
436 mesh_id: &AssetId<Mesh>,
437 mesh: &Mesh,
438 render_device: &RenderDevice,
439 render_queue: &RenderQueue,
440 ) {
441 self.copy_element_data(
443 &MeshAllocationKey::new(*mesh_id, ElementClass::Vertex),
444 mesh.get_vertex_buffer_size(),
445 |slice| mesh.write_packed_vertex_buffer_data(slice),
446 render_device,
447 render_queue,
448 );
449 }
450
451 fn copy_mesh_index_data(
454 &mut self,
455 mesh_id: &AssetId<Mesh>,
456 mesh: &Mesh,
457 render_device: &RenderDevice,
458 render_queue: &RenderQueue,
459 ) {
460 let Some(index_data) = mesh.get_index_buffer_bytes() else {
461 return;
462 };
463
464 self.copy_element_data(
466 &MeshAllocationKey::new(*mesh_id, ElementClass::Index),
467 index_data.len(),
468 |mut slice| slice.copy_from_slice(index_data),
469 render_device,
470 render_queue,
471 );
472 }
473
474 #[cfg(feature = "morph")]
477 fn copy_mesh_morph_target_data(
478 &mut self,
479 mesh_id: &AssetId<Mesh>,
480 mesh: &Mesh,
481 render_device: &RenderDevice,
482 render_queue: &RenderQueue,
483 ) {
484 let Some(morph_targets) = mesh.get_morph_targets() else {
485 return;
486 };
487
488 self.copy_element_data(
490 &MeshAllocationKey::new(*mesh_id, ElementClass::MorphTarget),
491 size_of_val(morph_targets),
492 |mut slice| slice.copy_from_slice(bytemuck::cast_slice(morph_targets)),
493 render_device,
494 render_queue,
495 );
496 }
497
498 fn free_meshes(&mut self, extracted_meshes: &ExtractedAssets<RenderMesh>) {
500 let mut deallocation_stage = self.slab_allocator.stage_deallocation();
501
502 let meshes_to_free = extracted_meshes
505 .removed
506 .iter()
507 .chain(extracted_meshes.modified.iter());
508
509 for mesh_id in meshes_to_free {
510 deallocation_stage.free(&MeshAllocationKey::new(*mesh_id, ElementClass::Vertex));
511 deallocation_stage.free(&MeshAllocationKey::new(*mesh_id, ElementClass::Index));
512 #[cfg(feature = "morph")]
513 deallocation_stage.free(&MeshAllocationKey::new(*mesh_id, ElementClass::MorphTarget));
514 }
515
516 deallocation_stage.commit();
517 }
518}
519
520impl ElementLayout {
521 fn new(class: ElementClass, size: u64) -> ElementLayout {
524 const {
525 assert!(4 == COPY_BUFFER_ALIGNMENT);
526 }
527 let elements_per_slot = [1, 4, 2, 4][size as usize & 3];
530 ElementLayout {
531 class,
532 size,
533 elements_per_slot,
536 }
537 }
538
539 fn vertex(
542 mesh_vertex_buffer_layouts: &mut MeshVertexBufferLayouts,
543 mesh: &Mesh,
544 ) -> ElementLayout {
545 let mesh_vertex_buffer_layout =
546 mesh.get_mesh_vertex_buffer_layout(mesh_vertex_buffer_layouts);
547 ElementLayout::new(
548 ElementClass::Vertex,
549 mesh_vertex_buffer_layout.0.layout().array_stride,
550 )
551 }
552
553 fn index(mesh: &Mesh) -> Option<ElementLayout> {
556 let size = match mesh.indices()? {
557 Indices::U16(_) => 2,
558 Indices::U32(_) => 4,
559 };
560 Some(ElementLayout::new(ElementClass::Index, size))
561 }
562}
563
564impl SlabItemLayout for ElementLayout {
565 fn size(&self) -> u64 {
566 self.size
567 }
568
569 fn elements_per_slot(&self) -> u32 {
570 self.elements_per_slot
571 }
572
573 fn buffer_usages(&self) -> BufferUsages {
574 self.class.buffer_usages()
575 }
576}
577
578impl ElementClass {
579 fn buffer_usages(&self) -> BufferUsages {
582 match *self {
583 ElementClass::Vertex => BufferUsages::VERTEX,
584 ElementClass::Index => BufferUsages::INDEX,
585 #[cfg(feature = "morph")]
586 ElementClass::MorphTarget => BufferUsages::STORAGE,
587 }
588 }
589}