1pub mod buffer_info;
4pub mod error;
5pub mod geometry;
6pub mod mesh;
7pub mod meta;
8pub mod morphs;
9#[cfg(feature = "lod")]
10pub mod skin_lod;
11pub mod skins;
12
13use std::collections::HashMap;
14
15use awsm_renderer_core::buffers::{BufferDescriptor, BufferUsage};
16use awsm_renderer_core::renderer::AwsmRendererWebGpu;
17use glam::Mat4;
18use slotmap::{new_key_type, DenseSlotMap, SecondaryMap};
19
20use crate::bind_groups::{BindGroupCreate, BindGroups};
21use crate::bounds::Aabb;
22use crate::buffer::dynamic_storage::DynamicStorageBuffer;
23use crate::instances::Instances;
24use crate::materials::Materials;
25use crate::meshes::buffer_info::MeshBufferVertexInfo;
26use crate::transforms::{Transform, TransformKey, Transforms};
27use crate::{AwsmRenderer, AwsmRendererLogging};
28use buffer_info::{MeshBufferInfoKey, MeshBufferInfos};
29use meta::{MeshMeta, MESH_META_INITIAL_CAPACITY};
30use skins::{SkinKey, Skins};
31
32use error::{AwsmMeshError, Result};
33use mesh::{BillboardMode, Mesh};
34use morphs::{GeometryMorphKey, MaterialMorphKey, Morphs};
35
36impl AwsmRenderer {
37 pub fn duplicate_mesh_with_transform(
39 &mut self,
40 mesh_key: MeshKey,
41 new_transform_key: TransformKey,
42 ) -> crate::error::Result<MeshKey> {
43 let new_mesh_key = self.meshes.duplicate_with_transform(
44 mesh_key,
45 new_transform_key,
46 &self.materials,
47 &self.transforms,
48 )?;
49
50 self.render_passes
51 .material_transparent
52 .pipelines
53 .clone_render_pipeline_key(mesh_key, new_mesh_key);
54
55 self.sync_spatial_for_mesh(new_mesh_key);
56
57 Ok(new_mesh_key)
58 }
59
60 pub fn clone_mesh(&mut self, mesh_key: MeshKey) -> crate::error::Result<MeshKey> {
62 let transform_key = self.meshes.get(mesh_key)?.transform_key;
63 let local_transform = self.transforms.get_local(transform_key)?.clone();
64 let parent_transform = self.transforms.get_parent(transform_key).ok();
65 let new_transform_key = self.transforms.insert(local_transform, parent_transform);
66
67 self.duplicate_mesh_with_transform(mesh_key, new_transform_key)
68 }
69
70 pub fn duplicate_meshes_by_transform_key(
74 &mut self,
75 transform_key: TransformKey,
76 ) -> crate::error::Result<(TransformKey, Vec<MeshKey>)> {
77 let source_mesh_keys = self
78 .meshes
79 .keys_by_transform_key(transform_key)
80 .cloned()
81 .ok_or(AwsmMeshError::TransformHasNoMeshes(transform_key))?;
82
83 let (new_transform_key, new_mesh_keys) = self.meshes.duplicate_by_transform_key(
84 transform_key,
85 &self.materials,
86 &mut self.transforms,
87 )?;
88
89 for (source_mesh_key, new_mesh_key) in source_mesh_keys
90 .into_iter()
91 .zip(new_mesh_keys.iter().copied())
92 {
93 self.render_passes
94 .material_transparent
95 .pipelines
96 .clone_render_pipeline_key(source_mesh_key, new_mesh_key);
97 self.sync_spatial_for_mesh(new_mesh_key);
98 }
99
100 Ok((new_transform_key, new_mesh_keys))
101 }
102
103 pub fn set_mesh_hidden(&mut self, mesh_key: MeshKey, hidden: bool) -> crate::error::Result<()> {
105 let mesh = self.meshes.get_mut(mesh_key)?;
106 mesh.hidden = hidden;
107 self.sync_spatial_for_mesh(mesh_key);
108 Ok(())
109 }
110
111 pub fn set_mesh_hud(&mut self, mesh_key: MeshKey, hud: bool) -> crate::error::Result<()> {
115 let mesh = self.meshes.get_mut(mesh_key)?;
116 mesh.hud = hud;
117 if hud {
118 self.meshes.mark_hud_used();
124 }
125 self.sync_spatial_for_mesh(mesh_key);
126 Ok(())
127 }
128
129 pub fn set_mesh_material(
136 &mut self,
137 mesh_key: MeshKey,
138 new_material_key: crate::materials::MaterialKey,
139 ) -> crate::error::Result<()> {
140 let mesh = self.meshes.get_mut(mesh_key)?;
141 mesh.material_key = new_material_key;
142 self.meshes
143 .refresh_meta_for_mesh_public(mesh_key, &self.materials, &self.transforms)?;
144 Ok(())
145 }
146
147 pub fn set_mesh_cheap_material(
171 &mut self,
172 mesh_key: MeshKey,
173 cheap_material_key: Option<crate::materials::MaterialKey>,
174 cheap_material_pixel_threshold: Option<u32>,
175 ) -> crate::error::Result<()> {
176 let authored_material = {
177 let mesh = self.meshes.get(mesh_key)?;
178 mesh.material_key
179 };
180 if let Some(cheap) = cheap_material_key {
181 let authored_shader = self.materials.shader_id(authored_material);
182 let cheap_shader = self.materials.shader_id(cheap);
183 if authored_shader != cheap_shader {
184 return Err(crate::meshes::AwsmMeshError::IncompatibleCheapMaterial {
185 authored: authored_material,
186 cheap,
187 reason: format!(
188 "shader_id mismatch (authored {authored_shader:?} vs cheap {cheap_shader:?}) — \
189 the per-frame routing only swaps material_offset; cross-shader cheap variants \
190 need a separate pipeline + render pool migration that isn't wired."
191 ),
192 }
193 .into());
194 }
195 let authored_blend = self.materials.is_transparency_pass(authored_material);
196 let cheap_blend = self.materials.is_transparency_pass(cheap);
197 if authored_blend != cheap_blend {
198 return Err(crate::meshes::AwsmMeshError::IncompatibleCheapMaterial {
199 authored: authored_material,
200 cheap,
201 reason: format!(
202 "transparency-pass classification mismatch (authored opaque?={} vs cheap opaque?={}) — \
203 a cheap variant on the opposite pass would land in the wrong renderable list.",
204 !authored_blend, !cheap_blend
205 ),
206 }
207 .into());
208 }
209 }
210 let mesh = self.meshes.get_mut(mesh_key)?;
211 mesh.cheap_material_key = cheap_material_key;
212 mesh.cheap_material_pixel_threshold = cheap_material_pixel_threshold;
213 Ok(())
214 }
215
216 pub fn remove_meshes_by_transform_key(&mut self, transform_key: TransformKey) -> Vec<MeshKey> {
218 let mesh_keys = self
219 .meshes
220 .keys_by_transform_key(transform_key)
221 .cloned()
222 .unwrap_or_default();
223
224 if mesh_keys.is_empty() {
225 return mesh_keys;
226 }
227
228 self.meshes.remove_by_transform_key(transform_key);
229
230 for mesh_key in &mesh_keys {
231 self.render_passes
232 .material_transparent
233 .pipelines
234 .remove_render_pipeline_key(*mesh_key);
235 self.drop_spatial_for_mesh(*mesh_key);
236 self.drop_cluster_lod_for_mesh(*mesh_key);
237 }
238
239 mesh_keys
240 }
241
242 pub fn remove_mesh(&mut self, mesh_key: MeshKey) -> bool {
244 let removed = self.meshes.remove(mesh_key).is_some();
245
246 if removed {
247 self.render_passes
248 .material_transparent
249 .pipelines
250 .remove_render_pipeline_key(mesh_key);
251 self.drop_spatial_for_mesh(mesh_key);
252 self.drop_cluster_lod_for_mesh(mesh_key);
253 }
254
255 removed
256 }
257
258 #[cfg(feature = "lod")]
264 fn drop_cluster_lod_for_mesh(&mut self, mesh_key: MeshKey) {
265 if let Some(pass) = self.render_passes.cluster_lod.as_mut() {
266 pass.remove_mesh(mesh_key);
267 }
268 }
269 #[cfg(not(feature = "lod"))]
270 fn drop_cluster_lod_for_mesh(&mut self, _mesh_key: MeshKey) {}
271
272 pub fn split_mesh(&mut self, mesh_key: MeshKey) -> crate::error::Result<TransformKey> {
274 let new_transform_key =
275 self.meshes
276 .split_mesh(mesh_key, &mut self.transforms, &self.materials)?;
277 self.sync_spatial_for_mesh(mesh_key);
278 Ok(new_transform_key)
279 }
280
281 pub fn split_meshes_by_transform_key(
283 &mut self,
284 transform_key: TransformKey,
285 ) -> crate::error::Result<Vec<(MeshKey, TransformKey)>> {
286 let result = self.meshes.split_meshes_by_transform_key(
287 transform_key,
288 &mut self.transforms,
289 &self.materials,
290 )?;
291 for (mesh_key, _) in &result {
292 self.sync_spatial_for_mesh(*mesh_key);
293 }
294 Ok(result)
295 }
296
297 pub fn join_meshes(
299 &mut self,
300 mesh_keys: &[MeshKey],
301 transform_override: Option<Transform>,
302 ) -> crate::error::Result<(TransformKey, Vec<MeshKey>)> {
303 let (new_transform_key, moved) = self.meshes.join_meshes(
304 mesh_keys,
305 &mut self.transforms,
306 &self.materials,
307 transform_override,
308 )?;
309 for mesh_key in &moved {
310 self.sync_spatial_for_mesh(*mesh_key);
311 }
312 Ok((new_transform_key, moved))
313 }
314
315 pub fn enable_mesh_instancing_opaque(
320 &mut self,
321 mesh_key: MeshKey,
322 transforms: &[Transform],
323 ) -> crate::error::Result<()> {
324 let transform_key = self.meshes.get(mesh_key)?.transform_key;
325 if transforms.is_empty() {
326 return Err(AwsmMeshError::InstancingMissingTransforms(mesh_key).into());
327 }
328 {
329 let mesh = self.meshes.get_mut(mesh_key)?;
330 if mesh.instanced {
331 return Err(AwsmMeshError::InstancingAlreadyEnabled(mesh_key).into());
332 }
333 mesh.instanced = true;
334 }
335 self.instances.transform_insert(transform_key, transforms)?;
336 Ok(())
337 }
338
339 pub async fn enable_mesh_instancing(
341 &mut self,
342 mesh_key: MeshKey,
343 transforms: &[Transform],
344 ) -> crate::error::Result<()> {
345 let buffer_info_key = self.meshes.buffer_info_key(mesh_key)?;
346 let transform_key = self.meshes.get(mesh_key)?.transform_key;
347 if transforms.is_empty() {
348 return Err(AwsmMeshError::InstancingMissingTransforms(mesh_key).into());
349 }
350 {
351 let mesh = self.meshes.get_mut(mesh_key)?;
352 if mesh.instanced {
353 return Err(AwsmMeshError::InstancingAlreadyEnabled(mesh_key).into());
354 }
355 mesh.instanced = true;
356 }
357
358 self.instances.transform_insert(transform_key, transforms)?;
359
360 let mesh = self.meshes.get(mesh_key)?;
361 if !self.materials.is_transparency_pass(mesh.material_key) {
366 return Ok(());
367 }
368 let writes_depth = self.materials.transparent_writes_depth(mesh.material_key);
369 let (mat_base, mat_pbr_features) = self.materials.transparent_variant(mesh.material_key);
370 let dynamic_shader_id = matches!(mat_base, crate::dynamic_materials::ShadingBase::Custom)
371 .then(|| self.materials.shader_id(mesh.material_key));
372 let dynamic_shader =
373 dynamic_shader_id.and_then(|id| self.dynamic_materials.shader_info_for(id));
374 let dynamic_vertex_shader =
375 dynamic_shader_id.and_then(|id| self.dynamic_materials.vertex_shader_info_for(id));
376 self.render_passes
377 .material_transparent
378 .pipelines
379 .set_render_pipeline_key(
380 &self.gpu,
381 mesh,
382 mesh_key,
383 buffer_info_key,
384 &mut self.shaders,
385 &mut self.pipelines,
386 &self.render_passes.material_transparent.bind_groups,
387 &self.pipeline_layouts,
388 &self.meshes.buffer_infos,
389 &self.anti_aliasing,
390 &self.textures,
391 &self.render_textures.formats,
392 writes_depth,
393 mat_base,
394 mat_pbr_features,
395 dynamic_shader_id,
396 dynamic_shader,
397 dynamic_vertex_shader,
398 )
399 .await?;
400
401 Ok(())
402 }
403
404 pub fn set_mesh_instances(
406 &mut self,
407 mesh_key: MeshKey,
408 transforms: &[Transform],
409 ) -> crate::error::Result<()> {
410 if transforms.is_empty() {
411 return Err(AwsmMeshError::InstancingMissingTransforms(mesh_key).into());
412 }
413 let mesh = self.meshes.get(mesh_key)?;
414 if !mesh.instanced {
415 return Err(AwsmMeshError::InstancingNotEnabled(mesh_key).into());
416 }
417
418 self.instances
421 .transform_write_all(mesh.transform_key, transforms)?;
422
423 Ok(())
424 }
425
426 pub fn set_mesh_billboard_mode(
429 &mut self,
430 mesh_key: MeshKey,
431 mode: BillboardMode,
432 ) -> crate::error::Result<()> {
433 if let Ok(mesh) = self.meshes.get_mut(mesh_key) {
434 mesh.billboard_mode = mode;
435 } else {
436 return Err(AwsmMeshError::MeshNotFound(mesh_key).into());
437 }
438 self.meshes
439 .refresh_meta_for_mesh_public(mesh_key, &self.materials, &self.transforms)?;
440 Ok(())
441 }
442
443 pub fn set_mesh_instance_attrs(
455 &mut self,
456 transform_key: TransformKey,
457 attrs: &[crate::instances::InstanceAttr],
458 ) -> crate::error::Result<()> {
459 let transforms = self
460 .instances
461 .transform_instance_count(transform_key)
462 .unwrap_or(0);
463 if transforms != attrs.len() {
464 return Err(AwsmMeshError::InstanceAttrCountMismatch {
465 transform_key,
466 attrs: attrs.len(),
467 transforms,
468 }
469 .into());
470 }
471 self.instances.attribute_write_all(transform_key, attrs)?;
472
473 let base = self
474 .instances
475 .attribute_buffer_offset(transform_key)
476 .map(|off| (off / crate::instances::InstanceAttr::BYTE_SIZE) as u32)
477 .unwrap_or(u32::MAX);
478
479 let mesh_keys: Vec<MeshKey> = self
480 .meshes
481 .keys_by_transform_key(transform_key)
482 .cloned()
483 .unwrap_or_default();
484
485 for mesh_key in mesh_keys {
486 if let Ok(mesh) = self.meshes.get_mut(mesh_key) {
487 mesh.instance_attr_base = base;
488 }
489 self.meshes.refresh_meta_for_mesh_public(
490 mesh_key,
491 &self.materials,
492 &self.transforms,
493 )?;
494 }
495
496 Ok(())
497 }
498
499 pub fn append_mesh_instance(
501 &mut self,
502 mesh_key: MeshKey,
503 transform: Transform,
504 ) -> crate::error::Result<usize> {
505 let start_index = self.append_mesh_instances(mesh_key, &[transform])?;
506 Ok(start_index)
507 }
508
509 pub fn append_mesh_instances(
515 &mut self,
516 mesh_key: MeshKey,
517 transforms: &[Transform],
518 ) -> crate::error::Result<usize> {
519 if transforms.is_empty() {
520 return Err(AwsmMeshError::InstancingMissingTransforms(mesh_key).into());
521 }
522
523 let mesh = self.meshes.get(mesh_key)?;
524 if !mesh.instanced {
525 return Err(AwsmMeshError::InstancingNotEnabled(mesh_key).into());
526 }
527 let transform_key = mesh.transform_key;
528 if self
529 .instances
530 .transform_instance_count(transform_key)
531 .is_none()
532 {
533 return Err(AwsmMeshError::InstancingMissingTransforms(mesh_key).into());
534 }
535
536 let start_index = self.instances.transform_extend(transform_key, transforms)?;
537 self.instances
538 .attribute_extend_with_default(transform_key, transforms.len())?;
539 Ok(start_index)
540 }
541
542 pub fn reserve_mesh_instances(
547 &mut self,
548 mesh_key: MeshKey,
549 additional: usize,
550 ) -> crate::error::Result<usize> {
551 let mesh = self.meshes.get(mesh_key)?;
552 if !mesh.instanced {
553 return Err(AwsmMeshError::InstancingNotEnabled(mesh_key).into());
554 }
555 let transform_key = mesh.transform_key;
556 if self
557 .instances
558 .transform_instance_count(transform_key)
559 .is_none()
560 {
561 return Err(AwsmMeshError::InstancingMissingTransforms(mesh_key).into());
562 }
563
564 let start_index = self
565 .instances
566 .transform_reserve(transform_key, additional)?;
567 self.instances
568 .attribute_extend_with_default(transform_key, additional)?;
569 Ok(start_index)
570 }
571}
572
573#[derive(Debug, Clone)]
575pub struct MeshResource {
576 pub buffer_info_key: MeshBufferInfoKey,
577 pub visibility_geometry_data_offset: Option<usize>,
578 pub transparency_geometry_data_offset: Option<usize>,
579 pub custom_attribute_data_offset: usize,
580 pub custom_attribute_index_offset: usize,
581 pub aabb: Option<Aabb>,
582 pub geometry_morph_key: Option<GeometryMorphKey>,
583 pub material_morph_key: Option<MaterialMorphKey>,
584 pub skin_key: Option<SkinKey>,
585 pub refcount: usize,
586}
587
588pub struct Meshes {
590 list: DenseSlotMap<MeshKey, Mesh>,
591 resources: DenseSlotMap<MeshResourceKey, MeshResource>,
592 geometries: DenseSlotMap<geometry::GeometryKey, geometry::GeometrySource>,
598 mesh_to_geometry: SecondaryMap<MeshKey, geometry::GeometryKey>,
601 geometry_to_meshes: SecondaryMap<geometry::GeometryKey, Vec<MeshKey>>,
604 mesh_to_resource: SecondaryMap<MeshKey, MeshResourceKey>,
605 transform_to_meshes: SecondaryMap<TransformKey, Vec<MeshKey>>,
606 mesh_geometry_pool_buffers: DynamicStorageBuffer<MeshResourceKey>,
612 mesh_geometry_pool_gpu_buffer: web_sys::GpuBuffer,
613 mesh_geometry_pool_dirty: bool,
614 visibility_geometry_index_buffers: DynamicStorageBuffer<MeshResourceKey>,
616 visibility_geometry_index_gpu_buffer: web_sys::GpuBuffer,
617 visibility_geometry_index_dirty: bool,
618 transparency_geometry_data_buffers: DynamicStorageBuffer<MeshResourceKey>,
620 transparency_geometry_data_gpu_buffer: web_sys::GpuBuffer,
621 transparency_geometry_data_dirty: bool,
622 mesh_geometry_pool_uploader: crate::buffer::mapped_uploader::MappedUploader,
623 visibility_geometry_index_uploader: crate::buffer::mapped_uploader::MappedUploader,
624 transparency_geometry_data_uploader: crate::buffer::mapped_uploader::MappedUploader,
625 pub buffer_infos: MeshBufferInfos,
627 pub meta: MeshMeta,
629 pub morphs: Morphs,
631 pub skins: Skins,
632 last_effective_material: SecondaryMap<MeshKey, crate::materials::MaterialKey>,
639 skin_zero_coverage_grace: SecondaryMap<SkinKey, u32>,
652 skin_consumers_scratch: HashMap<SkinKey, Vec<MeshKey>>,
663 has_seen_hud: bool,
669 hud_revision: u64,
679}
680impl Meshes {
681 const INDICES_INITIAL_SIZE: usize = MESH_META_INITIAL_CAPACITY * 3 * 1000;
684
685 const VISIBILITY_GEOMETRY_INITIAL_SIZE: usize =
686 Self::INDICES_INITIAL_SIZE * MeshBufferVertexInfo::VISIBILITY_GEOMETRY_BYTE_SIZE;
687
688 const TRANSPARENCY_GEOMETRY_INITIAL_SIZE: usize =
689 Self::INDICES_INITIAL_SIZE * MeshBufferVertexInfo::TRANSPARENCY_GEOMETRY_BYTE_SIZE;
690
691 const ATTRIBUTE_DATA_INITIAL_SIZE: usize = Self::INDICES_INITIAL_SIZE * 16;
695
696 const MESH_GEOMETRY_POOL_INITIAL_SIZE: usize = Self::VISIBILITY_GEOMETRY_INITIAL_SIZE
699 + Self::INDICES_INITIAL_SIZE
700 + Self::ATTRIBUTE_DATA_INITIAL_SIZE;
701
702 pub fn new(gpu: &AwsmRendererWebGpu) -> Result<Self> {
704 Ok(Self {
705 list: DenseSlotMap::with_key(),
706 resources: DenseSlotMap::with_key(),
707 geometries: DenseSlotMap::with_key(),
708 mesh_to_geometry: SecondaryMap::new(),
709 geometry_to_meshes: SecondaryMap::new(),
710 mesh_to_resource: SecondaryMap::new(),
711 transform_to_meshes: SecondaryMap::new(),
712 buffer_infos: MeshBufferInfos::new(),
713 mesh_geometry_pool_buffers: DynamicStorageBuffer::new(
715 Self::MESH_GEOMETRY_POOL_INITIAL_SIZE,
716 Some("MeshGeometryPool".to_string()),
717 ),
718 mesh_geometry_pool_gpu_buffer: gpu.create_buffer(
719 &BufferDescriptor::new(
720 Some("MeshGeometryPool"),
721 Self::MESH_GEOMETRY_POOL_INITIAL_SIZE,
722 BufferUsage::new()
723 .with_copy_dst()
724 .with_vertex()
725 .with_storage()
726 .with_index(),
727 )
728 .into(),
729 )?,
730 mesh_geometry_pool_dirty: true,
731 visibility_geometry_index_buffers: DynamicStorageBuffer::new(
733 Self::INDICES_INITIAL_SIZE,
734 Some("MeshVisibilityIndex".to_string()),
735 ),
736 visibility_geometry_index_gpu_buffer: gpu.create_buffer(
737 &BufferDescriptor::new(
738 Some("MeshVisibilityIndex"),
739 Self::INDICES_INITIAL_SIZE,
740 BufferUsage::new().with_copy_dst().with_index(),
741 )
742 .into(),
743 )?,
744 visibility_geometry_index_dirty: true,
745 transparency_geometry_data_buffers: DynamicStorageBuffer::new(
747 Self::TRANSPARENCY_GEOMETRY_INITIAL_SIZE,
748 Some("MeshTransparencyData".to_string()),
749 ),
750 transparency_geometry_data_gpu_buffer: gpu.create_buffer(
751 &BufferDescriptor::new(
752 Some("MeshTransparencyData"),
753 Self::TRANSPARENCY_GEOMETRY_INITIAL_SIZE,
754 BufferUsage::new().with_copy_dst().with_vertex(),
755 )
756 .into(),
757 )?,
758 transparency_geometry_data_dirty: true,
759 mesh_geometry_pool_uploader: crate::buffer::mapped_uploader::MappedUploader::new(
760 "MeshGeometryPool",
761 ),
762 visibility_geometry_index_uploader: crate::buffer::mapped_uploader::MappedUploader::new(
763 "MeshVisibilityIndex",
764 ),
765 transparency_geometry_data_uploader:
766 crate::buffer::mapped_uploader::MappedUploader::new("MeshTransparencyData"),
767 meta: MeshMeta::new(gpu)?,
768 morphs: Morphs::new(gpu)?,
770 skins: Skins::new(gpu)?,
771 last_effective_material: SecondaryMap::new(),
772 skin_zero_coverage_grace: SecondaryMap::new(),
773 skin_consumers_scratch: HashMap::new(),
774 has_seen_hud: false,
775 hud_revision: 0,
776 })
777 }
778
779 pub fn has_seen_hud(&self) -> bool {
785 self.has_seen_hud
786 }
787
788 pub fn hud_revision(&self) -> u64 {
793 self.hud_revision
794 }
795
796 pub(crate) fn mark_hud_used(&mut self) {
802 self.has_seen_hud = true;
803 self.hud_revision = self.hud_revision.wrapping_add(1);
804 }
805
806 pub fn refresh_cheap_material_routing(
831 &mut self,
832 materials: &crate::materials::Materials,
833 coverage: &crate::coverage::MeshCoverage,
834 default_threshold: u32,
835 ) -> Result<()> {
836 let mut updates: Vec<(MeshKey, u32, crate::materials::MaterialKey)> = Vec::new();
840 for (mesh_key, mesh) in self.list.iter() {
841 if mesh.cheap_material_key.is_none() {
842 continue;
843 }
844 let effective = mesh.effective_material_key(mesh_key, coverage, default_threshold);
845 let last = self.last_effective_material.get(mesh_key).copied();
846 if last == Some(effective) {
847 continue;
848 }
849 let offset = materials.buffer_offset(effective)? as u32;
853 updates.push((mesh_key, offset, effective));
854 }
855 for (mesh_key, offset, effective) in updates {
856 if self.meta.set_material_offset(mesh_key, offset) {
868 self.last_effective_material.insert(mesh_key, effective);
869 } else {
870 tracing::debug!(
871 "refresh_cheap_material_routing: mesh {mesh_key:?} has no material-meta slot; \
872 skipping cache update so the next gather pass retries"
873 );
874 }
875 }
876 Ok(())
877 }
878
879 pub fn upload_stats(&self) -> crate::buffer::mapped_staging_ring::UploadStats {
883 let mut s = self.mesh_geometry_pool_uploader.stats();
884 let b = self.visibility_geometry_index_uploader.stats();
885 let c = self.transparency_geometry_data_uploader.stats();
886 s.peak_ring_depth_used = s
887 .peak_ring_depth_used
888 .max(b.peak_ring_depth_used)
889 .max(c.peak_ring_depth_used);
890 s.fallback_count += b.fallback_count + c.fallback_count;
891 s.map_async_wait_ms += b.map_async_wait_ms + c.map_async_wait_ms;
892 s.bytes_uploaded_via_ring += b.bytes_uploaded_via_ring + c.bytes_uploaded_via_ring;
893 s.bytes_uploaded_via_fallback +=
894 b.bytes_uploaded_via_fallback + c.bytes_uploaded_via_fallback;
895 s.bytes_uploaded_via_writebuffer +=
896 b.bytes_uploaded_via_writebuffer + c.bytes_uploaded_via_writebuffer;
897 s.resize_count += b.resize_count + c.resize_count;
898 s
899 }
900
901 pub fn register_geometry(&mut self, source: geometry::GeometrySource) -> geometry::GeometryKey {
907 self.geometries.insert(source)
908 }
909
910 pub fn geometry_source(&self, key: geometry::GeometryKey) -> Option<&geometry::GeometrySource> {
914 self.geometries.get(key)
915 }
916
917 pub fn geometry_count(&self) -> usize {
920 self.geometries.len()
921 }
922
923 pub(crate) fn bind_mesh(
929 &mut self,
930 mut mesh: Mesh,
931 geometry_key: geometry::GeometryKey,
932 ) -> Result<MeshKey> {
933 let source = self
934 .geometries
935 .get(geometry_key)
936 .ok_or(AwsmMeshError::GeometryNotFound(geometry_key))?;
937 if mesh.world_aabb.is_none() {
938 mesh.world_aabb = source.aabb.clone();
939 }
940 let mesh_key = self.list.insert(mesh);
941 self.mesh_to_geometry.insert(mesh_key, geometry_key);
942 self.geometry_to_meshes
943 .entry(geometry_key)
944 .unwrap()
945 .or_default()
946 .push(mesh_key);
947 Ok(mesh_key)
948 }
949
950 pub(crate) fn resolve_geometry(
960 &mut self,
961 materials: &Materials,
962 transforms: &Transforms,
963 ) -> Result<Vec<MeshKey>> {
964 let geometry_keys: Vec<geometry::GeometryKey> = self.geometries.keys().collect();
965 let mut wired = Vec::new();
966 for gkey in geometry_keys {
967 wired.extend(self.resolve_one(gkey, materials, transforms)?);
968 }
969 Ok(wired)
970 }
971
972 pub(crate) fn resolve_one(
979 &mut self,
980 gkey: geometry::GeometryKey,
981 materials: &Materials,
982 transforms: &Transforms,
983 ) -> Result<Vec<MeshKey>> {
984 use crate::meshes::geometry::{geometry_kind, GeometryReps};
985
986 let Some(source) = self.geometries.remove(gkey) else {
992 return Ok(Vec::new());
993 };
994 let bound = self.geometry_to_meshes.remove(gkey).unwrap_or_default();
995 if bound.is_empty() {
996 return Ok(Vec::new()); }
998 let mut wired = Vec::new();
999
1000 {
1001 let reps = GeometryReps::from_kinds(bound.iter().filter_map(|&mk| {
1005 let mesh = self.list.get(mk)?;
1006 let material = materials.get(mesh.material_key).ok()?;
1007 Some(geometry_kind(material, mesh.hud))
1008 }));
1009 let want_visibility = reps.visibility;
1010 let want_transparency = reps.transparency;
1011 let want_tangents = bound.iter().any(|&mk| {
1013 self.list
1014 .get(mk)
1015 .and_then(|mesh| materials.get(mesh.material_key).ok())
1016 .is_some_and(crate::raw_mesh::material_wants_tangents)
1017 });
1018
1019 let tangents = source.tangents.clone().or_else(|| {
1023 if want_tangents {
1024 source.uvs0.as_ref().and_then(|uvs| {
1025 awsm_renderer_tangents::generate_tangents(
1026 &source.positions,
1027 &source.normals,
1028 uvs,
1029 &source.indices,
1030 )
1031 })
1032 } else {
1033 None
1034 }
1035 });
1036
1037 let visibility_bytes = want_visibility.then(|| {
1039 crate::mesh_pack::pack_visibility_bytes(
1040 &source.positions,
1041 &source.normals,
1042 tangents.as_deref(),
1043 &source.indices,
1044 source.front_face,
1045 )
1046 });
1047 let transparency_bytes = want_transparency.then(|| {
1048 crate::mesh_pack::pack_transparency_bytes(
1049 &source.positions,
1050 &source.normals,
1051 tangents.as_deref(),
1052 source.vertex_count(),
1053 )
1054 });
1055
1056 let triangle_count = source.triangle_count();
1059 let buffer_info = buffer_info::MeshBufferInfo {
1060 visibility_geometry_vertex: visibility_bytes.as_ref().map(|_| {
1061 MeshBufferVertexInfo {
1062 count: triangle_count * 3,
1063 }
1064 }),
1065 transparency_geometry_vertex: transparency_bytes.as_ref().map(|_| {
1066 MeshBufferVertexInfo {
1067 count: source.vertex_count(),
1068 }
1069 }),
1070 triangles: buffer_info::MeshBufferTriangleInfo {
1071 count: triangle_count,
1072 vertex_attribute_indices: buffer_info::MeshBufferAttributeIndexInfo {
1073 count: triangle_count * 3,
1074 },
1075 vertex_attributes: source.vertex_attributes.clone(),
1076 vertex_attributes_size: source.custom_attribute_bytes.len(),
1077 triangle_data: buffer_info::MeshBufferTriangleDataInfo {
1078 size_per_triangle: 12,
1079 total_size: triangle_count * 12,
1080 },
1081 },
1082 geometry_morph: source.geometry_morph_info.clone(),
1086 material_morph: source.material_morph_info.clone(),
1087 skin: source.skin_info.clone(),
1088 };
1089 let buffer_info_key = self.buffer_infos.insert(buffer_info);
1090
1091 let resource_key = self.insert_resource(
1093 buffer_info_key,
1094 visibility_bytes.as_deref(),
1095 transparency_bytes.as_deref(),
1096 &source.custom_attribute_bytes,
1097 &source.attribute_index_bytes,
1098 source.aabb.clone(),
1099 source.geometry_morph_key,
1100 source.material_morph_key,
1101 source.skin_key,
1102 )?;
1103 if let Some(resource) = self.resources.get_mut(resource_key) {
1104 resource.refcount = bound.len();
1105 }
1106
1107 for &mk in &bound {
1109 self.wire_instance(mk, resource_key, materials, transforms)?;
1110 self.mesh_to_geometry.remove(mk);
1111 wired.push(mk);
1112 }
1113 }
1114
1115 Ok(wired)
1116 }
1117
1118 fn insert_resource(
1125 &mut self,
1126 buffer_info_key: MeshBufferInfoKey,
1127 visibility_geometry_data: Option<&[u8]>,
1128 transparency_geometry_data: Option<&[u8]>,
1129 attribute_data: &[u8],
1130 attribute_index: &[u8],
1131 aabb: Option<Aabb>,
1132 geometry_morph_key: Option<GeometryMorphKey>,
1133 material_morph_key: Option<MaterialMorphKey>,
1134 skin_key: Option<SkinKey>,
1135 ) -> Result<MeshResourceKey> {
1136 let buffer_info = self.buffer_infos.get(buffer_info_key)?;
1137
1138 if visibility_geometry_data.is_some() && buffer_info.visibility_geometry_vertex.is_none() {
1140 return Err(AwsmMeshError::VisibilityGeometryBufferInfoNotFound(
1141 buffer_info_key,
1142 ));
1143 }
1144
1145 let resource_key = self.resources.insert(MeshResource {
1146 buffer_info_key,
1147 visibility_geometry_data_offset: None,
1148 transparency_geometry_data_offset: None,
1149 custom_attribute_data_offset: 0,
1150 custom_attribute_index_offset: 0,
1151 aabb,
1152 geometry_morph_key,
1153 material_morph_key,
1154 skin_key,
1155 refcount: 1,
1156 });
1157
1158 let vis_data_len = visibility_geometry_data.map(|d| d.len()).unwrap_or(0);
1162 let attr_index_len = attribute_index.len();
1163 let offsets_result: Result<(Option<usize>, Option<usize>, usize, usize)> = (|| {
1164 if let Some(geometry_data) = visibility_geometry_data {
1165 let vertex_info = buffer_info
1166 .visibility_geometry_vertex
1167 .as_ref()
1168 .expect("visibility_geometry_vertex presence pre-validated");
1169 let mut geometry_index = Vec::new();
1170 for i in 0..vertex_info.count {
1171 geometry_index.extend_from_slice(&(i as u32).to_le_bytes());
1172 }
1173 self.visibility_geometry_index_buffers
1174 .update(resource_key, &geometry_index)
1175 .map_err(|e| {
1176 AwsmMeshError::BufferCapacityOverflow(format!(
1177 "visibility geometry index: {e}"
1178 ))
1179 })?;
1180 self.visibility_geometry_index_dirty = true;
1181
1182 let mut combined =
1183 Vec::with_capacity(geometry_data.len() + attr_index_len + attribute_data.len());
1184 combined.extend_from_slice(geometry_data);
1185 combined.extend_from_slice(attribute_index);
1186 combined.extend_from_slice(attribute_data);
1187 let base = self
1188 .mesh_geometry_pool_buffers
1189 .update(resource_key, &combined)
1190 .map_err(|e| {
1191 AwsmMeshError::BufferCapacityOverflow(format!("mesh geometry pool: {e}"))
1192 })?;
1193 self.mesh_geometry_pool_dirty = true;
1194
1195 let visibility_offset = Some(base);
1196 let custom_attribute_indices_offset = base + vis_data_len;
1197 let custom_attribute_data_offset = base + vis_data_len + attr_index_len;
1198
1199 let transparency_offset = match transparency_geometry_data {
1200 Some(geometry_data) => {
1201 let offset = self
1202 .transparency_geometry_data_buffers
1203 .update(resource_key, geometry_data)
1204 .map_err(|e| {
1205 AwsmMeshError::BufferCapacityOverflow(format!(
1206 "transparency geometry data: {e}"
1207 ))
1208 })?;
1209 self.transparency_geometry_data_dirty = true;
1210 Some(offset)
1211 }
1212 None => None,
1213 };
1214
1215 Ok((
1216 visibility_offset,
1217 transparency_offset,
1218 custom_attribute_indices_offset,
1219 custom_attribute_data_offset,
1220 ))
1221 } else {
1222 let mut combined = Vec::with_capacity(attr_index_len + attribute_data.len());
1223 combined.extend_from_slice(attribute_index);
1224 combined.extend_from_slice(attribute_data);
1225 let base = self
1226 .mesh_geometry_pool_buffers
1227 .update(resource_key, &combined)
1228 .map_err(|e| {
1229 AwsmMeshError::BufferCapacityOverflow(format!("mesh geometry pool: {e}"))
1230 })?;
1231 self.mesh_geometry_pool_dirty = true;
1232
1233 let custom_attribute_indices_offset = base;
1234 let custom_attribute_data_offset = base + attr_index_len;
1235
1236 let transparency_offset = match transparency_geometry_data {
1237 Some(geometry_data) => {
1238 let offset = self
1239 .transparency_geometry_data_buffers
1240 .update(resource_key, geometry_data)
1241 .map_err(|e| {
1242 AwsmMeshError::BufferCapacityOverflow(format!(
1243 "transparency geometry data: {e}"
1244 ))
1245 })?;
1246 self.transparency_geometry_data_dirty = true;
1247 Some(offset)
1248 }
1249 None => None,
1250 };
1251
1252 Ok((
1253 None,
1254 transparency_offset,
1255 custom_attribute_indices_offset,
1256 custom_attribute_data_offset,
1257 ))
1258 }
1259 })();
1260
1261 let (
1262 visibility_geometry_data_offset,
1263 transparency_geometry_data_offset,
1264 custom_attribute_indices_offset,
1265 custom_attribute_data_offset,
1266 ) = match offsets_result {
1267 Ok(offsets) => offsets,
1268 Err(e) => {
1269 self.visibility_geometry_index_buffers.remove(resource_key);
1271 self.mesh_geometry_pool_buffers.remove(resource_key);
1272 self.transparency_geometry_data_buffers.remove(resource_key);
1273 self.resources.remove(resource_key);
1274 return Err(e);
1275 }
1276 };
1277
1278 if let Some(resource) = self.resources.get_mut(resource_key) {
1315 resource.visibility_geometry_data_offset = visibility_geometry_data_offset;
1316 resource.transparency_geometry_data_offset = transparency_geometry_data_offset;
1317 resource.custom_attribute_data_offset = custom_attribute_data_offset;
1318 resource.custom_attribute_index_offset = custom_attribute_indices_offset;
1319 }
1320
1321 Ok(resource_key)
1322 }
1323
1324 fn insert_instance(
1325 &mut self,
1326 mesh: Mesh,
1327 resource_key: MeshResourceKey,
1328 materials: &Materials,
1329 transforms: &Transforms,
1330 ) -> Result<MeshKey> {
1331 let mesh_key = self.list.insert(mesh);
1332 self.wire_instance(mesh_key, resource_key, materials, transforms)?;
1333 Ok(mesh_key)
1334 }
1335
1336 fn wire_instance(
1345 &mut self,
1346 mesh_key: MeshKey,
1347 resource_key: MeshResourceKey,
1348 materials: &Materials,
1349 transforms: &Transforms,
1350 ) -> Result<()> {
1351 let (
1352 resource_aabb,
1353 buffer_info_key,
1354 visibility_geometry_data_offset,
1355 transparency_geometry_data_offset,
1356 custom_attribute_index_offset,
1357 custom_attribute_data_offset,
1358 geometry_morph_key,
1359 material_morph_key,
1360 skin_key,
1361 ) = {
1362 let resource = self
1363 .resources
1364 .get(resource_key)
1365 .ok_or(AwsmMeshError::ResourceNotFound(resource_key))?;
1366 (
1367 resource.aabb.clone(),
1368 resource.buffer_info_key,
1369 resource.visibility_geometry_data_offset,
1370 resource.transparency_geometry_data_offset,
1371 resource.custom_attribute_index_offset,
1372 resource.custom_attribute_data_offset,
1373 resource.geometry_morph_key,
1374 resource.material_morph_key,
1375 resource.skin_key,
1376 )
1377 };
1378
1379 let transform_key = {
1380 let mesh = self
1381 .list
1382 .get_mut(mesh_key)
1383 .ok_or(AwsmMeshError::MeshNotFound(mesh_key))?;
1384 mesh.has_visibility_geometry = visibility_geometry_data_offset.is_some();
1387 mesh.has_transparency_geometry = transparency_geometry_data_offset.is_some();
1388 if mesh.world_aabb.is_none() {
1389 mesh.world_aabb = resource_aabb;
1390 }
1391 if mesh.hud {
1395 self.has_seen_hud = true;
1396 self.hud_revision = self.hud_revision.wrapping_add(1);
1397 }
1398 mesh.transform_key
1399 };
1400
1401 self.mesh_to_resource.insert(mesh_key, resource_key);
1402 self.transform_to_meshes
1403 .entry(transform_key)
1404 .unwrap()
1405 .or_default()
1406 .push(mesh_key);
1407
1408 let mesh = self
1409 .list
1410 .get(mesh_key)
1411 .ok_or(AwsmMeshError::MeshNotFound(mesh_key))?
1412 .clone();
1413 let buffer_info = self.buffer_infos.get(buffer_info_key)?;
1414 self.meta.insert(
1415 mesh_key,
1416 &mesh,
1417 buffer_info,
1418 visibility_geometry_data_offset,
1419 custom_attribute_index_offset,
1420 custom_attribute_data_offset,
1421 geometry_morph_key,
1422 material_morph_key,
1423 skin_key,
1424 materials,
1425 transforms,
1426 &self.morphs,
1427 &self.skins,
1428 )?;
1429
1430 Ok(())
1431 }
1432
1433 pub(crate) fn duplicate_with_transform(
1439 &mut self,
1440 mesh_key: MeshKey,
1441 new_transform_key: TransformKey,
1442 materials: &Materials,
1443 transforms: &Transforms,
1444 ) -> Result<MeshKey> {
1445 let mesh = self.get(mesh_key)?.clone();
1446 let resource_key = self.resource_key(mesh_key)?;
1447 let resource_aabb = {
1448 let resource = self
1449 .resources
1450 .get_mut(resource_key)
1451 .ok_or(AwsmMeshError::ResourceNotFound(resource_key))?;
1452 resource.refcount += 1;
1453 resource.aabb.clone()
1454 };
1455
1456 let world_aabb = match (
1464 resource_aabb.as_ref(),
1465 transforms.get_world(new_transform_key).ok(),
1466 ) {
1467 (Some(aabb), Some(world_mat)) => Some(aabb.transformed(world_mat)),
1468 (Some(aabb), None) => Some(aabb.clone()),
1469 (None, _) => None,
1470 };
1471
1472 let mut new_mesh = mesh.clone();
1473 new_mesh.transform_key = new_transform_key;
1474 new_mesh.world_aabb = world_aabb;
1475
1476 self.insert_instance(new_mesh, resource_key, materials, transforms)
1477 }
1478
1479 pub(crate) fn duplicate_by_transform_key(
1481 &mut self,
1482 transform_key: TransformKey,
1483 materials: &Materials,
1484 transforms: &mut Transforms,
1485 ) -> Result<(TransformKey, Vec<MeshKey>)> {
1486 let mesh_keys = self
1487 .transform_to_meshes
1488 .get(transform_key)
1489 .cloned()
1490 .ok_or(AwsmMeshError::TransformHasNoMeshes(transform_key))?;
1491
1492 if mesh_keys.is_empty() {
1493 return Err(AwsmMeshError::TransformHasNoMeshes(transform_key));
1494 }
1495
1496 for mesh_key in &mesh_keys {
1497 if self.get(*mesh_key)?.instanced {
1498 return Err(AwsmMeshError::InstancedMeshUnsupported(*mesh_key));
1499 }
1500 }
1501
1502 let new_transform_key = transforms.duplicate(transform_key)?;
1503
1504 let mut new_mesh_keys = Vec::with_capacity(mesh_keys.len());
1505 for mesh_key in mesh_keys {
1506 let new_mesh_key =
1507 self.duplicate_with_transform(mesh_key, new_transform_key, materials, transforms)?;
1508 new_mesh_keys.push(new_mesh_key);
1509 }
1510
1511 Ok((new_transform_key, new_mesh_keys))
1512 }
1513
1514 pub(crate) fn split_mesh(
1516 &mut self,
1517 mesh_key: MeshKey,
1518 transforms: &mut Transforms,
1519 materials: &Materials,
1520 ) -> Result<TransformKey> {
1521 let old_transform_key = self.get(mesh_key)?.transform_key;
1522 if self.get(mesh_key)?.instanced {
1523 return Err(AwsmMeshError::InstancedMeshUnsupported(mesh_key));
1524 }
1525
1526 let new_transform_key = transforms.duplicate(old_transform_key)?;
1527
1528 self.update_mesh_transform(
1529 mesh_key,
1530 old_transform_key,
1531 new_transform_key,
1532 materials,
1533 transforms,
1534 )?;
1535
1536 Ok(new_transform_key)
1537 }
1538
1539 pub(crate) fn split_meshes_by_transform_key(
1541 &mut self,
1542 transform_key: TransformKey,
1543 transforms: &mut Transforms,
1544 materials: &Materials,
1545 ) -> Result<Vec<(MeshKey, TransformKey)>> {
1546 let mesh_keys = self
1547 .transform_to_meshes
1548 .get(transform_key)
1549 .cloned()
1550 .ok_or(AwsmMeshError::TransformHasNoMeshes(transform_key))?;
1551
1552 if mesh_keys.is_empty() {
1553 return Err(AwsmMeshError::TransformHasNoMeshes(transform_key));
1554 }
1555
1556 let mut out = Vec::with_capacity(mesh_keys.len());
1557 for mesh_key in mesh_keys {
1558 let new_transform_key = self.split_mesh(mesh_key, transforms, materials)?;
1559 out.push((mesh_key, new_transform_key));
1560 }
1561
1562 Ok(out)
1563 }
1564
1565 pub(crate) fn join_meshes(
1567 &mut self,
1568 mesh_keys: &[MeshKey],
1569 transforms: &mut Transforms,
1570 materials: &Materials,
1571 transform_override: Option<Transform>,
1572 ) -> Result<(TransformKey, Vec<MeshKey>)> {
1573 if mesh_keys.is_empty() {
1574 return Err(AwsmMeshError::MeshListEmpty);
1575 }
1576
1577 for mesh_key in mesh_keys {
1578 if self.get(*mesh_key)?.instanced {
1579 return Err(AwsmMeshError::InstancedMeshUnsupported(*mesh_key));
1580 }
1581 }
1582
1583 let mut common_parent = None;
1584 for (index, mesh_key) in mesh_keys.iter().enumerate() {
1585 let mesh = self.get(*mesh_key)?;
1586 let parent = transforms.get_parent(mesh.transform_key).ok();
1587 if index == 0 {
1588 common_parent = parent;
1589 } else if common_parent != parent {
1590 common_parent = None;
1591 break;
1592 }
1593 }
1594
1595 let new_local = match transform_override {
1596 Some(transform) => transform,
1597 None => {
1598 let mut center_sum = glam::Vec3::ZERO;
1599 for mesh_key in mesh_keys {
1600 let mesh = self.get(*mesh_key)?;
1601 let center = mesh
1602 .world_aabb
1603 .as_ref()
1604 .map(|aabb| aabb.center())
1605 .or_else(|| {
1606 transforms
1607 .get_world(mesh.transform_key)
1608 .ok()
1609 .map(|m| m.w_axis.truncate())
1610 })
1611 .unwrap_or(glam::Vec3::ZERO);
1612 center_sum += center;
1613 }
1614 let centroid_world = center_sum / mesh_keys.len() as f32;
1615 let local_translation = match common_parent {
1616 Some(parent_key) => transforms
1617 .get_world(parent_key)
1618 .ok()
1619 .map(|m| m.inverse().transform_point3(centroid_world))
1620 .unwrap_or(centroid_world),
1621 None => centroid_world,
1622 };
1623 Transform::IDENTITY.with_translation(local_translation)
1624 }
1625 };
1626
1627 let new_transform_key = transforms.insert(new_local, common_parent);
1628
1629 let moved = mesh_keys.to_vec();
1630 for mesh_key in &moved {
1631 let old_transform_key = self.get(*mesh_key)?.transform_key;
1632 self.update_mesh_transform(
1633 *mesh_key,
1634 old_transform_key,
1635 new_transform_key,
1636 materials,
1637 transforms,
1638 )?;
1639 }
1640
1641 Ok((new_transform_key, moved))
1642 }
1643
1644 pub fn update_world(
1650 &mut self,
1651 dirty_transforms: HashMap<TransformKey, Mat4>,
1652 dirty_instances: &std::collections::HashSet<TransformKey>,
1653 transforms: &Transforms,
1654 instances: &Instances,
1655 frame_index: u64,
1656 coverage: &crate::coverage::MeshCoverage,
1661 frustum: Option<&crate::frustum::Frustum>,
1671 ) -> Vec<MeshKey> {
1672 let mut update_keys = std::collections::HashSet::new();
1673 update_keys.extend(dirty_transforms.keys().copied());
1674 update_keys.extend(dirty_instances.iter().copied());
1675
1676 let mut touched = Vec::new();
1677
1678 for transform_key in update_keys {
1680 let world_mat = dirty_transforms
1681 .get(&transform_key)
1682 .copied()
1683 .or_else(|| transforms.get_world(transform_key).ok().copied());
1684
1685 let world_mat = match world_mat {
1686 Some(mat) => mat,
1687 None => continue,
1688 };
1689
1690 if let Some(mesh_keys) = self.transform_to_meshes.get(transform_key) {
1691 for mesh_key in mesh_keys {
1692 let resource_aabb = self
1693 .resource(*mesh_key)
1694 .ok()
1695 .and_then(|resource| resource.aabb.clone());
1696
1697 let world_aabb = match resource_aabb {
1698 Some(aabb) => {
1699 let mesh = match self.list.get(*mesh_key) {
1700 Some(mesh) => mesh,
1701 None => continue,
1702 };
1703
1704 if mesh.instanced {
1705 match instances.transform_list(mesh.transform_key) {
1706 Some(transforms_list) if !transforms_list.is_empty() => {
1707 let first = world_mat * transforms_list[0].to_matrix();
1708 let mut combined = aabb.transformed(&first);
1709 for transform in &transforms_list[1..] {
1710 let world = world_mat * transform.to_matrix();
1711 let transformed = aabb.transformed(&world);
1712 combined.extend(&transformed);
1713 }
1714 Some(combined)
1715 }
1716 _ => None,
1717 }
1718 } else {
1719 Some(aabb.transformed(&world_mat))
1720 }
1721 }
1722 None => None,
1723 };
1724
1725 if let Some(mesh) = self.list.get_mut(*mesh_key) {
1726 mesh.world_aabb = world_aabb;
1727 }
1728 touched.push(*mesh_key);
1729 }
1730 }
1731 }
1732
1733 const SKIN_COVERAGE_GRACE_FRAMES: u32 = 2;
1765 let mut skip_skins: std::collections::HashSet<SkinKey> = std::collections::HashSet::new();
1766 {
1781 let Self {
1782 list,
1783 mesh_to_resource,
1784 resources,
1785 skin_consumers_scratch,
1786 ..
1787 } = self;
1788 for bucket in skin_consumers_scratch.values_mut() {
1789 bucket.clear();
1790 }
1791 for (mesh_key, _mesh) in list.iter() {
1792 let Some(resource_key) = mesh_to_resource.get(mesh_key).copied() else {
1793 continue;
1794 };
1795 let Some(resource) = resources.get(resource_key) else {
1796 continue;
1797 };
1798 if let Some(skin_key) = resource.skin_key {
1799 skin_consumers_scratch
1800 .entry(skin_key)
1801 .or_default()
1802 .push(mesh_key);
1803 }
1804 }
1805 }
1806 let skin_consumers: &HashMap<SkinKey, Vec<MeshKey>> = &self.skin_consumers_scratch;
1807
1808 if frame_index > 0 {
1809 let skin_keys: Vec<SkinKey> = self.skins.iter_skin_keys().collect();
1810 for skin_key in skin_keys {
1811 if !self.skin_should_update_this_frame(skin_key, frame_index) {
1813 skip_skins.insert(skin_key);
1814 continue;
1815 }
1816
1817 let consumers = skin_consumers
1819 .get(&skin_key)
1820 .map(Vec::as_slice)
1821 .unwrap_or(&[]);
1822
1823 let any_visible_last_frame = consumers
1833 .iter()
1834 .any(|mk| !coverage.is_below_threshold(*mk, 1));
1835
1836 let any_in_frustum = match frustum {
1837 None => true, Some(f) => consumers.iter().any(|mk| {
1839 self.list
1840 .get(*mk)
1841 .and_then(|m| m.world_aabb.as_ref())
1842 .map(|aabb| f.intersects_aabb(aabb))
1843 .unwrap_or(true)
1844 }),
1845 };
1846
1847 let grace = if any_visible_last_frame {
1851 0
1852 } else {
1853 self.skin_zero_coverage_grace
1854 .get(skin_key)
1855 .copied()
1856 .unwrap_or(0)
1857 .saturating_add(1)
1858 };
1859 self.skin_zero_coverage_grace.insert(skin_key, grace);
1860
1861 if !any_visible_last_frame && !any_in_frustum && grace > SKIN_COVERAGE_GRACE_FRAMES
1867 {
1868 skip_skins.insert(skin_key);
1869 }
1870 }
1871 }
1872
1873 self.skins
1875 .update_transforms(dirty_transforms, transforms, |skin_key| {
1876 !skip_skins.contains(&skin_key)
1877 });
1878
1879 touched
1880 }
1881
1882 fn update_mesh_transform(
1883 &mut self,
1884 mesh_key: MeshKey,
1885 old_transform_key: TransformKey,
1886 new_transform_key: TransformKey,
1887 materials: &Materials,
1888 transforms: &Transforms,
1889 ) -> Result<()> {
1890 let resource_aabb = self.resource(mesh_key).ok().and_then(|r| r.aabb.clone());
1891
1892 let world_aabb = match (
1897 resource_aabb.as_ref(),
1898 transforms.get_world(new_transform_key).ok(),
1899 ) {
1900 (Some(aabb), Some(world_mat)) => Some(aabb.transformed(world_mat)),
1901 (Some(aabb), None) => Some(aabb.clone()),
1902 (None, _) => None,
1903 };
1904
1905 if let Some(mesh) = self.list.get_mut(mesh_key) {
1906 mesh.transform_key = new_transform_key;
1907 mesh.world_aabb = world_aabb;
1908 }
1909
1910 if let Some(meshes) = self.transform_to_meshes.get_mut(old_transform_key) {
1911 meshes.retain(|&key| key != mesh_key);
1912 }
1913 if let Some(meshes) = self.transform_to_meshes.get(old_transform_key) {
1914 if meshes.is_empty() {
1915 self.transform_to_meshes.remove(old_transform_key);
1916 }
1917 }
1918
1919 if let Some(meshes) = self.transform_to_meshes.get_mut(new_transform_key) {
1920 meshes.push(mesh_key);
1921 } else {
1922 self.transform_to_meshes
1923 .insert(new_transform_key, vec![mesh_key]);
1924 }
1925
1926 self.refresh_meta_for_mesh(mesh_key, materials, transforms)?;
1927
1928 Ok(())
1929 }
1930
1931 pub fn refresh_meta_for_mesh_public(
1934 &mut self,
1935 mesh_key: MeshKey,
1936 materials: &Materials,
1937 transforms: &Transforms,
1938 ) -> Result<()> {
1939 self.refresh_meta_for_mesh(mesh_key, materials, transforms)
1940 }
1941
1942 fn refresh_meta_for_mesh(
1943 &mut self,
1944 mesh_key: MeshKey,
1945 materials: &Materials,
1946 transforms: &Transforms,
1947 ) -> Result<()> {
1948 let mesh = self
1949 .list
1950 .get(mesh_key)
1951 .ok_or(AwsmMeshError::MeshNotFound(mesh_key))?;
1952
1953 let (
1954 buffer_info_key,
1955 visibility_geometry_data_offset,
1956 custom_attribute_index_offset,
1957 custom_attribute_data_offset,
1958 geometry_morph_key,
1959 material_morph_key,
1960 skin_key,
1961 ) = {
1962 let resource = self.resource(mesh_key)?;
1963 (
1964 resource.buffer_info_key,
1965 resource.visibility_geometry_data_offset,
1966 resource.custom_attribute_index_offset,
1967 resource.custom_attribute_data_offset,
1968 resource.geometry_morph_key,
1969 resource.material_morph_key,
1970 resource.skin_key,
1971 )
1972 };
1973
1974 let buffer_info = self.buffer_infos.get(buffer_info_key)?;
1975
1976 self.meta.insert(
1977 mesh_key,
1978 mesh,
1979 buffer_info,
1980 visibility_geometry_data_offset,
1981 custom_attribute_index_offset,
1982 custom_attribute_data_offset,
1983 geometry_morph_key,
1984 material_morph_key,
1985 skin_key,
1986 materials,
1987 transforms,
1988 &self.morphs,
1989 &self.skins,
1990 )?;
1991
1992 Ok(())
1993 }
1994
1995 pub fn keys_by_transform_key(&self, transform_key: TransformKey) -> Option<&Vec<MeshKey>> {
1997 self.transform_to_meshes.get(transform_key)
1998 }
1999
2000 pub fn mesh_is_skinned(&self, mesh_key: MeshKey) -> bool {
2006 self.resource_key(mesh_key)
2007 .ok()
2008 .and_then(|rk| self.resources.get(rk))
2009 .map(|r| r.skin_key.is_some())
2010 .unwrap_or(false)
2011 }
2012
2013 pub fn mesh_triangle_count(&self, mesh_key: MeshKey) -> Option<usize> {
2016 let resource_key = self.resource_key(mesh_key).ok()?;
2017 let resource = self.resources.get(resource_key)?;
2018 let buffer_info = self.buffer_infos.get(resource.buffer_info_key).ok()?;
2019 Some(buffer_info.triangles.count)
2020 }
2021
2022 pub fn keys(&self) -> impl Iterator<Item = MeshKey> + '_ {
2024 self.list.keys()
2025 }
2026
2027 pub fn resource_key(&self, mesh_key: MeshKey) -> Result<MeshResourceKey> {
2029 self.mesh_to_resource
2030 .get(mesh_key)
2031 .copied()
2032 .ok_or(AwsmMeshError::MeshNotFound(mesh_key))
2033 }
2034
2035 pub fn buffer_info_key(&self, mesh_key: MeshKey) -> Result<MeshBufferInfoKey> {
2037 Ok(self.resource(mesh_key)?.buffer_info_key)
2038 }
2039
2040 pub fn buffer_info(&self, mesh_key: MeshKey) -> Result<&buffer_info::MeshBufferInfo> {
2042 let buffer_info_key = self.buffer_info_key(mesh_key)?;
2043 self.buffer_infos.get(buffer_info_key)
2044 }
2045
2046 pub fn resource(&self, mesh_key: MeshKey) -> Result<&MeshResource> {
2048 let resource_key = self.resource_key(mesh_key)?;
2049 self.resources
2050 .get(resource_key)
2051 .ok_or(AwsmMeshError::ResourceNotFound(resource_key))
2052 }
2053
2054 pub fn mesh_skin_key(&self, mesh_key: MeshKey) -> Option<Option<SkinKey>> {
2059 self.resource(mesh_key).ok().map(|r| r.skin_key)
2060 }
2061
2062 pub fn geometry_morph_key_for_mesh(&self, mesh_key: MeshKey) -> Option<GeometryMorphKey> {
2068 self.resource(mesh_key)
2069 .ok()
2070 .and_then(|r| r.geometry_morph_key)
2071 }
2072
2073 pub fn material_morph_key_for_mesh(&self, mesh_key: MeshKey) -> Option<MaterialMorphKey> {
2078 self.resource(mesh_key)
2079 .ok()
2080 .and_then(|r| r.material_morph_key)
2081 }
2082
2083 pub fn skin_smallest_period(&self, skin_key: SkinKey) -> u8 {
2090 let mut min_period: u8 = u8::MAX;
2091 for (mesh_key, mesh) in self.iter() {
2092 let same_skin = self
2093 .resource(mesh_key)
2094 .ok()
2095 .and_then(|r| r.skin_key)
2096 .map(|k| k == skin_key)
2097 .unwrap_or(false);
2098 if !same_skin {
2099 continue;
2100 }
2101 min_period = min_period.min(mesh.skin_update_period.max(1));
2102 }
2103 if min_period == u8::MAX {
2104 1
2105 } else {
2106 min_period
2107 }
2108 }
2109
2110 pub fn skin_all_consumers_zero_coverage(
2114 &self,
2115 skin_key: SkinKey,
2116 coverage: &crate::coverage::MeshCoverage,
2117 ) -> bool {
2118 let mut had_any_consumer = false;
2119 for (mesh_key, _mesh) in self.iter() {
2120 let same_skin = self
2121 .resource(mesh_key)
2122 .ok()
2123 .and_then(|r| r.skin_key)
2124 .map(|k| k == skin_key)
2125 .unwrap_or(false);
2126 if !same_skin {
2127 continue;
2128 }
2129 had_any_consumer = true;
2130 if coverage.is_visible_last_frame(mesh_key) {
2131 return false;
2132 }
2133 }
2134 had_any_consumer
2137 }
2138
2139 pub fn skin_should_update_this_frame(&self, skin_key: SkinKey, frame_index: u64) -> bool {
2144 let period = self.skin_smallest_period(skin_key).max(1) as u64;
2145 if period == 1 || frame_index == 0 {
2146 return true;
2147 }
2148 frame_index % period == 0
2149 }
2150
2151 pub fn mesh_geometry_pool_gpu_buffer(&self) -> &web_sys::GpuBuffer {
2157 &self.mesh_geometry_pool_gpu_buffer
2158 }
2159
2160 pub fn visibility_geometry_data_gpu_buffer(&self) -> &web_sys::GpuBuffer {
2165 &self.mesh_geometry_pool_gpu_buffer
2166 }
2167 pub fn visibility_geometry_data_buffer_offset(&self, key: MeshKey) -> Result<usize> {
2170 let resource_key = self.resource_key(key)?;
2171 self.resources
2172 .get(resource_key)
2173 .and_then(|r| r.visibility_geometry_data_offset)
2174 .ok_or(AwsmMeshError::VisibilityGeometryBufferNotFound(key))
2175 }
2176
2177 pub fn visibility_geometry_index_gpu_buffer(&self) -> &web_sys::GpuBuffer {
2179 &self.visibility_geometry_index_gpu_buffer
2180 }
2181 pub fn visibility_geometry_index_buffer_offset(&self, key: MeshKey) -> Result<usize> {
2183 let resource_key = self.resource_key(key)?;
2184 self.visibility_geometry_index_buffers
2185 .offset(resource_key)
2186 .ok_or(AwsmMeshError::VisibilityGeometryBufferNotFound(key))
2187 }
2188
2189 pub fn custom_attribute_data_gpu_buffer(&self) -> &web_sys::GpuBuffer {
2192 &self.mesh_geometry_pool_gpu_buffer
2193 }
2194 pub fn custom_attribute_data_buffer_offset(&self, key: MeshKey) -> Result<usize> {
2197 let resource_key = self.resource_key(key)?;
2198 self.resources
2199 .get(resource_key)
2200 .map(|r| r.custom_attribute_data_offset)
2201 .ok_or(AwsmMeshError::CustomAttributeBufferNotFound(key))
2202 }
2203
2204 pub fn transparency_geometry_data_gpu_buffer(&self) -> &web_sys::GpuBuffer {
2206 &self.transparency_geometry_data_gpu_buffer
2207 }
2208 pub fn transparency_geometry_data_buffer_offset(&self, key: MeshKey) -> Result<usize> {
2210 let resource_key = self.resource_key(key)?;
2211 self.transparency_geometry_data_buffers
2212 .offset(resource_key)
2213 .ok_or(AwsmMeshError::TransparencyGeometryBufferNotFound(key))
2214 }
2215 pub fn transparency_geometry_index_gpu_buffer(&self) -> &web_sys::GpuBuffer {
2218 &self.mesh_geometry_pool_gpu_buffer
2219 }
2220 pub fn transparency_geometry_index_buffer_offset(&self, key: MeshKey) -> Result<usize> {
2224 let resource_key = self.resource_key(key)?;
2225 self.resources
2226 .get(resource_key)
2227 .map(|r| r.custom_attribute_index_offset)
2228 .ok_or(AwsmMeshError::CustomAttributeBufferNotFound(key))
2229 }
2230
2231 pub fn custom_attribute_index_gpu_buffer(&self) -> &web_sys::GpuBuffer {
2234 &self.mesh_geometry_pool_gpu_buffer
2235 }
2236 pub fn custom_attribute_index_buffer_offset(&self, key: MeshKey) -> Result<usize> {
2239 let resource_key = self.resource_key(key)?;
2240 self.resources
2241 .get(resource_key)
2242 .map(|r| r.custom_attribute_index_offset)
2243 .ok_or(AwsmMeshError::CustomAttributeBufferNotFound(key))
2244 }
2245
2246 pub fn len(&self) -> usize {
2250 self.list.len()
2251 }
2252
2253 pub fn is_empty(&self) -> bool {
2255 self.list.is_empty()
2256 }
2257
2258 pub fn iter(&self) -> impl Iterator<Item = (MeshKey, &Mesh)> {
2260 self.list.iter()
2261 }
2262
2263 pub fn visible_triangle_count(&self) -> u64 {
2270 self.list
2271 .iter()
2272 .filter(|(_, m)| !m.hidden)
2273 .filter_map(|(k, _)| self.buffer_info(k).ok())
2274 .map(|info| (info.triangles.vertex_attribute_indices.count / 3) as u64)
2275 .sum()
2276 }
2277
2278 pub fn update_shadow_receiver_gates<F: FnMut(MeshKey) -> u32>(&mut self, mut gate_fn: F) {
2288 for mesh_key in self.list.keys() {
2289 let gate = gate_fn(mesh_key);
2290 self.meta.set_shadow_receiver_gate(mesh_key, gate);
2291 }
2292 }
2293
2294 pub fn get(&self, mesh_key: MeshKey) -> Result<&Mesh> {
2296 self.list
2297 .get(mesh_key)
2298 .ok_or(AwsmMeshError::MeshNotFound(mesh_key))
2299 }
2300
2301 pub(crate) fn get_mut(&mut self, mesh_key: MeshKey) -> Result<&mut Mesh> {
2303 self.list
2304 .get_mut(mesh_key)
2305 .ok_or(AwsmMeshError::MeshNotFound(mesh_key))
2306 }
2307
2308 pub(crate) fn remove_by_transform_key(
2310 &mut self,
2311 transform_key: TransformKey,
2312 ) -> Option<Vec<Mesh>> {
2313 if let Some(mesh_keys) = self.transform_to_meshes.get(transform_key).cloned() {
2314 let mut removed_meshes = Vec::with_capacity(mesh_keys.capacity());
2315 for mesh_key in mesh_keys.iter() {
2316 if let Some(mesh) = self.remove(*mesh_key) {
2317 removed_meshes.push(mesh);
2318 }
2319 }
2320 Some(removed_meshes)
2321 } else {
2322 None
2323 }
2324 }
2325 pub(crate) fn remove(&mut self, mesh_key: MeshKey) -> Option<Mesh> {
2327 if let Some(mesh) = self.list.remove(mesh_key) {
2328 self.meta.remove(mesh_key);
2329 self.last_effective_material.remove(mesh_key);
2333
2334 if let Some(meshes) = self.transform_to_meshes.get_mut(mesh.transform_key) {
2335 meshes.retain(|&key| key != mesh_key)
2336 }
2337
2338 if let Some(resource_key) = self.mesh_to_resource.remove(mesh_key) {
2339 let should_remove_resource = match self.resources.get_mut(resource_key) {
2340 Some(resource) => {
2341 if resource.refcount > 1 {
2342 resource.refcount -= 1;
2343 false
2344 } else {
2345 true
2346 }
2347 }
2348 None => false,
2349 };
2350
2351 if should_remove_resource {
2352 if let Some(resource) = self.resources.remove(resource_key) {
2353 self.mesh_geometry_pool_buffers.remove(resource_key);
2354 self.visibility_geometry_index_buffers.remove(resource_key);
2355 self.transparency_geometry_data_buffers.remove(resource_key);
2356
2357 self.mesh_geometry_pool_dirty = true;
2358 self.visibility_geometry_index_dirty = true;
2359 self.transparency_geometry_data_dirty = true;
2360
2361 if self.buffer_infos.remove(resource.buffer_info_key).is_some() {
2362 self.mesh_geometry_pool_dirty = true;
2363 self.visibility_geometry_index_dirty = true;
2364 self.transparency_geometry_data_dirty = true;
2365 }
2366
2367 if let Some(morph_key) = resource.geometry_morph_key {
2368 self.morphs.geometry.remove(morph_key);
2369 }
2370
2371 if let Some(morph_key) = resource.material_morph_key {
2372 self.morphs.material.remove(morph_key);
2373 }
2374
2375 if let Some(skin_key) = resource.skin_key {
2376 self.skins.remove(skin_key, None);
2377 self.skin_zero_coverage_grace.remove(skin_key);
2381 }
2382 }
2383 }
2384 }
2385
2386 Some(mesh)
2387 } else {
2388 None
2389 }
2390 }
2391
2392 pub fn write_gpu(
2394 &mut self,
2395 logging: &AwsmRendererLogging,
2396 gpu: &AwsmRendererWebGpu,
2397 bind_groups: &mut BindGroups,
2398 ) -> Result<()> {
2399 let any_dirty = self.mesh_geometry_pool_dirty
2400 || self.visibility_geometry_index_dirty
2401 || self.transparency_geometry_data_dirty;
2402
2403 if any_dirty {
2404 let _maybe_span_guard = if logging.render_timings.sub_frame() {
2405 Some(tracing::span!(tracing::Level::INFO, "Mesh GPU write").entered())
2406 } else {
2407 None
2408 };
2409
2410 if self.mesh_geometry_pool_dirty {
2411 let mut resized = false;
2412 if let Some(new_size) = self.mesh_geometry_pool_buffers.take_gpu_needs_resize() {
2413 self.mesh_geometry_pool_gpu_buffer = gpu.create_buffer(
2414 &BufferDescriptor::new(
2415 Some("MeshGeometryPool"),
2416 new_size,
2417 BufferUsage::new()
2418 .with_copy_dst()
2419 .with_vertex()
2420 .with_storage()
2421 .with_index(),
2422 )
2423 .into(),
2424 )?;
2425 bind_groups.mark_create(BindGroupCreate::MeshGeometryPoolResize);
2426 resized = true;
2427 }
2428 if resized {
2429 self.mesh_geometry_pool_buffers.clear_dirty_ranges();
2430 gpu.write_buffer(
2431 &self.mesh_geometry_pool_gpu_buffer,
2432 None,
2433 self.mesh_geometry_pool_buffers.raw_slice(),
2434 None,
2435 None,
2436 )?;
2437 } else {
2438 let ranges = self.mesh_geometry_pool_buffers.take_dirty_ranges();
2439 self.mesh_geometry_pool_uploader.write_dirty_ranges(
2440 gpu,
2441 &self.mesh_geometry_pool_gpu_buffer,
2442 self.mesh_geometry_pool_buffers.raw_slice().len(),
2443 self.mesh_geometry_pool_buffers.raw_slice(),
2444 &ranges,
2445 )?;
2446 }
2447 }
2448
2449 if self.visibility_geometry_index_dirty {
2450 let mut resized = false;
2451 if let Some(new_size) = self
2452 .visibility_geometry_index_buffers
2453 .take_gpu_needs_resize()
2454 {
2455 self.visibility_geometry_index_gpu_buffer = gpu.create_buffer(
2456 &BufferDescriptor::new(
2457 Some("MeshVisibilityIndex"),
2458 new_size,
2459 BufferUsage::new().with_copy_dst().with_index(),
2460 )
2461 .into(),
2462 )?;
2463 resized = true;
2464 }
2465 if resized {
2466 self.visibility_geometry_index_buffers.clear_dirty_ranges();
2467 gpu.write_buffer(
2468 &self.visibility_geometry_index_gpu_buffer,
2469 None,
2470 self.visibility_geometry_index_buffers.raw_slice(),
2471 None,
2472 None,
2473 )?;
2474 } else {
2475 let ranges = self.visibility_geometry_index_buffers.take_dirty_ranges();
2476 self.visibility_geometry_index_uploader.write_dirty_ranges(
2477 gpu,
2478 &self.visibility_geometry_index_gpu_buffer,
2479 self.visibility_geometry_index_buffers.raw_slice().len(),
2480 self.visibility_geometry_index_buffers.raw_slice(),
2481 &ranges,
2482 )?;
2483 }
2484 }
2485
2486 if self.transparency_geometry_data_dirty {
2487 let mut resized = false;
2488 if let Some(new_size) = self
2489 .transparency_geometry_data_buffers
2490 .take_gpu_needs_resize()
2491 {
2492 self.transparency_geometry_data_gpu_buffer = gpu.create_buffer(
2493 &BufferDescriptor::new(
2494 Some("MeshTransparencyGeometryData"),
2495 new_size,
2496 BufferUsage::new()
2497 .with_copy_dst()
2498 .with_vertex()
2499 .with_storage(),
2500 )
2501 .into(),
2502 )?;
2503 resized = true;
2504 }
2505 if resized {
2506 self.transparency_geometry_data_buffers.clear_dirty_ranges();
2507 gpu.write_buffer(
2508 &self.transparency_geometry_data_gpu_buffer,
2509 None,
2510 self.transparency_geometry_data_buffers.raw_slice(),
2511 None,
2512 None,
2513 )?;
2514 } else {
2515 let ranges = self.transparency_geometry_data_buffers.take_dirty_ranges();
2516 self.transparency_geometry_data_uploader
2517 .write_dirty_ranges(
2518 gpu,
2519 &self.transparency_geometry_data_gpu_buffer,
2520 self.transparency_geometry_data_buffers.raw_slice().len(),
2521 self.transparency_geometry_data_buffers.raw_slice(),
2522 &ranges,
2523 )?;
2524 }
2525 }
2526
2527 self.mesh_geometry_pool_dirty = false;
2528 self.visibility_geometry_index_dirty = false;
2529 self.transparency_geometry_data_dirty = false;
2530 }
2531
2532 Ok(())
2533 }
2534}
2535
2536impl Drop for Meshes {
2537 fn drop(&mut self) {
2538 self.mesh_geometry_pool_gpu_buffer.destroy();
2539 self.visibility_geometry_index_gpu_buffer.destroy();
2540 self.transparency_geometry_data_gpu_buffer.destroy();
2541 }
2542}
2543
2544new_key_type! {
2545 pub struct MeshKey;
2547 pub struct MeshResourceKey;
2549}