From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- third_party/rust/metal/src/argument.rs | 340 ++++ third_party/rust/metal/src/buffer.rs | 67 + third_party/rust/metal/src/capturedescriptor.rs | 79 + third_party/rust/metal/src/capturemanager.rs | 107 ++ third_party/rust/metal/src/commandbuffer.rs | 158 ++ third_party/rust/metal/src/commandqueue.rs | 44 + third_party/rust/metal/src/constants.rs | 151 ++ third_party/rust/metal/src/depthstencil.rs | 194 +++ third_party/rust/metal/src/device.rs | 2117 +++++++++++++++++++++++ third_party/rust/metal/src/drawable.rs | 26 + third_party/rust/metal/src/encoder.rs | 1376 +++++++++++++++ third_party/rust/metal/src/heap.rs | 207 +++ third_party/rust/metal/src/indirect_encoder.rs | 347 ++++ third_party/rust/metal/src/lib.rs | 549 ++++++ third_party/rust/metal/src/library.rs | 982 +++++++++++ third_party/rust/metal/src/mps.rs | 550 ++++++ third_party/rust/metal/src/pipeline/compute.rs | 488 ++++++ third_party/rust/metal/src/pipeline/mod.rs | 70 + third_party/rust/metal/src/pipeline/render.rs | 510 ++++++ third_party/rust/metal/src/renderpass.rs | 330 ++++ third_party/rust/metal/src/resource.rs | 176 ++ third_party/rust/metal/src/sampler.rs | 157 ++ third_party/rust/metal/src/sync.rs | 177 ++ third_party/rust/metal/src/texture.rs | 348 ++++ third_party/rust/metal/src/types.rs | 80 + third_party/rust/metal/src/vertexdescriptor.rs | 248 +++ 26 files changed, 9878 insertions(+) create mode 100644 third_party/rust/metal/src/argument.rs create mode 100644 third_party/rust/metal/src/buffer.rs create mode 100644 third_party/rust/metal/src/capturedescriptor.rs create mode 100644 third_party/rust/metal/src/capturemanager.rs create mode 100644 third_party/rust/metal/src/commandbuffer.rs create mode 100644 third_party/rust/metal/src/commandqueue.rs create mode 100644 third_party/rust/metal/src/constants.rs create mode 100644 third_party/rust/metal/src/depthstencil.rs create mode 100644 third_party/rust/metal/src/device.rs create mode 100644 third_party/rust/metal/src/drawable.rs create mode 100644 third_party/rust/metal/src/encoder.rs create mode 100644 third_party/rust/metal/src/heap.rs create mode 100644 third_party/rust/metal/src/indirect_encoder.rs create mode 100644 third_party/rust/metal/src/lib.rs create mode 100644 third_party/rust/metal/src/library.rs create mode 100644 third_party/rust/metal/src/mps.rs create mode 100644 third_party/rust/metal/src/pipeline/compute.rs create mode 100644 third_party/rust/metal/src/pipeline/mod.rs create mode 100644 third_party/rust/metal/src/pipeline/render.rs create mode 100644 third_party/rust/metal/src/renderpass.rs create mode 100644 third_party/rust/metal/src/resource.rs create mode 100644 third_party/rust/metal/src/sampler.rs create mode 100644 third_party/rust/metal/src/sync.rs create mode 100644 third_party/rust/metal/src/texture.rs create mode 100644 third_party/rust/metal/src/types.rs create mode 100644 third_party/rust/metal/src/vertexdescriptor.rs (limited to 'third_party/rust/metal/src') diff --git a/third_party/rust/metal/src/argument.rs b/third_party/rust/metal/src/argument.rs new file mode 100644 index 0000000000..1bf5565977 --- /dev/null +++ b/third_party/rust/metal/src/argument.rs @@ -0,0 +1,340 @@ +// 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::{MTLTextureType, NSUInteger}; +use objc::runtime::{NO, YES}; + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLDataType { + None = 0, + + Struct = 1, + Array = 2, + + Float = 3, + Float2 = 4, + Float3 = 5, + Float4 = 6, + + Float2x2 = 7, + Float2x3 = 8, + Float2x4 = 9, + + Float3x2 = 10, + Float3x3 = 11, + Float3x4 = 12, + + Float4x2 = 13, + Float4x3 = 14, + Float4x4 = 15, + + Half = 16, + Half2 = 17, + Half3 = 18, + Half4 = 19, + + Half2x2 = 20, + Half2x3 = 21, + Half2x4 = 22, + + Half3x2 = 23, + Half3x3 = 24, + Half3x4 = 25, + + Half4x2 = 26, + Half4x3 = 27, + Half4x4 = 28, + + Int = 29, + Int2 = 30, + Int3 = 31, + Int4 = 32, + + UInt = 33, + UInt2 = 34, + UInt3 = 35, + UInt4 = 36, + + Short = 37, + Short2 = 38, + Short3 = 39, + Short4 = 40, + + UShort = 41, + UShort2 = 42, + UShort3 = 43, + UShort4 = 44, + + Char = 45, + Char2 = 46, + Char3 = 47, + Char4 = 48, + + UChar = 49, + UChar2 = 50, + UChar3 = 51, + UChar4 = 52, + + Bool = 53, + Bool2 = 54, + Bool3 = 55, + Bool4 = 56, + + Texture = 58, + Sampler = 59, + Pointer = 60, + R8Unorm = 62, + R8Snorm = 63, + R16Unorm = 64, + R16Snorm = 65, + RG8Unorm = 66, + RG8Snorm = 67, + RG16Unorm = 68, + RG16Snorm = 69, + RGBA8Unorm = 70, + RGBA8Unorm_sRGB = 71, + RGBA8Snorm = 72, + RGBA16Unorm = 73, + RGBA16Snorm = 74, + RGB10A2Unorm = 75, + RG11B10Float = 76, + RGB9E5Float = 77, +} + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLArgumentType { + Buffer = 0, + ThreadgroupMemory = 1, + Texture = 2, + Sampler = 3, + ImageblockData = 16, + Imageblock = 17, +} + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLArgumentAccess { + ReadOnly = 0, + ReadWrite = 1, + WriteOnly = 2, +} + +pub enum MTLStructMember {} + +foreign_obj_type! { + type CType = MTLStructMember; + pub struct StructMember; + pub struct StructMemberRef; +} + +impl StructMemberRef { + pub fn name(&self) -> &str { + unsafe { + let name = msg_send![self, name]; + crate::nsstring_as_str(name) + } + } + + pub fn offset(&self) -> NSUInteger { + unsafe { msg_send![self, offset] } + } + + pub fn data_type(&self) -> MTLDataType { + unsafe { msg_send![self, dataType] } + } + + pub fn struct_type(&self) -> MTLStructType { + unsafe { msg_send![self, structType] } + } + + pub fn array_type(&self) -> MTLArrayType { + unsafe { msg_send![self, arrayType] } + } +} + +pub enum MTLStructMemberArray {} + +foreign_obj_type! { + type CType = MTLStructMemberArray; + pub struct StructMemberArray; + pub struct StructMemberArrayRef; +} + +impl StructMemberArrayRef { + pub fn object_at(&self, index: NSUInteger) -> Option<&StructMemberRef> { + unsafe { msg_send![self, objectAtIndexedSubscript: index] } + } + + pub fn count(&self) -> NSUInteger { + unsafe { msg_send![self, count] } + } +} + +pub enum MTLStructType {} + +foreign_obj_type! { + type CType = MTLStructType; + pub struct StructType; + pub struct StructTypeRef; +} + +impl StructTypeRef { + pub fn members(&self) -> &StructMemberArrayRef { + unsafe { msg_send![self, members] } + } + + pub fn member_from_name(&self, name: &str) -> Option<&StructMemberRef> { + let nsname = crate::nsstring_from_str(name); + + unsafe { msg_send![self, memberByName: nsname] } + } +} + +pub enum MTLArrayType {} + +foreign_obj_type! { + type CType = MTLArrayType; + pub struct ArrayType; + pub struct ArrayTypeRef; +} + +impl ArrayTypeRef { + pub fn array_length(&self) -> NSUInteger { + unsafe { msg_send![self, arrayLength] } + } + + pub fn stride(&self) -> NSUInteger { + unsafe { msg_send![self, stride] } + } + + pub fn element_type(&self) -> MTLDataType { + unsafe { msg_send![self, elementType] } + } + + pub fn element_struct_type(&self) -> MTLStructType { + unsafe { msg_send![self, elementStructType] } + } + + pub fn element_array_type(&self) -> MTLArrayType { + unsafe { msg_send![self, elementArrayType] } + } +} + +pub enum MTLArgument {} + +foreign_obj_type! { + type CType = MTLArgument; + pub struct Argument; + pub struct ArgumentRef; +} + +impl ArgumentRef { + pub fn name(&self) -> &str { + unsafe { + let name = msg_send![self, name]; + crate::nsstring_as_str(name) + } + } + + pub fn type_(&self) -> MTLArgumentType { + unsafe { msg_send![self, type] } + } + + pub fn access(&self) -> MTLArgumentAccess { + unsafe { msg_send![self, access] } + } + + pub fn index(&self) -> NSUInteger { + unsafe { msg_send![self, index] } + } + + pub fn is_active(&self) -> bool { + unsafe { + match msg_send![self, isActive] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn buffer_alignment(&self) -> NSUInteger { + unsafe { msg_send![self, bufferAlignment] } + } + + pub fn buffer_data_size(&self) -> NSUInteger { + unsafe { msg_send![self, bufferDataSize] } + } + + pub fn buffer_data_type(&self) -> MTLDataType { + unsafe { msg_send![self, bufferDataType] } + } + + pub fn buffer_struct_type(&self) -> &StructTypeRef { + unsafe { msg_send![self, bufferStructType] } + } + + pub fn threadgroup_memory_alignment(&self) -> NSUInteger { + unsafe { msg_send![self, threadgroupMemoryAlignment] } + } + + pub fn threadgroup_memory_data_size(&self) -> NSUInteger { + unsafe { msg_send![self, threadgroupMemoryDataSize] } + } + + pub fn texture_type(&self) -> MTLTextureType { + unsafe { msg_send![self, textureType] } + } + + pub fn texture_data_type(&self) -> MTLDataType { + unsafe { msg_send![self, textureDataType] } + } +} + +pub enum MTLArgumentDescriptor {} + +foreign_obj_type! { + type CType = MTLArgumentDescriptor; + pub struct ArgumentDescriptor; + pub struct ArgumentDescriptorRef; +} + +impl ArgumentDescriptor { + pub fn new<'a>() -> &'a ArgumentDescriptorRef { + unsafe { + let class = class!(MTLArgumentDescriptor); + msg_send![class, argumentDescriptor] + } + } +} + +impl ArgumentDescriptorRef { + pub fn set_data_type(&self, ty: MTLDataType) { + unsafe { msg_send![self, setDataType: ty] } + } + + pub fn set_index(&self, index: NSUInteger) { + unsafe { msg_send![self, setIndex: index] } + } + + pub fn set_access(&self, access: MTLArgumentAccess) { + unsafe { msg_send![self, setAccess: access] } + } + + pub fn set_array_length(&self, length: NSUInteger) { + unsafe { msg_send![self, setArrayLength: length] } + } + + pub fn set_texture_type(&self, ty: MTLTextureType) { + unsafe { msg_send![self, setTextureType: ty] } + } +} diff --git a/third_party/rust/metal/src/buffer.rs b/third_party/rust/metal/src/buffer.rs new file mode 100644 index 0000000000..e334c54e50 --- /dev/null +++ b/third_party/rust/metal/src/buffer.rs @@ -0,0 +1,67 @@ +// 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::*; + +pub enum MTLBuffer {} + +foreign_obj_type! { + type CType = MTLBuffer; + pub struct Buffer; + pub struct BufferRef; + type ParentType = ResourceRef; +} + +impl BufferRef { + pub fn length(&self) -> u64 { + unsafe { msg_send![self, length] } + } + + pub fn contents(&self) -> *mut std::ffi::c_void { + unsafe { msg_send![self, contents] } + } + + pub fn did_modify_range(&self, range: crate::NSRange) { + unsafe { msg_send![self, didModifyRange: range] } + } + + pub fn new_texture_with_descriptor( + &self, + descriptor: &TextureDescriptorRef, + offset: u64, + bytes_per_row: u64, + ) -> Texture { + unsafe { + msg_send![self, + newTextureWithDescriptor:descriptor + offset:offset + bytesPerRow:bytes_per_row + ] + } + } + + /// Only available on macos(10.15), NOT available on (ios) + pub fn remote_storage_buffer(&self) -> &BufferRef { + unsafe { msg_send![self, remoteStorageBuffer] } + } + + /// Only available on (macos(10.15), NOT available on (ios) + pub fn new_remote_buffer_view_for_device(&self, device: &DeviceRef) -> Buffer { + unsafe { msg_send![self, newRemoteBufferViewForDevice: device] } + } + + pub fn add_debug_marker(&self, name: &str, range: crate::NSRange) { + unsafe { + let name = crate::nsstring_from_str(name); + msg_send![self, addDebugMarker:name range:range] + } + } + + pub fn remove_all_debug_markers(&self) { + unsafe { msg_send![self, removeAllDebugMarkers] } + } +} diff --git a/third_party/rust/metal/src/capturedescriptor.rs b/third_party/rust/metal/src/capturedescriptor.rs new file mode 100644 index 0000000000..6f6e369f1a --- /dev/null +++ b/third_party/rust/metal/src/capturedescriptor.rs @@ -0,0 +1,79 @@ +// Copyright 2020 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 std::path::Path; + +/// https://developer.apple.com/documentation/metal/mtlcapturedestination?language=objc +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLCaptureDestination { + DeveloperTools = 1, + GpuTraceDocument = 2, +} + +/// https://developer.apple.com/documentation/metal/mtlcapturedescriptor +pub enum MTLCaptureDescriptor {} + +foreign_obj_type! { + type CType = MTLCaptureDescriptor; + pub struct CaptureDescriptor; + pub struct CaptureDescriptorRef; +} + +impl CaptureDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLCaptureDescriptor); + msg_send![class, new] + } + } +} + +impl CaptureDescriptorRef { + /// https://developer.apple.com/documentation/metal/mtlcapturedescriptor/3237248-captureobject + pub fn set_capture_device(&self, device: &DeviceRef) { + unsafe { msg_send![self, setCaptureObject: device] } + } + + /// https://developer.apple.com/documentation/metal/mtlcapturedescriptor/3237248-captureobject + pub fn set_capture_scope(&self, scope: &CaptureScopeRef) { + unsafe { msg_send![self, setCaptureObject: scope] } + } + + /// https://developer.apple.com/documentation/metal/mtlcapturedescriptor/3237248-captureobject + pub fn set_capture_command_queue(&self, command_queue: &CommandQueueRef) { + unsafe { msg_send![self, setCaptureObject: command_queue] } + } + + /// https://developer.apple.com/documentation/metal/mtlcapturedescriptor/3237250-outputurl + pub fn output_url(&self) -> &Path { + let output_url = unsafe { msg_send![self, outputURL] }; + let output_url = nsstring_as_str(output_url); + + Path::new(output_url) + } + + /// https://developer.apple.com/documentation/metal/mtlcapturedescriptor/3237250-outputurl + pub fn set_output_url>(&self, output_url: P) { + let output_url = nsstring_from_str(output_url.as_ref().to_str().unwrap()); + + unsafe { msg_send![self, setOutputURL: output_url] } + } + + /// https://developer.apple.com/documentation/metal/mtlcapturedescriptor?language=objc + pub fn destination(&self) -> MTLCaptureDestination { + unsafe { msg_send![self, destination] } + } + + /// https://developer.apple.com/documentation/metal/mtlcapturedescriptor?language=objc + pub fn set_destination(&self, destination: MTLCaptureDestination) { + unsafe { msg_send![self, setDestination: destination] } + } +} diff --git a/third_party/rust/metal/src/capturemanager.rs b/third_party/rust/metal/src/capturemanager.rs new file mode 100644 index 0000000000..95180c4239 --- /dev/null +++ b/third_party/rust/metal/src/capturemanager.rs @@ -0,0 +1,107 @@ +// Copyright 2018 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 std::ffi::CStr; + +pub enum MTLCaptureScope {} + +foreign_obj_type! { + type CType = MTLCaptureScope; + pub struct CaptureScope; + pub struct CaptureScopeRef; +} + +impl CaptureScopeRef { + pub fn begin_scope(&self) { + unsafe { msg_send![self, beginScope] } + } + + pub fn end_scope(&self) { + unsafe { msg_send![self, endScope] } + } + + pub fn label(&self) -> &str { + unsafe { + let label = msg_send![self, label]; + crate::nsstring_as_str(label) + } + } +} + +pub enum MTLCaptureManager {} + +foreign_obj_type! { + type CType = MTLCaptureManager; + pub struct CaptureManager; + pub struct CaptureManagerRef; +} + +impl CaptureManager { + pub fn shared<'a>() -> &'a CaptureManagerRef { + unsafe { + let class = class!(MTLCaptureManager); + msg_send![class, sharedCaptureManager] + } + } +} + +impl CaptureManagerRef { + pub fn new_capture_scope_with_device(&self, device: &DeviceRef) -> CaptureScope { + unsafe { msg_send![self, newCaptureScopeWithDevice: device] } + } + + pub fn new_capture_scope_with_command_queue( + &self, + command_queue: &CommandQueueRef, + ) -> CaptureScope { + unsafe { msg_send![self, newCaptureScopeWithCommandQueue: command_queue] } + } + + pub fn default_capture_scope(&self) -> Option<&CaptureScopeRef> { + unsafe { msg_send![self, defaultCaptureScope] } + } + + pub fn set_default_capture_scope(&self, scope: &CaptureScopeRef) { + unsafe { msg_send![self, setDefaultCaptureScope: scope] } + } + + /// https://developer.apple.com/documentation/metal/mtlcapturemanager/3237259-startcapture + pub fn start_capture(&self, descriptor: &CaptureDescriptorRef) -> Result<(), String> { + unsafe { + try_objc! { err => + msg_send![self, startCaptureWithDescriptor: descriptor + error: &mut err] + } + } + } + + pub fn start_capture_with_device(&self, device: &DeviceRef) { + unsafe { msg_send![self, startCaptureWithDevice: device] } + } + + pub fn start_capture_with_command_queue(&self, command_queue: &CommandQueueRef) { + unsafe { msg_send![self, startCaptureWithCommandQueue: command_queue] } + } + + pub fn start_capture_with_scope(&self, scope: &CaptureScopeRef) { + unsafe { msg_send![self, startCaptureWithScope: scope] } + } + + pub fn stop_capture(&self) { + unsafe { msg_send![self, stopCapture] } + } + + pub fn is_capturing(&self) -> bool { + unsafe { msg_send![self, isCapturing] } + } + + /// https://developer.apple.com/documentation/metal/mtlcapturemanager/3237260-supportsdestination?language=objc + pub fn supports_destination(&self, destination: MTLCaptureDestination) -> bool { + unsafe { msg_send![self, supportsDestination: destination] } + } +} diff --git a/third_party/rust/metal/src/commandbuffer.rs b/third_party/rust/metal/src/commandbuffer.rs new file mode 100644 index 0000000000..32a1d8fb94 --- /dev/null +++ b/third_party/rust/metal/src/commandbuffer.rs @@ -0,0 +1,158 @@ +// 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; + +#[repr(u32)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLCommandBufferStatus { + NotEnqueued = 0, + Enqueued = 1, + Committed = 2, + Scheduled = 3, + Completed = 4, + Error = 5, +} + +#[repr(u32)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLCommandBufferError { + None = 0, + Internal = 1, + Timeout = 2, + PageFault = 3, + Blacklisted = 4, + NotPermitted = 7, + OutOfMemory = 8, + InvalidResource = 9, + Memoryless = 10, + DeviceRemoved = 11, +} + +#[repr(u32)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLDispatchType { + Serial = 0, + Concurrent = 1, +} + +type CommandBufferHandler<'a> = Block<(&'a CommandBufferRef,), ()>; + +pub enum MTLCommandBuffer {} + +foreign_obj_type! { + type CType = MTLCommandBuffer; + pub struct CommandBuffer; + pub struct CommandBufferRef; +} + +impl CommandBufferRef { + 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 enqueue(&self) { + unsafe { msg_send![self, enqueue] } + } + + pub fn commit(&self) { + unsafe { msg_send![self, commit] } + } + + pub fn status(&self) -> MTLCommandBufferStatus { + unsafe { msg_send![self, status] } + } + + pub fn present_drawable(&self, drawable: &DrawableRef) { + unsafe { msg_send![self, presentDrawable: drawable] } + } + + pub fn wait_until_completed(&self) { + unsafe { msg_send![self, waitUntilCompleted] } + } + + pub fn wait_until_scheduled(&self) { + unsafe { msg_send![self, waitUntilScheduled] } + } + + pub fn add_completed_handler(&self, block: &CommandBufferHandler) { + unsafe { msg_send![self, addCompletedHandler: block] } + } + + pub fn new_blit_command_encoder(&self) -> &BlitCommandEncoderRef { + unsafe { msg_send![self, blitCommandEncoder] } + } + + pub fn new_compute_command_encoder(&self) -> &ComputeCommandEncoderRef { + unsafe { msg_send![self, computeCommandEncoder] } + } + + pub fn new_render_command_encoder( + &self, + descriptor: &RenderPassDescriptorRef, + ) -> &RenderCommandEncoderRef { + unsafe { msg_send![self, renderCommandEncoderWithDescriptor: descriptor] } + } + + pub fn new_parallel_render_command_encoder( + &self, + descriptor: &RenderPassDescriptorRef, + ) -> &ParallelRenderCommandEncoderRef { + unsafe { msg_send![self, parallelRenderCommandEncoderWithDescriptor: descriptor] } + } + + pub fn compute_command_encoder_with_dispatch_type( + &self, + ty: MTLDispatchType, + ) -> &ComputeCommandEncoderRef { + unsafe { msg_send![self, computeCommandEncoderWithDispatchType: ty] } + } + + pub fn encode_signal_event(&self, event: &EventRef, new_value: u64) { + unsafe { + msg_send![self, + encodeSignalEvent: event + value: new_value + ] + } + } + + pub fn encode_wait_for_event(&self, event: &EventRef, value: u64) { + unsafe { + msg_send![self, + encodeWaitForEvent: event + value: value + ] + } + } + + pub fn push_debug_group(&self, name: &str) { + unsafe { + let nslabel = crate::nsstring_from_str(name); + msg_send![self, pushDebugGroup: nslabel] + } + } + + pub fn pop_debug_group(&self) { + unsafe { msg_send![self, popDebugGroup] } + } +} diff --git a/third_party/rust/metal/src/commandqueue.rs b/third_party/rust/metal/src/commandqueue.rs new file mode 100644 index 0000000000..470d8dbe93 --- /dev/null +++ b/third_party/rust/metal/src/commandqueue.rs @@ -0,0 +1,44 @@ +// 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::*; + +pub enum MTLCommandQueue {} + +foreign_obj_type! { + type CType = MTLCommandQueue; + pub struct CommandQueue; + pub struct CommandQueueRef; +} + +impl CommandQueueRef { + 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 new_command_buffer(&self) -> &CommandBufferRef { + unsafe { msg_send![self, commandBuffer] } + } + + pub fn new_command_buffer_with_unretained_references(&self) -> &CommandBufferRef { + unsafe { msg_send![self, commandBufferWithUnretainedReferences] } + } + + pub fn device(&self) -> &DeviceRef { + unsafe { msg_send![self, device] } + } +} diff --git a/third_party/rust/metal/src/constants.rs b/third_party/rust/metal/src/constants.rs new file mode 100644 index 0000000000..0afbdd7e29 --- /dev/null +++ b/third_party/rust/metal/src/constants.rs @@ -0,0 +1,151 @@ +// 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. + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum MTLPixelFormat { + Invalid = 0, + A8Unorm = 1, + R8Unorm = 10, + R8Unorm_sRGB = 11, + R8Snorm = 12, + R8Uint = 13, + R8Sint = 14, + R16Unorm = 20, + R16Snorm = 22, + R16Uint = 23, + R16Sint = 24, + R16Float = 25, + RG8Unorm = 30, + RG8Unorm_sRGB = 31, + RG8Snorm = 32, + RG8Uint = 33, + RG8Sint = 34, + B5G6R5Unorm = 40, + A1BGR5Unorm = 41, + ABGR4Unorm = 42, + BGR5A1Unorm = 43, + R32Uint = 53, + R32Sint = 54, + R32Float = 55, + RG16Unorm = 60, + RG16Snorm = 62, + RG16Uint = 63, + RG16Sint = 64, + RG16Float = 65, + RGBA8Unorm = 70, + RGBA8Unorm_sRGB = 71, + RGBA8Snorm = 72, + RGBA8Uint = 73, + RGBA8Sint = 74, + BGRA8Unorm = 80, + BGRA8Unorm_sRGB = 81, + RGB10A2Unorm = 90, + RGB10A2Uint = 91, + RG11B10Float = 92, + RGB9E5Float = 93, + BGR10A2Unorm = 94, + RG32Uint = 103, + RG32Sint = 104, + RG32Float = 105, + RGBA16Unorm = 110, + RGBA16Snorm = 112, + RGBA16Uint = 113, + RGBA16Sint = 114, + RGBA16Float = 115, + RGBA32Uint = 123, + RGBA32Sint = 124, + RGBA32Float = 125, + BC1_RGBA = 130, + BC1_RGBA_sRGB = 131, + BC2_RGBA = 132, + BC2_RGBA_sRGB = 133, + BC3_RGBA = 134, + BC3_RGBA_sRGB = 135, + BC4_RUnorm = 140, + BC4_RSnorm = 141, + BC5_RGUnorm = 142, + BC5_RGSnorm = 143, + BC6H_RGBFloat = 150, + BC6H_RGBUfloat = 151, + BC7_RGBAUnorm = 152, + BC7_RGBAUnorm_sRGB = 153, + PVRTC_RGB_2BPP = 160, + PVRTC_RGB_2BPP_sRGB = 161, + PVRTC_RGB_4BPP = 162, + PVRTC_RGB_4BPP_sRGB = 163, + PVRTC_RGBA_2BPP = 164, + PVRTC_RGBA_2BPP_sRGB = 165, + PVRTC_RGBA_4BPP = 166, + PVRTC_RGBA_4BPP_sRGB = 167, + EAC_R11Unorm = 170, + EAC_R11Snorm = 172, + EAC_RG11Unorm = 174, + EAC_RG11Snorm = 176, + EAC_RGBA8 = 178, + EAC_RGBA8_sRGB = 179, + ETC2_RGB8 = 180, + ETC2_RGB8_sRGB = 181, + ETC2_RGB8A1 = 182, + ETC2_RGB8A1_sRGB = 183, + ASTC_4x4_sRGB = 186, + ASTC_5x4_sRGB = 187, + ASTC_5x5_sRGB = 188, + ASTC_6x5_sRGB = 189, + ASTC_6x6_sRGB = 190, + ASTC_8x5_sRGB = 192, + ASTC_8x6_sRGB = 193, + ASTC_8x8_sRGB = 194, + ASTC_10x5_sRGB = 195, + ASTC_10x6_sRGB = 196, + ASTC_10x8_sRGB = 197, + ASTC_10x10_sRGB = 198, + ASTC_12x10_sRGB = 199, + ASTC_12x12_sRGB = 200, + ASTC_4x4_LDR = 204, + ASTC_5x4_LDR = 205, + ASTC_5x5_LDR = 206, + ASTC_6x5_LDR = 207, + ASTC_6x6_LDR = 208, + ASTC_8x5_LDR = 210, + ASTC_8x6_LDR = 211, + ASTC_8x8_LDR = 212, + ASTC_10x5_LDR = 213, + ASTC_10x6_LDR = 214, + ASTC_10x8_LDR = 215, + ASTC_10x10_LDR = 216, + ASTC_12x10_LDR = 217, + ASTC_12x12_LDR = 218, + ASTC_4x4_HDR = 222, + ASTC_5x4_HDR = 223, + ASTC_5x5_HDR = 224, + ASTC_6x5_HDR = 225, + ASTC_6x6_HDR = 226, + ASTC_8x5_HDR = 228, + ASTC_8x6_HDR = 229, + ASTC_8x8_HDR = 230, + ASTC_10x5_HDR = 231, + ASTC_10x6_HDR = 232, + ASTC_10x8_HDR = 233, + ASTC_10x10_HDR = 234, + ASTC_12x10_HDR = 235, + ASTC_12x12_HDR = 236, + GBGR422 = 240, + BGRG422 = 241, + Depth16Unorm = 250, + Depth32Float = 252, + Stencil8 = 253, + Depth24Unorm_Stencil8 = 255, + Depth32Float_Stencil8 = 260, + X32_Stencil8 = 261, + X24_Stencil8 = 262, + BGRA10_XR = 552, + BGRA10_XR_SRGB = 553, + BGR10_XR = 554, + BGR10_XR_SRGB = 555, +} diff --git a/third_party/rust/metal/src/depthstencil.rs b/third_party/rust/metal/src/depthstencil.rs new file mode 100644 index 0000000000..5b578e6d46 --- /dev/null +++ b/third_party/rust/metal/src/depthstencil.rs @@ -0,0 +1,194 @@ +// 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 crate::DeviceRef; +use objc::runtime::{NO, YES}; + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLCompareFunction { + Never = 0, + Less = 1, + Equal = 2, + LessEqual = 3, + Greater = 4, + NotEqual = 5, + GreaterEqual = 6, + Always = 7, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLStencilOperation { + Keep = 0, + Zero = 1, + Replace = 2, + IncrementClamp = 3, + DecrementClamp = 4, + Invert = 5, + IncrementWrap = 6, + DecrementWrap = 7, +} + +pub enum MTLStencilDescriptor {} + +foreign_obj_type! { + type CType = MTLStencilDescriptor; + pub struct StencilDescriptor; + pub struct StencilDescriptorRef; +} + +impl StencilDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLStencilDescriptor); + msg_send![class, new] + } + } +} + +impl StencilDescriptorRef { + pub fn stencil_compare_function(&self) -> MTLCompareFunction { + unsafe { msg_send![self, stencilCompareFunction] } + } + + pub fn set_stencil_compare_function(&self, func: MTLCompareFunction) { + unsafe { msg_send![self, setStencilCompareFunction: func] } + } + + pub fn stencil_failure_operation(&self) -> MTLStencilOperation { + unsafe { msg_send![self, stencilFailureOperation] } + } + + pub fn set_stencil_failure_operation(&self, operation: MTLStencilOperation) { + unsafe { msg_send![self, setStencilFailureOperation: operation] } + } + + pub fn depth_failure_operation(&self) -> MTLStencilOperation { + unsafe { msg_send![self, depthFailureOperation] } + } + + pub fn set_depth_failure_operation(&self, operation: MTLStencilOperation) { + unsafe { msg_send![self, setDepthFailureOperation: operation] } + } + + pub fn depth_stencil_pass_operation(&self) -> MTLStencilOperation { + unsafe { msg_send![self, depthStencilPassOperation] } + } + + pub fn set_depth_stencil_pass_operation(&self, operation: MTLStencilOperation) { + unsafe { msg_send![self, setDepthStencilPassOperation: operation] } + } + + pub fn read_mask(&self) -> u32 { + unsafe { msg_send![self, readMask] } + } + + pub fn set_read_mask(&self, mask: u32) { + unsafe { msg_send![self, setReadMask: mask] } + } + + pub fn write_mask(&self) -> u32 { + unsafe { msg_send![self, writeMask] } + } + + pub fn set_write_mask(&self, mask: u32) { + unsafe { msg_send![self, setWriteMask: mask] } + } +} + +pub enum MTLDepthStencilDescriptor {} + +foreign_obj_type! { + type CType = MTLDepthStencilDescriptor; + pub struct DepthStencilDescriptor; + pub struct DepthStencilDescriptorRef; +} + +impl DepthStencilDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLDepthStencilDescriptor); + msg_send![class, new] + } + } +} + +impl DepthStencilDescriptorRef { + pub fn depth_compare_function(&self) -> MTLCompareFunction { + unsafe { msg_send![self, depthCompareFunction] } + } + + pub fn set_depth_compare_function(&self, func: MTLCompareFunction) { + unsafe { msg_send![self, setDepthCompareFunction: func] } + } + + pub fn depth_write_enabled(&self) -> bool { + unsafe { + match msg_send![self, isDepthWriteEnabled] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_depth_write_enabled(&self, enabled: bool) { + unsafe { msg_send![self, setDepthWriteEnabled: enabled] } + } + + pub fn front_face_stencil(&self) -> Option<&StencilDescriptorRef> { + unsafe { msg_send![self, frontFaceStencil] } + } + + pub fn set_front_face_stencil(&self, descriptor: Option<&StencilDescriptorRef>) { + unsafe { msg_send![self, setFrontFaceStencil: descriptor] } + } + + pub fn back_face_stencil(&self) -> Option<&StencilDescriptorRef> { + unsafe { msg_send![self, backFaceStencil] } + } + + pub fn set_back_face_stencil(&self, descriptor: Option<&StencilDescriptorRef>) { + unsafe { msg_send![self, setBackFaceStencil: descriptor] } + } + + 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 enum MTLDepthStencilState {} + +foreign_obj_type! { + type CType = MTLDepthStencilState; + pub struct DepthStencilState; + pub struct DepthStencilStateRef; +} + +impl DepthStencilStateRef { + 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) + } + } +} diff --git a/third_party/rust/metal/src/device.rs b/third_party/rust/metal/src/device.rs new file mode 100644 index 0000000000..1cb0a40783 --- /dev/null +++ b/third_party/rust/metal/src/device.rs @@ -0,0 +1,2117 @@ +// 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 block::{Block, ConcreteBlock}; +use foreign_types::ForeignType; +use objc::runtime::{Object, NO, YES}; + +use std::{ffi::CStr, os::raw::c_char, path::Path, ptr}; + +// Available on macOS 10.11+, iOS 8.0+, tvOS 9.0+ +#[allow(non_camel_case_types)] +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLFeatureSet { + iOS_GPUFamily1_v1 = 0, + iOS_GPUFamily2_v1 = 1, + iOS_GPUFamily1_v2 = 2, + iOS_GPUFamily2_v2 = 3, + iOS_GPUFamily3_v1 = 4, + iOS_GPUFamily1_v3 = 5, + iOS_GPUFamily2_v3 = 6, + iOS_GPUFamily3_v2 = 7, + iOS_GPUFamily1_v4 = 8, + iOS_GPUFamily2_v4 = 9, + iOS_GPUFamily3_v3 = 10, + iOS_GPUFamily4_v1 = 11, + iOS_GPUFamily1_v5 = 12, + iOS_GPUFamily2_v5 = 13, + iOS_GPUFamily3_v4 = 14, + iOS_GPUFamily4_v2 = 15, + iOS_GPUFamily5_v1 = 16, + + tvOS_GPUFamily1_v1 = 30000, + tvOS_GPUFamily1_v2 = 30001, + tvOS_GPUFamily1_v3 = 30002, + tvOS_GPUFamily2_v1 = 30003, + tvOS_GPUFamily1_v4 = 30004, + tvOS_GPUFamily2_v2 = 30005, + + macOS_GPUFamily1_v1 = 10000, + macOS_GPUFamily1_v2 = 10001, + // Available on macOS 10.12+ + macOS_ReadWriteTextureTier2 = 10002, + macOS_GPUFamily1_v3 = 10003, + macOS_GPUFamily1_v4 = 10004, + macOS_GPUFamily2_v1 = 10005, +} + +// Available on macOS 10.15+, iOS 13.0+ +#[repr(i64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[non_exhaustive] +pub enum MTLGPUFamily { + Common1 = 3001, + Common2 = 3002, + Common3 = 3003, + Apple1 = 1001, + Apple2 = 1002, + Apple3 = 1003, + Apple4 = 1004, + Apple5 = 1005, + Apple6 = 1006, + Apple7 = 1007, + Apple8 = 1008, + Apple9 = 1009, + Mac1 = 2001, + Mac2 = 2002, + MacCatalyst1 = 4001, + MacCatalyst2 = 4002, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLDeviceLocation { + BuiltIn = 0, + Slot = 1, + External = 2, + Unspecified = u64::MAX, +} + +bitflags! { + pub struct PixelFormatCapabilities: u32 { + const Filter = 1 << 0; + const Write = 1 << 1; + const Color = 1 << 2; + const Blend = 1 << 3; + const Msaa = 1 << 4; + const Resolve = 1 << 5; + } +} + +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +enum OS { + iOS, + tvOS, + macOS, +} + +const KB: u32 = 1024; +const MB: u32 = 1024 * KB; +const GB: u32 = 1024 * MB; + +impl MTLFeatureSet { + fn os(&self) -> OS { + let value = *self as u64; + if value < 10_000 { + OS::iOS + } else if value < 20_000 { + OS::macOS + } else if value >= 30_000 || value < 40_000 { + OS::tvOS + } else { + unreachable!() + } + } + + // returns the minor version on macos + fn os_version(&self) -> u32 { + use MTLFeatureSet::*; + match self { + iOS_GPUFamily1_v1 | iOS_GPUFamily2_v1 => 8, + iOS_GPUFamily1_v2 | iOS_GPUFamily2_v2 | iOS_GPUFamily3_v1 => 9, + iOS_GPUFamily1_v3 | iOS_GPUFamily2_v3 | iOS_GPUFamily3_v2 => 10, + iOS_GPUFamily1_v4 | iOS_GPUFamily2_v4 | iOS_GPUFamily3_v3 | iOS_GPUFamily4_v1 => 11, + iOS_GPUFamily1_v5 | iOS_GPUFamily2_v5 | iOS_GPUFamily3_v4 | iOS_GPUFamily4_v2 + | iOS_GPUFamily5_v1 => 12, + tvOS_GPUFamily1_v1 => 9, + tvOS_GPUFamily1_v2 => 10, + tvOS_GPUFamily1_v3 | tvOS_GPUFamily2_v1 => 11, + tvOS_GPUFamily1_v4 | tvOS_GPUFamily2_v2 => 12, + macOS_GPUFamily1_v1 => 11, + macOS_GPUFamily1_v2 | macOS_ReadWriteTextureTier2 => 12, + macOS_GPUFamily1_v3 => 13, + macOS_GPUFamily1_v4 | macOS_GPUFamily2_v1 => 14, + } + } + + fn gpu_family(&self) -> u32 { + use MTLFeatureSet::*; + match self { + iOS_GPUFamily1_v1 + | iOS_GPUFamily1_v2 + | iOS_GPUFamily1_v3 + | iOS_GPUFamily1_v4 + | iOS_GPUFamily1_v5 + | tvOS_GPUFamily1_v1 + | tvOS_GPUFamily1_v2 + | tvOS_GPUFamily1_v3 + | tvOS_GPUFamily1_v4 + | macOS_GPUFamily1_v1 + | macOS_GPUFamily1_v2 + | macOS_ReadWriteTextureTier2 + | macOS_GPUFamily1_v3 + | macOS_GPUFamily1_v4 => 1, + iOS_GPUFamily2_v1 | iOS_GPUFamily2_v2 | iOS_GPUFamily2_v3 | iOS_GPUFamily2_v4 + | iOS_GPUFamily2_v5 | tvOS_GPUFamily2_v1 | tvOS_GPUFamily2_v2 | macOS_GPUFamily2_v1 => { + 2 + } + iOS_GPUFamily3_v1 | iOS_GPUFamily3_v2 | iOS_GPUFamily3_v3 | iOS_GPUFamily3_v4 => 3, + iOS_GPUFamily4_v1 | iOS_GPUFamily4_v2 => 4, + iOS_GPUFamily5_v1 => 5, + } + } + + fn version(&self) -> u32 { + use MTLFeatureSet::*; + match self { + iOS_GPUFamily1_v1 + | iOS_GPUFamily2_v1 + | iOS_GPUFamily3_v1 + | iOS_GPUFamily4_v1 + | iOS_GPUFamily5_v1 + | macOS_GPUFamily1_v1 + | macOS_GPUFamily2_v1 + | macOS_ReadWriteTextureTier2 + | tvOS_GPUFamily1_v1 + | tvOS_GPUFamily2_v1 => 1, + iOS_GPUFamily1_v2 | iOS_GPUFamily2_v2 | iOS_GPUFamily3_v2 | iOS_GPUFamily4_v2 + | macOS_GPUFamily1_v2 | tvOS_GPUFamily1_v2 | tvOS_GPUFamily2_v2 => 2, + iOS_GPUFamily1_v3 | iOS_GPUFamily2_v3 | iOS_GPUFamily3_v3 | macOS_GPUFamily1_v3 + | tvOS_GPUFamily1_v3 => 3, + iOS_GPUFamily1_v4 | iOS_GPUFamily2_v4 | iOS_GPUFamily3_v4 | tvOS_GPUFamily1_v4 + | macOS_GPUFamily1_v4 => 4, + iOS_GPUFamily1_v5 | iOS_GPUFamily2_v5 => 5, + } + } + + pub fn supports_metal_kit(&self) -> bool { + true + } + + pub fn supports_metal_performance_shaders(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 2, + OS::tvOS => true, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_programmable_blending(&self) -> bool { + self.os() != OS::macOS + } + + pub fn supports_pvrtc_pixel_formats(&self) -> bool { + self.os() != OS::macOS + } + + pub fn supports_eac_etc_pixel_formats(&self) -> bool { + self.os() != OS::macOS + } + + pub fn supports_astc_pixel_formats(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 2, + OS::tvOS => true, + OS::macOS => false, + } + } + + pub fn supports_linear_textures(&self) -> bool { + self.os() != OS::macOS || self.os_version() >= 13 + } + + pub fn supports_bc_pixel_formats(&self) -> bool { + self.os() == OS::macOS + } + + pub fn supports_msaa_depth_resolve(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => false, + } + } + + pub fn supports_counting_occlusion_query(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => true, + } + } + + pub fn supports_base_vertex_instance_drawing(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => true, + } + } + + pub fn supports_indirect_buffers(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => true, + } + } + + pub fn supports_cube_map_texture_arrays(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 4, + OS::tvOS => false, + OS::macOS => true, + } + } + + pub fn supports_texture_barriers(&self) -> bool { + self.os() == OS::macOS + } + + pub fn supports_layered_rendering(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 5, + OS::tvOS => false, + OS::macOS => true, + } + } + + pub fn supports_tessellation(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3 && self.os_version() >= 10, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => self.os_version() >= 12, + } + } + + pub fn supports_resource_heaps(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 10, + OS::tvOS => self.os_version() >= 10, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_memoryless_render_targets(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 10, + OS::tvOS => self.os_version() >= 10, + OS::macOS => false, + } + } + + pub fn supports_function_specialization(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 10, + OS::tvOS => self.os_version() >= 10, + OS::macOS => self.os_version() >= 12, + } + } + + pub fn supports_function_buffer_read_writes(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3 && self.os_version() >= 10, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => self.os_version() >= 12, + } + } + + pub fn supports_function_texture_read_writes(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 4, + OS::tvOS => false, + OS::macOS => self.os_version() >= 12, + } + } + + pub fn supports_array_of_textures(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3 && self.os_version() >= 10, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_array_of_samplers(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3 && self.os_version() >= 11, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => self.os_version() >= 12, + } + } + + pub fn supports_stencil_texture_views(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 10, + OS::tvOS => self.os_version() >= 10, + OS::macOS => self.os_version() >= 12, + } + } + + pub fn supports_depth_16_pixel_format(&self) -> bool { + self.os() == OS::macOS && self.os_version() >= 12 + } + + pub fn supports_extended_range_pixel_formats(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3 && self.os_version() >= 10, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => false, + } + } + + pub fn supports_wide_color_pixel_format(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 11, + OS::tvOS => self.os_version() >= 11, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_combined_msaa_store_and_resolve_action(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3 && self.os_version() >= 10, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => self.os_version() >= 12, + } + } + + pub fn supports_deferred_store_action(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 10, + OS::tvOS => self.os_version() >= 10, + OS::macOS => self.os_version() >= 12, + } + } + + pub fn supports_msaa_blits(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 10, + OS::tvOS => self.os_version() >= 10, + OS::macOS => true, + } + } + + pub fn supports_srgb_writes(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3 || (self.gpu_family() >= 2 && self.version() >= 3), + OS::tvOS => self.os_version() >= 10, + OS::macOS => self.gpu_family() >= 2, + } + } + + pub fn supports_16_bit_unsigned_integer_coordinates(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 10, + OS::tvOS => self.os_version() >= 10, + OS::macOS => self.os_version() >= 12, + } + } + + pub fn supports_extract_insert_and_reverse_bits(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 10, + OS::tvOS => self.os_version() >= 10, + OS::macOS => self.os_version() >= 12, + } + } + + pub fn supports_simd_barrier(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 10, + OS::tvOS => self.os_version() >= 10, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_sampler_max_anisotropy(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 10, + OS::tvOS => self.os_version() >= 10, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_sampler_lod_clamp(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 10, + OS::tvOS => self.os_version() >= 10, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_border_color(&self) -> bool { + self.os() == OS::macOS && self.os_version() >= 12 + } + + pub fn supports_dual_source_blending(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 11, + OS::tvOS => self.os_version() >= 11, + OS::macOS => self.os_version() >= 12, + } + } + + pub fn supports_argument_buffers(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 11, + OS::tvOS => self.os_version() >= 11, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_programmable_sample_positions(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 11, + OS::tvOS => self.os_version() >= 11, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_uniform_type(&self) -> bool { + match self.os() { + OS::iOS => self.os_version() >= 11, + OS::tvOS => self.os_version() >= 11, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_imageblocks(&self) -> bool { + self.os() == OS::iOS && self.gpu_family() >= 4 + } + + pub fn supports_tile_shaders(&self) -> bool { + self.os() == OS::iOS && self.gpu_family() >= 4 + } + + pub fn supports_imageblock_sample_coverage_control(&self) -> bool { + self.os() == OS::iOS && self.gpu_family() >= 4 + } + + pub fn supports_threadgroup_sharing(&self) -> bool { + self.os() == OS::iOS && self.gpu_family() >= 4 + } + + pub fn supports_post_depth_coverage(&self) -> bool { + self.os() == OS::iOS && self.gpu_family() >= 4 + } + + pub fn supports_quad_scoped_permute_operations(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 4, + OS::tvOS => false, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_raster_order_groups(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 4, + OS::tvOS => false, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_non_uniform_threadgroup_size(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 4, + OS::tvOS => false, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_multiple_viewports(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 5, + OS::tvOS => false, + OS::macOS => self.os_version() >= 13, + } + } + + pub fn supports_device_notifications(&self) -> bool { + self.os() == OS::macOS && self.os_version() >= 13 + } + + pub fn supports_stencil_feedback(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 5, + OS::tvOS => false, + OS::macOS => self.gpu_family() >= 2, + } + } + + pub fn supports_stencil_resolve(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 5, + OS::tvOS => false, + OS::macOS => self.gpu_family() >= 2, + } + } + + pub fn supports_binary_archive(&self) -> bool { + match self.os() { + OS::iOS => self.gpu_family() >= 3, + OS::tvOS => self.gpu_family() >= 3, + OS::macOS => self.gpu_family() >= 1, + } + } + + pub fn max_vertex_attributes(&self) -> u32 { + 31 + } + + pub fn max_buffer_argument_entries(&self) -> u32 { + 31 + } + + pub fn max_texture_argument_entries(&self) -> u32 { + if self.os() == OS::macOS { + 128 + } else { + 31 + } + } + + pub fn max_sampler_state_argument_entries(&self) -> u32 { + 16 + } + + pub fn max_threadgroup_memory_argument_entries(&self) -> u32 { + 31 + } + + pub fn max_inlined_constant_data_buffers(&self) -> u32 { + if self.os() == OS::macOS { + 14 + } else { + 31 + } + } + + pub fn max_inline_constant_buffer_length(&self) -> u32 { + 4 * KB + } + + pub fn max_threads_per_threadgroup(&self) -> u32 { + if self.os() == OS::macOS || self.gpu_family() >= 4 { + 1024 + } else { + 512 + } + } + + pub fn max_total_threadgroup_memory_allocation(&self) -> u32 { + match (self.os(), self.gpu_family()) { + (OS::iOS, 5) => 64 * KB, + (OS::iOS, 4) => { + if self.os_version() >= 12 { + 64 * KB + } else { + 32 * KB + } + } + (OS::iOS, 3) => 16 * KB, + (OS::iOS, _) => 16 * KB - 32, + (OS::tvOS, 1) => 16 * KB - 32, + (OS::tvOS, _) => 16 * KB, + (OS::macOS, _) => 32 * KB, + } + } + + pub fn max_total_tile_memory_allocation(&self) -> u32 { + if self.os() == OS::iOS && self.gpu_family() == 4 { + 32 * KB + } else { + 0 + } + } + + pub fn threadgroup_memory_length_alignment(&self) -> u32 { + 16 + } + + pub fn max_constant_buffer_function_memory_allocation(&self) -> Option { + if self.os() == OS::macOS { + Some(64 * KB) + } else { + None + } + } + + pub fn max_fragment_inputs(&self) -> u32 { + if self.os() == OS::macOS { + 32 + } else { + 60 + } + } + + pub fn max_fragment_input_components(&self) -> u32 { + if self.os() == OS::macOS { + 128 + } else { + 60 + } + } + + pub fn max_function_constants(&self) -> u32 { + match self.os() { + OS::iOS if self.os_version() >= 11 => 65536, + OS::tvOS if self.os_version() >= 10 => 65536, + OS::macOS if self.os_version() >= 12 => 65536, + _ => 0, + } + } + + pub fn max_tessellation_factor(&self) -> u32 { + if self.supports_tessellation() { + match self.os() { + OS::iOS if self.gpu_family() >= 5 => 64, + OS::iOS => 16, + OS::tvOS => 16, + OS::macOS => 64, + } + } else { + 0 + } + } + + pub fn max_viewports_and_scissor_rectangles(&self) -> u32 { + if self.supports_multiple_viewports() { + 16 + } else { + 1 + } + } + + pub fn max_raster_order_groups(&self) -> u32 { + if self.supports_raster_order_groups() { + 8 + } else { + 0 + } + } + + pub fn max_buffer_length(&self) -> u32 { + if self.os() == OS::macOS && self.os_version() >= 12 { + 1 * GB + } else { + 256 * MB + } + } + + pub fn min_buffer_offset_alignment(&self) -> u32 { + if self.os() == OS::macOS { + 256 + } else { + 4 + } + } + + pub fn max_1d_texture_size(&self) -> u32 { + match (self.os(), self.gpu_family()) { + (OS::iOS, 1) | (OS::iOS, 2) => { + if self.version() <= 2 { + 4096 + } else { + 8192 + } + } + (OS::tvOS, 1) => 8192, + _ => 16384, + } + } + + pub fn max_2d_texture_size(&self) -> u32 { + match (self.os(), self.gpu_family()) { + (OS::iOS, 1) | (OS::iOS, 2) => { + if self.version() <= 2 { + 4096 + } else { + 8192 + } + } + (OS::tvOS, 1) => 8192, + _ => 16384, + } + } + + pub fn max_cube_map_texture_size(&self) -> u32 { + match (self.os(), self.gpu_family()) { + (OS::iOS, 1) | (OS::iOS, 2) => { + if self.version() <= 2 { + 4096 + } else { + 8192 + } + } + (OS::tvOS, 1) => 8192, + _ => 16384, + } + } + + pub fn max_3d_texture_size(&self) -> u32 { + 2048 + } + + pub fn max_array_layers(&self) -> u32 { + 2048 + } + + pub fn copy_texture_buffer_alignment(&self) -> u32 { + match (self.os(), self.gpu_family()) { + (OS::iOS, 1) | (OS::iOS, 2) | (OS::tvOS, 1) => 64, + (OS::iOS, _) | (OS::tvOS, _) => 16, + (OS::macOS, _) => 256, + } + } + + /// If this function returns `None` but linear textures are supported, + /// the buffer alignment can be discovered via API query + pub fn new_texture_buffer_alignment(&self) -> Option { + match self.os() { + OS::iOS => { + if self.os_version() >= 11 { + None + } else if self.gpu_family() == 3 { + Some(16) + } else { + Some(64) + } + } + OS::tvOS => { + if self.os_version() >= 11 { + None + } else { + Some(64) + } + } + OS::macOS => None, + } + } + + pub fn max_color_render_targets(&self) -> u32 { + if self.os() == OS::iOS && self.gpu_family() == 1 { + 4 + } else { + 8 + } + } + + pub fn max_point_primitive_size(&self) -> u32 { + 511 + } + + pub fn max_total_color_render_target_size(&self) -> Option { + match (self.os(), self.gpu_family()) { + (OS::iOS, 1) => Some(128), + (OS::iOS, 2) | (OS::iOS, 3) => Some(256), + (OS::iOS, _) => Some(512), + (OS::tvOS, _) => Some(256), + (OS::macOS, _) => None, + } + } + + pub fn max_visibility_query_offset(&self) -> u32 { + 64 * KB - 8 + } + + pub fn a8_unorm_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Filter + } + + pub fn r8_unorm_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::all() + } + + pub fn r8_unorm_srgb_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::empty() + } else if self.supports_srgb_writes() { + PixelFormatCapabilities::all() + } else { + !PixelFormatCapabilities::Write + } + } + + pub fn r8_snorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::iOS && self.gpu_family() == 1 { + !PixelFormatCapabilities::Resolve + } else { + PixelFormatCapabilities::all() + } + } + + pub fn r8_uint_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } + + pub fn r8_sint_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } + + pub fn r16_unorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() != OS::macOS { + !PixelFormatCapabilities::Resolve + } else { + PixelFormatCapabilities::all() + } + } + + pub fn r16_snorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() != OS::macOS { + !PixelFormatCapabilities::Resolve + } else { + PixelFormatCapabilities::all() + } + } + + pub fn r16_uint_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } + + pub fn r16_sint_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } + + pub fn r16_float_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::all() + } + + pub fn rg8_unorm_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::all() + } + + pub fn rg8_unorm_srgb_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::empty() + } else if self.supports_srgb_writes() { + PixelFormatCapabilities::all() + } else { + !PixelFormatCapabilities::Write + } + } + + pub fn rg8_snorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::iOS && self.gpu_family() == 1 { + !PixelFormatCapabilities::Resolve + } else { + PixelFormatCapabilities::all() + } + } + + pub fn rg8_uint_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } + + pub fn rg8_sint_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } + + pub fn b5_g6_r5_unorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::empty() + } else { + !PixelFormatCapabilities::Write + } + } + + pub fn a1_bgr5_unorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::empty() + } else { + !PixelFormatCapabilities::Write + } + } + + pub fn abgr4_unorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::empty() + } else { + !PixelFormatCapabilities::Write + } + } + + pub fn bgr5_a1_unorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::empty() + } else { + !PixelFormatCapabilities::Write + } + } + + pub fn r32_uint_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::iOS && self.os_version() == 8 { + PixelFormatCapabilities::Color + } else if self.os() == OS::macOS { + PixelFormatCapabilities::Color + | PixelFormatCapabilities::Write + | PixelFormatCapabilities::Msaa + } else { + PixelFormatCapabilities::Color | PixelFormatCapabilities::Write + } + } + + pub fn r32_sint_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::iOS && self.os_version() == 8 { + PixelFormatCapabilities::Color + } else if self.os() == OS::macOS { + PixelFormatCapabilities::Color + | PixelFormatCapabilities::Write + | PixelFormatCapabilities::Msaa + } else { + PixelFormatCapabilities::Color | PixelFormatCapabilities::Write + } + } + + pub fn r32_float_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::iOS && self.os_version() == 8 { + PixelFormatCapabilities::Color + | PixelFormatCapabilities::Blend + | PixelFormatCapabilities::Msaa + } else if self.os() == OS::macOS { + PixelFormatCapabilities::all() + } else { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Blend + | PixelFormatCapabilities::Msaa + } + } + + pub fn rg16_unorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::all() + } else { + !PixelFormatCapabilities::Resolve + } + } + + pub fn rg16_snorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::all() + } else { + !PixelFormatCapabilities::Resolve + } + } + + pub fn rg16_uint_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } + + pub fn rg16_sint_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } + + pub fn rg16_float_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::all() + } + + pub fn rgba8_unorm_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::all() + } + + pub fn rgba8_unorm_srgb_capabilities(&self) -> PixelFormatCapabilities { + if self.supports_srgb_writes() { + PixelFormatCapabilities::all() + } else { + !PixelFormatCapabilities::Write + } + } + + pub fn rgba8_snorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::iOS && self.gpu_family() == 1 { + !PixelFormatCapabilities::Resolve + } else { + PixelFormatCapabilities::all() + } + } + + pub fn rgba8_uint_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } + + pub fn rgba8_sint_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } + + pub fn bgra8_unorm_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::all() + } + + pub fn bgra8_unorm_srgb_capabilities(&self) -> PixelFormatCapabilities { + if self.supports_srgb_writes() { + PixelFormatCapabilities::all() + } else { + !PixelFormatCapabilities::Write + } + } + + pub fn rgb10_a2_unorm_capabilities(&self) -> PixelFormatCapabilities { + let supports_writes = match self.os() { + OS::iOS => self.gpu_family() >= 3, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => true, + }; + if supports_writes { + PixelFormatCapabilities::all() + } else { + !PixelFormatCapabilities::Write + } + } + + pub fn rgb10_a2_uint_capabilities(&self) -> PixelFormatCapabilities { + let supports_writes = match self.os() { + OS::iOS => self.gpu_family() >= 3, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => true, + }; + if supports_writes { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } else { + PixelFormatCapabilities::Color | PixelFormatCapabilities::Msaa + } + } + + pub fn rg11_b10_float_capabilities(&self) -> PixelFormatCapabilities { + let supports_writes = match self.os() { + OS::iOS => self.gpu_family() >= 3, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => true, + }; + if supports_writes { + PixelFormatCapabilities::all() + } else { + !PixelFormatCapabilities::Write + } + } + + pub fn rgb9_e5_float_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::Filter + } else { + let supports_writes = match self.os() { + OS::iOS => self.gpu_family() >= 3, + OS::tvOS => self.gpu_family() >= 2, + OS::macOS => false, + }; + if supports_writes { + PixelFormatCapabilities::all() + } else { + !PixelFormatCapabilities::Write + } + } + } + + pub fn rg32_uint_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::iOS && self.os_version() == 8 { + PixelFormatCapabilities::Color + } else if self.os() == OS::macOS { + PixelFormatCapabilities::Color + | PixelFormatCapabilities::Write + | PixelFormatCapabilities::Msaa + } else { + PixelFormatCapabilities::Color | PixelFormatCapabilities::Write + } + } + + pub fn rg32_sint_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::iOS && self.os_version() == 8 { + PixelFormatCapabilities::Color + } else if self.os() == OS::macOS { + PixelFormatCapabilities::Color + | PixelFormatCapabilities::Write + | PixelFormatCapabilities::Msaa + } else { + PixelFormatCapabilities::Color | PixelFormatCapabilities::Write + } + } + + pub fn rg32_float_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::all() + } else if self.os() == OS::iOS && self.os_version() == 8 { + PixelFormatCapabilities::Color | PixelFormatCapabilities::Blend + } else { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Blend + } + } + + pub fn rgba16_unorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::all() + } else { + !PixelFormatCapabilities::Write + } + } + + pub fn rgba16_snorm_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::all() + } else { + !PixelFormatCapabilities::Write + } + } + + pub fn rgba16_uint_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } + + pub fn rgba16_sint_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Write + | PixelFormatCapabilities::Color + | PixelFormatCapabilities::Msaa + } + + pub fn rgba16_float_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::all() + } + + pub fn rgba32_uint_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::iOS && self.os_version() == 8 { + PixelFormatCapabilities::Color + } else if self.os() == OS::macOS { + PixelFormatCapabilities::Color + | PixelFormatCapabilities::Write + | PixelFormatCapabilities::Msaa + } else { + PixelFormatCapabilities::Color | PixelFormatCapabilities::Write + } + } + + pub fn rgba32_sint_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::iOS && self.os_version() == 8 { + PixelFormatCapabilities::Color + } else if self.os() == OS::macOS { + PixelFormatCapabilities::Color + | PixelFormatCapabilities::Write + | PixelFormatCapabilities::Msaa + } else { + PixelFormatCapabilities::Color | PixelFormatCapabilities::Write + } + } + + pub fn rgba32_float_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::all() + } else if self.os() == OS::iOS && self.version() == 8 { + PixelFormatCapabilities::Color + } else { + PixelFormatCapabilities::Write | PixelFormatCapabilities::Color + } + } + + pub fn pvrtc_pixel_formats_capabilities(&self) -> PixelFormatCapabilities { + if self.supports_pvrtc_pixel_formats() { + PixelFormatCapabilities::Filter + } else { + PixelFormatCapabilities::empty() + } + } + + pub fn eac_etc_pixel_formats_capabilities(&self) -> PixelFormatCapabilities { + if self.supports_eac_etc_pixel_formats() { + PixelFormatCapabilities::Filter + } else { + PixelFormatCapabilities::empty() + } + } + + pub fn astc_pixel_formats_capabilities(&self) -> PixelFormatCapabilities { + if self.supports_astc_pixel_formats() { + PixelFormatCapabilities::Filter + } else { + PixelFormatCapabilities::empty() + } + } + + pub fn bc_pixel_formats_capabilities(&self) -> PixelFormatCapabilities { + if self.supports_bc_pixel_formats() { + PixelFormatCapabilities::Filter + } else { + PixelFormatCapabilities::empty() + } + } + + pub fn gbgr422_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Filter + } + + pub fn bgrg422_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Filter + } + + pub fn depth16_unorm_capabilities(&self) -> PixelFormatCapabilities { + if self.supports_depth_16_pixel_format() { + PixelFormatCapabilities::Filter + | PixelFormatCapabilities::Msaa + | PixelFormatCapabilities::Resolve + } else { + PixelFormatCapabilities::empty() + } + } + + pub fn depth32_float_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::Filter + | PixelFormatCapabilities::Msaa + | PixelFormatCapabilities::Resolve + } else if self.supports_msaa_depth_resolve() { + PixelFormatCapabilities::Msaa | PixelFormatCapabilities::Resolve + } else { + PixelFormatCapabilities::Msaa + } + } + + pub fn stencil8_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Msaa + } + + pub fn depth24_unorm_stencil8_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::Filter + | PixelFormatCapabilities::Msaa + | PixelFormatCapabilities::Resolve + } else { + PixelFormatCapabilities::empty() + } + } + + pub fn depth32_float_stencil8_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::Filter + | PixelFormatCapabilities::Msaa + | PixelFormatCapabilities::Resolve + } else if self.supports_msaa_depth_resolve() { + PixelFormatCapabilities::Msaa | PixelFormatCapabilities::Resolve + } else { + PixelFormatCapabilities::Msaa + } + } + + pub fn x24_stencil8_capabilities(&self) -> PixelFormatCapabilities { + if self.os() == OS::macOS { + PixelFormatCapabilities::Msaa + } else { + PixelFormatCapabilities::empty() + } + } + + pub fn x32_stencil8_capabilities(&self) -> PixelFormatCapabilities { + PixelFormatCapabilities::Msaa + } + + pub fn bgra10_xr_capabilities(&self) -> PixelFormatCapabilities { + if self.supports_extended_range_pixel_formats() { + PixelFormatCapabilities::all() + } else { + PixelFormatCapabilities::empty() + } + } + + pub fn bgra10_xr_srgb_capabilities(&self) -> PixelFormatCapabilities { + if self.supports_extended_range_pixel_formats() { + PixelFormatCapabilities::all() + } else { + PixelFormatCapabilities::empty() + } + } + + pub fn bgr10_xr_capabilities(&self) -> PixelFormatCapabilities { + if self.supports_extended_range_pixel_formats() { + PixelFormatCapabilities::all() + } else { + PixelFormatCapabilities::empty() + } + } + + pub fn bgr10_xr_srgb_capabilities(&self) -> PixelFormatCapabilities { + if self.supports_extended_range_pixel_formats() { + PixelFormatCapabilities::all() + } else { + PixelFormatCapabilities::empty() + } + } + + pub fn bgr10_a2_unorm_capabilities(&self) -> PixelFormatCapabilities { + if self.supports_wide_color_pixel_format() { + if self.os() == OS::macOS { + !PixelFormatCapabilities::Write + } else { + PixelFormatCapabilities::all() + } + } else { + PixelFormatCapabilities::empty() + } + } +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLArgumentBuffersTier { + Tier1 = 0, + Tier2 = 1, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLReadWriteTextureTier { + TierNone = 0, + Tier1 = 1, + Tier2 = 2, +} + +/// Only available on (macos(11.0), ios(14.0)) +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLCounterSamplingPoint { + AtStageBoundary = 0, + AtDrawBoundary = 1, + AtDispatchBoundary = 2, + AtTileDispatchBoundary = 3, + AtBlitBoundary = 4, +} + +/// Only available on (macos(11.0), macCatalyst(14.0), ios(13.0)) +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLSparseTextureRegionAlignmentMode { + Outward = 0, + Inward = 1, +} + +bitflags! { + /// Options that determine how Metal prepares the pipeline. + pub struct MTLPipelineOption: NSUInteger { + /// Do not provide any reflection information. + const None = 0; + /// An option that requests argument information for buffers, textures, and threadgroup memory. + const ArgumentInfo = 1 << 0; + /// An option that requests detailed buffer type information for buffer arguments. + const BufferTypeInfo = 1 << 1; + /// An option that specifies that Metal should create the pipeline state object only if the + /// compiled shader is present inside the binary archive. + /// + /// Only available on (macos(11.0), ios(14.0)) + const FailOnBinaryArchiveMiss = 1 << 2; + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[repr(C)] +pub struct MTLAccelerationStructureSizes { + pub acceleration_structure_size: NSUInteger, + pub build_scratch_buffer_size: NSUInteger, + pub refit_scratch_buffer_size: NSUInteger, +} + +#[link(name = "Metal", kind = "framework")] +extern "C" { + fn MTLCreateSystemDefaultDevice() -> *mut MTLDevice; + #[cfg(not(target_os = "ios"))] + fn MTLCopyAllDevices() -> *mut Object; //TODO: Array +} + +#[allow(non_camel_case_types)] +type dispatch_data_t = *mut Object; +#[allow(non_camel_case_types)] +pub type dispatch_queue_t = *mut Object; +#[allow(non_camel_case_types)] +type dispatch_block_t = *const Block<(), ()>; + +#[cfg_attr( + any(target_os = "macos", target_os = "ios"), + link(name = "System", kind = "dylib") +)] +#[cfg_attr( + not(any(target_os = "macos", target_os = "ios")), + link(name = "dispatch", kind = "dylib") +)] +#[allow(improper_ctypes)] +extern "C" { + static _dispatch_main_q: dispatch_queue_t; + + fn dispatch_data_create( + buffer: *const std::ffi::c_void, + size: crate::c_size_t, + queue: dispatch_queue_t, + destructor: dispatch_block_t, + ) -> dispatch_data_t; + fn dispatch_release(object: dispatch_data_t); // actually dispatch_object_t +} + +/*type MTLNewLibraryCompletionHandler = extern fn(library: id, error: id); +type MTLNewRenderPipelineStateCompletionHandler = extern fn(renderPipelineState: id, error: id); +type MTLNewRenderPipelineStateWithReflectionCompletionHandler = extern fn(renderPipelineState: id, reflection: id, error: id); +type MTLNewComputePipelineStateCompletionHandler = extern fn(computePipelineState: id, error: id); +type MTLNewComputePipelineStateWithReflectionCompletionHandler = extern fn(computePipelineState: id, reflection: id, error: id);*/ + +pub enum MTLDevice {} + +foreign_obj_type! { + type CType = MTLDevice; + pub struct Device; + pub struct DeviceRef; +} + +impl Device { + pub fn system_default() -> Option { + // `MTLCreateSystemDefaultDevice` may return null if Metal is not supported + unsafe { MTLCreateSystemDefaultDevice().as_mut().map(|x| Self(x)) } + } + + pub fn all() -> Vec { + #[cfg(target_os = "ios")] + { + Self::system_default().into_iter().collect() + } + #[cfg(not(target_os = "ios"))] + unsafe { + let array = MTLCopyAllDevices(); + let count: NSUInteger = msg_send![array, count]; + let ret = (0..count) + .map(|i| msg_send![array, objectAtIndex: i]) + // The elements of this array are references---we convert them to owned references + // (which just means that we increment the reference count here, and it is + // decremented in the `Drop` impl for `Device`) + .map(|device: *mut Object| msg_send![device, retain]) + .collect(); + let () = msg_send![array, release]; + ret + } + } +} + +impl DeviceRef { + pub fn name(&self) -> &str { + unsafe { + let name = msg_send![self, name]; + crate::nsstring_as_str(name) + } + } + + #[cfg(feature = "private")] + pub unsafe fn vendor(&self) -> &str { + let name = msg_send![self, vendorName]; + crate::nsstring_as_str(name) + } + + #[cfg(feature = "private")] + pub unsafe fn family_name(&self) -> &str { + let name = msg_send![self, familyName]; + crate::nsstring_as_str(name) + } + + pub fn registry_id(&self) -> u64 { + unsafe { msg_send![self, registryID] } + } + + pub fn location(&self) -> MTLDeviceLocation { + unsafe { msg_send![self, location] } + } + + pub fn location_number(&self) -> NSUInteger { + unsafe { msg_send![self, locationNumber] } + } + + pub fn max_threadgroup_memory_length(&self) -> NSUInteger { + unsafe { msg_send![self, maxThreadgroupMemoryLength] } + } + + pub fn max_threads_per_threadgroup(&self) -> MTLSize { + unsafe { msg_send![self, maxThreadsPerThreadgroup] } + } + + pub fn is_low_power(&self) -> bool { + unsafe { + match msg_send![self, isLowPower] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn is_headless(&self) -> bool { + unsafe { + match msg_send![self, isHeadless] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn is_removable(&self) -> bool { + unsafe { + match msg_send![self, isRemovable] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(11.0), ios(14.0)) + pub fn supports_raytracing(&self) -> bool { + unsafe { + match msg_send![self, supportsRaytracing] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn has_unified_memory(&self) -> bool { + unsafe { + match msg_send![self, hasUnifiedMemory] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn recommended_max_working_set_size(&self) -> u64 { + unsafe { msg_send![self, recommendedMaxWorkingSetSize] } + } + + pub fn max_transfer_rate(&self) -> u64 { + unsafe { msg_send![self, maxTransferRate] } + } + + pub fn supports_feature_set(&self, feature: MTLFeatureSet) -> bool { + unsafe { + match msg_send![self, supportsFeatureSet: feature] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn supports_family(&self, family: MTLGPUFamily) -> bool { + unsafe { + match msg_send![self, supportsFamily: family] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn supports_vertex_amplification_count(&self, count: NSUInteger) -> bool { + unsafe { + match msg_send![self, supportsVertexAmplificationCount: count] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn supports_texture_sample_count(&self, count: NSUInteger) -> bool { + unsafe { + match msg_send![self, supportsTextureSampleCount: count] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn supports_shader_barycentric_coordinates(&self) -> bool { + unsafe { + match msg_send![self, supportsShaderBarycentricCoordinates] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn supports_function_pointers(&self) -> bool { + unsafe { + match msg_send![self, supportsFunctionPointers] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(11.0), ios(14.0)) + pub fn supports_dynamic_libraries(&self) -> bool { + unsafe { + match msg_send![self, supportsDynamicLibraries] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(11.0), ios(14.0)) + pub fn supports_counter_sampling(&self, sampling_point: MTLCounterSamplingPoint) -> bool { + unsafe { + match msg_send![self, supportsCounterSampling: sampling_point] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn d24_s8_supported(&self) -> bool { + unsafe { + match msg_send![self, isDepth24Stencil8PixelFormatSupported] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn new_fence(&self) -> Fence { + unsafe { msg_send![self, newFence] } + } + + pub fn new_command_queue(&self) -> CommandQueue { + unsafe { msg_send![self, newCommandQueue] } + } + + pub fn new_command_queue_with_max_command_buffer_count( + &self, + count: NSUInteger, + ) -> CommandQueue { + unsafe { msg_send![self, newCommandQueueWithMaxCommandBufferCount: count] } + } + + pub fn new_default_library(&self) -> Library { + unsafe { msg_send![self, newDefaultLibrary] } + } + + pub fn new_library_with_source( + &self, + src: &str, + options: &CompileOptionsRef, + ) -> Result { + let source = nsstring_from_str(src); + unsafe { + let mut err: *mut Object = ptr::null_mut(); + let library: *mut MTLLibrary = msg_send![self, newLibraryWithSource:source + options:options + error:&mut err]; + if !err.is_null() { + let desc: *mut Object = msg_send![err, localizedDescription]; + let compile_error: *const c_char = msg_send![desc, UTF8String]; + let message = CStr::from_ptr(compile_error).to_string_lossy().into_owned(); + if library.is_null() { + return Err(message); + } else { + warn!("Shader warnings: {}", message); + } + } + + assert!(!library.is_null()); + Ok(Library::from_ptr(library)) + } + } + + pub fn new_library_with_file>(&self, file: P) -> Result { + let filename = nsstring_from_str(file.as_ref().to_string_lossy().as_ref()); + unsafe { + let library: *mut MTLLibrary = try_objc! { err => + msg_send![self, newLibraryWithFile:filename.as_ref() + error:&mut err] + }; + Ok(Library::from_ptr(library)) + } + } + + pub fn new_library_with_data(&self, library_data: &[u8]) -> Result { + unsafe { + let destructor_block = ConcreteBlock::new(|| {}).copy(); + let data = dispatch_data_create( + library_data.as_ptr() as *const std::ffi::c_void, + library_data.len() as crate::c_size_t, + &_dispatch_main_q as *const _ as dispatch_queue_t, + &*destructor_block.deref(), + ); + + let library: *mut MTLLibrary = try_objc! { err => + msg_send![self, newLibraryWithData:data + error:&mut err] + }; + dispatch_release(data); + Ok(Library::from_ptr(library)) + } + } + + /// Only available on (macos(11.0), ios(14.0)) + pub fn new_dynamic_library(&self, library: &LibraryRef) -> Result { + unsafe { + let mut err: *mut Object = ptr::null_mut(); + let dynamic_library: *mut MTLDynamicLibrary = msg_send![self, newDynamicLibrary:library + error:&mut err]; + if !err.is_null() { + // FIXME: copy pasta + let desc: *mut Object = msg_send![err, localizedDescription]; + let compile_error: *const c_char = msg_send![desc, UTF8String]; + let message = CStr::from_ptr(compile_error).to_string_lossy().into_owned(); + Err(message) + } else { + Ok(DynamicLibrary::from_ptr(dynamic_library)) + } + } + } + + /// Only available on (macos(11.0), ios(14.0)) + pub fn new_dynamic_library_with_url(&self, url: &URLRef) -> Result { + unsafe { + let mut err: *mut Object = ptr::null_mut(); + let dynamic_library: *mut MTLDynamicLibrary = msg_send![self, newDynamicLibraryWithURL:url + error:&mut err]; + if !err.is_null() { + // FIXME: copy pasta + let desc: *mut Object = msg_send![err, localizedDescription]; + let compile_error: *const c_char = msg_send![desc, UTF8String]; + let message = CStr::from_ptr(compile_error).to_string_lossy().into_owned(); + Err(message) + } else { + Ok(DynamicLibrary::from_ptr(dynamic_library)) + } + } + } + + /// Only available on (macos(11.0), ios(14.0)) + pub fn new_binary_archive_with_descriptor( + &self, + descriptor: &BinaryArchiveDescriptorRef, + ) -> Result { + unsafe { + let mut err: *mut Object = ptr::null_mut(); + let binary_archive: *mut MTLBinaryArchive = msg_send![self, newBinaryArchiveWithDescriptor:descriptor + error:&mut err]; + if !err.is_null() { + // TODO: 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 { + Ok(BinaryArchive::from_ptr(binary_archive)) + } + } + } + + /// Synchronously creates a render pipeline state object and associated reflection information. + pub fn new_render_pipeline_state_with_reflection( + &self, + descriptor: &RenderPipelineDescriptorRef, + reflection_options: MTLPipelineOption, + ) -> Result<(RenderPipelineState, RenderPipelineReflection), String> { + unsafe { + let mut reflection: *mut Object = ptr::null_mut(); + let pipeline_state: *mut MTLRenderPipelineState = try_objc! { err => + msg_send![self, newRenderPipelineStateWithDescriptor:descriptor + options:reflection_options + reflection:&mut reflection + error:&mut err] + }; + + let state = RenderPipelineState::from_ptr(pipeline_state); + + let () = msg_send![reflection, retain]; + let reflection = RenderPipelineReflection::from_ptr(reflection as _); + + Ok((state, reflection)) + } + } + + pub fn new_render_pipeline_state( + &self, + descriptor: &RenderPipelineDescriptorRef, + ) -> Result { + unsafe { + let pipeline_state: *mut MTLRenderPipelineState = try_objc! { err => + msg_send![self, newRenderPipelineStateWithDescriptor:descriptor + error:&mut err] + }; + + Ok(RenderPipelineState::from_ptr(pipeline_state)) + } + } + + pub fn new_compute_pipeline_state_with_function( + &self, + function: &FunctionRef, + ) -> Result { + unsafe { + let pipeline_state: *mut MTLComputePipelineState = try_objc! { err => + msg_send![self, newComputePipelineStateWithFunction:function + error:&mut err] + }; + + Ok(ComputePipelineState::from_ptr(pipeline_state)) + } + } + + pub fn new_compute_pipeline_state( + &self, + descriptor: &ComputePipelineDescriptorRef, + ) -> Result { + unsafe { + let pipeline_state: *mut MTLComputePipelineState = try_objc! { err => + msg_send![self, newComputePipelineStateWithDescriptor:descriptor + error:&mut err] + }; + + Ok(ComputePipelineState::from_ptr(pipeline_state)) + } + } + + /// Synchronously creates a compute pipeline state object and associated reflection information, + /// using a compute pipeline descriptor. + pub fn new_compute_pipeline_state_with_reflection( + &self, + descriptor: &ComputePipelineDescriptorRef, + reflection_options: MTLPipelineOption, + ) -> Result<(ComputePipelineState, ComputePipelineReflection), String> { + unsafe { + let mut reflection: *mut Object = ptr::null_mut(); + let pipeline_state: *mut MTLComputePipelineState = try_objc! { err => + msg_send![self, newComputePipelineStateWithDescriptor:descriptor + options:reflection_options + reflection:&mut reflection + error:&mut err] + }; + + let state = ComputePipelineState::from_ptr(pipeline_state); + + let () = msg_send![reflection, retain]; + let reflection = ComputePipelineReflection::from_ptr(reflection as _); + + Ok((state, reflection)) + } + } + + pub fn new_buffer(&self, length: u64, options: MTLResourceOptions) -> Buffer { + unsafe { + msg_send![self, newBufferWithLength:length + options:options] + } + } + + pub fn new_buffer_with_bytes_no_copy( + &self, + bytes: *const std::ffi::c_void, + length: NSUInteger, + options: MTLResourceOptions, + deallocator: Option<&Block<(*const std::ffi::c_void, NSUInteger), ()>>, + ) -> Buffer { + unsafe { + msg_send![self, newBufferWithBytesNoCopy:bytes + length:length + options:options + deallocator:deallocator] + } + } + + pub fn new_buffer_with_data( + &self, + bytes: *const std::ffi::c_void, + length: NSUInteger, + options: MTLResourceOptions, + ) -> Buffer { + unsafe { + msg_send![self, newBufferWithBytes:bytes + length:length + options:options] + } + } + + pub fn new_texture(&self, descriptor: &TextureDescriptorRef) -> Texture { + unsafe { msg_send![self, newTextureWithDescriptor: descriptor] } + } + + pub fn new_sampler(&self, descriptor: &SamplerDescriptorRef) -> SamplerState { + unsafe { msg_send![self, newSamplerStateWithDescriptor: descriptor] } + } + + pub fn new_depth_stencil_state( + &self, + descriptor: &DepthStencilDescriptorRef, + ) -> DepthStencilState { + unsafe { msg_send![self, newDepthStencilStateWithDescriptor: descriptor] } + } + + pub fn argument_buffers_support(&self) -> MTLArgumentBuffersTier { + unsafe { msg_send![self, argumentBuffersSupport] } + } + + pub fn read_write_texture_support(&self) -> MTLReadWriteTextureTier { + unsafe { msg_send![self, readWriteTextureSupport] } + } + + pub fn raster_order_groups_supported(&self) -> bool { + unsafe { + match msg_send![self, rasterOrderGroupsSupported] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(11.0), ios(14.0)) + pub fn supports_32bit_float_filtering(&self) -> bool { + unsafe { + match msg_send![self, supports32BitFloatFiltering] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(11.0), ios(14.0)) + pub fn supports_32bit_MSAA(&self) -> bool { + unsafe { + match msg_send![self, supports32BitMSAA] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(11.0), ios(14.0)) + pub fn supports_query_texture_LOD(&self) -> bool { + unsafe { + match msg_send![self, supportsQueryTextureLOD] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(11.0), ios(14.0)) + pub fn supports_BC_texture_compression(&self) -> bool { + unsafe { + match msg_send![self, supportsBCTextureCompression] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(11.0), ios(14.0)) + pub fn supports_pull_model_interpolation(&self) -> bool { + unsafe { + match msg_send![self, supportsPullModelInterpolation] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn new_argument_encoder( + &self, + arguments: &ArrayRef, + ) -> ArgumentEncoder { + unsafe { msg_send![self, newArgumentEncoderWithArguments: arguments] } + } + + pub fn new_heap(&self, descriptor: &HeapDescriptorRef) -> Heap { + unsafe { msg_send![self, newHeapWithDescriptor: descriptor] } + } + + pub fn new_event(&self) -> Event { + unsafe { msg_send![self, newEvent] } + } + + pub fn new_shared_event(&self) -> SharedEvent { + unsafe { msg_send![self, newSharedEvent] } + } + + pub fn heap_buffer_size_and_align( + &self, + length: NSUInteger, + options: MTLResourceOptions, + ) -> MTLSizeAndAlign { + unsafe { msg_send![self, heapBufferSizeAndAlignWithLength: length options: options] } + } + + pub fn heap_texture_size_and_align( + &self, + descriptor: &TextureDescriptorRef, + ) -> MTLSizeAndAlign { + unsafe { msg_send![self, heapTextureSizeAndAlignWithDescriptor: descriptor] } + } + + pub fn minimum_linear_texture_alignment_for_pixel_format( + &self, + format: MTLPixelFormat, + ) -> NSUInteger { + unsafe { msg_send![self, minimumLinearTextureAlignmentForPixelFormat: format] } + } + + pub fn minimum_texture_buffer_alignment_for_pixel_format( + &self, + format: MTLPixelFormat, + ) -> NSUInteger { + unsafe { msg_send![self, minimumTextureBufferAlignmentForPixelFormat: format] } + } + + pub fn max_argument_buffer_sampler_count(&self) -> NSUInteger { + unsafe { msg_send![self, maxArgumentBufferSamplerCount] } + } + + pub fn current_allocated_size(&self) -> NSUInteger { + unsafe { msg_send![self, currentAllocatedSize] } + } + + /// Only available on (macos(10.14), ios(12.0), tvos(12.0)) + pub fn max_buffer_length(&self) -> NSUInteger { + unsafe { msg_send![self, maxBufferLength] } + } +} diff --git a/third_party/rust/metal/src/drawable.rs b/third_party/rust/metal/src/drawable.rs new file mode 100644 index 0000000000..a1ab789b7f --- /dev/null +++ b/third_party/rust/metal/src/drawable.rs @@ -0,0 +1,26 @@ +// 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::NSUInteger; + +pub enum MTLDrawable {} + +foreign_obj_type! { + type CType = MTLDrawable; + pub struct Drawable; + pub struct DrawableRef; +} + +impl DrawableRef { + pub fn present(&self) { + unsafe { msg_send![self, present] } + } + + pub fn drawable_id(&self) -> NSUInteger { + unsafe { msg_send![self, drawableID] } + } +} diff --git a/third_party/rust/metal/src/encoder.rs b/third_party/rust/metal/src/encoder.rs new file mode 100644 index 0000000000..36c44c28ba --- /dev/null +++ b/third_party/rust/metal/src/encoder.rs @@ -0,0 +1,1376 @@ +// 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 std::ops::Range; + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLPrimitiveType { + Point = 0, + Line = 1, + LineStrip = 2, + Triangle = 3, + TriangleStrip = 4, +} + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLIndexType { + UInt16 = 0, + UInt32 = 1, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLVisibilityResultMode { + Disabled = 0, + Boolean = 1, + Counting = 2, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLCullMode { + None = 0, + Front = 1, + Back = 2, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLWinding { + Clockwise = 0, + CounterClockwise = 1, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLDepthClipMode { + Clip = 0, + Clamp = 1, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLTriangleFillMode { + Fill = 0, + Lines = 1, +} + +bitflags! { + /// https://developer.apple.com/documentation/metal/mtlblitoption + #[allow(non_upper_case_globals)] + pub struct MTLBlitOption: NSUInteger { + /// https://developer.apple.com/documentation/metal/mtlblitoption/mtlblitoptionnone + const None = 0; + /// https://developer.apple.com/documentation/metal/mtlblitoption/mtlblitoptiondepthfromdepthstencil + const DepthFromDepthStencil = 1 << 0; + /// https://developer.apple.com/documentation/metal/mtlblitoption/mtlblitoptionstencilfromdepthstencil + const StencilFromDepthStencil = 1 << 1; + /// https://developer.apple.com/documentation/metal/mtlblitoption/mtlblitoptionrowlinearpvrtc + const RowLinearPVRTC = 1 << 2; + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct MTLScissorRect { + pub x: NSUInteger, + pub y: NSUInteger, + pub width: NSUInteger, + pub height: NSUInteger, +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct MTLViewport { + pub originX: f64, + pub originY: f64, + pub width: f64, + pub height: f64, + pub znear: f64, + pub zfar: f64, +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct MTLDrawPrimitivesIndirectArguments { + pub vertexCount: u32, + pub instanceCount: u32, + pub vertexStart: u32, + pub baseInstance: u32, +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct MTLDrawIndexedPrimitivesIndirectArguments { + pub indexCount: u32, + pub instanceCount: u32, + pub indexStart: u32, + pub baseVertex: i32, + pub baseInstance: u32, +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct VertexAmplificationViewMapping { + pub renderTargetArrayIndexOffset: u32, + pub viewportArrayIndexOffset: u32, +} + +pub enum MTLCommandEncoder {} + +foreign_obj_type! { + type CType = MTLCommandEncoder; + pub struct CommandEncoder; + pub struct CommandEncoderRef; +} + +impl CommandEncoderRef { + 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); + msg_send![self, setLabel: nslabel] + } + } + + pub fn end_encoding(&self) { + unsafe { msg_send![self, endEncoding] } + } + + pub fn insert_debug_signpost(&self, name: &str) { + unsafe { + let nslabel = crate::nsstring_from_str(name); + msg_send![self, insertDebugSignpost: nslabel] + } + } + + pub fn push_debug_group(&self, name: &str) { + unsafe { + let nslabel = crate::nsstring_from_str(name); + msg_send![self, pushDebugGroup: nslabel] + } + } + + pub fn pop_debug_group(&self) { + unsafe { msg_send![self, popDebugGroup] } + } +} + +pub enum MTLParallelRenderCommandEncoder {} + +foreign_obj_type! { + type CType = MTLParallelRenderCommandEncoder; + pub struct ParallelRenderCommandEncoder; + pub struct ParallelRenderCommandEncoderRef; + type ParentType = CommandEncoderRef; +} + +impl ParallelRenderCommandEncoderRef { + pub fn render_command_encoder(&self) -> &RenderCommandEncoderRef { + unsafe { msg_send![self, renderCommandEncoder] } + } +} + +pub enum MTLRenderCommandEncoder {} + +foreign_obj_type! { + type CType = MTLRenderCommandEncoder; + pub struct RenderCommandEncoder; + pub struct RenderCommandEncoderRef; + type ParentType = CommandEncoderRef; +} + +impl RenderCommandEncoderRef { + pub fn set_render_pipeline_state(&self, pipeline_state: &RenderPipelineStateRef) { + unsafe { msg_send![self, setRenderPipelineState: pipeline_state] } + } + + pub fn set_viewport(&self, viewport: MTLViewport) { + unsafe { msg_send![self, setViewport: viewport] } + } + + pub fn set_front_facing_winding(&self, winding: MTLWinding) { + unsafe { msg_send![self, setFrontFacingWinding: winding] } + } + + pub fn set_cull_mode(&self, mode: MTLCullMode) { + unsafe { msg_send![self, setCullMode: mode] } + } + + pub fn set_depth_clip_mode(&self, mode: MTLDepthClipMode) { + unsafe { msg_send![self, setDepthClipMode: mode] } + } + + pub fn set_depth_bias(&self, bias: f32, scale: f32, clamp: f32) { + unsafe { + msg_send![self, setDepthBias:bias + slopeScale:scale + clamp:clamp] + } + } + + pub fn set_scissor_rect(&self, rect: MTLScissorRect) { + unsafe { msg_send![self, setScissorRect: rect] } + } + + pub fn set_triangle_fill_mode(&self, mode: MTLTriangleFillMode) { + unsafe { msg_send![self, setTriangleFillMode: mode] } + } + + pub fn set_blend_color(&self, red: f32, green: f32, blue: f32, alpha: f32) { + unsafe { + msg_send![self, setBlendColorRed:red + green:green + blue:blue + alpha:alpha] + } + } + + pub fn set_depth_stencil_state(&self, depth_stencil_state: &DepthStencilStateRef) { + unsafe { msg_send![self, setDepthStencilState: depth_stencil_state] } + } + + pub fn set_stencil_reference_value(&self, value: u32) { + unsafe { msg_send![self, setStencilReferenceValue: value] } + } + + pub fn set_stencil_front_back_reference_value(&self, front: u32, back: u32) { + unsafe { + msg_send![self, setStencilFrontReferenceValue:front + backReferenceValue:back] + } + } + + pub fn set_visibility_result_mode(&self, mode: MTLVisibilityResultMode, offset: NSUInteger) { + unsafe { + msg_send![self, setVisibilityResultMode:mode + offset:offset] + } + } + + pub fn set_vertex_amplification_count( + &self, + count: NSUInteger, + view_mappings: Option<&[VertexAmplificationViewMapping]>, + ) { + unsafe { + msg_send! [self, setVertexAmplificationCount: count viewMappings: view_mappings.map_or(std::ptr::null(), |vm| vm.as_ptr())] + } + } + + // Specifying Resources for a Vertex Shader Function + + pub fn set_vertex_bytes( + &self, + index: NSUInteger, + length: NSUInteger, + bytes: *const std::ffi::c_void, + ) { + unsafe { + msg_send![self, + setVertexBytes:bytes + length:length + atIndex:index + ] + } + } + + pub fn set_vertex_buffer( + &self, + index: NSUInteger, + buffer: Option<&BufferRef>, + offset: NSUInteger, + ) { + unsafe { + msg_send![self, + setVertexBuffer:buffer + offset:offset + atIndex:index + ] + } + } + + pub fn set_vertex_buffer_offset(&self, index: NSUInteger, offset: NSUInteger) { + unsafe { + msg_send![self, + setVertexBufferOffset:offset + atIndex:index + ] + } + } + + pub fn set_vertex_buffers( + &self, + start_index: NSUInteger, + data: &[Option<&BufferRef>], + offsets: &[NSUInteger], + ) { + debug_assert_eq!(offsets.len(), data.len()); + unsafe { + msg_send![self, + setVertexBuffers: data.as_ptr() + offsets: offsets.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + pub fn set_vertex_texture(&self, index: NSUInteger, texture: Option<&TextureRef>) { + unsafe { + msg_send![self, + setVertexTexture:texture + atIndex:index + ] + } + } + + pub fn set_vertex_textures(&self, start_index: NSUInteger, data: &[Option<&TextureRef>]) { + unsafe { + msg_send![self, + setVertexTextures: data.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + pub fn set_vertex_sampler_state(&self, index: NSUInteger, sampler: Option<&SamplerStateRef>) { + unsafe { + msg_send![self, + setVertexSamplerState:sampler + atIndex:index + ] + } + } + + pub fn set_vertex_sampler_states( + &self, + start_index: NSUInteger, + data: &[Option<&SamplerStateRef>], + ) { + unsafe { + msg_send![self, + setVertexSamplerStates: data.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + pub fn set_vertex_sampler_state_with_lod( + &self, + index: NSUInteger, + sampler: Option<&SamplerStateRef>, + lod_clamp: Range, + ) { + unsafe { + msg_send![self, + setVertexSamplerState:sampler + lodMinClamp:lod_clamp.start + lodMaxClamp:lod_clamp.end + atIndex:index + ] + } + } + + // Specifying Resources for a Fragment Shader Function + + pub fn set_fragment_bytes( + &self, + index: NSUInteger, + length: NSUInteger, + bytes: *const std::ffi::c_void, + ) { + unsafe { + msg_send![self, + setFragmentBytes:bytes + length:length + atIndex:index + ] + } + } + + pub fn set_fragment_buffer( + &self, + index: NSUInteger, + buffer: Option<&BufferRef>, + offset: NSUInteger, + ) { + unsafe { + msg_send![self, + setFragmentBuffer:buffer + offset:offset + atIndex:index + ] + } + } + + pub fn set_fragment_buffer_offset(&self, index: NSUInteger, offset: NSUInteger) { + unsafe { + msg_send![self, + setFragmentBufferOffset:offset + atIndex:index + ] + } + } + + pub fn set_fragment_buffers( + &self, + start_index: NSUInteger, + data: &[Option<&BufferRef>], + offsets: &[NSUInteger], + ) { + debug_assert_eq!(offsets.len(), data.len()); + unsafe { + msg_send![self, + setFragmentBuffers: data.as_ptr() + offsets: offsets.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + pub fn set_fragment_texture(&self, index: NSUInteger, texture: Option<&TextureRef>) { + unsafe { + msg_send![self, + setFragmentTexture:texture + atIndex:index + ] + } + } + + pub fn set_fragment_textures(&self, start_index: NSUInteger, data: &[Option<&TextureRef>]) { + unsafe { + msg_send![self, + setFragmentTextures: data.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + pub fn set_fragment_sampler_state(&self, index: NSUInteger, sampler: Option<&SamplerStateRef>) { + unsafe { + msg_send![self, setFragmentSamplerState:sampler + atIndex:index] + } + } + + pub fn set_fragment_sampler_states( + &self, + start_index: NSUInteger, + data: &[Option<&SamplerStateRef>], + ) { + unsafe { + msg_send![self, + setFragmentSamplerStates: data.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + pub fn set_fragment_sampler_state_with_lod( + &self, + index: NSUInteger, + sampler: Option<&SamplerStateRef>, + lod_clamp: Range, + ) { + unsafe { + msg_send![self, + setFragmentSamplerState:sampler + lodMinClamp:lod_clamp.start + lodMaxClamp:lod_clamp.end + atIndex:index + ] + } + } + + // Drawing Geometric Primitives + + pub fn draw_primitives( + &self, + primitive_type: MTLPrimitiveType, + vertex_start: NSUInteger, + vertex_count: NSUInteger, + ) { + unsafe { + msg_send![self, + drawPrimitives: primitive_type + vertexStart: vertex_start + vertexCount: vertex_count + ] + } + } + + pub fn draw_primitives_instanced( + &self, + primitive_type: MTLPrimitiveType, + vertex_start: NSUInteger, + vertex_count: NSUInteger, + instance_count: NSUInteger, + ) { + unsafe { + msg_send![self, + drawPrimitives: primitive_type + vertexStart: vertex_start + vertexCount: vertex_count + instanceCount: instance_count + ] + } + } + + pub fn draw_primitives_instanced_base_instance( + &self, + primitive_type: MTLPrimitiveType, + vertex_start: NSUInteger, + vertex_count: NSUInteger, + instance_count: NSUInteger, + base_instance: NSUInteger, + ) { + unsafe { + msg_send![self, + drawPrimitives: primitive_type + vertexStart: vertex_start + vertexCount: vertex_count + instanceCount: instance_count + baseInstance: base_instance + ] + } + } + + pub fn draw_primitives_indirect( + &self, + primitive_type: MTLPrimitiveType, + indirect_buffer: &BufferRef, + indirect_buffer_offset: NSUInteger, + ) { + unsafe { + msg_send![self, + drawPrimitives: primitive_type + indirectBuffer: indirect_buffer + indirectBufferOffset: indirect_buffer_offset + ] + } + } + + pub fn draw_indexed_primitives( + &self, + primitive_type: MTLPrimitiveType, + index_count: NSUInteger, + index_type: MTLIndexType, + index_buffer: &BufferRef, + index_buffer_offset: NSUInteger, + ) { + unsafe { + msg_send![self, + drawIndexedPrimitives: primitive_type + indexCount: index_count + indexType: index_type + indexBuffer: index_buffer + indexBufferOffset: index_buffer_offset + ] + } + } + + pub fn draw_indexed_primitives_instanced( + &self, + primitive_type: MTLPrimitiveType, + index_count: NSUInteger, + index_type: MTLIndexType, + index_buffer: &BufferRef, + index_buffer_offset: NSUInteger, + instance_count: NSUInteger, + ) { + unsafe { + msg_send![self, + drawIndexedPrimitives: primitive_type + indexCount: index_count + indexType: index_type + indexBuffer: index_buffer + indexBufferOffset: index_buffer_offset + instanceCount: instance_count + ] + } + } + + pub fn draw_indexed_primitives_instanced_base_instance( + &self, + primitive_type: MTLPrimitiveType, + index_count: NSUInteger, + index_type: MTLIndexType, + index_buffer: &BufferRef, + index_buffer_offset: NSUInteger, + instance_count: NSUInteger, + base_vertex: NSInteger, + base_instance: NSUInteger, + ) { + unsafe { + msg_send![self, + drawIndexedPrimitives: primitive_type + indexCount: index_count + indexType: index_type + indexBuffer: index_buffer + indexBufferOffset: index_buffer_offset + instanceCount: instance_count + baseVertex: base_vertex + baseInstance: base_instance + ] + } + } + + pub fn draw_indexed_primitives_indirect( + &self, + primitive_type: MTLPrimitiveType, + index_type: MTLIndexType, + index_buffer: &BufferRef, + index_buffer_offset: NSUInteger, + indirect_buffer: &BufferRef, + indirect_buffer_offset: NSUInteger, + ) { + unsafe { + msg_send![self, + drawIndexedPrimitives: primitive_type + indexType: index_type + indexBuffer: index_buffer + indexBufferOffset: index_buffer_offset + indirectBuffer: indirect_buffer + indirectBufferOffset: indirect_buffer_offset + ] + } + } + + // TODO: more draws + // fn setVertexBufferOffset_atIndex(self, offset: NSUInteger, index: NSUInteger); + // fn setVertexBuffers_offsets_withRange(self, buffers: *const id, offsets: *const NSUInteger, range: NSRange); + // fn setVertexSamplerStates_lodMinClamps_lodMaxClamps_withRange(self, samplers: *const id, lodMinClamps: *const f32, lodMaxClamps: *const f32, range: NSRange); + + /// Adds an untracked resource to the render pass. + /// + /// Availability: iOS 11.0+, macOS 10.13+ + /// + /// # Arguments + /// * `resource`: A resource within an argument buffer. + /// * `usage`: Options for describing how a graphics function uses the resource. + /// + /// See + #[deprecated(note = "Use use_resource_at instead")] + pub fn use_resource(&self, resource: &ResourceRef, usage: MTLResourceUsage) { + unsafe { + msg_send![self, + useResource:resource + usage:usage + ] + } + } + + /// Adds an untracked resource to the render pass, specifying which render stages need it. + /// + /// Availability: iOS 13.0+, macOS 10.15+ + /// + /// # Arguments + /// * `resource`: A resource within an argument buffer. + /// * `usage`: Options for describing how a graphics function uses the resource. + /// * `stages`: The render stages where the resource must be resident. + /// + /// See + pub fn use_resource_at( + &self, + resource: &ResourceRef, + usage: MTLResourceUsage, + stages: MTLRenderStages, + ) { + unsafe { + msg_send![self, + useResource: resource + usage: usage + stages: stages + ] + } + } + + /// Adds an array of untracked resources to the render pass, specifying which stages need them. + /// + /// When working with color render targets, call this method as late as possible to improve performance. + /// + /// Availability: iOS 13.0+, macOS 10.15+ + /// + /// # Arguments + /// * `resources`: A slice of resources within an argument buffer. + /// * `usage`: Options for describing how a graphics function uses the resources. + /// * `stages`: The render stages where the resources must be resident. + pub fn use_resources( + &self, + resources: &[&ResourceRef], + usage: MTLResourceUsage, + stages: MTLRenderStages, + ) { + unsafe { + msg_send![self, + useResources: resources.as_ptr() + count: resources.len() as NSUInteger + usage: usage + stages: stages + ] + } + } + + /// Adds the resources in a heap to the render pass. + /// + /// Availability: iOS 11.0+, macOS 10.13+ + /// + /// # Arguments: + /// * `heap`: A heap that contains resources within an argument buffer. + /// + /// See + #[deprecated(note = "Use use_heap_at instead")] + pub fn use_heap(&self, heap: &HeapRef) { + unsafe { msg_send![self, useHeap: heap] } + } + + /// Adds the resources in a heap to the render pass, specifying which render stages need them. + /// + /// Availability: iOS 13.0+, macOS 10.15+ + /// + /// # Arguments + /// * `heap`: A heap that contains resources within an argument buffer. + /// * `stages`: The render stages where the resources must be resident. + /// + pub fn use_heap_at(&self, heap: &HeapRef, stages: MTLRenderStages) { + unsafe { + msg_send![self, + useHeap: heap + stages: stages + ] + } + } + + /// Adds the resources in an array of heaps to the render pass, specifying which render stages need them. + /// + /// Availability: iOS 13.0+, macOS 10.15+ + /// + /// # Arguments + /// + /// * `heaps`: A slice of heaps that contains resources within an argument buffer. + /// * `stages`: The render stages where the resources must be resident. + pub fn use_heaps(&self, heaps: &[&HeapRef], stages: MTLRenderStages) { + unsafe { + msg_send![self, + useHeaps: heaps.as_ptr() + count: heaps.len() as NSUInteger + stages: stages + ] + } + } + + pub fn execute_commands_in_buffer( + &self, + buffer: &IndirectCommandBufferRef, + with_range: NSRange, + ) { + unsafe { msg_send![self, executeCommandsInBuffer:buffer withRange:with_range] } + } + + pub fn update_fence(&self, fence: &FenceRef, after_stages: MTLRenderStages) { + unsafe { + msg_send![self, + updateFence: fence + afterStages: after_stages + ] + } + } + + pub fn wait_for_fence(&self, fence: &FenceRef, before_stages: MTLRenderStages) { + unsafe { + msg_send![self, + waitForFence: fence + beforeStages: before_stages + ] + } + } +} + +pub enum MTLBlitCommandEncoder {} + +foreign_obj_type! { + type CType = MTLBlitCommandEncoder; + pub struct BlitCommandEncoder; + pub struct BlitCommandEncoderRef; + type ParentType = CommandEncoderRef; +} + +impl BlitCommandEncoderRef { + pub fn synchronize_resource(&self, resource: &ResourceRef) { + unsafe { msg_send![self, synchronizeResource: resource] } + } + + pub fn fill_buffer(&self, destination_buffer: &BufferRef, range: crate::NSRange, value: u8) { + unsafe { + msg_send![self, + fillBuffer: destination_buffer + range: range + value: value + ] + } + } + + pub fn generate_mipmaps(&self, texture: &TextureRef) { + unsafe { msg_send![self, generateMipmapsForTexture: texture] } + } + + pub fn copy_from_buffer( + &self, + source_buffer: &BufferRef, + source_offset: NSUInteger, + destination_buffer: &BufferRef, + destination_offset: NSUInteger, + size: NSUInteger, + ) { + unsafe { + msg_send![self, + copyFromBuffer: source_buffer + sourceOffset: source_offset + toBuffer: destination_buffer + destinationOffset: destination_offset + size: size + ] + } + } + + pub fn copy_from_texture( + &self, + source_texture: &TextureRef, + source_slice: NSUInteger, + source_level: NSUInteger, + source_origin: MTLOrigin, + source_size: MTLSize, + destination_texture: &TextureRef, + destination_slice: NSUInteger, + destination_level: NSUInteger, + destination_origin: MTLOrigin, + ) { + unsafe { + msg_send![self, + copyFromTexture: source_texture + sourceSlice: source_slice + sourceLevel: source_level + sourceOrigin: source_origin + sourceSize: source_size + toTexture: destination_texture + destinationSlice: destination_slice + destinationLevel: destination_level + destinationOrigin: destination_origin + ] + } + } + + pub fn copy_from_buffer_to_texture( + &self, + source_buffer: &BufferRef, + source_offset: NSUInteger, + source_bytes_per_row: NSUInteger, + source_bytes_per_image: NSUInteger, + source_size: MTLSize, + destination_texture: &TextureRef, + destination_slice: NSUInteger, + destination_level: NSUInteger, + destination_origin: MTLOrigin, + options: MTLBlitOption, + ) { + unsafe { + msg_send![self, + copyFromBuffer: source_buffer + sourceOffset: source_offset + sourceBytesPerRow: source_bytes_per_row + sourceBytesPerImage: source_bytes_per_image + sourceSize: source_size + toTexture: destination_texture + destinationSlice: destination_slice + destinationLevel: destination_level + destinationOrigin: destination_origin + options: options + ] + } + } + + /// https://developer.apple.com/documentation/metal/mtlblitcommandencoder/1400756-copy + pub fn copy_from_texture_to_buffer( + &self, + source_texture: &TextureRef, + source_slice: NSUInteger, + source_level: NSUInteger, + source_origin: MTLOrigin, + source_size: MTLSize, + destination_buffer: &BufferRef, + destination_offset: NSUInteger, + destination_bytes_per_row: NSUInteger, + destination_bytes_per_image: NSUInteger, + options: MTLBlitOption, + ) { + unsafe { + msg_send![self, + copyFromTexture: source_texture + sourceSlice: source_slice + sourceLevel: source_level + sourceOrigin: source_origin + sourceSize: source_size + toBuffer: destination_buffer + destinationOffset: destination_offset + destinationBytesPerRow: destination_bytes_per_row + destinationBytesPerImage: destination_bytes_per_image + options: options + ] + } + } + + pub fn optimize_contents_for_gpu_access(&self, texture: &TextureRef) { + unsafe { msg_send![self, optimizeContentsForGPUAccess: texture] } + } + + pub fn optimize_contents_for_gpu_access_slice_level( + &self, + texture: &TextureRef, + slice: NSUInteger, + level: NSUInteger, + ) { + unsafe { + msg_send![self, + optimizeContentsForGPUAccess: texture + slice: slice + level: level + ] + } + } + + pub fn optimize_contents_for_cpu_access(&self, texture: &TextureRef) { + unsafe { msg_send![self, optimizeContentsForCPUAccess: texture] } + } + + pub fn optimize_contents_for_cpu_access_slice_level( + &self, + texture: &TextureRef, + slice: NSUInteger, + level: NSUInteger, + ) { + unsafe { + msg_send![self, + optimizeContentsForCPUAccess: texture + slice: slice + level: level + ] + } + } + + pub fn update_fence(&self, fence: &FenceRef) { + unsafe { msg_send![self, updateFence: fence] } + } + + pub fn wait_for_fence(&self, fence: &FenceRef) { + unsafe { msg_send![self, waitForFence: fence] } + } +} + +pub enum MTLComputeCommandEncoder {} + +foreign_obj_type! { + type CType = MTLComputeCommandEncoder; + pub struct ComputeCommandEncoder; + pub struct ComputeCommandEncoderRef; + type ParentType = CommandEncoderRef; +} + +impl ComputeCommandEncoderRef { + pub fn set_compute_pipeline_state(&self, state: &ComputePipelineStateRef) { + unsafe { msg_send![self, setComputePipelineState: state] } + } + + pub fn set_buffer(&self, index: NSUInteger, buffer: Option<&BufferRef>, offset: NSUInteger) { + unsafe { msg_send![self, setBuffer:buffer offset:offset atIndex:index] } + } + + pub fn set_buffers( + &self, + start_index: NSUInteger, + data: &[Option<&BufferRef>], + offsets: &[NSUInteger], + ) { + debug_assert_eq!(offsets.len(), data.len()); + unsafe { + msg_send![self, + setBuffers: data.as_ptr() + offsets: offsets.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + pub fn set_texture(&self, index: NSUInteger, texture: Option<&TextureRef>) { + unsafe { + msg_send![self, + setTexture:texture + atIndex:index + ] + } + } + + pub fn set_textures(&self, start_index: NSUInteger, data: &[Option<&TextureRef>]) { + unsafe { + msg_send![self, + setTextures: data.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + pub fn set_sampler_state(&self, index: NSUInteger, sampler: Option<&SamplerStateRef>) { + unsafe { + msg_send![self, + setSamplerState:sampler + atIndex:index + ] + } + } + + pub fn set_sampler_states(&self, start_index: NSUInteger, data: &[Option<&SamplerStateRef>]) { + unsafe { + msg_send![self, + setSamplerStates: data.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + pub fn set_sampler_state_with_lod( + &self, + index: NSUInteger, + sampler: Option<&SamplerStateRef>, + lod_clamp: Range, + ) { + unsafe { + msg_send![self, + setSamplerState:sampler + lodMinClamp:lod_clamp.start + lodMaxClamp:lod_clamp.end + atIndex:index + ] + } + } + + pub fn set_bytes(&self, index: NSUInteger, length: NSUInteger, bytes: *const std::ffi::c_void) { + unsafe { + msg_send![self, + setBytes: bytes + length: length + atIndex: index + ] + } + } + + pub fn dispatch_thread_groups( + &self, + thread_groups_count: MTLSize, + threads_per_threadgroup: MTLSize, + ) { + unsafe { + msg_send![self, + dispatchThreadgroups:thread_groups_count + threadsPerThreadgroup:threads_per_threadgroup + ] + } + } + + pub fn dispatch_threads(&self, threads_per_grid: MTLSize, threads_per_thread_group: MTLSize) { + unsafe { + msg_send![self, + dispatchThreads:threads_per_grid + threadsPerThreadgroup:threads_per_thread_group + ] + } + } + + pub fn dispatch_thread_groups_indirect( + &self, + buffer: &BufferRef, + offset: NSUInteger, + threads_per_threadgroup: MTLSize, + ) { + unsafe { + msg_send![self, + dispatchThreadgroupsWithIndirectBuffer:buffer + indirectBufferOffset:offset + threadsPerThreadgroup:threads_per_threadgroup + ] + } + } + + pub fn set_threadgroup_memory_length(&self, at_index: NSUInteger, size: NSUInteger) { + unsafe { + msg_send![self, + setThreadgroupMemoryLength:size + atIndex: at_index + ] + } + } + + /// Specifies that a resource in an argument buffer can be safely used by a compute pass. + /// + /// Availability: iOS 11.0+, macOS 10.13+ + /// + /// # Arguments + /// * `resource`: A specific resource within an argument buffer. + /// * `usage`: The options that describe how the resource will be used by a compute function. + pub fn use_resource(&self, resource: &ResourceRef, usage: MTLResourceUsage) { + unsafe { + msg_send![self, + useResource: resource + usage: usage + ] + } + } + + /// Specifies that an array of resources in an argument buffer can be safely used by a compute pass. + /// + /// Availability: iOS 11.0+, macOS 10.13+ + /// + /// See + /// + /// # Arguments + /// * `resources`: A slice of resources within an argument buffer. + /// * `usage`: The options that describe how the array of resources will be used by a compute function. + pub fn use_resources(&self, resources: &[&ResourceRef], usage: MTLResourceUsage) { + unsafe { + msg_send![self, + useResources: resources.as_ptr() + count: resources.len() as NSUInteger + usage: usage + ] + } + } + + /// Specifies that a heap containing resources in an argument buffer can be safely used by a compute pass. + /// + /// Availability: iOS 11.0+, macOS 10.13+ + /// + /// See + /// + /// # Arguments + /// * `heap`: A heap that contains resources within an argument buffer. + pub fn use_heap(&self, heap: &HeapRef) { + unsafe { msg_send![self, useHeap: heap] } + } + + /// Specifies that an array of heaps containing resources in an argument buffer can be safely + /// used by a compute pass. + /// + /// Availability: iOS 11.0+, macOS 10.13+ + /// + /// # Arguments + /// * `heaps`: A slice of heaps that contains resources within an argument buffer. + pub fn use_heaps(&self, heaps: &[&HeapRef]) { + unsafe { + msg_send![self, + useHeaps: heaps.as_ptr() + count: heaps.len() as NSUInteger + ] + } + } + + pub fn update_fence(&self, fence: &FenceRef) { + unsafe { msg_send![self, updateFence: fence] } + } + + pub fn wait_for_fence(&self, fence: &FenceRef) { + unsafe { msg_send![self, waitForFence: fence] } + } +} + +pub enum MTLArgumentEncoder {} + +foreign_obj_type! { + type CType = MTLArgumentEncoder; + pub struct ArgumentEncoder; + pub struct ArgumentEncoderRef; +} + +impl ArgumentEncoderRef { + pub fn encoded_length(&self) -> NSUInteger { + unsafe { msg_send![self, encodedLength] } + } + + pub fn alignment(&self) -> NSUInteger { + unsafe { msg_send![self, alignment] } + } + + pub fn set_argument_buffer(&self, buffer: &BufferRef, offset: NSUInteger) { + unsafe { + msg_send![self, + setArgumentBuffer: buffer + offset: offset + ] + } + } + + pub fn set_argument_buffer_to_element( + &self, + array_element: NSUInteger, + buffer: &BufferRef, + offset: NSUInteger, + ) { + unsafe { + msg_send![self, + setArgumentBuffer: buffer + startOffset: offset + arrayElement: array_element + ] + } + } + + pub fn set_buffer(&self, at_index: NSUInteger, buffer: &BufferRef, offset: NSUInteger) { + unsafe { + msg_send![self, + setBuffer: buffer + offset: offset + atIndex: at_index + ] + } + } + + pub fn set_buffers( + &self, + start_index: NSUInteger, + data: &[&BufferRef], + offsets: &[NSUInteger], + ) { + assert_eq!(offsets.len(), data.len()); + unsafe { + msg_send![self, + setBuffers: data.as_ptr() + offsets: offsets.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + pub fn set_texture(&self, at_index: NSUInteger, texture: &TextureRef) { + unsafe { + msg_send![self, + setTexture: texture + atIndex: at_index + ] + } + } + + pub fn set_textures(&self, start_index: NSUInteger, data: &[&TextureRef]) { + unsafe { + msg_send![self, + setTextures: data.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + pub fn set_sampler_state(&self, at_index: NSUInteger, sampler_state: &SamplerStateRef) { + unsafe { + msg_send![self, + setSamplerState: sampler_state + atIndex: at_index + ] + } + } + + pub fn set_sampler_states(&self, start_index: NSUInteger, data: &[&SamplerStateRef]) { + unsafe { + msg_send![self, + setSamplerStates: data.as_ptr() + withRange: NSRange { + location: start_index, + length: data.len() as _, + } + ] + } + } + + pub fn set_render_pipeline_state( + &self, + at_index: NSUInteger, + pipeline: &RenderPipelineStateRef, + ) { + unsafe { + msg_send![self, + setRenderPipelineState: pipeline + atIndex: at_index + ] + } + } + + pub fn set_render_pipeline_states( + &self, + start_index: NSUInteger, + pipelines: &[&RenderPipelineStateRef], + ) { + unsafe { + msg_send![self, + setRenderPipelineStates: pipelines.as_ptr() + withRange: NSRange { + location: start_index, + length: pipelines.len() as _, + } + ] + } + } + + pub fn constant_data(&self, at_index: NSUInteger) -> *mut std::ffi::c_void { + unsafe { msg_send![self, constantDataAtIndex: at_index] } + } + + pub fn new_argument_encoder_for_buffer(&self, index: NSUInteger) -> ArgumentEncoder { + unsafe { + let ptr = msg_send![self, newArgumentEncoderForBufferAtIndex: index]; + ArgumentEncoder::from_ptr(ptr) + } + } +} diff --git a/third_party/rust/metal/src/heap.rs b/third_party/rust/metal/src/heap.rs new file mode 100644 index 0000000000..9d60142a7b --- /dev/null +++ b/third_party/rust/metal/src/heap.rs @@ -0,0 +1,207 @@ +// 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::*; + +/// Only available on macos(10.15), ios(13.0) +#[repr(u64)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLHeapType { + Automatic = 0, + Placement = 1, + /// Only available on macos(11.0), macCatalyst(14.0) + Sparse = 2, +} + +pub enum MTLHeap {} + +foreign_obj_type! { + type CType = MTLHeap; + pub struct Heap; + pub struct HeapRef; +} + +impl HeapRef { + 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 cpu_cache_mode(&self) -> MTLCPUCacheMode { + unsafe { msg_send![self, cpuCacheMode] } + } + + pub fn storage_mode(&self) -> MTLStorageMode { + unsafe { msg_send![self, storageMode] } + } + + /// Only available on macos(10.15), ios(13.0) + pub fn hazard_tracking_mode(&self) -> MTLHazardTrackingMode { + unsafe { msg_send![self, hazardTrackingMode] } + } + + /// Only available on macos(10.15), ios(13.0) + pub fn resource_options(&self) -> MTLResourceOptions { + unsafe { msg_send![self, resourceOptions] } + } + + pub fn set_purgeable_state(&self, state: MTLPurgeableState) -> MTLPurgeableState { + unsafe { msg_send![self, setPurgeableState: state] } + } + + pub fn size(&self) -> NSUInteger { + unsafe { msg_send![self, size] } + } + + pub fn used_size(&self) -> NSUInteger { + unsafe { msg_send![self, usedSize] } + } + + /// Only available on macos(10.15), ios(13.0) + pub fn heap_type(&self) -> MTLHeapType { + unsafe { msg_send![self, type] } + } + + /// Only available on macos(10.13), ios(11.0) + pub fn current_allocated_size(&self) -> NSUInteger { + unsafe { msg_send![self, currentAllocatedSize] } + } + + pub fn max_available_size_with_alignment(&self, alignment: NSUInteger) -> NSUInteger { + unsafe { msg_send![self, maxAvailableSizeWithAlignment: alignment] } + } + + pub fn new_buffer(&self, length: u64, options: MTLResourceOptions) -> Option { + unsafe { + let ptr: *mut MTLBuffer = msg_send![self, newBufferWithLength:length + options:options]; + if !ptr.is_null() { + Some(Buffer::from_ptr(ptr)) + } else { + None + } + } + } + + pub fn new_texture(&self, descriptor: &TextureDescriptorRef) -> Option { + unsafe { + let ptr: *mut MTLTexture = msg_send![self, newTextureWithDescriptor: descriptor]; + if !ptr.is_null() { + Some(Texture::from_ptr(ptr)) + } else { + None + } + } + } + + /// Only available on macOS 10.15+ & iOS 13.0+ + pub fn new_buffer_with_offset( + &self, + length: u64, + options: MTLResourceOptions, + offset: u64, + ) -> Option { + unsafe { + let ptr: *mut MTLBuffer = msg_send![self, newBufferWithLength:length + options:options + offset:offset]; + if !ptr.is_null() { + Some(Buffer::from_ptr(ptr)) + } else { + None + } + } + } + + /// Only available on macOS 10.15+ & iOS 13.0+ + pub fn new_texture_with_offset( + &self, + descriptor: &TextureDescriptorRef, + offset: u64, + ) -> Option { + unsafe { + let ptr: *mut MTLTexture = msg_send![self, newTextureWithDescriptor:descriptor + offset:offset]; + if !ptr.is_null() { + Some(Texture::from_ptr(ptr)) + } else { + None + } + } + } +} + +pub enum MTLHeapDescriptor {} + +foreign_obj_type! { + type CType = MTLHeapDescriptor; + pub struct HeapDescriptor; + pub struct HeapDescriptorRef; +} + +impl HeapDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLHeapDescriptor); + msg_send![class, new] + } + } +} + +impl HeapDescriptorRef { + pub fn cpu_cache_mode(&self) -> MTLCPUCacheMode { + unsafe { msg_send![self, cpuCacheMode] } + } + + pub fn set_cpu_cache_mode(&self, mode: MTLCPUCacheMode) { + unsafe { msg_send![self, setCpuCacheMode: mode] } + } + + pub fn storage_mode(&self) -> MTLStorageMode { + unsafe { msg_send![self, storageMode] } + } + + pub fn set_storage_mode(&self, mode: MTLStorageMode) { + unsafe { msg_send![self, setStorageMode: mode] } + } + + pub fn size(&self) -> NSUInteger { + unsafe { msg_send![self, size] } + } + + pub fn set_size(&self, size: NSUInteger) { + unsafe { msg_send![self, setSize: size] } + } + + /// Only available on macos(10.15), ios(13.0) + pub fn hazard_tracking_mode(&self) -> MTLHazardTrackingMode { + unsafe { msg_send![self, hazardTrackingMode] } + } + + /// Only available on macos(10.15), ios(13.0) + pub fn resource_options(&self) -> MTLResourceOptions { + unsafe { msg_send![self, resourceOptions] } + } + + /// Only available on macos(10.15), ios(13.0) + pub fn heap_type(&self) -> MTLHeapType { + unsafe { msg_send![self, type] } + } +} diff --git a/third_party/rust/metal/src/indirect_encoder.rs b/third_party/rust/metal/src/indirect_encoder.rs new file mode 100644 index 0000000000..88ac41d377 --- /dev/null +++ b/third_party/rust/metal/src/indirect_encoder.rs @@ -0,0 +1,347 @@ +use super::*; + +bitflags! { + #[allow(non_upper_case_globals)] + pub struct MTLIndirectCommandType: NSUInteger { + const Draw = 1 << 0; + const DrawIndexed = 1 << 1; + const DrawPatches = 1 << 2; + const DrawIndexedPatches = 1 << 3; + const ConcurrentDispatch = 1 << 4; + const ConcurrentDispatchThreads = 1 << 5; + } +} + +pub enum MTLIndirectCommandBufferDescriptor {} + +foreign_obj_type! { + type CType = MTLIndirectCommandBufferDescriptor; + pub struct IndirectCommandBufferDescriptor; + pub struct IndirectCommandBufferDescriptorRef; +} + +impl IndirectCommandBufferDescriptorRef { + pub fn command_types(&self) -> MTLIndirectCommandType { + unsafe { msg_send![self, commandTypes] } + } + + pub fn set_command_types(&self, types: MTLIndirectCommandType) { + unsafe { msg_send![self, setCommandTypes: types] } + } + + pub fn inherit_buffers(&self) -> bool { + unsafe { + match msg_send![self, inheritBuffers] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_inherit_buffers(&self, inherit: bool) { + unsafe { msg_send![self, setInheritBuffers: inherit] } + } + + pub fn inherit_pipeline_state(&self) -> bool { + unsafe { + match msg_send![self, inheritPipelineState] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_inherit_pipeline_state(&self, inherit: bool) { + unsafe { msg_send![self, setInheritPipelineState: inherit] } + } + + pub fn max_vertex_buffer_bind_count(&self) -> NSUInteger { + unsafe { msg_send![self, maxVertexBufferBindCount] } + } + + pub fn set_max_vertex_buffer_bind_count(&self, count: NSUInteger) { + unsafe { msg_send![self, setMaxVertexBufferBindCount: count] } + } + + pub fn max_fragment_buffer_bind_count(&self) -> NSUInteger { + unsafe { msg_send![self, maxFragmentBufferBindCount] } + } + + pub fn set_max_fragment_buffer_bind_count(&self, count: NSUInteger) { + unsafe { msg_send![self, setMaxFragmentBufferBindCount: count] } + } + + pub fn max_kernel_buffer_bind_count(&self) -> NSUInteger { + unsafe { msg_send![self, maxKernelBufferBindCount] } + } + + pub fn set_max_kernel_buffer_bind_count(&self, count: NSUInteger) { + unsafe { msg_send![self, setMaxKernelBufferBindCount: count] } + } +} + +pub enum MTLIndirectCommandBuffer {} + +foreign_obj_type! { + type CType = MTLIndirectCommandBuffer; + pub struct IndirectCommandBuffer; + pub struct IndirectCommandBufferRef; + type ParentType = ResourceRef; +} + +impl IndirectCommandBufferRef { + pub fn size(&self) -> NSUInteger { + unsafe { msg_send![self, size] } + } + + pub fn indirect_render_command_at_index(&self, index: NSUInteger) -> &IndirectRenderCommandRef { + unsafe { msg_send![self, indirectRenderCommandAtIndex: index] } + } + + pub fn indirect_compute_command_at_index( + &self, + index: NSUInteger, + ) -> &IndirectComputeCommandRef { + unsafe { msg_send![self, indirectComputeCommandAtIndex: index] } + } + + pub fn reset_with_range(&self, range: crate::NSRange) { + unsafe { msg_send![self, resetWithRange: range] } + } +} + +pub enum MTLIndirectRenderCommand {} + +foreign_obj_type! { + type CType = MTLIndirectRenderCommand; + pub struct IndirectRenderCommand; + pub struct IndirectRenderCommandRef; +} + +impl IndirectRenderCommandRef { + pub fn set_render_pipeline_state(&self, pipeline_state: &RenderPipelineStateRef) { + unsafe { msg_send![self, setRenderPipelineState: pipeline_state] } + } + + pub fn set_vertex_buffer( + &self, + index: NSUInteger, + buffer: Option<&BufferRef>, + offset: NSUInteger, + ) { + unsafe { + msg_send![self, + setVertexBuffer: buffer + offset: offset + atIndex: index + ] + } + } + + pub fn set_fragment_buffer( + &self, + index: NSUInteger, + buffer: Option<&BufferRef>, + offset: NSUInteger, + ) { + unsafe { + msg_send![self, + setFragmentBuffer:buffer + offset:offset + atIndex:index + ] + } + } + + pub fn draw_primitives( + &self, + primitive_type: MTLPrimitiveType, + vertex_start: NSUInteger, + vertex_count: NSUInteger, + instance_count: NSUInteger, + base_instance: NSUInteger, + ) { + unsafe { + msg_send![self, + drawPrimitives: primitive_type + vertexStart: vertex_start + vertexCount: vertex_count + instanceCount: instance_count + baseInstance: base_instance + ] + } + } + + pub fn draw_indexed_primitives( + &self, + primitive_type: MTLPrimitiveType, + index_count: NSUInteger, + index_type: MTLIndexType, + index_buffer: &BufferRef, + index_buffer_offset: NSUInteger, + instance_count: NSUInteger, + base_vertex: NSUInteger, + base_instance: NSUInteger, + ) { + unsafe { + msg_send![self, + drawIndexedPrimitives: primitive_type + indexCount: index_count + indexType: index_type + indexBuffer: index_buffer + indexBufferOffset: index_buffer_offset + instanceCount: instance_count + baseVertex: base_vertex + baseInstance: base_instance + ] + } + } + + pub fn draw_patches( + &self, + number_of_patch_control_points: NSUInteger, + patch_start: NSUInteger, + patch_count: NSUInteger, + patch_index_buffer: &BufferRef, + patch_index_buffer_offset: NSUInteger, + instance_count: NSUInteger, + base_instance: NSUInteger, + tesselation_factor_buffer: &BufferRef, + tesselation_factor_buffer_offset: NSUInteger, + tesselation_factor_buffer_instance_stride: NSUInteger, + ) { + unsafe { + msg_send![self, + drawPatches: number_of_patch_control_points + patchStart: patch_start + patchCount: patch_count + patchIndexBuffer: patch_index_buffer + patchIndexBufferOffset: patch_index_buffer_offset + instanceCount: instance_count + baseInstance: base_instance + tessellationFactorBuffer: tesselation_factor_buffer + tessellationFactorBufferOffset: tesselation_factor_buffer_offset + tessellationFactorBufferInstanceStride: tesselation_factor_buffer_instance_stride + ] + } + } + + pub fn draw_indexed_patches( + &self, + number_of_patch_control_points: NSUInteger, + patch_start: NSUInteger, + patch_count: NSUInteger, + patch_index_buffer: &BufferRef, + patch_index_buffer_offset: NSUInteger, + control_point_index_buffer: &BufferRef, + control_point_index_buffer_offset: NSUInteger, + instance_count: NSUInteger, + base_instance: NSUInteger, + tesselation_factor_buffer: &BufferRef, + tesselation_factor_buffer_offset: NSUInteger, + tesselation_factor_buffer_instance_stride: NSUInteger, + ) { + unsafe { + msg_send![self, + drawIndexedPatches: number_of_patch_control_points + patchStart: patch_start + patchCount: patch_count + patchIndexBuffer: patch_index_buffer + patchIndexBufferOffset: patch_index_buffer_offset + controlPointIndexBuffer: control_point_index_buffer + controlPointIndexBufferOffset: control_point_index_buffer_offset + instanceCount: instance_count + baseInstance: base_instance + tessellationFactorBuffer: tesselation_factor_buffer + tessellationFactorBufferOffset: tesselation_factor_buffer_offset + tessellationFactorBufferInstanceStride: tesselation_factor_buffer_instance_stride + ] + } + } + + pub fn reset(&self) { + unsafe { msg_send![self, reset] } + } +} + +pub enum MTLIndirectComputeCommand {} + +foreign_obj_type! { + type CType = MTLIndirectComputeCommand; + pub struct IndirectComputeCommand; + pub struct IndirectComputeCommandRef; +} + +impl IndirectComputeCommandRef { + pub fn set_compute_pipeline_state(&self, state: &ComputePipelineStateRef) { + unsafe { msg_send![self, setComputePipelineState: state] } + } + + pub fn set_kernel_buffer( + &self, + index: NSUInteger, + buffer: Option<&BufferRef>, + offset: NSUInteger, + ) { + unsafe { + msg_send![self, + setKernelBuffer: buffer + offset: offset + atIndex: index + ] + } + } + + pub fn set_threadgroup_memory_length(&self, index: NSUInteger, length: NSUInteger) { + unsafe { + msg_send![self, + setThreadgroupMemoryLength: length + atIndex: index + ] + } + } + + pub fn set_stage_in_region(&self, region: MTLRegion) { + unsafe { msg_send![self, setStageInRegion: region] } + } + + pub fn set_barrier(&self) { + unsafe { msg_send![self, setBarrier] } + } + + pub fn clear_barrier(&self) { + unsafe { msg_send![self, clearBarrier] } + } + + pub fn concurrent_dispatch_threadgroups( + &self, + thread_groups_per_grid: MTLSize, + threads_per_threadgroup: MTLSize, + ) { + unsafe { + msg_send![self, + concurrentDispatchThreadgroups: thread_groups_per_grid + threadsPerThreadgroup: threads_per_threadgroup + ] + } + } + + pub fn concurrent_dispatch_threads( + &self, + thread_groups_per_grid: MTLSize, + threads_per_threadgroup: MTLSize, + ) { + unsafe { + msg_send![self, + concurrentDispatchThreads: thread_groups_per_grid + threadsPerThreadgroup: threads_per_threadgroup + ] + } + } + + pub fn reset(&self) { + unsafe { msg_send![self, reset] } + } +} 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, or the MIT license , 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 { + _phantom: PhantomData, +} + +pub struct Array(*mut NSArray) +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static; +pub struct ArrayRef(foreign_types::Opaque, PhantomData) +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static; + +impl Drop for Array +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + fn drop(&mut self) { + unsafe { + let () = msg_send![self.0, release]; + } + } +} + +impl Clone for Array +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + fn clone(&self) -> Self { + unsafe { Array(msg_send![self.0, retain]) } + } +} + +unsafe impl objc::Message for NSArray +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ +} +unsafe impl objc::Message for ArrayRef +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ +} + +impl Array +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + pub fn from_slice<'a>(s: &[&T::Ref]) -> &'a ArrayRef { + 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 { + unsafe { + let class = class!(NSArray); + msg_send![class, arrayWithObjects: s.as_ptr() count: s.len()] + } + } +} + +impl foreign_types::ForeignType for Array +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + type CType = NSArray; + type Ref = ArrayRef; + + unsafe fn from_ptr(p: *mut NSArray) -> Self { + Array(p) + } + + fn as_ptr(&self) -> *mut NSArray { + self.0 + } +} + +impl foreign_types::ForeignTypeRef for ArrayRef +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + type CType = NSArray; +} + +impl Deref for Array +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + type Target = ArrayRef; + + #[inline] + fn deref(&self) -> &ArrayRef { + unsafe { mem::transmute(self.as_ptr()) } + } +} + +impl Borrow> for Array +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + fn borrow(&self) -> &ArrayRef { + unsafe { mem::transmute(self.as_ptr()) } + } +} + +impl ToOwned for ArrayRef +where + T: ForeignType + 'static, + T::Ref: objc::Message + 'static, +{ + type Owned = Array; + + fn to_owned(&self) -> Array { + 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(p: *mut T) { + msg_send![(p as *mut Object), release] +} + +#[inline] +unsafe fn obj_clone(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) + } + } +} diff --git a/third_party/rust/metal/src/library.rs b/third_party/rust/metal/src/library.rs new file mode 100644 index 0000000000..9a5a36b62e --- /dev/null +++ b/third_party/rust/metal/src/library.rs @@ -0,0 +1,982 @@ +// 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) +#[repr(u64)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLPatchType { + None = 0, + Triangle = 1, + Quad = 2, +} + +pub enum MTLVertexAttribute {} + +foreign_obj_type! { + type CType = MTLVertexAttribute; + pub struct VertexAttribute; + pub struct VertexAttributeRef; +} + +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 { + match msg_send![self, isActive] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(10.12), ios(10.0) + pub fn is_patch_data(&self) -> bool { + unsafe { + match msg_send![self, isPatchData] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(10.12), ios(10.0) + pub fn is_patch_control_point_data(&self) -> bool { + unsafe { + match msg_send![self, isPatchControlPointData] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } +} + +/// Only available on (macos(10.12), ios(10.0)) +pub enum MTLAttribute {} + +foreign_obj_type! { + type CType = MTLAttribute; + pub struct Attribute; + pub struct AttributeRef; +} + +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 { + match msg_send![self, isActive] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(10.12), ios(10.0)) + pub fn is_patch_data(&self) -> bool { + unsafe { + match msg_send![self, isPatchData] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(10.12), ios(10.0)) + pub fn is_patch_control_point_data(&self) -> bool { + unsafe { + match msg_send![self, isPatchControlPointData] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } +} + +#[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)) +pub enum MTLFunctionConstant {} + +foreign_obj_type! { + type CType = MTLFunctionConstant; + pub struct FunctionConstant; + pub struct FunctionConstantRef; +} + +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 { + match msg_send![self, required] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } +} + +bitflags! { + /// Only available on (macos(11.0), ios(14.0)) + pub struct MTLFunctionOptions: NSUInteger { + const None = 0; + const CompileToBinary = 1 << 0; + } +} + +/// Only available on (macos(11.0), ios(14.0)) +pub enum MTLFunctionDescriptor {} + +foreign_obj_type! { + type CType = MTLFunctionDescriptor; + pub struct FunctionDescriptor; + pub struct FunctionDescriptorRef; +} + +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)) +pub enum MTLIntersectionFunctionDescriptor {} + +foreign_obj_type! { + type CType = MTLIntersectionFunctionDescriptor; + pub struct IntersectionFunctionDescriptor; + pub struct IntersectionFunctionDescriptorRef; + type ParentType = FunctionDescriptorRef; +} + +/// Only available on (macos(11.0), ios(14.0)) +pub enum MTLFunctionHandle {} + +foreign_obj_type! { + type CType = MTLFunctionHandle; + pub struct FunctionHandle; + pub struct FunctionHandleRef; +} + +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 + +pub enum MTLFunction {} + +foreign_obj_type! { + type CType = MTLFunction; + pub struct Function; + pub struct FunctionRef; +} + +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] } + } +} + +#[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, +} + +pub enum MTLFunctionConstantValues {} + +foreign_obj_type! { + type CType = MTLFunctionConstantValues; + pub struct FunctionConstantValues; + pub struct FunctionConstantValuesRef; +} + +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)) +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLLibraryType { + Executable = 0, + Dynamic = 1, +} + +pub enum MTLCompileOptions {} + +foreign_obj_type! { + type CType = MTLCompileOptions; + pub struct CompileOptions; + pub struct CompileOptionsRef; +} + +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 { + match msg_send![self, fastMathEnabled] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + 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 { + match msg_send![self, preserveInvariance] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// 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] } + } +} + +#[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, +} + +pub enum MTLLibrary {} + +foreign_obj_type! { + type CType = MTLLibrary; + pub struct Library; + pub struct LibraryRef; +} + +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(); + let () = msg_send![names, release]; + 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)) +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLDynamicLibraryError { + None = 0, + InvalidFile = 1, + CompilationFailure = 2, + UnresolvedInstallName = 3, + DependencyLoadFailure = 4, + Unsupported = 5, +} + +pub enum MTLDynamicLibrary {} + +foreign_obj_type! { + type CType = MTLDynamicLibrary; + pub struct DynamicLibrary; + pub struct DynamicLibraryRef; +} + +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 { + 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), + _ => unreachable!(), + } + } + } + } +} + +/// macOS 11.0+ iOS 14.0+ +pub enum MTLBinaryArchiveDescriptor {} + +foreign_obj_type! { + type CType = MTLBinaryArchiveDescriptor; + pub struct BinaryArchiveDescriptor; + pub struct BinaryArchiveDescriptorRef; +} + +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+ +pub enum MTLBinaryArchive {} + +foreign_obj_type! { + type CType = MTLBinaryArchive; + pub struct BinaryArchive; + pub struct BinaryArchiveRef; +} + +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 { + let mut err: *mut Object = ptr::null_mut(); + let result: BOOL = msg_send![self, addComputePipelineFunctionsWithDescriptor:descriptor + 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), + _ => unreachable!(), + } + } + } + } + + pub fn add_render_pipeline_functions_with_descriptor( + &self, + descriptor: &RenderPipelineDescriptorRef, + ) -> Result { + unsafe { + let mut err: *mut Object = ptr::null_mut(); + let result: BOOL = msg_send![self, addRenderPipelineFunctionsWithDescriptor:descriptor + 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), + _ => unreachable!(), + } + } + } + } + + // 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), + _ => unreachable!(), + } + } + } + } +} + +/// macOS 11.0+ iOS 14.0+ +pub enum MTLLinkedFunctions {} + +foreign_obj_type! { + type CType = MTLLinkedFunctions; + pub struct LinkedFunctions; + pub struct LinkedFunctionsRef; +} + +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; +} diff --git a/third_party/rust/metal/src/mps.rs b/third_party/rust/metal/src/mps.rs new file mode 100644 index 0000000000..0d4da2eed5 --- /dev/null +++ b/third_party/rust/metal/src/mps.rs @@ -0,0 +1,550 @@ +// Copyright 2020 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 objc::runtime::{BOOL, YES}; + +#[link(name = "MetalPerformanceShaders", kind = "framework")] +extern "C" { + fn MPSSupportsMTLDevice(device: *const std::ffi::c_void) -> BOOL; +} + +pub fn mps_supports_device(device: &DeviceRef) -> bool { + let b: BOOL = unsafe { + let ptr: *const DeviceRef = device; + MPSSupportsMTLDevice(ptr as _) + }; + b == YES +} + +pub enum MPSKernel {} + +foreign_obj_type! { + type CType = MPSKernel; + pub struct Kernel; + pub struct KernelRef; +} + +pub enum MPSRayDataType { + OriginDirection = 0, + OriginMinDistanceDirectionMaxDistance = 1, + OriginMaskDirectionMaxDistance = 2, +} + +bitflags! { + #[allow(non_upper_case_globals)] + pub struct MPSRayMaskOptions: NSUInteger { + /// Enable primitive masks + const Primitive = 1; + /// Enable instance masks + const Instance = 2; + } +} + +/// Options that determine the data contained in an intersection result. +pub enum MPSIntersectionDataType { + Distance = 0, + DistancePrimitiveIndex = 1, + DistancePrimitiveIndexCoordinates = 2, + DistancePrimitiveIndexInstanceIndex = 3, + DistancePrimitiveIndexInstanceIndexCoordinates = 4, +} + +pub enum MPSIntersectionType { + /// Find the closest intersection to the ray's origin along the ray direction. + /// This is potentially slower than `Any` but is well suited to primary visibility rays. + Nearest = 0, + /// Find any intersection along the ray direction. This is potentially faster than `Nearest` and + /// is well suited to shadow and occlusion rays. + Any = 1, +} + +pub enum MPSRayMaskOperator { + /// Accept the intersection if `(primitive mask & ray mask) != 0`. + And = 0, + /// Accept the intersection if `~(primitive mask & ray mask) != 0`. + NotAnd = 1, + /// Accept the intersection if `(primitive mask | ray mask) != 0`. + Or = 2, + /// Accept the intersection if `~(primitive mask | ray mask) != 0`. + NotOr = 3, + /// Accept the intersection if `(primitive mask ^ ray mask) != 0`. + /// Note that this is equivalent to the "!=" operator. + Xor = 4, + /// Accept the intersection if `~(primitive mask ^ ray mask) != 0`. + /// Note that this is equivalent to the "==" operator. + NotXor = 5, + /// Accept the intersection if `(primitive mask < ray mask) != 0`. + LessThan = 6, + /// Accept the intersection if `(primitive mask <= ray mask) != 0`. + LessThanOrEqualTo = 7, + /// Accept the intersection if `(primitive mask > ray mask) != 0`. + GreaterThan = 8, + /// Accept the intersection if `(primitive mask >= ray mask) != 0`. + GreaterThanOrEqualTo = 9, +} + +pub enum MPSTriangleIntersectionTestType { + /// Use the default ray/triangle intersection test + Default = 0, + /// Use a watertight ray/triangle intersection test which avoids gaps along shared triangle edges. + /// Shared vertices may still have gaps. + /// This intersection test may be slower than `Default`. + Watertight = 1, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MPSAccelerationStructureStatus { + Unbuilt = 0, + Built = 1, +} + +bitflags! { + #[allow(non_upper_case_globals)] + pub struct MPSAccelerationStructureUsage: NSUInteger { + /// No usage options specified + const None = 0; + /// Option that enables support for refitting the acceleration structure after it has been built. + const Refit = 1; + /// Option indicating that the acceleration structure will be rebuilt frequently. + const FrequentRebuild = 2; + const PreferGPUBuild = 4; + const PreferCPUBuild = 8; + } +} + +/// A common bit for all floating point data types. +const MPSDataTypeFloatBit: isize = 0x10000000; +const MPSDataTypeSignedBit: isize = 0x20000000; +const MPSDataTypeNormalizedBit: isize = 0x40000000; + +pub enum MPSDataType { + Invalid = 0, + + Float32 = MPSDataTypeFloatBit | 32, + Float16 = MPSDataTypeFloatBit | 16, + + // Signed integers. + Int8 = MPSDataTypeSignedBit | 8, + Int16 = MPSDataTypeSignedBit | 16, + Int32 = MPSDataTypeSignedBit | 32, + + // Unsigned integers. Range: [0, UTYPE_MAX] + UInt8 = 8, + UInt16 = 16, + UInt32 = 32, + + // Unsigned normalized. Range: [0, 1.0] + Unorm1 = MPSDataTypeNormalizedBit | 1, + Unorm8 = MPSDataTypeNormalizedBit | 8, +} + +/// A kernel that performs intersection tests between rays and geometry. +pub enum MPSRayIntersector {} + +foreign_obj_type! { + type CType = MPSRayIntersector; + pub struct RayIntersector; + pub struct RayIntersectorRef; + type ParentType = KernelRef; +} + +impl RayIntersector { + pub fn from_device(device: &DeviceRef) -> Option { + unsafe { + let intersector: RayIntersector = msg_send![class!(MPSRayIntersector), alloc]; + let ptr: *mut Object = msg_send![intersector.as_ref(), initWithDevice: device]; + if ptr.is_null() { + None + } else { + Some(intersector) + } + } + } +} + +impl RayIntersectorRef { + pub fn set_cull_mode(&self, mode: MTLCullMode) { + unsafe { msg_send![self, setCullMode: mode] } + } + + pub fn set_front_facing_winding(&self, winding: MTLWinding) { + unsafe { msg_send![self, setFrontFacingWinding: winding] } + } + + pub fn set_intersection_data_type(&self, options: MPSIntersectionDataType) { + unsafe { msg_send![self, setIntersectionDataType: options] } + } + + pub fn set_intersection_stride(&self, stride: NSUInteger) { + unsafe { msg_send![self, setIntersectionStride: stride] } + } + + pub fn set_ray_data_type(&self, ty: MPSRayDataType) { + unsafe { msg_send![self, setRayDataType: ty] } + } + + pub fn set_ray_index_data_type(&self, ty: MPSDataType) { + unsafe { msg_send![self, setRayIndexDataType: ty] } + } + + pub fn set_ray_mask(&self, ray_mask: u32) { + unsafe { msg_send![self, setRayMask: ray_mask] } + } + + pub fn set_ray_mask_operator(&self, operator: MPSRayMaskOperator) { + unsafe { msg_send![self, setRayMaskOperator: operator] } + } + + pub fn set_ray_mask_options(&self, options: MPSRayMaskOptions) { + unsafe { msg_send![self, setRayMaskOptions: options] } + } + + pub fn set_ray_stride(&self, stride: NSUInteger) { + unsafe { msg_send![self, setRayStride: stride] } + } + + pub fn set_triangle_intersection_test_type(&self, test_type: MPSTriangleIntersectionTestType) { + unsafe { msg_send![self, setTriangleIntersectionTestType: test_type] } + } + + pub fn encode_intersection_to_command_buffer( + &self, + command_buffer: &CommandBufferRef, + intersection_type: MPSIntersectionType, + ray_buffer: &BufferRef, + ray_buffer_offset: NSUInteger, + intersection_buffer: &BufferRef, + intersection_buffer_offset: NSUInteger, + ray_count: NSUInteger, + acceleration_structure: &AccelerationStructureRef, + ) { + unsafe { + msg_send![ + self, + encodeIntersectionToCommandBuffer: command_buffer + intersectionType: intersection_type + rayBuffer: ray_buffer + rayBufferOffset: ray_buffer_offset + intersectionBuffer: intersection_buffer + intersectionBufferOffset: intersection_buffer_offset + rayCount: ray_count + accelerationStructure: acceleration_structure + ] + } + } + + pub fn recommended_minimum_ray_batch_size_for_ray_count( + &self, + ray_count: NSUInteger, + ) -> NSUInteger { + unsafe { msg_send![self, recommendedMinimumRayBatchSizeForRayCount: ray_count] } + } +} + +/// A group of acceleration structures which may be used together in an instance acceleration structure +pub enum MPSAccelerationStructureGroup {} + +foreign_obj_type! { + type CType = MPSAccelerationStructureGroup; + pub struct AccelerationStructureGroup; + pub struct AccelerationStructureGroupRef; +} + +impl AccelerationStructureGroup { + pub fn new_with_device(device: &DeviceRef) -> Option { + unsafe { + let group: AccelerationStructureGroup = + msg_send![class!(MPSAccelerationStructureGroup), alloc]; + let ptr: *mut Object = msg_send![group.as_ref(), initWithDevice: device]; + if ptr.is_null() { + None + } else { + Some(group) + } + } + } +} + +impl AccelerationStructureGroupRef { + pub fn device(&self) -> &DeviceRef { + unsafe { msg_send![self, device] } + } +} + +/// The base class for data structures that are built over geometry and used to accelerate ray tracing. +pub enum MPSAccelerationStructure {} + +foreign_obj_type! { + type CType = MPSAccelerationStructure; + pub struct AccelerationStructure; + pub struct AccelerationStructureRef; +} + +impl AccelerationStructureRef { + pub fn status(&self) -> MPSAccelerationStructureStatus { + unsafe { msg_send![self, status] } + } + + pub fn usage(&self) -> MPSAccelerationStructureUsage { + unsafe { msg_send![self, usage] } + } + + pub fn set_usage(&self, usage: MPSAccelerationStructureUsage) { + unsafe { msg_send![self, setUsage: usage] } + } + + pub fn group(&self) -> &AccelerationStructureGroupRef { + unsafe { msg_send![self, group] } + } + + pub fn encode_refit_to_command_buffer(&self, buffer: &CommandBufferRef) { + unsafe { msg_send![self, encodeRefitToCommandBuffer: buffer] } + } + + pub fn rebuild(&self) { + unsafe { msg_send![self, rebuild] } + } +} + +pub enum MPSPolygonAccelerationStructure {} + +foreign_obj_type! { + type CType = MPSPolygonAccelerationStructure; + pub struct PolygonAccelerationStructure; + pub struct PolygonAccelerationStructureRef; + type ParentType = AccelerationStructureRef; +} + +impl PolygonAccelerationStructureRef { + pub fn set_index_buffer(&self, buffer: Option<&BufferRef>) { + unsafe { msg_send![self, setIndexBuffer: buffer] } + } + + pub fn set_index_buffer_offset(&self, offset: NSUInteger) { + unsafe { msg_send![self, setIndexBufferOffset: offset] } + } + + pub fn set_index_type(&self, data_type: MPSDataType) { + unsafe { msg_send![self, setIndexType: data_type] } + } + + pub fn set_mask_buffer(&self, buffer: Option<&BufferRef>) { + unsafe { msg_send![self, setMaskBuffer: buffer] } + } + + pub fn set_mask_buffer_offset(&self, offset: NSUInteger) { + unsafe { msg_send![self, setMaskBufferOffset: offset] } + } + + pub fn set_vertex_buffer(&self, buffer: Option<&BufferRef>) { + unsafe { msg_send![self, setVertexBuffer: buffer] } + } + + pub fn set_vertex_buffer_offset(&self, offset: NSUInteger) { + unsafe { msg_send![self, setVertexBufferOffset: offset] } + } + + pub fn set_vertex_stride(&self, stride: NSUInteger) { + unsafe { msg_send![self, setVertexStride: stride] } + } +} + +/// An acceleration structure built over triangles. +pub enum MPSTriangleAccelerationStructure {} + +foreign_obj_type! { + type CType = MPSTriangleAccelerationStructure; + pub struct TriangleAccelerationStructure; + pub struct TriangleAccelerationStructureRef; + type ParentType = PolygonAccelerationStructureRef; +} + +impl TriangleAccelerationStructure { + pub fn from_device(device: &DeviceRef) -> Option { + unsafe { + let structure: TriangleAccelerationStructure = + msg_send![class!(MPSTriangleAccelerationStructure), alloc]; + let ptr: *mut Object = msg_send![structure.as_ref(), initWithDevice: device]; + if ptr.is_null() { + None + } else { + Some(structure) + } + } + } +} + +impl TriangleAccelerationStructureRef { + pub fn triangle_count(&self) -> NSUInteger { + unsafe { msg_send![self, triangleCount] } + } + + pub fn set_triangle_count(&self, count: NSUInteger) { + unsafe { msg_send![self, setTriangleCount: count] } + } +} + +#[repr(u64)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MPSTransformType { + Float4x4 = 0, + Identity = 1, +} + +/// An acceleration structure built over instances of other acceleration structures +pub enum MPSInstanceAccelerationStructure {} + +foreign_obj_type! { + type CType = MPSInstanceAccelerationStructure; + pub struct InstanceAccelerationStructure; + pub struct InstanceAccelerationStructureRef; + type ParentType = AccelerationStructureRef; +} + +impl InstanceAccelerationStructure { + pub fn init_with_group(group: &AccelerationStructureGroupRef) -> Option { + unsafe { + let structure: InstanceAccelerationStructure = + msg_send![class!(MPSInstanceAccelerationStructure), alloc]; + let ptr: *mut Object = msg_send![structure.as_ref(), initWithGroup: group]; + if ptr.is_null() { + None + } else { + Some(structure) + } + } + } +} + +impl InstanceAccelerationStructureRef { + /// Marshal to Rust Vec + pub fn acceleration_structures(&self) -> Vec { + unsafe { + let acs: *mut Object = msg_send![self, accelerationStructures]; + let count: NSUInteger = msg_send![acs, count]; + let ret = (0..count) + .map(|i| { + let ac = msg_send![acs, objectAtIndex: i]; + PolygonAccelerationStructure::from_ptr(ac) + }) + .collect(); + ret + } + } + + /// Marshal from Rust slice + pub fn set_acceleration_structures(&self, acs: &[&PolygonAccelerationStructureRef]) { + let ns_array = Array::::from_slice(acs); + unsafe { msg_send![self, setAccelerationStructures: ns_array] } + } + + pub fn instance_buffer(&self) -> &BufferRef { + unsafe { msg_send![self, instanceBuffer] } + } + + pub fn set_instance_buffer(&self, buffer: &BufferRef) { + unsafe { msg_send![self, setInstanceBuffer: buffer] } + } + + pub fn instance_buffer_offset(&self) -> NSUInteger { + unsafe { msg_send![self, instanceBufferOffset] } + } + + pub fn set_instance_buffer_offset(&self, offset: NSUInteger) { + unsafe { msg_send![self, setInstanceBufferOffset: offset] } + } + + pub fn transform_buffer(&self) -> &BufferRef { + unsafe { msg_send![self, transformBuffer] } + } + + pub fn set_transform_buffer(&self, buffer: &BufferRef) { + unsafe { msg_send![self, setTransformBuffer: buffer] } + } + + pub fn transform_buffer_offset(&self) -> NSUInteger { + unsafe { msg_send![self, transformBufferOffset] } + } + + pub fn set_transform_buffer_offset(&self, offset: NSUInteger) { + unsafe { msg_send![self, setTransformBufferOffset: offset] } + } + + pub fn transform_type(&self) -> MPSTransformType { + unsafe { msg_send![self, transformType] } + } + + pub fn set_transform_type(&self, transform_type: MPSTransformType) { + unsafe { msg_send![self, setTransformType: transform_type] } + } + + pub fn mask_buffer(&self) -> &BufferRef { + unsafe { msg_send![self, maskBuffer] } + } + + pub fn set_mask_buffer(&self, buffer: &BufferRef) { + unsafe { msg_send![self, setMaskBuffer: buffer] } + } + + pub fn mask_buffer_offset(&self) -> NSUInteger { + unsafe { msg_send![self, maskBufferOffset] } + } + + pub fn set_mask_buffer_offset(&self, offset: NSUInteger) { + unsafe { msg_send![self, setMaskBufferOffset: offset] } + } + + pub fn instance_count(&self) -> NSUInteger { + unsafe { msg_send![self, instanceCount] } + } + + pub fn set_instance_count(&self, count: NSUInteger) { + unsafe { msg_send![self, setInstanceCount: count] } + } +} + +#[repr(C)] +pub struct MPSPackedFloat3 { + pub elements: [f32; 3], +} + +/// Represents a 3D ray with an origin, a direction, and an intersection distance range from the origin. +#[repr(C)] +pub struct MPSRayOriginMinDistanceDirectionMaxDistance { + /// Ray origin. The intersection test will be skipped if the origin contains NaNs or infinities. + pub origin: MPSPackedFloat3, + /// Minimum intersection distance from the origin along the ray direction. + /// The intersection test will be skipped if the minimum distance is equal to positive infinity or NaN. + pub min_distance: f32, + /// Ray direction. Does not need to be normalized. The intersection test will be skipped if + /// the direction has length zero or contains NaNs or infinities. + pub direction: MPSPackedFloat3, + /// Maximum intersection distance from the origin along the ray direction. May be infinite. + /// The intersection test will be skipped if the maximum distance is less than zero, NaN, or + /// less than the minimum intersection distance. + pub max_distance: f32, +} + +/// Intersection result which contains the distance from the ray origin to the intersection point, +/// the index of the intersected primitive, and the first two barycentric coordinates of the intersection point. +#[repr(C)] +pub struct MPSIntersectionDistancePrimitiveIndexCoordinates { + /// Distance from the ray origin to the intersection point along the ray direction vector such + /// that `intersection = ray.origin + ray.direction * distance`. + /// Is negative if there is no intersection. If the intersection type is `MPSIntersectionTypeAny`, + /// is a positive value for a hit or a negative value for a miss. + pub distance: f32, + /// Index of the intersected primitive. Undefined if the ray does not intersect a primitive or + /// if the intersection type is `MPSIntersectionTypeAny`. + pub primitive_index: u32, + /// The first two barycentric coordinates `U` and `V` of the intersection point. + /// The third coordinate `W = 1 - U - V`. Undefined if the ray does not intersect a primitive or + /// if the intersection type is `MPSIntersectionTypeAny`. + pub coordinates: [f32; 2], +} diff --git a/third_party/rust/metal/src/pipeline/compute.rs b/third_party/rust/metal/src/pipeline/compute.rs new file mode 100644 index 0000000000..138b561cb3 --- /dev/null +++ b/third_party/rust/metal/src/pipeline/compute.rs @@ -0,0 +1,488 @@ +// 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 objc::runtime::{NO, YES}; + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLAttributeFormat { + Invalid = 0, + UChar2 = 1, + UChar3 = 2, + UChar4 = 3, + Char2 = 4, + Char3 = 5, + Char4 = 6, + UChar2Normalized = 7, + UChar3Normalized = 8, + UChar4Normalized = 9, + Char2Normalized = 10, + Char3Normalized = 11, + Char4Normalized = 12, + UShort2 = 13, + UShort3 = 14, + UShort4 = 15, + Short2 = 16, + Short3 = 17, + Short4 = 18, + UShort2Normalized = 19, + UShort3Normalized = 20, + UShort4Normalized = 21, + Short2Normalized = 22, + Short3Normalized = 23, + Short4Normalized = 24, + Half2 = 25, + Half3 = 26, + Half4 = 27, + Float = 28, + Float2 = 29, + Float3 = 30, + Float4 = 31, + Int = 32, + Int2 = 33, + Int3 = 34, + Int4 = 35, + UInt = 36, + UInt2 = 37, + UInt3 = 38, + UInt4 = 39, + Int1010102Normalized = 40, + UInt1010102Normalized = 41, + UChar4Normalized_BGRA = 42, + UChar = 45, + Char = 46, + UCharNormalized = 47, + CharNormalized = 48, + UShort = 49, + Short = 50, + UShortNormalized = 51, + ShortNormalized = 52, + Half = 53, +} + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLStepFunction { + Constant = 0, + PerInstance = 1, + PerPatch = 2, + PerPatchControlPoint = 3, + PerVertex = 4, + ThreadPositionInGridX = 5, + ThreadPositionInGridXIndexed = 6, + ThreadPositionInGridY = 7, + ThreadPositionInGridYIndexed = 8, +} + +pub enum MTLComputePipelineDescriptor {} + +foreign_obj_type! { + type CType = MTLComputePipelineDescriptor; + pub struct ComputePipelineDescriptor; + pub struct ComputePipelineDescriptorRef; +} + +impl ComputePipelineDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLComputePipelineDescriptor); + msg_send![class, new] + } + } +} + +impl ComputePipelineDescriptorRef { + 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 compute_function(&self) -> Option<&FunctionRef> { + unsafe { msg_send![self, computeFunction] } + } + + pub fn set_compute_function(&self, function: Option<&FunctionRef>) { + unsafe { msg_send![self, setComputeFunction: function] } + } + + pub fn thread_group_size_is_multiple_of_thread_execution_width(&self) -> bool { + unsafe { + match msg_send![self, threadGroupSizeIsMultipleOfThreadExecutionWidth] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_thread_group_size_is_multiple_of_thread_execution_width( + &self, + size_is_multiple_of_width: bool, + ) { + unsafe { + msg_send![ + self, + setThreadGroupSizeIsMultipleOfThreadExecutionWidth: size_is_multiple_of_width + ] + } + } + + /// API_AVAILABLE(macos(10.14), ios(12.0)); + pub fn max_total_threads_per_threadgroup(&self) -> NSUInteger { + unsafe { msg_send![self, maxTotalThreadsPerThreadgroup] } + } + + /// API_AVAILABLE(macos(10.14), ios(12.0)); + pub fn set_max_total_threads_per_threadgroup(&self, max_total_threads: NSUInteger) { + unsafe { msg_send![self, setMaxTotalThreadsPerThreadgroup: max_total_threads] } + } + + /// API_AVAILABLE(ios(13.0),macos(11.0)); + pub fn support_indirect_command_buffers(&self) -> bool { + unsafe { + match msg_send![self, supportIndirectCommandBuffers] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// API_AVAILABLE(ios(13.0),macos(11.0)); + pub fn set_support_indirect_command_buffers(&self, support: bool) { + unsafe { msg_send![self, setSupportIndirectCommandBuffers: support] } + } + + /// API_AVAILABLE(macos(11.0), ios(14.0)); + pub fn support_adding_binary_functions(&self) -> bool { + unsafe { + match msg_send![self, supportAddingBinaryFunctions] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// API_AVAILABLE(macos(11.0), ios(14.0)); + pub fn set_support_adding_binary_functions(&self, support: bool) { + unsafe { msg_send![self, setSupportAddingBinaryFunctions: support] } + } + + /// API_AVAILABLE(macos(11.0), ios(14.0)); + pub fn max_call_stack_depth(&self) -> NSUInteger { + unsafe { msg_send![self, maxCallStackDepth] } + } + + /// API_AVAILABLE(macos(11.0), ios(14.0)); + pub fn set_max_call_stack_depth(&self, depth: NSUInteger) { + unsafe { msg_send![self, setMaxCallStackDepth: depth] } + } + + /// API_AVAILABLE(macos(11.0), ios(14.0)); + /// Marshal to Rust Vec + pub fn insert_libraries(&self) -> Vec { + unsafe { + let libraries: *mut Object = msg_send![self, insertLibraries]; + 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 + } + } + + /// Marshal from Rust slice + pub fn set_insert_libraries(&self, libraries: &[&DynamicLibraryRef]) { + let ns_array = Array::::from_slice(libraries); + unsafe { msg_send![self, setInsertLibraries: ns_array] } + } + + /// API_AVAILABLE(macos(11.0), ios(14.0)); + /// Marshal to Rust Vec + pub fn binary_archives(&self) -> Vec { + unsafe { + let archives: *mut Object = msg_send![self, binaryArchives]; + let count: NSUInteger = msg_send![archives, count]; + let ret = (0..count) + .map(|i| { + let a = msg_send![archives, objectAtIndex: i]; + BinaryArchive::from_ptr(a) + }) + .collect(); + ret + } + } + + /// API_AVAILABLE(macos(11.0), ios(14.0)); + /// Marshal from Rust slice + pub fn set_binary_archives(&self, archives: &[&BinaryArchiveRef]) { + let ns_array = Array::::from_slice(archives); + unsafe { msg_send![self, setBinaryArchives: ns_array] } + } + + /// API_AVAILABLE(macos(11.0), ios(14.0)); + pub fn linked_functions(&self) -> &LinkedFunctionsRef { + unsafe { msg_send![self, linkedFunctions] } + } + + /// API_AVAILABLE(macos(11.0), ios(14.0)); + pub fn set_linked_functions(&self, functions: &LinkedFunctionsRef) { + unsafe { msg_send![self, setLinkedFunctions: functions] } + } + + pub fn stage_input_descriptor(&self) -> Option<&StageInputOutputDescriptorRef> { + unsafe { msg_send![self, stageInputDescriptor] } + } + + pub fn set_stage_input_descriptor(&self, descriptor: Option<&StageInputOutputDescriptorRef>) { + unsafe { msg_send![self, setStageInputDescriptor: descriptor] } + } + + pub fn buffers(&self) -> Option<&PipelineBufferDescriptorArrayRef> { + unsafe { msg_send![self, buffers] } + } + + pub fn reset(&self) { + unsafe { msg_send![self, reset] } + } +} + +pub enum MTLComputePipelineState {} + +foreign_obj_type! { + type CType = MTLComputePipelineState; + pub struct ComputePipelineState; + pub struct ComputePipelineStateRef; +} + +impl ComputePipelineStateRef { + pub fn label(&self) -> &str { + unsafe { + let label = msg_send![self, label]; + crate::nsstring_as_str(label) + } + } + + pub fn max_total_threads_per_threadgroup(&self) -> NSUInteger { + unsafe { msg_send![self, maxTotalThreadsPerThreadgroup] } + } + + pub fn thread_execution_width(&self) -> NSUInteger { + unsafe { msg_send![self, threadExecutionWidth] } + } + + pub fn static_threadgroup_memory_length(&self) -> NSUInteger { + unsafe { msg_send![self, staticThreadgroupMemoryLength] } + } + + /// Only available on (ios(11.0), macos(11.0), macCatalyst(14.0)) NOT available on (tvos) + pub fn imageblock_memory_length_for_dimensions(&self, dimensions: MTLSize) -> NSUInteger { + unsafe { msg_send![self, imageblockMemoryLengthForDimensions: dimensions] } + } + + /// Only available on (ios(13.0), macos(11.0)) + pub fn support_indirect_command_buffers(&self) -> bool { + unsafe { + match msg_send![self, supportIndirectCommandBuffers] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + /// Only available on (macos(11.0), ios(14.0)) + pub fn function_handle_with_function( + &self, + function: &FunctionRef, + ) -> Option<&FunctionHandleRef> { + unsafe { msg_send![self, functionHandleWithFunction: function] } + } + + // API_AVAILABLE(macos(11.0), ios(14.0)); + // TODO: newComputePipelineStateWithAdditionalBinaryFunctions + // - (nullable id )newComputePipelineStateWithAdditionalBinaryFunctions:(nonnull NSArray> *)functions error:(__autoreleasing NSError **)error + + // API_AVAILABLE(macos(11.0), ios(14.0)); + // TODO: newVisibleFunctionTableWithDescriptor + // - (nullable id)newVisibleFunctionTableWithDescriptor:(MTLVisibleFunctionTableDescriptor * __nonnull)descriptor + // API_AVAILABLE(macos(11.0), ios(14.0)); + // TODO: newIntersectionFunctionTableWithDescriptor + // - (nullable id )newIntersectionFunctionTableWithDescriptor:(MTLIntersectionFunctionTableDescriptor * _Nonnull)descriptor +} + +pub enum MTLStageInputOutputDescriptor {} + +foreign_obj_type! { + type CType = MTLStageInputOutputDescriptor; + pub struct StageInputOutputDescriptor; + pub struct StageInputOutputDescriptorRef; +} + +impl StageInputOutputDescriptor { + pub fn new<'a>() -> &'a StageInputOutputDescriptorRef { + unsafe { + let class = class!(MTLStageInputOutputDescriptor); + msg_send![class, stageInputOutputDescriptor] + } + } +} + +impl StageInputOutputDescriptorRef { + pub fn attributes(&self) -> Option<&AttributeDescriptorArrayRef> { + unsafe { msg_send![self, attributes] } + } + + pub fn index_buffer_index(&self) -> NSUInteger { + unsafe { msg_send![self, indexBufferIndex] } + } + + pub fn set_index_buffer_index(&self, idx_buffer_idx: NSUInteger) { + unsafe { msg_send![self, setIndexBufferIndex: idx_buffer_idx] } + } + + pub fn index_type(&self) -> MTLIndexType { + unsafe { msg_send![self, indexType] } + } + + pub fn set_index_type(&self, index_ty: MTLIndexType) { + unsafe { msg_send![self, setIndexType: index_ty] } + } + + pub fn layouts(&self) -> Option<&BufferLayoutDescriptorArrayRef> { + unsafe { msg_send![self, layouts] } + } + + pub fn reset(&self) { + unsafe { msg_send![self, reset] } + } +} + +pub enum MTLAttributeDescriptorArray {} + +foreign_obj_type! { + type CType = MTLAttributeDescriptorArray; + pub struct AttributeDescriptorArray; + pub struct AttributeDescriptorArrayRef; +} + +impl AttributeDescriptorArrayRef { + pub fn object_at(&self, index: NSUInteger) -> Option<&AttributeDescriptorRef> { + unsafe { msg_send![self, objectAtIndexedSubscript: index] } + } + + pub fn set_object_at(&self, index: NSUInteger, buffer_desc: Option<&AttributeDescriptorRef>) { + unsafe { msg_send![self, setObject:buffer_desc atIndexedSubscript:index] } + } +} + +pub enum MTLAttributeDescriptor {} + +foreign_obj_type! { + type CType = MTLAttributeDescriptor; + pub struct AttributeDescriptor; + pub struct AttributeDescriptorRef; +} + +impl AttributeDescriptorRef { + pub fn buffer_index(&self) -> NSUInteger { + unsafe { msg_send![self, bufferIndex] } + } + + pub fn set_buffer_index(&self, buffer_index: NSUInteger) { + unsafe { msg_send![self, setBufferIndex: buffer_index] } + } + + pub fn format(&self) -> MTLAttributeFormat { + unsafe { msg_send![self, format] } + } + + pub fn set_format(&self, format: MTLAttributeFormat) { + unsafe { msg_send![self, setFormat: format] } + } + + pub fn offset(&self) -> NSUInteger { + unsafe { msg_send![self, offset] } + } + + pub fn set_offset(&self, offset: NSUInteger) { + unsafe { msg_send![self, setOffset: offset] } + } +} + +pub enum MTLBufferLayoutDescriptorArray {} + +foreign_obj_type! { + type CType = MTLBufferLayoutDescriptorArray; + pub struct BufferLayoutDescriptorArray; + pub struct BufferLayoutDescriptorArrayRef; +} + +impl BufferLayoutDescriptorArrayRef { + pub fn object_at(&self, index: NSUInteger) -> Option<&BufferLayoutDescriptorRef> { + unsafe { msg_send![self, objectAtIndexedSubscript: index] } + } + + pub fn set_object_at( + &self, + index: NSUInteger, + buffer_desc: Option<&BufferLayoutDescriptorRef>, + ) { + unsafe { msg_send![self, setObject:buffer_desc atIndexedSubscript:index] } + } +} + +pub enum MTLBufferLayoutDescriptor {} + +foreign_obj_type! { + type CType = MTLBufferLayoutDescriptor; + pub struct BufferLayoutDescriptor; + pub struct BufferLayoutDescriptorRef; +} + +impl BufferLayoutDescriptorRef { + pub fn step_function(&self) -> MTLStepFunction { + unsafe { msg_send![self, stepFunction] } + } + + pub fn set_step_function(&self, step_function: MTLStepFunction) { + unsafe { msg_send![self, setStepFunction: step_function] } + } + + pub fn step_rate(&self) -> NSUInteger { + unsafe { msg_send![self, stepRate] } + } + + pub fn set_step_rate(&self, step_rate: NSUInteger) { + unsafe { msg_send![self, setStepRate: step_rate] } + } + + pub fn stride(&self) -> NSUInteger { + unsafe { msg_send![self, stride] } + } + + pub fn set_stride(&self, stride: NSUInteger) { + unsafe { msg_send![self, setStride: stride] } + } +} diff --git a/third_party/rust/metal/src/pipeline/mod.rs b/third_party/rust/metal/src/pipeline/mod.rs new file mode 100644 index 0000000000..e65d28d6ca --- /dev/null +++ b/third_party/rust/metal/src/pipeline/mod.rs @@ -0,0 +1,70 @@ +// 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::*; + +mod compute; +mod render; + +pub use self::compute::*; +pub use self::render::*; + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLMutability { + Default = 0, + Mutable = 1, + Immutable = 2, +} + +impl Default for MTLMutability { + #[inline] + fn default() -> Self { + MTLMutability::Default + } +} + +pub enum MTLPipelineBufferDescriptorArray {} + +foreign_obj_type! { + type CType = MTLPipelineBufferDescriptorArray; + pub struct PipelineBufferDescriptorArray; + pub struct PipelineBufferDescriptorArrayRef; +} + +impl PipelineBufferDescriptorArrayRef { + pub fn object_at(&self, index: NSUInteger) -> Option<&PipelineBufferDescriptorRef> { + unsafe { msg_send![self, objectAtIndexedSubscript: index] } + } + + pub fn set_object_at( + &self, + index: NSUInteger, + buffer_desc: Option<&PipelineBufferDescriptorRef>, + ) { + unsafe { msg_send![self, setObject:buffer_desc atIndexedSubscript:index] } + } +} + +pub enum MTLPipelineBufferDescriptor {} + +foreign_obj_type! { + type CType = MTLPipelineBufferDescriptor; + pub struct PipelineBufferDescriptor; + pub struct PipelineBufferDescriptorRef; +} + +impl PipelineBufferDescriptorRef { + pub fn mutability(&self) -> MTLMutability { + unsafe { msg_send![self, mutability] } + } + + pub fn set_mutability(&self, new_mutability: MTLMutability) { + unsafe { msg_send![self, setMutability: new_mutability] } + } +} diff --git a/third_party/rust/metal/src/pipeline/render.rs b/third_party/rust/metal/src/pipeline/render.rs new file mode 100644 index 0000000000..a4b3a629e1 --- /dev/null +++ b/third_party/rust/metal/src/pipeline/render.rs @@ -0,0 +1,510 @@ +// 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 objc::runtime::{NO, YES}; + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLBlendFactor { + Zero = 0, + One = 1, + SourceColor = 2, + OneMinusSourceColor = 3, + SourceAlpha = 4, + OneMinusSourceAlpha = 5, + DestinationColor = 6, + OneMinusDestinationColor = 7, + DestinationAlpha = 8, + OneMinusDestinationAlpha = 9, + SourceAlphaSaturated = 10, + BlendColor = 11, + OneMinusBlendColor = 12, + BlendAlpha = 13, + OneMinusBlendAlpha = 14, + Source1Color = 15, + OneMinusSource1Color = 16, + Source1Alpha = 17, + OneMinusSource1Alpha = 18, +} + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLBlendOperation { + Add = 0, + Subtract = 1, + ReverseSubtract = 2, + Min = 3, + Max = 4, +} + +bitflags! { + pub struct MTLColorWriteMask: NSUInteger { + const None = 0; + const Red = 0x1 << 3; + const Green = 0x1 << 2; + const Blue = 0x1 << 1; + const Alpha = 0x1 << 0; + const All = 0xf; + } +} + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLPrimitiveTopologyClass { + Unspecified = 0, + Point = 1, + Line = 2, + Triangle = 3, +} + +// TODO: MTLTessellationPartitionMode +// TODO: MTLTessellationFactorStepFunction +// TODO: MTLTessellationFactorFormat +// TODO: MTLTessellationControlPointIndexType + +pub enum MTLRenderPipelineColorAttachmentDescriptor {} + +foreign_obj_type! { + type CType = MTLRenderPipelineColorAttachmentDescriptor; + pub struct RenderPipelineColorAttachmentDescriptor; + pub struct RenderPipelineColorAttachmentDescriptorRef; +} + +impl RenderPipelineColorAttachmentDescriptorRef { + 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 is_blending_enabled(&self) -> bool { + unsafe { + match msg_send![self, isBlendingEnabled] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_blending_enabled(&self, enabled: bool) { + unsafe { msg_send![self, setBlendingEnabled: enabled] } + } + + pub fn source_rgb_blend_factor(&self) -> MTLBlendFactor { + unsafe { msg_send![self, sourceRGBBlendFactor] } + } + + pub fn set_source_rgb_blend_factor(&self, blend_factor: MTLBlendFactor) { + unsafe { msg_send![self, setSourceRGBBlendFactor: blend_factor] } + } + + pub fn destination_rgb_blend_factor(&self) -> MTLBlendFactor { + unsafe { msg_send![self, destinationRGBBlendFactor] } + } + + pub fn set_destination_rgb_blend_factor(&self, blend_factor: MTLBlendFactor) { + unsafe { msg_send![self, setDestinationRGBBlendFactor: blend_factor] } + } + + pub fn rgb_blend_operation(&self) -> MTLBlendOperation { + unsafe { msg_send![self, rgbBlendOperation] } + } + + pub fn set_rgb_blend_operation(&self, blend_operation: MTLBlendOperation) { + unsafe { msg_send![self, setRgbBlendOperation: blend_operation] } + } + + pub fn source_alpha_blend_factor(&self) -> MTLBlendFactor { + unsafe { msg_send![self, sourceAlphaBlendFactor] } + } + + pub fn set_source_alpha_blend_factor(&self, blend_factor: MTLBlendFactor) { + unsafe { msg_send![self, setSourceAlphaBlendFactor: blend_factor] } + } + + pub fn destination_alpha_blend_factor(&self) -> MTLBlendFactor { + unsafe { msg_send![self, destinationAlphaBlendFactor] } + } + + pub fn set_destination_alpha_blend_factor(&self, blend_factor: MTLBlendFactor) { + unsafe { msg_send![self, setDestinationAlphaBlendFactor: blend_factor] } + } + + pub fn alpha_blend_operation(&self) -> MTLBlendOperation { + unsafe { msg_send![self, alphaBlendOperation] } + } + + pub fn set_alpha_blend_operation(&self, blend_operation: MTLBlendOperation) { + unsafe { msg_send![self, setAlphaBlendOperation: blend_operation] } + } + + pub fn write_mask(&self) -> MTLColorWriteMask { + unsafe { msg_send![self, writeMask] } + } + + pub fn set_write_mask(&self, mask: MTLColorWriteMask) { + unsafe { msg_send![self, setWriteMask: mask] } + } +} + +pub enum MTLRenderPipelineReflection {} + +foreign_obj_type! { + type CType = MTLRenderPipelineReflection; + pub struct RenderPipelineReflection; + pub struct RenderPipelineReflectionRef; +} + +impl RenderPipelineReflection { + #[cfg(feature = "private")] + pub unsafe fn new( + vertex_data: *mut std::ffi::c_void, + fragment_data: *mut std::ffi::c_void, + vertex_desc: *mut std::ffi::c_void, + device: &DeviceRef, + options: u64, + flags: u64, + ) -> Self { + let class = class!(MTLRenderPipelineReflection); + let this: RenderPipelineReflection = msg_send![class, alloc]; + let this_alias: *mut Object = msg_send![this.as_ref(), initWithVertexData:vertex_data + fragmentData:fragment_data + serializedVertexDescriptor:vertex_desc + device:device + options:options + flags:flags]; + if this_alias.is_null() { + panic!("[MTLRenderPipelineReflection init] failed"); + } + this + } +} + +impl RenderPipelineReflectionRef { + /// An array of objects that describe the arguments of a fragment function. + pub fn fragment_arguments(&self) -> &ArgumentArrayRef { + unsafe { msg_send![self, fragmentArguments] } + } + + /// An array of objects that describe the arguments of a vertex function. + pub fn vertex_arguments(&self) -> &ArgumentArrayRef { + unsafe { msg_send![self, vertexArguments] } + } + + /// An array of objects that describe the arguments of a tile shading function. + pub fn tile_arguments(&self) -> &ArgumentArrayRef { + unsafe { msg_send![self, tileArguments] } + } +} + +pub enum MTLArgumentArray {} + +foreign_obj_type! { + type CType = MTLArgumentArray; + pub struct ArgumentArray; + pub struct ArgumentArrayRef; +} + +impl ArgumentArrayRef { + pub fn object_at(&self, index: NSUInteger) -> Option<&ArgumentRef> { + unsafe { msg_send![self, objectAtIndexedSubscript: index] } + } + + pub fn count(&self) -> NSUInteger { + unsafe { msg_send![self, count] } + } +} + +pub enum MTLComputePipelineReflection {} + +foreign_obj_type! { + type CType = MTLComputePipelineReflection; + pub struct ComputePipelineReflection; + pub struct ComputePipelineReflectionRef; +} + +impl ComputePipelineReflectionRef { + /// An array of objects that describe the arguments of a compute function. + pub fn arguments(&self) -> &ArgumentArrayRef { + unsafe { msg_send![self, arguments] } + } +} + +pub enum MTLRenderPipelineDescriptor {} + +foreign_obj_type! { + type CType = MTLRenderPipelineDescriptor; + pub struct RenderPipelineDescriptor; + pub struct RenderPipelineDescriptorRef; +} + +impl RenderPipelineDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLRenderPipelineDescriptor); + msg_send![class, new] + } + } +} + +impl RenderPipelineDescriptorRef { + 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 vertex_function(&self) -> Option<&FunctionRef> { + unsafe { msg_send![self, vertexFunction] } + } + + pub fn set_vertex_function(&self, function: Option<&FunctionRef>) { + unsafe { msg_send![self, setVertexFunction: function] } + } + + pub fn fragment_function(&self) -> Option<&FunctionRef> { + unsafe { msg_send![self, fragmentFunction] } + } + + pub fn set_fragment_function(&self, function: Option<&FunctionRef>) { + unsafe { msg_send![self, setFragmentFunction: function] } + } + + pub fn vertex_descriptor(&self) -> Option<&VertexDescriptorRef> { + unsafe { msg_send![self, vertexDescriptor] } + } + + pub fn set_vertex_descriptor(&self, descriptor: Option<&VertexDescriptorRef>) { + unsafe { msg_send![self, setVertexDescriptor: descriptor] } + } + + /// DEPRECATED - aliases rasterSampleCount property + pub fn sample_count(&self) -> NSUInteger { + unsafe { msg_send![self, sampleCount] } + } + + /// DEPRECATED - aliases rasterSampleCount property + pub fn set_sample_count(&self, count: NSUInteger) { + unsafe { msg_send![self, setSampleCount: count] } + } + + pub fn raster_sample_count(&self) -> NSUInteger { + unsafe { msg_send![self, rasterSampleCount] } + } + + pub fn set_raster_sample_count(&self, count: NSUInteger) { + unsafe { msg_send![self, setRasterSampleCount: count] } + } + + pub fn max_vertex_amplification_count(&self) -> NSUInteger { + unsafe { msg_send![self, maxVertexAmplificationCount] } + } + + pub fn set_max_vertex_amplification_count(&self, count: NSUInteger) { + unsafe { msg_send![self, setMaxVertexAmplificationCount: count] } + } + + pub fn is_alpha_to_coverage_enabled(&self) -> bool { + unsafe { + match msg_send![self, isAlphaToCoverageEnabled] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_alpha_to_coverage_enabled(&self, enabled: bool) { + unsafe { msg_send![self, setAlphaToCoverageEnabled: enabled] } + } + + pub fn is_alpha_to_one_enabled(&self) -> bool { + unsafe { + match msg_send![self, isAlphaToOneEnabled] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_alpha_to_one_enabled(&self, enabled: bool) { + unsafe { msg_send![self, setAlphaToOneEnabled: enabled] } + } + + pub fn is_rasterization_enabled(&self) -> bool { + unsafe { + match msg_send![self, isRasterizationEnabled] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_rasterization_enabled(&self, enabled: bool) { + unsafe { msg_send![self, setRasterizationEnabled: enabled] } + } + + pub fn color_attachments(&self) -> &RenderPipelineColorAttachmentDescriptorArrayRef { + unsafe { msg_send![self, colorAttachments] } + } + + pub fn depth_attachment_pixel_format(&self) -> MTLPixelFormat { + unsafe { msg_send![self, depthAttachmentPixelFormat] } + } + + pub fn set_depth_attachment_pixel_format(&self, pixel_format: MTLPixelFormat) { + unsafe { msg_send![self, setDepthAttachmentPixelFormat: pixel_format] } + } + + pub fn stencil_attachment_pixel_format(&self) -> MTLPixelFormat { + unsafe { msg_send![self, stencilAttachmentPixelFormat] } + } + + pub fn set_stencil_attachment_pixel_format(&self, pixel_format: MTLPixelFormat) { + unsafe { msg_send![self, setStencilAttachmentPixelFormat: pixel_format] } + } + + pub fn input_primitive_topology(&self) -> MTLPrimitiveTopologyClass { + unsafe { msg_send![self, inputPrimitiveTopology] } + } + + pub fn set_input_primitive_topology(&self, topology: MTLPrimitiveTopologyClass) { + unsafe { msg_send![self, setInputPrimitiveTopology: topology] } + } + + #[cfg(feature = "private")] + pub unsafe fn serialize_vertex_data(&self) -> *mut std::ffi::c_void { + use std::ptr; + let flags = 0; + let err: *mut Object = ptr::null_mut(); + msg_send![self, newSerializedVertexDataWithFlags:flags + error:err] + } + + #[cfg(feature = "private")] + pub unsafe fn serialize_fragment_data(&self) -> *mut std::ffi::c_void { + msg_send![self, serializeFragmentData] + } + + pub fn support_indirect_command_buffers(&self) -> bool { + unsafe { + match msg_send![self, supportIndirectCommandBuffers] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn set_support_indirect_command_buffers(&self, support: bool) { + unsafe { msg_send![self, setSupportIndirectCommandBuffers: support] } + } + + pub fn vertex_buffers(&self) -> Option<&PipelineBufferDescriptorArrayRef> { + unsafe { msg_send![self, vertexBuffers] } + } + + pub fn fragment_buffers(&self) -> Option<&PipelineBufferDescriptorArrayRef> { + unsafe { msg_send![self, fragmentBuffers] } + } + + // TODO: tesselation stuff + + /// API_AVAILABLE(macos(11.0), ios(14.0)); + /// Marshal to Rust Vec + pub fn binary_archives(&self) -> Vec { + unsafe { + let archives: *mut Object = msg_send![self, binaryArchives]; + let count: NSUInteger = msg_send![archives, count]; + let ret = (0..count) + .map(|i| { + let a = msg_send![archives, objectAtIndex: i]; + BinaryArchive::from_ptr(a) + }) + .collect(); + ret + } + } + + /// API_AVAILABLE(macos(11.0), ios(14.0)); + /// Marshal from Rust slice + pub fn set_binary_archives(&self, archives: &[&BinaryArchiveRef]) { + let ns_array = Array::::from_slice(archives); + unsafe { msg_send![self, setBinaryArchives: ns_array] } + } + + pub fn reset(&self) { + unsafe { msg_send![self, reset] } + } +} + +pub enum MTLRenderPipelineState {} + +foreign_obj_type! { + type CType = MTLRenderPipelineState; + pub struct RenderPipelineState; + pub struct RenderPipelineStateRef; +} + +impl RenderPipelineStateRef { + 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 enum MTLRenderPipelineColorAttachmentDescriptorArray {} + +foreign_obj_type! { + type CType = MTLRenderPipelineColorAttachmentDescriptorArray; + pub struct RenderPipelineColorAttachmentDescriptorArray; + pub struct RenderPipelineColorAttachmentDescriptorArrayRef; +} + +impl RenderPipelineColorAttachmentDescriptorArrayRef { + pub fn object_at( + &self, + index: NSUInteger, + ) -> Option<&RenderPipelineColorAttachmentDescriptorRef> { + unsafe { msg_send![self, objectAtIndexedSubscript: index] } + } + + pub fn set_object_at( + &self, + index: NSUInteger, + attachment: Option<&RenderPipelineColorAttachmentDescriptorRef>, + ) { + unsafe { + msg_send![self, setObject:attachment + atIndexedSubscript:index] + } + } +} diff --git a/third_party/rust/metal/src/renderpass.rs b/third_party/rust/metal/src/renderpass.rs new file mode 100644 index 0000000000..ed4f60a43d --- /dev/null +++ b/third_party/rust/metal/src/renderpass.rs @@ -0,0 +1,330 @@ +// 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::*; + +#[repr(u64)] +#[derive(Copy, Clone, Debug)] +pub enum MTLLoadAction { + DontCare = 0, + Load = 1, + Clear = 2, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug)] +pub enum MTLStoreAction { + DontCare = 0, + Store = 1, + MultisampleResolve = 2, + StoreAndMultisampleResolve = 3, + Unknown = 4, + CustomSampleDepthStore = 5, +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct MTLClearColor { + pub red: f64, + pub green: f64, + pub blue: f64, + pub alpha: f64, +} + +impl MTLClearColor { + #[inline] + pub fn new(red: f64, green: f64, blue: f64, alpha: f64) -> Self { + Self { + red, + green, + blue, + alpha, + } + } +} + +#[repr(u32)] +#[allow(non_camel_case_types)] +pub enum MTLMultisampleStencilResolveFilter { + Sample0 = 0, + DepthResolvedSample = 1, +} + +pub enum MTLRenderPassAttachmentDescriptor {} + +foreign_obj_type! { + type CType = MTLRenderPassAttachmentDescriptor; + pub struct RenderPassAttachmentDescriptor; + pub struct RenderPassAttachmentDescriptorRef; +} + +impl RenderPassAttachmentDescriptorRef { + pub fn texture(&self) -> Option<&TextureRef> { + unsafe { msg_send![self, texture] } + } + + pub fn set_texture(&self, texture: Option<&TextureRef>) { + unsafe { msg_send![self, setTexture: texture] } + } + + pub fn level(&self) -> NSUInteger { + unsafe { msg_send![self, level] } + } + + pub fn set_level(&self, level: NSUInteger) { + unsafe { msg_send![self, setLevel: level] } + } + + pub fn slice(&self) -> NSUInteger { + unsafe { msg_send![self, slice] } + } + + pub fn set_slice(&self, slice: NSUInteger) { + unsafe { msg_send![self, setSlice: slice] } + } + + pub fn depth_plane(&self) -> NSUInteger { + unsafe { msg_send![self, depthPlane] } + } + + pub fn set_depth_plane(&self, depth_plane: NSUInteger) { + unsafe { msg_send![self, setDepthPlane: depth_plane] } + } + + pub fn resolve_texture(&self) -> Option<&TextureRef> { + unsafe { msg_send![self, resolveTexture] } + } + + pub fn set_resolve_texture(&self, resolve_texture: Option<&TextureRef>) { + unsafe { msg_send![self, setResolveTexture: resolve_texture] } + } + + pub fn resolve_level(&self) -> NSUInteger { + unsafe { msg_send![self, resolveLevel] } + } + + pub fn set_resolve_level(&self, resolve_level: NSUInteger) { + unsafe { msg_send![self, setResolveLevel: resolve_level] } + } + + pub fn resolve_slice(&self) -> NSUInteger { + unsafe { msg_send![self, resolveSlice] } + } + + pub fn set_resolve_slice(&self, resolve_slice: NSUInteger) { + unsafe { msg_send![self, setResolveSlice: resolve_slice] } + } + + pub fn resolve_depth_plane(&self) -> NSUInteger { + unsafe { msg_send![self, resolveDepthPlane] } + } + + pub fn set_resolve_depth_plane(&self, resolve_depth_plane: NSUInteger) { + unsafe { msg_send![self, setResolveDepthPlane: resolve_depth_plane] } + } + + pub fn load_action(&self) -> MTLLoadAction { + unsafe { msg_send![self, loadAction] } + } + + pub fn set_load_action(&self, load_action: MTLLoadAction) { + unsafe { msg_send![self, setLoadAction: load_action] } + } + + pub fn store_action(&self) -> MTLStoreAction { + unsafe { msg_send![self, storeAction] } + } + + pub fn set_store_action(&self, store_action: MTLStoreAction) { + unsafe { msg_send![self, setStoreAction: store_action] } + } +} + +pub enum MTLRenderPassColorAttachmentDescriptor {} + +foreign_obj_type! { + type CType = MTLRenderPassColorAttachmentDescriptor; + pub struct RenderPassColorAttachmentDescriptor; + pub struct RenderPassColorAttachmentDescriptorRef; + type ParentType = RenderPassAttachmentDescriptorRef; +} + +impl RenderPassColorAttachmentDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLRenderPassColorAttachmentDescriptor); + msg_send![class, new] + } + } +} + +impl RenderPassColorAttachmentDescriptorRef { + pub fn clear_color(&self) -> MTLClearColor { + unsafe { msg_send![self, clearColor] } + } + + pub fn set_clear_color(&self, clear_color: MTLClearColor) { + unsafe { msg_send![self, setClearColor: clear_color] } + } +} + +pub enum MTLRenderPassDepthAttachmentDescriptor {} + +foreign_obj_type! { + type CType = MTLRenderPassDepthAttachmentDescriptor; + pub struct RenderPassDepthAttachmentDescriptor; + pub struct RenderPassDepthAttachmentDescriptorRef; + type ParentType = RenderPassAttachmentDescriptorRef; +} + +impl RenderPassDepthAttachmentDescriptorRef { + pub fn clear_depth(&self) -> f64 { + unsafe { msg_send![self, clearDepth] } + } + + pub fn set_clear_depth(&self, clear_depth: f64) { + unsafe { msg_send![self, setClearDepth: clear_depth] } + } +} + +pub enum MTLRenderPassStencilAttachmentDescriptor {} + +foreign_obj_type! { + type CType = MTLRenderPassStencilAttachmentDescriptor; + pub struct RenderPassStencilAttachmentDescriptor; + pub struct RenderPassStencilAttachmentDescriptorRef; + type ParentType = RenderPassAttachmentDescriptorRef; +} + +impl RenderPassStencilAttachmentDescriptorRef { + pub fn clear_stencil(&self) -> u32 { + unsafe { msg_send![self, clearStencil] } + } + + pub fn set_clear_stencil(&self, clear_stencil: u32) { + unsafe { msg_send![self, setClearStencil: clear_stencil] } + } + + pub fn stencil_resolve_filter(&self) -> MTLMultisampleStencilResolveFilter { + unsafe { msg_send![self, stencilResolveFilter] } + } + + pub fn set_stencil_resolve_filter( + &self, + stencil_resolve_filter: MTLMultisampleStencilResolveFilter, + ) { + unsafe { msg_send![self, setStencilResolveFilter: stencil_resolve_filter] } + } +} + +pub enum MTLRenderPassColorAttachmentDescriptorArray {} + +foreign_obj_type! { + type CType = MTLRenderPassColorAttachmentDescriptorArray; + pub struct RenderPassColorAttachmentDescriptorArray; + pub struct RenderPassColorAttachmentDescriptorArrayRef; +} + +impl RenderPassColorAttachmentDescriptorArrayRef { + pub fn object_at(&self, index: NSUInteger) -> Option<&RenderPassColorAttachmentDescriptorRef> { + unsafe { msg_send![self, objectAtIndexedSubscript: index] } + } + + pub fn set_object_at( + &self, + index: NSUInteger, + attachment: Option<&RenderPassColorAttachmentDescriptorRef>, + ) { + unsafe { + msg_send![self, setObject:attachment + atIndexedSubscript:index] + } + } +} + +pub enum MTLRenderPassDescriptor {} + +foreign_obj_type! { + type CType = MTLRenderPassDescriptor; + pub struct RenderPassDescriptor; + pub struct RenderPassDescriptorRef; +} + +impl RenderPassDescriptor { + /// Creates a default render pass descriptor with no attachments. + pub fn new<'a>() -> &'a RenderPassDescriptorRef { + unsafe { msg_send![class!(MTLRenderPassDescriptor), renderPassDescriptor] } + } +} + +impl RenderPassDescriptorRef { + pub fn color_attachments(&self) -> &RenderPassColorAttachmentDescriptorArrayRef { + unsafe { msg_send![self, colorAttachments] } + } + + pub fn depth_attachment(&self) -> Option<&RenderPassDepthAttachmentDescriptorRef> { + unsafe { msg_send![self, depthAttachment] } + } + + pub fn set_depth_attachment( + &self, + depth_attachment: Option<&RenderPassDepthAttachmentDescriptorRef>, + ) { + unsafe { msg_send![self, setDepthAttachment: depth_attachment] } + } + + pub fn stencil_attachment(&self) -> Option<&RenderPassStencilAttachmentDescriptorRef> { + unsafe { msg_send![self, stencilAttachment] } + } + + pub fn set_stencil_attachment( + &self, + stencil_attachment: Option<&RenderPassStencilAttachmentDescriptorRef>, + ) { + unsafe { msg_send![self, setStencilAttachment: stencil_attachment] } + } + + pub fn visibility_result_buffer(&self) -> Option<&BufferRef> { + unsafe { msg_send![self, visibilityResultBuffer] } + } + + pub fn set_visibility_result_buffer(&self, buffer: Option<&BufferRef>) { + unsafe { msg_send![self, setVisibilityResultBuffer: buffer] } + } + + pub fn render_target_array_length(&self) -> NSUInteger { + unsafe { msg_send![self, renderTargetArrayLength] } + } + + pub fn set_render_target_array_length(&self, length: NSUInteger) { + unsafe { msg_send![self, setRenderTargetArrayLength: length] } + } + + pub fn render_target_width(&self) -> NSUInteger { + unsafe { msg_send![self, renderTargetWidth] } + } + + pub fn set_render_target_width(&self, size: NSUInteger) { + unsafe { msg_send![self, setRenderTargetWidth: size] } + } + + pub fn render_target_height(&self) -> NSUInteger { + unsafe { msg_send![self, renderTargetHeight] } + } + + pub fn set_render_target_height(&self, size: NSUInteger) { + unsafe { msg_send![self, setRenderTargetHeight: size] } + } + + pub fn default_raster_sample_count(&self) -> NSUInteger { + unsafe { msg_send![self, defaultRasterSampleCount] } + } + + pub fn set_default_raster_sample_count(&self, count: NSUInteger) { + unsafe { msg_send![self, setDefaultRasterSampleCount: count] } + } +} diff --git a/third_party/rust/metal/src/resource.rs b/third_party/rust/metal/src/resource.rs new file mode 100644 index 0000000000..8986a9c838 --- /dev/null +++ b/third_party/rust/metal/src/resource.rs @@ -0,0 +1,176 @@ +// 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::{DeviceRef, HeapRef, NSUInteger}; +use objc::runtime::{NO, YES}; + +#[repr(u64)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLPurgeableState { + KeepCurrent = 1, + NonVolatile = 2, + Volatile = 3, + Empty = 4, +} + +#[repr(u64)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLCPUCacheMode { + DefaultCache = 0, + WriteCombined = 1, +} + +#[repr(u64)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLStorageMode { + Shared = 0, + Managed = 1, + Private = 2, + /// Only available on macos(11.0), macCatalyst(14.0), ios(10.0) + Memoryless = 3, +} + +/// Only available on macos(10.15), ios(13.0) +#[repr(u64)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum MTLHazardTrackingMode { + Default = 0, + Untracked = 1, + Tracked = 2, +} + +pub const MTLResourceCPUCacheModeShift: NSUInteger = 0; +pub const MTLResourceCPUCacheModeMask: NSUInteger = 0xf << MTLResourceCPUCacheModeShift; +pub const MTLResourceStorageModeShift: NSUInteger = 4; +pub const MTLResourceStorageModeMask: NSUInteger = 0xf << MTLResourceStorageModeShift; +pub const MTLResourceHazardTrackingModeShift: NSUInteger = 8; +pub const MTLResourceHazardTrackingModeMask: NSUInteger = 0x3 << MTLResourceHazardTrackingModeShift; + +bitflags! { + #[allow(non_upper_case_globals)] + pub struct MTLResourceOptions: NSUInteger { + const CPUCacheModeDefaultCache = (MTLCPUCacheMode::DefaultCache as NSUInteger) << MTLResourceCPUCacheModeShift; + const CPUCacheModeWriteCombined = (MTLCPUCacheMode::WriteCombined as NSUInteger) << MTLResourceCPUCacheModeShift; + + const StorageModeShared = (MTLStorageMode::Shared as NSUInteger) << MTLResourceStorageModeShift; + const StorageModeManaged = (MTLStorageMode::Managed as NSUInteger) << MTLResourceStorageModeShift; + const StorageModePrivate = (MTLStorageMode::Private as NSUInteger) << MTLResourceStorageModeShift; + const StorageModeMemoryless = (MTLStorageMode::Memoryless as NSUInteger) << MTLResourceStorageModeShift; + + /// Only available on macos(10.13), ios(10.0) + const HazardTrackingModeDefault = (MTLHazardTrackingMode::Default as NSUInteger) << MTLResourceHazardTrackingModeShift; + /// Only available on macos(10.13), ios(10.0) + const HazardTrackingModeUntracked = (MTLHazardTrackingMode::Untracked as NSUInteger) << MTLResourceHazardTrackingModeShift; + /// Only available on macos(10.15), ios(13.0) + const HazardTrackingModeTracked = (MTLHazardTrackingMode::Tracked as NSUInteger) << MTLResourceHazardTrackingModeShift; + } +} + +bitflags! { + /// Options that describe how a graphics or compute function uses an argument buffer’s resource. + /// + /// Enabling certain options for certain resources determines whether the Metal driver should + /// convert the resource to another format (for example, whether to decompress a color render target). + pub struct MTLResourceUsage: NSUInteger { + /// An option that enables reading from the resource. + const Read = 1 << 0; + /// An option that enables writing to the resource. + const Write = 1 << 1; + /// An option that enables sampling from the resource. + /// + /// Specify this option only if the resource is a texture. + const Sample = 1 << 2; + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[repr(C)] +pub struct MTLSizeAndAlign { + pub size: NSUInteger, + pub align: NSUInteger, +} + +pub enum MTLResource {} + +foreign_obj_type! { + type CType = MTLResource; + pub struct Resource; + pub struct ResourceRef; +} + +impl ResourceRef { + 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 cpu_cache_mode(&self) -> MTLCPUCacheMode { + unsafe { msg_send![self, cpuCacheMode] } + } + + pub fn storage_mode(&self) -> MTLStorageMode { + unsafe { msg_send![self, storageMode] } + } + + pub fn set_purgeable_state(&self, state: MTLPurgeableState) -> MTLPurgeableState { + unsafe { msg_send![self, setPurgeableState: state] } + } + + /// Only available on macOS 10.13+ & iOS 10.11+ + pub fn allocated_size(&self) -> NSUInteger { + unsafe { msg_send![self, allocatedSize] } + } + + /// Only available on macos(10.15), ios(13.0) + pub fn hazard_tracking_mode(&self) -> MTLHazardTrackingMode { + unsafe { msg_send![self, hazardTrackingMode] } + } + + /// Only available on macos(10.15), ios(13.0) + pub fn resource_options(&self) -> MTLResourceOptions { + unsafe { msg_send![self, resourceOptions] } + } + + /// Only available on macos(10.13), ios(10.0) + pub fn heap(&self) -> &HeapRef { + unsafe { msg_send![self, heap] } + } + + /// Only available on macos(10.15), ios(13.0) + pub fn heap_offset(&self) -> NSUInteger { + unsafe { msg_send![self, heapOffset] } + } + + /// Only available on macos(10.13), ios(10.0) + pub fn make_aliasable(&self) { + unsafe { msg_send![self, makeAliasable] } + } + + /// Only available on macos(10.13), ios(10.0) + pub fn is_aliasable(&self) -> bool { + unsafe { + match msg_send![self, isAliasable] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } +} diff --git a/third_party/rust/metal/src/sampler.rs b/third_party/rust/metal/src/sampler.rs new file mode 100644 index 0000000000..3dd871a3b4 --- /dev/null +++ b/third_party/rust/metal/src/sampler.rs @@ -0,0 +1,157 @@ +// 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::{depthstencil::MTLCompareFunction, DeviceRef, NSUInteger}; + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLSamplerMinMagFilter { + Nearest = 0, + Linear = 1, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLSamplerMipFilter { + NotMipmapped = 0, + Nearest = 1, + Linear = 2, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLSamplerAddressMode { + ClampToEdge = 0, + MirrorClampToEdge = 1, + Repeat = 2, + MirrorRepeat = 3, + ClampToZero = 4, + ClampToBorderColor = 5, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLSamplerBorderColor { + TransparentBlack = 0, + OpaqueBlack = 1, + OpaqueWhite = 2, +} + +pub enum MTLSamplerDescriptor {} + +foreign_obj_type! { + type CType = MTLSamplerDescriptor; + pub struct SamplerDescriptor; + pub struct SamplerDescriptorRef; +} + +impl SamplerDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLSamplerDescriptor); + msg_send![class, new] + } + } +} + +impl SamplerDescriptorRef { + pub fn set_min_filter(&self, filter: MTLSamplerMinMagFilter) { + unsafe { msg_send![self, setMinFilter: filter] } + } + + pub fn set_mag_filter(&self, filter: MTLSamplerMinMagFilter) { + unsafe { msg_send![self, setMagFilter: filter] } + } + + pub fn set_mip_filter(&self, filter: MTLSamplerMipFilter) { + unsafe { msg_send![self, setMipFilter: filter] } + } + + pub fn set_address_mode_s(&self, mode: MTLSamplerAddressMode) { + unsafe { msg_send![self, setSAddressMode: mode] } + } + + pub fn set_address_mode_t(&self, mode: MTLSamplerAddressMode) { + unsafe { msg_send![self, setTAddressMode: mode] } + } + + pub fn set_address_mode_r(&self, mode: MTLSamplerAddressMode) { + unsafe { msg_send![self, setRAddressMode: mode] } + } + + pub fn set_max_anisotropy(&self, anisotropy: NSUInteger) { + unsafe { msg_send![self, setMaxAnisotropy: anisotropy] } + } + + pub fn set_compare_function(&self, func: MTLCompareFunction) { + unsafe { msg_send![self, setCompareFunction: func] } + } + + #[cfg(feature = "private")] + pub unsafe fn set_lod_bias(&self, bias: f32) { + msg_send![self, setLodBias: bias] + } + + pub fn set_lod_min_clamp(&self, clamp: f32) { + unsafe { msg_send![self, setLodMinClamp: clamp] } + } + + pub fn set_lod_max_clamp(&self, clamp: f32) { + unsafe { msg_send![self, setLodMaxClamp: clamp] } + } + + pub fn set_lod_average(&self, enable: bool) { + unsafe { msg_send![self, setLodAverage: enable] } + } + + pub fn set_normalized_coordinates(&self, enable: bool) { + unsafe { msg_send![self, setNormalizedCoordinates: enable] } + } + + pub fn set_support_argument_buffers(&self, enable: bool) { + unsafe { msg_send![self, setSupportArgumentBuffers: enable] } + } + + pub fn set_border_color(&self, color: MTLSamplerBorderColor) { + unsafe { msg_send![self, setBorderColor: color] } + } + + 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 enum MTLSamplerState {} + +foreign_obj_type! { + type CType = MTLSamplerState; + pub struct SamplerState; + pub struct SamplerStateRef; +} + +impl SamplerStateRef { + 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) + } + } +} 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, 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; + +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 + 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 +} diff --git a/third_party/rust/metal/src/texture.rs b/third_party/rust/metal/src/texture.rs new file mode 100644 index 0000000000..5e9f1b3d52 --- /dev/null +++ b/third_party/rust/metal/src/texture.rs @@ -0,0 +1,348 @@ +// 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 objc::runtime::{NO, YES}; + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum MTLTextureType { + D1 = 0, + D1Array = 1, + D2 = 2, + D2Array = 3, + D2Multisample = 4, + Cube = 5, + CubeArray = 6, + D3 = 7, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum MTLTextureCompressionType { + Lossless = 0, + Lossy = 1, +} + +bitflags! { + pub struct MTLTextureUsage: NSUInteger { + const Unknown = 0x0000; + const ShaderRead = 0x0001; + const ShaderWrite = 0x0002; + const RenderTarget = 0x0004; + const PixelFormatView = 0x0010; + } +} + +pub enum MTLTextureDescriptor {} + +foreign_obj_type! { + type CType = MTLTextureDescriptor; + pub struct TextureDescriptor; + pub struct TextureDescriptorRef; +} + +impl TextureDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLTextureDescriptor); + msg_send![class, new] + } + } +} + +impl TextureDescriptorRef { + pub fn texture_type(&self) -> MTLTextureType { + unsafe { msg_send![self, textureType] } + } + + pub fn set_texture_type(&self, texture_type: MTLTextureType) { + unsafe { msg_send![self, setTextureType: texture_type] } + } + + 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 width(&self) -> NSUInteger { + unsafe { msg_send![self, width] } + } + + pub fn set_width(&self, width: NSUInteger) { + unsafe { msg_send![self, setWidth: width] } + } + + pub fn height(&self) -> NSUInteger { + unsafe { msg_send![self, height] } + } + + pub fn set_height(&self, height: NSUInteger) { + unsafe { msg_send![self, setHeight: height] } + } + + pub fn depth(&self) -> NSUInteger { + unsafe { msg_send![self, depth] } + } + + pub fn set_depth(&self, depth: NSUInteger) { + unsafe { msg_send![self, setDepth: depth] } + } + + pub fn mipmap_level_count(&self) -> NSUInteger { + unsafe { msg_send![self, mipmapLevelCount] } + } + + pub fn set_mipmap_level_count(&self, count: NSUInteger) { + unsafe { msg_send![self, setMipmapLevelCount: count] } + } + + pub fn set_mipmap_level_count_for_size(&self, size: MTLSize) { + let MTLSize { + width, + height, + depth, + } = size; + let count = (width.max(height).max(depth) as f64).log2().ceil() as u64; + self.set_mipmap_level_count(count); + } + + pub fn sample_count(&self) -> NSUInteger { + unsafe { msg_send![self, sampleCount] } + } + + pub fn set_sample_count(&self, count: NSUInteger) { + unsafe { msg_send![self, setSampleCount: count] } + } + + pub fn array_length(&self) -> NSUInteger { + unsafe { msg_send![self, arrayLength] } + } + + pub fn set_array_length(&self, length: NSUInteger) { + unsafe { msg_send![self, setArrayLength: length] } + } + + pub fn resource_options(&self) -> MTLResourceOptions { + unsafe { msg_send![self, resourceOptions] } + } + + pub fn set_resource_options(&self, options: MTLResourceOptions) { + unsafe { msg_send![self, setResourceOptions: options] } + } + + pub fn cpu_cache_mode(&self) -> MTLCPUCacheMode { + unsafe { msg_send![self, cpuCacheMode] } + } + + pub fn set_cpu_cache_mode(&self, mode: MTLCPUCacheMode) { + unsafe { msg_send![self, setCpuCacheMode: mode] } + } + + pub fn storage_mode(&self) -> MTLStorageMode { + unsafe { msg_send![self, storageMode] } + } + + pub fn set_storage_mode(&self, mode: MTLStorageMode) { + unsafe { msg_send![self, setStorageMode: mode] } + } + + pub fn usage(&self) -> MTLTextureUsage { + unsafe { msg_send![self, usage] } + } + + pub fn set_usage(&self, usage: MTLTextureUsage) { + unsafe { msg_send![self, setUsage: usage] } + } + + pub fn compression_type(&self) -> MTLTextureCompressionType { + unsafe { msg_send![self, compressionType] } + } + + pub fn set_compression_type(&self, compression_type: MTLTextureCompressionType) { + unsafe { msg_send![self, setCompressionType: compression_type] } + } +} + +pub enum MTLTexture {} + +foreign_obj_type! { + type CType = MTLTexture; + pub struct Texture; + pub struct TextureRef; + type ParentType = ResourceRef; +} + +impl TextureRef { + #[deprecated(since = "0.13.0")] + pub fn root_resource(&self) -> Option<&ResourceRef> { + unsafe { msg_send![self, rootResource] } + } + + pub fn parent_texture(&self) -> Option<&TextureRef> { + unsafe { msg_send![self, parentTexture] } + } + + pub fn parent_relative_level(&self) -> NSUInteger { + unsafe { msg_send![self, parentRelativeLevel] } + } + + pub fn parent_relative_slice(&self) -> NSUInteger { + unsafe { msg_send![self, parentRelativeSlice] } + } + + pub fn buffer(&self) -> Option<&BufferRef> { + unsafe { msg_send![self, buffer] } + } + + pub fn buffer_offset(&self) -> NSUInteger { + unsafe { msg_send![self, bufferOffset] } + } + + pub fn buffer_stride(&self) -> NSUInteger { + unsafe { msg_send![self, bufferBytesPerRow] } + } + + pub fn texture_type(&self) -> MTLTextureType { + unsafe { msg_send![self, textureType] } + } + + pub fn pixel_format(&self) -> MTLPixelFormat { + unsafe { msg_send![self, pixelFormat] } + } + + pub fn width(&self) -> NSUInteger { + unsafe { msg_send![self, width] } + } + + pub fn height(&self) -> NSUInteger { + unsafe { msg_send![self, height] } + } + + pub fn depth(&self) -> NSUInteger { + unsafe { msg_send![self, depth] } + } + + pub fn mipmap_level_count(&self) -> NSUInteger { + unsafe { msg_send![self, mipmapLevelCount] } + } + + pub fn sample_count(&self) -> NSUInteger { + unsafe { msg_send![self, sampleCount] } + } + + pub fn array_length(&self) -> NSUInteger { + unsafe { msg_send![self, arrayLength] } + } + + pub fn usage(&self) -> MTLTextureUsage { + unsafe { msg_send![self, usage] } + } + + /// [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, isFramebufferOnly] { + YES => true, + NO => false, + _ => unreachable!(), + } + } + } + + pub fn get_bytes( + &self, + bytes: *mut std::ffi::c_void, + stride: NSUInteger, + region: MTLRegion, + mipmap_level: NSUInteger, + ) { + unsafe { + msg_send![self, getBytes:bytes + bytesPerRow:stride + fromRegion:region + mipmapLevel:mipmap_level] + } + } + + pub fn get_bytes_in_slice( + &self, + bytes: *mut std::ffi::c_void, + stride: NSUInteger, + image_stride: NSUInteger, + region: MTLRegion, + mipmap_level: NSUInteger, + slice: NSUInteger, + ) { + unsafe { + msg_send![self, getBytes:bytes + bytesPerRow:stride + bytesPerImage:image_stride + fromRegion:region + mipmapLevel:mipmap_level + slice:slice] + } + } + + pub fn replace_region( + &self, + region: MTLRegion, + mipmap_level: NSUInteger, + bytes: *const std::ffi::c_void, + stride: NSUInteger, + ) { + unsafe { + msg_send![self, replaceRegion:region + mipmapLevel:mipmap_level + withBytes:bytes + bytesPerRow:stride] + } + } + + pub fn replace_region_in_slice( + &self, + region: MTLRegion, + mipmap_level: NSUInteger, + slice: NSUInteger, + bytes: *const std::ffi::c_void, + stride: NSUInteger, + image_stride: NSUInteger, + ) { + unsafe { + msg_send![self, replaceRegion:region + mipmapLevel:mipmap_level + slice:slice + withBytes:bytes + bytesPerRow:stride + bytesPerImage:image_stride] + } + } + + pub fn new_texture_view(&self, pixel_format: MTLPixelFormat) -> Texture { + unsafe { msg_send![self, newTextureViewWithPixelFormat: pixel_format] } + } + + pub fn new_texture_view_from_slice( + &self, + pixel_format: MTLPixelFormat, + texture_type: MTLTextureType, + mipmap_levels: crate::NSRange, + slices: crate::NSRange, + ) -> Texture { + unsafe { + msg_send![self, newTextureViewWithPixelFormat:pixel_format + textureType:texture_type + levels:mipmap_levels + slices:slices] + } + } +} diff --git a/third_party/rust/metal/src/types.rs b/third_party/rust/metal/src/types.rs new file mode 100644 index 0000000000..3ea937f061 --- /dev/null +++ b/third_party/rust/metal/src/types.rs @@ -0,0 +1,80 @@ +// 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::NSUInteger; +use std::default::Default; + +#[repr(C)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)] +pub struct MTLOrigin { + pub x: NSUInteger, + pub y: NSUInteger, + pub z: NSUInteger, +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)] +pub struct MTLSize { + pub width: NSUInteger, + pub height: NSUInteger, + pub depth: NSUInteger, +} + +impl MTLSize { + pub fn new(width: NSUInteger, height: NSUInteger, depth: NSUInteger) -> Self { + Self { + width, + height, + depth, + } + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Default)] +pub struct MTLRegion { + pub origin: MTLOrigin, + pub size: MTLSize, +} + +impl MTLRegion { + #[inline] + pub fn new_1d(x: NSUInteger, width: NSUInteger) -> Self { + Self::new_2d(x, 0, width, 1) + } + + #[inline] + pub fn new_2d(x: NSUInteger, y: NSUInteger, width: NSUInteger, height: NSUInteger) -> Self { + Self::new_3d(x, y, 0, width, height, 1) + } + + #[inline] + pub fn new_3d( + x: NSUInteger, + y: NSUInteger, + z: NSUInteger, + width: NSUInteger, + height: NSUInteger, + depth: NSUInteger, + ) -> Self { + Self { + origin: MTLOrigin { x, y, z }, + size: MTLSize { + width, + height, + depth, + }, + } + } +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Default)] +pub struct MTLSamplePosition { + pub x: f32, + pub y: f32, +} diff --git a/third_party/rust/metal/src/vertexdescriptor.rs b/third_party/rust/metal/src/vertexdescriptor.rs new file mode 100644 index 0000000000..201e1e30ad --- /dev/null +++ b/third_party/rust/metal/src/vertexdescriptor.rs @@ -0,0 +1,248 @@ +// 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::NSUInteger; + +#[repr(u64)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLVertexFormat { + Invalid = 0, + UChar2 = 1, + UChar3 = 2, + UChar4 = 3, + Char2 = 4, + Char3 = 5, + Char4 = 6, + UChar2Normalized = 7, + UChar3Normalized = 8, + UChar4Normalized = 9, + Char2Normalized = 10, + Char3Normalized = 11, + Char4Normalized = 12, + UShort2 = 13, + UShort3 = 14, + UShort4 = 15, + Short2 = 16, + Short3 = 17, + Short4 = 18, + UShort2Normalized = 19, + UShort3Normalized = 20, + UShort4Normalized = 21, + Short2Normalized = 22, + Short3Normalized = 23, + Short4Normalized = 24, + Half2 = 25, + Half3 = 26, + Half4 = 27, + Float = 28, + Float2 = 29, + Float3 = 30, + Float4 = 31, + Int = 32, + Int2 = 33, + Int3 = 34, + Int4 = 35, + UInt = 36, + UInt2 = 37, + UInt3 = 38, + UInt4 = 39, + Int1010102Normalized = 40, + UInt1010102Normalized = 41, + UChar4Normalized_BGRA = 42, + UChar = 45, + Char = 46, + UCharNormalized = 47, + CharNormalized = 48, + UShort = 49, + Short = 50, + UShortNormalized = 51, + ShortNormalized = 52, + Half = 53, +} + +#[repr(u64)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub enum MTLVertexStepFunction { + Constant = 0, + PerVertex = 1, + PerInstance = 2, + PerPatch = 3, + PerPatchControlPoint = 4, +} + +pub enum MTLVertexBufferLayoutDescriptor {} + +foreign_obj_type! { + type CType = MTLVertexBufferLayoutDescriptor; + pub struct VertexBufferLayoutDescriptor; + pub struct VertexBufferLayoutDescriptorRef; +} + +impl VertexBufferLayoutDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLVertexBufferLayoutDescriptor); + msg_send![class, new] + } + } +} + +impl VertexBufferLayoutDescriptorRef { + pub fn stride(&self) -> NSUInteger { + unsafe { msg_send![self, stride] } + } + + pub fn set_stride(&self, stride: NSUInteger) { + unsafe { msg_send![self, setStride: stride] } + } + + pub fn step_function(&self) -> MTLVertexStepFunction { + unsafe { msg_send![self, stepFunction] } + } + + pub fn set_step_function(&self, func: MTLVertexStepFunction) { + unsafe { msg_send![self, setStepFunction: func] } + } + + pub fn step_rate(&self) -> NSUInteger { + unsafe { msg_send![self, stepRate] } + } + + pub fn set_step_rate(&self, step_rate: NSUInteger) { + unsafe { msg_send![self, setStepRate: step_rate] } + } +} + +pub enum MTLVertexBufferLayoutDescriptorArray {} + +foreign_obj_type! { + type CType = MTLVertexBufferLayoutDescriptorArray; + pub struct VertexBufferLayoutDescriptorArray; + pub struct VertexBufferLayoutDescriptorArrayRef; +} + +impl VertexBufferLayoutDescriptorArrayRef { + pub fn object_at(&self, index: NSUInteger) -> Option<&VertexBufferLayoutDescriptorRef> { + unsafe { msg_send![self, objectAtIndexedSubscript: index] } + } + + pub fn set_object_at( + &self, + index: NSUInteger, + layout: Option<&VertexBufferLayoutDescriptorRef>, + ) { + unsafe { + msg_send![self, setObject:layout + atIndexedSubscript:index] + } + } +} + +pub enum MTLVertexAttributeDescriptor {} + +foreign_obj_type! { + type CType = MTLVertexAttributeDescriptor; + pub struct VertexAttributeDescriptor; + pub struct VertexAttributeDescriptorRef; +} + +impl VertexAttributeDescriptor { + pub fn new() -> Self { + unsafe { + let class = class!(MTLVertexAttributeDescriptor); + msg_send![class, new] + } + } +} + +impl VertexAttributeDescriptorRef { + pub fn format(&self) -> MTLVertexFormat { + unsafe { msg_send![self, format] } + } + + pub fn set_format(&self, format: MTLVertexFormat) { + unsafe { msg_send![self, setFormat: format] } + } + + pub fn offset(&self) -> NSUInteger { + unsafe { msg_send![self, offset] } + } + + pub fn set_offset(&self, offset: NSUInteger) { + unsafe { msg_send![self, setOffset: offset] } + } + + pub fn buffer_index(&self) -> NSUInteger { + unsafe { msg_send![self, bufferIndex] } + } + + pub fn set_buffer_index(&self, index: NSUInteger) { + unsafe { msg_send![self, setBufferIndex: index] } + } +} + +pub enum MTLVertexAttributeDescriptorArray {} + +foreign_obj_type! { + type CType = MTLVertexAttributeDescriptorArray; + pub struct VertexAttributeDescriptorArray; + pub struct VertexAttributeDescriptorArrayRef; +} + +impl VertexAttributeDescriptorArrayRef { + pub fn object_at(&self, index: NSUInteger) -> Option<&VertexAttributeDescriptorRef> { + unsafe { msg_send![self, objectAtIndexedSubscript: index] } + } + + pub fn set_object_at( + &self, + index: NSUInteger, + attribute: Option<&VertexAttributeDescriptorRef>, + ) { + unsafe { + msg_send![self, setObject:attribute + atIndexedSubscript:index] + } + } +} + +pub enum MTLVertexDescriptor {} + +foreign_obj_type! { + type CType = MTLVertexDescriptor; + pub struct VertexDescriptor; + pub struct VertexDescriptorRef; +} + +impl VertexDescriptor { + pub fn new<'a>() -> &'a VertexDescriptorRef { + unsafe { + let class = class!(MTLVertexDescriptor); + msg_send![class, vertexDescriptor] + } + } +} + +impl VertexDescriptorRef { + pub fn layouts(&self) -> &VertexBufferLayoutDescriptorArrayRef { + unsafe { msg_send![self, layouts] } + } + + pub fn attributes(&self) -> &VertexAttributeDescriptorArrayRef { + unsafe { msg_send![self, attributes] } + } + + #[cfg(feature = "private")] + pub unsafe fn serialize_descriptor(&self) -> *mut std::ffi::c_void { + msg_send![self, newSerializedDescriptor] + } + + pub fn reset(&self) { + unsafe { msg_send![self, reset] } + } +} -- cgit v1.2.3