Skip to main content

apple_mps/
state.rs

1use crate::ffi;
2use apple_metal::{CommandBuffer as MetalCommandBuffer, MetalDevice};
3use core::ffi::c_void;
4use core::ptr;
5
6/// `MPSStateResourceType` constants.
7pub 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/// Plain-Rust view of `MPSStateTextureInfo`.
14#[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}