// Copyright 2017 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 foreign_types::ForeignType; use objc::runtime::{Object, BOOL, NO, YES}; use std::ffi::CStr; use std::os::raw::{c_char, c_void}; use std::ptr; /// Only available on (macos(10.12), ios(10.0) /// /// See #[repr(u64)] #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum MTLPatchType { None = 0, Triangle = 1, Quad = 2, } /// See pub enum MTLVertexAttribute {} foreign_obj_type! { type CType = MTLVertexAttribute; pub struct VertexAttribute; } impl VertexAttributeRef { pub fn name(&self) -> &str { unsafe { let name = msg_send![self, name]; crate::nsstring_as_str(name) } } pub fn attribute_index(&self) -> u64 { unsafe { msg_send![self, attributeIndex] } } pub fn attribute_type(&self) -> MTLDataType { unsafe { msg_send![self, attributeType] } } pub fn is_active(&self) -> bool { unsafe { msg_send_bool![self, isActive] } } /// Only available on (macos(10.12), ios(10.0) pub fn is_patch_data(&self) -> bool { unsafe { msg_send_bool![self, isPatchData] } } /// Only available on (macos(10.12), ios(10.0) pub fn is_patch_control_point_data(&self) -> bool { unsafe { msg_send_bool![self, isPatchControlPointData] } } } /// Only available on (macos(10.12), ios(10.0)) /// /// See pub enum MTLAttribute {} foreign_obj_type! { type CType = MTLAttribute; pub struct Attribute; } impl AttributeRef { pub fn name(&self) -> &str { unsafe { let name = msg_send![self, name]; crate::nsstring_as_str(name) } } pub fn attribute_index(&self) -> u64 { unsafe { msg_send![self, attributeIndex] } } pub fn attribute_type(&self) -> MTLDataType { unsafe { msg_send![self, attributeType] } } pub fn is_active(&self) -> bool { unsafe { msg_send_bool![self, isActive] } } /// Only available on (macos(10.12), ios(10.0)) pub fn is_patch_data(&self) -> bool { unsafe { msg_send_bool![self, isPatchData] } } /// Only available on (macos(10.12), ios(10.0)) pub fn is_patch_control_point_data(&self) -> bool { unsafe { msg_send_bool![self, isPatchControlPointData] } } } /// See #[repr(u64)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum MTLFunctionType { Vertex = 1, Fragment = 2, Kernel = 3, /// Only available on (macos(11.0), ios(14.0)) Visible = 5, /// Only available on (macos(11.0), ios(14.0)) Intersection = 6, } /// Only available on (macos(10.12), ios(10.0)) /// /// See pub enum MTLFunctionConstant {} foreign_obj_type! { type CType = MTLFunctionConstant; pub struct FunctionConstant; } impl FunctionConstantRef { pub fn name(&self) -> &str { unsafe { let name = msg_send![self, name]; crate::nsstring_as_str(name) } } pub fn data_type(&self) -> MTLDataType { unsafe { msg_send![self, type] } } pub fn index(&self) -> NSUInteger { unsafe { msg_send![self, index] } } pub fn required(&self) -> bool { unsafe { msg_send_bool![self, required] } } } bitflags! { /// Only available on (macos(11.0), ios(14.0)) /// /// See #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct MTLFunctionOptions: NSUInteger { const None = 0; const CompileToBinary = 1 << 0; } } /// Only available on (macos(11.0), ios(14.0)) /// /// See pub enum MTLFunctionDescriptor {} foreign_obj_type! { type CType = MTLFunctionDescriptor; pub struct FunctionDescriptor; } impl FunctionDescriptor { pub fn new() -> Self { unsafe { let class = class!(MTLFunctionDescriptor); msg_send![class, new] } } } impl FunctionDescriptorRef { pub fn name(&self) -> &str { unsafe { let name = msg_send![self, name]; crate::nsstring_as_str(name) } } pub fn set_name(&self, name: &str) { unsafe { let ns_name = crate::nsstring_from_str(name); let () = msg_send![self, setName: ns_name]; } } pub fn specialized_name(&self) -> &str { unsafe { let name = msg_send![self, specializedName]; crate::nsstring_as_str(name) } } pub fn set_specialized_name(&self, name: &str) { unsafe { let ns_name = crate::nsstring_from_str(name); let () = msg_send![self, setSpecializedName: ns_name]; } } pub fn constant_values(&self) -> &FunctionConstantValuesRef { unsafe { msg_send![self, constantValues] } } pub fn set_constant_values(&self, values: &FunctionConstantValuesRef) { unsafe { msg_send![self, setConstantValues: values] } } pub fn options(&self) -> MTLFunctionOptions { unsafe { msg_send![self, options] } } pub fn set_options(&self, options: MTLFunctionOptions) { unsafe { msg_send![self, setOptions: options] } } } /// Only available on (macos(11.0), ios(14.0)) /// /// See pub enum MTLIntersectionFunctionDescriptor {} foreign_obj_type! { type CType = MTLIntersectionFunctionDescriptor; pub struct IntersectionFunctionDescriptor; type ParentType = FunctionDescriptor; } /// Only available on (macos(11.0), ios(14.0)) /// /// See pub enum MTLFunctionHandle {} foreign_obj_type! { type CType = MTLFunctionHandle; pub struct FunctionHandle; } impl FunctionHandleRef { pub fn device(&self) -> &DeviceRef { unsafe { msg_send![self, device] } } pub fn name(&self) -> &str { unsafe { let ns_name = msg_send![self, name]; crate::nsstring_as_str(ns_name) } } pub fn function_type(&self) -> MTLFunctionType { unsafe { msg_send![self, functionType] } } } // TODO: // MTLVisibleFunctionTableDescriptor // MTLVisibleFunctionTable // MTLIntersectionFunctionSignature // MTLIntersectionFunctionTableDescriptor // MTLIntersectionFunctionTable /// See pub enum MTLFunction {} foreign_obj_type! { type CType = MTLFunction; pub struct Function; } impl FunctionRef { pub fn device(&self) -> &DeviceRef { unsafe { msg_send![self, device] } } /// Only available on (macos(10.12), ios(10.0)) pub fn label(&self) -> &str { unsafe { let ns_label = msg_send![self, label]; crate::nsstring_as_str(ns_label) } } /// Only available on (macos(10.12), ios(10.0)) pub fn set_label(&self, label: &str) { unsafe { let ns_label = crate::nsstring_from_str(label); let () = msg_send![self, setLabel: ns_label]; } } pub fn name(&self) -> &str { unsafe { let name = msg_send![self, name]; crate::nsstring_as_str(name) } } pub fn function_type(&self) -> MTLFunctionType { unsafe { msg_send![self, functionType] } } /// Only available on (macos(10.12), ios(10.0)) pub fn patch_type(&self) -> MTLPatchType { unsafe { msg_send![self, patchType] } } /// Only available on (macos(10.12), ios(10.0)) pub fn patch_control_point_count(&self) -> NSUInteger { unsafe { msg_send![self, patchControlPointCount] } } /// Only available on (macos(10.12), ios(10.0)) pub fn vertex_attributes(&self) -> &Array { unsafe { msg_send![self, vertexAttributes] } } /// Only available on (macos(10.12), ios(10.0)) pub fn stage_input_attributes(&self) -> &Array { unsafe { msg_send![self, stageInputAttributes] } } pub fn new_argument_encoder(&self, buffer_index: NSUInteger) -> ArgumentEncoder { unsafe { let ptr = msg_send![self, newArgumentEncoderWithBufferIndex: buffer_index]; ArgumentEncoder::from_ptr(ptr) } } pub fn function_constants_dictionary(&self) -> *mut Object { unsafe { msg_send![self, functionConstantsDictionary] } } /// Only available on (macos(11.0), ios(14.0)) pub fn options(&self) -> MTLFunctionOptions { unsafe { msg_send![self, options] } } } /// See #[repr(u64)] #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] pub enum MTLLanguageVersion { V1_0 = 0x10000, V1_1 = 0x10001, V1_2 = 0x10002, V2_0 = 0x20000, V2_1 = 0x20001, V2_2 = 0x20002, /// available on macOS 11.0+, iOS 14.0+ V2_3 = 0x20003, /// available on macOS 12.0+, iOS 15.0+ V2_4 = 0x20004, } /// See pub enum MTLFunctionConstantValues {} foreign_obj_type! { type CType = MTLFunctionConstantValues; pub struct FunctionConstantValues; } impl FunctionConstantValues { pub fn new() -> Self { unsafe { let class = class!(MTLFunctionConstantValues); msg_send![class, new] } } } impl FunctionConstantValuesRef { pub fn set_constant_value_at_index( &self, value: *const c_void, ty: MTLDataType, index: NSUInteger, ) { unsafe { msg_send![self, setConstantValue:value type:ty atIndex:index] } } pub fn set_constant_values_with_range( &self, values: *const c_void, ty: MTLDataType, range: NSRange, ) { unsafe { msg_send![self, setConstantValues:values type:ty withRange:range] } } pub fn set_constant_value_with_name(&self, value: *const c_void, ty: MTLDataType, name: &str) { unsafe { let ns_name = crate::nsstring_from_str(name); msg_send![self, setConstantValue:value type:ty withName:ns_name] } } } /// Only available on (macos(11.0), ios(14.0)) /// /// See #[repr(u64)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum MTLLibraryType { Executable = 0, Dynamic = 1, } /// See pub enum MTLCompileOptions {} foreign_obj_type! { type CType = MTLCompileOptions; pub struct CompileOptions; } impl CompileOptions { pub fn new() -> Self { unsafe { let class = class!(MTLCompileOptions); msg_send![class, new] } } } impl CompileOptionsRef { pub unsafe fn preprocessor_macros(&self) -> *mut Object { msg_send![self, preprocessorMacros] } pub unsafe fn set_preprocessor_macros(&self, defines: *mut Object) { msg_send![self, setPreprocessorMacros: defines] } pub fn is_fast_math_enabled(&self) -> bool { unsafe { msg_send_bool![self, fastMathEnabled] } } pub fn set_fast_math_enabled(&self, enabled: bool) { unsafe { msg_send![self, setFastMathEnabled: enabled] } } /// Only available on (macos(10.11), ios(9.0)) pub fn language_version(&self) -> MTLLanguageVersion { unsafe { msg_send![self, languageVersion] } } /// Only available on (macos(10.11), ios(9.0)) pub fn set_language_version(&self, version: MTLLanguageVersion) { unsafe { msg_send![self, setLanguageVersion: version] } } /// Only available on (macos(11.0), ios(14.0)) pub fn library_type(&self) -> MTLLibraryType { unsafe { msg_send![self, libraryType] } } /// Only available on (macos(11.0), ios(14.0)) pub fn set_library_type(&self, lib_type: MTLLibraryType) { unsafe { msg_send![self, setLibraryType: lib_type] } } /// Only available on (macos(11.0), ios(14.0)) pub fn install_name(&self) -> &str { unsafe { let name = msg_send![self, installName]; crate::nsstring_as_str(name) } } /// Only available on (macos(11.0), ios(14.0)) pub fn set_install_name(&self, name: &str) { unsafe { let install_name = crate::nsstring_from_str(name); let () = msg_send![self, setInstallName: install_name]; } } /// Only available on (macos(11.0), ios(14.0)) /// /// Marshal to Rust Vec pub fn libraries(&self) -> Vec { unsafe { let libraries: *mut Object = msg_send![self, libraries]; let count: NSUInteger = msg_send![libraries, count]; let ret = (0..count) .map(|i| { let lib = msg_send![libraries, objectAtIndex: i]; DynamicLibrary::from_ptr(lib) }) .collect(); ret } } /// Only available on (macos(11.0), ios(14.0)) /// /// As raw NSArray pub fn libraries_as_nsarray(&self) -> &ArrayRef { unsafe { msg_send![self, libraries] } } /// Only available on (macos(11.0), ios(14.0)) /// /// Marshal from Rust slice pub fn set_libraries(&self, libraries: &[&DynamicLibraryRef]) { let ns_array = Array::::from_slice(libraries); unsafe { msg_send![self, setLibraries: ns_array] } } /// Only available on (macos(11.0), ios(14.0)) /// /// From raw NSArray pub fn set_libraries_nsarray(&self, libraries: &ArrayRef) { unsafe { msg_send![self, setLibraries: libraries] } } /// Only available on (macos(11.0), macCatalyst(14.0), ios(13.0)) pub fn preserve_invariance(&self) -> bool { unsafe { msg_send_bool![self, preserveInvariance] } } /// Only available on (macos(11.0), macCatalyst(14.0), ios(13.0)) pub fn set_preserve_invariance(&self, preserve: bool) { unsafe { msg_send![self, setPreserveInvariance: preserve] } } } /// See #[repr(u64)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum MTLLibraryError { Unsupported = 1, Internal = 2, CompileFailure = 3, CompileWarning = 4, /// Only available on (macos(10.12), ios(10.0)) FunctionNotFound = 5, /// Only available on (macos(10.12), ios(10.0)) FileNotFound = 6, } /// See pub enum MTLLibrary {} foreign_obj_type! { type CType = MTLLibrary; pub struct Library; } impl LibraryRef { 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]; } } // FIXME: should rename to new_function pub fn get_function( &self, name: &str, constants: Option, ) -> Result { unsafe { let nsname = crate::nsstring_from_str(name); let function: *mut MTLFunction = match constants { Some(c) => try_objc! { err => msg_send![self, newFunctionWithName: nsname.as_ref() constantValues: c.as_ref() error: &mut err ]}, None => msg_send![self, newFunctionWithName: nsname.as_ref()], }; if !function.is_null() { Ok(Function::from_ptr(function)) } else { Err(format!("Function '{}' does not exist", name)) } } } // TODO: get_function_async with completion handler pub fn function_names(&self) -> Vec { unsafe { let names: *mut Object = msg_send![self, functionNames]; let count: NSUInteger = msg_send![names, count]; let ret = (0..count) .map(|i| { let name = msg_send![names, objectAtIndex: i]; nsstring_as_str(name).to_string() }) .collect(); ret } } /// Only available on (macos(11.0), ios(14.0)) pub fn library_type(&self) -> MTLLibraryType { unsafe { msg_send![self, type] } } /// Only available on (macos(11.0), ios(14.0)) pub fn install_name(&self) -> Option<&str> { unsafe { let maybe_name: *mut Object = msg_send![self, installName]; maybe_name.as_ref().map(crate::nsstring_as_str) } } /// Only available on (macos(11.0), ios(14.0)) pub fn new_function_with_descriptor( &self, descriptor: &FunctionDescriptorRef, ) -> Result { unsafe { let function: *mut MTLFunction = try_objc! { err => msg_send![self, newFunctionWithDescriptor: descriptor error: &mut err ] }; if !function.is_null() { Ok(Function::from_ptr(function)) } else { Err(String::from("new_function_with_descriptor() failed")) } } } /// Only available on (macos(11.0), ios(14.0)) pub fn new_intersection_function_with_descriptor( &self, descriptor: &IntersectionFunctionDescriptorRef, ) -> Result { unsafe { let function: *mut MTLFunction = try_objc! { err => msg_send![self, newIntersectionFunctionWithDescriptor: descriptor error: &mut err ] }; if !function.is_null() { Ok(Function::from_ptr(function)) } else { Err(String::from( "new_intersection_function_with_descriptor() failed", )) } } } } /// Only available on (macos(11.0), ios(14.0)) /// /// See #[repr(u64)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum MTLDynamicLibraryError { None = 0, InvalidFile = 1, CompilationFailure = 2, UnresolvedInstallName = 3, DependencyLoadFailure = 4, Unsupported = 5, } /// See pub enum MTLDynamicLibrary {} foreign_obj_type! { type CType = MTLDynamicLibrary; pub struct DynamicLibrary; } impl DynamicLibraryRef { 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]; } } pub fn install_name(&self) -> &str { unsafe { let name = msg_send![self, installName]; crate::nsstring_as_str(name) } } pub fn serialize_to_url(&self, url: &URLRef) -> Result { unsafe { msg_send_bool_error_check![self, serializeToURL: url] } } } /// macOS 11.0+ iOS 14.0+ /// /// See pub enum MTLBinaryArchiveDescriptor {} foreign_obj_type! { type CType = MTLBinaryArchiveDescriptor; pub struct BinaryArchiveDescriptor; } impl BinaryArchiveDescriptor { pub fn new() -> Self { unsafe { let class = class!(MTLBinaryArchiveDescriptor); msg_send![class, new] } } } impl BinaryArchiveDescriptorRef { pub fn url(&self) -> &URLRef { unsafe { msg_send![self, url] } } pub fn set_url(&self, url: &URLRef) { unsafe { msg_send![self, setUrl: url] } } } /// macOS 11.0+ iOS 14.0+ /// /// See pub enum MTLBinaryArchive {} foreign_obj_type! { type CType = MTLBinaryArchive; pub struct BinaryArchive; } impl BinaryArchiveRef { 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]; } } pub fn add_compute_pipeline_functions_with_descriptor( &self, descriptor: &ComputePipelineDescriptorRef, ) -> Result { unsafe { msg_send_bool_error_check![self, addComputePipelineFunctionsWithDescriptor: descriptor] } } pub fn add_render_pipeline_functions_with_descriptor( &self, descriptor: &RenderPipelineDescriptorRef, ) -> Result { unsafe { msg_send_bool_error_check![self, addRenderPipelineFunctionsWithDescriptor: descriptor] } } // TODO: addTileRenderPipelineFunctionsWithDescriptor // - (BOOL)addTileRenderPipelineFunctionsWithDescriptor:(MTLTileRenderPipelineDescriptor *)descriptor // error:(NSError * _Nullable *)error; pub fn serialize_to_url(&self, url: &URLRef) -> Result { unsafe { let mut err: *mut Object = ptr::null_mut(); let result: BOOL = msg_send![self, serializeToURL:url error:&mut err]; if !err.is_null() { // FIXME: copy pasta let desc: *mut Object = msg_send![err, localizedDescription]; let c_msg: *const c_char = msg_send![desc, UTF8String]; let message = CStr::from_ptr(c_msg).to_string_lossy().into_owned(); Err(message) } else { match result { YES => Ok(true), NO => Ok(false), #[cfg(not(target_arch = "aarch64"))] _ => unreachable!(), } } } } } /// macOS 11.0+ iOS 14.0+ /// /// See pub enum MTLLinkedFunctions {} foreign_obj_type! { type CType = MTLLinkedFunctions; pub struct LinkedFunctions; } impl LinkedFunctions { pub fn new() -> Self { unsafe { let class = class!(MTLLinkedFunctions); msg_send![class, new] } } } impl LinkedFunctionsRef { /// Marshal to Rust Vec pub fn functions(&self) -> Vec { unsafe { let functions: *mut Object = msg_send![self, functions]; let count: NSUInteger = msg_send![functions, count]; let ret = (0..count) .map(|i| { let f = msg_send![functions, objectAtIndex: i]; Function::from_ptr(f) }) .collect(); ret } } /// Marshal from Rust slice pub fn set_functions(&self, functions: &[&FunctionRef]) { let ns_array = Array::::from_slice(functions); unsafe { msg_send![self, setFunctions: ns_array] } } /// Marshal to Rust Vec pub fn binary_functions(&self) -> Vec { unsafe { let functions: *mut Object = msg_send![self, binaryFunctions]; let count: NSUInteger = msg_send![functions, count]; let ret = (0..count) .map(|i| { let f = msg_send![functions, objectAtIndex: i]; Function::from_ptr(f) }) .collect(); ret } } /// Marshal from Rust slice pub fn set_binary_functions(&self, functions: &[&FunctionRef]) { let ns_array = Array::::from_slice(functions); unsafe { msg_send![self, setBinaryFunctions: ns_array] } } // TODO: figure out NSDictionary wrapper // TODO: groups // @property (readwrite, nonatomic, copy, nullable) NSDictionary>*> *groups; }