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