Skip to main content

mtl_gpu/io/
command_queue.rs

1//! IO command queue for Metal.
2
3use std::ffi::c_void;
4use std::ptr::NonNull;
5
6use mtl_foundation::Referencing;
7use mtl_sys::{msg_send_0, msg_send_1, sel};
8
9use super::IOCommandBuffer;
10
11/// Command queue for IO operations.
12///
13/// C++ equivalent: `MTL::IOCommandQueue`
14#[repr(transparent)]
15pub struct IOCommandQueue(pub(crate) NonNull<c_void>);
16
17impl IOCommandQueue {
18    /// Create from a raw pointer.
19    ///
20    /// # Safety
21    ///
22    /// The pointer must be a valid Metal IO command queue.
23    #[inline]
24    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
25        NonNull::new(ptr).map(Self)
26    }
27
28    /// Get the raw pointer.
29    #[inline]
30    pub fn as_raw(&self) -> *mut c_void {
31        self.0.as_ptr()
32    }
33
34    /// Create a command buffer.
35    ///
36    /// C++ equivalent: `IOCommandBuffer* commandBuffer()`
37    pub fn command_buffer(&self) -> Option<IOCommandBuffer> {
38        unsafe {
39            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(commandBuffer));
40            // commandBuffer returns an autoreleased object, so retain it
41            if !ptr.is_null() {
42                let _: *mut c_void = msg_send_0(ptr, sel!(retain));
43            }
44            IOCommandBuffer::from_raw(ptr)
45        }
46    }
47
48    /// Create a command buffer with unretained references.
49    ///
50    /// C++ equivalent: `IOCommandBuffer* commandBufferWithUnretainedReferences()`
51    pub fn command_buffer_with_unretained_references(&self) -> Option<IOCommandBuffer> {
52        unsafe {
53            let ptr: *mut c_void =
54                msg_send_0(self.as_ptr(), sel!(commandBufferWithUnretainedReferences));
55            if !ptr.is_null() {
56                let _: *mut c_void = msg_send_0(ptr, sel!(retain));
57            }
58            IOCommandBuffer::from_raw(ptr)
59        }
60    }
61
62    /// Enqueue a barrier.
63    ///
64    /// C++ equivalent: `void enqueueBarrier()`
65    #[inline]
66    pub fn enqueue_barrier(&self) {
67        unsafe {
68            msg_send_0::<()>(self.as_ptr(), sel!(enqueueBarrier));
69        }
70    }
71
72    /// Get the label.
73    ///
74    /// C++ equivalent: `NS::String* label() const`
75    pub fn label(&self) -> Option<String> {
76        unsafe {
77            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
78            if ptr.is_null() {
79                return None;
80            }
81            let utf8_ptr: *const std::ffi::c_char =
82                mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
83            if utf8_ptr.is_null() {
84                return None;
85            }
86            let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
87            Some(c_str.to_string_lossy().into_owned())
88        }
89    }
90
91    /// Set the label.
92    ///
93    /// C++ equivalent: `void setLabel(const NS::String*)`
94    pub fn set_label(&self, label: &str) {
95        if let Some(ns_label) = mtl_foundation::String::from_str(label) {
96            unsafe {
97                msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(setLabel:), ns_label.as_ptr());
98            }
99        }
100    }
101}
102
103impl Clone for IOCommandQueue {
104    fn clone(&self) -> Self {
105        unsafe {
106            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
107        }
108        Self(self.0)
109    }
110}
111
112impl Drop for IOCommandQueue {
113    fn drop(&mut self) {
114        unsafe {
115            msg_send_0::<()>(self.as_ptr(), sel!(release));
116        }
117    }
118}
119
120impl Referencing for IOCommandQueue {
121    #[inline]
122    fn as_ptr(&self) -> *const c_void {
123        self.0.as_ptr()
124    }
125}
126
127unsafe impl Send for IOCommandQueue {}
128unsafe impl Sync for IOCommandQueue {}