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