Skip to content

Commit 8de0506

Browse files
committed
[mtl] improved semaphore synchronization
1 parent b312258 commit 8de0506

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
@@ -1211,6 +1211,22 @@ impl CommandQueue {
12111211
shared,
12121212
}
12131213
}
1214+
1215+
fn wait<I>(&mut self, wait_semaphores: I)
1216+
where
1217+
I: IntoIterator,
1218+
I::Item: Borrow<native::Semaphore>,
1219+
{
1220+
for semaphore in wait_semaphores {
1221+
let sem = semaphore.borrow();
1222+
if let Some(ref system) = sem.system {
1223+
system.wait(!0);
1224+
}
1225+
if let Some(swap_image) = sem.image_ready.lock().unwrap().take() {
1226+
swap_image.wait_until_ready();
1227+
}
1228+
}
1229+
}
12141230
}
12151231

12161232
impl RawCommandQueue<Backend> for CommandQueue {
@@ -1222,17 +1238,20 @@ impl RawCommandQueue<Backend> for CommandQueue {
12221238
IC::Item: Borrow<CommandBuffer>,
12231239
{
12241240
debug!("submitting with fence {:?}", fence);
1225-
// FIXME: wait for semaphores!
12261241

1227-
// FIXME: multiple buffers signaling!
1228-
let signal_block = if !submit.signal_semaphores.is_empty() {
1229-
let semaphores_copy: Vec<_> = submit.signal_semaphores.iter().map(|semaphore| {
1230-
semaphore.0
1231-
}).collect();
1242+
self.wait(submit.wait_semaphores.iter().map(|&(s, _)| s));
1243+
1244+
let system_semaphores = submit.signal_semaphores
1245+
.into_iter()
1246+
.filter_map(|semaphore| {
1247+
semaphore.system.clone()
1248+
})
1249+
.collect::<Vec<_>>();
1250+
let signal_block = if !system_semaphores.is_empty() {
12321251
//Note: careful with those `ConcreteBlock::copy()` calls!
12331252
Some(ConcreteBlock::new(move |_cb: *mut ()| -> () {
1234-
for semaphore in semaphores_copy.iter() {
1235-
native::dispatch_semaphore_signal(*semaphore);
1253+
for semaphore in &system_semaphores {
1254+
semaphore.signal();
12361255
}
12371256
}).copy())
12381257
} else {
@@ -1297,18 +1316,19 @@ impl RawCommandQueue<Backend> for CommandQueue {
12971316
}
12981317
}
12991318

1300-
fn present<IS, S, IW>(&mut self, swapchains: IS, _wait_semaphores: IW) -> Result<(), ()>
1319+
fn present<IS, S, IW>(&mut self, swapchains: IS, wait_semaphores: IW) -> Result<(), ()>
13011320
where
13021321
IS: IntoIterator<Item = (S, SwapImageIndex)>,
13031322
S: Borrow<window::Swapchain>,
13041323
IW: IntoIterator,
13051324
IW::Item: Borrow<native::Semaphore>,
13061325
{
1326+
self.wait(wait_semaphores);
1327+
13071328
let queue = self.shared.queue.lock().unwrap();
13081329
let command_buffer = queue.raw.new_command_buffer();
13091330

13101331
for (swapchain, index) in swapchains {
1311-
// TODO: wait for semaphores
13121332
debug!("presenting frame {}", index);
13131333
let drawable = swapchain.borrow().take_drawable(index);
13141334
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)