Skip to content

Commit cc4276e

Browse files
committed
Buffer tracking and unmapping
Adds preliminary transitioning of buffers to mapped state. Adds buffer unmapping to the cube sample. Modifies wgpu_queue_submit to not hold a write lock on the device during callbacks.
1 parent 27a694f commit cc4276e

File tree

2 files changed

+146
-127
lines changed

2 files changed

+146
-127
lines changed

src/device.rs

Lines changed: 145 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -213,20 +213,22 @@ impl DestroyedResources<back::Backend> {
213213
let buffer_guard = HUB.buffers.read();
214214

215215
for i in (0..self.mapped.len()).rev() {
216-
// one in resource itself, one here in this list, one the owner holds, and one more somewhere?
217-
let num_refs = self.mapped[i].ref_count.load();
218-
trace!("{} references remain", num_refs);
219-
if num_refs <= 4 {
220-
// assert_eq!(num_refs, 4);
221-
let resource_id = self.mapped.swap_remove(i).value;
222-
let buf = &buffer_guard[resource_id];
223-
let submit_index = buf.life_guard.submission_index.load(Ordering::Acquire);
224-
self.active
225-
.iter_mut()
226-
.find(|a| a.index == submit_index)
227-
.map_or(&mut self.ready_to_map, |a| &mut a.mapped)
228-
.push(resource_id);
229-
}
216+
let resource_id = self.mapped.swap_remove(i).value;
217+
let buf = &buffer_guard[resource_id];
218+
219+
let usage = match buf.pending_map_operation {
220+
Some(BufferMapOperation::Read(..)) => resource::BufferUsageFlags::MAP_READ,
221+
Some(BufferMapOperation::Write(..)) => resource::BufferUsageFlags::MAP_WRITE,
222+
_ => unreachable!(),
223+
};
224+
trackers.buffers.get_with_replaced_usage(&buffer_guard, resource_id, usage).unwrap();
225+
226+
let submit_index = buf.life_guard.submission_index.load(Ordering::Acquire);
227+
self.active
228+
.iter_mut()
229+
.find(|a| a.index == submit_index)
230+
.map_or(&mut self.ready_to_map, |a| &mut a.mapped)
231+
.push(resource_id);
230232
}
231233
}
232234

@@ -269,34 +271,39 @@ impl DestroyedResources<back::Backend> {
269271
}
270272

