#![allow(clippy::cast_possible_truncation)]
use bytemuck::Pod;
use wgpu::{Device, util::DeviceExt};
use crate::vertex::Vertex;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BufferUsage {
Vertex,
Index,
Uniform,
Storage,
Indirect,
}
impl From<BufferUsage> for wgpu::BufferUsages {
fn from(usage: BufferUsage) -> Self {
match usage {
BufferUsage::Vertex => wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
BufferUsage::Index => wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
BufferUsage::Uniform => wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
BufferUsage::Storage => {
wgpu::BufferUsages::STORAGE
| wgpu::BufferUsages::COPY_DST
| wgpu::BufferUsages::COPY_SRC
}
BufferUsage::Indirect => wgpu::BufferUsages::INDIRECT | wgpu::BufferUsages::COPY_DST,
}
}
}
#[derive(Debug)]
pub struct Buffer {
inner: wgpu::Buffer,
usage: BufferUsage,
size: u64,
}
impl Buffer {
#[must_use]
pub fn new<T: Pod>(
device: &Device,
usage: BufferUsage,
data: &[T],
label: Option<&str>,
) -> Self {
let inner = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label,
contents: bytemuck::cast_slice(data),
usage: usage.into(),
});
Self {
inner,
usage,
size: std::mem::size_of_val(data) as u64,
}
}
#[must_use]
pub fn empty(device: &Device, usage: BufferUsage, size: u64, label: Option<&str>) -> Self {
let inner = device.create_buffer(&wgpu::BufferDescriptor {
label,
size,
usage: usage.into(),
mapped_at_creation: false,
});
Self { inner, usage, size }
}
#[must_use]
pub fn inner(&self) -> &wgpu::Buffer {
&self.inner
}
#[must_use]
pub fn usage(&self) -> BufferUsage {
self.usage
}
#[must_use]
pub fn size(&self) -> u64 {
self.size
}
#[must_use]
pub fn slice(&self) -> wgpu::BufferSlice<'_> {
self.inner.slice(..)
}
}
#[derive(Debug)]
pub struct VertexBuffer<V: Vertex> {
buffer: Buffer,
vertex_count: u32,
_marker: std::marker::PhantomData<V>,
}
impl<V: Vertex> VertexBuffer<V> {
#[must_use]
pub fn new(device: &Device, vertices: &[V]) -> Self {
let buffer = Buffer::new(device, BufferUsage::Vertex, vertices, Some("Vertex Buffer"));
Self {
buffer,
vertex_count: vertices.len() as u32,
_marker: std::marker::PhantomData,
}
}
#[must_use]
pub fn with_label(device: &Device, vertices: &[V], label: &str) -> Self {
let buffer = Buffer::new(device, BufferUsage::Vertex, vertices, Some(label));
Self {
buffer,
vertex_count: vertices.len() as u32,
_marker: std::marker::PhantomData,
}
}
#[must_use]
pub fn vertex_count(&self) -> u32 {
self.vertex_count
}
#[must_use]
pub fn buffer(&self) -> &Buffer {
&self.buffer
}
#[must_use]
pub fn slice(&self) -> wgpu::BufferSlice<'_> {
self.buffer.slice()
}
}
#[derive(Debug)]
pub struct IndexBuffer {
buffer: Buffer,
index_count: u32,
format: wgpu::IndexFormat,
}
impl IndexBuffer {
#[must_use]
pub fn new_u16(device: &Device, indices: &[u16]) -> Self {
let buffer = Buffer::new(device, BufferUsage::Index, indices, Some("Index Buffer"));
Self {
buffer,
index_count: indices.len() as u32,
format: wgpu::IndexFormat::Uint16,
}
}
#[must_use]
pub fn new_u32(device: &Device, indices: &[u32]) -> Self {
let buffer = Buffer::new(device, BufferUsage::Index, indices, Some("Index Buffer"));
Self {
buffer,
index_count: indices.len() as u32,
format: wgpu::IndexFormat::Uint32,
}
}
#[must_use]
pub fn index_count(&self) -> u32 {
self.index_count
}
#[must_use]
pub fn format(&self) -> wgpu::IndexFormat {
self.format
}
#[must_use]
pub fn buffer(&self) -> &Buffer {
&self.buffer
}
#[must_use]
pub fn slice(&self) -> wgpu::BufferSlice<'_> {
self.buffer.slice()
}
}