1use arrayvec::ArrayVec;
4use bevy_math::Mat4;
5use bevy_mesh::morph::MAX_MORPH_WEIGHTS;
6use bevy_render::{
7 mesh::morph::MorphTargetsResource,
8 render_resource::*,
9 renderer::{RenderAdapter, RenderDevice},
10};
11
12use crate::{binding_arrays_are_usable, render::skin::MAX_JOINTS, skin, LightmapSlab};
13
14const MORPH_WEIGHT_SIZE: usize = size_of::<f32>();
15
16pub const MORPH_BUFFER_SIZE: usize = MAX_MORPH_WEIGHTS * MORPH_WEIGHT_SIZE;
22
23const JOINT_SIZE: usize = size_of::<Mat4>();
24pub(crate) const JOINT_BUFFER_SIZE: usize = MAX_JOINTS * JOINT_SIZE;
25
26mod layout_entry {
28 use core::num::NonZeroU32;
29
30 use super::{JOINT_BUFFER_SIZE, MORPH_BUFFER_SIZE};
31 use crate::{render::skin, GpuMorphDescriptor, MeshUniform, LIGHTMAPS_PER_SLAB};
32 use bevy_mesh::morph::MorphAttributes;
33 use bevy_render::{
34 render_resource::{
35 binding_types::{
36 sampler, storage_buffer_read_only, storage_buffer_read_only_sized, texture_2d,
37 texture_3d, uniform_buffer_sized,
38 },
39 BindGroupLayoutEntryBuilder, BufferSize, GpuArrayBuffer, SamplerBindingType,
40 ShaderStages, TextureSampleType,
41 },
42 settings::WgpuLimits,
43 };
44
45 pub(super) fn model(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
46 GpuArrayBuffer::<MeshUniform>::binding_layout(limits)
47 .visibility(ShaderStages::VERTEX_FRAGMENT)
48 }
49 pub(super) fn skinning(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
50 let size = BufferSize::new(JOINT_BUFFER_SIZE as u64);
53 if skin::skins_use_uniform_buffers(limits) {
54 uniform_buffer_sized(true, size)
55 } else {
56 storage_buffer_read_only_sized(false, size)
57 }
58 }
59 pub(super) fn weights(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
60 if skin::skins_use_uniform_buffers(limits) {
61 uniform_buffer_sized(true, BufferSize::new(MORPH_BUFFER_SIZE as u64))
62 } else {
63 storage_buffer_read_only::<f32>(false)
64 }
65 }
66 pub(super) fn targets(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
67 if skin::skins_use_uniform_buffers(limits) {
68 texture_3d(TextureSampleType::Float { filterable: false })
69 } else {
70 storage_buffer_read_only::<MorphAttributes>(false)
71 }
72 }
73 pub(super) fn morph_descriptors() -> BindGroupLayoutEntryBuilder {
74 storage_buffer_read_only::<GpuMorphDescriptor>(false)
75 }
76 pub(super) fn lightmaps_texture_view() -> BindGroupLayoutEntryBuilder {
77 texture_2d(TextureSampleType::Float { filterable: true }).visibility(ShaderStages::FRAGMENT)
78 }
79 pub(super) fn lightmaps_sampler() -> BindGroupLayoutEntryBuilder {
80 sampler(SamplerBindingType::Filtering).visibility(ShaderStages::FRAGMENT)
81 }
82 pub(super) fn lightmaps_texture_view_array() -> BindGroupLayoutEntryBuilder {
83 texture_2d(TextureSampleType::Float { filterable: true })
84 .visibility(ShaderStages::FRAGMENT)
85 .count(NonZeroU32::new(LIGHTMAPS_PER_SLAB as u32).unwrap())
86 }
87 pub(super) fn lightmaps_sampler_array() -> BindGroupLayoutEntryBuilder {
88 sampler(SamplerBindingType::Filtering)
89 .visibility(ShaderStages::FRAGMENT)
90 .count(NonZeroU32::new(LIGHTMAPS_PER_SLAB as u32).unwrap())
91 }
92}
93
94mod entry {
97 use crate::render::skin;
98 use bevy_render::mesh::morph::MorphTargetsResource;
99
100 use super::{JOINT_BUFFER_SIZE, MORPH_BUFFER_SIZE};
101 use bevy_render::{
102 render_resource::{
103 BindGroupEntry, BindingResource, Buffer, BufferBinding, BufferSize, Sampler,
104 TextureView, WgpuSampler, WgpuTextureView,
105 },
106 renderer::RenderDevice,
107 };
108
109 fn entry(binding: u32, size: Option<u64>, buffer: &Buffer) -> BindGroupEntry<'_> {
110 BindGroupEntry {
111 binding,
112 resource: BindingResource::Buffer(BufferBinding {
113 buffer,
114 offset: 0,
115 size: size.map(|size| BufferSize::new(size).unwrap()),
116 }),
117 }
118 }
119 pub(super) fn model(binding: u32, resource: BindingResource) -> BindGroupEntry {
120 BindGroupEntry { binding, resource }
121 }
122 pub(super) fn skinning<'a>(
123 render_device: &RenderDevice,
124 binding: u32,
125 buffer: &'a Buffer,
126 ) -> BindGroupEntry<'a> {
127 let size = if skin::skins_use_uniform_buffers(&render_device.limits()) {
128 Some(JOINT_BUFFER_SIZE as u64)
129 } else {
130 None
131 };
132 entry(binding, size, buffer)
133 }
134 pub(super) fn weights<'a>(
135 render_device: &'_ RenderDevice,
136 binding: u32,
137 buffer: &'a Buffer,
138 ) -> BindGroupEntry<'a> {
139 if skin::skins_use_uniform_buffers(&render_device.limits()) {
140 entry(binding, Some(MORPH_BUFFER_SIZE as u64), buffer)
141 } else {
142 entry(binding, None, buffer)
143 }
144 }
145 pub(super) fn targets(binding: u32, targets: MorphTargetsResource<'_>) -> BindGroupEntry<'_> {
146 BindGroupEntry {
147 binding,
148 resource: match targets {
149 MorphTargetsResource::Texture(texture_view) => {
150 BindingResource::TextureView(texture_view)
151 }
152 MorphTargetsResource::Storage(buffer) => buffer.as_entire_binding(),
153 },
154 }
155 }
156 pub(super) fn morph_descriptors(binding: u32, buffer: &Buffer) -> BindGroupEntry<'_> {
157 entry(binding, None, buffer)
158 }
159 pub(super) fn lightmaps_texture_view(
160 binding: u32,
161 texture: &TextureView,
162 ) -> BindGroupEntry<'_> {
163 BindGroupEntry {
164 binding,
165 resource: BindingResource::TextureView(texture),
166 }
167 }
168 pub(super) fn lightmaps_sampler(binding: u32, sampler: &Sampler) -> BindGroupEntry<'_> {
169 BindGroupEntry {
170 binding,
171 resource: BindingResource::Sampler(sampler),
172 }
173 }
174 pub(super) fn lightmaps_texture_view_array<'a>(
175 binding: u32,
176 textures: &'a [&'a WgpuTextureView],
177 ) -> BindGroupEntry<'a> {
178 BindGroupEntry {
179 binding,
180 resource: BindingResource::TextureViewArray(textures),
181 }
182 }
183 pub(super) fn lightmaps_sampler_array<'a>(
184 binding: u32,
185 samplers: &'a [&'a WgpuSampler],
186 ) -> BindGroupEntry<'a> {
187 BindGroupEntry {
188 binding,
189 resource: BindingResource::SamplerArray(samplers),
190 }
191 }
192}
193
194#[derive(Clone)]
196pub struct MeshLayouts {
197 pub model_only: BindGroupLayoutDescriptor,
199
200 pub lightmapped: BindGroupLayoutDescriptor,
202
203 pub skinned: BindGroupLayoutDescriptor,
205
206 pub skinned_motion: BindGroupLayoutDescriptor,
209
210 pub morphed: BindGroupLayoutDescriptor,
214
215 pub morphed_motion: BindGroupLayoutDescriptor,
218
219 pub morphed_skinned: BindGroupLayoutDescriptor,
224
225 pub morphed_skinned_motion: BindGroupLayoutDescriptor,
229}
230
231impl MeshLayouts {
232 pub fn new(render_device: &RenderDevice, render_adapter: &RenderAdapter) -> Self {
236 MeshLayouts {
237 model_only: Self::model_only_layout(render_device),
238 lightmapped: Self::lightmapped_layout(render_device, render_adapter),
239 skinned: Self::skinned_layout(render_device),
240 skinned_motion: Self::skinned_motion_layout(render_device),
241 morphed: Self::morphed_layout(render_device),
242 morphed_motion: Self::morphed_motion_layout(render_device),
243 morphed_skinned: Self::morphed_skinned_layout(render_device),
244 morphed_skinned_motion: Self::morphed_skinned_motion_layout(render_device),
245 }
246 }
247
248 fn model_only_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
251 BindGroupLayoutDescriptor::new(
252 "mesh_layout",
253 &BindGroupLayoutEntries::single(
254 ShaderStages::empty(),
255 layout_entry::model(&render_device.limits()),
256 ),
257 )
258 }
259
260 fn skinned_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
262 BindGroupLayoutDescriptor::new(
263 "skinned_mesh_layout",
264 &BindGroupLayoutEntries::with_indices(
265 ShaderStages::VERTEX,
266 (
267 (0, layout_entry::model(&render_device.limits())),
268 (1, layout_entry::skinning(&render_device.limits())),
270 ),
271 ),
272 )
273 }
274
275 fn skinned_motion_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
278 BindGroupLayoutDescriptor::new(
279 "skinned_motion_mesh_layout",
280 &BindGroupLayoutEntries::with_indices(
281 ShaderStages::VERTEX,
282 (
283 (0, layout_entry::model(&render_device.limits())),
284 (1, layout_entry::skinning(&render_device.limits())),
286 (6, layout_entry::skinning(&render_device.limits())),
288 ),
289 ),
290 )
291 }
292
293 fn morphed_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
295 let limits = render_device.limits();
296
297 let mut entries: ArrayVec<BindGroupLayoutEntry, 4> = ArrayVec::new();
298
299 entries.extend(
300 [
301 (0, layout_entry::model(&limits)),
302 (2, layout_entry::weights(&limits)),
304 (3, layout_entry::targets(&limits)),
305 ]
306 .iter()
307 .map(|(binding, entry)| entry.build(*binding, ShaderStages::VERTEX)),
308 );
309
310 if !skin::skins_use_uniform_buffers(&render_device.limits()) {
311 entries.push(layout_entry::morph_descriptors().build(8, ShaderStages::VERTEX));
312 }
313
314 BindGroupLayoutDescriptor::new("morphed_mesh_layout", &entries)
315 }
316
317 fn morphed_motion_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
320 let limits = render_device.limits();
321
322 let mut entries: ArrayVec<BindGroupLayoutEntry, 5> = ArrayVec::new();
323
324 entries.extend(
325 [
326 (0, layout_entry::model(&limits)),
327 (2, layout_entry::weights(&limits)),
329 (3, layout_entry::targets(&limits)),
330 (7, layout_entry::weights(&limits)),
332 ]
333 .iter()
334 .map(|(binding, entry)| entry.build(*binding, ShaderStages::VERTEX)),
335 );
336
337 if !skin::skins_use_uniform_buffers(&render_device.limits()) {
338 entries.push(layout_entry::morph_descriptors().build(8, ShaderStages::VERTEX));
339 }
340
341 BindGroupLayoutDescriptor::new("morphed_motion_layout", &entries)
342 }
343
344 fn morphed_skinned_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
347 let limits = render_device.limits();
348
349 let mut entries: ArrayVec<BindGroupLayoutEntry, 5> = ArrayVec::new();
350
351 entries.extend(
352 [
353 (0, layout_entry::model(&limits)),
354 (1, layout_entry::skinning(&limits)),
356 (2, layout_entry::weights(&limits)),
358 (3, layout_entry::targets(&limits)),
359 ]
360 .iter()
361 .map(|(binding, entry)| entry.build(*binding, ShaderStages::VERTEX)),
362 );
363
364 if !skin::skins_use_uniform_buffers(&render_device.limits()) {
365 entries.push(layout_entry::morph_descriptors().build(8, ShaderStages::VERTEX));
366 }
367
368 BindGroupLayoutDescriptor::new("morphed_skinned_mesh_layout", &entries)
369 }
370
371 fn morphed_skinned_motion_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
374 let limits = render_device.limits();
375
376 let mut entries: ArrayVec<BindGroupLayoutEntry, 7> = ArrayVec::new();
377
378 entries.extend(
379 [
380 (0, layout_entry::model(&limits)),
381 (1, layout_entry::skinning(&limits)),
383 (2, layout_entry::weights(&limits)),
385 (3, layout_entry::targets(&limits)),
386 (6, layout_entry::skinning(&limits)),
388 (7, layout_entry::weights(&limits)),
390 ]
391 .iter()
392 .map(|(binding, entry)| entry.build(*binding, ShaderStages::VERTEX)),
393 );
394
395 if !skin::skins_use_uniform_buffers(&render_device.limits()) {
396 entries.push(layout_entry::morph_descriptors().build(8, ShaderStages::VERTEX));
397 }
398
399 BindGroupLayoutDescriptor::new("morphed_skinned_motion_mesh_layout", &entries)
400 }
401
402 fn lightmapped_layout(
403 render_device: &RenderDevice,
404 render_adapter: &RenderAdapter,
405 ) -> BindGroupLayoutDescriptor {
406 if binding_arrays_are_usable(render_device, render_adapter) {
407 BindGroupLayoutDescriptor::new(
408 "lightmapped_mesh_layout",
409 &BindGroupLayoutEntries::with_indices(
410 ShaderStages::VERTEX,
411 (
412 (0, layout_entry::model(&render_device.limits())),
413 (4, layout_entry::lightmaps_texture_view_array()),
414 (5, layout_entry::lightmaps_sampler_array()),
415 ),
416 ),
417 )
418 } else {
419 BindGroupLayoutDescriptor::new(
420 "lightmapped_mesh_layout",
421 &BindGroupLayoutEntries::with_indices(
422 ShaderStages::VERTEX,
423 (
424 (0, layout_entry::model(&render_device.limits())),
425 (4, layout_entry::lightmaps_texture_view()),
426 (5, layout_entry::lightmaps_sampler()),
427 ),
428 ),
429 )
430 }
431 }
432
433 pub fn model_only(
436 &self,
437 render_device: &RenderDevice,
438 pipeline_cache: &PipelineCache,
439 model: &BindingResource,
440 ) -> BindGroup {
441 render_device.create_bind_group(
442 "model_only_mesh_bind_group",
443 &pipeline_cache.get_bind_group_layout(&self.model_only),
444 &[entry::model(0, model.clone())],
445 )
446 }
447
448 pub fn lightmapped(
449 &self,
450 render_device: &RenderDevice,
451 pipeline_cache: &PipelineCache,
452 model: &BindingResource,
453 lightmap_slab: &LightmapSlab,
454 bindless_lightmaps: bool,
455 ) -> BindGroup {
456 if bindless_lightmaps {
457 let (texture_views, samplers) = lightmap_slab.build_binding_arrays();
458 render_device.create_bind_group(
459 "lightmapped_mesh_bind_group",
460 &pipeline_cache.get_bind_group_layout(&self.lightmapped),
461 &[
462 entry::model(0, model.clone()),
463 entry::lightmaps_texture_view_array(4, &texture_views),
464 entry::lightmaps_sampler_array(5, &samplers),
465 ],
466 )
467 } else {
468 let (texture_view, sampler) = lightmap_slab.bindings_for_first_lightmap();
469 render_device.create_bind_group(
470 "lightmapped_mesh_bind_group",
471 &pipeline_cache.get_bind_group_layout(&self.lightmapped),
472 &[
473 entry::model(0, model.clone()),
474 entry::lightmaps_texture_view(4, texture_view),
475 entry::lightmaps_sampler(5, sampler),
476 ],
477 )
478 }
479 }
480
481 pub fn skinned(
483 &self,
484 render_device: &RenderDevice,
485 pipeline_cache: &PipelineCache,
486 model: &BindingResource,
487 current_skin: &Buffer,
488 ) -> BindGroup {
489 render_device.create_bind_group(
490 "skinned_mesh_bind_group",
491 &pipeline_cache.get_bind_group_layout(&self.skinned),
492 &[
493 entry::model(0, model.clone()),
494 entry::skinning(render_device, 1, current_skin),
495 ],
496 )
497 }
498
499 pub fn skinned_motion(
507 &self,
508 render_device: &RenderDevice,
509 pipeline_cache: &PipelineCache,
510 model: &BindingResource,
511 current_skin: &Buffer,
512 prev_skin: &Buffer,
513 ) -> BindGroup {
514 render_device.create_bind_group(
515 "skinned_motion_mesh_bind_group",
516 &pipeline_cache.get_bind_group_layout(&self.skinned_motion),
517 &[
518 entry::model(0, model.clone()),
519 entry::skinning(render_device, 1, current_skin),
520 entry::skinning(render_device, 6, prev_skin),
521 ],
522 )
523 }
524
525 pub fn morphed(
527 &self,
528 render_device: &RenderDevice,
529 pipeline_cache: &PipelineCache,
530 model: &BindingResource,
531 current_weights: &Buffer,
532 targets: MorphTargetsResource,
533 maybe_morph_descriptors: Option<&Buffer>,
534 ) -> BindGroup {
535 let mut entries: ArrayVec<BindGroupEntry, 4> = ArrayVec::new();
536
537 entries.extend([
538 entry::model(0, model.clone()),
539 entry::weights(render_device, 2, current_weights),
540 entry::targets(3, targets),
541 ]);
542
543 if let Some(morph_descriptors) = maybe_morph_descriptors {
544 entries.push(entry::morph_descriptors(8, morph_descriptors));
545 }
546
547 render_device.create_bind_group(
548 "morphed_mesh_bind_group",
549 &pipeline_cache.get_bind_group_layout(&self.morphed),
550 &entries,
551 )
552 }
553
554 pub fn morphed_motion(
562 &self,
563 render_device: &RenderDevice,
564 pipeline_cache: &PipelineCache,
565 model: &BindingResource,
566 current_weights: &Buffer,
567 prev_weights: &Buffer,
568 targets: MorphTargetsResource,
569 maybe_morph_descriptors: Option<&Buffer>,
570 ) -> BindGroup {
571 let mut entries: ArrayVec<BindGroupEntry, 5> = ArrayVec::new();
572
573 entries.extend([
574 entry::model(0, model.clone()),
575 entry::weights(render_device, 2, current_weights),
576 entry::targets(3, targets),
577 entry::weights(render_device, 7, prev_weights),
578 ]);
579
580 if let Some(morph_descriptors) = maybe_morph_descriptors {
581 entries.push(entry::morph_descriptors(8, morph_descriptors));
582 }
583
584 render_device.create_bind_group(
585 "morphed_motion_mesh_bind_group",
586 &pipeline_cache.get_bind_group_layout(&self.morphed_motion),
587 &entries,
588 )
589 }
590
591 pub fn morphed_skinned(
593 &self,
594 render_device: &RenderDevice,
595 pipeline_cache: &PipelineCache,
596 model: &BindingResource,
597 current_skin: &Buffer,
598 current_weights: &Buffer,
599 targets: MorphTargetsResource,
600 maybe_morph_descriptors: Option<&Buffer>,
601 ) -> BindGroup {
602 let mut entries: ArrayVec<BindGroupEntry, 5> = ArrayVec::new();
603
604 entries.extend([
605 entry::model(0, model.clone()),
606 entry::skinning(render_device, 1, current_skin),
607 entry::weights(render_device, 2, current_weights),
608 entry::targets(3, targets),
609 ]);
610
611 if let Some(morph_descriptors) = maybe_morph_descriptors {
612 entries.push(entry::morph_descriptors(8, morph_descriptors));
613 }
614
615 render_device.create_bind_group(
616 "morphed_skinned_mesh_bind_group",
617 &pipeline_cache.get_bind_group_layout(&self.morphed_skinned),
618 &entries,
619 )
620 }
621
622 pub fn morphed_skinned_motion(
630 &self,
631 render_device: &RenderDevice,
632 pipeline_cache: &PipelineCache,
633 model: &BindingResource,
634 current_skin: &Buffer,
635 current_weights: &Buffer,
636 targets: MorphTargetsResource,
637 prev_skin: &Buffer,
638 prev_weights: &Buffer,
639 morph_descriptors: Option<&Buffer>,
640 ) -> BindGroup {
641 let mut entries: ArrayVec<BindGroupEntry, 7> = ArrayVec::new();
642
643 entries.extend([
644 entry::model(0, model.clone()),
645 entry::skinning(render_device, 1, current_skin),
646 entry::weights(render_device, 2, current_weights),
647 entry::targets(3, targets),
648 entry::skinning(render_device, 6, prev_skin),
649 entry::weights(render_device, 7, prev_weights),
650 ]);
651
652 if let Some(morph_descriptors) = morph_descriptors {
653 entries.push(entry::morph_descriptors(8, morph_descriptors));
654 }
655
656 render_device.create_bind_group(
657 "morphed_skinned_motion_mesh_bind_group",
658 &pipeline_cache.get_bind_group_layout(&self.morphed_skinned_motion),
659 &entries,
660 )
661 }
662}