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 {
10 pub const DEFAULT: usize = 0;
12 pub const LOW_POWER: usize = 1;
14 pub const SKIP_REMOVABLE: usize = 2;
16}
17
18macro_rules! opaque_handle {
19 ($name:ident, $doc:expr) => {
20 #[doc = $doc]
21 pub struct $name {
22 ptr: *mut c_void,
23 }
24
25 unsafe impl Send for $name {}
27 unsafe impl Sync for $name {}
29
30 impl Drop for $name {
31 fn drop(&mut self) {
32 if !self.ptr.is_null() {
33 unsafe { ffi::mps_object_release(self.ptr) };
35 self.ptr = ptr::null_mut();
36 }
37 }
38 }
39
40 impl $name {
41 #[must_use]
43 pub const fn as_ptr(&self) -> *mut c_void {
44 self.ptr
45 }
46 }
47 };
48}
49
50pub fn supports_mtl_device(device: &MetalDevice) -> bool {
52 unsafe { ffi::mps_supports_mtl_device(device.as_ptr()) }
54}
55
56opaque_handle!(PreferredDevice, "Owns the retained `MTLDevice` returned by `MPSGetPreferredDevice`.");
57impl PreferredDevice {
58 #[must_use]
60 pub fn as_borrowed_device(&self) -> ManuallyDropDevice {
61 unsafe { MetalDevice::from_raw_borrowed(self.ptr) }
63 }
64}
65
66#[must_use]
68pub fn preferred_device(options: usize) -> Option<PreferredDevice> {
69 let ptr = unsafe { ffi::mps_get_preferred_device(options) };
71 if ptr.is_null() {
72 None
73 } else {
74 Some(PreferredDevice { ptr })
75 }
76}
77
78pub fn hint_temporary_memory_high_water_mark(command_buffer: &MetalCommandBuffer, bytes: usize) {
80 unsafe { ffi::mps_hint_temporary_memory_high_water_mark(command_buffer.as_ptr(), bytes) };
82}
83
84#[doc(hidden)]
85pub use crate::generated::core::*;
86
87pub fn set_heap_cache_duration(command_buffer: &MetalCommandBuffer, seconds: f64) {
89 unsafe { ffi::mps_set_heap_cache_duration(command_buffer.as_ptr(), seconds) };
91}
92
93opaque_handle!(Predicate, "Wraps `MPSPredicate`.");
94impl Predicate {
95 #[must_use]
97 pub fn new_with_buffer(buffer: &MetalBuffer, offset: usize) -> Option<Self> {
98 let ptr = unsafe { ffi::mps_predicate_new_with_buffer(buffer.as_ptr(), offset) };
100 if ptr.is_null() {
101 None
102 } else {
103 Some(Self { ptr })
104 }
105 }
106
107 #[must_use]
109 pub fn new_with_device(device: &MetalDevice) -> Option<Self> {
110 let ptr = unsafe { ffi::mps_predicate_new_with_device(device.as_ptr()) };
112 if ptr.is_null() {
113 None
114 } else {
115 Some(Self { ptr })
116 }
117 }
118
119 #[must_use]
121 pub fn predicate_offset(&self) -> usize {
122 unsafe { ffi::mps_predicate_offset(self.ptr) }
124 }
125}
126
127opaque_handle!(CommandBuffer, "Wraps `MPSCommandBuffer`.");
128impl CommandBuffer {
129 #[must_use]
131 pub fn new_with_command_buffer(command_buffer: &MetalCommandBuffer) -> Option<Self> {
132 let ptr =
134 unsafe { ffi::mps_command_buffer_new_with_command_buffer(command_buffer.as_ptr()) };
135 if ptr.is_null() {
136 None
137 } else {
138 Some(Self { ptr })
139 }
140 }
141
142 #[must_use]
144 pub fn from_command_queue(command_queue: &CommandQueue) -> Option<Self> {
145 let ptr = unsafe { ffi::mps_command_buffer_from_command_queue(command_queue.as_ptr()) };
147 if ptr.is_null() {
148 None
149 } else {
150 Some(Self { ptr })
151 }
152 }
153
154 pub fn set_predicate(&self, predicate: &Predicate) {
156 unsafe { ffi::mps_command_buffer_set_predicate(self.ptr, predicate.as_ptr()) };
158 }
159
160 pub fn clear_predicate(&self) {
162 unsafe { ffi::mps_command_buffer_clear_predicate(self.ptr) };
164 }
165
166 pub fn prefetch_heap_for_workload_size(&self, size: usize) {
168 unsafe { ffi::mps_command_buffer_prefetch_heap(self.ptr, size) };
170 }
171
172 pub fn commit_and_continue(&self) {
174 unsafe { ffi::mps_command_buffer_commit_and_continue(self.ptr) };
176 }
177}