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 {}
22 unsafe impl Sync for $name {}
24
25 impl Drop for $name {
26 fn drop(&mut self) {
27 if !self.ptr.is_null() {
28 unsafe { ffi::mps_object_release(self.ptr) };
30 self.ptr = ptr::null_mut();
31 }
32 }
33 }
34
35 impl $name {
36 #[must_use]
37 pub const fn as_ptr(&self) -> *mut c_void {
38 self.ptr
39 }
40 }
41 };
42}
43
44pub fn supports_mtl_device(device: &MetalDevice) -> bool {
45 unsafe { ffi::mps_supports_mtl_device(device.as_ptr()) }
47}
48
49opaque_handle!(PreferredDevice);
50impl PreferredDevice {
51 #[must_use]
52 pub fn as_borrowed_device(&self) -> ManuallyDropDevice {
53 unsafe { MetalDevice::from_raw_borrowed(self.ptr) }
55 }
56}
57
58#[must_use]
59pub fn preferred_device(options: usize) -> Option<PreferredDevice> {
60 let ptr = unsafe { ffi::mps_get_preferred_device(options) };
62 if ptr.is_null() {
63 None
64 } else {
65 Some(PreferredDevice { ptr })
66 }
67}
68
69pub fn hint_temporary_memory_high_water_mark(command_buffer: &MetalCommandBuffer, bytes: usize) {
70 unsafe { ffi::mps_hint_temporary_memory_high_water_mark(command_buffer.as_ptr(), bytes) };
72}
73
74pub use crate::generated::core::*;
75
76pub fn set_heap_cache_duration(command_buffer: &MetalCommandBuffer, seconds: f64) {
77 unsafe { ffi::mps_set_heap_cache_duration(command_buffer.as_ptr(), seconds) };
79}
80
81opaque_handle!(Predicate);
82impl Predicate {
83 #[must_use]
84 pub fn new_with_buffer(buffer: &MetalBuffer, offset: usize) -> Option<Self> {
85 let ptr = unsafe { ffi::mps_predicate_new_with_buffer(buffer.as_ptr(), offset) };
87 if ptr.is_null() {
88 None
89 } else {
90 Some(Self { ptr })
91 }
92 }
93
94 #[must_use]
95 pub fn new_with_device(device: &MetalDevice) -> Option<Self> {
96 let ptr = unsafe { ffi::mps_predicate_new_with_device(device.as_ptr()) };
98 if ptr.is_null() {
99 None
100 } else {
101 Some(Self { ptr })
102 }
103 }
104
105 #[must_use]
106 pub fn predicate_offset(&self) -> usize {
107 unsafe { ffi::mps_predicate_offset(self.ptr) }
109 }
110}
111
112opaque_handle!(CommandBuffer);
113impl CommandBuffer {
114 #[must_use]
115 pub fn new_with_command_buffer(command_buffer: &MetalCommandBuffer) -> Option<Self> {
116 let ptr =
118 unsafe { ffi::mps_command_buffer_new_with_command_buffer(command_buffer.as_ptr()) };
119 if ptr.is_null() {
120 None
121 } else {
122 Some(Self { ptr })
123 }
124 }
125
126 #[must_use]
127 pub fn from_command_queue(command_queue: &CommandQueue) -> Option<Self> {
128 let ptr = unsafe { ffi::mps_command_buffer_from_command_queue(command_queue.as_ptr()) };
130 if ptr.is_null() {
131 None
132 } else {
133 Some(Self { ptr })
134 }
135 }
136
137 pub fn set_predicate(&self, predicate: &Predicate) {
138 unsafe { ffi::mps_command_buffer_set_predicate(self.ptr, predicate.as_ptr()) };
140 }
141
142 pub fn clear_predicate(&self) {
143 unsafe { ffi::mps_command_buffer_clear_predicate(self.ptr) };
145 }
146
147 pub fn prefetch_heap_for_workload_size(&self, size: usize) {
148 unsafe { ffi::mps_command_buffer_prefetch_heap(self.ptr, size) };
150 }
151
152 pub fn commit_and_continue(&self) {
153 unsafe { ffi::mps_command_buffer_commit_and_continue(self.ptr) };
155 }
156}