Bind only the written parts of storage buffers. (#16405)

# Objective
- Fix part of #15920

## Solution

- Keep track of the last written amount of bytes, and bind only that
much of the buffer.

## Testing

- Did you test these changes? If so, how? No
- Are there any parts that need more testing?
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?

---

## Migration Guide

- Fixed a bug with StorageBuffer and DynamicStorageBuffer binding data
from the previous frame(s) due to caching GPU buffers between frames.
This commit is contained in:
JMS55 2024-11-17 01:11:26 -08:00 committed by GitHub
parent 9f04fc030b
commit ed6508363e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -6,7 +6,7 @@ use encase::{
internal::WriteInto, DynamicStorageBuffer as DynamicStorageBufferWrapper, ShaderType, internal::WriteInto, DynamicStorageBuffer as DynamicStorageBufferWrapper, ShaderType,
StorageBuffer as StorageBufferWrapper, StorageBuffer as StorageBufferWrapper,
}; };
use wgpu::{util::BufferInitDescriptor, BindingResource, BufferBinding, BufferUsages}; use wgpu::{util::BufferInitDescriptor, BindingResource, BufferBinding, BufferSize, BufferUsages};
use super::IntoBinding; use super::IntoBinding;
@ -39,6 +39,7 @@ pub struct StorageBuffer<T: ShaderType> {
label: Option<String>, label: Option<String>,
changed: bool, changed: bool,
buffer_usage: BufferUsages, buffer_usage: BufferUsages,
last_written_size: Option<BufferSize>,
} }
impl<T: ShaderType> From<T> for StorageBuffer<T> { impl<T: ShaderType> From<T> for StorageBuffer<T> {
@ -50,6 +51,7 @@ impl<T: ShaderType> From<T> for StorageBuffer<T> {
label: None, label: None,
changed: false, changed: false,
buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE, buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
last_written_size: None,
} }
} }
} }
@ -63,6 +65,7 @@ impl<T: ShaderType + Default> Default for StorageBuffer<T> {
label: None, label: None,
changed: false, changed: false,
buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE, buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
last_written_size: None,
} }
} }
} }
@ -75,9 +78,11 @@ impl<T: ShaderType + WriteInto> StorageBuffer<T> {
#[inline] #[inline]
pub fn binding(&self) -> Option<BindingResource> { pub fn binding(&self) -> Option<BindingResource> {
Some(BindingResource::Buffer( Some(BindingResource::Buffer(BufferBinding {
self.buffer()?.as_entire_buffer_binding(), buffer: self.buffer()?,
)) offset: 0,
size: self.last_written_size,
}))
} }
pub fn set(&mut self, value: T) { pub fn set(&mut self, value: T) {
@ -137,16 +142,15 @@ impl<T: ShaderType + WriteInto> StorageBuffer<T> {
} else if let Some(buffer) = &self.buffer { } else if let Some(buffer) = &self.buffer {
queue.write_buffer(buffer, 0, self.scratch.as_ref()); queue.write_buffer(buffer, 0, self.scratch.as_ref());
} }
self.last_written_size = BufferSize::new(size);
} }
} }
impl<'a, T: ShaderType + WriteInto> IntoBinding<'a> for &'a StorageBuffer<T> { impl<'a, T: ShaderType + WriteInto> IntoBinding<'a> for &'a StorageBuffer<T> {
#[inline] #[inline]
fn into_binding(self) -> BindingResource<'a> { fn into_binding(self) -> BindingResource<'a> {
self.buffer() self.binding().expect("Failed to get buffer")
.expect("Failed to get buffer")
.as_entire_buffer_binding()
.into_binding()
} }
} }
@ -180,6 +184,7 @@ pub struct DynamicStorageBuffer<T: ShaderType> {
label: Option<String>, label: Option<String>,
changed: bool, changed: bool,
buffer_usage: BufferUsages, buffer_usage: BufferUsages,
last_written_size: Option<BufferSize>,
_marker: PhantomData<fn() -> T>, _marker: PhantomData<fn() -> T>,
} }
@ -191,6 +196,7 @@ impl<T: ShaderType> Default for DynamicStorageBuffer<T> {
label: None, label: None,
changed: false, changed: false,
buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE, buffer_usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
last_written_size: None,
_marker: PhantomData, _marker: PhantomData,
} }
} }
@ -207,7 +213,7 @@ impl<T: ShaderType + WriteInto> DynamicStorageBuffer<T> {
Some(BindingResource::Buffer(BufferBinding { Some(BindingResource::Buffer(BufferBinding {
buffer: self.buffer()?, buffer: self.buffer()?,
offset: 0, offset: 0,
size: Some(T::min_size()), size: self.last_written_size,
})) }))
} }
@ -260,6 +266,8 @@ impl<T: ShaderType + WriteInto> DynamicStorageBuffer<T> {
} else if let Some(buffer) = &self.buffer { } else if let Some(buffer) = &self.buffer {
queue.write_buffer(buffer, 0, self.scratch.as_ref()); queue.write_buffer(buffer, 0, self.scratch.as_ref());
} }
self.last_written_size = BufferSize::new(size);
} }
#[inline] #[inline]
@ -272,6 +280,6 @@ impl<T: ShaderType + WriteInto> DynamicStorageBuffer<T> {
impl<'a, T: ShaderType + WriteInto> IntoBinding<'a> for &'a DynamicStorageBuffer<T> { impl<'a, T: ShaderType + WriteInto> IntoBinding<'a> for &'a DynamicStorageBuffer<T> {
#[inline] #[inline]
fn into_binding(self) -> BindingResource<'a> { fn into_binding(self) -> BindingResource<'a> {
self.binding().unwrap() self.binding().expect("Failed to get buffer")
} }
} }