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