gfx-rs / wgpu

A cross-platform, safe, pure-Rust graphics API.
https://wgpu.rs
Apache License 2.0
12.4k stars 908 forks source link

Buffer Still Mapped Error Does Not Include Context or Buffer Name #4082

Open mcclure opened 1 year ago

mcclure commented 1 year ago

Warning: Sample code plays a loud noise.

Consider this branch:

https://github.com/mcclure/webgpu-tutorial-rs/tree/bug-still-mapped (Current head 2b73f96)

This builds a command buffer, the final step of which is to write some data into readback_buffer. Immediately after all commands, it runs:

// Done
println!("SUBMITTING FRAME…");
queue.submit(Some(encoder.finish()));
{
    let slice = readback_buffer.slice(..);
    let readback_buffer = readback_buffer.clone();

    // The WebGPU spec says this promise resolves successfully only "after the completion of currently-enqueued operations that use 'this'", so this doubles as an on_submitted_work_done for these purposes.
    slice.map_async(wgpu::MapMode::Read, move |result| {
        if let Ok(()) = result {
            let slice = readback_buffer.slice(..);
            let range = slice.get_mapped_range();
            let row = bytemuck::cast_slice::<u8, f32>(&range);
            println!("HAVE MAPPED RANGE! {}", row[0]);
        }
        readback_buffer.unmap();
    });
}
frame.present();

As far as I know, I am doing the right thing here: I clone readback_buffer (an std::sync::Arc<wgpu::Buffer>, I closure-move it into a callback to map_async, I do not call get_mapped_range until I am inside the callback, I unmap as soon as possible.

Running this prints:

Boot
SUBMITTING FRAME…
SUBMITTING FRAME…
thread 'main' panicked at 'Error in Queue::submit: Validation Error

Caused by:
    Buffer (21, 1, Metal) is still mapped
', /Users/mcc/.cargo/registry/src/github.com-1ecc6299db9ec823/wgpu-0.16.2/src/backend/direct.rs:2252:30
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
[2023-08-22T18:13:28Z ERROR wgpu_hal::metal::device] No active command buffers for fence value 4
thread 'main' panicked at 'Error in Device::drop: Validation Error

Caused by:
    Parent device is lost
', /Users/mcc/.cargo/registry/src/github.com-1ecc6299db9ec823/wgpu-0.16.2/src/backend/direct.rs:1407:34

(Full backtrace below)

There are two problems here

  1. Why doesn't this work?
  2. Even if the reason it doesn't work is my code is incorrect: readback_buffer was created with label: Some("Readback buffer"), so it should be called that, not Buffer (21, 1, Metal).

Notes:

Full stacktrace: TERMINAL-OUTPUT.TXT

mcclure commented 1 year ago

It has now been explained to me why the code does not work but I still think the error message is situationally wrong.

ErichDonGubler commented 1 year ago

@mcclure: An explanation here, even only linked or copy-pasted, would be much more easy to find than only within Matrix chat! 🙏🏻 EDIT: Before we correct diagnostics, of course. 🙂

mcclure commented 1 year ago

This link to the Matrix discussion should work:

https://matrix.to/#/!FZyQrssSlHEZqrYcOb:matrix.org/$6poBiHPId6cLm5mTm8JbpODN7QHE38d2WyWLpjSugow?via=matrix.org&via=mozilla.org&via=kde.org

But TLDR is that before submitting any commands that make use of a buffer, you must unmap that buffer before entering the queue.submit() call. I don't like this (my expectation would have been that queue.submit() would have blocked), but apparently it is dictated by the constraints of the upstream WebGPU spec.

Incidentally, if the message something said something like "Buffer referenced in submit() is still mapped" rather than just "Buffer is still mapped", that would have been helpful to me (because it would have made it more clear which api requirement I failed)