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
9328 views
1
use bevy_material::bind_group_layout_entries::{
2
binding_types::{storage_buffer_read_only, uniform_buffer_sized},
3
BindGroupLayoutEntryBuilder,
4
};
5
6
use super::BufferVec;
7
use crate::{
8
render_resource::batched_uniform_buffer::BatchedUniformBuffer,
9
renderer::{RenderDevice, RenderQueue},
10
};
11
use bevy_ecs::{prelude::Component, resource::Resource};
12
use core::marker::PhantomData;
13
use encase::{private::WriteInto, ShaderSize, ShaderType};
14
use nonmax::NonMaxU32;
15
use wgpu::{BindingResource, BufferUsages, Limits};
16
17
/// Trait for types able to go in a [`GpuArrayBuffer`].
18
pub trait GpuArrayBufferable: ShaderType + ShaderSize + WriteInto + Clone {}
19
20
impl<T: ShaderType + ShaderSize + WriteInto + Clone> GpuArrayBufferable for T {}
21
22
/// Stores an array of elements to be transferred to the GPU and made accessible to shaders as a read-only array.
23
///
24
/// On platforms that support storage buffers, this is equivalent to
25
/// [`BufferVec<T>`]. Otherwise, this falls back to a dynamic offset
26
/// uniform buffer with the largest array of T that fits within a uniform buffer
27
/// binding (within reasonable limits).
28
///
29
/// Other options for storing GPU-accessible data are:
30
/// * [`BufferVec`]
31
/// * [`DynamicStorageBuffer`](crate::render_resource::DynamicStorageBuffer)
32
/// * [`DynamicUniformBuffer`](crate::render_resource::DynamicUniformBuffer)
33
/// * [`RawBufferVec`](crate::render_resource::RawBufferVec)
34
/// * [`StorageBuffer`](crate::render_resource::StorageBuffer)
35
/// * [`Texture`](crate::render_resource::Texture)
36
/// * [`UniformBuffer`](crate::render_resource::UniformBuffer)
37
#[derive(Resource)]
38
pub enum GpuArrayBuffer<T: GpuArrayBufferable> {
39
Uniform(BatchedUniformBuffer<T>),
40
Storage(BufferVec<T>),
41
}
42
43
impl<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
// BatchedUniformBuffer uses a MaxCapacityArray that is runtime-sized, so we use
85
// None here and let wgpu figure out the size.
86
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
/// 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