Skip to content

Commit bf25b89

Browse files
fix(core): use BufferMapState::Active for any BufferUsages::MAP_* 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` and `MAP_WRITE` 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`.
1 parent c3b4672 commit bf25b89

File tree

6 files changed

+37
-11
lines changed

6 files changed

+37
-11
lines changed

cts_runner/test.lst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// ```
55
unittests:*
66
webgpu:api,operation,buffers,createBindGroup:buffer_binding_resource:*
7-
fails-if(vulkan,dx12,metal) webgpu:api,operation,buffers,map:mapAsync,read:*
7+
webgpu:api,operation,buffers,map:mapAsync,read:*
88
webgpu:api,operation,command_buffer,basic:*
99
webgpu:api,operation,command_buffer,copyBufferToBuffer:*
1010
fails-if(vulkan) webgpu:api,operation,command_buffer,copyTextureToTexture:copy_depth_stencil:format="depth24plus"

tests/tests/wgpu-gpu/cloneable_types.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ fn cloneable_buffers(ctx: TestingContext) {
2828

2929
buffer.unmap();
3030

31-
// This is actually a bug, we should not need to call submit to make the buffer contents visible.
32-
ctx.queue.submit([]);
33-
3431
let cloned_buffer = buffer.clone();
3532
let cloned_buffer_contents = buffer_contents.clone();
3633

wgpu-core/src/conv.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,16 @@ pub fn is_valid_external_image_copy_dst_texture_format(format: wgt::TextureForma
2626
}
2727
}
2828

29-
pub fn map_buffer_usage(usage: wgt::BufferUsages) -> wgt::BufferUses {
29+
pub fn map_buffer_usage(usage: wgt::BufferUsages, mapped_at_creation: bool) -> wgt::BufferUses {
3030
let mut u = wgt::BufferUses::empty();
3131
u.set(
3232
wgt::BufferUses::MAP_READ,
3333
usage.contains(wgt::BufferUsages::MAP_READ),
3434
);
3535
u.set(
3636
wgt::BufferUses::MAP_WRITE,
37-
usage.contains(wgt::BufferUsages::MAP_WRITE),
37+
usage.contains(wgt::BufferUsages::MAP_WRITE)
38+
|| (usage.contains(wgt::BufferUsages::MAP_READ) && mapped_at_creation),
3839
);
3940
u.set(
4041
wgt::BufferUses::COPY_SRC,

wgpu-core/src/device/resource.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ impl Device {
900900
}
901901
}
902902

903-
let mut usage = conv::map_buffer_usage(desc.usage);
903+
let mut usage = conv::map_buffer_usage(desc.usage, desc.mapped_at_creation);
904904

905905
if desc.usage.contains(wgt::BufferUsages::INDIRECT) {
906906
self.require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
@@ -990,7 +990,10 @@ impl Device {
990990

991991
let buffer_use = if !desc.mapped_at_creation {
992992
wgt::BufferUses::empty()
993-
} else if desc.usage.contains(wgt::BufferUsages::MAP_WRITE) {
993+
} else if desc
994+
.usage
995+
.intersects(wgt::BufferUsages::MAP_WRITE | wgt::BufferUsages::MAP_READ)
996+
{
994997
// buffer is mappable, so we are just doing that at start
995998
let map_size = buffer.size;
996999
let mapping = if map_size == 0 {

wgpu-hal/src/gles/device.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,10 @@ impl crate::Device for super::Device {
528528

529529
let host_backed_bytes = || Arc::new(MaybeMutex::new(vec![0; desc.size as usize]));
530530

531-
if emulate_map && desc.usage.intersects(wgt::BufferUses::MAP_WRITE) {
531+
if emulate_map
532+
&& (desc.usage.intersects(wgt::BufferUses::MAP_WRITE)
533+
&& !desc.usage.intersects(wgt::BufferUses::MAP_READ))
534+
{
532535
return Ok(super::Buffer {
533536
backing: BufferBacking::Host {
534537
data: host_backed_bytes(),
@@ -626,6 +629,7 @@ impl crate::Device for super::Device {
626629
BufferBacking::GlCachedOnHost {
627630
cache: host_backed_bytes(),
628631
raw,
632+
writeable_while_mapped: desc.usage.contains(wgt::BufferUses::MAP_WRITE),
629633
}
630634
} else {
631635
BufferBacking::Gl { raw }
@@ -644,7 +648,12 @@ impl crate::Device for super::Device {
644648

645649
unsafe fn destroy_buffer(&self, buffer: super::Buffer) {
646650
match buffer.backing {
647-
BufferBacking::Gl { raw } | BufferBacking::GlCachedOnHost { raw, cache: _ } => {
651+
BufferBacking::Gl { raw }
652+
| BufferBacking::GlCachedOnHost {
653+
raw,
654+
cache: _,
655+
writeable_while_mapped: _,
656+
} => {
648657
let gl = &self.shared.context.lock();
649658
unsafe { gl.delete_buffer(raw) };
650659
}
@@ -683,7 +692,11 @@ impl crate::Device for super::Device {
683692
)
684693
}
685694
}
686-
&BufferBacking::GlCachedOnHost { raw, ref cache } => {
695+
&BufferBacking::GlCachedOnHost {
696+
raw,
697+
ref cache,
698+
writeable_while_mapped: _,
699+
} => {
687700
let gl = &self.shared.context.lock();
688701
unsafe { gl.bind_buffer(buffer.target, Some(raw)) };
689702
let mut guard = lock(cache);
@@ -706,6 +719,17 @@ impl crate::Device for super::Device {
706719
unsafe { gl.bind_buffer(buffer.target, None) };
707720
*lock(&buffer.offset_of_current_mapping) = 0;
708721
}
722+
&BufferBacking::GlCachedOnHost {
723+
raw,
724+
ref cache,
725+
writeable_while_mapped,
726+
} if writeable_while_mapped => {
727+
let gl = &self.shared.context.lock();
728+
let data = lock(cache);
729+
unsafe { gl.bind_buffer(buffer.target, Some(raw)) };
730+
unsafe { gl.buffer_sub_data_u8_slice(buffer.target, 0, &data) };
731+
unsafe { gl.bind_buffer(buffer.target, None) };
732+
}
709733
&BufferBacking::Host { .. } | &BufferBacking::GlCachedOnHost { .. } => {}
710734
}
711735
}

wgpu-hal/src/gles/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ enum BufferBacking {
369369
GlCachedOnHost {
370370
raw: glow::Buffer,
371371
cache: Arc<MaybeMutex<Vec<u8>>>,
372+
writeable_while_mapped: bool,
372373
},
373374
}
374375

0 commit comments

Comments
 (0)