1use core::num::NonZero;
4
5use bevy_core_pipeline::core_3d::Camera3d;
6use bevy_ecs::{
7 component::Component,
8 entity::{Entity, EntityHashMap},
9 query::{With, Without},
10 reflect::ReflectComponent,
11 system::{Commands, Query, Res, Resource},
12 world::{FromWorld, World},
13};
14use bevy_math::{AspectRatio, UVec2, UVec3, UVec4, Vec3Swizzles as _, Vec4};
15use bevy_reflect::{std_traits::ReflectDefault, Reflect};
16use bevy_render::{
17 camera::Camera,
18 render_resource::{
19 BindingResource, BufferBindingType, ShaderSize as _, ShaderType, StorageBuffer,
20 UniformBuffer,
21 },
22 renderer::{RenderDevice, RenderQueue},
23 sync_world::RenderEntity,
24 Extract,
25};
26use bevy_utils::{hashbrown::HashSet, tracing::warn};
27
28pub(crate) use crate::cluster::assign::assign_objects_to_clusters;
29use crate::MeshPipeline;
30
31mod assign;
32
33#[cfg(test)]
34mod test;
35
36pub const MAX_UNIFORM_BUFFER_CLUSTERABLE_OBJECTS: usize = 204;
39const _: () =
42 assert!(size_of::<GpuClusterableObject>() * MAX_UNIFORM_BUFFER_CLUSTERABLE_OBJECTS <= 16384);
43
44pub const CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT: u32 = 3;
47
48const CLUSTER_COUNT_SIZE: u32 = 9;
51
52const CLUSTER_OFFSET_MASK: u32 = (1 << (32 - (CLUSTER_COUNT_SIZE * 2))) - 1;
53const CLUSTER_COUNT_MASK: u32 = (1 << CLUSTER_COUNT_SIZE) - 1;
54
55#[derive(Debug, Copy, Clone, Reflect)]
67pub enum ClusterFarZMode {
68 MaxClusterableObjectRange,
73 Constant(f32),
75}
76
77#[derive(Debug, Copy, Clone, Reflect)]
79#[reflect(Default)]
80pub struct ClusterZConfig {
81 pub first_slice_depth: f32,
83 pub far_z_mode: ClusterFarZMode,
85}
86
87#[derive(Debug, Copy, Clone, Component, Reflect)]
89#[reflect(Component, Debug, Default)]
90pub enum ClusterConfig {
91 None,
93 Single,
96 XYZ {
98 dimensions: UVec3,
99 z_config: ClusterZConfig,
100 dynamic_resizing: bool,
103 },
104 FixedZ {
110 total: u32,
111 z_slices: u32,
112 z_config: ClusterZConfig,
113 dynamic_resizing: bool,
116 },
117}
118
119#[derive(Component, Debug, Default)]
120pub struct Clusters {
121 pub(crate) tile_size: UVec2,
123 pub(crate) dimensions: UVec3,
125 pub(crate) near: f32,
128 pub(crate) far: f32,
129 pub(crate) clusterable_objects: Vec<VisibleClusterableObjects>,
130}
131
132#[derive(Clone, Component, Debug, Default)]
133pub struct VisibleClusterableObjects {
134 pub(crate) entities: Vec<Entity>,
135 pub point_light_count: usize,
136 pub spot_light_count: usize,
137}
138
139#[derive(Resource, Default)]
140pub struct GlobalVisibleClusterableObjects {
141 pub(crate) entities: HashSet<Entity>,
142}
143
144#[derive(Resource)]
145pub struct GlobalClusterableObjectMeta {
146 pub gpu_clusterable_objects: GpuClusterableObjects,
147 pub entity_to_index: EntityHashMap<usize>,
148}
149
150#[derive(Copy, Clone, ShaderType, Default, Debug)]
151pub struct GpuClusterableObject {
152 pub(crate) light_custom_data: Vec4,
155 pub(crate) color_inverse_square_range: Vec4,
156 pub(crate) position_radius: Vec4,
157 pub(crate) flags: u32,
158 pub(crate) shadow_depth_bias: f32,
159 pub(crate) shadow_normal_bias: f32,
160 pub(crate) spot_light_tan_angle: f32,
161 pub(crate) soft_shadow_size: f32,
162 pub(crate) shadow_map_near_z: f32,
163 pub(crate) pad_a: f32,
164 pub(crate) pad_b: f32,
165}
166
167pub enum GpuClusterableObjects {
168 Uniform(UniformBuffer<GpuClusterableObjectsUniform>),
169 Storage(StorageBuffer<GpuClusterableObjectsStorage>),
170}
171
172#[derive(ShaderType)]
173pub struct GpuClusterableObjectsUniform {
174 data: Box<[GpuClusterableObject; MAX_UNIFORM_BUFFER_CLUSTERABLE_OBJECTS]>,
175}
176
177#[derive(ShaderType, Default)]
178pub struct GpuClusterableObjectsStorage {
179 #[size(runtime)]
180 data: Vec<GpuClusterableObject>,
181}
182
183#[derive(Component)]
184pub struct ExtractedClusterConfig {
185 pub(crate) near: f32,
187 pub(crate) far: f32,
188 pub(crate) dimensions: UVec3,
190}
191
192enum ExtractedClusterableObjectElement {
193 ClusterHeader(u32, u32),
194 ClusterableObjectEntity(Entity),
195}
196
197#[derive(Component)]
198pub struct ExtractedClusterableObjects {
199 data: Vec<ExtractedClusterableObjectElement>,
200}
201
202#[derive(ShaderType)]
203struct GpuClusterOffsetsAndCountsUniform {
204 data: Box<[UVec4; ViewClusterBindings::MAX_UNIFORM_ITEMS]>,
205}
206
207#[derive(ShaderType, Default)]
208struct GpuClusterableObjectIndexListsStorage {
209 #[size(runtime)]
210 data: Vec<u32>,
211}
212
213#[derive(ShaderType, Default)]
214struct GpuClusterOffsetsAndCountsStorage {
215 #[size(runtime)]
216 data: Vec<UVec4>,
217}
218
219enum ViewClusterBuffers {
220 Uniform {
221 clusterable_object_index_lists: UniformBuffer<GpuClusterableObjectIndexListsUniform>,
223 cluster_offsets_and_counts: UniformBuffer<GpuClusterOffsetsAndCountsUniform>,
225 },
226 Storage {
227 clusterable_object_index_lists: StorageBuffer<GpuClusterableObjectIndexListsStorage>,
228 cluster_offsets_and_counts: StorageBuffer<GpuClusterOffsetsAndCountsStorage>,
229 },
230}
231
232#[derive(Component)]
233pub struct ViewClusterBindings {
234 n_indices: usize,
235 n_offsets: usize,
236 buffers: ViewClusterBuffers,
237}
238
239impl Default for ClusterZConfig {
240 fn default() -> Self {
241 Self {
242 first_slice_depth: 5.0,
243 far_z_mode: ClusterFarZMode::MaxClusterableObjectRange,
244 }
245 }
246}
247
248impl Default for ClusterConfig {
249 fn default() -> Self {
250 Self::FixedZ {
253 total: 4096,
254 z_slices: 24,
255 z_config: ClusterZConfig::default(),
256 dynamic_resizing: true,
257 }
258 }
259}
260
261impl ClusterConfig {
262 fn dimensions_for_screen_size(&self, screen_size: UVec2) -> UVec3 {
263 match &self {
264 ClusterConfig::None => UVec3::ZERO,
265 ClusterConfig::Single => UVec3::ONE,
266 ClusterConfig::XYZ { dimensions, .. } => *dimensions,
267 ClusterConfig::FixedZ {
268 total, z_slices, ..
269 } => {
270 let aspect_ratio: f32 = AspectRatio::try_from_pixels(screen_size.x, screen_size.y)
271 .expect("Failed to calculate aspect ratio for Cluster: screen dimensions must be positive, non-zero values")
272 .ratio();
273 let mut z_slices = *z_slices;
274 if *total < z_slices {
275 warn!("ClusterConfig has more z-slices than total clusters!");
276 z_slices = *total;
277 }
278 let per_layer = *total as f32 / z_slices as f32;
279
280 let y = f32::sqrt(per_layer / aspect_ratio);
281
282 let mut x = (y * aspect_ratio) as u32;
283 let mut y = y as u32;
284
285 if x == 0 {
287 x = 1;
288 y = per_layer as u32;
289 }
290 if y == 0 {
291 x = per_layer as u32;
292 y = 1;
293 }
294
295 UVec3::new(x, y, z_slices)
296 }
297 }
298 }
299
300 fn first_slice_depth(&self) -> f32 {
301 match self {
302 ClusterConfig::None | ClusterConfig::Single => 0.0,
303 ClusterConfig::XYZ { z_config, .. } | ClusterConfig::FixedZ { z_config, .. } => {
304 z_config.first_slice_depth
305 }
306 }
307 }
308
309 fn far_z_mode(&self) -> ClusterFarZMode {
310 match self {
311 ClusterConfig::None => ClusterFarZMode::Constant(0.0),
312 ClusterConfig::Single => ClusterFarZMode::MaxClusterableObjectRange,
313 ClusterConfig::XYZ { z_config, .. } | ClusterConfig::FixedZ { z_config, .. } => {
314 z_config.far_z_mode
315 }
316 }
317 }
318
319 fn dynamic_resizing(&self) -> bool {
320 match self {
321 ClusterConfig::None | ClusterConfig::Single => false,
322 ClusterConfig::XYZ {
323 dynamic_resizing, ..
324 }
325 | ClusterConfig::FixedZ {
326 dynamic_resizing, ..
327 } => *dynamic_resizing,
328 }
329 }
330}
331
332impl Clusters {
333 fn update(&mut self, screen_size: UVec2, requested_dimensions: UVec3) {
334 debug_assert!(
335 requested_dimensions.x > 0 && requested_dimensions.y > 0 && requested_dimensions.z > 0
336 );
337
338 let tile_size = (screen_size.as_vec2() / requested_dimensions.xy().as_vec2())
339 .ceil()
340 .as_uvec2()
341 .max(UVec2::ONE);
342 self.tile_size = tile_size;
343 self.dimensions = (screen_size.as_vec2() / tile_size.as_vec2())
344 .ceil()
345 .as_uvec2()
346 .extend(requested_dimensions.z)
347 .max(UVec3::ONE);
348
349 debug_assert!(self.dimensions.x * self.dimensions.y * self.dimensions.z <= 4096);
351 }
352 fn clear(&mut self) {
353 self.tile_size = UVec2::ONE;
354 self.dimensions = UVec3::ZERO;
355 self.near = 0.0;
356 self.far = 0.0;
357 self.clusterable_objects.clear();
358 }
359}
360
361pub fn add_clusters(
362 mut commands: Commands,
363 cameras: Query<(Entity, Option<&ClusterConfig>, &Camera), (Without<Clusters>, With<Camera3d>)>,
364) {
365 for (entity, config, camera) in &cameras {
366 if !camera.is_active {
367 continue;
368 }
369
370 let config = config.copied().unwrap_or_default();
371 commands
374 .entity(entity)
375 .insert((Clusters::default(), config));
376 }
377}
378
379impl VisibleClusterableObjects {
380 #[inline]
381 pub fn iter(&self) -> impl DoubleEndedIterator<Item = &Entity> {
382 self.entities.iter()
383 }
384
385 #[inline]
386 pub fn len(&self) -> usize {
387 self.entities.len()
388 }
389
390 #[inline]
391 pub fn is_empty(&self) -> bool {
392 self.entities.is_empty()
393 }
394}
395
396impl GlobalVisibleClusterableObjects {
397 #[inline]
398 pub fn iter(&self) -> impl Iterator<Item = &Entity> {
399 self.entities.iter()
400 }
401
402 #[inline]
403 pub fn contains(&self, entity: Entity) -> bool {
404 self.entities.contains(&entity)
405 }
406}
407
408impl FromWorld for GlobalClusterableObjectMeta {
409 fn from_world(world: &mut World) -> Self {
410 Self::new(
411 world
412 .resource::<RenderDevice>()
413 .get_supported_read_only_binding_type(CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT),
414 )
415 }
416}
417
418impl GlobalClusterableObjectMeta {
419 pub fn new(buffer_binding_type: BufferBindingType) -> Self {
420 Self {
421 gpu_clusterable_objects: GpuClusterableObjects::new(buffer_binding_type),
422 entity_to_index: EntityHashMap::default(),
423 }
424 }
425}
426
427impl GpuClusterableObjects {
428 fn new(buffer_binding_type: BufferBindingType) -> Self {
429 match buffer_binding_type {
430 BufferBindingType::Storage { .. } => Self::storage(),
431 BufferBindingType::Uniform => Self::uniform(),
432 }
433 }
434
435 fn uniform() -> Self {
436 Self::Uniform(UniformBuffer::default())
437 }
438
439 fn storage() -> Self {
440 Self::Storage(StorageBuffer::default())
441 }
442
443 pub(crate) fn set(&mut self, mut clusterable_objects: Vec<GpuClusterableObject>) {
444 match self {
445 GpuClusterableObjects::Uniform(buffer) => {
446 let len = clusterable_objects
447 .len()
448 .min(MAX_UNIFORM_BUFFER_CLUSTERABLE_OBJECTS);
449 let src = &clusterable_objects[..len];
450 let dst = &mut buffer.get_mut().data[..len];
451 dst.copy_from_slice(src);
452 }
453 GpuClusterableObjects::Storage(buffer) => {
454 buffer.get_mut().data.clear();
455 buffer.get_mut().data.append(&mut clusterable_objects);
456 }
457 }
458 }
459
460 pub(crate) fn write_buffer(
461 &mut self,
462 render_device: &RenderDevice,
463 render_queue: &RenderQueue,
464 ) {
465 match self {
466 GpuClusterableObjects::Uniform(buffer) => {
467 buffer.write_buffer(render_device, render_queue);
468 }
469 GpuClusterableObjects::Storage(buffer) => {
470 buffer.write_buffer(render_device, render_queue);
471 }
472 }
473 }
474
475 pub fn binding(&self) -> Option<BindingResource> {
476 match self {
477 GpuClusterableObjects::Uniform(buffer) => buffer.binding(),
478 GpuClusterableObjects::Storage(buffer) => buffer.binding(),
479 }
480 }
481
482 pub fn min_size(buffer_binding_type: BufferBindingType) -> NonZero<u64> {
483 match buffer_binding_type {
484 BufferBindingType::Storage { .. } => GpuClusterableObjectsStorage::min_size(),
485 BufferBindingType::Uniform => GpuClusterableObjectsUniform::min_size(),
486 }
487 }
488}
489
490impl Default for GpuClusterableObjectsUniform {
491 fn default() -> Self {
492 Self {
493 data: Box::new(
494 [GpuClusterableObject::default(); MAX_UNIFORM_BUFFER_CLUSTERABLE_OBJECTS],
495 ),
496 }
497 }
498}
499
500pub(crate) struct ClusterableObjectOrderData<'a> {
501 pub(crate) entity: &'a Entity,
502 pub(crate) shadows_enabled: &'a bool,
503 pub(crate) is_volumetric_light: &'a bool,
504 pub(crate) is_spot_light: &'a bool,
505}
506
507#[allow(clippy::too_many_arguments)]
508pub(crate) fn clusterable_object_order(
521 a: ClusterableObjectOrderData,
522 b: ClusterableObjectOrderData,
523) -> core::cmp::Ordering {
524 a.is_spot_light
525 .cmp(b.is_spot_light) .then_with(|| b.shadows_enabled.cmp(a.shadows_enabled)) .then_with(|| b.is_volumetric_light.cmp(a.is_volumetric_light)) .then_with(|| a.entity.cmp(b.entity)) }
530
531pub fn extract_clusters(
533 mut commands: Commands,
534 views: Extract<Query<(RenderEntity, &Clusters, &Camera)>>,
535 mapper: Extract<Query<RenderEntity>>,
536) {
537 for (entity, clusters, camera) in &views {
538 let mut entity_commands = commands
539 .get_entity(entity)
540 .expect("Clusters entity wasn't synced.");
541 if !camera.is_active {
542 entity_commands.remove::<(ExtractedClusterableObjects, ExtractedClusterConfig)>();
543 continue;
544 }
545
546 let num_entities: usize = clusters
547 .clusterable_objects
548 .iter()
549 .map(|l| l.entities.len())
550 .sum();
551 let mut data = Vec::with_capacity(clusters.clusterable_objects.len() + num_entities);
552 for cluster_objects in &clusters.clusterable_objects {
553 data.push(ExtractedClusterableObjectElement::ClusterHeader(
554 cluster_objects.point_light_count as u32,
555 cluster_objects.spot_light_count as u32,
556 ));
557 for clusterable_entity in &cluster_objects.entities {
558 if let Ok(entity) = mapper.get(*clusterable_entity) {
559 data.push(ExtractedClusterableObjectElement::ClusterableObjectEntity(
560 entity,
561 ));
562 }
563 }
564 }
565
566 entity_commands.insert((
567 ExtractedClusterableObjects { data },
568 ExtractedClusterConfig {
569 near: clusters.near,
570 far: clusters.far,
571 dimensions: clusters.dimensions,
572 },
573 ));
574 }
575}
576
577pub fn prepare_clusters(
578 mut commands: Commands,
579 render_device: Res<RenderDevice>,
580 render_queue: Res<RenderQueue>,
581 mesh_pipeline: Res<MeshPipeline>,
582 global_clusterable_object_meta: Res<GlobalClusterableObjectMeta>,
583 views: Query<(Entity, &ExtractedClusterableObjects)>,
584) {
585 let render_device = render_device.into_inner();
586 let supports_storage_buffers = matches!(
587 mesh_pipeline.clustered_forward_buffer_binding_type,
588 BufferBindingType::Storage { .. }
589 );
590 for (entity, extracted_clusters) in &views {
591 let mut view_clusters_bindings =
592 ViewClusterBindings::new(mesh_pipeline.clustered_forward_buffer_binding_type);
593 view_clusters_bindings.clear();
594
595 for record in &extracted_clusters.data {
596 match record {
597 ExtractedClusterableObjectElement::ClusterHeader(
598 point_light_count,
599 spot_light_count,
600 ) => {
601 let offset = view_clusters_bindings.n_indices();
602 view_clusters_bindings.push_offset_and_counts(
603 offset,
604 *point_light_count as usize,
605 *spot_light_count as usize,
606 );
607 }
608 ExtractedClusterableObjectElement::ClusterableObjectEntity(entity) => {
609 if let Some(clusterable_object_index) =
610 global_clusterable_object_meta.entity_to_index.get(entity)
611 {
612 if view_clusters_bindings.n_indices() >= ViewClusterBindings::MAX_INDICES
613 && !supports_storage_buffers
614 {
615 warn!(
616 "Clusterable object index lists are full! The clusterable \
617 objects in the view are present in too many clusters."
618 );
619 break;
620 }
621 view_clusters_bindings.push_index(*clusterable_object_index);
622 }
623 }
624 }
625 }
626
627 view_clusters_bindings.write_buffers(render_device, &render_queue);
628
629 commands.entity(entity).insert(view_clusters_bindings);
630 }
631}
632
633impl ViewClusterBindings {
634 pub const MAX_OFFSETS: usize = 16384 / 4;
635 const MAX_UNIFORM_ITEMS: usize = Self::MAX_OFFSETS / 4;
636 pub const MAX_INDICES: usize = 16384;
637
638 pub fn new(buffer_binding_type: BufferBindingType) -> Self {
639 Self {
640 n_indices: 0,
641 n_offsets: 0,
642 buffers: ViewClusterBuffers::new(buffer_binding_type),
643 }
644 }
645
646 pub fn clear(&mut self) {
647 match &mut self.buffers {
648 ViewClusterBuffers::Uniform {
649 clusterable_object_index_lists,
650 cluster_offsets_and_counts,
651 } => {
652 *clusterable_object_index_lists.get_mut().data =
653 [UVec4::ZERO; Self::MAX_UNIFORM_ITEMS];
654 *cluster_offsets_and_counts.get_mut().data = [UVec4::ZERO; Self::MAX_UNIFORM_ITEMS];
655 }
656 ViewClusterBuffers::Storage {
657 clusterable_object_index_lists,
658 cluster_offsets_and_counts,
659 ..
660 } => {
661 clusterable_object_index_lists.get_mut().data.clear();
662 cluster_offsets_and_counts.get_mut().data.clear();
663 }
664 }
665 }
666
667 pub fn push_offset_and_counts(&mut self, offset: usize, point_count: usize, spot_count: usize) {
668 match &mut self.buffers {
669 ViewClusterBuffers::Uniform {
670 cluster_offsets_and_counts,
671 ..
672 } => {
673 let array_index = self.n_offsets >> 2; if array_index >= Self::MAX_UNIFORM_ITEMS {
675 warn!("cluster offset and count out of bounds!");
676 return;
677 }
678 let component = self.n_offsets & ((1 << 2) - 1);
679 let packed = pack_offset_and_counts(offset, point_count, spot_count);
680
681 cluster_offsets_and_counts.get_mut().data[array_index][component] = packed;
682 }
683 ViewClusterBuffers::Storage {
684 cluster_offsets_and_counts,
685 ..
686 } => {
687 cluster_offsets_and_counts.get_mut().data.push(UVec4::new(
688 offset as u32,
689 point_count as u32,
690 spot_count as u32,
691 0,
692 ));
693 }
694 }
695
696 self.n_offsets += 1;
697 }
698
699 pub fn n_indices(&self) -> usize {
700 self.n_indices
701 }
702
703 pub fn push_index(&mut self, index: usize) {
704 match &mut self.buffers {
705 ViewClusterBuffers::Uniform {
706 clusterable_object_index_lists,
707 ..
708 } => {
709 let array_index = self.n_indices >> 4; let component = (self.n_indices >> 2) & ((1 << 2) - 1);
711 let sub_index = self.n_indices & ((1 << 2) - 1);
712 let index = index as u32;
713
714 clusterable_object_index_lists.get_mut().data[array_index][component] |=
715 index << (8 * sub_index);
716 }
717 ViewClusterBuffers::Storage {
718 clusterable_object_index_lists,
719 ..
720 } => {
721 clusterable_object_index_lists
722 .get_mut()
723 .data
724 .push(index as u32);
725 }
726 }
727
728 self.n_indices += 1;
729 }
730
731 pub fn write_buffers(&mut self, render_device: &RenderDevice, render_queue: &RenderQueue) {
732 match &mut self.buffers {
733 ViewClusterBuffers::Uniform {
734 clusterable_object_index_lists,
735 cluster_offsets_and_counts,
736 } => {
737 clusterable_object_index_lists.write_buffer(render_device, render_queue);
738 cluster_offsets_and_counts.write_buffer(render_device, render_queue);
739 }
740 ViewClusterBuffers::Storage {
741 clusterable_object_index_lists,
742 cluster_offsets_and_counts,
743 } => {
744 clusterable_object_index_lists.write_buffer(render_device, render_queue);
745 cluster_offsets_and_counts.write_buffer(render_device, render_queue);
746 }
747 }
748 }
749
750 pub fn clusterable_object_index_lists_binding(&self) -> Option<BindingResource> {
751 match &self.buffers {
752 ViewClusterBuffers::Uniform {
753 clusterable_object_index_lists,
754 ..
755 } => clusterable_object_index_lists.binding(),
756 ViewClusterBuffers::Storage {
757 clusterable_object_index_lists,
758 ..
759 } => clusterable_object_index_lists.binding(),
760 }
761 }
762
763 pub fn offsets_and_counts_binding(&self) -> Option<BindingResource> {
764 match &self.buffers {
765 ViewClusterBuffers::Uniform {
766 cluster_offsets_and_counts,
767 ..
768 } => cluster_offsets_and_counts.binding(),
769 ViewClusterBuffers::Storage {
770 cluster_offsets_and_counts,
771 ..
772 } => cluster_offsets_and_counts.binding(),
773 }
774 }
775
776 pub fn min_size_clusterable_object_index_lists(
777 buffer_binding_type: BufferBindingType,
778 ) -> NonZero<u64> {
779 match buffer_binding_type {
780 BufferBindingType::Storage { .. } => GpuClusterableObjectIndexListsStorage::min_size(),
781 BufferBindingType::Uniform => GpuClusterableObjectIndexListsUniform::min_size(),
782 }
783 }
784
785 pub fn min_size_cluster_offsets_and_counts(
786 buffer_binding_type: BufferBindingType,
787 ) -> NonZero<u64> {
788 match buffer_binding_type {
789 BufferBindingType::Storage { .. } => GpuClusterOffsetsAndCountsStorage::min_size(),
790 BufferBindingType::Uniform => GpuClusterOffsetsAndCountsUniform::min_size(),
791 }
792 }
793}
794
795impl ViewClusterBuffers {
796 fn new(buffer_binding_type: BufferBindingType) -> Self {
797 match buffer_binding_type {
798 BufferBindingType::Storage { .. } => Self::storage(),
799 BufferBindingType::Uniform => Self::uniform(),
800 }
801 }
802
803 fn uniform() -> Self {
804 ViewClusterBuffers::Uniform {
805 clusterable_object_index_lists: UniformBuffer::default(),
806 cluster_offsets_and_counts: UniformBuffer::default(),
807 }
808 }
809
810 fn storage() -> Self {
811 ViewClusterBuffers::Storage {
812 clusterable_object_index_lists: StorageBuffer::default(),
813 cluster_offsets_and_counts: StorageBuffer::default(),
814 }
815 }
816}
817
818fn pack_offset_and_counts(offset: usize, point_count: usize, spot_count: usize) -> u32 {
833 ((offset as u32 & CLUSTER_OFFSET_MASK) << (CLUSTER_COUNT_SIZE * 2))
834 | (point_count as u32 & CLUSTER_COUNT_MASK) << CLUSTER_COUNT_SIZE
835 | (spot_count as u32 & CLUSTER_COUNT_MASK)
836}
837
838#[derive(ShaderType)]
839struct GpuClusterableObjectIndexListsUniform {
840 data: Box<[UVec4; ViewClusterBindings::MAX_UNIFORM_ITEMS]>,
841}
842
843const _: () = assert!(GpuClusterableObjectIndexListsUniform::SHADER_SIZE.get() <= 16384);
846
847impl Default for GpuClusterableObjectIndexListsUniform {
848 fn default() -> Self {
849 Self {
850 data: Box::new([UVec4::ZERO; ViewClusterBindings::MAX_UNIFORM_ITEMS]),
851 }
852 }
853}
854
855impl Default for GpuClusterOffsetsAndCountsUniform {
856 fn default() -> Self {
857 Self {
858 data: Box::new([UVec4::ZERO; ViewClusterBindings::MAX_UNIFORM_ITEMS]),
859 }
860 }
861}