1use core::{cmp::Ordering, iter, marker::PhantomData, mem, ops::Range};
8
9use bevy_derive::{Deref, DerefMut};
10use bevy_ecs::{
11 resource::Resource,
12 world::{FromWorld, World},
13};
14use bevy_platform::collections::{HashMap, HashSet};
15use bevy_reflect::{prelude::ReflectDefault, Reflect};
16use bevy_render::{
17 render_resource::{
18 BindGroup, BindGroupEntry, BindGroupLayout, BindingNumber, BindingResource,
19 BindingResources, BindlessDescriptor, BindlessIndex, BindlessIndexTableDescriptor,
20 BindlessResourceType, Buffer, BufferBinding, BufferDescriptor, BufferId,
21 BufferInitDescriptor, BufferUsages, CompareFunction, FilterMode, OwnedBindingResource,
22 PreparedBindGroup, RawBufferVec, Sampler, SamplerDescriptor, SamplerId, TextureView,
23 TextureViewDimension, TextureViewId, UnpreparedBindGroup, WgpuSampler, WgpuTextureView,
24 },
25 renderer::{RenderDevice, RenderQueue},
26 settings::WgpuFeatures,
27 texture::FallbackImage,
28};
29use bevy_utils::default;
30use bytemuck::Pod;
31use tracing::{error, trace};
32
33use crate::Material;
34
35#[derive(Resource)]
42pub enum MaterialBindGroupAllocator<M>
43where
44 M: Material,
45{
46 Bindless(Box<MaterialBindGroupBindlessAllocator<M>>),
48 NonBindless(Box<MaterialBindGroupNonBindlessAllocator<M>>),
50}
51
52pub struct MaterialBindGroupBindlessAllocator<M>
55where
56 M: Material,
57{
58 slabs: Vec<MaterialBindlessSlab<M>>,
60 bind_group_layout: BindGroupLayout,
62 bindless_descriptor: BindlessDescriptor,
66
67 fallback_buffers: HashMap<BindlessIndex, Buffer>,
73
74 slab_capacity: u32,
79}
80
81pub struct MaterialBindlessSlab<M>
83where
84 M: Material,
85{
86 bind_group: Option<BindGroup>,
91
92 bindless_index_tables: Vec<MaterialBindlessIndexTable<M>>,
102
103 samplers: HashMap<BindlessResourceType, MaterialBindlessBindingArray<Sampler>>,
105 textures: HashMap<BindlessResourceType, MaterialBindlessBindingArray<TextureView>>,
107 buffers: HashMap<BindlessIndex, MaterialBindlessBindingArray<Buffer>>,
109 data_buffers: HashMap<BindlessIndex, MaterialDataBuffer>,
112
113 extra_data: Vec<Option<M::Data>>,
118
119 free_slots: Vec<MaterialBindGroupSlot>,
121 live_allocation_count: u32,
123 allocated_resource_count: u32,
125}
126
127struct MaterialBindlessIndexTable<M>
134where
135 M: Material,
136{
137 buffer: RetainedRawBufferVec<u32>,
139 index_range: Range<BindlessIndex>,
147 binding_number: BindingNumber,
149 phantom: PhantomData<M>,
150}
151
152struct MaterialBindlessBindingArray<R>
155where
156 R: GetBindingResourceId,
157{
158 binding_number: BindingNumber,
160 bindings: Vec<Option<MaterialBindlessBinding<R>>>,
163 resource_type: BindlessResourceType,
165 resource_to_slot: HashMap<BindingResourceId, u32>,
169 free_slots: Vec<u32>,
171 len: u32,
173}
174
175struct MaterialBindlessBinding<R>
181where
182 R: GetBindingResourceId,
183{
184 resource: R,
186 ref_count: u32,
189}
190
191pub struct MaterialBindGroupNonBindlessAllocator<M>
193where
194 M: Material,
195{
196 bind_groups: Vec<Option<MaterialNonBindlessAllocatedBindGroup<M>>>,
199 to_prepare: HashSet<MaterialBindGroupIndex>,
204 free_indices: Vec<MaterialBindGroupIndex>,
206 phantom: PhantomData<M>,
207}
208
209enum MaterialNonBindlessAllocatedBindGroup<M>
212where
213 M: Material,
214{
215 Unprepared {
221 bind_group: UnpreparedBindGroup<M::Data>,
223 layout: BindGroupLayout,
225 },
226 Prepared {
228 bind_group: PreparedBindGroup<M::Data>,
229 #[expect(dead_code, reason = "These buffers are only referenced by bind groups")]
230 uniform_buffers: Vec<Buffer>,
231 },
232}
233
234#[derive(Resource)]
237pub struct FallbackBindlessResources {
238 filtering_sampler: Sampler,
240 non_filtering_sampler: Sampler,
242 comparison_sampler: Sampler,
244}
245
246#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
248enum BindingResourceId {
249 Buffer(BufferId),
251 TextureView(TextureViewDimension, TextureViewId),
253 Sampler(SamplerId),
255 DataBuffer,
260}
261
262enum BindingResourceArray<'a> {
268 Buffers(Vec<BufferBinding<'a>>),
270 TextureViews(Vec<&'a WgpuTextureView>),
272 Samplers(Vec<&'a WgpuSampler>),
274}
275
276#[derive(Clone, Copy, Debug, Default, Reflect)]
279#[reflect(Clone, Default)]
280pub struct MaterialBindingId {
281 pub group: MaterialBindGroupIndex,
283 pub slot: MaterialBindGroupSlot,
287}
288
289#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Reflect, Deref, DerefMut)]
294#[reflect(Default, Clone, PartialEq, Hash)]
295pub struct MaterialBindGroupIndex(pub u32);
296
297impl From<u32> for MaterialBindGroupIndex {
298 fn from(value: u32) -> Self {
299 MaterialBindGroupIndex(value)
300 }
301}
302
303#[derive(Clone, Copy, Debug, Default, PartialEq, Reflect, Deref, DerefMut)]
310#[reflect(Default, Clone, PartialEq)]
311pub struct MaterialBindGroupSlot(pub u32);
312
313enum BufferDirtyState {
318 Clean,
320 NeedsReserve,
322 NeedsUpload,
324}
325
326struct BindlessAllocationCandidate {
329 pre_existing_resources: HashMap<BindlessIndex, u32>,
333 needed_free_slots: u32,
336}
337
338trait GetBindingResourceId {
345 fn binding_resource_id(&self, resource_type: BindlessResourceType) -> BindingResourceId;
351}
352
353pub struct MaterialSlab<'a, M>(MaterialSlabImpl<'a, M>)
355where
356 M: Material;
357
358enum MaterialSlabImpl<'a, M>
362where
363 M: Material,
364{
365 Bindless(&'a MaterialBindlessSlab<M>),
368 NonBindless(MaterialNonBindlessSlab<'a, M>),
371}
372
373enum MaterialNonBindlessSlab<'a, M>
376where
377 M: Material,
378{
379 Prepared(&'a PreparedBindGroup<M::Data>),
381 Unprepared(&'a UnpreparedBindGroup<M::Data>),
383}
384
385struct MaterialDataBuffer {
390 binding_number: BindingNumber,
392 buffer: RetainedRawBufferVec<u8>,
397 aligned_element_size: u32,
400 free_slots: Vec<u32>,
402 len: u32,
404}
405
406#[derive(Deref, DerefMut)]
412struct RetainedRawBufferVec<T>
413where
414 T: Pod,
415{
416 #[deref]
418 buffer: RawBufferVec<T>,
419 dirty: BufferDirtyState,
421}
422
423const DEFAULT_BINDLESS_FALLBACK_BUFFER_SIZE: u64 = 16;
428
429impl From<u32> for MaterialBindGroupSlot {
430 fn from(value: u32) -> Self {
431 MaterialBindGroupSlot(value)
432 }
433}
434
435impl From<MaterialBindGroupSlot> for u32 {
436 fn from(value: MaterialBindGroupSlot) -> Self {
437 value.0
438 }
439}
440
441impl<'a> From<&'a OwnedBindingResource> for BindingResourceId {
442 fn from(value: &'a OwnedBindingResource) -> Self {
443 match *value {
444 OwnedBindingResource::Buffer(ref buffer) => BindingResourceId::Buffer(buffer.id()),
445 OwnedBindingResource::Data(_) => BindingResourceId::DataBuffer,
446 OwnedBindingResource::TextureView(ref texture_view_dimension, ref texture_view) => {
447 BindingResourceId::TextureView(*texture_view_dimension, texture_view.id())
448 }
449 OwnedBindingResource::Sampler(_, ref sampler) => {
450 BindingResourceId::Sampler(sampler.id())
451 }
452 }
453 }
454}
455
456impl GetBindingResourceId for Buffer {
457 fn binding_resource_id(&self, _: BindlessResourceType) -> BindingResourceId {
458 BindingResourceId::Buffer(self.id())
459 }
460}
461
462impl GetBindingResourceId for Sampler {
463 fn binding_resource_id(&self, _: BindlessResourceType) -> BindingResourceId {
464 BindingResourceId::Sampler(self.id())
465 }
466}
467
468impl GetBindingResourceId for TextureView {
469 fn binding_resource_id(&self, resource_type: BindlessResourceType) -> BindingResourceId {
470 let texture_view_dimension = match resource_type {
471 BindlessResourceType::Texture1d => TextureViewDimension::D1,
472 BindlessResourceType::Texture2d => TextureViewDimension::D2,
473 BindlessResourceType::Texture2dArray => TextureViewDimension::D2Array,
474 BindlessResourceType::Texture3d => TextureViewDimension::D3,
475 BindlessResourceType::TextureCube => TextureViewDimension::Cube,
476 BindlessResourceType::TextureCubeArray => TextureViewDimension::CubeArray,
477 _ => panic!("Resource type is not a texture"),
478 };
479 BindingResourceId::TextureView(texture_view_dimension, self.id())
480 }
481}
482
483impl<M> MaterialBindGroupAllocator<M>
484where
485 M: Material,
486{
487 fn new(render_device: &RenderDevice) -> MaterialBindGroupAllocator<M> {
490 if material_uses_bindless_resources::<M>(render_device) {
491 MaterialBindGroupAllocator::Bindless(Box::new(MaterialBindGroupBindlessAllocator::new(
492 render_device,
493 )))
494 } else {
495 MaterialBindGroupAllocator::NonBindless(Box::new(
496 MaterialBindGroupNonBindlessAllocator::new(),
497 ))
498 }
499 }
500
501 pub fn get(&self, group: MaterialBindGroupIndex) -> Option<MaterialSlab<M>> {
503 match *self {
504 MaterialBindGroupAllocator::Bindless(ref bindless_allocator) => bindless_allocator
505 .get(group)
506 .map(|bindless_slab| MaterialSlab(MaterialSlabImpl::Bindless(bindless_slab))),
507 MaterialBindGroupAllocator::NonBindless(ref non_bindless_allocator) => {
508 non_bindless_allocator.get(group).map(|non_bindless_slab| {
509 MaterialSlab(MaterialSlabImpl::NonBindless(non_bindless_slab))
510 })
511 }
512 }
513 }
514
515 pub fn allocate_unprepared(
522 &mut self,
523 unprepared_bind_group: UnpreparedBindGroup<M::Data>,
524 bind_group_layout: &BindGroupLayout,
525 ) -> MaterialBindingId {
526 match *self {
527 MaterialBindGroupAllocator::Bindless(
528 ref mut material_bind_group_bindless_allocator,
529 ) => material_bind_group_bindless_allocator.allocate_unprepared(unprepared_bind_group),
530 MaterialBindGroupAllocator::NonBindless(
531 ref mut material_bind_group_non_bindless_allocator,
532 ) => material_bind_group_non_bindless_allocator
533 .allocate_unprepared(unprepared_bind_group, (*bind_group_layout).clone()),
534 }
535 }
536
537 pub fn allocate_prepared(
547 &mut self,
548 prepared_bind_group: PreparedBindGroup<M::Data>,
549 ) -> MaterialBindingId {
550 match *self {
551 MaterialBindGroupAllocator::Bindless(_) => {
552 panic!(
553 "Bindless resources are incompatible with implementing `as_bind_group` \
554 directly; implement `unprepared_bind_group` instead or disable bindless"
555 )
556 }
557 MaterialBindGroupAllocator::NonBindless(ref mut non_bindless_allocator) => {
558 non_bindless_allocator.allocate_prepared(prepared_bind_group)
559 }
560 }
561 }
562
563 pub fn free(&mut self, material_binding_id: MaterialBindingId) {
567 match *self {
568 MaterialBindGroupAllocator::Bindless(
569 ref mut material_bind_group_bindless_allocator,
570 ) => material_bind_group_bindless_allocator.free(material_binding_id),
571 MaterialBindGroupAllocator::NonBindless(
572 ref mut material_bind_group_non_bindless_allocator,
573 ) => material_bind_group_non_bindless_allocator.free(material_binding_id),
574 }
575 }
576
577 pub fn prepare_bind_groups(
580 &mut self,
581 render_device: &RenderDevice,
582 fallback_bindless_resources: &FallbackBindlessResources,
583 fallback_image: &FallbackImage,
584 ) {
585 match *self {
586 MaterialBindGroupAllocator::Bindless(
587 ref mut material_bind_group_bindless_allocator,
588 ) => material_bind_group_bindless_allocator.prepare_bind_groups(
589 render_device,
590 fallback_bindless_resources,
591 fallback_image,
592 ),
593 MaterialBindGroupAllocator::NonBindless(
594 ref mut material_bind_group_non_bindless_allocator,
595 ) => material_bind_group_non_bindless_allocator.prepare_bind_groups(render_device),
596 }
597 }
598
599 pub fn write_buffers(&mut self, render_device: &RenderDevice, render_queue: &RenderQueue) {
605 match *self {
606 MaterialBindGroupAllocator::Bindless(
607 ref mut material_bind_group_bindless_allocator,
608 ) => material_bind_group_bindless_allocator.write_buffers(render_device, render_queue),
609 MaterialBindGroupAllocator::NonBindless(_) => {
610 }
612 }
613 }
614}
615
616impl<M> MaterialBindlessIndexTable<M>
617where
618 M: Material,
619{
620 fn new(
622 bindless_index_table_descriptor: &BindlessIndexTableDescriptor,
623 ) -> MaterialBindlessIndexTable<M> {
624 let mut buffer = RetainedRawBufferVec::new(BufferUsages::STORAGE);
626 for _ in *bindless_index_table_descriptor.indices.start
627 ..*bindless_index_table_descriptor.indices.end
628 {
629 buffer.push(0);
630 }
631
632 MaterialBindlessIndexTable {
633 buffer,
634 index_range: bindless_index_table_descriptor.indices.clone(),
635 binding_number: bindless_index_table_descriptor.binding_number,
636 phantom: PhantomData,
637 }
638 }
639
640 fn get(&self, slot: MaterialBindGroupSlot) -> &[u32] {
646 let struct_size = *self.index_range.end as usize - *self.index_range.start as usize;
647 let start = struct_size * slot.0 as usize;
648 &self.buffer.values()[start..(start + struct_size)]
649 }
650
651 fn get_binding(
653 &self,
654 slot: MaterialBindGroupSlot,
655 bindless_index: BindlessIndex,
656 ) -> Option<u32> {
657 if bindless_index < self.index_range.start || bindless_index >= self.index_range.end {
658 return None;
659 }
660 self.get(slot)
661 .get((*bindless_index - *self.index_range.start) as usize)
662 .copied()
663 }
664
665 fn table_length(&self) -> u32 {
666 self.index_range.end.0 - self.index_range.start.0
667 }
668
669 fn set(
677 &mut self,
678 slot: MaterialBindGroupSlot,
679 allocated_resource_slots: &HashMap<BindlessIndex, u32>,
680 ) {
681 let table_len = self.table_length() as usize;
682 let range = (slot.0 as usize * table_len)..((slot.0 as usize + 1) * table_len);
683 while self.buffer.len() < range.end {
684 self.buffer.push(0);
685 }
686
687 for (&bindless_index, &resource_slot) in allocated_resource_slots {
688 if self.index_range.contains(&bindless_index) {
689 self.buffer.set(
690 *bindless_index + range.start as u32 - *self.index_range.start,
691 resource_slot,
692 );
693 }
694 }
695
696 self.buffer.dirty = BufferDirtyState::NeedsReserve;
698 }
699
700 fn bind_group_entry(&self) -> BindGroupEntry {
702 BindGroupEntry {
703 binding: *self.binding_number,
704 resource: self
705 .buffer
706 .buffer()
707 .expect("Bindings buffer must exist")
708 .as_entire_binding(),
709 }
710 }
711}
712
713impl<T> RetainedRawBufferVec<T>
714where
715 T: Pod,
716{
717 fn new(buffer_usages: BufferUsages) -> RetainedRawBufferVec<T> {
720 RetainedRawBufferVec {
721 buffer: RawBufferVec::new(buffer_usages),
722 dirty: BufferDirtyState::NeedsUpload,
723 }
724 }
725
726 fn prepare(&mut self, render_device: &RenderDevice) {
728 match self.dirty {
729 BufferDirtyState::Clean | BufferDirtyState::NeedsUpload => {}
730 BufferDirtyState::NeedsReserve => {
731 let capacity = self.buffer.len();
732 self.buffer.reserve(capacity, render_device);
733 self.dirty = BufferDirtyState::NeedsUpload;
734 }
735 }
736 }
737
738 fn write(&mut self, render_device: &RenderDevice, render_queue: &RenderQueue) {
740 match self.dirty {
741 BufferDirtyState::Clean => {}
742 BufferDirtyState::NeedsReserve | BufferDirtyState::NeedsUpload => {
743 self.buffer.write_buffer(render_device, render_queue);
744 self.dirty = BufferDirtyState::Clean;
745 }
746 }
747 }
748}
749
750impl<M> MaterialBindGroupBindlessAllocator<M>
751where
752 M: Material,
753{
754 fn new(render_device: &RenderDevice) -> MaterialBindGroupBindlessAllocator<M> {
757 let bindless_descriptor = M::bindless_descriptor()
758 .expect("Non-bindless materials should use the non-bindless allocator");
759 let fallback_buffers = bindless_descriptor
760 .buffers
761 .iter()
762 .map(|bindless_buffer_descriptor| {
763 (
764 bindless_buffer_descriptor.bindless_index,
765 render_device.create_buffer(&BufferDescriptor {
766 label: Some("bindless fallback buffer"),
767 size: match bindless_buffer_descriptor.size {
768 Some(size) => size as u64,
769 None => DEFAULT_BINDLESS_FALLBACK_BUFFER_SIZE,
770 },
771 usage: BufferUsages::STORAGE,
772 mapped_at_creation: false,
773 }),
774 )
775 })
776 .collect();
777
778 MaterialBindGroupBindlessAllocator {
779 slabs: vec![],
780 bind_group_layout: M::bind_group_layout(render_device),
781 bindless_descriptor,
782 fallback_buffers,
783 slab_capacity: M::bindless_slot_count()
784 .expect("Non-bindless materials should use the non-bindless allocator")
785 .resolve(),
786 }
787 }
788
789 fn allocate_unprepared(
798 &mut self,
799 mut unprepared_bind_group: UnpreparedBindGroup<M::Data>,
800 ) -> MaterialBindingId {
801 for (slab_index, slab) in self.slabs.iter_mut().enumerate() {
802 trace!("Trying to allocate in slab {}", slab_index);
803 match slab.try_allocate(unprepared_bind_group, self.slab_capacity) {
804 Ok(slot) => {
805 return MaterialBindingId {
806 group: MaterialBindGroupIndex(slab_index as u32),
807 slot,
808 };
809 }
810 Err(bind_group) => unprepared_bind_group = bind_group,
811 }
812 }
813
814 let group = MaterialBindGroupIndex(self.slabs.len() as u32);
815 self.slabs
816 .push(MaterialBindlessSlab::new(&self.bindless_descriptor));
817
818 let Ok(slot) = self
820 .slabs
821 .last_mut()
822 .expect("We just pushed a slab")
823 .try_allocate(unprepared_bind_group, self.slab_capacity)
824 else {
825 panic!("An allocation into an empty slab should always succeed")
826 };
827
828 MaterialBindingId { group, slot }
829 }
830
831 fn free(&mut self, material_binding_id: MaterialBindingId) {
835 self.slabs
836 .get_mut(material_binding_id.group.0 as usize)
837 .expect("Slab should exist")
838 .free(material_binding_id.slot, &self.bindless_descriptor);
839 }
840
841 fn get(&self, group: MaterialBindGroupIndex) -> Option<&MaterialBindlessSlab<M>> {
846 self.slabs.get(group.0 as usize)
847 }
848
849 fn prepare_bind_groups(
853 &mut self,
854 render_device: &RenderDevice,
855 fallback_bindless_resources: &FallbackBindlessResources,
856 fallback_image: &FallbackImage,
857 ) {
858 for slab in &mut self.slabs {
859 slab.prepare(
860 render_device,
861 &self.bind_group_layout,
862 fallback_bindless_resources,
863 &self.fallback_buffers,
864 fallback_image,
865 &self.bindless_descriptor,
866 self.slab_capacity,
867 );
868 }
869 }
870
871 fn write_buffers(&mut self, render_device: &RenderDevice, render_queue: &RenderQueue) {
875 for slab in &mut self.slabs {
876 slab.write_buffer(render_device, render_queue);
877 }
878 }
879}
880
881impl<M> FromWorld for MaterialBindGroupAllocator<M>
882where
883 M: Material,
884{
885 fn from_world(world: &mut World) -> Self {
886 let render_device = world.resource::<RenderDevice>();
887 MaterialBindGroupAllocator::new(render_device)
888 }
889}
890
891impl<M> MaterialBindlessSlab<M>
892where
893 M: Material,
894{
895 fn try_allocate(
902 &mut self,
903 unprepared_bind_group: UnpreparedBindGroup<M::Data>,
904 slot_capacity: u32,
905 ) -> Result<MaterialBindGroupSlot, UnpreparedBindGroup<M::Data>> {
906 let Some(allocation_candidate) = self.check_allocation(&unprepared_bind_group) else {
908 return Err(unprepared_bind_group);
909 };
910
911 if self.allocated_resource_count > 0
920 && self.allocated_resource_count + allocation_candidate.needed_free_slots
921 > slot_capacity
922 {
923 trace!("Slab is full, can't allocate");
924 return Err(unprepared_bind_group);
925 }
926
927 let slot = self
929 .free_slots
930 .pop()
931 .unwrap_or(MaterialBindGroupSlot(self.live_allocation_count));
932
933 self.live_allocation_count += 1;
935
936 let allocated_resource_slots =
938 self.insert_resources(unprepared_bind_group.bindings, allocation_candidate);
939
940 for bindless_index_table in &mut self.bindless_index_tables {
942 bindless_index_table.set(slot, &allocated_resource_slots);
943 }
944
945 if self.extra_data.len() < (*slot as usize + 1) {
947 self.extra_data.resize_with(*slot as usize + 1, || None);
948 }
949 self.extra_data[*slot as usize] = Some(unprepared_bind_group.data);
950
951 self.bind_group = None;
953
954 Ok(slot)
955 }
956
957 fn check_allocation(
960 &self,
961 unprepared_bind_group: &UnpreparedBindGroup<M::Data>,
962 ) -> Option<BindlessAllocationCandidate> {
963 let mut allocation_candidate = BindlessAllocationCandidate {
964 pre_existing_resources: HashMap::default(),
965 needed_free_slots: 0,
966 };
967
968 for &(bindless_index, ref owned_binding_resource) in unprepared_bind_group.bindings.iter() {
969 let bindless_index = BindlessIndex(bindless_index);
970 match *owned_binding_resource {
971 OwnedBindingResource::Buffer(ref buffer) => {
972 let Some(binding_array) = self.buffers.get(&bindless_index) else {
973 error!(
974 "Binding array wasn't present for buffer at index {:?}",
975 bindless_index
976 );
977 return None;
978 };
979 match binding_array.find(BindingResourceId::Buffer(buffer.id())) {
980 Some(slot) => {
981 allocation_candidate
982 .pre_existing_resources
983 .insert(bindless_index, slot);
984 }
985 None => allocation_candidate.needed_free_slots += 1,
986 }
987 }
988
989 OwnedBindingResource::Data(_) => {
990 }
992
993 OwnedBindingResource::TextureView(texture_view_dimension, ref texture_view) => {
994 let bindless_resource_type = BindlessResourceType::from(texture_view_dimension);
995 match self
996 .textures
997 .get(&bindless_resource_type)
998 .expect("Missing binding array for texture")
999 .find(BindingResourceId::TextureView(
1000 texture_view_dimension,
1001 texture_view.id(),
1002 )) {
1003 Some(slot) => {
1004 allocation_candidate
1005 .pre_existing_resources
1006 .insert(bindless_index, slot);
1007 }
1008 None => {
1009 allocation_candidate.needed_free_slots += 1;
1010 }
1011 }
1012 }
1013
1014 OwnedBindingResource::Sampler(sampler_binding_type, ref sampler) => {
1015 let bindless_resource_type = BindlessResourceType::from(sampler_binding_type);
1016 match self
1017 .samplers
1018 .get(&bindless_resource_type)
1019 .expect("Missing binding array for sampler")
1020 .find(BindingResourceId::Sampler(sampler.id()))
1021 {
1022 Some(slot) => {
1023 allocation_candidate
1024 .pre_existing_resources
1025 .insert(bindless_index, slot);
1026 }
1027 None => {
1028 allocation_candidate.needed_free_slots += 1;
1029 }
1030 }
1031 }
1032 }
1033 }
1034
1035 Some(allocation_candidate)
1036 }
1037
1038 fn insert_resources(
1043 &mut self,
1044 mut binding_resources: BindingResources,
1045 allocation_candidate: BindlessAllocationCandidate,
1046 ) -> HashMap<BindlessIndex, u32> {
1047 let mut allocated_resource_slots = HashMap::default();
1048
1049 for (bindless_index, owned_binding_resource) in binding_resources.drain(..) {
1050 let bindless_index = BindlessIndex(bindless_index);
1051 if let Some(pre_existing_resource_slot) = allocation_candidate
1054 .pre_existing_resources
1055 .get(&bindless_index)
1056 {
1057 allocated_resource_slots.insert(bindless_index, *pre_existing_resource_slot);
1058
1059 match owned_binding_resource {
1060 OwnedBindingResource::Buffer(_) => {
1061 self.buffers
1062 .get_mut(&bindless_index)
1063 .expect("Buffer binding array should exist")
1064 .bindings
1065 .get_mut(*pre_existing_resource_slot as usize)
1066 .and_then(|binding| binding.as_mut())
1067 .expect("Slot should exist")
1068 .ref_count += 1;
1069 }
1070
1071 OwnedBindingResource::Data(_) => {
1072 panic!("Data buffers can't be deduplicated")
1073 }
1074
1075 OwnedBindingResource::TextureView(texture_view_dimension, _) => {
1076 let bindless_resource_type =
1077 BindlessResourceType::from(texture_view_dimension);
1078 self.textures
1079 .get_mut(&bindless_resource_type)
1080 .expect("Texture binding array should exist")
1081 .bindings
1082 .get_mut(*pre_existing_resource_slot as usize)
1083 .and_then(|binding| binding.as_mut())
1084 .expect("Slot should exist")
1085 .ref_count += 1;
1086 }
1087
1088 OwnedBindingResource::Sampler(sampler_binding_type, _) => {
1089 let bindless_resource_type =
1090 BindlessResourceType::from(sampler_binding_type);
1091 self.samplers
1092 .get_mut(&bindless_resource_type)
1093 .expect("Sampler binding array should exist")
1094 .bindings
1095 .get_mut(*pre_existing_resource_slot as usize)
1096 .and_then(|binding| binding.as_mut())
1097 .expect("Slot should exist")
1098 .ref_count += 1;
1099 }
1100 }
1101
1102 continue;
1103 }
1104
1105 let binding_resource_id = BindingResourceId::from(&owned_binding_resource);
1107 match owned_binding_resource {
1108 OwnedBindingResource::Buffer(buffer) => {
1109 let slot = self
1110 .buffers
1111 .get_mut(&bindless_index)
1112 .expect("Buffer binding array should exist")
1113 .insert(binding_resource_id, buffer);
1114 allocated_resource_slots.insert(bindless_index, slot);
1115 }
1116 OwnedBindingResource::Data(data) => {
1117 let slot = self
1118 .data_buffers
1119 .get_mut(&bindless_index)
1120 .expect("Data buffer binding array should exist")
1121 .insert(&data);
1122 allocated_resource_slots.insert(bindless_index, slot);
1123 }
1124 OwnedBindingResource::TextureView(texture_view_dimension, texture_view) => {
1125 let bindless_resource_type = BindlessResourceType::from(texture_view_dimension);
1126 let slot = self
1127 .textures
1128 .get_mut(&bindless_resource_type)
1129 .expect("Texture array should exist")
1130 .insert(binding_resource_id, texture_view);
1131 allocated_resource_slots.insert(bindless_index, slot);
1132 }
1133 OwnedBindingResource::Sampler(sampler_binding_type, sampler) => {
1134 let bindless_resource_type = BindlessResourceType::from(sampler_binding_type);
1135 let slot = self
1136 .samplers
1137 .get_mut(&bindless_resource_type)
1138 .expect("Sampler should exist")
1139 .insert(binding_resource_id, sampler);
1140 allocated_resource_slots.insert(bindless_index, slot);
1141 }
1142 }
1143
1144 self.allocated_resource_count += 1;
1146 }
1147
1148 allocated_resource_slots
1149 }
1150
1151 fn free(&mut self, slot: MaterialBindGroupSlot, bindless_descriptor: &BindlessDescriptor) {
1154 for (bindless_index, bindless_resource_type) in
1156 bindless_descriptor.resources.iter().enumerate()
1157 {
1158 let bindless_index = BindlessIndex::from(bindless_index as u32);
1159 let Some(bindless_index_table) = self.get_bindless_index_table(bindless_index) else {
1160 continue;
1161 };
1162 let Some(bindless_binding) = bindless_index_table.get_binding(slot, bindless_index)
1163 else {
1164 continue;
1165 };
1166
1167 let decrement_allocated_resource_count = match *bindless_resource_type {
1171 BindlessResourceType::None => false,
1172 BindlessResourceType::Buffer => self
1173 .buffers
1174 .get_mut(&bindless_index)
1175 .expect("Buffer should exist with that bindless index")
1176 .remove(bindless_binding),
1177 BindlessResourceType::DataBuffer => {
1178 self.data_buffers
1179 .get_mut(&bindless_index)
1180 .expect("Data buffer should exist with that bindless index")
1181 .remove(bindless_binding);
1182 false
1183 }
1184 BindlessResourceType::SamplerFiltering
1185 | BindlessResourceType::SamplerNonFiltering
1186 | BindlessResourceType::SamplerComparison => self
1187 .samplers
1188 .get_mut(bindless_resource_type)
1189 .expect("Sampler array should exist")
1190 .remove(bindless_binding),
1191 BindlessResourceType::Texture1d
1192 | BindlessResourceType::Texture2d
1193 | BindlessResourceType::Texture2dArray
1194 | BindlessResourceType::Texture3d
1195 | BindlessResourceType::TextureCube
1196 | BindlessResourceType::TextureCubeArray => self
1197 .textures
1198 .get_mut(bindless_resource_type)
1199 .expect("Texture array should exist")
1200 .remove(bindless_binding),
1201 };
1202
1203 if decrement_allocated_resource_count {
1206 self.allocated_resource_count -= 1;
1207 }
1208 }
1209
1210 self.extra_data[slot.0 as usize] = None;
1212
1213 self.bind_group = None;
1215
1216 self.free_slots.push(slot);
1218 self.live_allocation_count -= 1;
1219 }
1220
1221 fn prepare(
1223 &mut self,
1224 render_device: &RenderDevice,
1225 bind_group_layout: &BindGroupLayout,
1226 fallback_bindless_resources: &FallbackBindlessResources,
1227 fallback_buffers: &HashMap<BindlessIndex, Buffer>,
1228 fallback_image: &FallbackImage,
1229 bindless_descriptor: &BindlessDescriptor,
1230 slab_capacity: u32,
1231 ) {
1232 for bindless_index_table in &mut self.bindless_index_tables {
1234 bindless_index_table.buffer.prepare(render_device);
1235 }
1236
1237 for data_buffer in self.data_buffers.values_mut() {
1239 data_buffer.buffer.prepare(render_device);
1240 }
1241
1242 self.prepare_bind_group(
1244 render_device,
1245 bind_group_layout,
1246 fallback_bindless_resources,
1247 fallback_buffers,
1248 fallback_image,
1249 bindless_descriptor,
1250 slab_capacity,
1251 );
1252 }
1253
1254 fn prepare_bind_group(
1257 &mut self,
1258 render_device: &RenderDevice,
1259 bind_group_layout: &BindGroupLayout,
1260 fallback_bindless_resources: &FallbackBindlessResources,
1261 fallback_buffers: &HashMap<BindlessIndex, Buffer>,
1262 fallback_image: &FallbackImage,
1263 bindless_descriptor: &BindlessDescriptor,
1264 slab_capacity: u32,
1265 ) {
1266 if self.bind_group.is_some() {
1268 return;
1269 }
1270
1271 let required_binding_array_size = if render_device
1274 .features()
1275 .contains(WgpuFeatures::PARTIALLY_BOUND_BINDING_ARRAY)
1276 {
1277 None
1278 } else {
1279 Some(slab_capacity)
1280 };
1281
1282 let binding_resource_arrays = self.create_binding_resource_arrays(
1283 fallback_bindless_resources,
1284 fallback_buffers,
1285 fallback_image,
1286 bindless_descriptor,
1287 required_binding_array_size,
1288 );
1289
1290 let mut bind_group_entries: Vec<_> = self
1291 .bindless_index_tables
1292 .iter()
1293 .map(|bindless_index_table| bindless_index_table.bind_group_entry())
1294 .collect();
1295
1296 for &(&binding, ref binding_resource_array) in binding_resource_arrays.iter() {
1297 bind_group_entries.push(BindGroupEntry {
1298 binding,
1299 resource: match *binding_resource_array {
1300 BindingResourceArray::Buffers(ref buffer_bindings) => {
1301 BindingResource::BufferArray(&buffer_bindings[..])
1302 }
1303 BindingResourceArray::TextureViews(ref texture_views) => {
1304 BindingResource::TextureViewArray(&texture_views[..])
1305 }
1306 BindingResourceArray::Samplers(ref samplers) => {
1307 BindingResource::SamplerArray(&samplers[..])
1308 }
1309 },
1310 });
1311 }
1312
1313 for data_buffer in self.data_buffers.values() {
1315 bind_group_entries.push(BindGroupEntry {
1316 binding: *data_buffer.binding_number,
1317 resource: data_buffer
1318 .buffer
1319 .buffer()
1320 .expect("Backing data buffer must have been uploaded by now")
1321 .as_entire_binding(),
1322 });
1323 }
1324
1325 self.bind_group = Some(render_device.create_bind_group(
1326 M::label(),
1327 bind_group_layout,
1328 &bind_group_entries,
1329 ));
1330 }
1331
1332 fn write_buffer(&mut self, render_device: &RenderDevice, render_queue: &RenderQueue) {
1337 for bindless_index_table in &mut self.bindless_index_tables {
1338 bindless_index_table
1339 .buffer
1340 .write(render_device, render_queue);
1341 }
1342
1343 for data_buffer in self.data_buffers.values_mut() {
1344 data_buffer.buffer.write(render_device, render_queue);
1345 }
1346 }
1347
1348 fn create_binding_resource_arrays<'a>(
1351 &'a self,
1352 fallback_bindless_resources: &'a FallbackBindlessResources,
1353 fallback_buffers: &'a HashMap<BindlessIndex, Buffer>,
1354 fallback_image: &'a FallbackImage,
1355 bindless_descriptor: &'a BindlessDescriptor,
1356 required_binding_array_size: Option<u32>,
1357 ) -> Vec<(&'a u32, BindingResourceArray<'a>)> {
1358 let mut binding_resource_arrays = vec![];
1359
1360 self.create_sampler_binding_resource_arrays(
1362 &mut binding_resource_arrays,
1363 fallback_bindless_resources,
1364 required_binding_array_size,
1365 );
1366
1367 self.create_texture_binding_resource_arrays(
1369 &mut binding_resource_arrays,
1370 fallback_image,
1371 required_binding_array_size,
1372 );
1373
1374 self.create_buffer_binding_resource_arrays(
1376 &mut binding_resource_arrays,
1377 fallback_buffers,
1378 bindless_descriptor,
1379 required_binding_array_size,
1380 );
1381
1382 binding_resource_arrays
1383 }
1384
1385 fn create_sampler_binding_resource_arrays<'a, 'b>(
1388 &'a self,
1389 binding_resource_arrays: &'b mut Vec<(&'a u32, BindingResourceArray<'a>)>,
1390 fallback_bindless_resources: &'a FallbackBindlessResources,
1391 required_binding_array_size: Option<u32>,
1392 ) {
1393 for (bindless_resource_type, fallback_sampler) in [
1395 (
1396 BindlessResourceType::SamplerFiltering,
1397 &fallback_bindless_resources.filtering_sampler,
1398 ),
1399 (
1400 BindlessResourceType::SamplerNonFiltering,
1401 &fallback_bindless_resources.non_filtering_sampler,
1402 ),
1403 (
1404 BindlessResourceType::SamplerComparison,
1405 &fallback_bindless_resources.comparison_sampler,
1406 ),
1407 ] {
1408 let mut sampler_bindings = vec![];
1409
1410 match self.samplers.get(&bindless_resource_type) {
1411 Some(sampler_bindless_binding_array) => {
1412 for maybe_bindless_binding in sampler_bindless_binding_array.bindings.iter() {
1413 match *maybe_bindless_binding {
1414 Some(ref bindless_binding) => {
1415 sampler_bindings.push(&*bindless_binding.resource);
1416 }
1417 None => sampler_bindings.push(&**fallback_sampler),
1418 }
1419 }
1420 }
1421
1422 None => {
1423 sampler_bindings.push(&**fallback_sampler);
1425 }
1426 }
1427
1428 if let Some(required_binding_array_size) = required_binding_array_size {
1429 sampler_bindings.extend(iter::repeat_n(
1430 &**fallback_sampler,
1431 required_binding_array_size as usize - sampler_bindings.len(),
1432 ));
1433 }
1434
1435 let binding_number = bindless_resource_type
1436 .binding_number()
1437 .expect("Sampler bindless resource type must have a binding number");
1438
1439 binding_resource_arrays.push((
1440 &**binding_number,
1441 BindingResourceArray::Samplers(sampler_bindings),
1442 ));
1443 }
1444 }
1445
1446 fn create_texture_binding_resource_arrays<'a, 'b>(
1449 &'a self,
1450 binding_resource_arrays: &'b mut Vec<(&'a u32, BindingResourceArray<'a>)>,
1451 fallback_image: &'a FallbackImage,
1452 required_binding_array_size: Option<u32>,
1453 ) {
1454 for (bindless_resource_type, fallback_image) in [
1455 (BindlessResourceType::Texture1d, &fallback_image.d1),
1456 (BindlessResourceType::Texture2d, &fallback_image.d2),
1457 (
1458 BindlessResourceType::Texture2dArray,
1459 &fallback_image.d2_array,
1460 ),
1461 (BindlessResourceType::Texture3d, &fallback_image.d3),
1462 (BindlessResourceType::TextureCube, &fallback_image.cube),
1463 (
1464 BindlessResourceType::TextureCubeArray,
1465 &fallback_image.cube_array,
1466 ),
1467 ] {
1468 let mut texture_bindings = vec![];
1469
1470 let binding_number = bindless_resource_type
1471 .binding_number()
1472 .expect("Texture bindless resource type must have a binding number");
1473
1474 match self.textures.get(&bindless_resource_type) {
1475 Some(texture_bindless_binding_array) => {
1476 for maybe_bindless_binding in texture_bindless_binding_array.bindings.iter() {
1477 match *maybe_bindless_binding {
1478 Some(ref bindless_binding) => {
1479 texture_bindings.push(&*bindless_binding.resource);
1480 }
1481 None => texture_bindings.push(&*fallback_image.texture_view),
1482 }
1483 }
1484 }
1485
1486 None => {
1487 texture_bindings.push(&*fallback_image.texture_view);
1489 }
1490 }
1491
1492 if let Some(required_binding_array_size) = required_binding_array_size {
1493 texture_bindings.extend(iter::repeat_n(
1494 &*fallback_image.texture_view,
1495 required_binding_array_size as usize - texture_bindings.len(),
1496 ));
1497 }
1498
1499 binding_resource_arrays.push((
1500 binding_number,
1501 BindingResourceArray::TextureViews(texture_bindings),
1502 ));
1503 }
1504 }
1505
1506 fn create_buffer_binding_resource_arrays<'a, 'b>(
1509 &'a self,
1510 binding_resource_arrays: &'b mut Vec<(&'a u32, BindingResourceArray<'a>)>,
1511 fallback_buffers: &'a HashMap<BindlessIndex, Buffer>,
1512 bindless_descriptor: &'a BindlessDescriptor,
1513 required_binding_array_size: Option<u32>,
1514 ) {
1515 for bindless_buffer_descriptor in bindless_descriptor.buffers.iter() {
1516 let Some(buffer_bindless_binding_array) =
1517 self.buffers.get(&bindless_buffer_descriptor.bindless_index)
1518 else {
1519 continue;
1523 };
1524
1525 let fallback_buffer = fallback_buffers
1526 .get(&bindless_buffer_descriptor.bindless_index)
1527 .expect("Fallback buffer should exist");
1528
1529 let mut buffer_bindings: Vec<_> = buffer_bindless_binding_array
1530 .bindings
1531 .iter()
1532 .map(|maybe_bindless_binding| {
1533 let buffer = match *maybe_bindless_binding {
1534 None => fallback_buffer,
1535 Some(ref bindless_binding) => &bindless_binding.resource,
1536 };
1537 BufferBinding {
1538 buffer,
1539 offset: 0,
1540 size: None,
1541 }
1542 })
1543 .collect();
1544
1545 if let Some(required_binding_array_size) = required_binding_array_size {
1546 buffer_bindings.extend(iter::repeat_n(
1547 BufferBinding {
1548 buffer: fallback_buffer,
1549 offset: 0,
1550 size: None,
1551 },
1552 required_binding_array_size as usize - buffer_bindings.len(),
1553 ));
1554 }
1555
1556 binding_resource_arrays.push((
1557 &*buffer_bindless_binding_array.binding_number,
1558 BindingResourceArray::Buffers(buffer_bindings),
1559 ));
1560 }
1561 }
1562
1563 fn bind_group(&self) -> Option<&BindGroup> {
1566 self.bind_group.as_ref()
1567 }
1568
1569 fn get_extra_data(&self, slot: MaterialBindGroupSlot) -> &M::Data {
1571 self.extra_data
1572 .get(slot.0 as usize)
1573 .and_then(|data| data.as_ref())
1574 .expect("Extra data not present")
1575 }
1576
1577 fn get_bindless_index_table(
1579 &self,
1580 bindless_index: BindlessIndex,
1581 ) -> Option<&MaterialBindlessIndexTable<M>> {
1582 let table_index = self
1583 .bindless_index_tables
1584 .binary_search_by(|bindless_index_table| {
1585 if bindless_index < bindless_index_table.index_range.start {
1586 Ordering::Less
1587 } else if bindless_index >= bindless_index_table.index_range.end {
1588 Ordering::Greater
1589 } else {
1590 Ordering::Equal
1591 }
1592 })
1593 .ok()?;
1594 self.bindless_index_tables.get(table_index)
1595 }
1596}
1597
1598impl<R> MaterialBindlessBindingArray<R>
1599where
1600 R: GetBindingResourceId,
1601{
1602 fn new(
1605 binding_number: BindingNumber,
1606 resource_type: BindlessResourceType,
1607 ) -> MaterialBindlessBindingArray<R> {
1608 MaterialBindlessBindingArray {
1609 binding_number,
1610 bindings: vec![],
1611 resource_type,
1612 resource_to_slot: HashMap::default(),
1613 free_slots: vec![],
1614 len: 0,
1615 }
1616 }
1617
1618 fn find(&self, binding_resource_id: BindingResourceId) -> Option<u32> {
1623 self.resource_to_slot.get(&binding_resource_id).copied()
1624 }
1625
1626 fn insert(&mut self, binding_resource_id: BindingResourceId, resource: R) -> u32 {
1629 let slot = self.free_slots.pop().unwrap_or(self.len);
1630 self.resource_to_slot.insert(binding_resource_id, slot);
1631
1632 if self.bindings.len() < slot as usize + 1 {
1633 self.bindings.resize_with(slot as usize + 1, || None);
1634 }
1635 self.bindings[slot as usize] = Some(MaterialBindlessBinding::new(resource));
1636
1637 self.len += 1;
1638 slot
1639 }
1640
1641 fn remove(&mut self, slot: u32) -> bool {
1647 let maybe_binding = &mut self.bindings[slot as usize];
1648 let binding = maybe_binding
1649 .as_mut()
1650 .expect("Attempted to free an already-freed binding");
1651
1652 binding.ref_count -= 1;
1653 if binding.ref_count != 0 {
1654 return false;
1655 }
1656
1657 let binding_resource_id = binding.resource.binding_resource_id(self.resource_type);
1658 self.resource_to_slot.remove(&binding_resource_id);
1659
1660 *maybe_binding = None;
1661 self.free_slots.push(slot);
1662 self.len -= 1;
1663 true
1664 }
1665}
1666
1667impl<R> MaterialBindlessBinding<R>
1668where
1669 R: GetBindingResourceId,
1670{
1671 fn new(resource: R) -> MaterialBindlessBinding<R> {
1675 MaterialBindlessBinding {
1676 resource,
1677 ref_count: 1,
1678 }
1679 }
1680}
1681
1682pub fn material_uses_bindless_resources<M>(render_device: &RenderDevice) -> bool
1688where
1689 M: Material,
1690{
1691 M::bindless_slot_count().is_some_and(|bindless_slot_count| {
1692 M::bindless_supported(render_device) && bindless_slot_count.resolve() > 1
1693 })
1694}
1695
1696impl<M> MaterialBindlessSlab<M>
1697where
1698 M: Material,
1699{
1700 fn new(bindless_descriptor: &BindlessDescriptor) -> MaterialBindlessSlab<M> {
1705 let mut buffers = HashMap::default();
1706 let mut samplers = HashMap::default();
1707 let mut textures = HashMap::default();
1708 let mut data_buffers = HashMap::default();
1709
1710 for (bindless_index, bindless_resource_type) in
1711 bindless_descriptor.resources.iter().enumerate()
1712 {
1713 let bindless_index = BindlessIndex(bindless_index as u32);
1714 match *bindless_resource_type {
1715 BindlessResourceType::None => {}
1716 BindlessResourceType::Buffer => {
1717 let binding_number = bindless_descriptor
1718 .buffers
1719 .iter()
1720 .find(|bindless_buffer_descriptor| {
1721 bindless_buffer_descriptor.bindless_index == bindless_index
1722 })
1723 .expect(
1724 "Bindless buffer descriptor matching that bindless index should be \
1725 present",
1726 )
1727 .binding_number;
1728 buffers.insert(
1729 bindless_index,
1730 MaterialBindlessBindingArray::new(binding_number, *bindless_resource_type),
1731 );
1732 }
1733 BindlessResourceType::DataBuffer => {
1734 let buffer_descriptor = bindless_descriptor
1736 .buffers
1737 .iter()
1738 .find(|bindless_buffer_descriptor| {
1739 bindless_buffer_descriptor.bindless_index == bindless_index
1740 })
1741 .expect(
1742 "Bindless buffer descriptor matching that bindless index should be \
1743 present",
1744 );
1745 data_buffers.insert(
1746 bindless_index,
1747 MaterialDataBuffer::new(
1748 buffer_descriptor.binding_number,
1749 buffer_descriptor
1750 .size
1751 .expect("Data buffers should have a size")
1752 as u32,
1753 ),
1754 );
1755 }
1756 BindlessResourceType::SamplerFiltering
1757 | BindlessResourceType::SamplerNonFiltering
1758 | BindlessResourceType::SamplerComparison => {
1759 samplers.insert(
1760 *bindless_resource_type,
1761 MaterialBindlessBindingArray::new(
1762 *bindless_resource_type.binding_number().unwrap(),
1763 *bindless_resource_type,
1764 ),
1765 );
1766 }
1767 BindlessResourceType::Texture1d
1768 | BindlessResourceType::Texture2d
1769 | BindlessResourceType::Texture2dArray
1770 | BindlessResourceType::Texture3d
1771 | BindlessResourceType::TextureCube
1772 | BindlessResourceType::TextureCubeArray => {
1773 textures.insert(
1774 *bindless_resource_type,
1775 MaterialBindlessBindingArray::new(
1776 *bindless_resource_type.binding_number().unwrap(),
1777 *bindless_resource_type,
1778 ),
1779 );
1780 }
1781 }
1782 }
1783
1784 let bindless_index_tables = bindless_descriptor
1785 .index_tables
1786 .iter()
1787 .map(|bindless_index_table| MaterialBindlessIndexTable::new(bindless_index_table))
1788 .collect();
1789
1790 MaterialBindlessSlab {
1791 bind_group: None,
1792 bindless_index_tables,
1793 samplers,
1794 textures,
1795 buffers,
1796 data_buffers,
1797 extra_data: vec![],
1798 free_slots: vec![],
1799 live_allocation_count: 0,
1800 allocated_resource_count: 0,
1801 }
1802 }
1803}
1804
1805impl FromWorld for FallbackBindlessResources {
1806 fn from_world(world: &mut World) -> Self {
1807 let render_device = world.resource::<RenderDevice>();
1808 FallbackBindlessResources {
1809 filtering_sampler: render_device.create_sampler(&SamplerDescriptor {
1810 label: Some("fallback filtering sampler"),
1811 ..default()
1812 }),
1813 non_filtering_sampler: render_device.create_sampler(&SamplerDescriptor {
1814 label: Some("fallback non-filtering sampler"),
1815 mag_filter: FilterMode::Nearest,
1816 min_filter: FilterMode::Nearest,
1817 mipmap_filter: FilterMode::Nearest,
1818 ..default()
1819 }),
1820 comparison_sampler: render_device.create_sampler(&SamplerDescriptor {
1821 label: Some("fallback comparison sampler"),
1822 compare: Some(CompareFunction::Always),
1823 ..default()
1824 }),
1825 }
1826 }
1827}
1828
1829impl<M> MaterialBindGroupNonBindlessAllocator<M>
1830where
1831 M: Material,
1832{
1833 fn new() -> MaterialBindGroupNonBindlessAllocator<M> {
1836 MaterialBindGroupNonBindlessAllocator {
1837 bind_groups: vec![],
1838 to_prepare: HashSet::default(),
1839 free_indices: vec![],
1840 phantom: PhantomData,
1841 }
1842 }
1843
1844 fn allocate(
1850 &mut self,
1851 bind_group: MaterialNonBindlessAllocatedBindGroup<M>,
1852 ) -> MaterialBindingId {
1853 let group_id = self
1854 .free_indices
1855 .pop()
1856 .unwrap_or(MaterialBindGroupIndex(self.bind_groups.len() as u32));
1857 if self.bind_groups.len() < *group_id as usize + 1 {
1858 self.bind_groups
1859 .resize_with(*group_id as usize + 1, || None);
1860 }
1861
1862 if matches!(
1863 bind_group,
1864 MaterialNonBindlessAllocatedBindGroup::Unprepared { .. }
1865 ) {
1866 self.to_prepare.insert(group_id);
1867 }
1868
1869 self.bind_groups[*group_id as usize] = Some(bind_group);
1870
1871 MaterialBindingId {
1872 group: group_id,
1873 slot: default(),
1874 }
1875 }
1876
1877 fn allocate_unprepared(
1880 &mut self,
1881 unprepared_bind_group: UnpreparedBindGroup<M::Data>,
1882 bind_group_layout: BindGroupLayout,
1883 ) -> MaterialBindingId {
1884 self.allocate(MaterialNonBindlessAllocatedBindGroup::Unprepared {
1885 bind_group: unprepared_bind_group,
1886 layout: bind_group_layout,
1887 })
1888 }
1889
1890 fn allocate_prepared(
1893 &mut self,
1894 prepared_bind_group: PreparedBindGroup<M::Data>,
1895 ) -> MaterialBindingId {
1896 self.allocate(MaterialNonBindlessAllocatedBindGroup::Prepared {
1897 bind_group: prepared_bind_group,
1898 uniform_buffers: vec![],
1899 })
1900 }
1901
1902 fn free(&mut self, binding_id: MaterialBindingId) {
1904 debug_assert_eq!(binding_id.slot, MaterialBindGroupSlot(0));
1905 debug_assert!(self.bind_groups[*binding_id.group as usize].is_some());
1906 self.bind_groups[*binding_id.group as usize] = None;
1907 self.to_prepare.remove(&binding_id.group);
1908 self.free_indices.push(binding_id.group);
1909 }
1910
1911 fn get(&self, group: MaterialBindGroupIndex) -> Option<MaterialNonBindlessSlab<M>> {
1913 self.bind_groups[group.0 as usize]
1914 .as_ref()
1915 .map(|bind_group| match bind_group {
1916 MaterialNonBindlessAllocatedBindGroup::Prepared { bind_group, .. } => {
1917 MaterialNonBindlessSlab::Prepared(bind_group)
1918 }
1919 MaterialNonBindlessAllocatedBindGroup::Unprepared { bind_group, .. } => {
1920 MaterialNonBindlessSlab::Unprepared(bind_group)
1921 }
1922 })
1923 }
1924
1925 fn prepare_bind_groups(&mut self, render_device: &RenderDevice) {
1932 for bind_group_index in mem::take(&mut self.to_prepare) {
1933 let Some(MaterialNonBindlessAllocatedBindGroup::Unprepared {
1934 bind_group: unprepared_bind_group,
1935 layout: bind_group_layout,
1936 }) = mem::take(&mut self.bind_groups[*bind_group_index as usize])
1937 else {
1938 panic!("Allocation didn't exist or was already prepared");
1939 };
1940
1941 let mut uniform_buffers = vec![];
1943 for (index, binding) in unprepared_bind_group.bindings.iter() {
1944 let OwnedBindingResource::Data(ref owned_data) = *binding else {
1945 continue;
1946 };
1947 let label = format!("material uniform data {}", *index);
1948 let uniform_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
1949 label: Some(&label),
1950 contents: &owned_data.0,
1951 usage: BufferUsages::COPY_DST | BufferUsages::UNIFORM,
1952 });
1953 uniform_buffers.push(uniform_buffer);
1954 }
1955
1956 let mut bind_group_entries = vec![];
1958 let mut uniform_buffers_iter = uniform_buffers.iter();
1959 for (index, binding) in unprepared_bind_group.bindings.iter() {
1960 match *binding {
1961 OwnedBindingResource::Data(_) => {
1962 bind_group_entries.push(BindGroupEntry {
1963 binding: *index,
1964 resource: uniform_buffers_iter
1965 .next()
1966 .expect("We should have created uniform buffers for each `Data`")
1967 .as_entire_binding(),
1968 });
1969 }
1970 _ => bind_group_entries.push(BindGroupEntry {
1971 binding: *index,
1972 resource: binding.get_binding(),
1973 }),
1974 }
1975 }
1976
1977 let bind_group = render_device.create_bind_group(
1979 M::label(),
1980 &bind_group_layout,
1981 &bind_group_entries,
1982 );
1983
1984 self.bind_groups[*bind_group_index as usize] =
1985 Some(MaterialNonBindlessAllocatedBindGroup::Prepared {
1986 bind_group: PreparedBindGroup {
1987 bindings: unprepared_bind_group.bindings,
1988 bind_group,
1989 data: unprepared_bind_group.data,
1990 },
1991 uniform_buffers,
1992 });
1993 }
1994 }
1995}
1996
1997impl<'a, M> MaterialSlab<'a, M>
1998where
1999 M: Material,
2000{
2001 pub fn get_extra_data(&self, slot: MaterialBindGroupSlot) -> &M::Data {
2006 match self.0 {
2007 MaterialSlabImpl::Bindless(material_bindless_slab) => {
2008 material_bindless_slab.get_extra_data(slot)
2009 }
2010 MaterialSlabImpl::NonBindless(MaterialNonBindlessSlab::Prepared(
2011 prepared_bind_group,
2012 )) => &prepared_bind_group.data,
2013 MaterialSlabImpl::NonBindless(MaterialNonBindlessSlab::Unprepared(
2014 unprepared_bind_group,
2015 )) => &unprepared_bind_group.data,
2016 }
2017 }
2018
2019 pub fn bind_group(&self) -> Option<&'a BindGroup> {
2026 match self.0 {
2027 MaterialSlabImpl::Bindless(material_bindless_slab) => {
2028 material_bindless_slab.bind_group()
2029 }
2030 MaterialSlabImpl::NonBindless(MaterialNonBindlessSlab::Prepared(
2031 prepared_bind_group,
2032 )) => Some(&prepared_bind_group.bind_group),
2033 MaterialSlabImpl::NonBindless(MaterialNonBindlessSlab::Unprepared(_)) => None,
2034 }
2035 }
2036}
2037
2038impl MaterialDataBuffer {
2039 fn new(binding_number: BindingNumber, aligned_element_size: u32) -> MaterialDataBuffer {
2043 MaterialDataBuffer {
2044 binding_number,
2045 buffer: RetainedRawBufferVec::new(BufferUsages::STORAGE),
2046 aligned_element_size,
2047 free_slots: vec![],
2048 len: 0,
2049 }
2050 }
2051
2052 fn insert(&mut self, data: &[u8]) -> u32 {
2058 debug_assert_eq!(data.len(), self.aligned_element_size as usize);
2060
2061 let slot = self.free_slots.pop().unwrap_or(self.len);
2063
2064 let start = slot as usize * self.aligned_element_size as usize;
2066 let end = (slot as usize + 1) * self.aligned_element_size as usize;
2067
2068 if self.buffer.len() < end {
2070 self.buffer.reserve_internal(end);
2071 }
2072 while self.buffer.values().len() < end {
2073 self.buffer.push(0);
2074 }
2075
2076 self.buffer.values_mut()[start..end].copy_from_slice(data);
2078
2079 self.len += 1;
2081 self.buffer.dirty = BufferDirtyState::NeedsReserve;
2082 slot
2083 }
2084
2085 fn remove(&mut self, slot: u32) {
2087 self.free_slots.push(slot);
2088 self.len -= 1;
2089 }
2090}