Rename buffers module to buffer

... and move `StaticBuffer` to nested `static` module
This commit is contained in:
Héctor Ramón Jiménez 2022-11-03 05:00:35 +01:00
parent 7e22e2d452
commit 99cf98971d
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
7 changed files with 66 additions and 66 deletions

199
wgpu/src/buffer/dynamic.rs Normal file
View file

@ -0,0 +1,199 @@
//! Utilities for uniform buffer operations.
use encase::private::WriteInto;
use encase::ShaderType;
use std::marker::PhantomData;
/// A dynamic buffer is any type of buffer which does not have a static offset.
pub(crate) struct Buffer<T: ShaderType> {
offsets: Vec<wgpu::DynamicOffset>,
cpu: Internal,
gpu: wgpu::Buffer,
label: &'static str,
size: u64,
_data: PhantomData<T>,
}
impl<T: ShaderType + WriteInto> Buffer<T> {
/// Creates a new dynamic uniform buffer.
pub fn uniform(device: &wgpu::Device, label: &'static str) -> Self {
Buffer::new(
device,
Internal::Uniform(encase::DynamicUniformBuffer::new(Vec::new())),
label,
wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
)
}
/// Creates a new dynamic storage buffer.
pub fn storage(device: &wgpu::Device, label: &'static str) -> Self {
Buffer::new(
device,
Internal::Storage(encase::DynamicStorageBuffer::new(Vec::new())),
label,
wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
)
}
fn new(
device: &wgpu::Device,
dynamic_buffer_type: Internal,
label: &'static str,
usage: wgpu::BufferUsages,
) -> Self {
let initial_size = u64::from(T::min_size());
Self {
offsets: Vec::new(),
cpu: dynamic_buffer_type,
gpu: Buffer::<T>::create_gpu_buffer(
device,
label,
usage,
initial_size,
),
label,
size: initial_size,
_data: Default::default(),
}
}
fn create_gpu_buffer(
device: &wgpu::Device,
label: &'static str,
usage: wgpu::BufferUsages,
size: u64,
) -> wgpu::Buffer {
device.create_buffer(&wgpu::BufferDescriptor {
label: Some(label),
size,
usage,
mapped_at_creation: false,
})
}
/// Write a new value to the CPU buffer with proper alignment. Stores the returned offset value
/// in the buffer for future use.
pub fn push(&mut self, value: &T) {
//this write operation on the cpu buffer will adjust for uniform alignment requirements
let offset = self.cpu.write(value);
self.offsets.push(offset as u32);
}
/// Resize buffer contents if necessary. This will re-create the GPU buffer if current size is
/// less than the newly computed size from the CPU buffer.
///
/// If the gpu buffer is resized, its bind group will need to be recreated!
pub fn resize(&mut self, device: &wgpu::Device) -> bool {
let new_size = self.cpu.get_ref().len() as u64;
if self.size < new_size {
let usages = match self.cpu {
Internal::Uniform(_) => {
wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST
}
Internal::Storage(_) => {
wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST
}
};
self.gpu = Buffer::<T>::create_gpu_buffer(
device, self.label, usages, new_size,
);
self.size = new_size;
true
} else {
false
}
}
/// Write the contents of this dynamic buffer to the GPU via staging belt command.
pub fn write(
&mut self,
device: &wgpu::Device,
staging_belt: &mut wgpu::util::StagingBelt,
encoder: &mut wgpu::CommandEncoder,
) {
let size = self.cpu.get_ref().len();
if let Some(buffer_size) = wgpu::BufferSize::new(size as u64) {
let mut buffer = staging_belt.write_buffer(
encoder,
&self.gpu,
0,
buffer_size,
device,
);
buffer.copy_from_slice(self.cpu.get_ref());
}
}
// Gets the aligned offset at the given index from the CPU buffer.
pub fn offset_at_index(&self, index: usize) -> wgpu::DynamicOffset {
let offset = self
.offsets
.get(index)
.copied()
.expect("Index not found in offsets.");
offset
}
/// Returns a reference to the GPU buffer.
pub fn raw(&self) -> &wgpu::Buffer {
&self.gpu
}
/// Reset the buffer.
pub fn clear(&mut self) {
self.offsets.clear();
self.cpu.clear();
}
}
// Currently supported dynamic buffers.
enum Internal {
Uniform(encase::DynamicUniformBuffer<Vec<u8>>),
Storage(encase::DynamicStorageBuffer<Vec<u8>>),
}
impl Internal {
/// Writes the current value to its CPU buffer with proper alignment.
pub(super) fn write<T: ShaderType + WriteInto>(
&mut self,
value: &T,
) -> wgpu::DynamicOffset {
match self {
Internal::Uniform(buf) => buf
.write(value)
.expect("Error when writing to dynamic uniform buffer.")
as u32,
Internal::Storage(buf) => buf
.write(value)
.expect("Error when writing to dynamic storage buffer.")
as u32,
}
}
/// Returns bytearray of aligned CPU buffer.
pub(super) fn get_ref(&self) -> &Vec<u8> {
match self {
Internal::Uniform(buf) => buf.as_ref(),
Internal::Storage(buf) => buf.as_ref(),
}
}
/// Resets the CPU buffer.
pub(super) fn clear(&mut self) {
match self {
Internal::Uniform(buf) => {
buf.as_mut().clear();
buf.set_offset(0);
}
Internal::Storage(buf) => {
buf.as_mut().clear();
buf.set_offset(0);
}
}
}
}

