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;
9 pub const BUFFER: usize = 1;
10 pub const TEXTURE: usize = 2;
11}
12
13#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
15pub struct StateTextureInfo {
16 pub width: usize,
17 pub height: usize,
18 pub depth: usize,
19 pub array_length: usize,
20 pub pixel_format: usize,
21 pub texture_type: usize,
22 pub usage: usize,
23}
24
25macro_rules! opaque_handle {
26 ($name:ident) => {
27 pub struct $name {
28 ptr: *mut c_void,
29 }
30
31 unsafe impl Send for $name {}
33 unsafe impl Sync for $name {}
35
36 impl Drop for $name {
37 fn drop(&mut self) {
38 if !self.ptr.is_null() {
39 unsafe { ffi::mps_object_release(self.ptr) };
41 self.ptr = ptr::null_mut();
42 }
43 }
44 }
45
46 impl $name {
47 #[must_use]
48 pub const fn as_ptr(&self) -> *mut c_void {
49 self.ptr
50 }
51 }
52 };
53}
54
55opaque_handle!(StateResourceList);
56impl StateResourceList {
57 #[must_use]
58 pub fn new() -> Option<Self> {
59 let ptr = unsafe { ffi::mps_state_resource_list_new() };
61 if ptr.is_null() {
62 None
63 } else {
64 Some(Self { ptr })
65 }
66 }
67
68 pub fn append_buffer(&self, size: usize) {
69 unsafe { ffi::mps_state_resource_list_append_buffer(self.ptr, size) };
71 }
72}
73
74opaque_handle!(State);
75impl State {
76 #[must_use]
77 pub fn temporary(command_buffer: &MetalCommandBuffer) -> Option<Self> {
78 let ptr = unsafe { ffi::mps_state_temporary_new(command_buffer.as_ptr()) };
80 if ptr.is_null() {
81 None
82 } else {
83 Some(Self { ptr })
84 }
85 }
86
87 #[must_use]
88 pub fn temporary_with_buffer_size(
89 command_buffer: &MetalCommandBuffer,
90 buffer_size: usize,
91 ) -> Option<Self> {
92 let ptr = unsafe {
93 ffi::mps_state_temporary_new_with_buffer_size(command_buffer.as_ptr(), buffer_size)
94 };
95 if ptr.is_null() {
96 None
97 } else {
98 Some(Self { ptr })
99 }
100 }
101
102 #[must_use]
103 pub fn new_with_buffer_size(device: &MetalDevice, buffer_size: usize) -> Option<Self> {
104 let ptr = unsafe { ffi::mps_state_new_with_buffer_size(device.as_ptr(), buffer_size) };
106 if ptr.is_null() {
107 None
108 } else {
109 Some(Self { ptr })
110 }
111 }
112
113 #[must_use]
114 pub fn new_with_resource_list(
115 device: &MetalDevice,
116 resource_list: &StateResourceList,
117 ) -> Option<Self> {
118 let ptr = unsafe {
119 ffi::mps_state_new_with_resource_list(device.as_ptr(), resource_list.as_ptr())
120 };
121 if ptr.is_null() {
122 None
123 } else {
124 Some(Self { ptr })
125 }
126 }
127
128 #[must_use]
129 pub fn temporary_with_resource_list(
130 command_buffer: &MetalCommandBuffer,
131 resource_list: &StateResourceList,
132 ) -> Option<Self> {
133 let ptr = unsafe {
134 ffi::mps_state_temporary_new_with_resource_list(
135 command_buffer.as_ptr(),
136 resource_list.as_ptr(),
137 )
138 };
139 if ptr.is_null() {
140 None
141 } else {
142 Some(Self { ptr })
143 }
144 }
145
146 #[must_use]
147 pub fn resource_count(&self) -> usize {
148 unsafe { ffi::mps_state_resource_count(self.ptr) }
150 }
151
152 #[must_use]
153 pub fn read_count(&self) -> usize {
154 unsafe { ffi::mps_state_read_count(self.ptr) }
156 }
157
158 pub fn set_read_count(&self, count: usize) {
159 unsafe { ffi::mps_state_set_read_count(self.ptr, count) };
161 }
162
163 #[must_use]
164 pub fn is_temporary(&self) -> bool {
165 unsafe { ffi::mps_state_is_temporary(self.ptr) }
166 }
167
168 #[must_use]
169 pub fn buffer_size_at_index(&self, index: usize) -> usize {
170 unsafe { ffi::mps_state_buffer_size_at_index(self.ptr, index) }
171 }
172
173 #[must_use]
174 pub fn texture_info_at_index(&self, index: usize) -> StateTextureInfo {
175 let mut width = 0;
176 let mut height = 0;
177 let mut depth = 0;
178 let mut array_length = 0;
179 let mut pixel_format = 0;
180 let mut texture_type = 0;
181 let mut usage = 0;
182 unsafe {
183 ffi::mps_state_texture_info(
184 self.ptr,
185 index,
186 &mut width,
187 &mut height,
188 &mut depth,
189 &mut array_length,
190 &mut pixel_format,
191 &mut texture_type,
192 &mut usage,
193 );
194 };
195 StateTextureInfo {
196 width,
197 height,
198 depth,
199 array_length,
200 pixel_format,
201 texture_type,
202 usage,
203 }
204 }
205
206 #[must_use]
207 pub fn resource_type_at_index(&self, index: usize) -> usize {
208 unsafe { ffi::mps_state_resource_type_at_index(self.ptr, index) }
209 }
210
211 pub fn synchronize_on_command_buffer(&self, command_buffer: &MetalCommandBuffer) {
212 unsafe { ffi::mps_state_synchronize_on_command_buffer(self.ptr, command_buffer.as_ptr()) };
213 }
214
215 #[must_use]
216 pub fn resource_size(&self) -> usize {
217 unsafe { ffi::mps_state_resource_size(self.ptr) }
218 }
219}
220
221#[must_use]
222pub fn state_batch_increment_read_count(states: &[&State], amount: isize) -> usize {
223 let handles: Vec<_> = states.iter().map(|state| state.as_ptr()).collect();
224 let handles_ptr = if handles.is_empty() {
225 ptr::null()
226 } else {
227 handles.as_ptr()
228 };
229 unsafe { ffi::mps_state_batch_increment_read_count(handles_ptr, handles.len(), amount) }
230}
231
232#[must_use]
233pub fn state_batch_resource_size(states: &[&State]) -> usize {
234 let handles: Vec<_> = states.iter().map(|state| state.as_ptr()).collect();
235 let handles_ptr = if handles.is_empty() {
236 ptr::null()
237 } else {
238 handles.as_ptr()
239 };
240 unsafe { ffi::mps_state_batch_resource_size(handles_ptr, handles.len()) }
241}
242
243pub fn state_batch_synchronize(states: &[&State], command_buffer: &MetalCommandBuffer) {
244 let handles: Vec<_> = states.iter().map(|state| state.as_ptr()).collect();
245 let handles_ptr = if handles.is_empty() {
246 ptr::null()
247 } else {
248 handles.as_ptr()
249 };
250 unsafe {
251 ffi::mps_state_batch_synchronize(handles_ptr, handles.len(), command_buffer.as_ptr());
252 };
253}