Skip to main content

mtl_gpu/indirect/
buffer.rs

1//! A buffer that stores GPU commands for indirect execution.
2
3use std::ffi::c_void;
4use std::ptr::NonNull;
5
6use mtl_foundation::{Referencing, UInteger};
7use mtl_sys::{msg_send_0, msg_send_1, sel};
8
9use crate::types::ResourceID;
10
11use super::{IndirectComputeCommand, IndirectRenderCommand};
12
13/// A buffer that stores GPU commands for indirect execution.
14///
15/// C++ equivalent: `MTL::IndirectCommandBuffer`
16///
17/// Indirect command buffers are created from a device and can be populated
18/// with commands either from the CPU or from GPU compute shaders.
19#[repr(transparent)]
20pub struct IndirectCommandBuffer(NonNull<c_void>);
21
22impl IndirectCommandBuffer {
23    /// Create from a raw pointer.
24    ///
25    /// # Safety
26    ///
27    /// The pointer must be a valid Metal indirect command buffer.
28    #[inline]
29    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
30        NonNull::new(ptr).map(Self)
31    }
32
33    /// Get the raw pointer.
34    #[inline]
35    pub fn as_raw(&self) -> *mut c_void {
36        self.0.as_ptr()
37    }
38
39    /// Get the number of commands this buffer can hold.
40    ///
41    /// C++ equivalent: `NS::UInteger size() const`
42    #[inline]
43    pub fn size(&self) -> UInteger {
44        unsafe { msg_send_0(self.as_ptr(), sel!(size)) }
45    }
46
47    /// Get the GPU resource ID for bindless access.
48    ///
49    /// C++ equivalent: `ResourceID gpuResourceID() const`
50    #[inline]
51    pub fn gpu_resource_id(&self) -> ResourceID {
52        unsafe { msg_send_0(self.as_ptr(), sel!(gpuResourceID)) }
53    }
54
55    /// Reset commands in the specified range.
56    ///
57    /// C++ equivalent: `void reset(NS::Range)`
58    pub fn reset(&self, location: UInteger, length: UInteger) {
59        unsafe {
60            let range = mtl_foundation::Range::new(location, length);
61            msg_send_1::<(), mtl_foundation::Range>(self.as_ptr(), sel!(resetWithRange:), range);
62        }
63    }
64
65    /// Get an indirect render command at the specified index.
66    ///
67    /// C++ equivalent: `IndirectRenderCommand* indirectRenderCommand(NS::UInteger)`
68    pub fn indirect_render_command(&self, index: UInteger) -> Option<IndirectRenderCommand> {
69        unsafe {
70            let ptr: *mut c_void =
71                msg_send_1(self.as_ptr(), sel!(indirectRenderCommandAtIndex:), index);
72            IndirectRenderCommand::from_raw(ptr)
73        }
74    }
75
76    /// Get an indirect compute command at the specified index.
77    ///
78    /// C++ equivalent: `IndirectComputeCommand* indirectComputeCommand(NS::UInteger)`
79    pub fn indirect_compute_command(&self, index: UInteger) -> Option<IndirectComputeCommand> {
80        unsafe {
81            let ptr: *mut c_void =
82                msg_send_1(self.as_ptr(), sel!(indirectComputeCommandAtIndex:), index);
83            IndirectComputeCommand::from_raw(ptr)
84        }
85    }
86}
87
88impl Clone for IndirectCommandBuffer {
89    fn clone(&self) -> Self {
90        unsafe {
91            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
92        }
93        Self(self.0)
94    }
95}
96
97impl Drop for IndirectCommandBuffer {
98    fn drop(&mut self) {
99        unsafe {
100            msg_send_0::<()>(self.as_ptr(), sel!(release));
101        }
102    }
103}
104
105impl Referencing for IndirectCommandBuffer {
106    #[inline]
107    fn as_ptr(&self) -> *const c_void {
108        self.0.as_ptr()
109    }
110}
111
112unsafe impl Send for IndirectCommandBuffer {}
113unsafe impl Sync for IndirectCommandBuffer {}
114
115impl std::fmt::Debug for IndirectCommandBuffer {
116    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117        f.debug_struct("IndirectCommandBuffer")
118            .field("size", &self.size())
119            .finish()
120    }
121}