use std::marker::PhantomData;
use super::Buffer;
use crate::renderer::{RenderDevice, RenderQueue};
use encase::{
internal::WriteInto, DynamicStorageBuffer as DynamicStorageBufferWrapper, ShaderType,
StorageBuffer as StorageBufferWrapper,
};
use wgpu::{util::BufferInitDescriptor, BindingResource, BufferBinding, BufferUsages};
pub struct StorageBuffer<T: ShaderType> {
value: T,
scratch: StorageBufferWrapper<Vec<u8>>,
buffer: Option<Buffer>,
label: Option<String>,
changed: bool,
buffer_usage: BufferUsages,
}
impl<T: ShaderType> From<T> for StorageBuffer<T> {
fn from(value: T) -> Self {
Self {
value,
scratch: StorageBufferWrapper::new(Vec::new()),
buffer: None,
label: None,
changed: false,
buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
}
}
}
impl<T: ShaderType + Default> Default for StorageBuffer<T> {
fn default() -> Self {
Self {
value: T::default(),
scratch: StorageBufferWrapper::new(Vec::new()),
buffer: None,
label: None,
changed: false,
buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
}
}
}
impl<T: ShaderType + WriteInto> StorageBuffer<T> {
#[inline]
pub fn buffer(&self) -> Option<&Buffer> {
self.buffer.as_ref()
}
#[inline]
pub fn binding(&self) -> Option<BindingResource> {
Some(BindingResource::Buffer(
self.buffer()?.as_entire_buffer_binding(),
))
}
pub fn set(&mut self, value: T) {
self.value = value;
}
pub fn get(&self) -> &T {
&self.value
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.value
}
pub fn set_label(&mut self, label: Option<&str>) {
let label = label.map(str::to_string);
if label != self.label {
self.changed = true;
}
self.label = label;
}
pub fn get_label(&self) -> Option<&str> {
self.label.as_deref()
}
pub fn add_usages(&mut self, usage: BufferUsages) {
self.buffer_usage |= usage;
self.changed = true;
}
pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
self.scratch.write(&self.value).unwrap();
let capacity = self.buffer.as_deref().map(wgpu::Buffer::size).unwrap_or(0);
let size = self.scratch.as_ref().len() as u64;
if capacity < size || self.changed {
self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
label: self.label.as_deref(),
usage: self.buffer_usage,
contents: self.scratch.as_ref(),
}));
self.changed = false;
} else if let Some(buffer) = &self.buffer {
queue.write_buffer(buffer, 0, self.scratch.as_ref());
}
}
}
pub struct DynamicStorageBuffer<T: ShaderType> {
scratch: DynamicStorageBufferWrapper<Vec<u8>>,
buffer: Option<Buffer>,
label: Option<String>,
changed: bool,
buffer_usage: BufferUsages,
_marker: PhantomData<fn() -> T>,
}
impl<T: ShaderType> Default for DynamicStorageBuffer<T> {
fn default() -> Self {
Self {
scratch: DynamicStorageBufferWrapper::new(Vec::new()),
buffer: None,
label: None,
changed: false,
buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
_marker: PhantomData,
}
}
}
impl<T: ShaderType + WriteInto> DynamicStorageBuffer<T> {
#[inline]
pub fn buffer(&self) -> Option<&Buffer> {
self.buffer.as_ref()
}
#[inline]
pub fn binding(&self) -> Option<BindingResource> {
Some(BindingResource::Buffer(BufferBinding {
buffer: self.buffer()?,
offset: 0,
size: Some(T::min_size()),
}))
}
#[inline]
pub fn is_empty(&self) -> bool {
self.scratch.as_ref().is_empty()
}
#[inline]
pub fn push(&mut self, value: T) -> u32 {
self.scratch.write(&value).unwrap() as u32
}
pub fn set_label(&mut self, label: Option<&str>) {
let label = label.map(str::to_string);
if label != self.label {
self.changed = true;
}
self.label = label;
}
pub fn get_label(&self) -> Option<&str> {
self.label.as_deref()
}
pub fn add_usages(&mut self, usage: BufferUsages) {
self.buffer_usage |= usage;
self.changed = true;
}
#[inline]
pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
let capacity = self.buffer.as_deref().map(wgpu::Buffer::size).unwrap_or(0);
let size = self.scratch.as_ref().len() as u64;
if capacity < size || self.changed {
self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
label: self.label.as_deref(),
usage: self.buffer_usage,
contents: self.scratch.as_ref(),
}));
self.changed = false;
} else if let Some(buffer) = &self.buffer {
queue.write_buffer(buffer, 0, self.scratch.as_ref());
}
}
#[inline]
pub fn clear(&mut self) {
self.scratch.as_mut().clear();
self.scratch.set_offset(0);
}
}