enum BufferContents<'a> {
Empty(u64),
Data(&'a [u8]),
}
pub struct BufferBuilder<'a> {
label: Option<&'a str>,
usage: wgpu::BufferUsages,
contents: BufferContents<'a>,
}
impl<'a> Default for BufferBuilder<'a> {
fn default() -> Self {
Self { label: None, usage: wgpu::BufferUsages::empty(), contents: BufferContents::Empty(0) }
}
}
impl<'a> BufferBuilder<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn label(mut self, label: impl Into<Option<&'a str>>) -> Self {
self.label = label.into();
self
}
pub fn usage(mut self, usage: wgpu::BufferUsages) -> Self {
self.usage = usage;
self
}
pub fn uniform(self) -> Self {
self.usage(wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST)
}
pub fn storage(self) -> Self {
self.usage(wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST)
}
pub fn data(mut self, data: &'a [u8]) -> Self {
self.contents = BufferContents::Data(data);
self
}
pub fn size(mut self, size: u64) -> Self {
self.contents = BufferContents::Empty(size);
self
}
pub fn build(self, device: &wgpu::Device) -> wgpu::Buffer {
match self.contents {
BufferContents::Data(data) => {
use wgpu::util::DeviceExt;
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: self.label,
contents: data,
usage: self.usage,
})
}
BufferContents::Empty(size) => device.create_buffer(&wgpu::BufferDescriptor {
label: self.label,
size,
usage: self.usage,
mapped_at_creation: false,
}),
}
}
}
pub fn update_buffer(queue: &wgpu::Queue, buffer: &wgpu::Buffer, data: &[u8]) {
queue.write_buffer(buffer, 0, data);
}
pub fn update_buffer_at(queue: &wgpu::Queue, buffer: &wgpu::Buffer, offset: u64, data: &[u8]) {
queue.write_buffer(buffer, offset, data);
}
enum DynamicKind {
Uniform,
Storage,
}
pub struct DynamicBufferBuilder<'a> {
label: Option<&'a str>,
kind: DynamicKind,
element_size: u64,
count: u64,
}
impl<'a> DynamicBufferBuilder<'a> {
pub fn uniform(element_size: u64, count: u64) -> Self {
Self { label: None, kind: DynamicKind::Uniform, element_size, count }
}
pub fn storage(element_size: u64, count: u64) -> Self {
Self { label: None, kind: DynamicKind::Storage, element_size, count }
}
pub fn label(mut self, label: impl Into<Option<&'a str>>) -> Self {
self.label = label.into();
self
}
pub fn build(self, device: &wgpu::Device) -> (wgpu::Buffer, u64) {
let (usage, stride) = match self.kind {
DynamicKind::Uniform => (
wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
dynamic_uniform_offset_stride(device, self.element_size),
),
DynamicKind::Storage => (
wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
dynamic_storage_offset_stride(device, self.element_size),
),
};
let buffer = BufferBuilder::new()
.label(self.label)
.usage(usage)
.size(stride * self.count)
.build(device);
(buffer, stride)
}
}
pub fn dynamic_uniform_offset_stride(device: &wgpu::Device, element_size: u64) -> u64 {
align_to(element_size, device.limits().min_uniform_buffer_offset_alignment as u64)
}
pub fn dynamic_storage_offset_stride(device: &wgpu::Device, element_size: u64) -> u64 {
align_to(element_size, device.limits().min_storage_buffer_offset_alignment as u64)
}
fn align_to(size: u64, alignment: u64) -> u64 {
size.div_ceil(alignment) * alignment
}
fn dynamic_buffer_binding(buffer: &wgpu::Buffer, element_size: u64) -> wgpu::BindingResource<'_> {
wgpu::BindingResource::Buffer(wgpu::BufferBinding {
buffer,
offset: 0,
size: wgpu::BufferSize::new(element_size),
})
}
pub struct BindGroupBuilder<'a> {
label: Option<&'a str>,
layout: &'a wgpu::BindGroupLayout,
entries: Vec<wgpu::BindGroupEntry<'a>>,
next_binding: u32,
}
impl<'a> BindGroupBuilder<'a> {
pub fn new(layout: &'a wgpu::BindGroupLayout) -> Self {
Self { label: None, layout, entries: Vec::new(), next_binding: 0 }
}
pub fn label(mut self, label: impl Into<Option<&'a str>>) -> Self {
self.label = label.into();
self
}
pub fn buffer(self, buffer: &'a wgpu::Buffer) -> Self {
let binding = self.next_binding;
self.buffer_at(binding, buffer)
}
pub fn buffer_at(mut self, binding: u32, buffer: &'a wgpu::Buffer) -> Self {
self.entries.push(wgpu::BindGroupEntry { binding, resource: buffer.as_entire_binding() });
self.next_binding = self.next_binding.max(binding + 1);
self
}
pub fn dynamic_buffer(self, buffer: &'a wgpu::Buffer, element_size: u64) -> Self {
let binding = self.next_binding;
self.dynamic_buffer_at(binding, buffer, element_size)
}
pub fn dynamic_buffer_at(mut self, binding: u32, buffer: &'a wgpu::Buffer, element_size: u64) -> Self {
self.entries.push(wgpu::BindGroupEntry { binding, resource: dynamic_buffer_binding(buffer, element_size) });
self.next_binding = self.next_binding.max(binding + 1);
self
}
pub fn texture(self, view: &'a wgpu::TextureView) -> Self {
let binding = self.next_binding;
self.texture_at(binding, view)
}
pub fn texture_at(mut self, binding: u32, view: &'a wgpu::TextureView) -> Self {
self.entries.push(wgpu::BindGroupEntry { binding, resource: wgpu::BindingResource::TextureView(view) });
self.next_binding = self.next_binding.max(binding + 1);
self
}
pub fn sampler(self, sampler: &'a wgpu::Sampler) -> Self {
let binding = self.next_binding;
self.sampler_at(binding, sampler)
}
pub fn sampler_at(mut self, binding: u32, sampler: &'a wgpu::Sampler) -> Self {
self.entries.push(wgpu::BindGroupEntry { binding, resource: wgpu::BindingResource::Sampler(sampler) });
self.next_binding = self.next_binding.max(binding + 1);
self
}
pub fn build(self, device: &wgpu::Device) -> wgpu::BindGroup {
device.create_bind_group(&wgpu::BindGroupDescriptor {
label: self.label,
layout: self.layout,
entries: &self.entries,
})
}
}