diff options
Diffstat (limited to 'third_party/rust/metal/src/mps.rs')
-rw-r--r-- | third_party/rust/metal/src/mps.rs | 550 |
1 files changed, 550 insertions, 0 deletions
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, <LICENSE-APACHE or +// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or +// http://opensource.org/licenses/MIT>, at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use super::*; + +use 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<Self> { + 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<Self> { + 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<Self> { + 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<Self> { + 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<PolygonAccelerationStructure> { + 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::<PolygonAccelerationStructure>::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], +} |