Skip to content

Commit 5eca832

Browse files
authored
Add convenience methods for constructing and setting storage buffer data (#15044)
Adds some methods to assist in building `ShaderStorageBuffer` without using `bytemuck`. We keep the `&[u8]` constructors since this is still modeled as a thin wrapper around the buffer descriptor, but should make it easier to interact with at the cost of an extra allocation in the `ShaderType` path for the buffer writer. Follow up from #14663
1 parent e939d6c commit 5eca832

File tree

2 files changed

+39
-21
lines changed

2 files changed

+39
-21
lines changed

crates/bevy_render/src/storage.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use bevy_ecs::system::SystemParamItem;
88
use bevy_reflect::prelude::ReflectDefault;
99
use bevy_reflect::Reflect;
1010
use bevy_utils::default;
11+
use encase::internal::WriteInto;
12+
use encase::ShaderType;
1113
use wgpu::util::BufferInitDescriptor;
1214

1315
/// Adds [`ShaderStorageBuffer`] as an asset that is extracted and uploaded to the GPU.
@@ -72,6 +74,29 @@ impl ShaderStorageBuffer {
7274
storage.asset_usage = asset_usage;
7375
storage
7476
}
77+
78+
/// Sets the data of the storage buffer to the given [`ShaderType`].
79+
pub fn set_data<T>(&mut self, value: T)
80+
where
81+
T: ShaderType + WriteInto,
82+
{
83+
let size = value.size().get() as usize;
84+
let mut wrapper = encase::StorageBuffer::<Vec<u8>>::new(Vec::with_capacity(size));
85+
wrapper.write(&value).unwrap();
86+
self.data = Some(wrapper.into_inner());
87+
}
88+
}
89+
90+
impl<T> From<T> for ShaderStorageBuffer
91+
where
92+
T: ShaderType + WriteInto,
93+
{
94+
fn from(value: T) -> Self {
95+
let size = value.size().get() as usize;
96+
let mut wrapper = encase::StorageBuffer::<Vec<u8>>::new(Vec::with_capacity(size));
97+
wrapper.write(&value).unwrap();
98+
Self::new(wrapper.as_ref(), RenderAssetUsages::default())
99+
}
75100
}
76101

77102
/// A storage buffer that is prepared as a [`RenderAsset`] and uploaded to the GPU.

examples/shader/storage_buffer.rs

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use bevy::{
44
reflect::TypePath,
55
render::render_resource::{AsBindGroup, ShaderRef},
66
};
7-
use bevy_render::render_asset::RenderAssetUsages;
87
use bevy_render::storage::ShaderStorageBuffer;
98

109
const SHADER_ASSET_PATH: &str = "shaders/storage_buffer.wgsl";
@@ -33,10 +32,7 @@ fn setup(
3332
[0.0, 1.0, 1.0, 1.0],
3433
];
3534

36-
let colors = buffers.add(ShaderStorageBuffer::new(
37-
bytemuck::cast_slice(color_data.as_slice()),
38-
RenderAssetUsages::default(),
39-
));
35+
let colors = buffers.add(ShaderStorageBuffer::from(color_data));
4036

4137
// Create the custom material with the storage buffer
4238
let custom_material = CustomMaterial { colors };
@@ -72,22 +68,19 @@ fn update(
7268
) {
7369
let material = materials.get_mut(&material_handle.0).unwrap();
7470
let buffer = buffers.get_mut(&material.colors).unwrap();
75-
buffer.data = Some(
76-
bytemuck::cast_slice(
77-
(0..5)
78-
.map(|i| {
79-
let t = time.elapsed_seconds() * 5.0;
80-
[
81-
(t + i as f32).sin() / 2.0 + 0.5,
82-
(t + i as f32 + 2.0).sin() / 2.0 + 0.5,
83-
(t + i as f32 + 4.0).sin() / 2.0 + 0.5,
84-
1.0,
85-
]
86-
})
87-
.collect::<Vec<[f32; 4]>>()
88-
.as_slice(),
89-
)
90-
.to_vec(),
71+
buffer.set_data(
72+
(0..5)
73+
.map(|i| {
74+
let t = time.elapsed_seconds() * 5.0;
75+
[
76+
(t + i as f32).sin() / 2.0 + 0.5,
77+
(t + i as f32 + 2.0).sin() / 2.0 + 0.5,
78+
(t + i as f32 + 4.0).sin() / 2.0 + 0.5,
79+
1.0,
80+
]
81+
})
82+
.collect::<Vec<[f32; 4]>>()
83+
.as_slice(),
9184
);
9285
}
9386

0 commit comments

Comments
 (0)