Path: blob/main/crates/bevy_render/src/render_resource/gpu_array_buffer.rs
9328 views
use bevy_material::bind_group_layout_entries::{1binding_types::{storage_buffer_read_only, uniform_buffer_sized},2BindGroupLayoutEntryBuilder,3};45use super::BufferVec;6use crate::{7render_resource::batched_uniform_buffer::BatchedUniformBuffer,8renderer::{RenderDevice, RenderQueue},9};10use bevy_ecs::{prelude::Component, resource::Resource};11use core::marker::PhantomData;12use encase::{private::WriteInto, ShaderSize, ShaderType};13use nonmax::NonMaxU32;14use wgpu::{BindingResource, BufferUsages, Limits};1516/// Trait for types able to go in a [`GpuArrayBuffer`].17pub trait GpuArrayBufferable: ShaderType + ShaderSize + WriteInto + Clone {}1819impl<T: ShaderType + ShaderSize + WriteInto + Clone> GpuArrayBufferable for T {}2021/// Stores an array of elements to be transferred to the GPU and made accessible to shaders as a read-only array.22///23/// On platforms that support storage buffers, this is equivalent to24/// [`BufferVec<T>`]. Otherwise, this falls back to a dynamic offset25/// uniform buffer with the largest array of T that fits within a uniform buffer26/// binding (within reasonable limits).27///28/// Other options for storing GPU-accessible data are:29/// * [`BufferVec`]30/// * [`DynamicStorageBuffer`](crate::render_resource::DynamicStorageBuffer)31/// * [`DynamicUniformBuffer`](crate::render_resource::DynamicUniformBuffer)32/// * [`RawBufferVec`](crate::render_resource::RawBufferVec)33/// * [`StorageBuffer`](crate::render_resource::StorageBuffer)34/// * [`Texture`](crate::render_resource::Texture)35/// * [`UniformBuffer`](crate::render_resource::UniformBuffer)36#[derive(Resource)]37pub enum GpuArrayBuffer<T: GpuArrayBufferable> {38Uniform(BatchedUniformBuffer<T>),39Storage(BufferVec<T>),40}4142impl<T: GpuArrayBufferable> GpuArrayBuffer<T> {43pub fn new(limits: &Limits) -> Self {44if limits.max_storage_buffers_per_shader_stage == 0 {45GpuArrayBuffer::Uniform(BatchedUniformBuffer::new(limits))46} else {47GpuArrayBuffer::Storage(BufferVec::new(BufferUsages::STORAGE))48}49}5051pub fn clear(&mut self) {52match self {53GpuArrayBuffer::Uniform(buffer) => buffer.clear(),54GpuArrayBuffer::Storage(buffer) => buffer.clear(),55}56}5758pub fn push(&mut self, value: T) -> GpuArrayBufferIndex<T> {59match self {60GpuArrayBuffer::Uniform(buffer) => buffer.push(value),61GpuArrayBuffer::Storage(buffer) => {62let index = buffer.push(value) as u32;63GpuArrayBufferIndex {64index,65dynamic_offset: None,66element_type: PhantomData,67}68}69}70}7172pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {73match self {74GpuArrayBuffer::Uniform(buffer) => buffer.write_buffer(device, queue),75GpuArrayBuffer::Storage(buffer) => buffer.write_buffer(device, queue),76}77}7879pub fn binding_layout(limits: &Limits) -> BindGroupLayoutEntryBuilder {80if limits.max_storage_buffers_per_shader_stage == 0 {81uniform_buffer_sized(82true,83// BatchedUniformBuffer uses a MaxCapacityArray that is runtime-sized, so we use84// None here and let wgpu figure out the size.85None,86)87} else {88storage_buffer_read_only::<T>(false)89}90}9192pub fn binding(&self) -> Option<BindingResource<'_>> {93match self {94GpuArrayBuffer::Uniform(buffer) => buffer.binding(),95GpuArrayBuffer::Storage(buffer) => buffer.binding(),96}97}9899pub fn batch_size(limits: &Limits) -> Option<u32> {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