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, resource::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 {}
17
18impl<T: ShaderType + ShaderSize + WriteInto + Clone> GpuArrayBufferable for T {}
19
20#[derive(Resource)]
36pub enum GpuArrayBuffer<T: GpuArrayBufferable> {
37 Uniform(BatchedUniformBuffer<T>),
38 Storage(BufferVec<T>),
39}
40
41impl<T: GpuArrayBufferable> GpuArrayBuffer<T> {
42 pub fn new(device: &RenderDevice) -> Self {
43 let limits = device.limits();
44 if limits.max_storage_buffers_per_shader_stage == 0 {
45 GpuArrayBuffer::Uniform(BatchedUniformBuffer::new(&limits))
46 } else {
47 GpuArrayBuffer::Storage(BufferVec::new(BufferUsages::STORAGE))
48 }
49 }
50
51 pub fn clear(&mut self) {
52 match self {
53 GpuArrayBuffer::Uniform(buffer) => buffer.clear(),
54 GpuArrayBuffer::Storage(buffer) => buffer.clear(),
55 }
56 }
57
58 pub fn push(&mut self, value: T) -> GpuArrayBufferIndex<T> {
59 match self {
60 GpuArrayBuffer::Uniform(buffer) => buffer.push(value),
61 GpuArrayBuffer::Storage(buffer) => {
62 let index = buffer.push(value) as u32;
63 GpuArrayBufferIndex {
64 index,
65 dynamic_offset: None,
66 element_type: PhantomData,
67 }
68 }
69 }
70 }
71
72 pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
73 match self {
74 GpuArrayBuffer::Uniform(buffer) => buffer.write_buffer(device, queue),
75 GpuArrayBuffer::Storage(buffer) => buffer.write_buffer(device, queue),
76 }
77 }
78
79 pub fn binding_layout(device: &RenderDevice) -> BindGroupLayoutEntryBuilder {
80 if device.limits().max_storage_buffers_per_shader_stage == 0 {
81 uniform_buffer_sized(
82 true,
83 None,
86 )
87 } else {
88 storage_buffer_read_only::<T>(false)
89 }
90 }
91
92 pub fn binding(&self) -> Option<BindingResource<'_>> {
93 match self {
94 GpuArrayBuffer::Uniform(buffer) => buffer.binding(),
95 GpuArrayBuffer::Storage(buffer) => buffer.binding(),
96 }
97 }
98
99 pub fn batch_size(device: &RenderDevice) -> Option<u32> {
100 let limits = device.limits();
101 if limits.max_storage_buffers_per_shader_stage == 0 {
102 Some(BatchedUniformBuffer::<T>::batch_size(&limits) as u32)
103 } else {
104 None
105 }
106 }
107}
108
109#[derive(Component, Clone)]
111pub struct GpuArrayBufferIndex<T: GpuArrayBufferable> {
112 pub index: u32,
114 pub dynamic_offset: Option<NonMaxU32>,
117 pub element_type: PhantomData<T>,
118}