Skip to main content

mtl_gpu/mtl4/
render_command_encoder.rs

1//! MTL4 RenderCommandEncoder implementation.
2//!
3//! Corresponds to `Metal/MTL4RenderCommandEncoder.hpp`.
4
5use std::ffi::c_void;
6use std::ptr::NonNull;
7
8use mtl_foundation::{Referencing, UInteger};
9use mtl_sys::{
10    msg_send_0, msg_send_1, msg_send_2, msg_send_3, msg_send_4, msg_send_5, msg_send_6, sel,
11};
12
13use super::enums::VisibilityOptions;
14use crate::{
15    CullMode, DepthClipMode, DepthStencilState, Device, PrimitiveType, RenderPipelineState,
16    RenderStages, ScissorRect, Size, TriangleFillMode, Viewport, Winding,
17};
18
19// ============================================================
20// RenderCommandEncoder
21// ============================================================
22
23/// MTL4 render command encoder.
24///
25/// C++ equivalent: `MTL4::RenderCommandEncoder`
26///
27/// RenderCommandEncoder encodes render commands including draw calls,
28/// state changes, and resource bindings.
29#[repr(transparent)]
30pub struct RenderCommandEncoder(NonNull<c_void>);
31
32impl RenderCommandEncoder {
33    /// Create a RenderCommandEncoder from a raw pointer.
34    #[inline]
35    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
36        NonNull::new(ptr).map(Self)
37    }
38
39    /// Get the raw pointer.
40    #[inline]
41    pub fn as_raw(&self) -> *mut c_void {
42        self.0.as_ptr()
43    }
44
45    /// Get the device.
46    ///
47    /// C++ equivalent: `MTL::Device* device() const`
48    pub fn device(&self) -> Option<Device> {
49        unsafe {
50            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(device));
51            Device::from_raw(ptr)
52        }
53    }
54
55    /// Get the label.
56    ///
57    /// C++ equivalent: `NS::String* label() const`
58    pub fn label(&self) -> Option<String> {
59        unsafe {
60            let ns_string: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
61            if ns_string.is_null() {
62                return None;
63            }
64            let c_str: *const i8 = msg_send_0(ns_string, sel!(UTF8String));
65            if c_str.is_null() {
66                return None;
67            }
68            Some(
69                std::ffi::CStr::from_ptr(c_str)
70                    .to_string_lossy()
71                    .into_owned(),
72            )
73        }
74    }
75
76    /// Set the label.
77    ///
78    /// C++ equivalent: `void setLabel(const NS::String*)`
79    pub fn set_label(&self, label: &str) {
80        if let Some(ns_label) = mtl_foundation::String::from_str(label) {
81            unsafe {
82                let _: () = msg_send_1(self.as_ptr(), sel!(setLabel:), ns_label.as_ptr());
83            }
84        }
85    }
86
87    // ========== Pipeline State ==========
88
89    /// Set the render pipeline state.
90    ///
91    /// C++ equivalent: `void setRenderPipelineState(const MTL::RenderPipelineState*)`
92    pub fn set_render_pipeline_state(&self, pipeline: &RenderPipelineState) {
93        unsafe {
94            let _: () = msg_send_1(
95                self.as_ptr(),
96                sel!(setRenderPipelineState:),
97                pipeline.as_ptr(),
98            );
99        }
100    }
101
102    // ========== Argument Table ==========
103
104    /// Set vertex argument table at index.
105    ///
106    /// C++ equivalent: `void setVertexArgumentTable(const MTL4::ArgumentTable*, NS::UInteger)`
107    pub fn set_vertex_argument_table(&self, table: *const c_void, index: UInteger) {
108        unsafe {
109            let _: () = msg_send_2(
110                self.as_ptr(),
111                sel!(setVertexArgumentTable:atIndex:),
112                table,
113                index,
114            );
115        }
116    }
117
118    /// Set fragment argument table at index.
119    ///
120    /// C++ equivalent: `void setFragmentArgumentTable(const MTL4::ArgumentTable*, NS::UInteger)`
121    pub fn set_fragment_argument_table(&self, table: *const c_void, index: UInteger) {
122        unsafe {
123            let _: () = msg_send_2(
124                self.as_ptr(),
125                sel!(setFragmentArgumentTable:atIndex:),
126                table,
127                index,
128            );
129        }
130    }
131
132    /// Set tile argument table at index.
133    ///
134    /// C++ equivalent: `void setTileArgumentTable(const MTL4::ArgumentTable*, NS::UInteger)`
135    pub fn set_tile_argument_table(&self, table: *const c_void, index: UInteger) {
136        unsafe {
137            let _: () = msg_send_2(
138                self.as_ptr(),
139                sel!(setTileArgumentTable:atIndex:),
140                table,
141                index,
142            );
143        }
144    }
145
146    /// Set object argument table at index.
147    ///
148    /// C++ equivalent: `void setObjectArgumentTable(const MTL4::ArgumentTable*, NS::UInteger)`
149    pub fn set_object_argument_table(&self, table: *const c_void, index: UInteger) {
150        unsafe {
151            let _: () = msg_send_2(
152                self.as_ptr(),
153                sel!(setObjectArgumentTable:atIndex:),
154                table,
155                index,
156            );
157        }
158    }
159
160    /// Set mesh argument table at index.
161    ///
162    /// C++ equivalent: `void setMeshArgumentTable(const MTL4::ArgumentTable*, NS::UInteger)`
163    pub fn set_mesh_argument_table(&self, table: *const c_void, index: UInteger) {
164        unsafe {
165            let _: () = msg_send_2(
166                self.as_ptr(),
167                sel!(setMeshArgumentTable:atIndex:),
168                table,
169                index,
170            );
171        }
172    }
173
174    // ========== Vertex Buffer Binding ==========
175
176    /// Set vertex buffer at index.
177    ///
178    /// C++ equivalent: `void setVertexBuffer(const MTL::Buffer*, NS::UInteger, NS::UInteger)`
179    pub fn set_vertex_buffer(&self, buffer: *const c_void, offset: UInteger, index: UInteger) {
180        unsafe {
181            let _: () = msg_send_3(
182                self.as_ptr(),
183                sel!(setVertexBuffer:offset:atIndex:),
184                buffer,
185                offset,
186                index,
187            );
188        }
189    }
190
191    /// Set vertex bytes at index.
192    ///
193    /// C++ equivalent: `void setVertexBytes(const void*, NS::UInteger, NS::UInteger)`
194    pub fn set_vertex_bytes(&self, bytes: *const c_void, length: UInteger, index: UInteger) {
195        unsafe {
196            let _: () = msg_send_3(
197                self.as_ptr(),
198                sel!(setVertexBytes:length:atIndex:),
199                bytes,
200                length,
201                index,
202            );
203        }
204    }
205
206    /// Set vertex texture at index.
207    ///
208    /// C++ equivalent: `void setVertexTexture(const MTL::Texture*, NS::UInteger)`
209    pub fn set_vertex_texture(&self, texture: *const c_void, index: UInteger) {
210        unsafe {
211            let _: () = msg_send_2(
212                self.as_ptr(),
213                sel!(setVertexTexture:atIndex:),
214                texture,
215                index,
216            );
217        }
218    }
219
220    /// Set vertex sampler state at index.
221    ///
222    /// C++ equivalent: `void setVertexSamplerState(const MTL::SamplerState*, NS::UInteger)`
223    pub fn set_vertex_sampler_state(&self, sampler: *const c_void, index: UInteger) {
224        unsafe {
225            let _: () = msg_send_2(
226                self.as_ptr(),
227                sel!(setVertexSamplerState:atIndex:),
228                sampler,
229                index,
230            );
231        }
232    }
233
234    // ========== Fragment Buffer Binding ==========
235
236    /// Set fragment buffer at index.
237    ///
238    /// C++ equivalent: `void setFragmentBuffer(const MTL::Buffer*, NS::UInteger, NS::UInteger)`
239    pub fn set_fragment_buffer(&self, buffer: *const c_void, offset: UInteger, index: UInteger) {
240        unsafe {
241            let _: () = msg_send_3(
242                self.as_ptr(),
243                sel!(setFragmentBuffer:offset:atIndex:),
244                buffer,
245                offset,
246                index,
247            );
248        }
249    }
250
251    /// Set fragment bytes at index.
252    ///
253    /// C++ equivalent: `void setFragmentBytes(const void*, NS::UInteger, NS::UInteger)`
254    pub fn set_fragment_bytes(&self, bytes: *const c_void, length: UInteger, index: UInteger) {
255        unsafe {
256            let _: () = msg_send_3(
257                self.as_ptr(),
258                sel!(setFragmentBytes:length:atIndex:),
259                bytes,
260                length,
261                index,
262            );
263        }
264    }
265
266    /// Set fragment texture at index.
267    ///
268    /// C++ equivalent: `void setFragmentTexture(const MTL::Texture*, NS::UInteger)`
269    pub fn set_fragment_texture(&self, texture: *const c_void, index: UInteger) {
270        unsafe {
271            let _: () = msg_send_2(
272                self.as_ptr(),
273                sel!(setFragmentTexture:atIndex:),
274                texture,
275                index,
276            );
277        }
278    }
279
280    /// Set fragment sampler state at index.
281    ///
282    /// C++ equivalent: `void setFragmentSamplerState(const MTL::SamplerState*, NS::UInteger)`
283    pub fn set_fragment_sampler_state(&self, sampler: *const c_void, index: UInteger) {
284        unsafe {
285            let _: () = msg_send_2(
286                self.as_ptr(),
287                sel!(setFragmentSamplerState:atIndex:),
288                sampler,
289                index,
290            );
291        }
292    }
293
294    // ========== Tile Buffer Binding ==========
295
296    /// Set tile buffer at index.
297    ///
298    /// C++ equivalent: `void setTileBuffer(const MTL::Buffer*, NS::UInteger, NS::UInteger)`
299    pub fn set_tile_buffer(&self, buffer: *const c_void, offset: UInteger, index: UInteger) {
300        unsafe {
301            let _: () = msg_send_3(
302                self.as_ptr(),
303                sel!(setTileBuffer:offset:atIndex:),
304                buffer,
305                offset,
306                index,
307            );
308        }
309    }
310
311    /// Set tile bytes at index.
312    ///
313    /// C++ equivalent: `void setTileBytes(const void*, NS::UInteger, NS::UInteger)`
314    pub fn set_tile_bytes(&self, bytes: *const c_void, length: UInteger, index: UInteger) {
315        unsafe {
316            let _: () = msg_send_3(
317                self.as_ptr(),
318                sel!(setTileBytes:length:atIndex:),
319                bytes,
320                length,
321                index,
322            );
323        }
324    }
325
326    /// Set tile texture at index.
327    ///
328    /// C++ equivalent: `void setTileTexture(const MTL::Texture*, NS::UInteger)`
329    pub fn set_tile_texture(&self, texture: *const c_void, index: UInteger) {
330        unsafe {
331            let _: () = msg_send_2(self.as_ptr(), sel!(setTileTexture:atIndex:), texture, index);
332        }
333    }
334
335    /// Set tile sampler state at index.
336    ///
337    /// C++ equivalent: `void setTileSamplerState(const MTL::SamplerState*, NS::UInteger)`
338    pub fn set_tile_sampler_state(&self, sampler: *const c_void, index: UInteger) {
339        unsafe {
340            let _: () = msg_send_2(
341                self.as_ptr(),
342                sel!(setTileSamplerState:atIndex:),
343                sampler,
344                index,
345            );
346        }
347    }
348
349    // ========== Render State ==========
350
351    /// Set viewport.
352    ///
353    /// C++ equivalent: `void setViewport(MTL::Viewport)`
354    pub fn set_viewport(&self, viewport: Viewport) {
355        unsafe {
356            let _: () = msg_send_1(self.as_ptr(), sel!(setViewport:), viewport);
357        }
358    }
359
360    /// Set multiple viewports.
361    ///
362    /// C++ equivalent: `void setViewports(const MTL::Viewport*, NS::UInteger)`
363    pub fn set_viewports(&self, viewports: *const Viewport, count: UInteger) {
364        unsafe {
365            let _: () = msg_send_2(self.as_ptr(), sel!(setViewports:count:), viewports, count);
366        }
367    }
368
369    /// Set scissor rect.
370    ///
371    /// C++ equivalent: `void setScissorRect(MTL::ScissorRect)`
372    pub fn set_scissor_rect(&self, rect: ScissorRect) {
373        unsafe {
374            let _: () = msg_send_1(self.as_ptr(), sel!(setScissorRect:), rect);
375        }
376    }
377
378    /// Set multiple scissor rects.
379    ///
380    /// C++ equivalent: `void setScissorRects(const MTL::ScissorRect*, NS::UInteger)`
381    pub fn set_scissor_rects(&self, rects: *const ScissorRect, count: UInteger) {
382        unsafe {
383            let _: () = msg_send_2(self.as_ptr(), sel!(setScissorRects:count:), rects, count);
384        }
385    }
386
387    /// Set front facing winding.
388    ///
389    /// C++ equivalent: `void setFrontFacingWinding(MTL::Winding)`
390    pub fn set_front_facing_winding(&self, winding: Winding) {
391        unsafe {
392            let _: () = msg_send_1(self.as_ptr(), sel!(setFrontFacingWinding:), winding);
393        }
394    }
395
396    /// Set cull mode.
397    ///
398    /// C++ equivalent: `void setCullMode(MTL::CullMode)`
399    pub fn set_cull_mode(&self, mode: CullMode) {
400        unsafe {
401            let _: () = msg_send_1(self.as_ptr(), sel!(setCullMode:), mode);
402        }
403    }
404
405    /// Set triangle fill mode.
406    ///
407    /// C++ equivalent: `void setTriangleFillMode(MTL::TriangleFillMode)`
408    pub fn set_triangle_fill_mode(&self, mode: TriangleFillMode) {
409        unsafe {
410            let _: () = msg_send_1(self.as_ptr(), sel!(setTriangleFillMode:), mode);
411        }
412    }
413
414    /// Set depth clip mode.
415    ///
416    /// C++ equivalent: `void setDepthClipMode(MTL::DepthClipMode)`
417    pub fn set_depth_clip_mode(&self, mode: DepthClipMode) {
418        unsafe {
419            let _: () = msg_send_1(self.as_ptr(), sel!(setDepthClipMode:), mode);
420        }
421    }
422
423    /// Set depth bias.
424    ///
425    /// C++ equivalent: `void setDepthBias(float, float, float)`
426    pub fn set_depth_bias(&self, depth_bias: f32, slope_scale: f32, clamp: f32) {
427        unsafe {
428            let _: () = msg_send_3(
429                self.as_ptr(),
430                sel!(setDepthBias:slopeScale:clamp:),
431                depth_bias,
432                slope_scale,
433                clamp,
434            );
435        }
436    }
437
438    /// Set depth stencil state.
439    ///
440    /// C++ equivalent: `void setDepthStencilState(const MTL::DepthStencilState*)`
441    pub fn set_depth_stencil_state(&self, state: &DepthStencilState) {
442        unsafe {
443            let _: () = msg_send_1(self.as_ptr(), sel!(setDepthStencilState:), state.as_ptr());
444        }
445    }
446
447    /// Set stencil reference value.
448    ///
449    /// C++ equivalent: `void setStencilReferenceValue(uint32_t)`
450    pub fn set_stencil_reference_value(&self, value: u32) {
451        unsafe {
452            let _: () = msg_send_1(self.as_ptr(), sel!(setStencilReferenceValue:), value);
453        }
454    }
455
456    /// Set front and back stencil reference values.
457    ///
458    /// C++ equivalent: `void setStencilReferenceValues(uint32_t, uint32_t)`
459    pub fn set_stencil_reference_values(&self, front: u32, back: u32) {
460        unsafe {
461            let _: () = msg_send_2(
462                self.as_ptr(),
463                sel!(setStencilFrontReferenceValue:backReferenceValue:),
464                front,
465                back,
466            );
467        }
468    }
469
470    /// Set blend color.
471    ///
472    /// C++ equivalent: `void setBlendColor(float, float, float, float)`
473    pub fn set_blend_color(&self, red: f32, green: f32, blue: f32, alpha: f32) {
474        unsafe {
475            let _: () = msg_send_4(
476                self.as_ptr(),
477                sel!(setBlendColorRed:green:blue:alpha:),
478                red,
479                green,
480                blue,
481                alpha,
482            );
483        }
484    }
485
486    // ========== Draw Primitives ==========
487
488    /// Draw primitives.
489    ///
490    /// C++ equivalent: `void drawPrimitives(MTL::PrimitiveType, NS::UInteger, NS::UInteger)`
491    pub fn draw_primitives(
492        &self,
493        primitive_type: PrimitiveType,
494        vertex_start: UInteger,
495        vertex_count: UInteger,
496    ) {
497        unsafe {
498            let _: () = msg_send_3(
499                self.as_ptr(),
500                sel!(drawPrimitives:vertexStart:vertexCount:),
501                primitive_type,
502                vertex_start,
503                vertex_count,
504            );
505        }
506    }
507
508    /// Draw primitives with instance count.
509    ///
510    /// C++ equivalent: `void drawPrimitives(MTL::PrimitiveType, NS::UInteger, NS::UInteger, NS::UInteger)`
511    pub fn draw_primitives_instanced(
512        &self,
513        primitive_type: PrimitiveType,
514        vertex_start: UInteger,
515        vertex_count: UInteger,
516        instance_count: UInteger,
517    ) {
518        unsafe {
519            let _: () = msg_send_4(
520                self.as_ptr(),
521                sel!(drawPrimitives:vertexStart:vertexCount:instanceCount:),
522                primitive_type,
523                vertex_start,
524                vertex_count,
525                instance_count,
526            );
527        }
528    }
529
530    /// Draw primitives with instance count and base instance.
531    ///
532    /// C++ equivalent: `void drawPrimitives(MTL::PrimitiveType, NS::UInteger, NS::UInteger, NS::UInteger, NS::UInteger)`
533    pub fn draw_primitives_instanced_base(
534        &self,
535        primitive_type: PrimitiveType,
536        vertex_start: UInteger,
537        vertex_count: UInteger,
538        instance_count: UInteger,
539        base_instance: UInteger,
540    ) {
541        unsafe {
542            let _: () = msg_send_5(
543                self.as_ptr(),
544                sel!(drawPrimitives:vertexStart:vertexCount:instanceCount:baseInstance:),
545                primitive_type,
546                vertex_start,
547                vertex_count,
548                instance_count,
549                base_instance,
550            );
551        }
552    }
553
554    // ========== Draw Indexed Primitives ==========
555
556    /// Draw indexed primitives.
557    ///
558    /// C++ equivalent: `void drawIndexedPrimitives(...)`
559    pub fn draw_indexed_primitives(
560        &self,
561        primitive_type: PrimitiveType,
562        index_count: UInteger,
563        index_type: UInteger,
564        index_buffer: *const c_void,
565        index_buffer_offset: UInteger,
566    ) {
567        unsafe {
568            let _: () = msg_send_5(
569                self.as_ptr(),
570                sel!(drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:),
571                primitive_type,
572                index_count,
573                index_type,
574                index_buffer,
575                index_buffer_offset,
576            );
577        }
578    }
579
580    /// Draw indexed primitives with indirect buffer.
581    ///
582    /// C++ equivalent: `void drawIndexedPrimitives(... indirectBuffer ...)`
583    pub fn draw_indexed_primitives_indirect(
584        &self,
585        primitive_type: PrimitiveType,
586        index_type: UInteger,
587        index_buffer: *const c_void,
588        index_buffer_offset: UInteger,
589        indirect_buffer: *const c_void,
590        indirect_buffer_offset: UInteger,
591    ) {
592        unsafe {
593            let _: () = msg_send_6(
594                self.as_ptr(),
595                sel!(drawIndexedPrimitives:indexType:indexBuffer:indexBufferOffset:indirectBuffer:indirectBufferOffset:),
596                primitive_type.0 as UInteger,
597                index_type,
598                index_buffer,
599                index_buffer_offset,
600                indirect_buffer,
601                indirect_buffer_offset,
602            );
603        }
604    }
605
606    // ========== Draw Mesh Threadgroups ==========
607
608    /// Draw mesh threadgroups.
609    ///
610    /// C++ equivalent: `void drawMeshThreadgroups(MTL::Size, MTL::Size, MTL::Size)`
611    pub fn draw_mesh_threadgroups(
612        &self,
613        threadgroups_per_grid: Size,
614        threads_per_object_threadgroup: Size,
615        threads_per_mesh_threadgroup: Size,
616    ) {
617        unsafe {
618            let _: () = msg_send_3(
619                self.as_ptr(),
620                sel!(drawMeshThreadgroups:threadsPerObjectThreadgroup:threadsPerMeshThreadgroup:),
621                threadgroups_per_grid,
622                threads_per_object_threadgroup,
623                threads_per_mesh_threadgroup,
624            );
625        }
626    }
627
628    /// Draw mesh threadgroups with indirect buffer.
629    ///
630    /// C++ equivalent: `void drawMeshThreadgroups(const MTL::Buffer*, NS::UInteger, MTL::Size, MTL::Size)`
631    pub fn draw_mesh_threadgroups_indirect(
632        &self,
633        indirect_buffer: *const c_void,
634        indirect_buffer_offset: UInteger,
635        threads_per_object_threadgroup: Size,
636        threads_per_mesh_threadgroup: Size,
637    ) {
638        unsafe {
639            let _: () = msg_send_4(
640                self.as_ptr(),
641                sel!(drawMeshThreadgroupsWithIndirectBuffer:indirectBufferOffset:threadsPerObjectThreadgroup:threadsPerMeshThreadgroup:),
642                indirect_buffer,
643                indirect_buffer_offset,
644                threads_per_object_threadgroup,
645                threads_per_mesh_threadgroup,
646            );
647        }
648    }
649
650    /// Draw mesh threads.
651    ///
652    /// C++ equivalent: `void drawMeshThreads(MTL::Size, MTL::Size, MTL::Size)`
653    pub fn draw_mesh_threads(
654        &self,
655        threads_per_grid: Size,
656        threads_per_object_threadgroup: Size,
657        threads_per_mesh_threadgroup: Size,
658    ) {
659        unsafe {
660            let _: () = msg_send_3(
661                self.as_ptr(),
662                sel!(drawMeshThreads:threadsPerObjectThreadgroup:threadsPerMeshThreadgroup:),
663                threads_per_grid,
664                threads_per_object_threadgroup,
665                threads_per_mesh_threadgroup,
666            );
667        }
668    }
669
670    // ========== Memory Barrier ==========
671
672    /// Insert a barrier.
673    ///
674    /// C++ equivalent: `void barrier()`
675    pub fn barrier(&self) {
676        unsafe {
677            let _: () = msg_send_0(self.as_ptr(), sel!(barrier));
678        }
679    }
680
681    /// Insert a barrier for a buffer.
682    ///
683    /// C++ equivalent: `void barrier(const MTL::Buffer*, MTL4::VisibilityOptions)`
684    pub fn barrier_buffer(&self, buffer: *const c_void, visibility: VisibilityOptions) {
685        unsafe {
686            let _: () = msg_send_2(
687                self.as_ptr(),
688                sel!(barrierWithBuffer:visibilityOptions:),
689                buffer,
690                visibility.0,
691            );
692        }
693    }
694
695    /// Insert a barrier for a texture.
696    ///
697    /// C++ equivalent: `void barrier(const MTL::Texture*, MTL4::VisibilityOptions)`
698    pub fn barrier_texture(&self, texture: *const c_void, visibility: VisibilityOptions) {
699        unsafe {
700            let _: () = msg_send_2(
701                self.as_ptr(),
702                sel!(barrierWithTexture:visibilityOptions:),
703                texture,
704                visibility.0,
705            );
706        }
707    }
708
709    // ========== Fence Methods ==========
710
711    /// Update a fence.
712    ///
713    /// C++ equivalent: `void updateFence(const MTL::Fence*)`
714    pub fn update_fence(&self, fence: *const c_void) {
715        unsafe {
716            let _: () = msg_send_1(self.as_ptr(), sel!(updateFence:), fence);
717        }
718    }
719
720    /// Wait for a fence.
721    ///
722    /// C++ equivalent: `void waitForFence(const MTL::Fence*)`
723    pub fn wait_for_fence(&self, fence: *const c_void) {
724        unsafe {
725            let _: () = msg_send_1(self.as_ptr(), sel!(waitForFence:), fence);
726        }
727    }
728
729    // ========== Resource Usage ==========
730
731    /// Use resource.
732    ///
733    /// C++ equivalent: `void useResource(const MTL::Resource*, MTL::ResourceUsage)`
734    pub fn use_resource(&self, resource: *const c_void, usage: UInteger) {
735        unsafe {
736            let _: () = msg_send_2(self.as_ptr(), sel!(useResource:usage:), resource, usage);
737        }
738    }
739
740    /// Use heap.
741    ///
742    /// C++ equivalent: `void useHeap(const MTL::Heap*, MTL::ResourceUsage)`
743    pub fn use_heap(&self, heap: *const c_void, usage: UInteger) {
744        unsafe {
745            let _: () = msg_send_2(self.as_ptr(), sel!(useHeap:usage:), heap, usage);
746        }
747    }
748
749    // ========== Debug Methods ==========
750
751    /// Push a debug group.
752    ///
753    /// C++ equivalent: `void pushDebugGroup(const NS::String*)`
754    pub fn push_debug_group(&self, name: &str) {
755        if let Some(ns_name) = mtl_foundation::String::from_str(name) {
756            unsafe {
757                let _: () = msg_send_1(self.as_ptr(), sel!(pushDebugGroup:), ns_name.as_ptr());
758            }
759        }
760    }
761
762    /// Pop a debug group.
763    ///
764    /// C++ equivalent: `void popDebugGroup()`
765    pub fn pop_debug_group(&self) {
766        unsafe {
767            let _: () = msg_send_0(self.as_ptr(), sel!(popDebugGroup));
768        }
769    }
770
771    /// Insert a debug signpost.
772    ///
773    /// C++ equivalent: `void insertDebugSignpost(const NS::String*)`
774    pub fn insert_debug_signpost(&self, name: &str) {
775        if let Some(ns_name) = mtl_foundation::String::from_str(name) {
776            unsafe {
777                let _: () = msg_send_1(self.as_ptr(), sel!(insertDebugSignpost:), ns_name.as_ptr());
778            }
779        }
780    }
781
782    // ========== Counter/Timestamp Methods ==========
783
784    /// Write a timestamp to a counter heap.
785    ///
786    /// C++ equivalent: `void writeTimestamp(MTL4::TimestampGranularity, MTL::RenderStages, const MTL4::CounterHeap*, NS::UInteger)`
787    pub fn write_timestamp(
788        &self,
789        granularity: super::TimestampGranularity,
790        stage: RenderStages,
791        counter_heap: *const c_void,
792        index: UInteger,
793    ) {
794        unsafe {
795            let _: () = msg_send_4(
796                self.as_ptr(),
797                sel!(writeTimestampWithGranularity:afterStage:intoHeap:atIndex:),
798                granularity.0,
799                stage.0,
800                counter_heap,
801                index,
802            );
803        }
804    }
805
806    // ========== Encoding ==========
807
808    /// End encoding.
809    ///
810    /// C++ equivalent: `void endEncoding()`
811    pub fn end_encoding(&self) {
812        unsafe {
813            let _: () = msg_send_0(self.as_ptr(), sel!(endEncoding));
814        }
815    }
816}
817
818impl Clone for RenderCommandEncoder {
819    fn clone(&self) -> Self {
820        unsafe {
821            mtl_sys::msg_send_0::<*mut c_void>(self.as_ptr(), mtl_sys::sel!(retain));
822        }
823        Self(self.0)
824    }
825}
826
827impl Drop for RenderCommandEncoder {
828    fn drop(&mut self) {
829        unsafe {
830            mtl_sys::msg_send_0::<()>(self.as_ptr(), mtl_sys::sel!(release));
831        }
832    }
833}
834
835impl Referencing for RenderCommandEncoder {
836    #[inline]
837    fn as_ptr(&self) -> *const c_void {
838        self.0.as_ptr()
839    }
840}
841
842unsafe impl Send for RenderCommandEncoder {}
843unsafe impl Sync for RenderCommandEncoder {}
844
845impl std::fmt::Debug for RenderCommandEncoder {
846    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
847        f.debug_struct("RenderCommandEncoder")
848            .field("label", &self.label())
849            .finish()
850    }
851}
852
853#[cfg(test)]
854mod tests {
855    use super::*;
856
857    #[test]
858    fn test_render_command_encoder_size() {
859        assert_eq!(
860            std::mem::size_of::<RenderCommandEncoder>(),
861            std::mem::size_of::<*mut c_void>()
862        );
863    }
864}