2024-09-24 11:42:59 +00:00
|
|
|
use crate::{
|
|
|
|
render_asset::{PrepareAssetError, RenderAsset, RenderAssetPlugin, RenderAssetUsages},
|
|
|
|
render_resource::{Buffer, BufferUsages},
|
|
|
|
renderer::RenderDevice,
|
|
|
|
};
|
2024-09-02 16:46:34 +00:00
|
|
|
use bevy_app::{App, Plugin};
|
|
|
|
use bevy_asset::{Asset, AssetApp};
|
2024-09-24 11:42:59 +00:00
|
|
|
use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem};
|
|
|
|
use bevy_reflect::{prelude::ReflectDefault, Reflect};
|
2024-09-02 16:46:34 +00:00
|
|
|
use bevy_utils::default;
|
2024-09-24 11:42:59 +00:00
|
|
|
use encase::{internal::WriteInto, ShaderType};
|
2024-09-02 16:46:34 +00:00
|
|
|
use wgpu::util::BufferInitDescriptor;
|
|
|
|
|
|
|
|
/// Adds [`ShaderStorageBuffer`] as an asset that is extracted and uploaded to the GPU.
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct StoragePlugin;
|
|
|
|
|
|
|
|
impl Plugin for StoragePlugin {
|
|
|
|
fn build(&self, app: &mut App) {
|
|
|
|
app.add_plugins(RenderAssetPlugin::<GpuShaderStorageBuffer>::default())
|
|
|
|
.register_type::<ShaderStorageBuffer>()
|
|
|
|
.init_asset::<ShaderStorageBuffer>()
|
|
|
|
.register_asset_reflect::<ShaderStorageBuffer>();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A storage buffer that is prepared as a [`RenderAsset`] and uploaded to the GPU.
|
|
|
|
#[derive(Asset, Reflect, Debug, Clone)]
|
bevy_reflect: Replace "value" terminology with "opaque" (#15240)
# Objective
Currently, the term "value" in the context of reflection is a bit
overloaded.
For one, it can be used synonymously with "data" or "variable". An
example sentence would be "this function takes a reflected value".
However, it is also used to refer to reflected types which are
`ReflectKind::Value`. These types are usually either primitives, opaque
types, or types that don't fall into any other `ReflectKind` (or perhaps
could, but don't due to some limitation/difficulty). An example sentence
would be "this function takes a reflected value type".
This makes it difficult to write good documentation or other learning
material without causing some amount of confusion to readers. Ideally,
we'd be able to move away from the `ReflectKind::Value` usage and come
up with a better term.
## Solution
This PR replaces the terminology of "value" with "opaque" across
`bevy_reflect`. This includes in documentation, type names, variant
names, and macros.
The term "opaque" was chosen because that's essentially how the type is
treated within the reflection API. In other words, its internal
structure is hidden. All we can do is work with the type itself.
### Primitives
While primitives are not technically opaque types, I think it's still
clearer to refer to them as "opaque" rather than keep the confusing
"value" terminology.
We could consider adding another concept for primitives (e.g.
`ReflectKind::Primitive`), but I'm not sure that provides a lot of
benefit right now. In most circumstances, they'll be treated just like
an opaque type. They would also likely use the same macro (or two copies
of the same macro but with different names).
## Testing
You can test locally by running:
```
cargo test --package bevy_reflect --all-features
```
---
## Migration Guide
The reflection concept of "value type" has been replaced with a clearer
"opaque type". The following renames have been made to account for this:
- `ReflectKind::Value` → `ReflectKind::Opaque`
- `ReflectRef::Value` → `ReflectRef::Opaque`
- `ReflectMut::Value` → `ReflectMut::Opaque`
- `ReflectOwned::Value` → `ReflectOwned::Opaque`
- `TypeInfo::Value` → `TypeInfo::Opaque`
- `ValueInfo` → `OpaqueInfo`
- `impl_reflect_value!` → `impl_reflect_opaque!`
- `impl_from_reflect_value!` → `impl_from_reflect_opaque!`
Additionally, declaring your own opaque types no longer uses
`#[reflect_value]`. This attribute has been replaced by
`#[reflect(opaque)]`:
```rust
// BEFORE
#[derive(Reflect)]
#[reflect_value(Default)]
struct MyOpaqueType(u32);
// AFTER
#[derive(Reflect)]
#[reflect(opaque)]
#[reflect(Default)]
struct MyOpaqueType(u32);
```
Note that the order in which `#[reflect(opaque)]` appears does not
matter.
2024-09-23 18:04:57 +00:00
|
|
|
#[reflect(opaque)]
|
|
|
|
#[reflect(Default, Debug)]
|
2024-09-02 16:46:34 +00:00
|
|
|
pub struct ShaderStorageBuffer {
|
|
|
|
/// Optional data used to initialize the buffer.
|
|
|
|
pub data: Option<Vec<u8>>,
|
|
|
|
/// The buffer description used to create the buffer.
|
|
|
|
pub buffer_description: wgpu::BufferDescriptor<'static>,
|
|
|
|
/// The asset usage of the storage buffer.
|
|
|
|
pub asset_usage: RenderAssetUsages,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for ShaderStorageBuffer {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
|
|
|
data: None,
|
|
|
|
buffer_description: wgpu::BufferDescriptor {
|
|
|
|
label: None,
|
|
|
|
size: 0,
|
|
|
|
usage: BufferUsages::STORAGE,
|
|
|
|
mapped_at_creation: false,
|
|
|
|
},
|
|
|
|
asset_usage: RenderAssetUsages::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ShaderStorageBuffer {
|
|
|
|
/// Creates a new storage buffer with the given data and asset usage.
|
|
|
|
pub fn new(data: &[u8], asset_usage: RenderAssetUsages) -> Self {
|
|
|
|
let mut storage = ShaderStorageBuffer {
|
|
|
|
data: Some(data.to_vec()),
|
|
|
|
..default()
|
|
|
|
};
|
|
|
|
storage.asset_usage = asset_usage;
|
|
|
|
storage
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Creates a new storage buffer with the given size and asset usage.
|
|
|
|
pub fn with_size(size: usize, asset_usage: RenderAssetUsages) -> Self {
|
|
|
|
let mut storage = ShaderStorageBuffer {
|
|
|
|
data: None,
|
|
|
|
..default()
|
|
|
|
};
|
|
|
|
storage.buffer_description.size = size as u64;
|
|
|
|
storage.buffer_description.mapped_at_creation = false;
|
|
|
|
storage.asset_usage = asset_usage;
|
|
|
|
storage
|
|
|
|
}
|
2024-09-09 15:28:31 +00:00
|
|
|
|
|
|
|
/// Sets the data of the storage buffer to the given [`ShaderType`].
|
|
|
|
pub fn set_data<T>(&mut self, value: T)
|
|
|
|
where
|
|
|
|
T: ShaderType + WriteInto,
|
|
|
|
{
|
|
|
|
let size = value.size().get() as usize;
|
|
|
|
let mut wrapper = encase::StorageBuffer::<Vec<u8>>::new(Vec::with_capacity(size));
|
|
|
|
wrapper.write(&value).unwrap();
|
|
|
|
self.data = Some(wrapper.into_inner());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> From<T> for ShaderStorageBuffer
|
|
|
|
where
|
|
|
|
T: ShaderType + WriteInto,
|
|
|
|
{
|
|
|
|
fn from(value: T) -> Self {
|
|
|
|
let size = value.size().get() as usize;
|
|
|
|
let mut wrapper = encase::StorageBuffer::<Vec<u8>>::new(Vec::with_capacity(size));
|
|
|
|
wrapper.write(&value).unwrap();
|
|
|
|
Self::new(wrapper.as_ref(), RenderAssetUsages::default())
|
|
|
|
}
|
2024-09-02 16:46:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// A storage buffer that is prepared as a [`RenderAsset`] and uploaded to the GPU.
|
|
|
|
pub struct GpuShaderStorageBuffer {
|
|
|
|
pub buffer: Buffer,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RenderAsset for GpuShaderStorageBuffer {
|
|
|
|
type SourceAsset = ShaderStorageBuffer;
|
|
|
|
type Param = SRes<RenderDevice>;
|
|
|
|
|
|
|
|
fn asset_usage(source_asset: &Self::SourceAsset) -> RenderAssetUsages {
|
|
|
|
source_asset.asset_usage
|
|
|
|
}
|
|
|
|
|
|
|
|
fn prepare_asset(
|
|
|
|
source_asset: Self::SourceAsset,
|
|
|
|
render_device: &mut SystemParamItem<Self::Param>,
|
|
|
|
) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
|
|
|
|
match source_asset.data {
|
|
|
|
Some(data) => {
|
|
|
|
let buffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
|
|
|
|
label: source_asset.buffer_description.label,
|
|
|
|
contents: &data,
|
|
|
|
usage: source_asset.buffer_description.usage,
|
|
|
|
});
|
|
|
|
Ok(GpuShaderStorageBuffer { buffer })
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
let buffer = render_device.create_buffer(&source_asset.buffer_description);
|
|
|
|
Ok(GpuShaderStorageBuffer { buffer })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|