use crate::context::WgpuContext;
use bytemuck::{Pod, Zeroable};
use std::marker::PhantomData;
pub struct VertexBuffer {
pub(crate) buffer: wgpu::Buffer,
pub(crate) count: u32,
pub(crate) stride: u64,
}
impl VertexBuffer {
pub fn new<V: Pod + Zeroable>(ctx: &WgpuContext, vertices: &[V], label: Option<&str>) -> Self {
use wgpu::util::DeviceExt;
let buffer = ctx
.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label,
contents: bytemuck::cast_slice(vertices),
usage: wgpu::BufferUsages::VERTEX,
});
Self {
buffer,
count: vertices.len() as u32,
stride: std::mem::size_of::<V>() as u64,
}
}
pub fn buffer(&self) -> &wgpu::Buffer {
&self.buffer
}
pub fn count(&self) -> u32 {
self.count
}
pub fn stride(&self) -> u64 {
self.stride
}
pub fn slice(&self) -> wgpu::BufferSlice<'_> {
self.buffer.slice(..)
}
}
pub struct IndexBuffer {
pub(crate) buffer: wgpu::Buffer,
pub(crate) count: u32,
pub(crate) format: wgpu::IndexFormat,
}
impl IndexBuffer {
pub fn new_u16(ctx: &WgpuContext, indices: &[u16], label: Option<&str>) -> Self {
use wgpu::util::DeviceExt;
let buffer = ctx
.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label,
contents: bytemuck::cast_slice(indices),
usage: wgpu::BufferUsages::INDEX,
});
Self {
buffer,
count: indices.len() as u32,
format: wgpu::IndexFormat::Uint16,
}
}
pub fn new_u32(ctx: &WgpuContext, indices: &[u32], label: Option<&str>) -> Self {
use wgpu::util::DeviceExt;
let buffer = ctx
.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label,
contents: bytemuck::cast_slice(indices),
usage: wgpu::BufferUsages::INDEX,
});
Self {
buffer,
count: indices.len() as u32,
format: wgpu::IndexFormat::Uint32,
}
}
pub fn buffer(&self) -> &wgpu::Buffer {
&self.buffer
}
pub fn count(&self) -> u32 {
self.count
}
pub fn format(&self) -> wgpu::IndexFormat {
self.format
}
pub fn slice(&self) -> wgpu::BufferSlice<'_> {
self.buffer.slice(..)
}
}
pub struct UniformBuffer<T> {
pub(crate) buffer: wgpu::Buffer,
pub(crate) bind_group_layout: wgpu::BindGroupLayout,
pub(crate) bind_group: wgpu::BindGroup,
_marker: PhantomData<T>,
}
impl<T: Pod + Zeroable> UniformBuffer<T> {
pub fn new(ctx: &WgpuContext, data: &T, binding: u32, label: Option<&str>) -> Self {
use wgpu::util::DeviceExt;
let buffer = ctx
.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label,
contents: bytemuck::bytes_of(data),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
let bind_group_layout =
ctx.device
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: label.map(|l| format!("{} layout", l)).as_deref(),
entries: &[wgpu::BindGroupLayoutEntry {
binding,
visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}],
});
let bind_group = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor {
label: label.map(|l| format!("{} bind group", l)).as_deref(),
layout: &bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding,
resource: buffer.as_entire_binding(),
}],
});
Self {
buffer,
bind_group_layout,
bind_group,
_marker: PhantomData,
}
}
pub fn update(&self, ctx: &WgpuContext, data: &T) {
ctx.queue
.write_buffer(&self.buffer, 0, bytemuck::bytes_of(data));
}
pub fn buffer(&self) -> &wgpu::Buffer {
&self.buffer
}
pub fn bind_group_layout(&self) -> &wgpu::BindGroupLayout {
&self.bind_group_layout
}
pub fn bind_group(&self) -> &wgpu::BindGroup {
&self.bind_group
}
}
pub struct RawUniformBuffer {
pub(crate) buffer: wgpu::Buffer,
pub(crate) size: u64,
}
impl RawUniformBuffer {
pub fn new(ctx: &WgpuContext, size: u64, label: Option<&str>) -> Self {
let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
label,
size,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
Self { buffer, size }
}
pub fn write<T: Pod>(&self, ctx: &WgpuContext, data: &T) {
ctx.queue
.write_buffer(&self.buffer, 0, bytemuck::bytes_of(data));
}
pub fn buffer(&self) -> &wgpu::Buffer {
&self.buffer
}
pub fn size(&self) -> u64 {
self.size
}
}