Skip to content

Commit

Permalink
Try to solve crash on wasm
Browse files Browse the repository at this point in the history
  • Loading branch information
cwfitzgerald committed Jun 25, 2022
1 parent 7375acb commit 99c49b9
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 13 deletions.
8 changes: 5 additions & 3 deletions wgpu/src/backend/direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1641,13 +1641,15 @@ impl crate::Context for Context {
ready(scope.error)
}

fn buffer_map_async(
fn buffer_map_async<F>(
&self,
buffer: &Self::BufferId,
mode: MapMode,
range: Range<wgt::BufferAddress>,
callback: impl FnOnce(Result<(), crate::BufferAsyncError>) + Send + 'static,
) {
callback: F,
) where
F: FnOnce(Result<(), crate::BufferAsyncError>) + Send + 'static,
{
let operation = wgc::resource::BufferMapOperation {
host: match mode {
MapMode::Read => wgc::device::HostMap::Read,
Expand Down
27 changes: 20 additions & 7 deletions wgpu/src/backend/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1685,13 +1685,15 @@ impl crate::Context for Context {
)
}

fn buffer_map_async(
fn buffer_map_async<F>(
&self,
buffer: &Self::BufferId,
mode: crate::MapMode,
range: Range<wgt::BufferAddress>,
callback: impl FnOnce(Result<(), crate::BufferAsyncError>) + Send + 'static,
) {
callback: F,
) where
F: FnOnce(Result<(), crate::BufferAsyncError>) + Send + 'static,
{
let map_promise = buffer.0.map_async_with_f64_and_f64(
map_map_mode(mode),
range.start as f64,
Expand All @@ -1703,17 +1705,28 @@ impl crate::Context for Context {
// and then take ownership of callback when invoked.
//
// We also only need Rc's because these will only ever be called on our thread.
let rc_callback = Rc::new(RefCell::new(Some(callback)));
let rc_callback: Rc<RefCell<Option<(_, _, F)>>> = Rc::new(RefCell::new(None));

let rc_callback_clone = rc_callback.clone();
let rc_callback_clone1 = rc_callback.clone();
let rc_callback_clone2 = rc_callback.clone();
let closure_success = wasm_bindgen::closure::Closure::once(move |_| {
rc_callback.borrow_mut().take().unwrap()(Ok(()))
if let Some((success, rejection, callback)) = rc_callback_clone1.borrow_mut().take() {
callback(Ok(()));
drop((success, rejection));
}
});
let closure_rejected = wasm_bindgen::closure::Closure::once(move |_| {
rc_callback_clone.borrow_mut().take().unwrap()(Err(crate::BufferAsyncError))
if let Some((success, rejection, callback)) = rc_callback_clone2.borrow_mut().take() {
callback(Err(crate::BufferAsyncError));
drop((success, rejection));
}
});

// Calling then before setting the value in the Rc seems like a race, but it isn't
// because the promise callback will run on this thread, so there is no race.
let _ = map_promise.then2(&closure_success, &closure_rejected);

*rc_callback.borrow_mut() = Some((closure_success, closure_rejected, callback));
}

fn buffer_get_mapped_range(
Expand Down
7 changes: 4 additions & 3 deletions wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,16 +330,17 @@ trait Context: Debug + Send + Sized + Sync {
fn device_push_error_scope(&self, device: &Self::DeviceId, filter: ErrorFilter);
fn device_pop_error_scope(&self, device: &Self::DeviceId) -> Self::PopErrorScopeFuture;

fn buffer_map_async(
fn buffer_map_async<F>(
&self,
buffer: &Self::BufferId,
mode: MapMode,
range: Range<BufferAddress>,
// Note: we keep this as an `impl` through the context because the native backend
// needs to wrap it with a wrapping closure. queue_on_submitted_work_done doesn't
// need this wrapping closure, so can be made a Box immediately.
callback: impl FnOnce(Result<(), BufferAsyncError>) + Send + 'static,
);
callback: F,
) where
F: FnOnce(Result<(), BufferAsyncError>) + Send + 'static;
fn buffer_get_mapped_range(
&self,
buffer: &Self::BufferId,
Expand Down

0 comments on commit 99c49b9

Please sign in to comment.