diff options
Diffstat (limited to 'third_party/rust/metal/src/sync.rs')
-rw-r--r-- | third_party/rust/metal/src/sync.rs | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/third_party/rust/metal/src/sync.rs b/third_party/rust/metal/src/sync.rs new file mode 100644 index 0000000000..e4b3d8aa67 --- /dev/null +++ b/third_party/rust/metal/src/sync.rs @@ -0,0 +1,177 @@ +// Copyright 2016 GFX developers +// +// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or +// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or +// http://opensource.org/licenses/MIT>, 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; + +type MTLSharedEventNotificationBlock<'a> = RcBlock<(&'a SharedEventRef, u64), ()>; + +pub enum MTLEvent {} + +foreign_obj_type! { + type CType = MTLEvent; + pub struct Event; + pub struct EventRef; +} + +impl EventRef { + pub fn device(&self) -> &DeviceRef { + unsafe { msg_send![self, device] } + } +} + +pub enum MTLSharedEvent {} + +foreign_obj_type! { + type CType = MTLSharedEvent; + pub struct SharedEvent; + pub struct SharedEventRef; + type ParentType = EventRef; +} + +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]; + mem::forget(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, + }; + } +} + +pub enum MTLSharedEventListener {} + +foreign_obj_type! { + type CType = MTLSharedEventListener; + pub struct SharedEventListener; + pub struct SharedEventListenerRef; +} + +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) + } + } +} + +pub enum MTLFence {} + +foreign_obj_type! { + type CType = MTLFence; + pub struct Fence; + pub struct FenceRef; +} + +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 <https://developer.apple.com/documentation/metal/mtlrenderstages> + 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<A, R> { + isa: *const std::ffi::c_void, // 0x00 + flags: i32, // 0x08 + _reserved: i32, // 0x0c + invoke: unsafe extern "C" fn(*mut Block<A, R>, ...) -> R, // 0x10 + extra: *const BlockExtra<A, R>, // 0x18 +} + +type BlockExtraDtor<A, R> = extern "C" fn(*mut BlockBase<A, R>); + +#[repr(C)] +struct BlockExtra<A, R> { + unknown0: *mut i32, // 0x00 + unknown1: *mut i32, // 0x08 + unknown2: *mut i32, // 0x10 + dtor: BlockExtraDtor<A, R>, // 0x18 + signature: *const *const i8, // 0x20 +} |