1use crate::ffi;
2use apple_metal::{CommandBuffer as MetalCommandBuffer, MetalDevice};
3use core::ffi::c_void;
4use core::ptr;
5
6pub mod state_resource_type {
8 pub const NONE: usize = 0;
10 pub const BUFFER: usize = 1;
12 pub const TEXTURE: usize = 2;
14}
15
16#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
18pub struct StateTextureInfo {
19 pub width: usize,
21 pub height: usize,
23 pub depth: usize,
25 pub array_length: usize,
27 pub pixel_format: usize,
29 pub texture_type: usize,
31 pub usage: usize,
33}
34
35macro_rules! opaque_handle {
36 ($name:ident, $doc:expr) => {
37 #[doc = $doc]
38 pub struct $name {
39 ptr: *mut c_void,
40 }
41
42 unsafe impl Send for $name {}
44 unsafe impl Sync for $name {}
46
47 impl Drop for $name {
48 fn drop(&mut self) {
49 if !self.ptr.is_null() {
50 unsafe { ffi::mps_object_release(self.ptr) };
52 self.ptr = ptr::null_mut();
53 }
54 }
55 }
56
57 impl $name {
58 #[must_use]
60 pub const fn as_ptr(&self) -> *mut c_void {
61 self.ptr
62 }
63 }
64 };
65}
66
67opaque_handle!(StateResourceList, "Wraps `MPSStateResourceList`.");
68impl StateResourceList {
69 #[must_use]
71 pub fn new() -> Option<Self> {
72 let ptr = unsafe { ffi::mps_state_resource_list_new() };
74 if ptr.is_null() {
75 None
76 } else {
77 Some(Self { ptr })
78 }
79 }
80
81 pub fn append_buffer(&self, size: usize) {
83 unsafe { ffi::mps_state_resource_list_append_buffer(self.ptr, size) };
85 }
86}
87
88opaque_handle!(State, "Wraps `MPSState`.");
89impl State {
90 #[must_use]
92 pub fn temporary(command_buffer: &MetalCommandBuffer) -> Option<Self> {
93 let ptr = unsafe { ffi::mps_state_temporary_new(command_buffer.as_ptr()) };
95 if ptr.is_null() {
96 None
97 } else {
98 Some(Self { ptr })
99 }
100 }
101
102 #[must_use]
104 pub fn temporary_with_buffer_size(
105 command_buffer: &MetalCommandBuffer,
106 buffer_size: usize,
107 ) -> Option<Self> {
108 let ptr = unsafe {
109 ffi::mps_state_temporary_new_with_buffer_size(command_buffer.as_ptr(), buffer_size)
110 };
111 if ptr.is_null() {
112 None
113 } else {
114 Some(Self { ptr })
115 }
116 }
117
118 #[must_use]
120 pub fn new_with_buffer_size(device: &MetalDevice, buffer_size: usize) -> Option<Self> {
121 let ptr = unsafe { ffi::mps_state_new_with_buffer_size(device.as_ptr(), buffer_size) };
123 if ptr.is_null() {
124 None
125 } else {
126 Some(Self { ptr })
127 }
128 }
129
130 #[must_use]
132 pub fn new_with_resource_list(
133 device: &MetalDevice,
134 resource_list: &StateResourceList,
135 ) -> Option<Self> {
136 let ptr = unsafe {
137 ffi::mps_state_new_with_resource_list(device.as_ptr(), resource_list.as_ptr())
138 };
139 if ptr.is_null() {
140 None
141 } else {
142 Some(Self { ptr })
143 }
144 }
145
146 #[must_use]
148 pub fn temporary_with_resource_list(
149 command_buffer: &MetalCommandBuffer,
150 resource_list: &StateResourceList,
151 ) -> Option<Self> {
152 let ptr = unsafe {
153 ffi::mps_state_temporary_new_with_resource_list(
154 command_buffer.as_ptr(),
155 resource_list.as_ptr(),
156 )
157 };
158 if ptr.is_null() {
159 None
160 } else {
161 Some(Self { ptr })
162 }
163 }
164
165 #[must_use]
167 pub fn resource_count(&self) -> usize {
168 unsafe { ffi::mps_state_resource_count(self.ptr) }
170 }
171
172 #[must_use]
174 pub fn read_count(&self) -> usize {
175 unsafe { ffi::mps_state_read_count(self.ptr) }
177 }
178
179 pub fn set_read_count(&self, count: usize) {
181 unsafe { ffi::mps_state_set_read_count(self.ptr, count) };
183 }
184
185 #[must_use]
187 pub fn is_temporary(&self) -> bool {
188 unsafe { ffi::mps_state_is_temporary(self.ptr) }
189 }
190
191 #[must_use]
193 pub fn buffer_size_at_index(&self, index: usize) -> usize {
194 unsafe { ffi::mps_state_buffer_size_at_index(self.ptr, index) }
195 }
196
197 #[must_use]
199 pub fn texture_info_at_index(&self, index: usize) -> StateTextureInfo {
200 let mut width = 0;
201 let mut height = 0;
202 let mut depth = 0;
203 let mut array_length = 0;
204 let mut pixel_format = 0;
205 let mut texture_type = 0;
206 let mut usage = 0;
207 unsafe {
208 ffi::mps_state_texture_info(
209 self.ptr,
210 index,
211 &mut width,
212 &mut height,
213 &mut depth,
214 &mut array_length,
215 &mut pixel_format,
216 &mut texture_type,
217 &mut usage,
218 );
219 };
220 StateTextureInfo {
221 width,
222 height,
223 depth,
224 array_length,
225 pixel_format,
226 texture_type,
227 usage,
228 }
229 }
230
231 #[must_use]
233 pub fn resource_type_at_index(&self, index: usize) -> usize {
234 unsafe { ffi::mps_state_resource_type_at_index(self.ptr, index) }
235 }
236
237 pub fn synchronize_on_command_buffer(&self, command_buffer: &MetalCommandBuffer) {
239 unsafe { ffi::mps_state_synchronize_on_command_buffer(self.ptr, command_buffer.as_ptr()) };
240 }
241
242 #[must_use]
244 pub fn resource_size(&self) -> usize {
245 unsafe { ffi::mps_state_resource_size(self.ptr) }
246 }
247}
248
249#[must_use]
251pub fn state_batch_increment_read_count(states: &[&State], amount: isize) -> usize {
252 let handles: Vec<_> = states.iter().map(|state| state.as_ptr()).collect();
253 let handles_ptr = if handles.is_empty() {
254 ptr::null()
255 } else {
256 handles.as_ptr()
257 };
258 unsafe { ffi::mps_state_batch_increment_read_count(handles_ptr, handles.len(), amount) }
259}
260
261#[must_use]
263pub fn state_batch_resource_size(states: &[&State]) -> usize {
264 let handles: Vec<_> = states.iter().map(|state| state.as_ptr()).collect();
265 let handles_ptr = if handles.is_empty() {
266 ptr::null()
267 } else {
268 handles.as_ptr()
269 };
270 unsafe { ffi::mps_state_batch_resource_size(handles_ptr, handles.len()) }
271}
272
273pub fn state_batch_synchronize(states: &[&State], command_buffer: &MetalCommandBuffer) {
275 let handles: Vec<_> = states.iter().map(|state| state.as_ptr()).collect();
276 let handles_ptr = if handles.is_empty() {
277 ptr::null()
278 } else {
279 handles.as_ptr()
280 };
281 unsafe {
282 ffi::mps_state_batch_synchronize(handles_ptr, handles.len(), command_buffer.as_ptr());
283 };
284}