1use core::{iter, mem};
2
3use bevy_camera::visibility::ViewVisibility;
4use bevy_derive::{Deref, DerefMut};
5use bevy_ecs::prelude::*;
6use bevy_mesh::morph::{MeshMorphWeights, MorphWeights, MAX_MORPH_WEIGHTS};
7use bevy_platform::collections::hash_map::Entry;
8use bevy_render::mesh::allocator::MeshAllocator;
9use bevy_render::mesh::RenderMesh;
10use bevy_render::render_asset::RenderAssets;
11use bevy_render::render_resource::ShaderType;
12use bevy_render::sync_world::{MainEntity, MainEntityHashMap};
13use bevy_render::{
14 batching::NoAutomaticBatching,
15 render_resource::{BufferUsages, RawBufferVec},
16 renderer::{RenderDevice, RenderQueue},
17 Extract,
18};
19use bytemuck::{NoUninit, Pod, Zeroable};
20
21use crate::{skin, RenderMeshInstances};
22
23#[derive(Component)]
24pub struct MorphIndex {
25 pub index: u32,
26}
27
28#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Deref, DerefMut)]
30pub struct MorphDescriptorIndex(pub u32);
31
32#[derive(Resource)]
38pub enum MorphIndices {
39 Uniform {
42 current: MainEntityHashMap<MorphIndex>,
45
46 prev: MainEntityHashMap<MorphIndex>,
49 },
50
51 Storage {
54 morph_weights_info: MainEntityHashMap<MorphWeightsInfo>,
56 gpu_descriptor_indices: MainEntityHashMap<MorphDescriptorIndex>,
59 gpu_descriptor_free_list: Vec<MorphDescriptorIndex>,
61 },
62}
63
64#[derive(Clone, Copy)]
67pub struct MorphWeightsInfo {
68 current_weight_offset: u32,
71 pub(crate) prev_weight_offset: Option<u32>,
74 weight_count: u32,
76}
77
78impl FromWorld for MorphIndices {
79 fn from_world(world: &mut World) -> MorphIndices {
80 let render_device = world.resource::<RenderDevice>();
81
82 if skin::skins_use_uniform_buffers(&render_device.limits()) {
83 MorphIndices::Uniform {
84 current: MainEntityHashMap::default(),
85 prev: MainEntityHashMap::default(),
86 }
87 } else {
88 MorphIndices::Storage {
89 morph_weights_info: MainEntityHashMap::default(),
90 gpu_descriptor_indices: MainEntityHashMap::default(),
91 gpu_descriptor_free_list: vec![],
92 }
93 }
94 }
95}
96
97#[derive(Resource)]
104pub struct MorphUniforms {
105 pub current_buffer: RawBufferVec<f32>,
107 pub prev_buffer: RawBufferVec<f32>,
109 pub descriptors_buffer: Option<RawBufferVec<GpuMorphDescriptor>>,
116}
117
118impl FromWorld for MorphUniforms {
119 fn from_world(world: &mut World) -> MorphUniforms {
120 let render_device = world.resource::<RenderDevice>();
121
122 let skins_use_uniform_buffers = skin::skins_use_uniform_buffers(&render_device.limits());
123
124 let buffer_usages = BufferUsages::COPY_DST
125 | (if skins_use_uniform_buffers {
126 BufferUsages::UNIFORM
127 } else {
128 BufferUsages::STORAGE
129 });
130
131 MorphUniforms {
132 current_buffer: RawBufferVec::new(buffer_usages),
133 prev_buffer: RawBufferVec::new(buffer_usages),
134 descriptors_buffer: if skins_use_uniform_buffers {
135 None
136 } else {
137 Some(RawBufferVec::new(
138 BufferUsages::COPY_DST | BufferUsages::STORAGE,
139 ))
140 },
141 }
142 }
143}
144
145impl MorphUniforms {
146 fn prepare_for_new_frame(&mut self) {
149 mem::swap(&mut self.current_buffer, &mut self.prev_buffer);
150 self.current_buffer.clear();
151 }
152}
153
154impl MorphIndices {
155 pub fn morph_descriptor_index(&self, main_entity: MainEntity) -> Option<MorphDescriptorIndex> {
162 match *self {
163 MorphIndices::Uniform { .. } => None,
164 MorphIndices::Storage {
165 ref gpu_descriptor_indices,
166 ..
167 } => gpu_descriptor_indices.get(&main_entity).copied(),
168 }
169 }
170}
171
172#[derive(Clone, Copy, Default, ShaderType, Pod, Zeroable)]
175#[repr(C)]
176pub struct GpuMorphDescriptor {
177 pub current_weights_offset: u32,
179 pub prev_weights_offset: u32,
182 pub targets_offset: u32,
185 pub vertex_count: u32,
187 pub weight_count: u32,
189}
190
191pub fn write_morph_buffers(
193 render_device: Res<RenderDevice>,
194 render_queue: Res<RenderQueue>,
195 mut uniform: ResMut<MorphUniforms>,
196) {
197 if uniform.current_buffer.is_empty() {
198 return;
199 }
200 let len = uniform.current_buffer.len();
201 uniform.current_buffer.reserve(len, &render_device);
202 uniform
203 .current_buffer
204 .write_buffer(&render_device, &render_queue);
205
206 if let Some(ref mut descriptors_buffer) = uniform.descriptors_buffer {
210 if descriptors_buffer.is_empty() {
211 descriptors_buffer.push(GpuMorphDescriptor::default());
212 }
213 descriptors_buffer.write_buffer(&render_device, &render_queue);
214 }
215}
216
217const fn can_align(step: usize, target: usize) -> bool {
218 step.is_multiple_of(target) || target.is_multiple_of(step)
219}
220
221const WGPU_MIN_ALIGN: usize = 256;
222
223fn add_to_alignment<T: NoUninit + Default>(buffer: &mut RawBufferVec<T>) {
225 let n = WGPU_MIN_ALIGN;
226 let t_size = size_of::<T>();
227 if !can_align(n, t_size) {
228 panic!(
230 "RawBufferVec should contain only types with a size multiple or divisible by {n}, \
231 {} has a size of {t_size}, which is neither multiple or divisible by {n}",
232 core::any::type_name::<T>()
233 );
234 }
235
236 let buffer_size = buffer.len();
237 let byte_size = t_size * buffer_size;
238 let bytes_over_n = byte_size % n;
239 if bytes_over_n == 0 {
240 return;
241 }
242 let bytes_to_add = n - bytes_over_n;
243 let ts_to_add = bytes_to_add / t_size;
244 buffer.extend(iter::repeat_with(T::default).take(ts_to_add));
245}
246
247pub fn extract_morphs(
250 morph_indices: ResMut<MorphIndices>,
251 uniform: ResMut<MorphUniforms>,
252 query: Extract<Query<(Entity, &ViewVisibility, &MeshMorphWeights)>>,
253 weights_query: Extract<Query<&MorphWeights>>,
254 render_device: Res<RenderDevice>,
255) {
256 let (morph_indices, uniform) = (morph_indices.into_inner(), uniform.into_inner());
258
259 let morphs_use_uniform_buffers = skin::skins_use_uniform_buffers(&render_device.limits());
260
261 let maybe_old_morph_target_info = match *morph_indices {
264 MorphIndices::Uniform {
265 ref mut current,
266 ref mut prev,
267 } => {
268 mem::swap(current, prev);
269 current.clear();
270 None
271 }
272 MorphIndices::Storage {
273 morph_weights_info: ref mut morph_target_info,
274 ..
275 } => Some(mem::take(morph_target_info)),
276 };
277
278 uniform.prepare_for_new_frame();
279
280 for (entity, view_visibility, mesh_weights) in &query {
282 if !view_visibility.get() {
283 continue;
284 }
285 let Ok(weights) = (match mesh_weights {
286 MeshMorphWeights::Reference(entity) => {
287 weights_query.get(*entity).map(MorphWeights::weights)
288 }
289 MeshMorphWeights::Value { weights } => Ok(weights.as_slice()),
290 }) else {
291 continue;
292 };
293
294 let start = uniform.current_buffer.len();
297 if morphs_use_uniform_buffers {
298 let legal_weights = weights
299 .iter()
300 .chain(iter::repeat(&0.0))
301 .take(MAX_MORPH_WEIGHTS)
302 .copied();
303 uniform.current_buffer.extend(legal_weights);
304 add_to_alignment::<f32>(&mut uniform.current_buffer);
305 } else {
306 uniform.current_buffer.extend(weights.iter().copied());
307 }
308
309 let maybe_prev_weights_offset =
311 maybe_old_morph_target_info
312 .as_ref()
313 .and_then(|old_morph_target_info| {
314 old_morph_target_info
315 .get(&MainEntity::from(entity))
316 .map(|morph_target_info| morph_target_info.current_weight_offset)
317 });
318
319 match *morph_indices {
321 MorphIndices::Uniform {
322 ref mut current, ..
323 } => {
324 let index = (start * size_of::<f32>()) as u32;
325 current.insert(entity.into(), MorphIndex { index });
326 }
327 MorphIndices::Storage {
328 morph_weights_info: ref mut morph_target_info,
329 ..
330 } => {
331 morph_target_info.insert(
332 entity.into(),
333 MorphWeightsInfo {
334 current_weight_offset: start as u32,
335 prev_weight_offset: maybe_prev_weights_offset,
336 weight_count: weights.len() as u32,
337 },
338 );
339 }
340 }
341 }
342}
343
344pub fn prepare_morph_descriptors(
351 mut morph_indices: ResMut<MorphIndices>,
352 mut morph_uniforms: ResMut<MorphUniforms>,
353 render_mesh_instances: Res<RenderMeshInstances>,
354 meshes: Res<RenderAssets<RenderMesh>>,
355 mesh_allocator: Res<MeshAllocator>,
356) {
357 let (
359 &mut MorphIndices::Storage {
360 morph_weights_info: ref morph_target_info,
361 ref mut gpu_descriptor_indices,
362 ref mut gpu_descriptor_free_list,
363 },
364 &mut Some(ref mut descriptors_buffer),
365 ) = (&mut *morph_indices, &mut morph_uniforms.descriptors_buffer)
366 else {
367 return;
368 };
369
370 for (&morph_target_main_entity, morph_target_info) in morph_target_info {
371 let Some(mesh_id) = render_mesh_instances.mesh_asset_id(morph_target_main_entity) else {
372 continue;
373 };
374 let Some(mesh) = meshes.get(mesh_id) else {
375 continue;
376 };
377 let Some(morph_targets_slice) = mesh_allocator.mesh_morph_target_slice(&mesh_id) else {
378 continue;
379 };
380
381 let morph_descriptor = GpuMorphDescriptor {
383 current_weights_offset: morph_target_info.current_weight_offset,
384 prev_weights_offset: morph_target_info.prev_weight_offset.unwrap_or(!0),
385 targets_offset: morph_targets_slice.range.start,
386 vertex_count: mesh.vertex_count,
387 weight_count: morph_target_info.weight_count,
388 };
389
390 let descriptor_index;
397 match gpu_descriptor_indices.entry(morph_target_main_entity) {
398 Entry::Occupied(occupied_entry) => {
399 descriptor_index = *occupied_entry.get();
400 descriptors_buffer.set(descriptor_index.0, morph_descriptor);
401 }
402 Entry::Vacant(vacant_entry) => {
403 match gpu_descriptor_free_list.pop() {
404 Some(free_descriptor_index) => {
405 descriptor_index = free_descriptor_index;
406 descriptors_buffer.set(descriptor_index.0, morph_descriptor);
407 }
408 None => {
409 descriptor_index =
410 MorphDescriptorIndex(descriptors_buffer.push(morph_descriptor) as u32);
411 }
412 }
413 vacant_entry.insert(descriptor_index);
414 }
415 };
416
417 gpu_descriptor_indices.insert(morph_target_main_entity, descriptor_index);
419 }
420
421 gpu_descriptor_indices.retain(|morph_target_main_entity, descriptor_index| {
423 let live = morph_target_info.contains_key(morph_target_main_entity);
424 if !live {
425 gpu_descriptor_free_list.push(*descriptor_index);
426 }
427 live
428 });
429}
430
431pub fn no_automatic_morph_batching(
434 mut commands: Commands,
435 query: Query<Entity, (With<MeshMorphWeights>, Without<NoAutomaticBatching>)>,
436 render_device: Res<RenderDevice>,
437) {
438 if !skin::skins_use_uniform_buffers(&render_device.limits()) {
441 return;
442 }
443
444 for entity in &query {
445 commands.entity(entity).try_insert(NoAutomaticBatching);
446 }
447}