Skip to content

Commit 2daba8f

Browse files
committed
Implement map read/write async
1 parent f5c5c1a commit 2daba8f

File tree

2 files changed

+159
-15
lines changed

2 files changed

+159
-15
lines changed

src/device.rs

Lines changed: 139 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::hub::HUB;
33
use crate::track::{TrackerSet, TrackPermit};
44
use crate::{
55
LifeGuard, RefCount, Stored, SubmissionIndex, WeaklyStored,
6+
BufferMapAsyncStatus, BufferMapOperation,
67
};
78
use crate::{
89
BufferId, CommandBufferId, AdapterId, DeviceId, QueueId,
@@ -11,7 +12,7 @@ use crate::{
1112
#[cfg(feature = "local")]
1213
use crate::{
1314
BindGroupId, BindGroupLayoutId, PipelineLayoutId, SamplerId, SwapChainId,
14-
ShaderModuleId, CommandEncoderId, RenderPipelineId, ComputePipelineId,
15+
ShaderModuleId, CommandEncoderId, RenderPipelineId, ComputePipelineId,
1516
};
1617

1718
use back;
@@ -83,9 +84,12 @@ struct ActiveSubmission<B: hal::Backend> {
8384
index: SubmissionIndex,
8485
fence: B::Fence,
8586
resources: Vec<Resource<B>>,
87+
mapped: Vec<BufferId>,
8688
}
8789

8890
struct DestroyedResources<B: hal::Backend> {
91+
/// Resources that the user has requested be mapped, but are still in use.
92+
mapped: Vec<Stored<BufferId>>,
8993
/// Resources that are destroyed by the user but still referenced by
9094
/// other objects or command buffers.
9195
referenced: Vec<(ResourceId, RefCount)>,
@@ -95,17 +99,22 @@ struct DestroyedResources<B: hal::Backend> {
9599
/// Resources that are neither referenced or used, just pending
96100
/// actual deletion.
97101
free: Vec<Resource<B>>,
102+
ready_to_map: Vec<BufferId>,
98103
}
99104

100105
unsafe impl<B: hal::Backend> Send for DestroyedResources<B> {}
101106
unsafe impl<B: hal::Backend> Sync for DestroyedResources<B> {}
102107

103108
impl<B: hal::Backend> DestroyedResources<B> {
104-
fn add(&mut self, resource_id: ResourceId, ref_count: RefCount) {
109+
fn destroy(&mut self, resource_id: ResourceId, ref_count: RefCount) {
105110
debug_assert!(!self.referenced.iter().any(|r| r.0 == resource_id));
106111
self.referenced.push((resource_id, ref_count));
107112
}
108113

114+
fn map(&mut self, buffer: BufferId, ref_count: RefCount) {
115+
self.mapped.push(Stored{value: buffer, ref_count});
116+
}
117+
109118
/// Returns the last submission index that is done.
110119
fn cleanup(&mut self, raw: &B::Device) -> SubmissionIndex {
111120
let mut last_done = 0;
@@ -185,9 +194,63 @@ impl DestroyedResources<back::Backend> {
185194
}
186195
}
187196
}
197+
198+
let buffer_guard = HUB.buffers.read();
199+
200+
for i in (0..self.mapped.len()).rev() {
201+
// one in resource itself, one here in this list, one the owner holds, and one more somewhere?
202+
let num_refs = self.mapped[i].ref_count.load();
203+
trace!("{} references remain", num_refs);
204+
if num_refs <= 4 {
205+
// assert_eq!(num_refs, 4);
206+
let resource_id = self.mapped.swap_remove(i).value;
207+
let buf = buffer_guard.get(resource_id);
208+
let submit_index = buf.life_guard.submission_index.load(Ordering::Acquire);
209+
match self
210+
.active
211+
.iter_mut()
212+
.find(|a| a.index == submit_index)
213+
{
214+
Some(a) => a.mapped.push(resource_id),
215+
None => self.ready_to_map.push(resource_id),
216+
}
217+
}
218+
}
188219
}
189-
}
190220

221+
fn handle_mapping(&mut self, raw: &<back::Backend as hal::Backend>::Device) {
222+
let mut buffer_guard = HUB.buffers.write();
223+
224+
for buffer_id in self.ready_to_map.drain(..) {
225+
let mut buffer = buffer_guard.get_mut(buffer_id);
226+
let mut operation = None;
227+
std::mem::swap(&mut operation, &mut buffer.pending_map_operation);
228+
match operation {
229+
Some(BufferMapOperation::Read(range, callback, userdata)) => {
230+
if let Ok(ptr) = unsafe { raw.map_memory(&buffer.memory, range.clone()) } {
231+
if !buffer.memory_properties.contains(hal::memory::Properties::COHERENT) {
232+
unsafe { raw.invalidate_mapped_memory_ranges(iter::once((&buffer.memory, range.clone()))).unwrap() }; // TODO
233+
}
234+
callback(BufferMapAsyncStatus::Success, ptr, userdata);
235+
} else {
236+
callback(BufferMapAsyncStatus::Error, std::ptr::null(), userdata);
237+
}
238+
},
239+
Some(BufferMapOperation::Write(range, callback, userdata)) => {
240+
if let Ok(ptr) = unsafe { raw.map_memory(&buffer.memory, range.clone()) } {
241+
if !buffer.memory_properties.contains(hal::memory::Properties::COHERENT) {
242+
buffer.mapped_write_ranges.push(range);
243+
}
244+
callback(BufferMapAsyncStatus::Success, ptr, userdata);
245+
} else {
246+
callback(BufferMapAsyncStatus::Error, std::ptr::null_mut(), userdata);
247+
}
248+
},
249+
_ => unreachable!(),
250+
};
251+
}
252+
}
253+
}
191254

192255
pub struct Device<B: hal::Backend> {
193256
pub(crate) raw: B::Device,
@@ -276,9 +339,11 @@ impl<B: hal::Backend> Device<B> {
276339
framebuffers: Mutex::new(FastHashMap::default()),
277340
desc_pool,
278341
destroyed: Mutex::new(DestroyedResources {
342+
mapped: Vec::new(),
279343
referenced: Vec::new(),
280344
active: Vec::new(),
281345
free: Vec::new(),
346+
ready_to_map: Vec::new(),
282347
}),
283348
}
284349
}
@@ -296,7 +361,7 @@ pub fn device_create_buffer(
296361
) -> resource::Buffer<back::Backend> {
297362
let device_guard = HUB.devices.read();
298363
let device = &device_guard.get(device_id);
299-
let (usage, _) = conv::map_buffer_usage(desc.usage);
364+
let (usage, memory_properties) = conv::map_buffer_usage(desc.usage);
300365

301366
let mut buffer = unsafe {
302367
device.raw.create_buffer(desc.size as u64, usage).unwrap()
@@ -310,11 +375,10 @@ pub fn device_create_buffer(
310375
.iter()
311376
.enumerate()
312377
.position(|(id, memory_type)| {
313-
// TODO
314378
requirements.type_mask & (1 << id) != 0
315379
&& memory_type
316380
.properties
317-
.contains(hal::memory::Properties::DEVICE_LOCAL)
381+
.contains(memory_properties)
318382
})
319383
.unwrap()
320384
.into();
@@ -336,6 +400,10 @@ pub fn device_create_buffer(
336400
value: device_id,
337401
ref_count: device.life_guard.ref_count.clone(),
338402
},
403+
memory_properties,
404+
memory,
405+
mapped_write_ranges: Vec::new(),
406+
pending_map_operation: None,
339407
life_guard: LifeGuard::new(),
340408
}
341409
}
@@ -377,13 +445,12 @@ pub extern "C" fn wgpu_buffer_destroy(buffer_id: BufferId) {
377445
.get(buffer.device_id.value)
378446
.destroyed
379447
.lock()
380-
.add(
448+
.destroy(
381449
ResourceId::Buffer(buffer_id),
382450
buffer.life_guard.ref_count.clone(),
383451
);
384452
}
385453

386-
387454
pub fn device_create_texture(
388455
device_id: DeviceId,
389456
desc: &resource::TextureDescriptor,
@@ -618,7 +685,7 @@ pub extern "C" fn wgpu_texture_destroy(texture_id: TextureId) {
618685
.get(texture.device_id.value)
619686
.destroyed
620687
.lock()
621-
.add(
688+
.destroy(
622689
ResourceId::Texture(texture_id),
623690
texture.life_guard.ref_count.clone(),
624691
);
@@ -637,7 +704,7 @@ pub extern "C" fn wgpu_texture_view_destroy(texture_view_id: TextureViewId) {
637704
.get(device_id)
638705
.destroyed
639706
.lock()
640-
.add(
707+
.destroy(
641708
ResourceId::TextureView(texture_view_id),
642709
view.life_guard.ref_count.clone(),
643710
);
@@ -1047,11 +1114,13 @@ pub extern "C" fn wgpu_queue_submit(
10471114
let mut destroyed = device.destroyed.lock();
10481115
destroyed.triage_referenced(&mut *trackers);
10491116
let last_done = destroyed.cleanup(&device.raw);
1117+
destroyed.handle_mapping(&device.raw);
10501118

10511119
destroyed.active.push(ActiveSubmission {
10521120
index: old_submit_index + 1,
10531121
fence,
10541122
resources: Vec::new(),
1123+
mapped: Vec::new(),
10551124
});
10561125

10571126
last_done
@@ -1386,8 +1455,8 @@ pub fn device_create_swap_chain(
13861455
let mut destroyed = device.destroyed.lock();
13871456
assert_eq!(old.device_id.value, device_id);
13881457
for frame in old.frames {
1389-
destroyed.add(ResourceId::Texture(frame.texture_id.value), frame.texture_id.ref_count);
1390-
destroyed.add(ResourceId::TextureView(frame.view_id.value), frame.view_id.ref_count);
1458+
destroyed.destroy(ResourceId::Texture(frame.texture_id.value), frame.texture_id.ref_count);
1459+
destroyed.destroy(ResourceId::TextureView(frame.view_id.value), frame.view_id.ref_count);
13911460
}
13921461
unsafe {
13931462
old.command_pool.reset()
@@ -1610,4 +1679,62 @@ pub extern "C" fn wgpu_buffer_set_sub_data(
16101679
#[no_mangle]
16111680
pub extern "C" fn wgpu_device_destroy(device_id: BufferId) {
16121681
HUB.devices.unregister(device_id);
1682+
}
1683+
1684+
pub type BufferMapReadCallback = extern "C" fn(status: BufferMapAsyncStatus, data: *const u8, userdata: *mut u8);
1685+
pub type BufferMapWriteCallback = extern "C" fn(status: BufferMapAsyncStatus, data: *mut u8, userdata: *mut u8);
1686+
1687+
#[no_mangle]
1688+
pub extern "C" fn wgpu_buffer_map_read_async(
1689+
buffer_id: BufferId,
1690+
start: u32, size: u32, callback: BufferMapReadCallback, userdata: *mut u8,
1691+
) {
1692+
let mut buffer_guard = HUB.buffers.write();
1693+
let buffer = buffer_guard.get_mut(buffer_id);
1694+
let device_guard = HUB.devices.read();
1695+
let device = device_guard.get(buffer.device_id.value);
1696+
1697+
let range = start as u64..(start + size) as u64;
1698+
buffer.pending_map_operation = Some(BufferMapOperation::Read(range, callback, userdata));
1699+
1700+
device
1701+
.destroyed
1702+
.lock()
1703+
.map(buffer_id, buffer.life_guard.ref_count.clone());
1704+
}
1705+
1706+
#[no_mangle]
1707+
pub extern "C" fn wgpu_buffer_map_write_async(
1708+
buffer_id: BufferId,
1709+
start: u32, size: u32, callback: BufferMapWriteCallback, userdata: *mut u8,
1710+
) {
1711+
let mut buffer_guard = HUB.buffers.write();
1712+
let buffer = buffer_guard.get_mut(buffer_id);
1713+
let device_guard = HUB.devices.read();
1714+
let device = device_guard.get(buffer.device_id.value);
1715+
1716+
let range = start as u64..(start + size) as u64;
1717+
buffer.pending_map_operation = Some(BufferMapOperation::Write(range, callback, userdata));
1718+
1719+
device
1720+
.destroyed
1721+
.lock()
1722+
.map(buffer_id, buffer.life_guard.ref_count.clone());
1723+
}
1724+
1725+
#[no_mangle]
1726+
pub extern "C" fn wgpu_buffer_unmap(
1727+
buffer_id: BufferId,
1728+
) {
1729+
let mut buffer_guard = HUB.buffers.write();
1730+
let buffer = buffer_guard.get_mut(buffer_id);
1731+
let mut device_guard = HUB.devices.write();
1732+
let device = device_guard.get_mut(buffer.device_id.value);
1733+
1734+
if !buffer.mapped_write_ranges.is_empty() {
1735+
unsafe { device.raw.flush_mapped_memory_ranges( buffer.mapped_write_ranges.iter().map(|r| {(&buffer.memory, r.clone())}) ).unwrap() }; // TODO
1736+
buffer.mapped_write_ranges.clear();
1737+
}
1738+
1739+
unsafe { device.raw.unmap_memory(&buffer.memory) };
16131740
}

src/resource.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::{
22
Extent3d, LifeGuard, RefCount, Stored,
33
DeviceId, TextureId,
4+
BufferMapReadCallback, BufferMapWriteCallback,
45
};
56
use crate::swap_chain::{SwapChainLink, SwapImageEpoch};
67

@@ -10,7 +11,6 @@ use parking_lot::Mutex;
1011

1112
use std::borrow::Borrow;
1213

13-
1414
bitflags! {
1515
#[repr(transparent)]
1616
pub struct BufferUsageFlags: u32 {
@@ -33,12 +33,29 @@ pub struct BufferDescriptor {
3333
pub usage: BufferUsageFlags,
3434
}
3535

36+
pub enum BufferMapAsyncStatus {
37+
Success,
38+
Error,
39+
Unknown,
40+
ContextLost,
41+
}
42+
43+
pub(crate) enum BufferMapOperation {
44+
Read(std::ops::Range<u64>, BufferMapReadCallback, *mut u8),
45+
Write(std::ops::Range<u64>, BufferMapWriteCallback, *mut u8),
46+
}
47+
48+
unsafe impl Send for BufferMapOperation {}
49+
unsafe impl Sync for BufferMapOperation {}
50+
3651
pub struct Buffer<B: hal::Backend> {
3752
pub(crate) raw: B::Buffer,
3853
pub(crate) device_id: Stored<DeviceId>,
39-
//pub memory_properties: hal::memory::Properties,
54+
pub(crate) memory_properties: hal::memory::Properties,
55+
pub(crate) memory: B::Memory,
56+
pub(crate) mapped_write_ranges: Vec<std::ops::Range<u64>>,
57+
pub(crate) pending_map_operation: Option<BufferMapOperation>,
4058
pub(crate) life_guard: LifeGuard,
41-
// TODO: mapping, unmap()
4259
}
4360

4461
impl<B: hal::Backend> Borrow<RefCount> for Buffer<B> {

0 commit comments

Comments
 (0)