1use crate::ffi;
2use apple_metal::{
3 CommandBuffer as MetalCommandBuffer, CommandQueue, ManuallyDropDevice, MetalBuffer, MetalDevice,
4};
5use core::ffi::c_void;
6use core::ptr;
7
8pub mod device_options {
9 pub const DEFAULT: usize = 0;
10 pub const LOW_POWER: usize = 1;
11 pub const SKIP_REMOVABLE: usize = 2;
12}
13
14macro_rules! opaque_handle {
15 ($name:ident) => {
16 pub struct $name {
17 ptr: *mut c_void,
18 }
19
20 unsafe impl Send for $name {}
21 unsafe impl Sync for $name {}
22
23 impl Drop for $name {
24 fn drop(&mut self) {
25 if !self.ptr.is_null() {
26 unsafe { ffi::mps_object_release(self.ptr) };
27 self.ptr = ptr::null_mut();
28 }
29 }
30 }
31
32 impl $name {
33 #[must_use]
34 pub const fn as_ptr(&self) -> *mut c_void {
35 self.ptr
36 }
37 }
38 };
39}
40
41pub fn supports_mtl_device(device: &MetalDevice) -> bool {
42 unsafe { ffi::mps_supports_mtl_device(device.as_ptr()) }
43}
44
45opaque_handle!(PreferredDevice);
46impl PreferredDevice {
47 #[must_use]
48 pub fn as_borrowed_device(&self) -> ManuallyDropDevice {
49 unsafe { MetalDevice::from_raw_borrowed(self.ptr) }
50 }
51}
52
53#[must_use]
54pub fn preferred_device(options: usize) -> Option<PreferredDevice> {
55 let ptr = unsafe { ffi::mps_get_preferred_device(options) };
56 if ptr.is_null() {
57 None
58 } else {
59 Some(PreferredDevice { ptr })
60 }
61}
62
63pub fn hint_temporary_memory_high_water_mark(command_buffer: &MetalCommandBuffer, bytes: usize) {
64 unsafe { ffi::mps_hint_temporary_memory_high_water_mark(command_buffer.as_ptr(), bytes) };
65}
66
67pub fn set_heap_cache_duration(command_buffer: &MetalCommandBuffer, seconds: f64) {
68 unsafe { ffi::mps_set_heap_cache_duration(command_buffer.as_ptr(), seconds) };
69}
70
71opaque_handle!(Predicate);
72impl Predicate {
73 #[must_use]
74 pub fn new_with_buffer(buffer: &MetalBuffer, offset: usize) -> Option<Self> {
75 let ptr = unsafe { ffi::mps_predicate_new_with_buffer(buffer.as_ptr(), offset) };
76 if ptr.is_null() {
77 None
78 } else {
79 Some(Self { ptr })
80 }
81 }
82
83 #[must_use]
84 pub fn new_with_device(device: &MetalDevice) -> Option<Self> {
85 let ptr = unsafe { ffi::mps_predicate_new_with_device(device.as_ptr()) };
86 if ptr.is_null() {
87 None
88 } else {
89 Some(Self { ptr })
90 }
91 }
92
93 #[must_use]
94 pub fn predicate_offset(&self) -> usize {
95 unsafe { ffi::mps_predicate_offset(self.ptr) }
96 }
97}
98
99opaque_handle!(CommandBuffer);
100impl CommandBuffer {
101 #[must_use]
102 pub fn new_with_command_buffer(command_buffer: &MetalCommandBuffer) -> Option<Self> {
103 let ptr =
104 unsafe { ffi::mps_command_buffer_new_with_command_buffer(command_buffer.as_ptr()) };
105 if ptr.is_null() {
106 None
107 } else {
108 Some(Self { ptr })
109 }
110 }
111
112 #[must_use]
113 pub fn from_command_queue(command_queue: &CommandQueue) -> Option<Self> {
114 let ptr = unsafe { ffi::mps_command_buffer_from_command_queue(command_queue.as_ptr()) };
115 if ptr.is_null() {
116 None
117 } else {
118 Some(Self { ptr })
119 }
120 }
121
122 pub fn set_predicate(&self, predicate: &Predicate) {
123 unsafe { ffi::mps_command_buffer_set_predicate(self.ptr, predicate.as_ptr()) };
124 }
125
126 pub fn clear_predicate(&self) {
127 unsafe { ffi::mps_command_buffer_clear_predicate(self.ptr) };
128 }
129
130 pub fn prefetch_heap_for_workload_size(&self, size: usize) {
131 unsafe { ffi::mps_command_buffer_prefetch_heap(self.ptr, size) };
132 }
133
134 pub fn commit_and_continue(&self) {
135 unsafe { ffi::mps_command_buffer_commit_and_continue(self.ptr) };
136 }
137}