Skip to main content

metal/
sync.rs

1// Copyright 2016 GFX developers
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use std::ffi::CStr;
9
10use super::*;
11use block::{Block, RcBlock};
12
13#[cfg(feature = "dispatch")]
14use dispatch;
15
16/// See <https://developer.apple.com/documentation/metal/mtlsharedeventnotificationblock>
17type MTLSharedEventNotificationBlock<'a> = RcBlock<(&'a SharedEventRef, u64), ()>;
18
19/// See <https://developer.apple.com/documentation/metal/mtlevent>
20pub enum MTLEvent {}
21
22foreign_obj_type! {
23    type CType = MTLEvent;
24    pub struct Event;
25}
26
27impl EventRef {
28    pub fn device(&self) -> &DeviceRef {
29        unsafe { msg_send![self, device] }
30    }
31}
32
33/// See <https://developer.apple.com/documentation/metal/mtlsharedevent>
34pub enum MTLSharedEvent {}
35
36foreign_obj_type! {
37    type CType = MTLSharedEvent;
38    pub struct SharedEvent;
39    type ParentType = Event;
40}
41
42impl SharedEventRef {
43    pub fn signaled_value(&self) -> u64 {
44        unsafe { msg_send![self, signaledValue] }
45    }
46
47    pub fn set_signaled_value(&self, new_value: u64) {
48        unsafe { msg_send![self, setSignaledValue: new_value] }
49    }
50
51    /// Schedules a notification handler to be called after the shareable event’s signal value
52    /// equals or exceeds a given value.
53    pub fn notify(
54        &self,
55        listener: &SharedEventListenerRef,
56        value: u64,
57        block: MTLSharedEventNotificationBlock,
58    ) {
59        unsafe {
60            // If the block doesn't have a signature, this segfaults.
61            // Taken from https://github.com/servo/pathfinder/blob/e858c8dc1d8ff02a5b603e21e09a64d6b3e11327/metal/src/lib.rs#L2327
62            let block = mem::transmute::<
63                MTLSharedEventNotificationBlock,
64                *mut BlockBase<(&SharedEventRef, u64), ()>,
65            >(block);
66            (*block).flags |= BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE;
67            (*block).extra = &raw const BLOCK_EXTRA;
68            let () = msg_send![self, notifyListener:listener atValue:value block:block];
69        }
70
71        extern "C" fn dtor(_: *mut BlockBase<(&SharedEventRef, u64), ()>) {}
72
73        const SIGNATURE: &CStr = c"v16@?0Q8";
74        const SIGNATURE_PTR: *const i8 = SIGNATURE.as_ptr().cast();
75        static mut BLOCK_EXTRA: BlockExtra<(&SharedEventRef, u64), ()> = BlockExtra {
76            unknown0: std::ptr::null_mut(),
77            unknown1: std::ptr::null_mut(),
78            unknown2: std::ptr::null_mut(),
79            dtor,
80            signature: &SIGNATURE_PTR,
81        };
82    }
83}
84
85/// See <https://developer.apple.com/documentation/metal/mtlsharedeventlistener>
86pub enum MTLSharedEventListener {}
87
88foreign_obj_type! {
89    type CType = MTLSharedEventListener;
90    pub struct SharedEventListener;
91}
92
93impl SharedEventListener {
94    pub unsafe fn from_queue_handle(queue: dispatch_queue_t) -> Self {
95        let listener: SharedEventListener = msg_send![class!(MTLSharedEventListener), alloc];
96        let ptr: *mut Object = msg_send![listener.as_ref(), initWithDispatchQueue: queue];
97        if ptr.is_null() {
98            panic!("[MTLSharedEventListener alloc] initWithDispatchQueue failed");
99        }
100        listener
101    }
102
103    #[cfg(feature = "dispatch")]
104    pub fn from_queue(queue: &dispatch::Queue) -> Self {
105        unsafe {
106            let raw_queue = std::mem::transmute::<&dispatch::Queue, *const dispatch_queue_t>(queue);
107            Self::from_queue_handle(*raw_queue)
108        }
109    }
110}
111
112/// See <https://developer.apple.com/documentation/metal/mtlfence>
113pub enum MTLFence {}
114
115foreign_obj_type! {
116    type CType = MTLFence;
117    pub struct Fence;
118}
119
120impl FenceRef {
121    pub fn device(&self) -> &DeviceRef {
122        unsafe { msg_send![self, device] }
123    }
124
125    pub fn label(&self) -> &str {
126        unsafe {
127            let label = msg_send![self, label];
128            crate::nsstring_as_str(label)
129        }
130    }
131
132    pub fn set_label(&self, label: &str) {
133        unsafe {
134            let nslabel = crate::nsstring_from_str(label);
135            let () = msg_send![self, setLabel: nslabel];
136        }
137    }
138}
139
140bitflags::bitflags! {
141    /// The render stages at which a synchronization command is triggered.
142    ///
143    /// Render stages provide finer control for specifying when synchronization must occur,
144    /// allowing for vertex and fragment processing to overlap in execution.
145    ///
146    /// See <https://developer.apple.com/documentation/metal/mtlrenderstages>
147    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
148    pub struct MTLRenderStages: NSUInteger {
149        /// The vertex rendering stage.
150        const Vertex = 1 << 0;
151        /// The fragment rendering stage.
152        const Fragment = 1 << 1;
153        /// The tile rendering stage.
154        const Tile = 1 << 2;
155    }
156}
157
158const BLOCK_HAS_COPY_DISPOSE: i32 = 0x02000000;
159const BLOCK_HAS_SIGNATURE: i32 = 0x40000000;
160
161#[repr(C)]
162struct BlockBase<A, R> {
163    isa: *const std::ffi::c_void,                             // 0x00
164    flags: i32,                                               // 0x08
165    _reserved: i32,                                           // 0x0c
166    invoke: unsafe extern "C" fn(*mut Block<A, R>, ...) -> R, // 0x10
167    extra: *const BlockExtra<A, R>,                           // 0x18
168}
169
170type BlockExtraDtor<A, R> = extern "C" fn(*mut BlockBase<A, R>);
171
172#[repr(C)]
173struct BlockExtra<A, R> {
174    unknown0: *mut i32,          // 0x00
175    unknown1: *mut i32,          // 0x08
176    unknown2: *mut i32,          // 0x10
177    dtor: BlockExtraDtor<A, R>,  // 0x18
178    signature: *const *const i8, // 0x20
179}