117
wgpu/src/buffer/static.rs Normal file
View file

@ -0,0 +1,117 @@
use bytemuck::{Pod, Zeroable};
use std::marker::PhantomData;
use std::mem;
//128 triangles/indices
const DEFAULT_STATIC_BUFFER_COUNT: wgpu::BufferAddress = 128;
/// A generic buffer struct useful for items which have no alignment requirements
/// (e.g. Vertex, Index buffers) & no dynamic offsets.
#[derive(Debug)]
pub(crate) struct Buffer<T> {
//stored sequentially per mesh iteration; refers to the offset index in the GPU buffer
offsets: Vec<wgpu::BufferAddress>,
label: &'static str,
usages: wgpu::BufferUsages,
gpu: wgpu::Buffer,
size: wgpu::BufferAddress,
_data: PhantomData<T>,
}
impl<T: Pod + Zeroable> Buffer<T> {
/// Initialize a new static buffer.
pub fn new(
device: &wgpu::Device,
label: &'static str,
usages: wgpu::BufferUsages,
) -> Self {
let size = (mem::size_of::<T>() as u64) * DEFAULT_STATIC_BUFFER_COUNT;
Self {
offsets: Vec::new(),
label,
usages,
gpu: Self::gpu_buffer(device, label, size, usages),
size,
_data: PhantomData,
}
}
fn gpu_buffer(
device: &wgpu::Device,
label: &'static str,
size: wgpu::BufferAddress,
usage: wgpu::BufferUsages,
) -> wgpu::Buffer {
device.create_buffer(&wgpu::BufferDescriptor {
label: Some(label),
size,
usage,
mapped_at_creation: false,
})
}
/// Returns whether or not the buffer needs to be recreated. This can happen whenever mesh data
/// changes & a redraw is requested.
pub fn resize(&mut self, device: &wgpu::Device, new_count: usize) -> bool {
let size = (mem::size_of::<T>() * new_count) as u64;
if self.size < size {
self.offsets.clear();
self.size = size;
self.gpu = Self::gpu_buffer(device, self.label, size, self.usages);
true
} else {
false
}
}
/// Writes the current vertex data to the gpu buffer with a memcpy & stores its offset.
///
/// Returns the size of the written bytes.
pub fn write(
&mut self,
device: &wgpu::Device,
staging_belt: &mut wgpu::util::StagingBelt,
encoder: &mut wgpu::CommandEncoder,
offset: u64,
content: &[T],
) -> u64 {
let bytes = bytemuck::cast_slice(content);
let bytes_size = bytes.len() as u64;
if let Some(buffer_size) = wgpu::BufferSize::new(bytes_size) {
let mut buffer = staging_belt.write_buffer(
encoder,
&self.gpu,
offset,
buffer_size,
device,
);
buffer.copy_from_slice(bytes);
self.offsets.push(offset);
}
bytes_size
}
fn offset_at(&self, index: usize) -> &wgpu::BufferAddress {
self.offsets
.get(index)
.expect("Offset at index does not exist.")
}
/// Returns the slice calculated from the offset stored at the given index.
/// e.g. to calculate the slice for the 2nd mesh in the layer, this would be the offset at index
/// 1 that we stored earlier when writing.
pub fn slice_from_index(&self, index: usize) -> wgpu::BufferSlice<'_> {
self.gpu.slice(self.offset_at(index)..)
}
/// Clears any temporary data from the buffer.
pub fn clear(&mut self) {
self.offsets.clear()
}
}