271273
fn handle_mapping(&mut self, raw: &<back::Backend as hal::Backend>::Device) {
272-
let mut buffer_guard = HUB.buffers.write();
273-
274274
for buffer_id in self.ready_to_map.drain(..) {
275-
let buffer = &mut buffer_guard[buffer_id];
276275
let mut operation = None;
277-
std::mem::swap(&mut operation, &mut buffer.pending_map_operation);
278-
match operation {
279-
Some(BufferMapOperation::Read(range, callback, userdata)) => {
280-
if let Ok(ptr) = unsafe { raw.map_memory(&buffer.memory, range.clone()) } {
281-
if !buffer.memory_properties.contains(hal::memory::Properties::COHERENT) {
282-
unsafe { raw.invalidate_mapped_memory_ranges(iter::once((&buffer.memory, range.clone()))).unwrap() }; // TODO
276+
let (result, ptr) = {
277+
let mut buffer_guard = HUB.buffers.write();
278+
let buffer = &mut buffer_guard[buffer_id];
279+
std::mem::swap(&mut operation, &mut buffer.pending_map_operation);
280+
match operation.clone().unwrap() {
281+
BufferMapOperation::Read(range, ..) => {
282+
if let Ok(ptr) = unsafe { raw.map_memory(&buffer.memory, range.clone()) } {
283+
if !buffer.memory_properties.contains(hal::memory::Properties::COHERENT) {
284+
unsafe { raw.invalidate_mapped_memory_ranges(iter::once((&buffer.memory, range.clone()))).unwrap() }; // TODO
285+
}
286+
(BufferMapAsyncStatus::Success, Some(ptr))
287+
} else {
288+
(BufferMapAsyncStatus::Error, None)
283289
}
284-
callback(BufferMapAsyncStatus::Success, ptr, userdata);
285-
} else {
286-
callback(BufferMapAsyncStatus::Error, std::ptr::null(), userdata);
287-
}
288-
},
289-
Some(BufferMapOperation::Write(range, callback, userdata)) => {
290-
if let Ok(ptr) = unsafe { raw.map_memory(&buffer.memory, range.clone()) } {
291-
if !buffer.memory_properties.contains(hal::memory::Properties::COHERENT) {
292-
buffer.mapped_write_ranges.push(range);
290+
},
291+
BufferMapOperation::Write(range, ..) => {
292+
if let Ok(ptr) = unsafe { raw.map_memory(&buffer.memory, range.clone()) } {
293+
if !buffer.memory_properties.contains(hal::memory::Properties::COHERENT) {
294+
buffer.mapped_write_ranges.push(range.clone());
295+
}
296+
(BufferMapAsyncStatus::Success, Some(ptr))
297+
} else {
298+
(BufferMapAsyncStatus::Error, None)
293299
}
294-
callback(BufferMapAsyncStatus::Success, ptr, userdata);
295-
} else {
296-
callback(BufferMapAsyncStatus::Error, std::ptr::null_mut(), userdata);
297-
}
298-
},
299-
_ => unreachable!(),
300+
},
301+
}
302+
};
303+
304+
match operation.unwrap() {
305+
BufferMapOperation::Read(_, callback, userdata) => callback(result, ptr.unwrap_or(std::ptr::null_mut()), userdata),
306+
BufferMapOperation::Write(_, callback, userdata) => callback(result, ptr.unwrap_or(std::ptr::null_mut()), userdata),
300307
};
301308
}
302309
}
@@ -1022,108 +1029,119 @@ pub extern "C" fn wgpu_queue_submit(
10221029
command_buffer_ptr: *const CommandBufferId,
10231030
command_buffer_count: usize,
10241031
) {
1025-
let mut device_guard = HUB.devices.write();
1026-
let device = &mut device_guard[queue_id];
1027-
1028-
let mut swap_chain_links = Vec::new();
10291032
let command_buffer_ids =
10301033
unsafe { slice::from_raw_parts(command_buffer_ptr, command_buffer_count) };
10311034

1032-
let old_submit_index = device
1033-
.life_guard
1034-
.submission_index
1035-
.fetch_add(1, Ordering::Relaxed);
1036-
let mut trackers = device.trackers.lock();
1037-
1038-
//TODO: if multiple command buffers are submitted, we can re-use the last
1039-
// native command buffer of the previous chain instead of always creating
1040-
// a temporary one, since the chains are not finished.
1041-
{
1042-
let mut command_buffer_guard = HUB.command_buffers.write();
1043-
let buffer_guard = HUB.buffers.read();
1044-
let texture_guard = HUB.textures.read();
1045-
let texture_view_guard = HUB.texture_views.read();
1046-
1047-
// finish all the command buffers first
1048-
for &cmb_id in command_buffer_ids {
1049-
let comb = &mut command_buffer_guard[cmb_id];
1050-
swap_chain_links.extend(comb.swap_chain_links.drain(..));
1051-
// update submission IDs
1052-
comb.life_guard.submission_index
1053-
.store(old_submit_index, Ordering::Release);
1054-
for id in comb.trackers.buffers.used() {
1055-
buffer_guard[id].life_guard.submission_index
1056-
.store(old_submit_index, Ordering::Release);
1057-
}
1058-
for id in comb.trackers.textures.used() {
1059-
texture_guard[id].life_guard.submission_index
1060-
.store(old_submit_index, Ordering::Release);
1061-
}
1062-
for id in comb.trackers.views.used() {
1063-
texture_view_guard[id].life_guard.submission_index
1035+
let (old_submit_index, fence) = {
1036+
let mut device_guard = HUB.devices.write();
1037+
let device = &mut device_guard[queue_id];
1038+
1039+
let mut swap_chain_links = Vec::new();
1040+
1041+
let old_submit_index = device
1042+
.life_guard
1043+
.submission_index
1044+
.fetch_add(1, Ordering::Relaxed);
1045+
let mut trackers = device.trackers.lock();
1046+
1047+
//TODO: if multiple command buffers are submitted, we can re-use the last
1048+
// native command buffer of the previous chain instead of always creating
1049+
// a temporary one, since the chains are not finished.
1050+
{
1051+
let mut command_buffer_guard = HUB.command_buffers.write();
1052+
let buffer_guard = HUB.buffers.read();
1053+
let texture_guard = HUB.textures.read();
1054+
let texture_view_guard = HUB.texture_views.read();
1055+
1056+
// finish all the command buffers first
1057+
for &cmb_id in command_buffer_ids {
1058+
let comb = &mut command_buffer_guard[cmb_id];
1059+
swap_chain_links.extend(comb.swap_chain_links.drain(..));
1060+
// update submission IDs
1061+
comb.life_guard.submission_index
10641062
.store(old_submit_index, Ordering::Release);
1065-
}
1063+
for id in comb.trackers.buffers.used() {
1064+
buffer_guard[id].life_guard.submission_index
1065+
.store(old_submit_index, Ordering::Release);
1066+
}
1067+
for id in comb.trackers.textures.used() {
1068+
texture_guard[id].life_guard.submission_index
1069+
.store(old_submit_index, Ordering::Release);
1070+
}
1071+
for id in comb.trackers.views.used() {
1072+
texture_view_guard[id].life_guard.submission_index
1073+
.store(old_submit_index, Ordering::Release);
1074+
}
10661075

1067-
// execute resource transitions
1068-
let mut transit = device.com_allocator.extend(comb);
1069-
unsafe {
1070-
transit.begin(
1071-
hal::command::CommandBufferFlags::ONE_TIME_SUBMIT,
1072-
hal::command::CommandBufferInheritanceInfo::default(),
1076+
// execute resource transitions
1077+
let mut transit = device.com_allocator.extend(comb);
1078+
unsafe {
1079+
transit.begin(
1080+
hal::command::CommandBufferFlags::ONE_TIME_SUBMIT,
1081+
hal::command::CommandBufferInheritanceInfo::default(),
1082+
);
1083+
}
1084+
command::CommandBuffer::insert_barriers(
1085+
&mut transit,
1086+
&mut *trackers,
1087+
&comb.trackers,
1088+
Stitch::Init,
1089+
&*buffer_guard,
1090+
&*texture_guard,
10731091
);
1092+
unsafe {
1093+
transit.finish();
1094+
}
1095+
comb.raw.insert(0, transit);
1096+
unsafe {
1097+
comb.raw.last_mut().unwrap().finish();
1098+
}
10741099
}
1075-
command::CommandBuffer::insert_barriers(
1076-
&mut transit,
1077-
&mut *trackers,
1078-
&comb.trackers,
1079-
Stitch::Init,
1080-
&*buffer_guard,
1081-
&*texture_guard,
1082-
);
1083-
unsafe {
1084-
transit.finish();
1085-
}
1086-
comb.raw.insert(0, transit);
1100+
}
1101+
1102+
// now prepare the GPU submission
1103+
let fence = device.raw.create_fence(false).unwrap();
1104+
{
1105+
let command_buffer_guard = HUB.command_buffers.read();
1106+
let surface_guard = HUB.surfaces.read();
1107+
1108+
let wait_semaphores = swap_chain_links
1109+
.into_iter()
1110+
.flat_map(|link| {
1111+
//TODO: check the epoch
1112+
surface_guard[link.swap_chain_id].swap_chain
1113+
.as_ref()
1114+
.map(|swap_chain| (
1115+
&swap_chain.frames[link.image_index as usize].sem_available,
1116+
hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT,
1117+
))
1118+
});
1119+
1120+
let submission =
1121+
hal::queue::Submission::<_, _, &[<back::Backend as hal::Backend>::Semaphore]> {
1122+
//TODO: may `OneShot` be enough?
1123+
command_buffers: command_buffer_ids
1124+
.iter()
1125+
.flat_map(|&cmb_id| &command_buffer_guard[cmb_id].raw),
1126+
wait_semaphores,
1127+
signal_semaphores: &[], //TODO: signal `sem_present`?
1128+
};
1129+
10871130
unsafe {
1088-
comb.raw.last_mut().unwrap().finish();
1131+
device.queue_group.queues[0]
1132+
.as_raw_mut()
1133+
.submit(submission, Some(&fence));
10891134
}
10901135
}
1091-
}
10921136

1093-
// now prepare the GPU submission
1094-
let fence = device.raw.create_fence(false).unwrap();
1095-
{
1096-
let command_buffer_guard = HUB.command_buffers.read();
1097-
let surface_guard = HUB.surfaces.read();
1098-
1099-
let wait_semaphores = swap_chain_links
1100-
.into_iter()
1101-
.flat_map(|link| {
1102-
//TODO: check the epoch
1103-
surface_guard[link.swap_chain_id].swap_chain
1104-
.as_ref()
1105-
.map(|swap_chain| (
1106-
&swap_chain.frames[link.image_index as usize].sem_available,
1107-
hal::pso::PipelineStage::COLOR_ATTACHMENT_OUTPUT,
1108-
))
1109-
});
1137+
(old_submit_index, fence)
1138+
};
11101139

1111-
let submission =
1112-
hal::queue::Submission::<_, _, &[<back::Backend as hal::Backend>::Semaphore]> {
1113-
//TODO: may `OneShot` be enough?
1114-
command_buffers: command_buffer_ids
1115-
.iter()
1116-
.flat_map(|&cmb_id| &command_buffer_guard[cmb_id].raw),
1117-
wait_semaphores,
1118-
signal_semaphores: &[], //TODO: signal `sem_present`?
1119-
};
1140+
// No need for write access to the device from here on out
1141+
let device_guard = HUB.devices.read();
1142+
let device = &device_guard[queue_id];
11201143

1121-
unsafe {
1122-
device.queue_group.queues[0]
1123-
.as_raw_mut()
1124-
.submit(submission, Some(&fence));
1125-
}
1126-
}
1144+
let mut trackers = device.trackers.lock();
11271145

11281146
let last_done = {
11291147
let mut destroyed = device.destroyed.lock();

src/resource.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub enum BufferMapAsyncStatus {
4040
ContextLost,
4141
}
4242

43+
#[derive(Clone)]
4344
pub(crate) enum BufferMapOperation {
4445
Read(std::ops::Range<u64>, BufferMapReadCallback, *mut u8),
4546
Write(std::ops::Range<u64>, BufferMapWriteCallback, *mut u8),

0 commit comments

Comments
 (0)