bevy_render/render_resource/
gpu_array_buffer.rs1use super::{
2 binding_types::{storage_buffer_read_only, uniform_buffer_sized},
3 BindGroupLayoutEntryBuilder, BufferVec,
4};
5use crate::{
6 render_resource::batched_uniform_buffer::BatchedUniformBuffer,
7 renderer::{RenderDevice, RenderQueue},
8};
9use bevy_ecs::{prelude::Component, system::Resource};
10use core::marker::PhantomData;
11use encase::{private::WriteInto, ShaderSize, ShaderType};
12use nonmax::NonMaxU32;
13use wgpu::{BindingResource, BufferUsages};
14
15pub trait GpuArrayBufferable: ShaderType + ShaderSize + WriteInto + Clone {}
17impl<T: ShaderType + ShaderSize + WriteInto + Clone> GpuArrayBufferable for T {}
18
19#[derive(Resource)]
35pub enum GpuArrayBuffer<T: GpuArrayBufferable> {
36 Uniform(BatchedUniformBuffer<T>),
37 Storage(BufferVec<T>),
38}
39
40impl<T: GpuArrayBufferable> GpuArrayBuffer<T> {
41 pub fn new(device: &RenderDevice) -> Self {
42 let limits = device.limits();
43 if limits.max_storage_buffers_per_shader_stage == 0 {
44 GpuArrayBuffer::Uniform(BatchedUniformBuffer::new(&limits))
45 } else {
46 GpuArrayBuffer::Storage(BufferVec::new(BufferUsages::STORAGE))
47 }
48 }
49
50 pub fn clear(&mut self) {
51 match self {
52 GpuArrayBuffer::Uniform(buffer) => buffer.clear(),
53 GpuArrayBuffer::Storage(buffer) => buffer.clear(),
54 }
55 }
56
57 pub fn push(&mut self, value: T) -> GpuArrayBufferIndex<T> {
58 match self {
59 GpuArrayBuffer::Uniform(buffer) => buffer.push(value),
60 GpuArrayBuffer::Storage(buffer) => {
61 let index = buffer.push(value) as u32;
62 GpuArrayBufferIndex {
63 index,
64 dynamic_offset: None,
65 element_type: PhantomData,
66 }
67 }
68 }
69 }
70
71 pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
72 match self {
73 GpuArrayBuffer::Uniform(buffer) => buffer.write_buffer(device, queue),
74 GpuArrayBuffer::Storage(buffer) => buffer.write_buffer(device, queue),
75 }
76 }
77
78 pub fn binding_layout(device: &RenderDevice) -> BindGroupLayoutEntryBuilder {
79 if device.limits().max_storage_buffers_per_shader_stage == 0 {
80 uniform_buffer_sized(
81 true,
82 None,
85 )
86 } else {
87 storage_buffer_read_only::<T>(false)
88 }
89 }
90
91 pub fn binding(&self) -> Option<BindingResource> {
92 match self {
93 GpuArrayBuffer::Uniform(buffer) => buffer.binding(),
94 GpuArrayBuffer::Storage(buffer) => buffer.binding(),
95 }
96 }
97
98 pub fn batch_size(device: &RenderDevice) -> Option<u32> {
99 let limits = device.limits();
100 if limits.max_storage_buffers_per_shader_stage == 0 {
101 Some(BatchedUniformBuffer::<T>::batch_size(&limits) as u32)
102 } else {
103 None
104 }
105 }
106}
107
108#[derive(Component, Clone)]
110pub struct GpuArrayBufferIndex<T: GpuArrayBufferable> {
111 pub index: u32,
113 pub dynamic_offset: Option<NonMaxU32>,
116 pub element_type: PhantomData<T>,
117}