Skip to main content

pebble/wgpu/
buffers.rs

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 resolve_buffer(device: &wgpu::Device, source: BufferSource<'_>, usage: wgpu::BufferUsages) -> wgpu::Buffer {
35    match source {
36        BufferSource::Data(data) => build_buffer(device, data, usage),
37        BufferSource::Buffer(buffer) => buffer,
38    }
39}
40
41pub fn resolve_uniform_buffer(device: &wgpu::Device, source: BufferSource<'_>) -> wgpu::Buffer {
42    resolve_buffer(device, source, wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST)
43}
44
45pub fn resolve_storage_buffer(device: &wgpu::Device, source: BufferSource<'_>) -> wgpu::Buffer {
46    resolve_buffer(device, source, wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST)
47}
48
49pub fn build_uniform_bind_group<'a>(
50    device: &wgpu::Device,
51    layout: &wgpu::BindGroupLayout,
52    source: impl Into<BufferSource<'a>>,
53) -> (wgpu::Buffer, wgpu::BindGroup) {
54    let (mut buffers, bind_group) = build_bind_group(device, layout, vec![BindingResource::UniformBuffer(source.into())]);
55    (buffers.remove(0), bind_group)
56}
57
58pub fn build_storage_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::StorageBuffer(source.into())]);
64    (buffers.remove(0), bind_group)
65}
66
67pub fn update_uniform_buffer(queue: &wgpu::Queue, buffer: &wgpu::Buffer, data: &[u8]) {
68    queue.write_buffer(buffer, 0, data);
69}
70
71/// Builds a bind group from multiple resources. Buffers created from `Data` are returned
72/// in order (texture views and samplers are not returned). Pre-built buffers passed via
73/// `Buffer` are consumed and also returned.
74pub fn build_bind_group<'a>(
75    device: &wgpu::Device,
76    layout: &wgpu::BindGroupLayout,
77    resources: Vec<BindingResource<'a>>,
78) -> (Vec<wgpu::Buffer>, wgpu::BindGroup) {
79    enum Resolved<'a> {
80        Buffer(wgpu::Buffer),
81        TextureView(&'a wgpu::TextureView),
82        Sampler(&'a wgpu::Sampler),
83    }
84
85    let resolved: Vec<Resolved> = resources
86        .into_iter()
87        .map(|r| match r {
88            BindingResource::UniformBuffer(src) => Resolved::Buffer(resolve_uniform_buffer(device, src)),
89            BindingResource::StorageBuffer(src) => Resolved::Buffer(resolve_storage_buffer(device, src)),
90            BindingResource::TextureView(view) => Resolved::TextureView(view),
91            BindingResource::Sampler(sampler) => Resolved::Sampler(sampler),
92        })
93        .collect();
94
95    let bind_group = {
96        let entries: Vec<wgpu::BindGroupEntry> = resolved
97            .iter()
98            .enumerate()
99            .map(|(i, r)| wgpu::BindGroupEntry {
100                binding: i as u32,
101                resource: match r {
102                    Resolved::Buffer(buf) => buf.as_entire_binding(),
103                    Resolved::TextureView(view) => wgpu::BindingResource::TextureView(view),
104                    Resolved::Sampler(sampler) => wgpu::BindingResource::Sampler(sampler),
105                },
106            })
107            .collect();
108
109        device.create_bind_group(&wgpu::BindGroupDescriptor {
110            label: None,
111            layout,
112            entries: &entries,
113        })
114    };
115
116    let buffers = resolved
117        .into_iter()
118        .filter_map(|r| match r {
119            Resolved::Buffer(buf) => Some(buf),
120            _ => None,
121        })
122        .collect();
123
124    (buffers, bind_group)
125}