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 
8 use super::*;
9 use block::{Block, RcBlock};
10 use std::mem;
11 
12 #[cfg(feature = "dispatch_queue")]
13 use dispatch;
14 
15 type MTLSharedEventNotificationBlock<'a> = RcBlock<(&'a SharedEventRef, u64), ()>;
16 
17 pub enum MTLEvent {}
18 
19 foreign_obj_type! {
20     type CType = MTLEvent;
21     pub struct Event;
22     pub struct EventRef;
23 }
24 
25 impl EventRef {
device(&self) -> &DeviceRef26     pub fn device(&self) -> &DeviceRef {
27         unsafe { msg_send![self, device] }
28     }
29 }
30 
31 pub enum MTLSharedEvent {}
32 
33 foreign_obj_type! {
34     type CType = MTLSharedEvent;
35     pub struct SharedEvent;
36     pub struct SharedEventRef;
37     type ParentType = EventRef;
38 }
39 
40 impl SharedEventRef {
signaled_value(&self) -> u6441     pub fn signaled_value(&self) -> u64 {
42         unsafe { msg_send![self, signaledValue] }
43     }
44 
set_signaled_value(&self, new_value: u64)45     pub fn set_signaled_value(&self, new_value: u64) {
46         unsafe { msg_send![self, setSignaledValue: new_value] }
47     }
48 
49     /// Schedules a notification handler to be called after the shareable event’s signal value
50     /// equals or exceeds a given value.
notify( &self, listener: &SharedEventListenerRef, value: u64, block: MTLSharedEventNotificationBlock, )51     pub fn notify(
52         &self,
53         listener: &SharedEventListenerRef,
54         value: u64,
55         block: MTLSharedEventNotificationBlock,
56     ) {
57         unsafe {
58             // If the block doesn't have a signature, this segfaults.
59             // Taken from https://github.com/servo/pathfinder/blob/e858c8dc1d8ff02a5b603e21e09a64d6b3e11327/metal/src/lib.rs#L2327
60             let block = mem::transmute::<
61                 MTLSharedEventNotificationBlock,
62                 *mut BlockBase<(&SharedEventRef, u64), ()>,
63             >(block);
64             (*block).flags |= BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE;
65             (*block).extra = &BLOCK_EXTRA;
66             let () = msg_send![self, notifyListener:listener atValue:value block:block];
67             mem::forget(block);
68         }
69 
70         extern "C" fn dtor(_: *mut BlockBase<(&SharedEventRef, u64), ()>) {}
71 
72         const SIGNATURE: &[u8] = b"v16@?0Q8\0";
73         const SIGNATURE_PTR: *const i8 = &SIGNATURE[0] as *const u8 as *const i8;
74         static mut BLOCK_EXTRA: BlockExtra<(&SharedEventRef, u64), ()> = BlockExtra {
75             unknown0: 0 as *mut i32,
76             unknown1: 0 as *mut i32,
77             unknown2: 0 as *mut i32,
78             dtor,
79             signature: &SIGNATURE_PTR,
80         };
81     }
82 }
83 
84 pub enum MTLSharedEventListener {}
85 
86 foreign_obj_type! {
87     type CType = MTLSharedEventListener;
88     pub struct SharedEventListener;
89     pub struct SharedEventListenerRef;
90 }
91 
92 impl SharedEventListener {
from_queue_handle(queue: dispatch_queue_t) -> Self93     pub unsafe fn from_queue_handle(queue: dispatch_queue_t) -> Self {
94         let listener: SharedEventListener = msg_send![class!(MTLSharedEventListener), alloc];
95         let ptr: *mut Object = msg_send![listener.as_ref(), initWithDispatchQueue: queue];
96         if ptr.is_null() {
97             panic!("[MTLSharedEventListener alloc] initWithDispatchQueue failed");
98         }
99         listener
100     }
101 
102     #[cfg(feature = "dispatch")]
from_queue(queue: &dispatch::Queue) -> Self103     pub fn from_queue(queue: &dispatch::Queue) -> Self {
104         unsafe {
105             let raw_queue = std::mem::transmute::<&dispatch::Queue, *const dispatch_queue_t>(queue);
106             Self::from_queue_handle(*raw_queue)
107         }
108     }
109 }
110 
111 pub enum MTLFence {}
112 
113 foreign_obj_type! {
114     type CType = MTLFence;
115     pub struct Fence;
116     pub struct FenceRef;
117 }
118 
119 impl FenceRef {
device(&self) -> &DeviceRef120     pub fn device(&self) -> &DeviceRef {
121         unsafe { msg_send![self, device] }
122     }
123 
label(&self) -> &str124     pub fn label(&self) -> &str {
125         unsafe {
126             let label = msg_send![self, label];
127             crate::nsstring_as_str(label)
128         }
129     }
130 
set_label(&self, label: &str)131     pub fn set_label(&self, label: &str) {
132         unsafe {
133             let nslabel = crate::nsstring_from_str(label);
134             let () = msg_send![self, setLabel: nslabel];
135         }
136     }
137 }
138 
139 #[repr(u64)]
140 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
141 pub enum MTLRenderStages {
142     Vertex = 0,
143     Fragment = 1,
144 }
145 
146 const BLOCK_HAS_COPY_DISPOSE: i32 = 0x02000000;
147 const BLOCK_HAS_SIGNATURE: i32 = 0x40000000;
148 
149 #[repr(C)]
150 struct BlockBase<A, R> {
151     isa: *const std::ffi::c_void,                             // 0x00
152     flags: i32,                                               // 0x08
153     _reserved: i32,                                           // 0x0c
154     invoke: unsafe extern "C" fn(*mut Block<A, R>, ...) -> R, // 0x10
155     extra: *const BlockExtra<A, R>,                           // 0x18
156 }
157 
158 type BlockExtraDtor<A, R> = extern "C" fn(*mut BlockBase<A, R>);
159 
160 #[repr(C)]
161 struct BlockExtra<A, R> {
162     unknown0: *mut i32,          // 0x00
163     unknown1: *mut i32,          // 0x08
164     unknown2: *mut i32,          // 0x10
165     dtor: BlockExtraDtor<A, R>,  // 0x18
166     signature: *const *const i8, // 0x20
167 }
168