1pub enum BufferSource<'a> {
2 Data(&'a [u8]),
3 Buffer(wgpu::Buffer),
4}
5
6impl<'a> From<&'a [u8]> for BufferSource<'a> {
7 fn from(data: &'a [u8]) -> Self {
8 BufferSource::Data(data)
9 }
10}
11
12impl<'a> From<wgpu::Buffer> for BufferSource<'a> {
13 fn from(buffer: wgpu::Buffer) -> Self {
14 BufferSource::Buffer(buffer)
15 }
16}
17
18pub enum BindingResource<'a> {
19 UniformBuffer(BufferSource<'a>),
20 StorageBuffer(BufferSource<'a>),
21 DynamicUniformBuffer { buffer: wgpu::Buffer, element_size: u64 },
25 DynamicStorageBuffer { buffer: wgpu::Buffer, element_size: u64 },
27 TextureView(&'a wgpu::TextureView),
28 Sampler(&'a wgpu::Sampler),
29}
30
31pub fn build_buffer(device: &wgpu::Device, contents: &[u8], usage: wgpu::BufferUsages) -> wgpu::Buffer {
32 use wgpu::util::DeviceExt;
33 device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
34 label: None,
35 contents,
36 usage,
37 })
38}
39
40pub fn build_buffer_sized(device: &wgpu::Device, size: u64, usage: wgpu::BufferUsages) -> wgpu::Buffer {
41 device.create_buffer(&wgpu::BufferDescriptor {
42 label: None,
43 size,
44 usage,
45 mapped_at_creation: false,
46 })
47}
48
49pub fn resolve_buffer(device: &wgpu::Device, source: BufferSource<'_>, usage: wgpu::BufferUsages) -> wgpu::Buffer {
50 match source {
51 BufferSource::Data(data) => build_buffer(device, data, usage),
52 BufferSource::Buffer(buffer) => buffer,
53 }
54}
55
56pub fn resolve_uniform_buffer(device: &wgpu::Device, source: BufferSource<'_>) -> wgpu::Buffer {
57 resolve_buffer(device, source, wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST)
58}
59
60pub fn resolve_storage_buffer(device: &wgpu::Device, source: BufferSource<'_>) -> wgpu::Buffer {
61 resolve_buffer(device, source, wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST)
62}
63
64pub fn build_uniform_bind_group<'a>(
65 device: &wgpu::Device,
66 layout: &wgpu::BindGroupLayout,
67 source: impl Into<BufferSource<'a>>,
68) -> (wgpu::Buffer, wgpu::BindGroup) {
69 let (mut buffers, bind_group) = build_bind_group(device, layout, vec![BindingResource::UniformBuffer(source.into())]);
70 (buffers.remove(0), bind_group)
71}
72
73pub fn build_storage_bind_group<'a>(
74 device: &wgpu::Device,
75 layout: &wgpu::BindGroupLayout,
76 source: impl Into<BufferSource<'a>>,
77) -> (wgpu::Buffer, wgpu::BindGroup) {
78 let (mut buffers, bind_group) = build_bind_group(device, layout, vec![BindingResource::StorageBuffer(source.into())]);
79 (buffers.remove(0), bind_group)
80}
81
82pub fn build_dynamic_uniform_bind_group(
88 device: &wgpu::Device,
89 layout: &wgpu::BindGroupLayout,
90 element_size: u64,
91 count: u64,
92) -> (wgpu::Buffer, u64, wgpu::BindGroup) {
93 let (buffer, stride) = build_dynamic_uniform_buffer(device, element_size, count);
94 let (mut buffers, bind_group) =
95 build_bind_group(device, layout, vec![BindingResource::DynamicUniformBuffer { buffer, element_size }]);
96 (buffers.remove(0), stride, bind_group)
97}
98
99pub fn build_dynamic_storage_bind_group(
101 device: &wgpu::Device,
102 layout: &wgpu::BindGroupLayout,
103 element_size: u64,
104 count: u64,
105) -> (wgpu::Buffer, u64, wgpu::BindGroup) {
106 let (buffer, stride) = build_dynamic_storage_buffer(device, element_size, count);
107 let (mut buffers, bind_group) =
108 build_bind_group(device, layout, vec![BindingResource::DynamicStorageBuffer { buffer, element_size }]);
109 (buffers.remove(0), stride, bind_group)
110}
111
112pub fn update_uniform_buffer(queue: &wgpu::Queue, buffer: &wgpu::Buffer, data: &[u8]) {
113 queue.write_buffer(buffer, 0, data);
114}
115
116pub fn update_buffer_at(queue: &wgpu::Queue, buffer: &wgpu::Buffer, offset: u64, data: &[u8]) {
120 queue.write_buffer(buffer, offset, data);
121}
122
123pub fn dynamic_uniform_offset_stride(device: &wgpu::Device, element_size: u64) -> u64 {
127 align_to(element_size, device.limits().min_uniform_buffer_offset_alignment as u64)
128}
129
130pub fn dynamic_storage_offset_stride(device: &wgpu::Device, element_size: u64) -> u64 {
132 align_to(element_size, device.limits().min_storage_buffer_offset_alignment as u64)
133}
134
135fn align_to(size: u64, alignment: u64) -> u64 {
136 size.div_ceil(alignment) * alignment
137}
138
139pub fn dynamic_buffer_binding(buffer: &wgpu::Buffer, element_size: u64) -> wgpu::BindingResource<'_> {
146 wgpu::BindingResource::Buffer(wgpu::BufferBinding {
147 buffer,
148 offset: 0,
149 size: wgpu::BufferSize::new(element_size),
150 })
151}
152
153pub fn build_dynamic_uniform_buffer(device: &wgpu::Device, element_size: u64, count: u64) -> (wgpu::Buffer, u64) {
157 let stride = dynamic_uniform_offset_stride(device, element_size);
158 let buffer = build_buffer_sized(device, stride * count, wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST);
159 (buffer, stride)
160}
161
162pub fn build_dynamic_storage_buffer(device: &wgpu::Device, element_size: u64, count: u64) -> (wgpu::Buffer, u64) {
165 let stride = dynamic_storage_offset_stride(device, element_size);
166 let buffer = build_buffer_sized(device, stride * count, wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST);
167 (buffer, stride)
168}
169
170pub fn build_bind_group<'a>(
174 device: &wgpu::Device,
175 layout: &wgpu::BindGroupLayout,
176 resources: Vec<BindingResource<'a>>,
177) -> (Vec<wgpu::Buffer>, wgpu::BindGroup) {
178 enum Resolved<'a> {
179 Buffer(wgpu::Buffer),
180 DynamicBuffer(wgpu::Buffer, u64),
181 TextureView(&'a wgpu::TextureView),
182 Sampler(&'a wgpu::Sampler),
183 }
184
185 let resolved: Vec<Resolved> = resources
186 .into_iter()
187 .map(|r| match r {
188 BindingResource::UniformBuffer(src) => Resolved::Buffer(resolve_uniform_buffer(device, src)),
189 BindingResource::StorageBuffer(src) => Resolved::Buffer(resolve_storage_buffer(device, src)),
190 BindingResource::DynamicUniformBuffer { buffer, element_size } => Resolved::DynamicBuffer(buffer, element_size),
191 BindingResource::DynamicStorageBuffer { buffer, element_size } => Resolved::DynamicBuffer(buffer, element_size),
192 BindingResource::TextureView(view) => Resolved::TextureView(view),
193 BindingResource::Sampler(sampler) => Resolved::Sampler(sampler),
194 })
195 .collect();
196
197 let bind_group = {
198 let entries: Vec<wgpu::BindGroupEntry> = resolved
199 .iter()
200 .enumerate()
201 .map(|(i, r)| wgpu::BindGroupEntry {
202 binding: i as u32,
203 resource: match r {
204 Resolved::Buffer(buf) => buf.as_entire_binding(),
205 Resolved::DynamicBuffer(buf, element_size) => dynamic_buffer_binding(buf, *element_size),
206 Resolved::TextureView(view) => wgpu::BindingResource::TextureView(view),
207 Resolved::Sampler(sampler) => wgpu::BindingResource::Sampler(sampler),
208 },
209 })
210 .collect();
211
212 device.create_bind_group(&wgpu::BindGroupDescriptor {
213 label: None,
214 layout,
215 entries: &entries,
216 })
217 };
218
219 let buffers = resolved
220 .into_iter()
221 .filter_map(|r| match r {
222 Resolved::Buffer(buf) => Some(buf),
223 Resolved::DynamicBuffer(buf, _) => Some(buf),
224 _ => None,
225 })
226 .collect();
227
228 (buffers, bind_group)
229}