1use std::ffi::c_void;
6use std::ptr::NonNull;
7
8use mtl_foundation::{Referencing, UInteger};
9use mtl_sys::{msg_send_0, msg_send_1, sel};
10
11use crate::Buffer;
12use crate::Texture;
13use crate::enums::SparseTextureMappingMode;
14use crate::sync::Fence;
15use crate::types::{Origin, Region, Size};
16
17#[repr(C, packed)]
21#[derive(Copy, Clone, Debug, Default)]
22pub struct MapIndirectArguments {
23 pub region_origin_x: u32,
25 pub region_origin_y: u32,
27 pub region_origin_z: u32,
29 pub region_size_width: u32,
31 pub region_size_height: u32,
33 pub region_size_depth: u32,
35 pub mip_map_level: u32,
37 pub slice_id: u32,
39}
40
41#[repr(transparent)]
48pub struct ResourceStateCommandEncoder(pub(crate) NonNull<c_void>);
49
50impl ResourceStateCommandEncoder {
51 #[inline]
57 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
58 NonNull::new(ptr).map(Self)
59 }
60
61 #[inline]
63 pub fn as_raw(&self) -> *mut c_void {
64 self.0.as_ptr()
65 }
66
67 pub fn device(&self) -> crate::Device {
75 unsafe {
76 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(device));
77 let _: *mut c_void = msg_send_0(ptr, sel!(retain));
78 crate::Device::from_raw(ptr).expect("encoder has no device")
79 }
80 }
81
82 pub fn command_buffer(&self) -> crate::CommandBuffer {
86 unsafe {
87 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(commandBuffer));
88 let _: *mut c_void = msg_send_0(ptr, sel!(retain));
89 crate::CommandBuffer::from_raw(ptr).expect("encoder has no command buffer")
90 }
91 }
92
93 pub fn label(&self) -> Option<String> {
97 unsafe {
98 let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
99 if ptr.is_null() {
100 return None;
101 }
102 let utf8_ptr: *const std::ffi::c_char =
103 mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
104 if utf8_ptr.is_null() {
105 return None;
106 }
107 let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
108 Some(c_str.to_string_lossy().into_owned())
109 }
110 }
111
112 pub fn set_label(&self, label: &str) {
116 if let Some(ns_label) = mtl_foundation::String::from_str(label) {
117 unsafe {
118 msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(setLabel:), ns_label.as_ptr());
119 }
120 }
121 }
122
123 #[inline]
127 pub fn end_encoding(&self) {
128 unsafe {
129 msg_send_0::<()>(self.as_ptr(), sel!(endEncoding));
130 }
131 }
132
133 pub fn insert_debug_signpost(&self, string: &str) {
137 if let Some(ns_string) = mtl_foundation::String::from_str(string) {
138 unsafe {
139 msg_send_1::<(), *const c_void>(
140 self.as_ptr(),
141 sel!(insertDebugSignpost:),
142 ns_string.as_ptr(),
143 );
144 }
145 }
146 }
147
148 pub fn push_debug_group(&self, string: &str) {
152 if let Some(ns_string) = mtl_foundation::String::from_str(string) {
153 unsafe {
154 msg_send_1::<(), *const c_void>(
155 self.as_ptr(),
156 sel!(pushDebugGroup:),
157 ns_string.as_ptr(),
158 );
159 }
160 }
161 }
162
163 #[inline]
167 pub fn pop_debug_group(&self) {
168 unsafe {
169 msg_send_0::<()>(self.as_ptr(), sel!(popDebugGroup));
170 }
171 }
172
173 #[inline]
177 pub fn barrier_after_queue_stages(
178 &self,
179 after_stages: crate::enums::Stages,
180 before_stages: crate::enums::Stages,
181 ) {
182 unsafe {
183 mtl_sys::msg_send_2::<(), crate::enums::Stages, crate::enums::Stages>(
184 self.as_ptr(),
185 sel!(barrierAfterQueueStages:beforeQueueStages:),
186 after_stages,
187 before_stages,
188 );
189 }
190 }
191
192 pub fn update_texture_mapping(
200 &self,
201 texture: &Texture,
202 mode: SparseTextureMappingMode,
203 region: Region,
204 mip_level: UInteger,
205 slice: UInteger,
206 ) {
207 unsafe {
208 mtl_sys::msg_send_5::<
209 (),
210 *const c_void,
211 SparseTextureMappingMode,
212 Region,
213 UInteger,
214 UInteger,
215 >(
216 self.as_ptr(),
217 sel!(updateTextureMapping: mode: region: mipLevel: slice:),
218 texture.as_ptr(),
219 mode,
220 region,
221 mip_level,
222 slice,
223 );
224 }
225 }
226
227 pub fn update_texture_mapping_indirect(
231 &self,
232 texture: &Texture,
233 mode: SparseTextureMappingMode,
234 indirect_buffer: &Buffer,
235 indirect_buffer_offset: UInteger,
236 ) {
237 unsafe {
238 mtl_sys::msg_send_4::<
239 (),
240 *const c_void,
241 SparseTextureMappingMode,
242 *const c_void,
243 UInteger,
244 >(
245 self.as_ptr(),
246 sel!(updateTextureMapping: mode: indirectBuffer: indirectBufferOffset:),
247 texture.as_ptr(),
248 mode,
249 indirect_buffer.as_ptr(),
250 indirect_buffer_offset,
251 );
252 }
253 }
254
255 pub unsafe fn update_texture_mappings(
263 &self,
264 texture: &Texture,
265 mode: SparseTextureMappingMode,
266 regions: *const Region,
267 mip_levels: *const UInteger,
268 slices: *const UInteger,
269 num_regions: UInteger,
270 ) {
271 unsafe {
272 mtl_sys::msg_send_6::<
273 (),
274 *const c_void,
275 SparseTextureMappingMode,
276 *const Region,
277 *const UInteger,
278 *const UInteger,
279 UInteger,
280 >(
281 self.as_ptr(),
282 sel!(updateTextureMappings: mode: regions: mipLevels: slices: numRegions:),
283 texture.as_ptr(),
284 mode,
285 regions,
286 mip_levels,
287 slices,
288 num_regions,
289 );
290 }
291 }
292
293 #[allow(clippy::too_many_arguments)]
297 pub fn move_texture_mappings_from_texture(
298 &self,
299 source_texture: &Texture,
300 source_slice: UInteger,
301 source_level: UInteger,
302 source_origin: Origin,
303 source_size: Size,
304 destination_texture: &Texture,
305 destination_slice: UInteger,
306 destination_level: UInteger,
307 destination_origin: Origin,
308 ) {
309 unsafe {
310 mtl_sys::msg_send_9::<
311 (),
312 *const c_void,
313 UInteger,
314 UInteger,
315 Origin,
316 Size,
317 *const c_void,
318 UInteger,
319 UInteger,
320 Origin,
321 >(
322 self.as_ptr(),
323 sel!(moveTextureMappingsFromTexture: sourceSlice: sourceLevel: sourceOrigin: sourceSize: toTexture: destinationSlice: destinationLevel: destinationOrigin:),
324 source_texture.as_ptr(),
325 source_slice,
326 source_level,
327 source_origin,
328 source_size,
329 destination_texture.as_ptr(),
330 destination_slice,
331 destination_level,
332 destination_origin,
333 );
334 }
335 }
336
337 #[inline]
345 pub fn update_fence(&self, fence: &Fence) {
346 unsafe {
347 msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(updateFence:), fence.as_ptr());
348 }
349 }
350
351 #[inline]
355 pub fn wait_for_fence(&self, fence: &Fence) {
356 unsafe {
357 msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(waitForFence:), fence.as_ptr());
358 }
359 }
360}
361
362impl Clone for ResourceStateCommandEncoder {
363 fn clone(&self) -> Self {
364 unsafe {
365 msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
366 }
367 Self(self.0)
368 }
369}
370
371impl Drop for ResourceStateCommandEncoder {
372 fn drop(&mut self) {
373 unsafe {
374 msg_send_0::<()>(self.as_ptr(), sel!(release));
375 }
376 }
377}
378
379impl Referencing for ResourceStateCommandEncoder {
380 #[inline]
381 fn as_ptr(&self) -> *const c_void {
382 self.0.as_ptr()
383 }
384}
385
386unsafe impl Send for ResourceStateCommandEncoder {}
387unsafe impl Sync for ResourceStateCommandEncoder {}
388
389impl std::fmt::Debug for ResourceStateCommandEncoder {
390 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
391 f.debug_struct("ResourceStateCommandEncoder")
392 .field("label", &self.label())
393 .finish()
394 }
395}
396
397#[cfg(test)]
398mod tests {
399 use super::*;
400
401 #[test]
402 fn test_resource_state_encoder_size() {
403 assert_eq!(
404 std::mem::size_of::<ResourceStateCommandEncoder>(),
405 std::mem::size_of::<*mut c_void>()
406 );
407 }
408
409 #[test]
410 fn test_map_indirect_arguments_size() {
411 assert_eq!(std::mem::size_of::<MapIndirectArguments>(), 32);
413 }
414}