Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_render/src/render_resource/gpu_array_buffer.rs
6596 views
1
use super::{
2
binding_types::{storage_buffer_read_only, uniform_buffer_sized},
3
BindGroupLayoutEntryBuilder, BufferVec,
4
};
5
use crate::{
6
render_resource::batched_uniform_buffer::BatchedUniformBuffer,
7
renderer::{RenderDevice, RenderQueue},
8
};
9
use bevy_ecs::{prelude::Component, resource::Resource};
10
use core::marker::PhantomData;
11
use encase::{private::WriteInto, ShaderSize, ShaderType};
12
use nonmax::NonMaxU32;
13
use wgpu::{BindingResource, BufferUsages};
14
15
/// Trait for types able to go in a [`GpuArrayBuffer`].
16
pub trait GpuArrayBufferable: ShaderType + ShaderSize + WriteInto + Clone {}
17
18
impl<T: ShaderType + ShaderSize + WriteInto + Clone> GpuArrayBufferable for T {}
19
20
/// Stores an array of elements to be transferred to the GPU and made accessible to shaders as a read-only array.
21
///
22
/// On platforms that support storage buffers, this is equivalent to
23
/// [`BufferVec<T>`]. Otherwise, this falls back to a dynamic offset
24
/// uniform buffer with the largest array of T that fits within a uniform buffer
25
/// binding (within reasonable limits).
26
///
27
/// Other options for storing GPU-accessible data are:
28
/// * [`BufferVec`]
29
/// * [`DynamicStorageBuffer`](crate::render_resource::DynamicStorageBuffer)
30
/// * [`DynamicUniformBuffer`](crate::render_resource::DynamicUniformBuffer)
31
/// * [`RawBufferVec`](crate::render_resource::RawBufferVec)
32
/// * [`StorageBuffer`](crate::render_resource::StorageBuffer)
33
/// * [`Texture`](crate::render_resource::Texture)
34
/// * [`UniformBuffer`](crate::render_resource::UniformBuffer)
35
#[derive(Resource)]
36
pub enum GpuArrayBuffer<T: GpuArrayBufferable> {
37
Uniform(BatchedUniformBuffer<T>),
38
Storage(BufferVec<T>),
39
}
40
41
impl<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
// BatchedUniformBuffer uses a MaxCapacityArray that is runtime-sized, so we use
84
// None here and let wgpu figure out the size.
85
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
/// An index into a [`GpuArrayBuffer`] for a given element.
110
#[derive(Component, Clone)]
111
pub struct GpuArrayBufferIndex<T: GpuArrayBufferable> {
112
/// The index to use in a shader into the array.
113
pub index: u32,
114
/// The dynamic offset to use when setting the bind group in a pass.
115
/// Only used on platforms that don't support storage buffers.
116
pub dynamic_offset: Option<NonMaxU32>,
117
pub element_type: PhantomData<T>,
118
}
119
120