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 TextureView(&'a wgpu::TextureView),
22 Sampler(&'a wgpu::Sampler),
23}
24
25pub fn build_buffer(device: &wgpu::Device, contents: &[u8], usage: wgpu::BufferUsages) -> wgpu::Buffer {
26 use wgpu::util::DeviceExt;
27 device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
28 label: None,
29 contents,
30 usage,
31 })
32}
33
34pub fn build_buffer_sized(device: &wgpu::Device, size: u64, usage: wgpu::BufferUsages) -> wgpu::Buffer {
35 device.create_buffer(&wgpu::BufferDescriptor {
36 label: None,
37 size,
38 usage,
39 mapped_at_creation: false,
40 })
41}
42
43pub fn resolve_buffer(device: &wgpu::Device, source: BufferSource<'_>, usage: wgpu::BufferUsages) -> wgpu::Buffer {
44 match source {
45 BufferSource::Data(data) => build_buffer(device, data, usage),
46 BufferSource::Buffer(buffer) => buffer,
47 }
48}
49
50pub fn resolve_uniform_buffer(device: &wgpu::Device, source: BufferSource<'_>) -> wgpu::Buffer {
51 resolve_buffer(device, source, wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST)
52}
53
54pub fn resolve_storage_buffer(device: &wgpu::Device, source: BufferSource<'_>) -> wgpu::Buffer {
55 resolve_buffer(device, source, wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST)
56}
57
58pub fn build_uniform_bind_group<'a>(
59 device: &wgpu::Device,
60 layout: &wgpu::BindGroupLayout,
61 source: impl Into<BufferSource<'a>>,
62) -> (wgpu::Buffer, wgpu::BindGroup) {
63 let (mut buffers, bind_group) = build_bind_group(device, layout, vec![BindingResource::UniformBuffer(source.into())]);
64 (buffers.remove(0), bind_group)
65}
66
67pub fn build_storage_bind_group<'a>(
68 device: &wgpu::Device,
69 layout: &wgpu::BindGroupLayout,
70 source: impl Into<BufferSource<'a>>,
71) -> (wgpu::Buffer, wgpu::BindGroup) {
72 let (mut buffers, bind_group) = build_bind_group(device, layout, vec![BindingResource::StorageBuffer(source.into())]);
73 (buffers.remove(0), bind_group)
74}
75
76pub fn update_uniform_buffer(queue: &wgpu::Queue, buffer: &wgpu::Buffer, data: &[u8]) {
77 queue.write_buffer(buffer, 0, data);
78}
79
80pub fn update_buffer_at(queue: &wgpu::Queue, buffer: &wgpu::Buffer, offset: u64, data: &[u8]) {
84 queue.write_buffer(buffer, offset, data);
85}
86
87pub fn dynamic_uniform_offset_stride(device: &wgpu::Device, element_size: u64) -> u64 {
91 align_to(element_size, device.limits().min_uniform_buffer_offset_alignment as u64)
92}
93
94pub fn dynamic_storage_offset_stride(device: &wgpu::Device, element_size: u64) -> u64 {
96 align_to(element_size, device.limits().min_storage_buffer_offset_alignment as u64)
97}
98
99fn align_to(size: u64, alignment: u64) -> u64 {
100 size.div_ceil(alignment) * alignment
101}
102
103pub fn dynamic_buffer_binding(buffer: &wgpu::Buffer, element_size: u64) -> wgpu::BindingResource<'_> {
110 wgpu::BindingResource::Buffer(wgpu::BufferBinding {
111 buffer,
112 offset: 0,
113 size: wgpu::BufferSize::new(element_size),
114 })
115}
116
117pub fn build_dynamic_uniform_buffer(device: &wgpu::Device, element_size: u64, count: u64) -> (wgpu::Buffer, u64) {
121 let stride = dynamic_uniform_offset_stride(device, element_size);
122 let buffer = build_buffer_sized(device, stride * count, wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST);
123 (buffer, stride)
124}
125
126pub fn build_dynamic_storage_buffer(device: &wgpu::Device, element_size: u64, count: u64) -> (wgpu::Buffer, u64) {
129 let stride = dynamic_storage_offset_stride(device, element_size);
130 let buffer = build_buffer_sized(device, stride * count, wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST);
131 (buffer, stride)
132}
133
134pub fn build_bind_group<'a>(
138 device: &wgpu::Device,
139 layout: &wgpu::BindGroupLayout,
140 resources: Vec<BindingResource<'a>>,
141) -> (Vec<wgpu::Buffer>, wgpu::BindGroup) {
142 enum Resolved<'a> {
143 Buffer(wgpu::Buffer),
144 TextureView(&'a wgpu::TextureView),
145 Sampler(&'a wgpu::Sampler),
146 }
147
148 let resolved: Vec<Resolved> = resources
149 .into_iter()
150 .map(|r| match r {
151 BindingResource::UniformBuffer(src) => Resolved::Buffer(resolve_uniform_buffer(device, src)),
152 BindingResource::StorageBuffer(src) => Resolved::Buffer(resolve_storage_buffer(device, src)),
153 BindingResource::TextureView(view) => Resolved::TextureView(view),
154 BindingResource::Sampler(sampler) => Resolved::Sampler(sampler),
155 })
156 .collect();
157
158 let bind_group = {
159 let entries: Vec<wgpu::BindGroupEntry> = resolved
160 .iter()
161 .enumerate()
162 .map(|(i, r)| wgpu::BindGroupEntry {
163 binding: i as u32,
164 resource: match r {
165 Resolved::Buffer(buf) => buf.as_entire_binding(),
166 Resolved::TextureView(view) => wgpu::BindingResource::TextureView(view),
167 Resolved::Sampler(sampler) => wgpu::BindingResource::Sampler(sampler),
168 },
169 })
170 .collect();
171
172 device.create_bind_group(&wgpu::BindGroupDescriptor {
173 label: None,
174 layout,
175 entries: &entries,
176 })
177 };
178
179 let buffers = resolved
180 .into_iter()
181 .filter_map(|r| match r {
182 Resolved::Buffer(buf) => Some(buf),
183 _ => None,
184 })
185 .collect();
186
187 (buffers, bind_group)
188}