1use bevy_math::Mat4;
4use bevy_mesh::morph::MAX_MORPH_WEIGHTS;
5use bevy_render::{
6 render_resource::*,
7 renderer::{RenderAdapter, RenderDevice},
8};
9
10use crate::{binding_arrays_are_usable, render::skin::MAX_JOINTS, LightmapSlab};
11
12const MORPH_WEIGHT_SIZE: usize = size_of::<f32>();
13
14pub const MORPH_BUFFER_SIZE: usize = MAX_MORPH_WEIGHTS * MORPH_WEIGHT_SIZE;
20
21const JOINT_SIZE: usize = size_of::<Mat4>();
22pub(crate) const JOINT_BUFFER_SIZE: usize = MAX_JOINTS * JOINT_SIZE;
23
24mod layout_entry {
26 use core::num::NonZeroU32;
27
28 use super::{JOINT_BUFFER_SIZE, MORPH_BUFFER_SIZE};
29 use crate::{render::skin, MeshUniform, LIGHTMAPS_PER_SLAB};
30 use bevy_render::{
31 render_resource::{
32 binding_types::{
33 sampler, storage_buffer_read_only_sized, texture_2d, texture_3d,
34 uniform_buffer_sized,
35 },
36 BindGroupLayoutEntryBuilder, BufferSize, GpuArrayBuffer, SamplerBindingType,
37 ShaderStages, TextureSampleType,
38 },
39 settings::WgpuLimits,
40 };
41
42 pub(super) fn model(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
43 GpuArrayBuffer::<MeshUniform>::binding_layout(limits)
44 .visibility(ShaderStages::VERTEX_FRAGMENT)
45 }
46 pub(super) fn skinning(limits: &WgpuLimits) -> BindGroupLayoutEntryBuilder {
47 let size = BufferSize::new(JOINT_BUFFER_SIZE as u64);
50 if skin::skins_use_uniform_buffers(limits) {
51 uniform_buffer_sized(true, size)
52 } else {
53 storage_buffer_read_only_sized(false, size)
54 }
55 }
56 pub(super) fn weights() -> BindGroupLayoutEntryBuilder {
57 uniform_buffer_sized(true, BufferSize::new(MORPH_BUFFER_SIZE as u64))
58 }
59 pub(super) fn targets() -> BindGroupLayoutEntryBuilder {
60 texture_3d(TextureSampleType::Float { filterable: false })
61 }
62 pub(super) fn lightmaps_texture_view() -> BindGroupLayoutEntryBuilder {
63 texture_2d(TextureSampleType::Float { filterable: true }).visibility(ShaderStages::FRAGMENT)
64 }
65 pub(super) fn lightmaps_sampler() -> BindGroupLayoutEntryBuilder {
66 sampler(SamplerBindingType::Filtering).visibility(ShaderStages::FRAGMENT)
67 }
68 pub(super) fn lightmaps_texture_view_array() -> BindGroupLayoutEntryBuilder {
69 texture_2d(TextureSampleType::Float { filterable: true })
70 .visibility(ShaderStages::FRAGMENT)
71 .count(NonZeroU32::new(LIGHTMAPS_PER_SLAB as u32).unwrap())
72 }
73 pub(super) fn lightmaps_sampler_array() -> BindGroupLayoutEntryBuilder {
74 sampler(SamplerBindingType::Filtering)
75 .visibility(ShaderStages::FRAGMENT)
76 .count(NonZeroU32::new(LIGHTMAPS_PER_SLAB as u32).unwrap())
77 }
78}
79
80mod entry {
83 use crate::render::skin;
84
85 use super::{JOINT_BUFFER_SIZE, MORPH_BUFFER_SIZE};
86 use bevy_render::{
87 render_resource::{
88 BindGroupEntry, BindingResource, Buffer, BufferBinding, BufferSize, Sampler,
89 TextureView, WgpuSampler, WgpuTextureView,
90 },
91 renderer::RenderDevice,
92 };
93
94 fn entry(binding: u32, size: Option<u64>, buffer: &Buffer) -> BindGroupEntry<'_> {
95 BindGroupEntry {
96 binding,
97 resource: BindingResource::Buffer(BufferBinding {
98 buffer,
99 offset: 0,
100 size: size.map(|size| BufferSize::new(size).unwrap()),
101 }),
102 }
103 }
104 pub(super) fn model(binding: u32, resource: BindingResource) -> BindGroupEntry {
105 BindGroupEntry { binding, resource }
106 }
107 pub(super) fn skinning<'a>(
108 render_device: &RenderDevice,
109 binding: u32,
110 buffer: &'a Buffer,
111 ) -> BindGroupEntry<'a> {
112 let size = if skin::skins_use_uniform_buffers(&render_device.limits()) {
113 Some(JOINT_BUFFER_SIZE as u64)
114 } else {
115 None
116 };
117 entry(binding, size, buffer)
118 }
119 pub(super) fn weights(binding: u32, buffer: &Buffer) -> BindGroupEntry<'_> {
120 entry(binding, Some(MORPH_BUFFER_SIZE as u64), buffer)
121 }
122 pub(super) fn targets(binding: u32, texture: &TextureView) -> BindGroupEntry<'_> {
123 BindGroupEntry {
124 binding,
125 resource: BindingResource::TextureView(texture),
126 }
127 }
128 pub(super) fn lightmaps_texture_view(
129 binding: u32,
130 texture: &TextureView,
131 ) -> BindGroupEntry<'_> {
132 BindGroupEntry {
133 binding,
134 resource: BindingResource::TextureView(texture),
135 }
136 }
137 pub(super) fn lightmaps_sampler(binding: u32, sampler: &Sampler) -> BindGroupEntry<'_> {
138 BindGroupEntry {
139 binding,
140 resource: BindingResource::Sampler(sampler),
141 }
142 }
143 pub(super) fn lightmaps_texture_view_array<'a>(
144 binding: u32,
145 textures: &'a [&'a WgpuTextureView],
146 ) -> BindGroupEntry<'a> {
147 BindGroupEntry {
148 binding,
149 resource: BindingResource::TextureViewArray(textures),
150 }
151 }
152 pub(super) fn lightmaps_sampler_array<'a>(
153 binding: u32,
154 samplers: &'a [&'a WgpuSampler],
155 ) -> BindGroupEntry<'a> {
156 BindGroupEntry {
157 binding,
158 resource: BindingResource::SamplerArray(samplers),
159 }
160 }
161}
162
163#[derive(Clone)]
165pub struct MeshLayouts {
166 pub model_only: BindGroupLayoutDescriptor,
168
169 pub lightmapped: BindGroupLayoutDescriptor,
171
172 pub skinned: BindGroupLayoutDescriptor,
174
175 pub skinned_motion: BindGroupLayoutDescriptor,
178
179 pub morphed: BindGroupLayoutDescriptor,
183
184 pub morphed_motion: BindGroupLayoutDescriptor,
187
188 pub morphed_skinned: BindGroupLayoutDescriptor,
193
194 pub morphed_skinned_motion: BindGroupLayoutDescriptor,
198}
199
200impl MeshLayouts {
201 pub fn new(render_device: &RenderDevice, render_adapter: &RenderAdapter) -> Self {
205 MeshLayouts {
206 model_only: Self::model_only_layout(render_device),
207 lightmapped: Self::lightmapped_layout(render_device, render_adapter),
208 skinned: Self::skinned_layout(render_device),
209 skinned_motion: Self::skinned_motion_layout(render_device),
210 morphed: Self::morphed_layout(render_device),
211 morphed_motion: Self::morphed_motion_layout(render_device),
212 morphed_skinned: Self::morphed_skinned_layout(render_device),
213 morphed_skinned_motion: Self::morphed_skinned_motion_layout(render_device),
214 }
215 }
216
217 fn model_only_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
220 BindGroupLayoutDescriptor::new(
221 "mesh_layout",
222 &BindGroupLayoutEntries::single(
223 ShaderStages::empty(),
224 layout_entry::model(&render_device.limits()),
225 ),
226 )
227 }
228
229 fn skinned_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
231 BindGroupLayoutDescriptor::new(
232 "skinned_mesh_layout",
233 &BindGroupLayoutEntries::with_indices(
234 ShaderStages::VERTEX,
235 (
236 (0, layout_entry::model(&render_device.limits())),
237 (1, layout_entry::skinning(&render_device.limits())),
239 ),
240 ),
241 )
242 }
243
244 fn skinned_motion_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
247 BindGroupLayoutDescriptor::new(
248 "skinned_motion_mesh_layout",
249 &BindGroupLayoutEntries::with_indices(
250 ShaderStages::VERTEX,
251 (
252 (0, layout_entry::model(&render_device.limits())),
253 (1, layout_entry::skinning(&render_device.limits())),
255 (6, layout_entry::skinning(&render_device.limits())),
257 ),
258 ),
259 )
260 }
261
262 fn morphed_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
264 BindGroupLayoutDescriptor::new(
265 "morphed_mesh_layout",
266 &BindGroupLayoutEntries::with_indices(
267 ShaderStages::VERTEX,
268 (
269 (0, layout_entry::model(&render_device.limits())),
270 (2, layout_entry::weights()),
272 (3, layout_entry::targets()),
273 ),
274 ),
275 )
276 }
277
278 fn morphed_motion_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
281 BindGroupLayoutDescriptor::new(
282 "morphed_mesh_layout",
283 &BindGroupLayoutEntries::with_indices(
284 ShaderStages::VERTEX,
285 (
286 (0, layout_entry::model(&render_device.limits())),
287 (2, layout_entry::weights()),
289 (3, layout_entry::targets()),
290 (7, layout_entry::weights()),
292 ),
293 ),
294 )
295 }
296
297 fn morphed_skinned_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
300 BindGroupLayoutDescriptor::new(
301 "morphed_skinned_mesh_layout",
302 &BindGroupLayoutEntries::with_indices(
303 ShaderStages::VERTEX,
304 (
305 (0, layout_entry::model(&render_device.limits())),
306 (1, layout_entry::skinning(&render_device.limits())),
308 (2, layout_entry::weights()),
310 (3, layout_entry::targets()),
311 ),
312 ),
313 )
314 }
315
316 fn morphed_skinned_motion_layout(render_device: &RenderDevice) -> BindGroupLayoutDescriptor {
319 BindGroupLayoutDescriptor::new(
320 "morphed_skinned_motion_mesh_layout",
321 &BindGroupLayoutEntries::with_indices(
322 ShaderStages::VERTEX,
323 (
324 (0, layout_entry::model(&render_device.limits())),
325 (1, layout_entry::skinning(&render_device.limits())),
327 (2, layout_entry::weights()),
329 (3, layout_entry::targets()),
330 (6, layout_entry::skinning(&render_device.limits())),
332 (7, layout_entry::weights()),
334 ),
335 ),
336 )
337 }
338
339 fn lightmapped_layout(
340 render_device: &RenderDevice,
341 render_adapter: &RenderAdapter,
342 ) -> BindGroupLayoutDescriptor {
343 if binding_arrays_are_usable(render_device, render_adapter) {
344 BindGroupLayoutDescriptor::new(
345 "lightmapped_mesh_layout",
346 &BindGroupLayoutEntries::with_indices(
347 ShaderStages::VERTEX,
348 (
349 (0, layout_entry::model(&render_device.limits())),
350 (4, layout_entry::lightmaps_texture_view_array()),
351 (5, layout_entry::lightmaps_sampler_array()),
352 ),
353 ),
354 )
355 } else {
356 BindGroupLayoutDescriptor::new(
357 "lightmapped_mesh_layout",
358 &BindGroupLayoutEntries::with_indices(
359 ShaderStages::VERTEX,
360 (
361 (0, layout_entry::model(&render_device.limits())),
362 (4, layout_entry::lightmaps_texture_view()),
363 (5, layout_entry::lightmaps_sampler()),
364 ),
365 ),
366 )
367 }
368 }
369
370 pub fn model_only(
373 &self,
374 render_device: &RenderDevice,
375 pipeline_cache: &PipelineCache,
376 model: &BindingResource,
377 ) -> BindGroup {
378 render_device.create_bind_group(
379 "model_only_mesh_bind_group",
380 &pipeline_cache.get_bind_group_layout(&self.model_only),
381 &[entry::model(0, model.clone())],
382 )
383 }
384
385 pub fn lightmapped(
386 &self,
387 render_device: &RenderDevice,
388 pipeline_cache: &PipelineCache,
389 model: &BindingResource,
390 lightmap_slab: &LightmapSlab,
391 bindless_lightmaps: bool,
392 ) -> BindGroup {
393 if bindless_lightmaps {
394 let (texture_views, samplers) = lightmap_slab.build_binding_arrays();
395 render_device.create_bind_group(
396 "lightmapped_mesh_bind_group",
397 &pipeline_cache.get_bind_group_layout(&self.lightmapped),
398 &[
399 entry::model(0, model.clone()),
400 entry::lightmaps_texture_view_array(4, &texture_views),
401 entry::lightmaps_sampler_array(5, &samplers),
402 ],
403 )
404 } else {
405 let (texture_view, sampler) = lightmap_slab.bindings_for_first_lightmap();
406 render_device.create_bind_group(
407 "lightmapped_mesh_bind_group",
408 &pipeline_cache.get_bind_group_layout(&self.lightmapped),
409 &[
410 entry::model(0, model.clone()),
411 entry::lightmaps_texture_view(4, texture_view),
412 entry::lightmaps_sampler(5, sampler),
413 ],
414 )
415 }
416 }
417
418 pub fn skinned(
420 &self,
421 render_device: &RenderDevice,
422 pipeline_cache: &PipelineCache,
423 model: &BindingResource,
424 current_skin: &Buffer,
425 ) -> BindGroup {
426 render_device.create_bind_group(
427 "skinned_mesh_bind_group",
428 &pipeline_cache.get_bind_group_layout(&self.skinned),
429 &[
430 entry::model(0, model.clone()),
431 entry::skinning(render_device, 1, current_skin),
432 ],
433 )
434 }
435
436 pub fn skinned_motion(
444 &self,
445 render_device: &RenderDevice,
446 pipeline_cache: &PipelineCache,
447 model: &BindingResource,
448 current_skin: &Buffer,
449 prev_skin: &Buffer,
450 ) -> BindGroup {
451 render_device.create_bind_group(
452 "skinned_motion_mesh_bind_group",
453 &pipeline_cache.get_bind_group_layout(&self.skinned_motion),
454 &[
455 entry::model(0, model.clone()),
456 entry::skinning(render_device, 1, current_skin),
457 entry::skinning(render_device, 6, prev_skin),
458 ],
459 )
460 }
461
462 pub fn morphed(
464 &self,
465 render_device: &RenderDevice,
466 pipeline_cache: &PipelineCache,
467 model: &BindingResource,
468 current_weights: &Buffer,
469 targets: &TextureView,
470 ) -> BindGroup {
471 render_device.create_bind_group(
472 "morphed_mesh_bind_group",
473 &pipeline_cache.get_bind_group_layout(&self.morphed),
474 &[
475 entry::model(0, model.clone()),
476 entry::weights(2, current_weights),
477 entry::targets(3, targets),
478 ],
479 )
480 }
481
482 pub fn morphed_motion(
490 &self,
491 render_device: &RenderDevice,
492 pipeline_cache: &PipelineCache,
493 model: &BindingResource,
494 current_weights: &Buffer,
495 targets: &TextureView,
496 prev_weights: &Buffer,
497 ) -> BindGroup {
498 render_device.create_bind_group(
499 "morphed_motion_mesh_bind_group",
500 &pipeline_cache.get_bind_group_layout(&self.morphed_motion),
501 &[
502 entry::model(0, model.clone()),
503 entry::weights(2, current_weights),
504 entry::targets(3, targets),
505 entry::weights(7, prev_weights),
506 ],
507 )
508 }
509
510 pub fn morphed_skinned(
512 &self,
513 render_device: &RenderDevice,
514 pipeline_cache: &PipelineCache,
515 model: &BindingResource,
516 current_skin: &Buffer,
517 current_weights: &Buffer,
518 targets: &TextureView,
519 ) -> BindGroup {
520 render_device.create_bind_group(
521 "morphed_skinned_mesh_bind_group",
522 &pipeline_cache.get_bind_group_layout(&self.morphed_skinned),
523 &[
524 entry::model(0, model.clone()),
525 entry::skinning(render_device, 1, current_skin),
526 entry::weights(2, current_weights),
527 entry::targets(3, targets),
528 ],
529 )
530 }
531
532 pub fn morphed_skinned_motion(
540 &self,
541 render_device: &RenderDevice,
542 pipeline_cache: &PipelineCache,
543 model: &BindingResource,
544 current_skin: &Buffer,
545 current_weights: &Buffer,
546 targets: &TextureView,
547 prev_skin: &Buffer,
548 prev_weights: &Buffer,
549 ) -> BindGroup {
550 render_device.create_bind_group(
551 "morphed_skinned_motion_mesh_bind_group",
552 &pipeline_cache.get_bind_group_layout(&self.morphed_skinned_motion),
553 &[
554 entry::model(0, model.clone()),
555 entry::skinning(render_device, 1, current_skin),
556 entry::weights(2, current_weights),
557 entry::targets(3, targets),
558 entry::skinning(render_device, 6, prev_skin),
559 entry::weights(7, prev_weights),
560 ],
561 )
562 }
563}