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 mesh::MeshMetadata,
35 render_resource::{
36 binding_types::{
37 sampler, storage_buffer_read_only, storage_buffer_read_only_sized, texture_2d,
38 texture_3d, uniform_buffer_sized,
39 },
40 BindGroupLayoutEntryBuilder, BufferSize, GpuArrayBuffer, SamplerBindingType,
41 ShaderStages, TextureSampleType,
42 },
43 settings::WgpuLimits,
44 };
45
46 pub(super) fn model(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
47 GpuArrayBuffer::<MeshUniform>::binding_layout(limits)
48 .visibility(ShaderStages::VERTEX_FRAGMENT)
49 }
50 pub(super) fn metadata(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
51 if bevy_render::storage_buffers_are_unsupported(limits) {
52 uniform_buffer_sized(false, BufferSize::new(size_of::<MeshMetadata>() as u64))
53 } else {
54 storage_buffer_read_only::<MeshMetadata>(false)
55 }
56 }
57 pub(super) fn skinning(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
58 let size = BufferSize::new(JOINT_BUFFER_SIZE as u64);
61 if skin::skins_use_uniform_buffers(limits) {
62 uniform_buffer_sized(true, size)
63 } else {
64 storage_buffer_read_only_sized(false, size)
65 }
66 }
67 pub(super) fn weights(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
68 if skin::skins_use_uniform_buffers(limits) {
69 uniform_buffer_sized(true, BufferSize::new(MORPH_BUFFER_SIZE as u64))
70 } else {
71 storage_buffer_read_only::<f32>(false)
72 }
73 }
74 pub(super) fn targets(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
75 if skin::skins_use_uniform_buffers(limits) {
76 texture_3d(TextureSampleType::Float { filterable: false })
77 } else {
78 storage_buffer_read_only::<MorphAttributes>(false)
79 }
80 }
81 pub(super) fn morph_descriptors() -> BindGroupLayoutEntryBuilder {
82 storage_buffer_read_only::<GpuMorphDescriptor>(false)
83 }
84 pub(super) fn lightmaps_texture_view() -> BindGroupLayoutEntryBuilder {
85 texture_2d(TextureSampleType::Float { filterable: true }).visibility(ShaderStages::FRAGMENT)
86 }
87 pub(super) fn lightmaps_sampler() -> BindGroupLayoutEntryBuilder {
88 sampler(SamplerBindingType::Filtering).visibility(ShaderStages::FRAGMENT)
89 }
90 pub(super) fn lightmaps_texture_view_array() -> BindGroupLayoutEntryBuilder {
91 texture_2d(TextureSampleType::Float { filterable: true })
92 .visibility(ShaderStages::FRAGMENT)
93 .count(NonZeroU32::new(LIGHTMAPS_PER_SLAB as u32).unwrap())
94 }
95 pub(super) fn lightmaps_sampler_array() -> BindGroupLayoutEntryBuilder {
96 sampler(SamplerBindingType::Filtering)
97 .visibility(ShaderStages::FRAGMENT)
98 .count(NonZeroU32::new(LIGHTMAPS_PER_SLAB as u32).unwrap())
99 }
100}
101
102mod entry {
105 use crate::render::skin;
106 use bevy_render::mesh::morph::MorphTargetsResource;
107
108 use super::{JOINT_BUFFER_SIZE, MORPH_BUFFER_SIZE};
109 use bevy_render::{
110 render_resource::{
111 BindGroupEntry, BindingResource, Buffer, BufferBinding, BufferSize, Sampler,
112 TextureView, WgpuSampler, WgpuTextureView,
113 },
114 renderer::RenderDevice,
115 };
116
117 fn entry(binding: u32, size: Option<u64>, buffer: &Buffer) -> BindGroupEntry<'_> {
118 BindGroupEntry {
119 binding,
120 resource: BindingResource::Buffer(BufferBinding {
121 buffer,
122 offset: 0,
123 size: size.map(|size| BufferSize::new(size).unwrap()),
124 }),
125 }
126 }
127 pub(super) fn model(binding: u32, resource: BindingResource) -> BindGroupEntry {
128 BindGroupEntry { binding, resource }
129 }
130 pub(super) fn metadata<'a>(binding: u32, buffer: &'a Buffer) -> BindGroupEntry<'a> {
131 entry(binding, None, buffer)
132 }
133 pub(super) fn skinning<'a>(
134 render_device: &RenderDevice,
135 binding: u32,
136 buffer: &'a Buffer,
137 ) -> BindGroupEntry<'a> {
138 let size = if skin::skins_use_uniform_buffers(&render_device.limits()) {
139 Some(JOINT_BUFFER_SIZE as u64)
140 } else {
141 None
142 };
143 entry(binding, size, buffer)
144 }
145 pub(super) fn weights<'a>(
146 render_device: &'_ RenderDevice,
147 binding: u32,
148 buffer: &'a Buffer,
149 ) -> BindGroupEntry<'a> {
150 if skin::skins_use_uniform_buffers(&render_device.limits()) {
151 entry(binding, Some(MORPH_BUFFER_SIZE as u64), buffer)
152 } else {
153 entry(binding, None, buffer)
154 }
155 }
156 pub(super) fn targets(binding: u32, targets: MorphTargetsResource<'_>) -> BindGroupEntry<'_> {
157 BindGroupEntry {
158 binding,
159 resource: match targets {
160 MorphTargetsResource::Texture(texture_view) => {
161 BindingResource::TextureView(texture_view)
162 }
163 MorphTargetsResource::Storage(buffer) => buffer.as_entire_binding(),
164 },
165 }
166 }
167 pub(super) fn morph_descriptors(binding: u32, buffer: &Buffer) -> BindGroupEntry<'_> {
168 entry(binding, None, buffer)
169 }
170 pub(super) fn lightmaps_texture_view(
171 binding: u32,
172 texture: &TextureView,
173 ) -> BindGroupEntry<'_> {
174 BindGroupEntry {
175 binding,
176 resource: BindingResource::TextureView(texture),
177 }
178 }
179 pub(super) fn lightmaps_sampler(binding: u32, sampler: &Sampler) -> BindGroupEntry<'_> {
180 BindGroupEntry {
181 binding,
182 resource: BindingResource::Sampler(sampler),
183 }
184 }
185 pub(super) fn lightmaps_texture_view_array<'a>(
186 binding: u32,
187 textures: &'a [&'a WgpuTextureView],
188 ) -> BindGroupEntry<'a> {
189 BindGroupEntry {
190 binding,
191 resource: BindingResource::TextureViewArray(textures),
192 }
193 }
194 pub(super) fn lightmaps_sampler_array<'a>(
195 binding: u32,
196 samplers: &'a [&'a WgpuSampler],
197 ) -> BindGroupEntry<'a> {
198 BindGroupEntry {
199 binding,
200 resource: BindingResource::SamplerArray(samplers),
201 }
202 }
203}
204
205#[derive(Clone)]
207pub struct MeshLayouts {
208 pub model_only: BindGroupLayoutDescriptor,
210
211 pub lightmapped: BindGroupLayoutDescriptor,
213
214 pub skinned: BindGroupLayoutDescriptor,
216
217 pub skinned_motion: BindGroupLayoutDescriptor,
220
221 pub morphed: BindGroupLayoutDescriptor,
225
226 pub morphed_motion: BindGroupLayoutDescriptor,
229
230 pub morphed_skinned: BindGroupLayoutDescriptor,
235
236 pub morphed_skinned_motion: BindGroupLayoutDescriptor,
240}
241
242impl MeshLayouts {
243 pub fn new(render_device: &RenderDevice, render_adapter: &RenderAdapter) -> Self {
247 MeshLayouts {
248 model_only: Self::model_only_layout(render_device),
249 lightmapped: Self::lightmapped_layout(render_device, render_adapter),
250 skinned: Self::skinned_layout(render_device),
251 skinned_motion: Self::skinned_motion_layout(render_device),
252 morphed: Self::morphed_layout(render_device),
253 morphed_motion: Self::morphed_motion_layout(render_device),
254 morphed_skinned: Self::morphed_skinned_layout(render_device),
255 morphed_skinned_motion: Self::morphed_skinned_motion_layout(render_device),
256 }
257 }
258
259 fn model_only_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
262 let limits = render_device.limits();
263 BindGroupLayoutDescriptor::new(
264 "mesh_layout",
265 &BindGroupLayoutEntries::with_indices(
266 ShaderStages::VERTEX,
267 (
268 (0, layout_entry::model(&limits)),
269 (9, layout_entry::metadata(&limits)),
270 ),
271 ),
272 )
273 }
274
275 fn skinned_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
277 let limits = render_device.limits();
278 BindGroupLayoutDescriptor::new(
279 "skinned_mesh_layout",
280 &BindGroupLayoutEntries::with_indices(
281 ShaderStages::VERTEX,
282 (
283 (0, layout_entry::model(&limits)),
284 (9, layout_entry::metadata(&limits)),
285 (1, layout_entry::skinning(&limits)),
287 ),
288 ),
289 )
290 }
291
292 fn skinned_motion_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
295 let limits = render_device.limits();
296 BindGroupLayoutDescriptor::new(
297 "skinned_motion_mesh_layout",
298 &BindGroupLayoutEntries::with_indices(
299 ShaderStages::VERTEX,
300 (
301 (0, layout_entry::model(&limits)),
302 (9, layout_entry::metadata(&limits)),
303 (1, layout_entry::skinning(&limits)),
305 (6, layout_entry::skinning(&limits)),
307 ),
308 ),
309 )
310 }
311
312 fn morphed_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
314 let limits = render_device.limits();
315 let mut entries: ArrayVec<BindGroupLayoutEntry, 5> = ArrayVec::new();
316
317 entries.extend(
318 [
319 (0, layout_entry::model(&limits)),
320 (9, layout_entry::metadata(&limits)),
321 (2, layout_entry::weights(&limits)),
323 (3, layout_entry::targets(&limits)),
324 ]
325 .iter()
326 .map(|(binding, entry)| entry.build(*binding, ShaderStages::VERTEX)),
327 );
328
329 if !skin::skins_use_uniform_buffers(&limits) {
330 entries.push(layout_entry::morph_descriptors().build(8, ShaderStages::VERTEX));
331 }
332
333 BindGroupLayoutDescriptor::new("morphed_mesh_layout", &entries)
334 }
335
336 fn morphed_motion_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
339 let limits = render_device.limits();
340 let mut entries: ArrayVec<BindGroupLayoutEntry, 6> = ArrayVec::new();
341
342 entries.extend(
343 [
344 (0, layout_entry::model(&limits)),
345 (9, layout_entry::metadata(&limits)),
346 (2, layout_entry::weights(&limits)),
348 (3, layout_entry::targets(&limits)),
349 (7, layout_entry::weights(&limits)),
351 ]
352 .iter()
353 .map(|(binding, entry)| entry.build(*binding, ShaderStages::VERTEX)),
354 );
355
356 if !skin::skins_use_uniform_buffers(&limits) {
357 entries.push(layout_entry::morph_descriptors().build(8, ShaderStages::VERTEX));
358 }
359
360 BindGroupLayoutDescriptor::new("morphed_motion_layout", &entries)
361 }
362
363 fn morphed_skinned_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
366 let limits = render_device.limits();
367
368 let mut entries: ArrayVec<BindGroupLayoutEntry, 6> = ArrayVec::new();
369
370 entries.extend(
371 [
372 (0, layout_entry::model(&limits)),
373 (9, layout_entry::metadata(&limits)),
374 (1, layout_entry::skinning(&limits)),
376 (2, layout_entry::weights(&limits)),
378 (3, layout_entry::targets(&limits)),
379 ]
380 .iter()
381 .map(|(binding, entry)| entry.build(*binding, ShaderStages::VERTEX)),
382 );
383
384 if !skin::skins_use_uniform_buffers(&limits) {
385 entries.push(layout_entry::morph_descriptors().build(8, ShaderStages::VERTEX));
386 }
387
388 BindGroupLayoutDescriptor::new("morphed_skinned_mesh_layout", &entries)
389 }
390
391 fn morphed_skinned_motion_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
394 let limits = render_device.limits();
395
396 let mut entries: ArrayVec<BindGroupLayoutEntry, 8> = ArrayVec::new();
397
398 entries.extend(
399 [
400 (0, layout_entry::model(&limits)),
401 (9, layout_entry::metadata(&limits)),
402 (1, layout_entry::skinning(&limits)),
404 (2, layout_entry::weights(&limits)),
406 (3, layout_entry::targets(&limits)),
407 (6, layout_entry::skinning(&limits)),
409 (7, layout_entry::weights(&limits)),
411 ]
412 .iter()
413 .map(|(binding, entry)| entry.build(*binding, ShaderStages::VERTEX)),
414 );
415
416 if !skin::skins_use_uniform_buffers(&limits) {
417 entries.push(layout_entry::morph_descriptors().build(8, ShaderStages::VERTEX));
418 }
419
420 BindGroupLayoutDescriptor::new("morphed_skinned_motion_mesh_layout", &entries)
421 }
422
423 fn lightmapped_layout(
424 render_device: &RenderDevice,
425 render_adapter: &RenderAdapter,
426 ) -> BindGroupLayoutDescriptor {
427 let limits = render_device.limits();
428 if binding_arrays_are_usable(render_device, render_adapter) {
429 BindGroupLayoutDescriptor::new(
430 "lightmapped_mesh_layout",
431 &BindGroupLayoutEntries::with_indices(
432 ShaderStages::VERTEX,
433 (
434 (0, layout_entry::model(&limits)),
435 (9, layout_entry::metadata(&limits)),
436 (4, layout_entry::lightmaps_texture_view_array()),
437 (5, layout_entry::lightmaps_sampler_array()),
438 ),
439 ),
440 )
441 } else {
442 BindGroupLayoutDescriptor::new(
443 "lightmapped_mesh_layout",
444 &BindGroupLayoutEntries::with_indices(
445 ShaderStages::VERTEX,
446 (
447 (0, layout_entry::model(&limits)),
448 (9, layout_entry::metadata(&limits)),
449 (4, layout_entry::lightmaps_texture_view()),
450 (5, layout_entry::lightmaps_sampler()),
451 ),
452 ),
453 )
454 }
455 }
456
457 pub fn model_only(
460 &self,
461 render_device: &RenderDevice,
462 pipeline_cache: &PipelineCache,
463 model: &BindingResource,
464 metadata: &Buffer,
465 ) -> BindGroup {
466 render_device.create_bind_group(
467 "model_only_mesh_bind_group",
468 &pipeline_cache.get_bind_group_layout(&self.model_only),
469 &[entry::model(0, model.clone()), entry::metadata(9, metadata)],
470 )
471 }
472
473 pub fn lightmapped(
474 &self,
475 render_device: &RenderDevice,
476 pipeline_cache: &PipelineCache,
477 model: &BindingResource,
478 metadata: &Buffer,
479 lightmap_slab: &LightmapSlab,
480 bindless_lightmaps: bool,
481 ) -> BindGroup {
482 if bindless_lightmaps {
483 let (texture_views, samplers) = lightmap_slab.build_binding_arrays();
484 render_device.create_bind_group(
485 "lightmapped_mesh_bind_group",
486 &pipeline_cache.get_bind_group_layout(&self.lightmapped),
487 &[
488 entry::model(0, model.clone()),
489 entry::metadata(9, metadata),
490 entry::lightmaps_texture_view_array(4, &texture_views),
491 entry::lightmaps_sampler_array(5, &samplers),
492 ],
493 )
494 } else {
495 let (texture_view, sampler) = lightmap_slab.bindings_for_first_lightmap();
496 render_device.create_bind_group(
497 "lightmapped_mesh_bind_group",
498 &pipeline_cache.get_bind_group_layout(&self.lightmapped),
499 &[
500 entry::model(0, model.clone()),
501 entry::metadata(9, metadata),
502 entry::lightmaps_texture_view(4, texture_view),
503 entry::lightmaps_sampler(5, sampler),
504 ],
505 )
506 }
507 }
508
509 pub fn skinned(
511 &self,
512 render_device: &RenderDevice,
513 pipeline_cache: &PipelineCache,
514 model: &BindingResource,
515 metadata: &Buffer,
516 current_skin: &Buffer,
517 ) -> BindGroup {
518 render_device.create_bind_group(
519 "skinned_mesh_bind_group",
520 &pipeline_cache.get_bind_group_layout(&self.skinned),
521 &[
522 entry::model(0, model.clone()),
523 entry::metadata(9, metadata),
524 entry::skinning(render_device, 1, current_skin),
525 ],
526 )
527 }
528
529 pub fn skinned_motion(
537 &self,
538 render_device: &RenderDevice,
539 pipeline_cache: &PipelineCache,
540 model: &BindingResource,
541 metadata: &Buffer,
542 current_skin: &Buffer,
543 prev_skin: &Buffer,
544 ) -> BindGroup {
545 render_device.create_bind_group(
546 "skinned_motion_mesh_bind_group",
547 &pipeline_cache.get_bind_group_layout(&self.skinned_motion),
548 &[
549 entry::model(0, model.clone()),
550 entry::metadata(9, metadata),
551 entry::skinning(render_device, 1, current_skin),
552 entry::skinning(render_device, 6, prev_skin),
553 ],
554 )
555 }
556
557 pub fn morphed(
559 &self,
560 render_device: &RenderDevice,
561 pipeline_cache: &PipelineCache,
562 model: &BindingResource,
563 metadata: &Buffer,
564 current_weights: &Buffer,
565 targets: MorphTargetsResource,
566 maybe_morph_descriptors: Option<&Buffer>,
567 ) -> BindGroup {
568 let mut entries: ArrayVec<BindGroupEntry, 5> = ArrayVec::new();
569
570 entries.extend([
571 entry::model(0, model.clone()),
572 entry::metadata(9, metadata),
573 entry::weights(render_device, 2, current_weights),
574 entry::targets(3, targets),
575 ]);
576
577 if let Some(morph_descriptors) = maybe_morph_descriptors {
578 entries.push(entry::morph_descriptors(8, morph_descriptors));
579 }
580
581 render_device.create_bind_group(
582 "morphed_mesh_bind_group",
583 &pipeline_cache.get_bind_group_layout(&self.morphed),
584 &entries,
585 )
586 }
587
588 pub fn morphed_motion(
596 &self,
597 render_device: &RenderDevice,
598 pipeline_cache: &PipelineCache,
599 model: &BindingResource,
600 metadata: &Buffer,
601 current_weights: &Buffer,
602 prev_weights: &Buffer,
603 targets: MorphTargetsResource,
604 maybe_morph_descriptors: Option<&Buffer>,
605 ) -> BindGroup {
606 let mut entries: ArrayVec<BindGroupEntry, 6> = ArrayVec::new();
607
608 entries.extend([
609 entry::model(0, model.clone()),
610 entry::metadata(9, metadata),
611 entry::weights(render_device, 2, current_weights),
612 entry::targets(3, targets),
613 entry::weights(render_device, 7, prev_weights),
614 ]);
615
616 if let Some(morph_descriptors) = maybe_morph_descriptors {
617 entries.push(entry::morph_descriptors(8, morph_descriptors));
618 }
619
620 render_device.create_bind_group(
621 "morphed_motion_mesh_bind_group",
622 &pipeline_cache.get_bind_group_layout(&self.morphed_motion),
623 &entries,
624 )
625 }
626
627 pub fn morphed_skinned(
629 &self,
630 render_device: &RenderDevice,
631 pipeline_cache: &PipelineCache,
632 model: &BindingResource,
633 metadata: &Buffer,
634 current_skin: &Buffer,
635 current_weights: &Buffer,
636 targets: MorphTargetsResource,
637 maybe_morph_descriptors: Option<&Buffer>,
638 ) -> BindGroup {
639 let mut entries: ArrayVec<BindGroupEntry, 6> = ArrayVec::new();
640
641 entries.extend([
642 entry::model(0, model.clone()),
643 entry::metadata(9, metadata),
644 entry::skinning(render_device, 1, current_skin),
645 entry::weights(render_device, 2, current_weights),
646 entry::targets(3, targets),
647 ]);
648
649 if let Some(morph_descriptors) = maybe_morph_descriptors {
650 entries.push(entry::morph_descriptors(8, morph_descriptors));
651 }
652
653 render_device.create_bind_group(
654 "morphed_skinned_mesh_bind_group",
655 &pipeline_cache.get_bind_group_layout(&self.morphed_skinned),
656 &entries,
657 )
658 }
659
660 pub fn morphed_skinned_motion(
668 &self,
669 render_device: &RenderDevice,
670 pipeline_cache: &PipelineCache,
671 model: &BindingResource,
672 metadata: &Buffer,
673 current_skin: &Buffer,
674 current_weights: &Buffer,
675 targets: MorphTargetsResource,
676 prev_skin: &Buffer,
677 prev_weights: &Buffer,
678 morph_descriptors: Option<&Buffer>,
679 ) -> BindGroup {
680 let mut entries: ArrayVec<BindGroupEntry, 8> = ArrayVec::new();
681
682 entries.extend([
683 entry::model(0, model.clone()),
684 entry::metadata(9, metadata),
685 entry::skinning(render_device, 1, current_skin),
686 entry::weights(render_device, 2, current_weights),
687 entry::targets(3, targets),
688 entry::skinning(render_device, 6, prev_skin),
689 entry::weights(render_device, 7, prev_weights),
690 ]);
691
692 if let Some(morph_descriptors) = morph_descriptors {
693 entries.push(entry::morph_descriptors(8, morph_descriptors));
694 }
695
696 render_device.create_bind_group(
697 "morphed_skinned_motion_mesh_bind_group",
698 &pipeline_cache.get_bind_group_layout(&self.morphed_skinned_motion),
699 &entries,
700 )
701 }
702}