Skip to content

Commit 3d7d45c

Browse files
committed
[mtl] improved semaphore synchronization
1 parent 1cedfc2 commit 3d7d45c

File tree

5 files changed

+220
-52
lines changed

5 files changed

+220
-52
lines changed

src/backend/metal/src/command.rs

+30-10
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,22 @@ impl CommandQueue {
11971197
shared,
11981198
}
11991199
}
1200+
1201+
fn wait<I>(&mut self, wait_semaphores: I)
1202+
where
1203+
I: IntoIterator,
1204+
I::Item: Borrow<native::Semaphore>,
1205+
{
1206+
for semaphore in wait_semaphores {
1207+
let sem = semaphore.borrow();
1208+
if let Some(ref system) = sem.system {
1209+
system.wait(!0);
1210+
}
1211+
if let Some(swap_image) = sem.image_ready.lock().unwrap().take() {
1212+
swap_image.wait_until_ready();
1213+
}
1214+
}
1215+
}
12001216
}
12011217

12021218
impl RawCommandQueue<Backend> for CommandQueue {
@@ -1208,17 +1224,20 @@ impl RawCommandQueue<Backend> for CommandQueue {
12081224
IC::Item: Borrow<CommandBuffer>,
12091225
{
12101226
debug!("submitting with fence {:?}", fence);
1211-
// FIXME: wait for semaphores!
12121227

1213-
// FIXME: multiple buffers signaling!
1214-
let signal_block = if !submit.signal_semaphores.is_empty() {
1215-
let semaphores_copy: Vec<_> = submit.signal_semaphores.iter().map(|semaphore| {
1216-
semaphore.0
1217-
}).collect();
1228+
self.wait(submit.wait_semaphores.iter().map(|&(s, _)| s));
1229+
1230+
let system_semaphores = submit.signal_semaphores
1231+
.into_iter()
1232+
.filter_map(|semaphore| {
1233+
semaphore.system.clone()
1234+
})
1235+
.collect::<Vec<_>>();
1236+
let signal_block = if !system_semaphores.is_empty() {
12181237
//Note: careful with those `ConcreteBlock::copy()` calls!
12191238
Some(ConcreteBlock::new(move |_cb: *mut ()| -> () {
1220-
for semaphore in semaphores_copy.iter() {
1221-
native::dispatch_semaphore_signal(*semaphore);
1239+
for semaphore in &system_semaphores {
1240+
semaphore.signal();
12221241
}
12231242
}).copy())
12241243
} else {
@@ -1283,18 +1302,19 @@ impl RawCommandQueue<Backend> for CommandQueue {
12831302
}
12841303
}
12851304

1286-
fn present<IS, S, IW>(&mut self, swapchains: IS, _wait_semaphores: IW) -> Result<(), ()>
1305+
fn present<IS, S, IW>(&mut self, swapchains: IS, wait_semaphores: IW) -> Result<(), ()>
12871306
where
12881307
IS: IntoIterator<Item = (S, SwapImageIndex)>,
12891308
S: Borrow<window::Swapchain>,
12901309
IW: IntoIterator,
12911310
IW::Item: Borrow<native::Semaphore>,
12921311
{
1312+
self.wait(wait_semaphores);
1313+
12931314
let queue = self.shared.queue.lock().unwrap();
12941315
let command_buffer = queue.raw.new_command_buffer();
12951316

12961317
for (swapchain, index) in swapchains {
1297-
// TODO: wait for semaphores
12981318
debug!("presenting frame {}", index);
12991319
let drawable = swapchain.borrow().take_drawable(index);
13001320
command_buffer.present_drawable(&drawable);

src/backend/metal/src/device.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ impl PhysicalDevice {
264264
let private_caps = {
265265
let device = &*shared.device.lock().unwrap();
266266
PrivateCapabilities {
267+
exposed_queues: 1,
267268
resource_heaps: Self::supports_any(device, RESOURCE_HEAP_SUPPORT),
268269
argument_buffers: Self::supports_any(device, ARGUMENT_BUFFER_SUPPORT) && false, //TODO
269270
shared_textures: !Self::is_mac(device),
@@ -328,7 +329,9 @@ impl hal::PhysicalDevice<Backend> for PhysicalDevice {
328329
}
329330

330331
let mut queue_group = hal::backend::RawQueueGroup::new(family);
331-
queue_group.add_queue(command::CommandQueue::new(self.shared.clone()));
332+
for _ in 0 .. self.private_caps.exposed_queues {
333+
queue_group.add_queue(command::CommandQueue::new(self.shared.clone()));
334+
}
332335

333336
let device = Device {
334337
shared: self.shared.clone(),
@@ -1325,7 +1328,16 @@ impl hal::Device<Backend> for Device {
13251328
}
13261329

13271330
fn create_semaphore(&self) -> n::Semaphore {
1328-
unsafe { n::Semaphore(n::dispatch_semaphore_create(1)) } // Returns retained
1331+
n::Semaphore {
1332+
// Semaphore synchronization between command buffers of the same queue
1333+
// is useless, don't bother even creating one.
1334+
system: if self.private_caps.exposed_queues > 1 {
1335+
Some(n::SystemSemaphore::new())
1336+
} else {
1337+
None
1338+
},
1339+
image_ready: Arc::new(Mutex::new(None)),
1340+
}
13291341
}
13301342

13311343
fn create_descriptor_pool<I>(&self, _max_sets: usize, descriptor_ranges: I) -> n::DescriptorPool
@@ -1524,8 +1536,7 @@ impl hal::Device<Backend> for Device {
15241536
fn destroy_framebuffer(&self, _buffer: n::Framebuffer) {
15251537
}
15261538

1527-
fn destroy_semaphore(&self, semaphore: n::Semaphore) {
1528-
unsafe { n::dispatch_release(semaphore.0) }
1539+
fn destroy_semaphore(&self, _semaphore: n::Semaphore) {
15291540
}
15301541

15311542
fn allocate_memory(&self, memory_type: hal::MemoryTypeId, size: u64) -> Result<n::Memory, OutOfMemory> {

src/backend/metal/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ impl hal::Backend for Backend {
198198

199199
#[derive(Clone, Copy, Debug)]
200200
struct PrivateCapabilities {
201+
exposed_queues: usize,
201202
resource_heaps: bool,
202203
argument_buffers: bool,
203204
shared_textures: bool,

src/backend/metal/src/native.rs

+39-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use Backend;
22
use internal::Channel;
3+
use window::SwapchainImage;
34

45
use std::collections::HashMap;
56
use std::ops::Range;
@@ -210,10 +211,10 @@ unsafe impl Send for Sampler {}
210211
unsafe impl Sync for Sampler {}
211212

212213
#[derive(Debug)]
213-
pub struct Semaphore(pub(crate) *mut c_void);
214-
215-
unsafe impl Send for Semaphore {}
216-
unsafe impl Sync for Semaphore {}
214+
pub struct Semaphore {
215+
pub(crate) system: Option<SystemSemaphore>,
216+
pub(crate) image_ready: Arc<Mutex<Option<SwapchainImage>>>,
217+
}
217218

218219
#[derive(Debug)]
219220
pub struct Buffer {
@@ -481,21 +482,50 @@ pub struct FenceInner {
481482
pub type Fence = Arc<FenceInner>;
482483

483484
extern "C" {
484-
#[allow(dead_code)]
485-
pub fn dispatch_semaphore_wait(
485+
fn dispatch_semaphore_wait(
486486
semaphore: *mut c_void,
487487
timeout: u64,
488488
) -> c_long;
489489

490-
pub fn dispatch_semaphore_signal(
490+
fn dispatch_semaphore_signal(
491491
semaphore: *mut c_void,
492492
) -> c_long;
493493

494-
pub fn dispatch_semaphore_create(
494+
fn dispatch_semaphore_create(
495495
value: c_long,
496496
) -> *mut c_void;
497497

498-
pub fn dispatch_release(
498+
fn dispatch_release(
499499
object: *mut c_void,
500500
);
501501
}
502+
503+
#[derive(Clone, Debug)]
504+
pub struct SystemSemaphore(*mut c_void);
505+
unsafe impl Send for SystemSemaphore {}
506+
unsafe impl Sync for SystemSemaphore {}
507+
508+
impl Drop for SystemSemaphore {
509+
fn drop(&mut self) {
510+
unsafe {
511+
dispatch_release(self.0)
512+
}
513+
}
514+
}
515+
impl SystemSemaphore {
516+
pub(crate) fn new() -> Self {
517+
SystemSemaphore(unsafe {
518+
dispatch_semaphore_create(1)
519+
})
520+
}
521+
pub(crate) fn signal(&self) {
522+
unsafe {
523+
dispatch_semaphore_signal(self.0);
524+
}
525+
}
526+
pub(crate) fn wait(&self, timeout: u64) {
527+
unsafe {
528+
dispatch_semaphore_wait(self.0, timeout);
529+
}
530+
}
531+
}

0 commit comments

Comments
 (0)