Path: blob/main/crates/bevy_render/src/render_resource/gpu_array_buffer.rs
6596 views
use super::{1binding_types::{storage_buffer_read_only, uniform_buffer_sized},2BindGroupLayoutEntryBuilder, BufferVec,3};4use crate::{5render_resource::batched_uniform_buffer::BatchedUniformBuffer,6renderer::{RenderDevice, RenderQueue},7};8use bevy_ecs::{prelude::Component, resource::Resource};9use core::marker::PhantomData;10use encase::{private::WriteInto, ShaderSize, ShaderType};11use nonmax::NonMaxU32;12use wgpu::{BindingResource, BufferUsages};1314/// Trait for types able to go in a [`GpuArrayBuffer`].15pub trait GpuArrayBufferable: ShaderType + ShaderSize + WriteInto + Clone {}1617impl<T: ShaderType + ShaderSize + WriteInto + Clone> GpuArrayBufferable for T {}1819/// Stores an array of elements to be transferred to the GPU and made accessible to shaders as a read-only array.20///21/// On platforms that support storage buffers, this is equivalent to22/// [`BufferVec<T>`]. Otherwise, this falls back to a dynamic offset23/// uniform buffer with the largest array of T that fits within a uniform buffer24/// binding (within reasonable limits).25///26/// Other options for storing GPU-accessible data are:27/// * [`BufferVec`]28/// * [`DynamicStorageBuffer`](crate::render_resource::DynamicStorageBuffer)29/// * [`DynamicUniformBuffer`](crate::render_resource::DynamicUniformBuffer)30/// * [`RawBufferVec`](crate::render_resource::RawBufferVec)31/// * [`StorageBuffer`](crate::render_resource::StorageBuffer)32/// * [`Texture`](crate::render_resource::Texture)33/// * [`UniformBuffer`](crate::render_resource::UniformBuffer)34#[derive(Resource)]35pub enum GpuArrayBuffer<T: GpuArrayBufferable> {36Uniform(BatchedUniformBuffer<T>),37Storage(BufferVec<T>),38}3940impl<T: GpuArrayBufferable> GpuArrayBuffer<T> {41pub fn new(device: &RenderDevice) -> Self {42let limits = device.limits();43if limits.max_storage_buffers_per_shader_stage == 0 {44GpuArrayBuffer::Uniform(BatchedUniformBuffer::new(&limits))45} else {46GpuArrayBuffer::Storage(BufferVec::new(BufferUsages::STORAGE))47}48}4950pub fn clear(&mut self) {51match self {52GpuArrayBuffer::Uniform(buffer) => buffer.clear(),53GpuArrayBuffer::Storage(buffer) => buffer.clear(),54}55}5657pub fn push(&mut self, value: T) -> GpuArrayBufferIndex<T> {58match self {59GpuArrayBuffer::Uniform(buffer) => buffer.push(value),60GpuArrayBuffer::Storage(buffer) => {61let index = buffer.push(value) as u32;62GpuArrayBufferIndex {63index,64dynamic_offset: None,65element_type: PhantomData,66}67}68}69}7071pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {72match self {73GpuArrayBuffer::Uniform(buffer) => buffer.write_buffer(device, queue),74GpuArrayBuffer::Storage(buffer) => buffer.write_buffer(device, queue),75}76}7778pub fn binding_layout(device: &RenderDevice) -> BindGroupLayoutEntryBuilder {79if device.limits().max_storage_buffers_per_shader_stage == 0 {80uniform_buffer_sized(81true,82// BatchedUniformBuffer uses a MaxCapacityArray that is runtime-sized, so we use83// None here and let wgpu figure out the size.84None,85)86} else {87storage_buffer_read_only::<T>(false)88}89}9091pub fn binding(&self) -> Option<BindingResource<'_>> {92match self {93GpuArrayBuffer::Uniform(buffer) => buffer.binding(),94GpuArrayBuffer::Storage(buffer) => buffer.binding(),95}96}9798pub fn batch_size(device: &RenderDevice) -> Option<u32> {99let limits = device.limits();100if limits.max_storage_buffers_per_shader_stage == 0 {101Some(BatchedUniformBuffer::<T>::batch_size(&limits) as u32)102} else {103None104}105}106}107108/// An index into a [`GpuArrayBuffer`] for a given element.109#[derive(Component, Clone)]110pub struct GpuArrayBufferIndex<T: GpuArrayBufferable> {111/// The index to use in a shader into the array.112pub index: u32,113/// The dynamic offset to use when setting the bind group in a pass.114/// Only used on platforms that don't support storage buffers.115pub dynamic_offset: Option<NonMaxU32>,116pub element_type: PhantomData<T>,117}118119120