bevy_render/
combined_bind_group.rs1use alloc::borrow::Cow;
4
5use bevy_ecs::system::SystemParamItem;
6use bevy_platform::{collections::HashSet, hash::FixedHasher};
7use wgpu::BindGroupLayoutEntry;
8
9use crate::{
10 render_resource::{
11 AsBindGroup, AsBindGroupError, BindGroupBuilder, BindGroupLayout, BindlessDescriptor,
12 BindlessResourceType, BindlessSlabResourceLimit,
13 },
14 renderer::RenderDevice,
15};
16
17pub fn bindless_slot_count<B: AsBindGroup, E: AsBindGroup>() -> Option<BindlessSlabResourceLimit> {
19 Some(combine_bindless_slot_count(
23 B::bindless_slot_count()?,
24 E::bindless_slot_count()?,
25 ))
26}
27
28fn combine_bindless_slot_count(
30 base: BindlessSlabResourceLimit,
31 extension: BindlessSlabResourceLimit,
32) -> BindlessSlabResourceLimit {
33 match (base, extension) {
34 (BindlessSlabResourceLimit::Auto, BindlessSlabResourceLimit::Auto) => {
35 BindlessSlabResourceLimit::Auto
36 }
37 (BindlessSlabResourceLimit::Auto, BindlessSlabResourceLimit::Custom(limit))
38 | (BindlessSlabResourceLimit::Custom(limit), BindlessSlabResourceLimit::Auto) => {
39 BindlessSlabResourceLimit::Custom(limit)
40 }
41 (
42 BindlessSlabResourceLimit::Custom(base_limit),
43 BindlessSlabResourceLimit::Custom(extended_limit),
44 ) => BindlessSlabResourceLimit::Custom(base_limit.min(extended_limit)),
45 }
46}
47
48pub fn bind_group_data<B: AsBindGroup, E: AsBindGroup>(
50 base: &B,
51 extension: &E,
52) -> CombinedBindGroupData<B::Data, E::Data> {
53 CombinedBindGroupData {
54 base: base.bind_group_data(),
55 extension: extension.bind_group_data(),
56 }
57}
58
59pub fn build_bind_group<B: AsBindGroup, E: AsBindGroup>(
61 base: &B,
62 extension: &E,
63 layout: &BindGroupLayout,
64 render_device: &RenderDevice,
65 (base_param, extended_param): &mut SystemParamItem<'_, '_, (B::Param, E::Param)>,
66 mut force_no_bindless: bool,
67 output: &mut BindGroupBuilder,
68) -> Result<(), AsBindGroupError> {
69 force_no_bindless = force_no_bindless || bindless_slot_count::<B, E>().is_none();
70
71 B::build_bind_group(
72 base,
73 layout,
74 render_device,
75 base_param,
76 force_no_bindless,
77 output,
78 )?;
79 E::build_bind_group(
80 extension,
81 layout,
82 render_device,
83 extended_param,
84 force_no_bindless,
85 output,
86 )?;
87
88 Ok(())
89}
90
91pub fn bind_group_layout_entries<B: AsBindGroup, E: AsBindGroup>(
93 render_device: &RenderDevice,
94 mut force_no_bindless: bool,
95) -> Vec<BindGroupLayoutEntry> {
96 force_no_bindless = force_no_bindless || bindless_slot_count::<B, E>().is_none();
97
98 let base_entries = B::bind_group_layout_entries(render_device, force_no_bindless);
99 let extension_entries = E::bind_group_layout_entries(render_device, force_no_bindless);
100
101 combine_bind_group_layout_entries(base_entries, extension_entries)
102}
103
104pub fn combine_bind_group_layout_entries(
106 base_entries: Vec<BindGroupLayoutEntry>,
107 extension_entries: Vec<BindGroupLayoutEntry>,
108) -> Vec<BindGroupLayoutEntry> {
109 let mut seen_bindings = HashSet::<u32>::with_hasher(FixedHasher);
115
116 base_entries
117 .into_iter()
118 .chain(extension_entries)
119 .filter(|entry| seen_bindings.insert(entry.binding))
120 .collect()
121}
122
123pub fn bindless_descriptor<B: AsBindGroup, E: AsBindGroup>() -> Option<BindlessDescriptor> {
125 let base_bindless_descriptor = B::bindless_descriptor()?;
126 let extended_bindless_descriptor = E::bindless_descriptor()?;
127
128 Some(combine_bindless_descriptors(
129 base_bindless_descriptor,
130 extended_bindless_descriptor,
131 ))
132}
133
134pub fn combine_bindless_descriptors(
136 base_bindless_descriptor: BindlessDescriptor,
137 extended_bindless_descriptor: BindlessDescriptor,
138) -> BindlessDescriptor {
139 let mut buffers = base_bindless_descriptor.buffers.to_vec();
141 let mut index_tables = base_bindless_descriptor.index_tables.to_vec();
142
143 buffers.extend(extended_bindless_descriptor.buffers.iter().cloned());
144 index_tables.extend(extended_bindless_descriptor.index_tables.iter().cloned());
145
146 let max_bindless_index = base_bindless_descriptor
150 .resources
151 .len()
152 .max(extended_bindless_descriptor.resources.len());
153 let mut resources = Vec::with_capacity(max_bindless_index);
154 for bindless_index in 0..max_bindless_index {
155 match base_bindless_descriptor.resources.get(bindless_index) {
158 None | Some(&BindlessResourceType::None) => resources.push(
159 extended_bindless_descriptor
160 .resources
161 .get(bindless_index)
162 .copied()
163 .unwrap_or(BindlessResourceType::None),
164 ),
165 Some(&resource_type) => resources.push(resource_type),
166 }
167 }
168
169 BindlessDescriptor {
170 resources: Cow::Owned(resources),
171 buffers: Cow::Owned(buffers),
172 index_tables: Cow::Owned(index_tables),
173 }
174}
175
176#[derive(Copy, Clone, PartialEq, Eq, Hash)]
178#[repr(C, packed)]
179pub struct CombinedBindGroupData<B, E> {
180 pub base: B,
181 pub extension: E,
182}