1use 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#[repr(transparent)]
30pub struct RenderCommandEncoder(NonNull<c_void>);
31
32impl RenderCommandEncoder {
33 #[inline]
35 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
36 NonNull::new(ptr).map(Self)
37 }
38
39 #[inline]
41 pub fn as_raw(&self) -> *mut c_void {
42 self.0.as_ptr()
43 }
44
45 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 pub fn set_viewport(&self, viewport: Viewport) {
355 unsafe {
356 let _: () = msg_send_1(self.as_ptr(), sel!(setViewport:), viewport);
357 }
358 }
359
360 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 pub fn barrier(&self) {
676 unsafe {
677 let _: () = msg_send_0(self.as_ptr(), sel!(barrier));
678 }
679 }
680
681 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 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 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 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 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 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 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 pub fn pop_debug_group(&self) {
766 unsafe {
767 let _: () = msg_send_0(self.as_ptr(), sel!(popDebugGroup));
768 }
769 }
770
771 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 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 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}