mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Change API from BufferSlice::get_mapped_range_as_array_buffer() to BufferView::as_uint8array() to fix bug where using the former API prevents you from ever unmapping your buffer (#7738)
Co-authored-by: Ryan Kaplan <ryan@Ryans-M2>
This commit is contained in:
parent
f139e223e2
commit
1268219ba3
@ -61,6 +61,7 @@ Bottom level categories:
|
||||
#### General
|
||||
|
||||
- Fix error message for sampler array limit. By @LPGhatguy in [#7704](https://github.com/gfx-rs/wgpu/pull/7704).
|
||||
- Fix bug where using `BufferSlice::get_mapped_range_as_array_buffer()` on a buffer would prevent you from ever unmapping it. Note that this API has changed and is now `BufferView::as_uint8array()`.
|
||||
|
||||
#### Naga
|
||||
|
||||
@ -478,15 +479,16 @@ By @cwfitzgerald in [#6811](https://github.com/gfx-rs/wgpu/pull/6811), [#6815](h
|
||||
|
||||
- Call `pre_present_notify()` before presenting. By @kjarosh in [#7074](https://github.com/gfx-rs/wgpu/pull/7074).
|
||||
|
||||
|
||||
## v24.0.5 (2025-05-24)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
#### General
|
||||
|
||||
- Fix a possible deadlock within `Queue::write_buffer`. By @RedMindZ in [#7582](https://github.com/gfx-rs/wgpu/pull/7582)
|
||||
|
||||
#### WebGPU
|
||||
|
||||
- Insert fragment pipeline constants into fragment descriptor instead of vertex descriptor. By @DerSchmale in [#7621](https://github.com/gfx-rs/wgpu/pull/7621)
|
||||
|
||||
## v24.0.4 (2025-04-03)
|
||||
|
||||
@ -335,33 +335,6 @@ impl Buffer {
|
||||
self.slice(bounds).get_mapped_range()
|
||||
}
|
||||
|
||||
/// Synchronously and immediately map a buffer for reading. If the buffer is not immediately mappable
|
||||
/// through [`BufferDescriptor::mapped_at_creation`] or [`BufferSlice::map_async`], will fail.
|
||||
///
|
||||
/// This is useful when targeting WebGPU and you want to pass mapped data directly to js.
|
||||
/// Unlike `get_mapped_range` which unconditionally copies mapped data into the wasm heap,
|
||||
/// this function directly hands you the ArrayBuffer that we mapped the data into in js.
|
||||
///
|
||||
/// This is only available on WebGPU, on any other backends this will return `None`.
|
||||
///
|
||||
/// `bounds` may be less than the bounds passed to [`Self::map_async()`],
|
||||
/// and multiple views may be obtained and used simultaneously as long as they do not overlap.
|
||||
///
|
||||
/// This can also be performed using [`BufferSlice::get_mapped_range_as_array_buffer()`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - If `bounds` is outside of the bounds of `self`.
|
||||
/// - If `bounds` has a length less than 1.
|
||||
/// - If the start and end of `bounds` are not aligned to [`MAP_ALIGNMENT`].
|
||||
#[cfg(webgpu)]
|
||||
pub fn get_mapped_range_as_array_buffer<S: RangeBounds<BufferAddress>>(
|
||||
&self,
|
||||
bounds: S,
|
||||
) -> Option<js_sys::ArrayBuffer> {
|
||||
self.slice(bounds).get_mapped_range_as_array_buffer()
|
||||
}
|
||||
|
||||
/// Gain write access to the bytes of a [mapped] [`Buffer`].
|
||||
///
|
||||
/// Returns a [`BufferViewMut`] referring to the buffer range represented by
|
||||
@ -531,32 +504,6 @@ impl<'a> BufferSlice<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Synchronously and immediately map a buffer for reading. If the buffer is not immediately mappable
|
||||
/// through [`BufferDescriptor::mapped_at_creation`] or [`BufferSlice::map_async`], will fail.
|
||||
///
|
||||
/// This is useful when targeting WebGPU and you want to pass mapped data directly to js.
|
||||
/// Unlike `get_mapped_range` which unconditionally copies mapped data into the wasm heap,
|
||||
/// this function directly hands you the ArrayBuffer that we mapped the data into in js.
|
||||
///
|
||||
/// This is only available on WebGPU, on any other backends this will return `None`.
|
||||
///
|
||||
/// Multiple views may be obtained and used simultaneously as long as they are from
|
||||
/// non-overlapping slices.
|
||||
///
|
||||
/// This can also be performed using [`Buffer::get_mapped_range_as_array_buffer()`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - If the endpoints of this slice are not aligned to [`MAP_ALIGNMENT`] within the buffer.
|
||||
#[cfg(webgpu)]
|
||||
pub fn get_mapped_range_as_array_buffer(&self) -> Option<js_sys::ArrayBuffer> {
|
||||
let end = self.buffer.map_context.lock().add(self.offset, self.size);
|
||||
|
||||
self.buffer
|
||||
.inner
|
||||
.get_mapped_range_as_array_buffer(self.offset..end)
|
||||
}
|
||||
|
||||
/// Gain write access to the bytes of a [mapped] [`Buffer`].
|
||||
///
|
||||
/// Returns a [`BufferViewMut`] referring to the buffer range represented by
|
||||
@ -760,6 +707,16 @@ pub struct BufferView<'a> {
|
||||
inner: dispatch::DispatchBufferMappedRange,
|
||||
}
|
||||
|
||||
#[cfg(webgpu)]
|
||||
impl BufferView<'_> {
|
||||
/// Provides the same data as dereferencing the view, but as a `Uint8Array` in js.
|
||||
/// This can be MUCH faster than dereferencing the view which copies the data into
|
||||
/// the Rust / wasm heap.
|
||||
pub fn as_uint8array(&self) -> &js_sys::Uint8Array {
|
||||
self.inner.as_uint8array()
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Deref for BufferView<'_> {
|
||||
type Target = [u8];
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ use alloc::{
|
||||
vec::Vec,
|
||||
};
|
||||
use core::{
|
||||
cell::OnceCell,
|
||||
cell::RefCell,
|
||||
fmt,
|
||||
future::Future,
|
||||
@ -1219,16 +1220,6 @@ impl WebBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a raw Javascript array buffer over the provided range.
|
||||
fn get_mapped_array_buffer(&self, sub_range: Range<wgt::BufferAddress>) -> js_sys::ArrayBuffer {
|
||||
self.inner
|
||||
.get_mapped_range_with_f64_and_f64(
|
||||
sub_range.start as f64,
|
||||
(sub_range.end - sub_range.start) as f64,
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Obtains a reference to the re-usable buffer mapping as a Javascript array view.
|
||||
fn get_mapped_range(&self, sub_range: Range<wgt::BufferAddress>) -> js_sys::Uint8Array {
|
||||
let mut mapping = self.mapping.borrow_mut();
|
||||
@ -1374,9 +1365,9 @@ pub struct WebQueueWriteBuffer {
|
||||
#[derive(Debug)]
|
||||
pub struct WebBufferMappedRange {
|
||||
actual_mapping: js_sys::Uint8Array,
|
||||
/// Copy of the mapped data that lives in the Rust/Wasm heap instead of JS,
|
||||
/// so Rust code can borrow it.
|
||||
temporary_mapping: Vec<u8>,
|
||||
/// Copy of actual_mapping that lives in the Rust/Wasm heap instead of JS. This
|
||||
/// is done only when accessed for the first time to avoid unnecessary allocations.
|
||||
temporary_mapping: OnceCell<Vec<u8>>,
|
||||
/// Whether `temporary_mapping` has possibly been written to and needs to be written back to JS.
|
||||
temporary_mapping_modified: bool,
|
||||
/// Unique identifier for this BufferMappedRange.
|
||||
@ -2667,23 +2658,15 @@ impl dispatch::BufferInterface for WebBuffer {
|
||||
sub_range: Range<crate::BufferAddress>,
|
||||
) -> dispatch::DispatchBufferMappedRange {
|
||||
let actual_mapping = self.get_mapped_range(sub_range);
|
||||
let temporary_mapping = actual_mapping.to_vec();
|
||||
WebBufferMappedRange {
|
||||
actual_mapping,
|
||||
temporary_mapping,
|
||||
temporary_mapping: OnceCell::new(),
|
||||
temporary_mapping_modified: false,
|
||||
ident: crate::cmp::Identifier::create(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
fn get_mapped_range_as_array_buffer(
|
||||
&self,
|
||||
sub_range: Range<wgt::BufferAddress>,
|
||||
) -> Option<js_sys::ArrayBuffer> {
|
||||
Some(self.get_mapped_array_buffer(sub_range))
|
||||
}
|
||||
|
||||
fn unmap(&self) {
|
||||
self.inner.unmap();
|
||||
self.mapping.borrow_mut().mapped_buffer = None;
|
||||
@ -3794,13 +3777,22 @@ impl Drop for WebSurfaceOutputDetail {
|
||||
impl dispatch::BufferMappedRangeInterface for WebBufferMappedRange {
|
||||
#[inline]
|
||||
fn slice(&self) -> &[u8] {
|
||||
&self.temporary_mapping
|
||||
self.temporary_mapping
|
||||
.get_or_init(|| self.actual_mapping.to_vec())
|
||||
.as_slice()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn slice_mut(&mut self) -> &mut [u8] {
|
||||
self.temporary_mapping_modified = true;
|
||||
&mut self.temporary_mapping
|
||||
self.temporary_mapping
|
||||
.get_or_init(|| self.actual_mapping.to_vec());
|
||||
self.temporary_mapping.get_mut().unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_uint8array(&self) -> &js_sys::Uint8Array {
|
||||
&self.actual_mapping
|
||||
}
|
||||
}
|
||||
impl Drop for WebBufferMappedRange {
|
||||
@ -3813,7 +3805,7 @@ impl Drop for WebBufferMappedRange {
|
||||
|
||||
// Copy from the temporary mapping back into the array buffer that was
|
||||
// originally provided by the browser
|
||||
let temporary_mapping_slice = self.temporary_mapping.as_slice();
|
||||
let temporary_mapping_slice = self.temporary_mapping.get().unwrap().as_slice();
|
||||
unsafe {
|
||||
// Note: no allocations can happen between `view` and `set`, or this
|
||||
// will break
|
||||
|
||||
@ -2037,14 +2037,6 @@ impl dispatch::BufferInterface for CoreBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(webgpu)]
|
||||
fn get_mapped_range_as_array_buffer(
|
||||
&self,
|
||||
_sub_range: Range<wgt::BufferAddress>,
|
||||
) -> Option<js_sys::ArrayBuffer> {
|
||||
None
|
||||
}
|
||||
|
||||
fn unmap(&self) {
|
||||
match self.context.0.buffer_unmap(self.id) {
|
||||
Ok(()) => (),
|
||||
@ -3705,4 +3697,9 @@ impl dispatch::BufferMappedRangeInterface for CoreBufferMappedRange {
|
||||
fn slice_mut(&mut self) -> &mut [u8] {
|
||||
unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), self.size) }
|
||||
}
|
||||
|
||||
#[cfg(webgpu)]
|
||||
fn as_uint8array(&self) -> &js_sys::Uint8Array {
|
||||
panic!("Only available on WebGPU")
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,11 +240,6 @@ pub trait BufferInterface: CommonTraits {
|
||||
);
|
||||
fn get_mapped_range(&self, sub_range: Range<crate::BufferAddress>)
|
||||
-> DispatchBufferMappedRange;
|
||||
#[cfg(webgpu)]
|
||||
fn get_mapped_range_as_array_buffer(
|
||||
&self,
|
||||
sub_range: Range<crate::BufferAddress>,
|
||||
) -> Option<js_sys::ArrayBuffer>;
|
||||
|
||||
fn unmap(&self);
|
||||
|
||||
@ -539,6 +534,9 @@ pub trait QueueWriteBufferInterface: CommonTraits {
|
||||
pub trait BufferMappedRangeInterface: CommonTraits {
|
||||
fn slice(&self) -> &[u8];
|
||||
fn slice_mut(&mut self) -> &mut [u8];
|
||||
|
||||
#[cfg(webgpu)]
|
||||
fn as_uint8array(&self) -> &js_sys::Uint8Array;
|
||||
}
|
||||
|
||||
/// Generates Dispatch types for each of the interfaces. Each type is a wrapper around the
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user