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