Skip to main content

mtl_gpu/mtl4/
render_pass.rs

1//! MTL4 RenderPass implementation.
2//!
3//! Corresponds to `Metal/MTL4RenderPass.hpp`.
4
5use std::ffi::c_void;
6use std::ptr::NonNull;
7
8use mtl_foundation::{Referencing, UInteger};
9use mtl_sys::{msg_send_0, msg_send_1, msg_send_2, sel};
10
11use crate::{
12    Buffer, RenderPassColorAttachmentDescriptorArray, RenderPassDepthAttachmentDescriptor,
13    RenderPassStencilAttachmentDescriptor, SamplePosition, VisibilityResultType,
14};
15
16// ============================================================
17// RenderPassDescriptor
18// ============================================================
19
20/// MTL4 render pass descriptor.
21///
22/// C++ equivalent: `MTL4::RenderPassDescriptor`
23///
24/// RenderPassDescriptor configures a render pass including color, depth,
25/// and stencil attachments, sample positions, and tile dimensions.
26#[repr(transparent)]
27pub struct RenderPassDescriptor(NonNull<c_void>);
28
29impl RenderPassDescriptor {
30    /// Create a RenderPassDescriptor from a raw pointer.
31    #[inline]
32    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
33        NonNull::new(ptr).map(Self)
34    }
35
36    /// Get the raw pointer.
37    #[inline]
38    pub fn as_raw(&self) -> *mut c_void {
39        self.0.as_ptr()
40    }
41
42    /// Create a new render pass descriptor.
43    pub fn new() -> Option<Self> {
44        unsafe {
45            let class = mtl_sys::Class::get("MTL4RenderPassDescriptor")?;
46            let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
47            if ptr.is_null() {
48                return None;
49            }
50            let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
51            Self::from_raw(ptr)
52        }
53    }
54
55    // ========== Color Attachments ==========
56
57    /// Get the color attachments array.
58    ///
59    /// C++ equivalent: `MTL::RenderPassColorAttachmentDescriptorArray* colorAttachments() const`
60    pub fn color_attachments(&self) -> Option<RenderPassColorAttachmentDescriptorArray> {
61        unsafe {
62            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(colorAttachments));
63            RenderPassColorAttachmentDescriptorArray::from_raw(ptr)
64        }
65    }
66
67    // ========== Depth Attachment ==========
68
69    /// Get the depth attachment.
70    ///
71    /// C++ equivalent: `MTL::RenderPassDepthAttachmentDescriptor* depthAttachment() const`
72    pub fn depth_attachment(&self) -> Option<RenderPassDepthAttachmentDescriptor> {
73        unsafe {
74            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(depthAttachment));
75            RenderPassDepthAttachmentDescriptor::from_raw(ptr)
76        }
77    }
78
79    /// Set the depth attachment.
80    ///
81    /// C++ equivalent: `void setDepthAttachment(const MTL::RenderPassDepthAttachmentDescriptor*)`
82    pub fn set_depth_attachment(&self, attachment: &RenderPassDepthAttachmentDescriptor) {
83        unsafe {
84            let _: () = msg_send_1(
85                self.as_ptr(),
86                sel!(setDepthAttachment:),
87                attachment.as_ptr(),
88            );
89        }
90    }
91
92    // ========== Stencil Attachment ==========
93
94    /// Get the stencil attachment.
95    ///
96    /// C++ equivalent: `MTL::RenderPassStencilAttachmentDescriptor* stencilAttachment() const`
97    pub fn stencil_attachment(&self) -> Option<RenderPassStencilAttachmentDescriptor> {
98        unsafe {
99            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(stencilAttachment));
100            RenderPassStencilAttachmentDescriptor::from_raw(ptr)
101        }
102    }
103
104    /// Set the stencil attachment.
105    ///
106    /// C++ equivalent: `void setStencilAttachment(const MTL::RenderPassStencilAttachmentDescriptor*)`
107    pub fn set_stencil_attachment(&self, attachment: &RenderPassStencilAttachmentDescriptor) {
108        unsafe {
109            let _: () = msg_send_1(
110                self.as_ptr(),
111                sel!(setStencilAttachment:),
112                attachment.as_ptr(),
113            );
114        }
115    }
116
117    // ========== Render Target Dimensions ==========
118
119    /// Get the render target width.
120    ///
121    /// C++ equivalent: `NS::UInteger renderTargetWidth() const`
122    pub fn render_target_width(&self) -> UInteger {
123        unsafe { msg_send_0(self.as_ptr(), sel!(renderTargetWidth)) }
124    }
125
126    /// Set the render target width.
127    ///
128    /// C++ equivalent: `void setRenderTargetWidth(NS::UInteger)`
129    pub fn set_render_target_width(&self, width: UInteger) {
130        unsafe {
131            let _: () = msg_send_1(self.as_ptr(), sel!(setRenderTargetWidth:), width);
132        }
133    }
134
135    /// Get the render target height.
136    ///
137    /// C++ equivalent: `NS::UInteger renderTargetHeight() const`
138    pub fn render_target_height(&self) -> UInteger {
139        unsafe { msg_send_0(self.as_ptr(), sel!(renderTargetHeight)) }
140    }
141
142    /// Set the render target height.
143    ///
144    /// C++ equivalent: `void setRenderTargetHeight(NS::UInteger)`
145    pub fn set_render_target_height(&self, height: UInteger) {
146        unsafe {
147            let _: () = msg_send_1(self.as_ptr(), sel!(setRenderTargetHeight:), height);
148        }
149    }
150
151    /// Get the render target array length.
152    ///
153    /// C++ equivalent: `NS::UInteger renderTargetArrayLength() const`
154    pub fn render_target_array_length(&self) -> UInteger {
155        unsafe { msg_send_0(self.as_ptr(), sel!(renderTargetArrayLength)) }
156    }
157
158    /// Set the render target array length.
159    ///
160    /// C++ equivalent: `void setRenderTargetArrayLength(NS::UInteger)`
161    pub fn set_render_target_array_length(&self, length: UInteger) {
162        unsafe {
163            let _: () = msg_send_1(self.as_ptr(), sel!(setRenderTargetArrayLength:), length);
164        }
165    }
166
167    // ========== Sample Count ==========
168
169    /// Get the default raster sample count.
170    ///
171    /// C++ equivalent: `NS::UInteger defaultRasterSampleCount() const`
172    pub fn default_raster_sample_count(&self) -> UInteger {
173        unsafe { msg_send_0(self.as_ptr(), sel!(defaultRasterSampleCount)) }
174    }
175
176    /// Set the default raster sample count.
177    ///
178    /// C++ equivalent: `void setDefaultRasterSampleCount(NS::UInteger)`
179    pub fn set_default_raster_sample_count(&self, count: UInteger) {
180        unsafe {
181            let _: () = msg_send_1(self.as_ptr(), sel!(setDefaultRasterSampleCount:), count);
182        }
183    }
184
185    // ========== Sample Positions ==========
186
187    /// Get sample positions.
188    ///
189    /// C++ equivalent: `NS::UInteger getSamplePositions(MTL::SamplePosition*, NS::UInteger)`
190    pub fn get_sample_positions(&self, positions: &mut [SamplePosition]) -> UInteger {
191        unsafe {
192            msg_send_2(
193                self.as_ptr(),
194                sel!(getSamplePositions:count:),
195                positions.as_mut_ptr(),
196                positions.len() as UInteger,
197            )
198        }
199    }
200
201    /// Set sample positions.
202    ///
203    /// C++ equivalent: `void setSamplePositions(const MTL::SamplePosition*, NS::UInteger)`
204    pub fn set_sample_positions(&self, positions: &[SamplePosition]) {
205        unsafe {
206            let _: () = msg_send_2(
207                self.as_ptr(),
208                sel!(setSamplePositions:count:),
209                positions.as_ptr(),
210                positions.len() as UInteger,
211            );
212        }
213    }
214
215    // ========== Tile Dimensions ==========
216
217    /// Get the tile width.
218    ///
219    /// C++ equivalent: `NS::UInteger tileWidth() const`
220    pub fn tile_width(&self) -> UInteger {
221        unsafe { msg_send_0(self.as_ptr(), sel!(tileWidth)) }
222    }
223
224    /// Set the tile width.
225    ///
226    /// C++ equivalent: `void setTileWidth(NS::UInteger)`
227    pub fn set_tile_width(&self, width: UInteger) {
228        unsafe {
229            let _: () = msg_send_1(self.as_ptr(), sel!(setTileWidth:), width);
230        }
231    }
232
233    /// Get the tile height.
234    ///
235    /// C++ equivalent: `NS::UInteger tileHeight() const`
236    pub fn tile_height(&self) -> UInteger {
237        unsafe { msg_send_0(self.as_ptr(), sel!(tileHeight)) }
238    }
239
240    /// Set the tile height.
241    ///
242    /// C++ equivalent: `void setTileHeight(NS::UInteger)`
243    pub fn set_tile_height(&self, height: UInteger) {
244        unsafe {
245            let _: () = msg_send_1(self.as_ptr(), sel!(setTileHeight:), height);
246        }
247    }
248
249    // ========== Threadgroup Memory ==========
250
251    /// Get the threadgroup memory length.
252    ///
253    /// C++ equivalent: `NS::UInteger threadgroupMemoryLength() const`
254    pub fn threadgroup_memory_length(&self) -> UInteger {
255        unsafe { msg_send_0(self.as_ptr(), sel!(threadgroupMemoryLength)) }
256    }
257
258    /// Set the threadgroup memory length.
259    ///
260    /// C++ equivalent: `void setThreadgroupMemoryLength(NS::UInteger)`
261    pub fn set_threadgroup_memory_length(&self, length: UInteger) {
262        unsafe {
263            let _: () = msg_send_1(self.as_ptr(), sel!(setThreadgroupMemoryLength:), length);
264        }
265    }
266
267    // ========== Imageblock ==========
268
269    /// Get the imageblock sample length.
270    ///
271    /// C++ equivalent: `NS::UInteger imageblockSampleLength() const`
272    pub fn imageblock_sample_length(&self) -> UInteger {
273        unsafe { msg_send_0(self.as_ptr(), sel!(imageblockSampleLength)) }
274    }
275
276    /// Set the imageblock sample length.
277    ///
278    /// C++ equivalent: `void setImageblockSampleLength(NS::UInteger)`
279    pub fn set_imageblock_sample_length(&self, length: UInteger) {
280        unsafe {
281            let _: () = msg_send_1(self.as_ptr(), sel!(setImageblockSampleLength:), length);
282        }
283    }
284
285    // ========== Rasterization Rate Map ==========
286
287    /// Get the rasterization rate map (as raw pointer).
288    ///
289    /// C++ equivalent: `MTL::RasterizationRateMap* rasterizationRateMap() const`
290    pub fn rasterization_rate_map_raw(&self) -> *mut c_void {
291        unsafe { msg_send_0(self.as_ptr(), sel!(rasterizationRateMap)) }
292    }
293
294    /// Set the rasterization rate map (from raw pointer).
295    ///
296    /// C++ equivalent: `void setRasterizationRateMap(const MTL::RasterizationRateMap*)`
297    pub fn set_rasterization_rate_map_raw(&self, map: *const c_void) {
298        unsafe {
299            let _: () = msg_send_1(self.as_ptr(), sel!(setRasterizationRateMap:), map);
300        }
301    }
302
303    // ========== Visibility Result ==========
304
305    /// Get the visibility result buffer.
306    ///
307    /// C++ equivalent: `MTL::Buffer* visibilityResultBuffer() const`
308    pub fn visibility_result_buffer(&self) -> Option<Buffer> {
309        unsafe {
310            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(visibilityResultBuffer));
311            Buffer::from_raw(ptr)
312        }
313    }
314
315    /// Set the visibility result buffer.
316    ///
317    /// C++ equivalent: `void setVisibilityResultBuffer(const MTL::Buffer*)`
318    pub fn set_visibility_result_buffer(&self, buffer: &Buffer) {
319        unsafe {
320            let _: () = msg_send_1(
321                self.as_ptr(),
322                sel!(setVisibilityResultBuffer:),
323                buffer.as_ptr(),
324            );
325        }
326    }
327
328    /// Get the visibility result type.
329    ///
330    /// C++ equivalent: `MTL::VisibilityResultType visibilityResultType() const`
331    pub fn visibility_result_type(&self) -> VisibilityResultType {
332        unsafe { msg_send_0(self.as_ptr(), sel!(visibilityResultType)) }
333    }
334
335    /// Set the visibility result type.
336    ///
337    /// C++ equivalent: `void setVisibilityResultType(MTL::VisibilityResultType)`
338    pub fn set_visibility_result_type(&self, result_type: VisibilityResultType) {
339        unsafe {
340            let _: () = msg_send_1(self.as_ptr(), sel!(setVisibilityResultType:), result_type);
341        }
342    }
343
344    // ========== Color Attachment Mapping ==========
345
346    /// Check if color attachment mapping is supported.
347    ///
348    /// C++ equivalent: `bool supportColorAttachmentMapping() const`
349    pub fn support_color_attachment_mapping(&self) -> bool {
350        unsafe { msg_send_0(self.as_ptr(), sel!(supportColorAttachmentMapping)) }
351    }
352
353    /// Set whether color attachment mapping is supported.
354    ///
355    /// C++ equivalent: `void setSupportColorAttachmentMapping(bool)`
356    pub fn set_support_color_attachment_mapping(&self, support: bool) {
357        unsafe {
358            let _: () = msg_send_1(
359                self.as_ptr(),
360                sel!(setSupportColorAttachmentMapping:),
361                support,
362            );
363        }
364    }
365}
366
367impl Default for RenderPassDescriptor {
368    fn default() -> Self {
369        Self::new().expect("Failed to create MTL4RenderPassDescriptor")
370    }
371}
372
373impl Clone for RenderPassDescriptor {
374    fn clone(&self) -> Self {
375        unsafe {
376            mtl_sys::msg_send_0::<*mut c_void>(self.as_ptr(), mtl_sys::sel!(retain));
377        }
378        Self(self.0)
379    }
380}
381
382impl Drop for RenderPassDescriptor {
383    fn drop(&mut self) {
384        unsafe {
385            mtl_sys::msg_send_0::<()>(self.as_ptr(), mtl_sys::sel!(release));
386        }
387    }
388}
389
390impl Referencing for RenderPassDescriptor {
391    #[inline]
392    fn as_ptr(&self) -> *const c_void {
393        self.0.as_ptr()
394    }
395}
396
397unsafe impl Send for RenderPassDescriptor {}
398unsafe impl Sync for RenderPassDescriptor {}
399
400impl std::fmt::Debug for RenderPassDescriptor {
401    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
402        f.debug_struct("RenderPassDescriptor")
403            .field("render_target_width", &self.render_target_width())
404            .field("render_target_height", &self.render_target_height())
405            .field("tile_width", &self.tile_width())
406            .field("tile_height", &self.tile_height())
407            .finish()
408    }
409}
410
411#[cfg(test)]
412mod tests {
413    use super::*;
414
415    #[test]
416    fn test_render_pass_descriptor_size() {
417        assert_eq!(
418            std::mem::size_of::<RenderPassDescriptor>(),
419            std::mem::size_of::<*mut c_void>()
420        );
421    }
422}