1use crate::{
6 id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId},
7 track::{TrackerSet, DUMMY_SELECTOR},
8 FastHashMap, LifeGuard, MultiRefCount, RefCount, Stored, MAX_BIND_GROUPS,
9};
10
11use arrayvec::ArrayVec;
12use cart_tmp_gdesc::{DescriptorCounts, DescriptorSet};
13
14#[cfg(feature = "replay")]
15use serde::Deserialize;
16#[cfg(feature = "trace")]
17use serde::Serialize;
18use std::borrow::Borrow;
19
20#[derive(Clone, Debug)]
21pub enum BindGroupLayoutError {
22 ConflictBinding(u32),
23 MissingFeature(wgt::Features),
24 ZeroCount,
26 ArrayUnsupported,
28}
29
30#[derive(Clone, Debug)]
31pub enum BindGroupError {
32 BindingsNumMismatch { actual: usize, expected: usize },
35 MissingBindingDeclaration(u32),
37 WrongBindingType {
39 binding: u32,
41 actual: wgt::BindingType,
43 expected: &'static str,
45 },
46 WrongSamplerComparison,
49}
50
51pub(crate) type BindEntryMap = FastHashMap<u32, wgt::BindGroupLayoutEntry>;
52
53#[derive(Debug)]
54pub struct BindGroupLayout<B: hal::Backend> {
55 pub(crate) raw: B::DescriptorSetLayout,
56 pub(crate) device_id: Stored<DeviceId>,
57 pub(crate) multi_ref_count: MultiRefCount,
58 pub(crate) entries: BindEntryMap,
59 pub(crate) desc_counts: DescriptorCounts,
60 pub(crate) dynamic_count: usize,
61}
62
63#[repr(C)]
64#[derive(Debug)]
65pub struct PipelineLayoutDescriptor {
66 pub bind_group_layouts: *const BindGroupLayoutId,
67 pub bind_group_layouts_length: usize,
68}
69
70#[derive(Clone, Debug)]
71pub enum PipelineLayoutError {
72 TooManyGroups(usize),
73}
74
75#[derive(Debug)]
76pub struct PipelineLayout<B: hal::Backend> {
77 pub(crate) raw: B::PipelineLayout,
78 pub(crate) device_id: Stored<DeviceId>,
79 pub(crate) life_guard: LifeGuard,
80 pub(crate) bind_group_layout_ids: ArrayVec<[Stored<BindGroupLayoutId>; MAX_BIND_GROUPS]>,
81}
82
83#[repr(C)]
84#[derive(Clone, Debug, Hash, PartialEq)]
85#[cfg_attr(feature = "trace", derive(Serialize))]
86#[cfg_attr(feature = "replay", derive(Deserialize))]
87pub struct BufferBinding {
88 pub buffer_id: BufferId,
89 pub offset: wgt::BufferAddress,
90 pub size: Option<wgt::BufferSize>,
91}
92
93#[derive(Debug)]
95pub enum BindingResource<'a> {
96 Buffer(BufferBinding),
97 Sampler(SamplerId),
98 TextureView(TextureViewId),
99 TextureViewArray(&'a [TextureViewId]),
100}
101
102#[derive(Debug)]
104pub struct BindGroupEntry<'a> {
105 pub binding: u32,
106 pub resource: BindingResource<'a>,
107}
108
109#[derive(Debug)]
111pub struct BindGroupDescriptor<'a> {
112 pub label: Option<&'a str>,
113 pub layout: BindGroupLayoutId,
114 pub bindings: &'a [BindGroupEntry<'a>],
115}
116
117#[derive(Debug)]
118pub enum BindError {
119 MismatchedDynamicOffsetCount { actual: usize, expected: usize },
122 UnalignedDynamicBinding { idx: usize },
124 DynamicBindingOutOfBounds { idx: usize },
126}
127
128#[derive(Debug)]
129pub struct BindGroupDynamicBindingData {
130 pub(crate) maximum_dynamic_offset: wgt::BufferAddress,
132}
133
134#[derive(Debug)]
135pub struct BindGroup<B: hal::Backend> {
136 pub(crate) raw: DescriptorSet<B>,
137 pub(crate) device_id: Stored<DeviceId>,
138 pub(crate) layout_id: BindGroupLayoutId,
139 pub(crate) life_guard: LifeGuard,
140 pub(crate) used: TrackerSet,
141 pub(crate) dynamic_binding_info: Vec<BindGroupDynamicBindingData>,
142}
143
144impl<B: hal::Backend> BindGroup<B> {
145 pub(crate) fn validate_dynamic_bindings(
146 &self,
147 offsets: &[wgt::DynamicOffset],
148 ) -> Result<(), BindError> {
149 if self.dynamic_binding_info.len() != offsets.len() {
150 log::error!(
151 "BindGroup has {} dynamic bindings, but {} dynamic offsets were provided",
152 self.dynamic_binding_info.len(),
153 offsets.len()
154 );
155 return Err(BindError::MismatchedDynamicOffsetCount {
156 expected: self.dynamic_binding_info.len(),
157 actual: offsets.len(),
158 });
159 }
160
161 for (idx, (info, &offset)) in self
162 .dynamic_binding_info
163 .iter()
164 .zip(offsets.iter())
165 .enumerate()
166 {
167 if offset as wgt::BufferAddress % wgt::BIND_BUFFER_ALIGNMENT != 0 {
168 log::error!(
169 "Dynamic buffer offset index {}: {} needs to be aligned as a multiple of {}",
170 idx,
171 offset,
172 wgt::BIND_BUFFER_ALIGNMENT
173 );
174 return Err(BindError::UnalignedDynamicBinding { idx });
175 }
176
177 if offset as wgt::BufferAddress > info.maximum_dynamic_offset {
178 log::error!(
179 "Dynamic offset index {} with value {} overruns underlying buffer. Dynamic offset must be no more than {}",
180 idx,
181 offset,
182 info.maximum_dynamic_offset,
183 );
184 return Err(BindError::DynamicBindingOutOfBounds { idx });
185 }
186 }
187
188 Ok(())
189 }
190}
191
192impl<B: hal::Backend> Borrow<RefCount> for BindGroup<B> {
193 fn borrow(&self) -> &RefCount {
194 self.life_guard.ref_count.as_ref().unwrap()
195 }
196}
197
198impl<B: hal::Backend> Borrow<()> for BindGroup<B> {
199 fn borrow(&self) -> &() {
200 &DUMMY_SELECTOR
201 }
202}