Skip to main content

apple_mps/
ray.rs

1use crate::ffi;
2use apple_metal::{CommandBuffer, MetalBuffer, MetalDevice};
3use core::ffi::c_void;
4use core::ptr;
5
6/// `MPSPolygonType` constants.
7pub mod polygon_type {
8    pub const TRIANGLE: usize = 0;
9    pub const QUADRILATERAL: usize = 1;
10}
11
12/// `MPSAccelerationStructureUsage` bitflags.
13pub mod acceleration_structure_usage {
14    pub const NONE: usize = 0;
15    pub const REFIT: usize = 1;
16    pub const FREQUENT_REBUILD: usize = 2;
17    pub const PREFER_GPU_BUILD: usize = 4;
18    pub const PREFER_CPU_BUILD: usize = 8;
19}
20
21/// `MPSAccelerationStructureStatus` constants.
22pub mod acceleration_structure_status {
23    pub const UNBUILT: usize = 0;
24    pub const BUILT: usize = 1;
25}
26
27/// `MPSIntersectionType` constants.
28pub mod intersection_type {
29    pub const NEAREST: usize = 0;
30    pub const ANY: usize = 1;
31}
32
33/// `MPSRayDataType` constants.
34pub mod ray_data_type {
35    pub const ORIGIN_DIRECTION: usize = 0;
36    pub const ORIGIN_MIN_DISTANCE_DIRECTION_MAX_DISTANCE: usize = 1;
37    pub const ORIGIN_MASK_DIRECTION_MAX_DISTANCE: usize = 2;
38    pub const PACKED_ORIGIN_DIRECTION: usize = 3;
39}
40
41/// `MPSIntersectionDataType` constants.
42pub mod intersection_data_type {
43    pub const DISTANCE: usize = 0;
44    pub const DISTANCE_PRIMITIVE_INDEX: usize = 1;
45    pub const DISTANCE_PRIMITIVE_INDEX_COORDINATES: usize = 2;
46    pub const DISTANCE_PRIMITIVE_INDEX_INSTANCE_INDEX: usize = 3;
47    pub const DISTANCE_PRIMITIVE_INDEX_INSTANCE_INDEX_COORDINATES: usize = 4;
48    pub const DISTANCE_PRIMITIVE_INDEX_BUFFER_INDEX: usize = 5;
49    pub const DISTANCE_PRIMITIVE_INDEX_BUFFER_INDEX_COORDINATES: usize = 6;
50    pub const DISTANCE_PRIMITIVE_INDEX_BUFFER_INDEX_INSTANCE_INDEX: usize = 7;
51    pub const DISTANCE_PRIMITIVE_INDEX_BUFFER_INDEX_INSTANCE_INDEX_COORDINATES: usize = 8;
52}
53
54/// `MTLCullMode` constants.
55pub mod cull_mode {
56    pub const NONE: usize = 0;
57    pub const FRONT: usize = 1;
58    pub const BACK: usize = 2;
59}
60
61/// `MTLWinding` constants.
62pub mod winding {
63    pub const CLOCKWISE: usize = 0;
64    pub const COUNTER_CLOCKWISE: usize = 1;
65}
66
67pub use crate::generated::ray::*;
68
69macro_rules! opaque_handle {
70    ($name:ident) => {
71        pub struct $name {
72            ptr: *mut c_void,
73        }
74
75        // SAFETY: MPS handles are opaque pointers to thread-safe Swift/ObjC objects.
76        unsafe impl Send for $name {}
77        // SAFETY: MPS handles are opaque pointers to thread-safe Swift/ObjC objects.
78        unsafe impl Sync for $name {}
79
80        impl Drop for $name {
81            fn drop(&mut self) {
82                if !self.ptr.is_null() {
83                    // SAFETY: `ptr` is a +1 retained MPS object owned by this wrapper.
84                    unsafe { ffi::mps_object_release(self.ptr) };
85                    self.ptr = ptr::null_mut();
86                }
87            }
88        }
89
90        impl $name {
91            #[must_use]
92            pub const fn as_ptr(&self) -> *mut c_void {
93                self.ptr
94            }
95        }
96    };
97}
98
99opaque_handle!(PolygonAccelerationStructure);
100impl PolygonAccelerationStructure {
101    #[must_use]
102    pub fn new(device: &MetalDevice) -> Option<Self> {
103        let ptr = unsafe { ffi::mps_polygon_acceleration_structure_new(device.as_ptr()) };
104        if ptr.is_null() {
105            None
106        } else {
107            Some(Self { ptr })
108        }
109    }
110
111    #[must_use]
112    pub fn polygon_type(&self) -> usize {
113        unsafe { ffi::mps_polygon_acceleration_structure_polygon_type(self.ptr) }
114    }
115
116    pub fn set_polygon_type(&self, polygon_type: usize) {
117        unsafe { ffi::mps_polygon_acceleration_structure_set_polygon_type(self.ptr, polygon_type) };
118    }
119
120    #[must_use]
121    pub fn vertex_stride(&self) -> usize {
122        unsafe { ffi::mps_polygon_acceleration_structure_vertex_stride(self.ptr) }
123    }
124
125    pub fn set_vertex_stride(&self, vertex_stride: usize) {
126        unsafe {
127            ffi::mps_polygon_acceleration_structure_set_vertex_stride(self.ptr, vertex_stride);
128        };
129    }
130
131    #[must_use]
132    pub fn index_type(&self) -> u32 {
133        unsafe { ffi::mps_polygon_acceleration_structure_index_type(self.ptr) }
134    }
135
136    pub fn set_index_type(&self, index_type: u32) {
137        unsafe { ffi::mps_polygon_acceleration_structure_set_index_type(self.ptr, index_type) };
138    }
139
140    pub fn set_vertex_buffer(&self, buffer: Option<&MetalBuffer>) {
141        let buffer_ptr = buffer.map_or(ptr::null_mut(), MetalBuffer::as_ptr);
142        unsafe { ffi::mps_polygon_acceleration_structure_set_vertex_buffer(self.ptr, buffer_ptr) };
143    }
144
145    #[must_use]
146    pub fn vertex_buffer_offset(&self) -> usize {
147        unsafe { ffi::mps_polygon_acceleration_structure_vertex_buffer_offset(self.ptr) }
148    }
149
150    pub fn set_vertex_buffer_offset(&self, offset: usize) {
151        unsafe {
152            ffi::mps_polygon_acceleration_structure_set_vertex_buffer_offset(self.ptr, offset);
153        };
154    }
155
156    pub fn set_index_buffer(&self, buffer: Option<&MetalBuffer>) {
157        let buffer_ptr = buffer.map_or(ptr::null_mut(), MetalBuffer::as_ptr);
158        unsafe { ffi::mps_polygon_acceleration_structure_set_index_buffer(self.ptr, buffer_ptr) };
159    }
160
161    #[must_use]
162    pub fn index_buffer_offset(&self) -> usize {
163        unsafe { ffi::mps_polygon_acceleration_structure_index_buffer_offset(self.ptr) }
164    }
165
166    pub fn set_index_buffer_offset(&self, offset: usize) {
167        unsafe {
168            ffi::mps_polygon_acceleration_structure_set_index_buffer_offset(self.ptr, offset);
169        };
170    }
171
172    #[must_use]
173    pub fn polygon_count(&self) -> usize {
174        unsafe { ffi::mps_polygon_acceleration_structure_polygon_count(self.ptr) }
175    }
176
177    pub fn set_polygon_count(&self, count: usize) {
178        unsafe { ffi::mps_polygon_acceleration_structure_set_polygon_count(self.ptr, count) };
179    }
180
181    #[must_use]
182    pub fn usage(&self) -> usize {
183        unsafe { ffi::mps_polygon_acceleration_structure_usage(self.ptr) }
184    }
185
186    pub fn set_usage(&self, usage: usize) {
187        unsafe { ffi::mps_polygon_acceleration_structure_set_usage(self.ptr, usage) };
188    }
189
190    #[must_use]
191    pub fn status(&self) -> usize {
192        unsafe { ffi::mps_polygon_acceleration_structure_status(self.ptr) }
193    }
194
195    pub fn rebuild(&self) {
196        unsafe { ffi::mps_polygon_acceleration_structure_rebuild(self.ptr) };
197    }
198
199    pub fn encode_refit(&self, command_buffer: &CommandBuffer) {
200        unsafe {
201            ffi::mps_polygon_acceleration_structure_encode_refit(self.ptr, command_buffer.as_ptr());
202        };
203    }
204}
205
206opaque_handle!(RayIntersector);
207impl RayIntersector {
208    #[must_use]
209    pub fn new(device: &MetalDevice) -> Option<Self> {
210        let ptr = unsafe { ffi::mps_ray_intersector_new(device.as_ptr()) };
211        if ptr.is_null() {
212            None
213        } else {
214            Some(Self { ptr })
215        }
216    }
217
218    #[must_use]
219    pub fn cull_mode(&self) -> usize {
220        unsafe { ffi::mps_ray_intersector_cull_mode(self.ptr) }
221    }
222
223    pub fn set_cull_mode(&self, cull_mode: usize) {
224        unsafe { ffi::mps_ray_intersector_set_cull_mode(self.ptr, cull_mode) };
225    }
226
227    #[must_use]
228    pub fn front_facing_winding(&self) -> usize {
229        unsafe { ffi::mps_ray_intersector_front_facing_winding(self.ptr) }
230    }
231
232    pub fn set_front_facing_winding(&self, winding: usize) {
233        unsafe { ffi::mps_ray_intersector_set_front_facing_winding(self.ptr, winding) };
234    }
235
236    #[must_use]
237    pub fn ray_stride(&self) -> usize {
238        unsafe { ffi::mps_ray_intersector_ray_stride(self.ptr) }
239    }
240
241    pub fn set_ray_stride(&self, stride: usize) {
242        unsafe { ffi::mps_ray_intersector_set_ray_stride(self.ptr, stride) };
243    }
244
245    #[must_use]
246    pub fn intersection_stride(&self) -> usize {
247        unsafe { ffi::mps_ray_intersector_intersection_stride(self.ptr) }
248    }
249
250    pub fn set_intersection_stride(&self, stride: usize) {
251        unsafe { ffi::mps_ray_intersector_set_intersection_stride(self.ptr, stride) };
252    }
253
254    #[must_use]
255    pub fn ray_data_type(&self) -> usize {
256        unsafe { ffi::mps_ray_intersector_ray_data_type(self.ptr) }
257    }
258
259    pub fn set_ray_data_type(&self, data_type: usize) {
260        unsafe { ffi::mps_ray_intersector_set_ray_data_type(self.ptr, data_type) };
261    }
262
263    #[must_use]
264    pub fn intersection_data_type(&self) -> usize {
265        unsafe { ffi::mps_ray_intersector_intersection_data_type(self.ptr) }
266    }
267
268    pub fn set_intersection_data_type(&self, data_type: usize) {
269        unsafe { ffi::mps_ray_intersector_set_intersection_data_type(self.ptr, data_type) };
270    }
271
272    #[must_use]
273    pub fn recommended_minimum_ray_batch_size(&self, ray_count: usize) -> usize {
274        unsafe { ffi::mps_ray_intersector_recommended_minimum_ray_batch_size(self.ptr, ray_count) }
275    }
276
277    #[allow(clippy::too_many_arguments)]
278    pub fn encode_intersection(
279        &self,
280        command_buffer: &CommandBuffer,
281        intersection_type: usize,
282        ray_buffer: &MetalBuffer,
283        ray_buffer_offset: usize,
284        intersection_buffer: &MetalBuffer,
285        intersection_buffer_offset: usize,
286        ray_count: usize,
287        acceleration_structure: &PolygonAccelerationStructure,
288    ) {
289        unsafe {
290            ffi::mps_ray_intersector_encode_intersection(
291                self.ptr,
292                command_buffer.as_ptr(),
293                intersection_type,
294                ray_buffer.as_ptr(),
295                ray_buffer_offset,
296                intersection_buffer.as_ptr(),
297                intersection_buffer_offset,
298                ray_count,
299                acceleration_structure.as_ptr(),
300            );
301        };
302    }
303}
304
305opaque_handle!(SVGF);
306impl SVGF {
307    #[must_use]
308    pub fn new(device: &MetalDevice) -> Option<Self> {
309        let ptr = unsafe { ffi::mps_svgf_new(device.as_ptr()) };
310        if ptr.is_null() {
311            None
312        } else {
313            Some(Self { ptr })
314        }
315    }
316
317    #[must_use]
318    pub fn depth_weight(&self) -> f32 {
319        unsafe { ffi::mps_svgf_depth_weight(self.ptr) }
320    }
321
322    pub fn set_depth_weight(&self, value: f32) {
323        unsafe { ffi::mps_svgf_set_depth_weight(self.ptr, value) };
324    }
325
326    #[must_use]
327    pub fn normal_weight(&self) -> f32 {
328        unsafe { ffi::mps_svgf_normal_weight(self.ptr) }
329    }
330
331    pub fn set_normal_weight(&self, value: f32) {
332        unsafe { ffi::mps_svgf_set_normal_weight(self.ptr, value) };
333    }
334
335    #[must_use]
336    pub fn luminance_weight(&self) -> f32 {
337        unsafe { ffi::mps_svgf_luminance_weight(self.ptr) }
338    }
339
340    pub fn set_luminance_weight(&self, value: f32) {
341        unsafe { ffi::mps_svgf_set_luminance_weight(self.ptr, value) };
342    }
343
344    #[must_use]
345    pub fn channel_count(&self) -> usize {
346        unsafe { ffi::mps_svgf_channel_count(self.ptr) }
347    }
348
349    pub fn set_channel_count(&self, value: usize) {
350        unsafe { ffi::mps_svgf_set_channel_count(self.ptr, value) };
351    }
352
353    #[must_use]
354    pub fn channel_count2(&self) -> usize {
355        unsafe { ffi::mps_svgf_channel_count2(self.ptr) }
356    }
357
358    pub fn set_channel_count2(&self, value: usize) {
359        unsafe { ffi::mps_svgf_set_channel_count2(self.ptr, value) };
360    }
361}