// Copyright 2016 GFX developers // // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. use super::*; use block::{Block, RcBlock}; use std::mem; #[cfg(feature = "dispatch_queue")] use dispatch; /// See type MTLSharedEventNotificationBlock<'a> = RcBlock<(&'a SharedEventRef, u64), ()>; /// See pub enum MTLEvent {} foreign_obj_type! { type CType = MTLEvent; pub struct Event; } impl EventRef { pub fn device(&self) -> &DeviceRef { unsafe { msg_send![self, device] } } } /// See pub enum MTLSharedEvent {} foreign_obj_type! { type CType = MTLSharedEvent; pub struct SharedEvent; type ParentType = Event; } impl SharedEventRef { pub fn signaled_value(&self) -> u64 { unsafe { msg_send![self, signaledValue] } } pub fn set_signaled_value(&self, new_value: u64) { unsafe { msg_send![self, setSignaledValue: new_value] } } /// Schedules a notification handler to be called after the shareable event’s signal value /// equals or exceeds a given value. pub fn notify( &self, listener: &SharedEventListenerRef, value: u64, block: MTLSharedEventNotificationBlock, ) { unsafe { // If the block doesn't have a signature, this segfaults. // Taken from https://github.com/servo/pathfinder/blob/e858c8dc1d8ff02a5b603e21e09a64d6b3e11327/metal/src/lib.rs#L2327 let block = mem::transmute::< MTLSharedEventNotificationBlock, *mut BlockBase<(&SharedEventRef, u64), ()>, >(block); (*block).flags |= BLOCK_HAS_SIGNATURE | BLOCK_HAS_COPY_DISPOSE; (*block).extra = &BLOCK_EXTRA; let () = msg_send![self, notifyListener:listener atValue:value block:block]; } extern "C" fn dtor(_: *mut BlockBase<(&SharedEventRef, u64), ()>) {} const SIGNATURE: &[u8] = b"v16@?0Q8\0"; const SIGNATURE_PTR: *const i8 = &SIGNATURE[0] as *const u8 as *const i8; static mut BLOCK_EXTRA: BlockExtra<(&SharedEventRef, u64), ()> = BlockExtra { unknown0: 0 as *mut i32, unknown1: 0 as *mut i32, unknown2: 0 as *mut i32, dtor, signature: &SIGNATURE_PTR, }; } } /// See pub enum MTLSharedEventListener {} foreign_obj_type! { type CType = MTLSharedEventListener; pub struct SharedEventListener; } impl SharedEventListener { pub unsafe fn from_queue_handle(queue: dispatch_queue_t) -> Self { let listener: SharedEventListener = msg_send![class!(MTLSharedEventListener), alloc]; let ptr: *mut Object = msg_send![listener.as_ref(), initWithDispatchQueue: queue]; if ptr.is_null() { panic!("[MTLSharedEventListener alloc] initWithDispatchQueue failed"); } listener } #[cfg(feature = "dispatch")] pub fn from_queue(queue: &dispatch::Queue) -> Self { unsafe { let raw_queue = std::mem::transmute::<&dispatch::Queue, *const dispatch_queue_t>(queue); Self::from_queue_handle(*raw_queue) } } } /// See pub enum MTLFence {} foreign_obj_type! { type CType = MTLFence; pub struct Fence; } impl FenceRef { pub fn device(&self) -> &DeviceRef { unsafe { msg_send![self, device] } } pub fn label(&self) -> &str { unsafe { let label = msg_send![self, label]; crate::nsstring_as_str(label) } } pub fn set_label(&self, label: &str) { unsafe { let nslabel = crate::nsstring_from_str(label); let () = msg_send![self, setLabel: nslabel]; } } } bitflags! { /// The render stages at which a synchronization command is triggered. /// /// Render stages provide finer control for specifying when synchronization must occur, /// allowing for vertex and fragment processing to overlap in execution. /// /// See #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct MTLRenderStages: NSUInteger { /// The vertex rendering stage. const Vertex = 1 << 0; /// The fragment rendering stage. const Fragment = 1 << 1; /// The tile rendering stage. const Tile = 1 << 2; } } const BLOCK_HAS_COPY_DISPOSE: i32 = 0x02000000; const BLOCK_HAS_SIGNATURE: i32 = 0x40000000; #[repr(C)] struct BlockBase { isa: *const std::ffi::c_void, // 0x00 flags: i32, // 0x08 _reserved: i32, // 0x0c invoke: unsafe extern "C" fn(*mut Block, ...) -> R, // 0x10 extra: *const BlockExtra, // 0x18 } type BlockExtraDtor = extern "C" fn(*mut BlockBase); #[repr(C)] struct BlockExtra { unknown0: *mut i32, // 0x00 unknown1: *mut i32, // 0x08 unknown2: *mut i32, // 0x10 dtor: BlockExtraDtor, // 0x18 signature: *const *const i8, // 0x20 }