Path: blob/main/crates/bevy_render/src/render_resource/buffer_vec.rs
9328 views
use core::{iter, marker::PhantomData};12use crate::{3render_resource::Buffer,4renderer::{RenderDevice, RenderQueue},5};6use bytemuck::{must_cast_slice, NoUninit};7use encase::{8internal::{WriteInto, Writer},9ShaderType,10};11use thiserror::Error;12use wgpu::{BindingResource, BufferAddress, BufferUsages};1314use super::GpuArrayBufferable;1516/// A structure for storing raw bytes that have already been properly formatted17/// for use by the GPU.18///19/// "Properly formatted" means that item data already meets the alignment and padding20/// requirements for how it will be used on the GPU. The item type must implement [`NoUninit`]21/// for its data representation to be directly copyable.22///23/// Index, vertex, and instance-rate vertex buffers have no alignment nor padding requirements and24/// so this helper type is a good choice for them.25///26/// The contained data is stored in system RAM. Calling [`reserve`](RawBufferVec::reserve)27/// allocates VRAM from the [`RenderDevice`].28/// [`write_buffer`](RawBufferVec::write_buffer) queues copying of the data29/// from system RAM to VRAM.30///31/// Other options for storing GPU-accessible data are:32/// * [`BufferVec`]33/// * [`DynamicStorageBuffer`](crate::render_resource::DynamicStorageBuffer)34/// * [`DynamicUniformBuffer`](crate::render_resource::DynamicUniformBuffer)35/// * [`GpuArrayBuffer`](crate::render_resource::GpuArrayBuffer)36/// * [`StorageBuffer`](crate::render_resource::StorageBuffer)37/// * [`Texture`](crate::render_resource::Texture)38/// * [`UniformBuffer`](crate::render_resource::UniformBuffer)39pub struct RawBufferVec<T: NoUninit> {40values: Vec<T>,41buffer: Option<Buffer>,42capacity: usize,43item_size: usize,44buffer_usage: BufferUsages,45label: Option<String>,46changed: bool,47}4849impl<T: NoUninit> RawBufferVec<T> {50/// Creates a new [`RawBufferVec`] with the given [`BufferUsages`].51pub const fn new(buffer_usage: BufferUsages) -> Self {52Self {53values: Vec::new(),54buffer: None,55capacity: 0,56item_size: size_of::<T>(),57buffer_usage,58label: None,59changed: false,60}61}6263/// Returns a handle to the buffer, if the data has been uploaded.64#[inline]65pub fn buffer(&self) -> Option<&Buffer> {66self.buffer.as_ref()67}6869/// Returns the binding for the buffer if the data has been uploaded.70#[inline]71pub fn binding(&self) -> Option<BindingResource<'_>> {72Some(BindingResource::Buffer(73self.buffer()?.as_entire_buffer_binding(),74))75}7677/// Returns the amount of space that the GPU will use before reallocating.78#[inline]79pub fn capacity(&self) -> usize {80self.capacity81}8283/// Returns the number of items that have been pushed to this buffer.84#[inline]85pub fn len(&self) -> usize {86self.values.len()87}8889/// Returns true if the buffer is empty.90#[inline]91pub fn is_empty(&self) -> bool {92self.values.is_empty()93}9495/// Adds a new value and returns its index.96pub fn push(&mut self, value: T) -> usize {97let index = self.values.len();98self.values.push(value);99index100}101102pub fn append(&mut self, other: &mut RawBufferVec<T>) {103self.values.append(&mut other.values);104}105106/// Returns the value at the given index.107pub fn get(&self, index: u32) -> Option<&T> {108self.values.get(index as usize)109}110111/// Sets the value at the given index.112///113/// The index must be less than [`RawBufferVec::len`].114pub fn set(&mut self, index: u32, value: T) {115self.values[index as usize] = value;116}117118/// Preallocates space for `count` elements in the internal CPU-side buffer.119///120/// Unlike [`RawBufferVec::reserve`], this doesn't have any effect on the GPU buffer.121pub fn reserve_internal(&mut self, count: usize) {122self.values.reserve(count);123}124125/// Changes the debugging label of the buffer.126///127/// The next time the buffer is updated (via [`reserve`](Self::reserve)), Bevy will inform128/// the driver of the new label.129pub fn set_label(&mut self, label: Option<&str>) {130let label = label.map(str::to_string);131132if label != self.label {133self.changed = true;134}135136self.label = label;137}138139/// Returns the label140pub fn get_label(&self) -> Option<&str> {141self.label.as_deref()142}143144/// Creates a [`Buffer`] on the [`RenderDevice`] with size145/// at least `size_of::<T>() * capacity`, unless a such a buffer already exists.146///147/// If a [`Buffer`] exists, but is too small, references to it will be discarded,148/// and a new [`Buffer`] will be created. Any previously created [`Buffer`]s149/// that are no longer referenced will be deleted by the [`RenderDevice`]150/// once it is done using them (typically 1-2 frames).151///152/// In addition to any [`BufferUsages`] provided when153/// the `RawBufferVec` was created, the buffer on the [`RenderDevice`]154/// is marked as [`BufferUsages::COPY_DST`](BufferUsages).155pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {156let size = self.item_size * capacity;157if capacity > self.capacity || (self.changed && size > 0) {158self.capacity = capacity;159self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {160label: make_buffer_label::<Self>(&self.label),161size: size as BufferAddress,162usage: BufferUsages::COPY_DST | self.buffer_usage,163mapped_at_creation: false,164}));165self.changed = false;166}167}168169/// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]170/// and the provided [`RenderQueue`].171///172/// Before queuing the write, a [`reserve`](RawBufferVec::reserve) operation173/// is executed.174pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {175if self.values.is_empty() {176return;177}178self.reserve(self.values.len(), device);179if let Some(buffer) = &self.buffer {180let range = 0..self.item_size * self.values.len();181let bytes: &[u8] = must_cast_slice(&self.values);182queue.write_buffer(buffer, 0, &bytes[range]);183}184}185186/// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]187/// and the provided [`RenderQueue`].188///189/// If the buffer is not initialized on the GPU or the range is bigger than the capacity it will190/// return an error. You'll need to either reserve a new buffer which will lose data on the GPU191/// or create a new buffer and copy the old data to it.192///193/// This will only write the data contained in the given range. It is useful if you only want194/// to update a part of the buffer.195pub fn write_buffer_range(196&mut self,197render_queue: &RenderQueue,198range: core::ops::Range<usize>,199) -> Result<(), WriteBufferRangeError> {200if self.values.is_empty() {201return Err(WriteBufferRangeError::NoValuesToUpload);202}203if range.end > self.item_size * self.capacity {204return Err(WriteBufferRangeError::RangeBiggerThanBuffer);205}206if let Some(buffer) = &self.buffer {207// Cast only the bytes we need to write208let bytes: &[u8] = must_cast_slice(&self.values[range.start..range.end]);209render_queue.write_buffer(buffer, (range.start * self.item_size) as u64, bytes);210Ok(())211} else {212Err(WriteBufferRangeError::BufferNotInitialized)213}214}215216/// Reduces the length of the buffer.217pub fn truncate(&mut self, len: usize) {218self.values.truncate(len);219}220221/// Removes all elements from the buffer.222pub fn clear(&mut self) {223self.values.clear();224}225226/// Removes and returns the last element in the buffer.227pub fn pop(&mut self) -> Option<T> {228self.values.pop()229}230231pub fn values(&self) -> &Vec<T> {232&self.values233}234235pub fn values_mut(&mut self) -> &mut Vec<T> {236&mut self.values237}238}239240impl<T> RawBufferVec<T>241where242T: NoUninit + Default,243{244pub fn grow_set(&mut self, index: u32, value: T) {245self.values.reserve(index as usize + 1);246while index as usize + 1 > self.len() {247self.values.push(T::default());248}249self.values[index as usize] = value;250}251}252253impl<T: NoUninit> Extend<T> for RawBufferVec<T> {254#[inline]255fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {256self.values.extend(iter);257}258}259260/// Like [`RawBufferVec`], but doesn't require that the data type `T` be261/// [`NoUninit`].262///263/// This is a high-performance data structure that you should use whenever264/// possible if your data is more complex than is suitable for [`RawBufferVec`].265/// The [`ShaderType`] trait from the `encase` library is used to ensure that266/// the data is correctly aligned for use by the GPU.267///268/// For performance reasons, unlike [`RawBufferVec`], this type doesn't allow269/// CPU access to the data after it's been added via [`BufferVec::push`]. If you270/// need CPU access to the data, consider another type, such as271/// [`StorageBuffer`][super::StorageBuffer].272///273/// Other options for storing GPU-accessible data are:274/// * [`DynamicStorageBuffer`](crate::render_resource::DynamicStorageBuffer)275/// * [`DynamicUniformBuffer`](crate::render_resource::DynamicUniformBuffer)276/// * [`GpuArrayBuffer`](crate::render_resource::GpuArrayBuffer)277/// * [`RawBufferVec`]278/// * [`StorageBuffer`](crate::render_resource::StorageBuffer)279/// * [`Texture`](crate::render_resource::Texture)280/// * [`UniformBuffer`](crate::render_resource::UniformBuffer)281pub struct BufferVec<T>282where283T: ShaderType + WriteInto,284{285data: Vec<u8>,286buffer: Option<Buffer>,287capacity: usize,288buffer_usage: BufferUsages,289label: Option<String>,290label_changed: bool,291phantom: PhantomData<T>,292}293294impl<T> BufferVec<T>295where296T: ShaderType + WriteInto,297{298/// Creates a new [`BufferVec`] with the given [`BufferUsages`].299pub const fn new(buffer_usage: BufferUsages) -> Self {300Self {301data: vec![],302buffer: None,303capacity: 0,304buffer_usage,305label: None,306label_changed: false,307phantom: PhantomData,308}309}310311/// Returns a handle to the buffer, if the data has been uploaded.312#[inline]313pub fn buffer(&self) -> Option<&Buffer> {314self.buffer.as_ref()315}316317/// Returns the binding for the buffer if the data has been uploaded.318#[inline]319pub fn binding(&self) -> Option<BindingResource<'_>> {320Some(BindingResource::Buffer(321self.buffer()?.as_entire_buffer_binding(),322))323}324325/// Returns the amount of space that the GPU will use before reallocating.326#[inline]327pub fn capacity(&self) -> usize {328self.capacity329}330331/// Returns the number of items that have been pushed to this buffer.332#[inline]333pub fn len(&self) -> usize {334self.data.len() / u64::from(T::min_size()) as usize335}336337/// Returns true if the buffer is empty.338#[inline]339pub fn is_empty(&self) -> bool {340self.data.is_empty()341}342343/// Adds a new value and returns its index.344pub fn push(&mut self, value: T) -> usize {345let element_size = u64::from(T::min_size()) as usize;346let offset = self.data.len();347348// `extend` does not optimize for reallocation. Related `trusted_len` feature is unstable.349self.data.reserve(self.data.len() + element_size);350// We can't optimize and push uninitialized data here (using e.g. spare_capacity_mut())351// because write_into() does not initialize inner padding bytes in T's expansion352self.data.extend(iter::repeat_n(0, element_size));353354// Take a slice of the new data for `write_into` to use. This is355// important: it hoists the bounds check up here so that the compiler356// can eliminate all the bounds checks that `write_into` will emit.357let mut dest = &mut self.data[offset..(offset + element_size)];358value.write_into(&mut Writer::new(&value, &mut dest, 0).unwrap());359360offset / u64::from(T::min_size()) as usize361}362363/// Changes the debugging label of the buffer.364///365/// The next time the buffer is updated (via [`Self::reserve`]), Bevy will inform366/// the driver of the new label.367pub fn set_label(&mut self, label: Option<&str>) {368let label = label.map(str::to_string);369370if label != self.label {371self.label_changed = true;372}373374self.label = label;375}376377/// Returns the label378pub fn get_label(&self) -> Option<&str> {379self.label.as_deref()380}381382/// Preallocates space for `count` elements in the internal CPU-side buffer.383///384/// Unlike [`Self::reserve`], this doesn't have any effect on the GPU buffer.385pub fn reserve_internal(&mut self, count: usize) {386self.data.reserve(count * u64::from(T::min_size()) as usize);387}388389/// Creates a [`Buffer`] on the [`RenderDevice`] with size390/// at least `size_of::<T>() * capacity`, unless such a buffer already exists.391///392/// If a [`Buffer`] exists, but is too small, references to it will be discarded,393/// and a new [`Buffer`] will be created. Any previously created [`Buffer`]s394/// that are no longer referenced will be deleted by the [`RenderDevice`]395/// once it is done using them (typically 1-2 frames).396///397/// In addition to any [`BufferUsages`] provided when398/// the `BufferVec` was created, the buffer on the [`RenderDevice`]399/// is marked as [`BufferUsages::COPY_DST`](BufferUsages).400pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {401if capacity <= self.capacity && !self.label_changed {402return;403}404405self.capacity = capacity;406let size = u64::from(T::min_size()) as usize * capacity;407self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {408label: make_buffer_label::<Self>(&self.label),409size: size as BufferAddress,410usage: BufferUsages::COPY_DST | self.buffer_usage,411mapped_at_creation: false,412}));413self.label_changed = false;414}415416/// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]417/// and the provided [`RenderQueue`].418///419/// Before queuing the write, a [`reserve`](BufferVec::reserve) operation is420/// executed.421pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {422if self.data.is_empty() {423return;424}425426self.reserve(self.data.len() / u64::from(T::min_size()) as usize, device);427428let Some(buffer) = &self.buffer else { return };429queue.write_buffer(buffer, 0, &self.data);430}431432/// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]433/// and the provided [`RenderQueue`].434///435/// If the buffer is not initialized on the GPU or the range is bigger than the capacity it will436/// return an error. You'll need to either reserve a new buffer which will lose data on the GPU437/// or create a new buffer and copy the old data to it.438///439/// This will only write the data contained in the given range. It is useful if you only want440/// to update a part of the buffer.441pub fn write_buffer_range(442&mut self,443render_queue: &RenderQueue,444range: core::ops::Range<usize>,445) -> Result<(), WriteBufferRangeError> {446if self.data.is_empty() {447return Err(WriteBufferRangeError::NoValuesToUpload);448}449let item_size = u64::from(T::min_size()) as usize;450if range.end > item_size * self.capacity {451return Err(WriteBufferRangeError::RangeBiggerThanBuffer);452}453if let Some(buffer) = &self.buffer {454let bytes = &self.data[range.start..range.end];455render_queue.write_buffer(buffer, (range.start * item_size) as u64, bytes);456Ok(())457} else {458Err(WriteBufferRangeError::BufferNotInitialized)459}460}461462/// Reduces the length of the buffer.463pub fn truncate(&mut self, len: usize) {464self.data.truncate(u64::from(T::min_size()) as usize * len);465}466467/// Removes all elements from the buffer.468pub fn clear(&mut self) {469self.data.clear();470}471}472473/// Like a [`BufferVec`], but only reserves space on the GPU for elements474/// instead of initializing them CPU-side.475///476/// This type is useful when you're accumulating "output slots" for a GPU477/// compute shader to write into.478///479/// The type `T` need not be [`NoUninit`], unlike [`RawBufferVec`]; it only has to480/// be [`GpuArrayBufferable`].481pub struct UninitBufferVec<T>482where483T: GpuArrayBufferable,484{485buffer: Option<Buffer>,486len: usize,487capacity: usize,488item_size: usize,489buffer_usage: BufferUsages,490label: Option<String>,491label_changed: bool,492phantom: PhantomData<T>,493}494495impl<T> UninitBufferVec<T>496where497T: GpuArrayBufferable,498{499/// Creates a new [`UninitBufferVec`] with the given [`BufferUsages`].500pub const fn new(buffer_usage: BufferUsages) -> Self {501Self {502len: 0,503buffer: None,504capacity: 0,505item_size: size_of::<T>(),506buffer_usage,507label: None,508label_changed: false,509phantom: PhantomData,510}511}512513/// Returns the buffer, if allocated.514#[inline]515pub fn buffer(&self) -> Option<&Buffer> {516self.buffer.as_ref()517}518519/// Returns the binding for the buffer if the data has been uploaded.520#[inline]521pub fn binding(&self) -> Option<BindingResource<'_>> {522Some(BindingResource::Buffer(523self.buffer()?.as_entire_buffer_binding(),524))525}526527/// Reserves space for one more element in the buffer and returns its index.528pub fn add(&mut self) -> usize {529self.add_multiple(1)530}531532/// Reserves space for the given number of elements in the buffer and533/// returns the index of the first one.534pub fn add_multiple(&mut self, count: usize) -> usize {535let index = self.len;536self.len += count;537index538}539540/// Returns true if no elements have been added to this [`UninitBufferVec`].541pub fn is_empty(&self) -> bool {542self.len == 0543}544545/// Removes all elements from the buffer.546pub fn clear(&mut self) {547self.len = 0;548}549550/// Returns the length of the buffer.551pub fn len(&self) -> usize {552self.len553}554555/// Returns the amount of space that the GPU will use before reallocating.556#[inline]557pub fn capacity(&self) -> usize {558self.capacity559}560561/// Changes the debugging label of the buffer.562///563/// The next time the buffer is updated (via [`Self::reserve`]), Bevy will inform564/// the driver of the new label.565pub fn set_label(&mut self, label: Option<&str>) {566let label = label.map(str::to_string);567568if label != self.label {569self.label_changed = true;570}571572self.label = label;573}574575/// Returns the label576pub fn get_label(&self) -> Option<&str> {577self.label.as_deref()578}579580/// Materializes the buffer on the GPU with space for `capacity` elements.581///582/// If the buffer is already big enough, this function doesn't reallocate583/// the buffer.584pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {585if capacity <= self.capacity && !self.label_changed {586return;587}588589self.capacity = capacity;590let size = self.item_size * capacity;591self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {592label: make_buffer_label::<Self>(&self.label),593size: size as BufferAddress,594usage: BufferUsages::COPY_DST | self.buffer_usage,595mapped_at_creation: false,596}));597598self.label_changed = false;599}600601/// Materializes the buffer on the GPU, with an appropriate size for the602/// elements that have been pushed so far.603pub fn write_buffer(&mut self, device: &RenderDevice) {604if !self.is_empty() {605self.reserve(self.len, device);606}607}608}609610/// Error returned when `write_buffer_range` fails611///612/// See [`RawBufferVec::write_buffer_range`] [`BufferVec::write_buffer_range`]613#[derive(Debug, Eq, PartialEq, Copy, Clone, Error)]614pub enum WriteBufferRangeError {615#[error("the range is bigger than the capacity of the buffer")]616RangeBiggerThanBuffer,617#[error("the gpu buffer is not initialized")]618BufferNotInitialized,619#[error("there are no values to upload")]620NoValuesToUpload,621}622623#[inline]624pub(crate) fn make_buffer_label<'a, T>(label: &'a Option<String>) -> Option<&'a str> {625#[cfg(feature = "type_label_buffers")]626if label.is_none() {627return Some(core::any::type_name::<T>());628}629label.as_deref()630}631632633