1use std::ffi::c_void;
10use std::ptr::NonNull;
11
12use mtl_foundation::{Range, Referencing, UInteger};
13use mtl_sys::{Class, msg_send_0, msg_send_1, msg_send_2, msg_send_3, sel};
14
15use crate::Buffer;
16use crate::enums::{FunctionType, IntersectionFunctionSignature};
17use crate::types::ResourceID;
18
19#[repr(C, packed)]
27#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
28pub struct IntersectionFunctionBufferArguments {
29 pub intersection_function_buffer: u64,
30 pub intersection_function_buffer_size: u64,
31 pub intersection_function_stride: u64,
32}
33
34#[repr(transparent)]
42pub struct FunctionHandle(pub(crate) NonNull<c_void>);
43
44impl FunctionHandle {
45 #[inline]
51 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
52 NonNull::new(ptr).map(Self)
53 }
54
55 #[inline]
57 pub fn as_raw(&self) -> *mut c_void {
58 self.0.as_ptr()
59 }
60
61 pub fn device(&self) -> crate::Device {
69 unsafe {
70 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(device));
71 let _: *mut c_void = msg_send_0(ptr, sel!(retain));
72 crate::Device::from_raw(ptr).expect("function handle has no device")
73 }
74 }
75
76 #[inline]
80 pub fn function_type(&self) -> FunctionType {
81 unsafe { msg_send_0(self.as_ptr(), sel!(functionType)) }
82 }
83
84 #[inline]
88 pub fn gpu_resource_id(&self) -> ResourceID {
89 unsafe { msg_send_0(self.as_ptr(), sel!(gpuResourceID)) }
90 }
91
92 pub fn name(&self) -> Option<String> {
96 unsafe {
97 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(name));
98 if ptr.is_null() {
99 return None;
100 }
101 let utf8_ptr: *const std::ffi::c_char =
102 mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
103 if utf8_ptr.is_null() {
104 return None;
105 }
106 let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
107 Some(c_str.to_string_lossy().into_owned())
108 }
109 }
110}
111
112impl Clone for FunctionHandle {
113 fn clone(&self) -> Self {
114 unsafe {
115 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
116 }
117 Self(self.0)
118 }
119}
120
121impl Drop for FunctionHandle {
122 fn drop(&mut self) {
123 unsafe {
124 msg_send_0::<()>(self.as_ptr(), sel!(release));
125 }
126 }
127}
128
129impl Referencing for FunctionHandle {
130 #[inline]
131 fn as_ptr(&self) -> *const c_void {
132 self.0.as_ptr()
133 }
134}
135
136unsafe impl Send for FunctionHandle {}
137unsafe impl Sync for FunctionHandle {}
138
139impl std::fmt::Debug for FunctionHandle {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 f.debug_struct("FunctionHandle")
142 .field("name", &self.name())
143 .field("function_type", &self.function_type())
144 .finish()
145 }
146}
147
148#[repr(transparent)]
156pub struct VisibleFunctionTableDescriptor(pub(crate) NonNull<c_void>);
157
158impl VisibleFunctionTableDescriptor {
159 pub fn new() -> Option<Self> {
163 unsafe {
164 let class = Class::get("MTLVisibleFunctionTableDescriptor")?;
165 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
166 if ptr.is_null() {
167 return None;
168 }
169 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
170 Self::from_raw(ptr)
171 }
172 }
173
174 pub fn visible_function_table_descriptor() -> Option<Self> {
178 unsafe {
179 let class = Class::get("MTLVisibleFunctionTableDescriptor")?;
180 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(visibleFunctionTableDescriptor));
181 if ptr.is_null() {
182 return None;
183 }
184 msg_send_0::<*mut c_void>(ptr, sel!(retain));
186 Self::from_raw(ptr)
187 }
188 }
189
190 #[inline]
196 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
197 NonNull::new(ptr).map(Self)
198 }
199
200 #[inline]
202 pub fn as_raw(&self) -> *mut c_void {
203 self.0.as_ptr()
204 }
205
206 #[inline]
214 pub fn function_count(&self) -> UInteger {
215 unsafe { msg_send_0(self.as_ptr(), sel!(functionCount)) }
216 }
217
218 #[inline]
222 pub fn set_function_count(&self, function_count: UInteger) {
223 unsafe {
224 let _: () = msg_send_1(self.as_ptr(), sel!(setFunctionCount:), function_count);
225 }
226 }
227}
228
229impl Clone for VisibleFunctionTableDescriptor {
230 fn clone(&self) -> Self {
231 unsafe {
232 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
233 }
234 Self(self.0)
235 }
236}
237
238impl Drop for VisibleFunctionTableDescriptor {
239 fn drop(&mut self) {
240 unsafe {
241 msg_send_0::<()>(self.as_ptr(), sel!(release));
242 }
243 }
244}
245
246impl Referencing for VisibleFunctionTableDescriptor {
247 #[inline]
248 fn as_ptr(&self) -> *const c_void {
249 self.0.as_ptr()
250 }
251}
252
253unsafe impl Send for VisibleFunctionTableDescriptor {}
254unsafe impl Sync for VisibleFunctionTableDescriptor {}
255
256impl std::fmt::Debug for VisibleFunctionTableDescriptor {
257 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258 f.debug_struct("VisibleFunctionTableDescriptor")
259 .field("function_count", &self.function_count())
260 .finish()
261 }
262}
263
264#[repr(transparent)]
274pub struct VisibleFunctionTable(pub(crate) NonNull<c_void>);
275
276impl VisibleFunctionTable {
277 #[inline]
283 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
284 NonNull::new(ptr).map(Self)
285 }
286
287 #[inline]
289 pub fn as_raw(&self) -> *mut c_void {
290 self.0.as_ptr()
291 }
292
293 #[inline]
301 pub fn gpu_resource_id(&self) -> ResourceID {
302 unsafe { msg_send_0(self.as_ptr(), sel!(gpuResourceID)) }
303 }
304
305 pub fn set_function(&self, function: &FunctionHandle, index: UInteger) {
313 unsafe {
314 let _: () = msg_send_2(
315 self.as_ptr(),
316 sel!(setFunction:atIndex:),
317 function.as_ptr(),
318 index,
319 );
320 }
321 }
322
323 pub fn set_functions(&self, functions: &[&FunctionHandle], range: Range) {
327 let ptrs: Vec<*const c_void> = functions.iter().map(|f| f.as_ptr()).collect();
328 unsafe {
329 let _: () = msg_send_2(
330 self.as_ptr(),
331 sel!(setFunctions:withRange:),
332 ptrs.as_ptr(),
333 range,
334 );
335 }
336 }
337}
338
339impl Clone for VisibleFunctionTable {
340 fn clone(&self) -> Self {
341 unsafe {
342 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
343 }
344 Self(self.0)
345 }
346}
347
348impl Drop for VisibleFunctionTable {
349 fn drop(&mut self) {
350 unsafe {
351 msg_send_0::<()>(self.as_ptr(), sel!(release));
352 }
353 }
354}
355
356impl Referencing for VisibleFunctionTable {
357 #[inline]
358 fn as_ptr(&self) -> *const c_void {
359 self.0.as_ptr()
360 }
361}
362
363unsafe impl Send for VisibleFunctionTable {}
364unsafe impl Sync for VisibleFunctionTable {}
365
366impl std::fmt::Debug for VisibleFunctionTable {
367 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
368 f.debug_struct("VisibleFunctionTable").finish()
369 }
370}
371
372#[repr(transparent)]
380pub struct IntersectionFunctionTableDescriptor(pub(crate) NonNull<c_void>);
381
382impl IntersectionFunctionTableDescriptor {
383 pub fn new() -> Option<Self> {
387 unsafe {
388 let class = Class::get("MTLIntersectionFunctionTableDescriptor")?;
389 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
390 if ptr.is_null() {
391 return None;
392 }
393 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
394 Self::from_raw(ptr)
395 }
396 }
397
398 pub fn intersection_function_table_descriptor() -> Option<Self> {
402 unsafe {
403 let class = Class::get("MTLIntersectionFunctionTableDescriptor")?;
404 let ptr: *mut c_void =
405 msg_send_0(class.as_ptr(), sel!(intersectionFunctionTableDescriptor));
406 if ptr.is_null() {
407 return None;
408 }
409 msg_send_0::<*mut c_void>(ptr, sel!(retain));
411 Self::from_raw(ptr)
412 }
413 }
414
415 #[inline]
421 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
422 NonNull::new(ptr).map(Self)
423 }
424
425 #[inline]
427 pub fn as_raw(&self) -> *mut c_void {
428 self.0.as_ptr()
429 }
430
431 #[inline]
439 pub fn function_count(&self) -> UInteger {
440 unsafe { msg_send_0(self.as_ptr(), sel!(functionCount)) }
441 }
442
443 #[inline]
447 pub fn set_function_count(&self, function_count: UInteger) {
448 unsafe {
449 let _: () = msg_send_1(self.as_ptr(), sel!(setFunctionCount:), function_count);
450 }
451 }
452}
453
454impl Clone for IntersectionFunctionTableDescriptor {
455 fn clone(&self) -> Self {
456 unsafe {
457 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
458 }
459 Self(self.0)
460 }
461}
462
463impl Drop for IntersectionFunctionTableDescriptor {
464 fn drop(&mut self) {
465 unsafe {
466 msg_send_0::<()>(self.as_ptr(), sel!(release));
467 }
468 }
469}
470
471impl Referencing for IntersectionFunctionTableDescriptor {
472 #[inline]
473 fn as_ptr(&self) -> *const c_void {
474 self.0.as_ptr()
475 }
476}
477
478unsafe impl Send for IntersectionFunctionTableDescriptor {}
479unsafe impl Sync for IntersectionFunctionTableDescriptor {}
480
481impl std::fmt::Debug for IntersectionFunctionTableDescriptor {
482 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
483 f.debug_struct("IntersectionFunctionTableDescriptor")
484 .field("function_count", &self.function_count())
485 .finish()
486 }
487}
488
489#[repr(transparent)]
499pub struct IntersectionFunctionTable(pub(crate) NonNull<c_void>);
500
501impl IntersectionFunctionTable {
502 #[inline]
508 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
509 NonNull::new(ptr).map(Self)
510 }
511
512 #[inline]
514 pub fn as_raw(&self) -> *mut c_void {
515 self.0.as_ptr()
516 }
517
518 #[inline]
526 pub fn gpu_resource_id(&self) -> ResourceID {
527 unsafe { msg_send_0(self.as_ptr(), sel!(gpuResourceID)) }
528 }
529
530 pub fn set_buffer(&self, buffer: &Buffer, offset: UInteger, index: UInteger) {
538 unsafe {
539 let _: () = msg_send_3(
540 self.as_ptr(),
541 sel!(setBuffer:offset:atIndex:),
542 buffer.as_ptr(),
543 offset,
544 index,
545 );
546 }
547 }
548
549 pub fn set_buffers(&self, buffers: &[&Buffer], offsets: &[UInteger], range: Range) {
553 let ptrs: Vec<*const c_void> = buffers.iter().map(|b| b.as_ptr()).collect();
554 unsafe {
555 let _: () = msg_send_3(
556 self.as_ptr(),
557 sel!(setBuffers:offsets:withRange:),
558 ptrs.as_ptr(),
559 offsets.as_ptr(),
560 range,
561 );
562 }
563 }
564
565 pub fn set_function(&self, function: &FunctionHandle, index: UInteger) {
573 unsafe {
574 let _: () = msg_send_2(
575 self.as_ptr(),
576 sel!(setFunction:atIndex:),
577 function.as_ptr(),
578 index,
579 );
580 }
581 }
582
583 pub fn set_functions(&self, functions: &[&FunctionHandle], range: Range) {
587 let ptrs: Vec<*const c_void> = functions.iter().map(|f| f.as_ptr()).collect();
588 unsafe {
589 let _: () = msg_send_2(
590 self.as_ptr(),
591 sel!(setFunctions:withRange:),
592 ptrs.as_ptr(),
593 range,
594 );
595 }
596 }
597
598 pub fn set_opaque_curve_intersection_function_at_index(
606 &self,
607 signature: IntersectionFunctionSignature,
608 index: UInteger,
609 ) {
610 unsafe {
611 let _: () = msg_send_2(
612 self.as_ptr(),
613 sel!(setOpaqueCurveIntersectionFunctionWithSignature:atIndex:),
614 signature,
615 index,
616 );
617 }
618 }
619
620 pub fn set_opaque_curve_intersection_function_with_range(
624 &self,
625 signature: IntersectionFunctionSignature,
626 range: Range,
627 ) {
628 unsafe {
629 let _: () = msg_send_2(
630 self.as_ptr(),
631 sel!(setOpaqueCurveIntersectionFunctionWithSignature:withRange:),
632 signature,
633 range,
634 );
635 }
636 }
637
638 pub fn set_opaque_triangle_intersection_function_at_index(
642 &self,
643 signature: IntersectionFunctionSignature,
644 index: UInteger,
645 ) {
646 unsafe {
647 let _: () = msg_send_2(
648 self.as_ptr(),
649 sel!(setOpaqueTriangleIntersectionFunctionWithSignature:atIndex:),
650 signature,
651 index,
652 );
653 }
654 }
655
656 pub fn set_opaque_triangle_intersection_function_with_range(
660 &self,
661 signature: IntersectionFunctionSignature,
662 range: Range,
663 ) {
664 unsafe {
665 let _: () = msg_send_2(
666 self.as_ptr(),
667 sel!(setOpaqueTriangleIntersectionFunctionWithSignature:withRange:),
668 signature,
669 range,
670 );
671 }
672 }
673
674 pub fn set_visible_function_table(
682 &self,
683 function_table: &VisibleFunctionTable,
684 buffer_index: UInteger,
685 ) {
686 unsafe {
687 let _: () = msg_send_2(
688 self.as_ptr(),
689 sel!(setVisibleFunctionTable:atBufferIndex:),
690 function_table.as_ptr(),
691 buffer_index,
692 );
693 }
694 }
695
696 pub fn set_visible_function_tables(
700 &self,
701 function_tables: &[&VisibleFunctionTable],
702 buffer_range: Range,
703 ) {
704 let ptrs: Vec<*const c_void> = function_tables.iter().map(|t| t.as_ptr()).collect();
705 unsafe {
706 let _: () = msg_send_2(
707 self.as_ptr(),
708 sel!(setVisibleFunctionTables:withBufferRange:),
709 ptrs.as_ptr(),
710 buffer_range,
711 );
712 }
713 }
714}
715
716impl Clone for IntersectionFunctionTable {
717 fn clone(&self) -> Self {
718 unsafe {
719 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
720 }
721 Self(self.0)
722 }
723}
724
725impl Drop for IntersectionFunctionTable {
726 fn drop(&mut self) {
727 unsafe {
728 msg_send_0::<()>(self.as_ptr(), sel!(release));
729 }
730 }
731}
732
733impl Referencing for IntersectionFunctionTable {
734 #[inline]
735 fn as_ptr(&self) -> *const c_void {
736 self.0.as_ptr()
737 }
738}
739
740unsafe impl Send for IntersectionFunctionTable {}
741unsafe impl Sync for IntersectionFunctionTable {}
742
743impl std::fmt::Debug for IntersectionFunctionTable {
744 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
745 f.debug_struct("IntersectionFunctionTable").finish()
746 }
747}
748
749#[cfg(test)]
754mod tests {
755 use super::*;
756
757 #[test]
758 fn test_intersection_function_buffer_arguments_size() {
759 assert_eq!(
760 std::mem::size_of::<IntersectionFunctionBufferArguments>(),
761 24
762 );
763 }
764
765 #[test]
766 fn test_visible_function_table_descriptor_creation() {
767 let desc = VisibleFunctionTableDescriptor::new();
768 assert!(desc.is_some());
769 }
770
771 #[test]
772 fn test_visible_function_table_descriptor_class_method() {
773 let desc = VisibleFunctionTableDescriptor::visible_function_table_descriptor();
774 assert!(desc.is_some());
775 }
776
777 #[test]
778 fn test_visible_function_table_descriptor_function_count() {
779 let desc = VisibleFunctionTableDescriptor::new().unwrap();
780 assert_eq!(desc.function_count(), 0);
782
783 desc.set_function_count(10);
784 assert_eq!(desc.function_count(), 10);
785 }
786
787 #[test]
788 fn test_intersection_function_table_descriptor_creation() {
789 let desc = IntersectionFunctionTableDescriptor::new();
790 assert!(desc.is_some());
791 }
792
793 #[test]
794 fn test_intersection_function_table_descriptor_class_method() {
795 let desc = IntersectionFunctionTableDescriptor::intersection_function_table_descriptor();
796 assert!(desc.is_some());
797 }
798
799 #[test]
800 fn test_intersection_function_table_descriptor_function_count() {
801 let desc = IntersectionFunctionTableDescriptor::new().unwrap();
802 assert_eq!(desc.function_count(), 0);
804
805 desc.set_function_count(5);
806 assert_eq!(desc.function_count(), 5);
807 }
808}