From 99cf98971dae22ae65adb2104c5a3eec578649f1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 3 Nov 2022 05:00:35 +0100 Subject: Rename `buffers` module to `buffer` ... and move `StaticBuffer` to nested `static` module --- wgpu/src/buffer.rs | 3 + wgpu/src/buffer/dynamic.rs | 199 ++++++++++++++++++++++++++++++++++++++++++ wgpu/src/buffer/static.rs | 117 +++++++++++++++++++++++++ wgpu/src/buffers.rs | 120 ------------------------- wgpu/src/buffers/dynamic.rs | 199 ------------------------------------------ wgpu/src/lib.rs | 2 +- wgpu/src/triangle.rs | 10 +-- wgpu/src/triangle/gradient.rs | 2 +- wgpu/src/triangle/solid.rs | 2 +- 9 files changed, 327 insertions(+), 327 deletions(-) create mode 100644 wgpu/src/buffer.rs create mode 100644 wgpu/src/buffer/dynamic.rs create mode 100644 wgpu/src/buffer/static.rs delete mode 100644 wgpu/src/buffers.rs delete mode 100644 wgpu/src/buffers/dynamic.rs diff --git a/wgpu/src/buffer.rs b/wgpu/src/buffer.rs new file mode 100644 index 00000000..7c092d0b --- /dev/null +++ b/wgpu/src/buffer.rs @@ -0,0 +1,3 @@ +//! Utilities for buffer operations. +pub mod dynamic; +pub mod r#static; diff --git a/wgpu/src/buffer/dynamic.rs b/wgpu/src/buffer/dynamic.rs new file mode 100644 index 00000000..c0c48c74 --- /dev/null +++ b/wgpu/src/buffer/dynamic.rs @@ -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 { + offsets: Vec, + cpu: Internal, + gpu: wgpu::Buffer, + label: &'static str, + size: u64, + _data: PhantomData, +} + +impl Buffer { + /// 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::::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::::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>), + Storage(encase::DynamicStorageBuffer>), +} + +impl Internal { + /// Writes the current value to its CPU buffer with proper alignment. + pub(super) fn write( + &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 { + 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); + } + } + } +} diff --git a/wgpu/src/buffer/static.rs b/wgpu/src/buffer/static.rs new file mode 100644 index 00000000..cf06790c --- /dev/null +++ b/wgpu/src/buffer/static.rs @@ -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 { + //stored sequentially per mesh iteration; refers to the offset index in the GPU buffer + offsets: Vec, + label: &'static str, + usages: wgpu::BufferUsages, + gpu: wgpu::Buffer, + size: wgpu::BufferAddress, + _data: PhantomData, +} + +impl Buffer { + /// Initialize a new static buffer. + pub fn new( + device: &wgpu::Device, + label: &'static str, + usages: wgpu::BufferUsages, + ) -> Self { + let size = (mem::size_of::() 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::() * 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() + } +} diff --git a/wgpu/src/buffers.rs b/wgpu/src/buffers.rs deleted file mode 100644 index 707ad832..00000000 --- a/wgpu/src/buffers.rs +++ /dev/null @@ -1,120 +0,0 @@ -//! Utilities for buffer operations. -pub mod dynamic; - -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 StaticBuffer { - //stored sequentially per mesh iteration; refers to the offset index in the GPU buffer - offsets: Vec, - label: &'static str, - usages: wgpu::BufferUsages, - gpu: wgpu::Buffer, - size: wgpu::BufferAddress, - _data: PhantomData, -} - -impl StaticBuffer { - /// Initialize a new static buffer. - pub fn new( - device: &wgpu::Device, - label: &'static str, - usages: wgpu::BufferUsages, - ) -> Self { - let size = (mem::size_of::() 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::() * 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() - } -} diff --git a/wgpu/src/buffers/dynamic.rs b/wgpu/src/buffers/dynamic.rs deleted file mode 100644 index f1262d83..00000000 --- a/wgpu/src/buffers/dynamic.rs +++ /dev/null @@ -1,199 +0,0 @@ -//! Utilities for uniform buffer operations. -use encase::private::WriteInto; -use encase::ShaderType; -use std::marker::PhantomData; - -// Currently supported dynamic buffers. -enum BufferType { - Uniform(encase::DynamicUniformBuffer>), - Storage(encase::DynamicStorageBuffer>), -} - -impl BufferType { - /// Writes the current value to its CPU buffer with proper alignment. - pub(super) fn write( - &mut self, - value: &T, - ) -> wgpu::DynamicOffset { - match self { - BufferType::Uniform(buf) => buf - .write(value) - .expect("Error when writing to dynamic uniform buffer.") - as u32, - BufferType::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 { - match self { - BufferType::Uniform(buf) => buf.as_ref(), - BufferType::Storage(buf) => buf.as_ref(), - } - } - - /// Resets the CPU buffer. - pub(super) fn clear(&mut self) { - match self { - BufferType::Uniform(buf) => { - buf.as_mut().clear(); - buf.set_offset(0); - } - BufferType::Storage(buf) => { - buf.as_mut().clear(); - buf.set_offset(0); - } - } - } -} - -/// A dynamic buffer is any type of buffer which does not have a static offset. -pub(crate) struct Buffer { - offsets: Vec, - cpu: BufferType, - gpu: wgpu::Buffer, - label: &'static str, - size: u64, - _data: PhantomData, -} - -impl Buffer { - /// Creates a new dynamic uniform buffer. - pub fn uniform(device: &wgpu::Device, label: &'static str) -> Self { - Buffer::new( - device, - BufferType::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, - BufferType::Storage(encase::DynamicStorageBuffer::new(Vec::new())), - label, - wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST, - ) - } - - fn new( - device: &wgpu::Device, - dynamic_buffer_type: BufferType, - 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::::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 { - BufferType::Uniform(_) => { - wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST - } - BufferType::Storage(_) => { - wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST - } - }; - - self.gpu = Buffer::::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(); - } -} diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index a2b4ff39..1295516b 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -43,7 +43,7 @@ pub mod triangle; pub mod window; mod backend; -mod buffers; +mod buffer; mod quad; mod text; diff --git a/wgpu/src/triangle.rs b/wgpu/src/triangle.rs index 2af35588..28051edf 100644 --- a/wgpu/src/triangle.rs +++ b/wgpu/src/triangle.rs @@ -6,7 +6,7 @@ use std::fmt::Formatter; use iced_graphics::layer::{mesh, Mesh}; use iced_graphics::Size; -use crate::buffers::StaticBuffer; +use crate::buffer::r#static::Buffer; pub use iced_graphics::triangle::{Mesh2D, Vertex2D}; mod gradient; @@ -17,8 +17,8 @@ mod solid; #[derive(Debug)] pub(crate) struct Pipeline { blit: Option, - vertex_buffer: StaticBuffer, - index_buffer: StaticBuffer, + vertex_buffer: Buffer, + index_buffer: Buffer, index_strides: Vec, pipelines: PipelineList, } @@ -65,12 +65,12 @@ impl Pipeline { ) -> Pipeline { Pipeline { blit: antialiasing.map(|a| msaa::Blit::new(device, format, a)), - vertex_buffer: StaticBuffer::new( + vertex_buffer: Buffer::new( device, "iced_wgpu::triangle vertex buffer", wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, ), - index_buffer: StaticBuffer::new( + index_buffer: Buffer::new( device, "iced_wgpu::triangle vertex buffer", wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST, diff --git a/wgpu/src/triangle/gradient.rs b/wgpu/src/triangle/gradient.rs index 6698bb4e..03332234 100644 --- a/wgpu/src/triangle/gradient.rs +++ b/wgpu/src/triangle/gradient.rs @@ -1,4 +1,4 @@ -use crate::buffers::dynamic; +use crate::buffer::dynamic; use crate::settings; use crate::triangle; use encase::ShaderType; diff --git a/wgpu/src/triangle/solid.rs b/wgpu/src/triangle/solid.rs index 9d85ff7b..6b5dad41 100644 --- a/wgpu/src/triangle/solid.rs +++ b/wgpu/src/triangle/solid.rs @@ -1,4 +1,4 @@ -use crate::buffers::dynamic; +use crate::buffer::dynamic; use crate::triangle; use crate::{settings, Color}; use encase::ShaderType; -- cgit