Skip to content

Conversation

@ErichDonGubler
Copy link
Member

@ErichDonGubler ErichDonGubler commented Oct 23, 2025

Connections

Description

For cases where a buffer is mapped_at_creation, our current implementation of Buffer::create initializes the buffer's internal state with BufferMapState::Init (which contains a staging buffer underneath the hood) for a descriptor requesting MAP_READ that is copied to a host-backed buffer . MAP_WRITE works a little differently, starting from the beginning with a host-backed buffer.

Init does a buffer copy between the staging buffer and the host-backed buffer in the device's queue when the buffer is unmapped. However, Buffer::map_async (correctly) assumes that a host-backed buffer need not wait for anything in the queue. This results in a bug where map_async doesn't actually wait long enough for the device queue to complete its operations before resolving. Oops!

Up to the point where a buffer is unmapped after being mapped at creation, MAP_READ, MAP_WRITE, and even non-MAP_* buffers' capabilities are the same. That is, we should be able to get mutable slices for mapped ranges, no matter what. So, make MAP_READ just initialize its internal state in the same way as with MAP_WRITE.

Testing

Added webgpu:api,operation,buffers,map:mapAsync,read:*, which is expected to fail in the first commit, and is resolved with the second commit.

Squash or Rebase?

Rebase.

@ErichDonGubler ErichDonGubler changed the title WIP: fix(core): use BufferMapState::Active for any BufferUsages::MAP_* flags fix(core): use BufferMapState::Active for any BufferUsages::MAP_* flags Oct 23, 2025
@ErichDonGubler
Copy link
Member Author

ErichDonGubler commented Oct 24, 2025

Hmmm…I'm not immediately sure how to fix the CI errors, which all seem to be on GL backends (incl. WebGL). I'm not familiar with GL backends, so I'm sure I'm doing something wrong with bookkeeping there, but not what that might be.

@ErichDonGubler ErichDonGubler force-pushed the erichdongubler-push-dazed-adept-horse branch 2 times, most recently from 60bd075 to 10d652f Compare October 24, 2025 22:04
@ErichDonGubler ErichDonGubler marked this pull request as ready for review October 24, 2025 22:04
@ErichDonGubler
Copy link
Member Author

Going to mark this as ready for review. I'm not sure how to resolve CI yet, but at least the approach can be validated, and maybe a reviewer will know more than I do about how to resolve this. 😖

