diff options
Diffstat (limited to 'third_party/rust/metal/src/lib.rs')
-rw-r--r-- | third_party/rust/metal/src/lib.rs | 549 |
1 files changed, 549 insertions, 0 deletions
diff --git a/third_party/rust/metal/src/lib.rs b/third_party/rust/metal/src/lib.rs new file mode 100644 index 0000000000..bc8427922c --- /dev/null +++ b/third_party/rust/metal/src/lib.rs @@ -0,0 +1,549 @@ +// Copyright 2017 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. + +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] + +#[macro_use] +extern crate bitflags; +#[macro_use] +extern crate log; +#[macro_use] +extern crate objc; +#[macro_use] +extern crate foreign_types; + +use std::{ + borrow::{Borrow, ToOwned}, + marker::PhantomData, + mem, + ops::Deref, + os::raw::c_void, +}; + +use core_graphics_types::{base::CGFloat, geometry::CGSize}; +use foreign_types::ForeignType; +use objc::runtime::{Object, NO, YES}; + +#[cfg(target_pointer_width = "64")] +pub type NSInteger = i64; +#[cfg(not(target_pointer_width = "64"))] +pub type NSInteger = i32; +#[cfg(target_pointer_width = "64")] +pub type NSUInteger = u64; +#[cfg(target_pointer_width = "32")] +pub type NSUInteger = u32; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct NSRange { + pub location: NSUInteger, + pub length: NSUInteger, +} + +impl NSRange { + #[inline] + pub fn new(location: NSUInteger, length: NSUInteger) -> NSRange { + NSRange { location, length } + } +} + +fn nsstring_as_str(nsstr: &objc::runtime::Object) -> &str { + let bytes = unsafe { + let bytes: *const std::os::raw::c_char = msg_send![nsstr, UTF8String]; + bytes as *const u8 + }; + let len: NSUInteger = unsafe { msg_send![nsstr, length] }; + unsafe { + let bytes = std::slice::from_raw_parts(bytes, len as usize); + std::str::from_utf8(bytes).unwrap() + } +} + +fn nsstring_from_str(string: &str) -> *mut objc::runtime::Object { + const UTF8_ENCODING: usize = 4; + + let cls = class!(NSString); + let bytes = string.as_ptr() as *const c_void; + unsafe { + let obj: *mut objc::runtime::Object = msg_send![cls, alloc]; + let obj: *mut objc::runtime::Object = msg_send![ + obj, + initWithBytes:bytes + length:string.len() + encoding:UTF8_ENCODING + ]; + let _: *mut c_void = msg_send![obj, autorelease]; + obj + } +} + +macro_rules! foreign_obj_type { + {type CType = $raw_ident:ident; + pub struct $owned_ident:ident; + pub struct $ref_ident:ident; + type ParentType = $parent_ref:ident; + } => { + foreign_obj_type! { + type CType = $raw_ident; + pub struct $owned_ident; + pub struct $ref_ident; + } + + impl ::std::ops::Deref for $ref_ident { + type Target = $parent_ref; + + #[inline] + fn deref(&self) -> &$parent_ref { + unsafe { &*(self as *const $ref_ident as *const $parent_ref) } + } + } + }; + {type CType = $raw_ident:ident; + pub struct $owned_ident:ident; + pub struct $ref_ident:ident; + } => { + foreign_type! { + type CType = $raw_ident; + fn drop = crate::obj_drop; + fn clone = crate::obj_clone; + pub struct $owned_ident; + pub struct $ref_ident; + } + + unsafe impl ::objc::Message for $raw_ident { + } + unsafe impl ::objc::Message for $ref_ident { + } + + impl ::std::fmt::Debug for $ref_ident { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + unsafe { + let string: *mut ::objc::runtime::Object = msg_send![self, debugDescription]; + write!(f, "{}", crate::nsstring_as_str(&*string)) + } + } + } + + impl ::std::fmt::Debug for $owned_ident { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + ::std::ops::Deref::deref(self).fmt(f) + } + } + }; +} + +macro_rules! try_objc { + { + $err_name: ident => $body:expr + } => { + { + let mut $err_name: *mut ::objc::runtime::Object = ::std::ptr::null_mut(); + let value = $body; + if !$err_name.is_null() { + let desc: *mut Object = msg_send![$err_name, localizedDescription]; + let compile_error: *const std::os::raw::c_char = msg_send![desc, UTF8String]; + let message = CStr::from_ptr(compile_error).to_string_lossy().into_owned(); + let () = msg_send![$err_name, release]; + return Err(message); + } + value + } + }; +} + +pub struct NSArray<T> { + _phantom: PhantomData<T>, +} + +pub struct Array<T>(*mut NSArray<T>) +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static; +pub struct ArrayRef<T>(foreign_types::Opaque, PhantomData<T>) +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static; + +impl<T> Drop for Array<T> +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + fn drop(&mut self) { + unsafe { + let () = msg_send![self.0, release]; + } + } +} + +impl<T> Clone for Array<T> +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + fn clone(&self) -> Self { + unsafe { Array(msg_send![self.0, retain]) } + } +} + +unsafe impl<T> objc::Message for NSArray<T> +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ +} +unsafe impl<T> objc::Message for ArrayRef<T> +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ +} + +impl<T> Array<T> +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + pub fn from_slice<'a>(s: &[&T::Ref]) -> &'a ArrayRef<T> { + unsafe { + let class = class!(NSArray); + msg_send![class, arrayWithObjects: s.as_ptr() count: s.len()] + } + } + + pub fn from_owned_slice<'a>(s: &[T]) -> &'a ArrayRef<T> { + unsafe { + let class = class!(NSArray); + msg_send![class, arrayWithObjects: s.as_ptr() count: s.len()] + } + } +} + +impl<T> foreign_types::ForeignType for Array<T> +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + type CType = NSArray<T>; + type Ref = ArrayRef<T>; + + unsafe fn from_ptr(p: *mut NSArray<T>) -> Self { + Array(p) + } + + fn as_ptr(&self) -> *mut NSArray<T> { + self.0 + } +} + +impl<T> foreign_types::ForeignTypeRef for ArrayRef<T> +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + type CType = NSArray<T>; +} + +impl<T> Deref for Array<T> +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + type Target = ArrayRef<T>; + + #[inline] + fn deref(&self) -> &ArrayRef<T> { + unsafe { mem::transmute(self.as_ptr()) } + } +} + +impl<T> Borrow<ArrayRef<T>> for Array<T> +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + fn borrow(&self) -> &ArrayRef<T> { + unsafe { mem::transmute(self.as_ptr()) } + } +} + +impl<T> ToOwned for ArrayRef<T> +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + type Owned = Array<T>; + + fn to_owned(&self) -> Array<T> { + unsafe { Array::from_ptr(msg_send![self, retain]) } + } +} + +pub enum CAMetalDrawable {} + +foreign_obj_type! { + type CType = CAMetalDrawable; + pub struct MetalDrawable; + pub struct MetalDrawableRef; + type ParentType = DrawableRef; +} + +impl MetalDrawableRef { + pub fn texture(&self) -> &TextureRef { + unsafe { msg_send![self, texture] } + } +} + +pub enum CAMetalLayer {} + +foreign_obj_type! { + type CType = CAMetalLayer; + pub struct MetalLayer; + pub struct MetalLayerRef; +} + +impl MetalLayer { + pub fn new() -> Self { + unsafe { + let class = class!(CAMetalLayer); + msg_send![class, new] + } + } +} + +impl MetalLayerRef { + pub fn device(&self) -> &DeviceRef { + unsafe { msg_send![self, device] } + } + + pub fn set_device(&self, device: &DeviceRef) { + unsafe { msg_send![self, setDevice: device] } + } + + pub fn pixel_format(&self) -> MTLPixelFormat { + unsafe { msg_send![self, pixelFormat] } + } + + pub fn set_pixel_format(&self, pixel_format: MTLPixelFormat) { + unsafe { msg_send![self, setPixelFormat: pixel_format] } + } + + pub fn drawable_size(&self) -> CGSize { + unsafe { msg_send![self, drawableSize] } + } + + pub fn set_drawable_size(&self, size: CGSize) { + unsafe { msg_send![self, setDrawableSize: size] } + } + + pub fn presents_with_transaction(&self) -> bool { + unsafe { + match msg_send![self, presentsWithTransaction] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_presents_with_transaction(&self, transaction: bool) { + unsafe { msg_send![self, setPresentsWithTransaction: transaction] } + } + + pub fn display_sync_enabled(&self) -> bool { + unsafe { + match msg_send![self, displaySyncEnabled] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_display_sync_enabled(&self, enabled: bool) { + unsafe { msg_send![self, setDisplaySyncEnabled: enabled] } + } + + pub fn maximum_drawable_count(&self) -> NSUInteger { + unsafe { msg_send![self, maximumDrawableCount] } + } + + pub fn set_maximum_drawable_count(&self, count: NSUInteger) { + unsafe { msg_send![self, setMaximumDrawableCount: count] } + } + + pub fn set_edge_antialiasing_mask(&self, mask: u64) { + unsafe { msg_send![self, setEdgeAntialiasingMask: mask] } + } + + pub fn set_masks_to_bounds(&self, masks: bool) { + unsafe { msg_send![self, setMasksToBounds: masks] } + } + + pub fn remove_all_animations(&self) { + unsafe { msg_send![self, removeAllAnimations] } + } + + pub fn next_drawable(&self) -> Option<&MetalDrawableRef> { + unsafe { msg_send![self, nextDrawable] } + } + + pub fn contents_scale(&self) -> CGFloat { + unsafe { msg_send![self, contentsScale] } + } + + pub fn set_contents_scale(&self, scale: CGFloat) { + unsafe { msg_send![self, setContentsScale: scale] } + } + + /// [framebufferOnly Apple Docs](https://developer.apple.com/documentation/metal/mtltexture/1515749-framebufferonly?language=objc) + pub fn framebuffer_only(&self) -> bool { + unsafe { + match msg_send![self, framebufferOnly] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_framebuffer_only(&self, framebuffer_only: bool) { + unsafe { msg_send![self, setFramebufferOnly: framebuffer_only] } + } + + pub fn is_opaque(&self) -> bool { + unsafe { + match msg_send![self, isOpaque] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_opaque(&self, opaque: bool) { + unsafe { msg_send![self, setOpaque: opaque] } + } + + pub fn wants_extended_dynamic_range_content(&self) -> bool { + unsafe { + match msg_send![self, wantsExtendedDynamicRangeContent] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_wants_extended_dynamic_range_content( + &self, + wants_extended_dynamic_range_content: bool, + ) { + unsafe { + msg_send![ + self, + setWantsExtendedDynamicRangeContent: wants_extended_dynamic_range_content + ] + } + } +} + +mod argument; +mod buffer; +mod capturedescriptor; +mod capturemanager; +mod commandbuffer; +mod commandqueue; +mod constants; +mod depthstencil; +mod device; +mod drawable; +mod encoder; +mod heap; +mod indirect_encoder; +mod library; +#[cfg(feature = "mps")] +mod mps; +mod pipeline; +mod renderpass; +mod resource; +mod sampler; +mod sync; +mod texture; +mod types; +mod vertexdescriptor; + +#[rustfmt::skip] +pub use { + argument::*, + buffer::*, + capturedescriptor::*, + capturemanager::*, + commandbuffer::*, + commandqueue::*, + constants::*, + depthstencil::*, + device::*, + drawable::*, + encoder::*, + heap::*, + indirect_encoder::*, + library::*, + pipeline::*, + renderpass::*, + resource::*, + sampler::*, + texture::*, + types::*, + vertexdescriptor::*, + sync::*, +}; + +#[cfg(feature = "mps")] +pub use mps::*; + +#[inline] +unsafe fn obj_drop<T>(p: *mut T) { + msg_send![(p as *mut Object), release] +} + +#[inline] +unsafe fn obj_clone<T: 'static>(p: *mut T) -> *mut T { + msg_send![(p as *mut Object), retain] +} + +#[allow(non_camel_case_types)] +type c_size_t = usize; + +// TODO: expand supported interface +pub enum NSURL {} + +foreign_obj_type! { + type CType = NSURL; + pub struct URL; + pub struct URLRef; +} + +impl URL { + pub fn new_with_string(string: &str) -> Self { + unsafe { + let ns_str = crate::nsstring_from_str(string); + let class = class!(NSURL); + msg_send![class, URLWithString: ns_str] + } + } +} + +impl URLRef { + pub fn absolute_string(&self) -> &str { + unsafe { + let absolute_string = msg_send![self, absoluteString]; + crate::nsstring_as_str(absolute_string) + } + } +} |