Skip to content

Conversation

@ryankaplan
Copy link
Contributor

@ryankaplan ryankaplan commented Oct 14, 2025

Connections

N/A

Description

Mapping sub-ranges of buffers on web is currently broken and fails with OperationError: GPUBuffer.getMappedRange: GetMappedRange range extends beyond buffer's mapped range. I have code like the code below in my app that reliably fails on 27.0.1 but not on 26.0.1. It works again after this PR.

let for_closure = my_buffer.clone();

my_buffer.slice(..amount_to_read_back).map_async(wgpu::MapMode::Read, move |res| {
  if res.is_err() {
    panic!("Failed to map buffer");
  }

  // This fails with the above error
  let data = for_closure.slice(..amount_to_read_back).get_mapped_range();
});

When you call create_buffer(..) on web, we create a WebBuffer under the hood. This contains a reference to the underlying GPUBuffer and a WebBufferMapState which is stores the last range passed to map_async(..).

The bug: this range is stored in a RefCell<..> and not in an Rc<RefCell<..>>. So if you clone the buffer and call map_async(..) on one of the clones, the others will have an out-of-date mapped range.

On web, this potentially stale range is used any time someone calls get_mapped_range(..). That because on web when you call buffer.get_mapped_range(sub_range) we do not map sub_range! We map the range used for map_async(..) and then use sub_range to get a slice of the appropriate size.

This is a pretty common case because the typical way to call get_mapped_range(..) is inside a callback passed to .map_async(..), which requires cloning the buffer.

So this PR wraps WebBufferMapState in an Rc<>, and fixes a validation check that seemed off.

Testing

I didn't add new tests, but my app no longer fails with OperationError: GPUBuffer.getMappedRange: GetMappedRange range extends beyond buffer's mapped range.

Squash or Rebase?

Squash

Checklist

  • Run cargo fmt.
  • Run taplo format.
  • Run cargo clippy --tests. If applicable, add:
    • --target wasm32-unknown-unknown
  • Run cargo xtask test to run tests <-- can't find a way to get this to run locally
  • If this contains user-facing changes, add a CHANGELOG.md entry.

panic!("tried to call get_mapped_range(_mut) on an unmapped buffer");
}
if !range_overlaps(&self.mapped_range, &new_sub.index) {
if !range_contains(&self.mapped_range, &new_sub.index) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is unrelated but seemed wrong

Copy link
Member

Choose a reason for hiding this comment

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

Hmm yeah, weird. I wonder why the tests were passing.

@cwfitzgerald cwfitzgerald self-assigned this Oct 14, 2025
Copy link
Member

@cwfitzgerald cwfitzgerald left a comment

Choose a reason for hiding this comment

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

Thanks!

panic!("tried to call get_mapped_range(_mut) on an unmapped buffer");
}
if !range_overlaps(&self.mapped_range, &new_sub.index) {
if !range_contains(&self.mapped_range, &new_sub.index) {
Copy link
Member

Choose a reason for hiding this comment

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

Hmm yeah, weird. I wonder why the tests were passing.

@cwfitzgerald cwfitzgerald merged commit 756dd3c into gfx-rs:trunk Oct 16, 2025
41 checks passed
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.

2 participants