let buffer = Buffer {
raw: Snatchable::new(buffer),
device: self.clone(),
usage: desc.usage,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To address the GL error: I don't think we are passing the right usage to HAL, when we create the buffer its usage should include MAP_WRITE if mapped_at_creation == true.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this'll do it: ac38c82

WDYT?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually we need to set the MAP_WRITE flag only when MAP_READ and mapped_at_creation are present. So that we don't set it on GPU-backed buffers.

@teoxoy teoxoy self-assigned this Oct 27, 2025
@ErichDonGubler ErichDonGubler force-pushed the erichdongubler-push-dazed-adept-horse branch from 10d652f to 146f37e Compare October 27, 2025 17:46
@ErichDonGubler

This comment was marked as resolved.

@ErichDonGubler
Copy link
Member Author

ErichDonGubler commented Oct 27, 2025

Hmm, some WebGL tests failed with ac38c82 with recursive snatch log errors, but I'm not sure that they're related to this PR.

Dump of the error log:
failures:

---- shadow::test_webgl output ----
    info output:
        Testing using adapter: AdapterInfo {
            name: "ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)",
            vendor: 0,
            device: 0,
            device_type: Cpu,
            device_pci_bus_id: "",
            driver: "",
            driver_info: "WebGL 2.0 (OpenGL ES 3.0 Chromium)",
            backend: Gl,
            transient_saves_memory: false,
        }
        TEST: shadow
        Only vertex shader is present. Creating an empty fragment shader
    
    error output:
        panicked at wgpu-hal/src/gles/device.rs:1264:44:
        called `Option::unwrap()` on a `None` value
        
        Stack:
        
        Error
            at http://127.0.0.1:41349/wasm-bindgen-test:1774:21
            at logError (http://127.0.0.1:41349/wasm-bindgen-test:15:18)
            at imports.wbg.__wbg_new_f346c2f0d1ef8376 (http://127.0.0.1:41349/wasm-bindgen-test:1773:66)
            at wgpu_examples-a17d3159d541b1d4.wasm.__wbg_new_f346c2f0d1ef8376 externref shim (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[55624]:0x1073f48)
            at wgpu_examples-a17d3159d541b1d4.wasm.wasm_bindgen_test::__rt::Context::new::panic_handling::Error::new::hf74adf7e0df59c0e (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[33682]:0xf2bc30)
            at wgpu_examples-a17d3159d541b1d4.wasm.wasm_bindgen_test::__rt::Context::new::panic_handling::h2b93081e962d06e3 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[11193]:0xb7d91f)
            at wgpu_examples-a17d3159d541b1d4.wasm.wasm_bindgen_test::__rt::Context::new::{{closure}}::{{closure}}::hfdb32d2f4b85e1d4 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[31010]:0xeec89e)
            at wgpu_examples-a17d3159d541b1d4.wasm.std::panicking::rust_panic_with_hook::hc276d0501ad5b954 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[17093]:0xcf4680)
            at wgpu_examples-a17d3159d541b1d4.wasm.std::panicking::begin_panic_handler::{{closure}}::h23ff416a921468b4 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[22541]:0xdeb832)
            at wgpu_examples-a17d3159d541b1d4.wasm.std::sys::backtrace::__rust_end_short_backtrace::h16ab72765b32282d (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[56647]:0x1077648)
        
        
        at logError (http://127.0.0.1:41349/wasm-bindgen-test:15:18)
        at imports.wbg.__wbg_new_f346c2f0d1ef8376 (http://127.0.0.1:41349/wasm-bindgen-test:1773:66)
        at wgpu_examples-a17d3159d541b1d4.wasm.__wbg_new_f346c2f0d1ef8376 externref shim (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[55624]:0x1073f48)
        at wgpu_examples-a17d3159d541b1d4.wasm.wasm_bindgen_test::__rt::Context::new::panic_handling::Error::new::hf74adf7e0df59c0e (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[33682]:0xf2bc30)
        at wgpu_examples-a17d3159d541b1d4.wasm.wasm_bindgen_test::__rt::Context::new::panic_handling::h2b93081e962d06e3 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[11193]:0xb7d91f)
        at wgpu_examples-a17d3159d541b1d4.wasm.wasm_bindgen_test::__rt::Context::new::{{closure}}::{{closure}}::hfdb32d2f4b85e1d4 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[31010]:0xeec89e)
        at wgpu_examples-a17d3159d541b1d4.wasm.std::panicking::rust_panic_with_hook::hc276d0501ad5b954 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[17093]:0xcf4680)
        at wgpu_examples-a17d3159d541b1d4.wasm.std::panicking::begin_panic_handler::{{closure}}::h23ff416a921468b4 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[22541]:0xdeb832)
        at wgpu_examples-a17d3159d541b1d4.wasm.std::sys::backtrace::__rust_end_short_backtrace::h16ab72765b32282d (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[56647]:0x1077648)
    
    
    panicked at wgpu-core/src/device/resource.rs:1495:59:
    thread '<unnamed>' attempted to acquire a snatch lock recursively.
    - Currently trying to acquire a read lock at wgpu-core/src/device/resource.rs:1495:59
    disabled backtrace
    - Previously acquired a read lock at wgpu-core/src/device/resource.rs:2958:49
    disabled backtrace
    
    Stack:
    
    Error
        at http://127.0.0.1:41349/wasm-bindgen-test:1774:21
        at logError (http://127.0.0.1:41349/wasm-bindgen-test:15:18)
        at imports.wbg.__wbg_new_f346c2f0d1ef8376 (http://127.0.0.1:41349/wasm-bindgen-test:1773:66)
        at wgpu_examples-a17d3159d541b1d4.wasm.__wbg_new_f346c2f0d1ef8376 externref shim (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[55624]:0x1073f48)
        at wgpu_examples-a17d3159d541b1d4.wasm.wasm_bindgen_test::__rt::Context::new::panic_handling::Error::new::hf74adf7e0df59c0e (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[33682]:0xf2bc30)
        at wgpu_examples-a17d3159d541b1d4.wasm.wasm_bindgen_test::__rt::Context::new::panic_handling::h2b93081e962d06e3 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[11193]:0xb7d91f)
        at wgpu_examples-a17d3159d541b1d4.wasm.wasm_bindgen_test::__rt::Context::new::{{closure}}::{{closure}}::hfdb32d2f4b85e1d4 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[31010]:0xeec89e)
        at wgpu_examples-a17d3159d541b1d4.wasm.std::panicking::rust_panic_with_hook::hc276d0501ad5b954 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[17093]:0xcf4680)
        at wgpu_examples-a17d3159d541b1d4.wasm.std::panicking::begin_panic_handler::{{closure}}::h23ff416a921468b4 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[22541]:0xdeb803)
        at wgpu_examples-a17d3159d541b1d4.wasm.std::sys::backtrace::__rust_end_short_backtrace::h16ab72765b32282d (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[56647]:0x1077648)
    
    
    panicked at wgpu-hal/src/gles/device.rs:1264:44:
    called `Option::unwrap()` on a `None` value
    
    Stack:
    
    Error
        at http://127.0.0.1:41349/wasm-bindgen-test:1774:21
        at logError (http://127.0.0.1:41349/wasm-bindgen-test:15:18)
        at imports.wbg.__wbg_new_f346c2f0d1ef8376 (http://127.0.0.1:41349/wasm-bindgen-test:1773:66)
        at wgpu_examples-a17d3159d541b1d4.wasm.__wbg_new_f346c2f0d1ef8376 externref shim (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[55624]:0x1073f48)
        at wgpu_examples-a17d3159d541b1d4.wasm.wasm_bindgen_test::__rt::Context::new::panic_handling::Error::new::hf74adf7e0df59c0e (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[33682]:0xf2bc30)
        at wgpu_examples-a17d3159d541b1d4.wasm.wasm_bindgen_test::__rt::Context::new::panic_handling::h2b93081e962d06e3 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[11193]:0xb7d91f)
        at wgpu_examples-a17d3159d541b1d4.wasm.wasm_bindgen_test::__rt::Context::new::{{closure}}::{{closure}}::hfdb32d2f4b85e1d4 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[31010]:0xeec89e)
        at wgpu_examples-a17d3159d541b1d4.wasm.std::panicking::rust_panic_with_hook::hc276d0501ad5b954 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[17093]:0xcf4680)
        at wgpu_examples-a17d3159d541b1d4.wasm.std::panicking::begin_panic_handler::{{closure}}::h23ff416a921468b4 (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[22541]:0xdeb832)
        at wgpu_examples-a17d3159d541b1d4.wasm.std::sys::backtrace::__rust_end_short_backtrace::h16ab72765b32282d (http://127.0.0.1:41349/wasm-bindgen-test_bg.wasm:wasm-function[56647]:0x1077648)

[2025-10-27T19:18:32Z DEBUG ureq::response] Body entirely buffered (length: 70)
[2025-10-27T19:18:32Z DEBUG ureq::pool] adding stream to pool: http|127.0.0.1|43809 -> Stream(TcpStream { addr: 127.0.0.1:52486, peer: 127.0.0.1:43809, fd: 4 })
[2025-10-27T19:18:32Z DEBUG ureq::unit] response 200 to DELETE http://127.0.0.1:43809/session/2a28b0a47c449b44d9c0ba6084ab26e6/window
[2025-10-27T19:18:32Z DEBUG wasm_bindgen_test_runner::headless] got: {"sessionId":"2a28b0a47c449b44d9c0ba6084ab26e6","status":0,"value":[]}
[2025-10-27T19:18:32Z DEBUG ureq::stream] dropping stream: Stream(TcpStream { addr: 127.0.0.1:52486, peer: 127.0.0.1:43809, fd: 4 })
Error: some tests failed

I guess we'll see if they reproduce with 34a3316, which should be the same repository state.

EDIT: It does. Ugh. 😩

… flags

For cases where a buffer is `mapped_at_creation`, our current
implementation of `Buffer::create` initializes the buffer's internal
state with `BufferMapState::Init` (which contains a staging buffer
underneath the hood) for a descriptor requesting `MAP_READ` that is
copied to a host-backed buffer . `MAP_WRITE` works a little differently,
starting from the beginning with a host-backed buffer.

`Init` does a buffer copy between the staging buffer and the host-backed
buffer in the device's queue when the buffer is `unmap`ped. However,
`Buffer::map_async` (correctly) assumes that a host-backed buffer need
not wait for anything in the queue. This results in a bug where
`map_async` doesn't actually wait long enough for the device queue to
complete its operations before resolving. Oops!

Up to the point where a buffer is unmapped after being mapped at
creation, `MAP_READ`, `MAP_WRITE`, and even _non_-`MAP_*` buffers'
capabilities are the same. That is, we should be able to get mutable
slices for mapped ranges, no matter what. So, make `MAP_READ` just
initialize its internal state in the same way as with `MAP_WRITE`.
@ErichDonGubler ErichDonGubler force-pushed the erichdongubler-push-dazed-adept-horse branch from 34a3316 to 684859e Compare October 28, 2025 15:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Read-mapped buffer content incorrect unless a submission happens between write and read

2 participants