use std::cell::Cell;
pub struct StreamBuffer {
buffer: Option<wgpu::Buffer>,
capacity_bytes: u64,
write_offset: Cell<u64>,
usage: wgpu::BufferUsages,
label: &'static str,
}
impl StreamBuffer {
pub fn new(usage: wgpu::BufferUsages, label: &'static str) -> Self {
Self {
buffer: None,
capacity_bytes: 0,
write_offset: Cell::new(0),
usage,
label,
}
}
pub fn reset(&self) {
self.write_offset.set(0);
}
pub fn ensure_capacity(&mut self, device: &wgpu::Device, required_bytes: u64) {
if required_bytes <= self.capacity_bytes && self.buffer.is_some() {
return;
}
let new_cap = required_bytes.max(1024).next_power_of_two();
self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
label: Some(self.label),
size: new_cap,
usage: self.usage | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
}));
self.capacity_bytes = new_cap;
}
pub fn write(&self, queue: &wgpu::Queue, data: &[u8]) -> Option<(&wgpu::Buffer, u64, u64)> {
let buf = self.buffer.as_ref()?;
let offset = self.write_offset.get();
let len = data.len() as u64;
if offset + len > self.capacity_bytes {
debug_assert!(
false,
"StreamBuffer overflow: {} + {} > {} ({}) — frame-start quad count \
undercounted this pipeline; the batch is dropped",
offset, len, self.capacity_bytes, self.label
);
return None;
}
queue.write_buffer(buf, offset, data);
self.write_offset.set(offset + len);
Some((buf, offset, len))
}
}
pub struct StreamBuffers {
pub rect: StreamBuffer,
pub sdf: StreamBuffer,
pub quad: StreamBuffer,
pub shadow: StreamBuffer,
pub anim_proc: StreamBuffer,
pub path_gradient: StreamBuffer,
pub index: StreamBuffer,
}
impl StreamBuffers {
pub fn new() -> Self {
Self {
rect: StreamBuffer::new(wgpu::BufferUsages::VERTEX, "rect_stream"),
sdf: StreamBuffer::new(wgpu::BufferUsages::VERTEX, "sdf_stream"),
quad: StreamBuffer::new(wgpu::BufferUsages::VERTEX, "quad_stream"),
shadow: StreamBuffer::new(wgpu::BufferUsages::VERTEX, "shadow_stream"),
anim_proc: StreamBuffer::new(wgpu::BufferUsages::VERTEX, "anim_proc_stream"),
path_gradient: StreamBuffer::new(wgpu::BufferUsages::VERTEX, "path_gradient_stream"),
index: StreamBuffer::new(wgpu::BufferUsages::INDEX, "index_stream"),
}
}
pub fn reset(&self) {
self.rect.reset();
self.sdf.reset();
self.quad.reset();
self.shadow.reset();
self.anim_proc.reset();
self.path_gradient.reset();
self.index.reset();
}
}
impl Default for StreamBuffers {
fn default() -> Self {
Self::new()
}
}