Skip to main content

mtl_gpu/encoder/
blit_encoder.rs

1//! Blit command encoder.
2//!
3//! Corresponds to `Metal/MTLBlitCommandEncoder.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, sel};
10
11use crate::Buffer;
12use crate::Texture;
13use crate::enums::BlitOption;
14use crate::types::{Origin, Region, Size};
15
16/// A command encoder for data transfer operations.
17///
18/// C++ equivalent: `MTL::BlitCommandEncoder`
19///
20/// Blit encoders are used to copy data between buffers and textures,
21/// generate mipmaps, and synchronize resources.
22#[repr(transparent)]
23pub struct BlitCommandEncoder(pub(crate) NonNull<c_void>);
24
25impl BlitCommandEncoder {
26    /// Create a BlitCommandEncoder from a raw pointer.
27    ///
28    /// # Safety
29    ///
30    /// The pointer must be a valid Metal blit command encoder object.
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 to the encoder.
37    #[inline]
38    pub fn as_raw(&self) -> *mut c_void {
39        self.0.as_ptr()
40    }
41
42    // =========================================================================
43    // CommandEncoder base methods
44    // =========================================================================
45
46    /// Get the device that created this encoder.
47    ///
48    /// C++ equivalent: `Device* device() const`
49    pub fn device(&self) -> crate::Device {
50        unsafe {
51            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(device));
52            let _: *mut c_void = msg_send_0(ptr, sel!(retain));
53            crate::Device::from_raw(ptr).expect("encoder has no device")
54        }
55    }
56
57    /// Get the command buffer that this encoder is encoding into.
58    ///
59    /// C++ equivalent: `CommandBuffer* commandBuffer() const`
60    pub fn command_buffer(&self) -> crate::CommandBuffer {
61        unsafe {
62            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(commandBuffer));
63            let _: *mut c_void = msg_send_0(ptr, sel!(retain));
64            crate::CommandBuffer::from_raw(ptr).expect("encoder has no command buffer")
65        }
66    }
67
68    /// Get the label for this encoder.
69    ///
70    /// C++ equivalent: `NS::String* label() const`
71    pub fn label(&self) -> Option<String> {
72        unsafe {
73            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
74            if ptr.is_null() {
75                return None;
76            }
77            let utf8_ptr: *const std::ffi::c_char =
78                mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
79            if utf8_ptr.is_null() {
80                return None;
81            }
82            let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
83            Some(c_str.to_string_lossy().into_owned())
84        }
85    }
86
87    /// Set the label for this encoder.
88    ///
89    /// C++ equivalent: `void setLabel(const NS::String*)`
90    pub fn set_label(&self, label: &str) {
91        if let Some(ns_label) = mtl_foundation::String::from_str(label) {
92            unsafe {
93                msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(setLabel:), ns_label.as_ptr());
94            }
95        }
96    }
97
98    /// End encoding commands with this encoder.
99    ///
100    /// C++ equivalent: `void endEncoding()`
101    #[inline]
102    pub fn end_encoding(&self) {
103        unsafe {
104            msg_send_0::<()>(self.as_ptr(), sel!(endEncoding));
105        }
106    }
107
108    /// Insert a debug signpost.
109    ///
110    /// C++ equivalent: `void insertDebugSignpost(const NS::String*)`
111    pub fn insert_debug_signpost(&self, string: &str) {
112        if let Some(ns_string) = mtl_foundation::String::from_str(string) {
113            unsafe {
114                msg_send_1::<(), *const c_void>(
115                    self.as_ptr(),
116                    sel!(insertDebugSignpost:),
117                    ns_string.as_ptr(),
118                );
119            }
120        }
121    }
122
123    /// Push a debug group.
124    ///
125    /// C++ equivalent: `void pushDebugGroup(const NS::String*)`
126    pub fn push_debug_group(&self, string: &str) {
127        if let Some(ns_string) = mtl_foundation::String::from_str(string) {
128            unsafe {
129                msg_send_1::<(), *const c_void>(
130                    self.as_ptr(),
131                    sel!(pushDebugGroup:),
132                    ns_string.as_ptr(),
133                );
134            }
135        }
136    }
137
138    /// Pop the current debug group.
139    ///
140    /// C++ equivalent: `void popDebugGroup()`
141    #[inline]
142    pub fn pop_debug_group(&self) {
143        unsafe {
144            msg_send_0::<()>(self.as_ptr(), sel!(popDebugGroup));
145        }
146    }
147
148    /// Insert a barrier to synchronize queue stages.
149    ///
150    /// C++ equivalent: `void barrierAfterQueueStages(Stages, Stages)`
151    #[inline]
152    pub fn barrier_after_queue_stages(
153        &self,
154        after_stages: crate::enums::Stages,
155        before_stages: crate::enums::Stages,
156    ) {
157        unsafe {
158            mtl_sys::msg_send_2::<(), crate::enums::Stages, crate::enums::Stages>(
159                self.as_ptr(),
160                sel!(barrierAfterQueueStages:beforeQueueStages:),
161                after_stages,
162                before_stages,
163            );
164        }
165    }
166
167    // =========================================================================
168    // Tensor Copy
169    // =========================================================================
170
171    /// Copy data from one tensor to another (raw pointer version).
172    ///
173    /// C++ equivalent: `void copyFromTensor(...)`
174    ///
175    /// # Safety
176    ///
177    /// All tensor and extents pointers must be valid Metal tensor/extents objects.
178    #[allow(clippy::too_many_arguments)]
179    pub unsafe fn copy_from_tensor_ptr(
180        &self,
181        source_tensor: *const c_void,
182        source_origin: *const c_void,
183        source_dimensions: *const c_void,
184        destination_tensor: *const c_void,
185        destination_origin: *const c_void,
186        destination_dimensions: *const c_void,
187    ) {
188        unsafe {
189            mtl_sys::msg_send_6::<
190                (),
191                *const c_void,
192                *const c_void,
193                *const c_void,
194                *const c_void,
195                *const c_void,
196                *const c_void,
197            >(
198                self.as_ptr(),
199                sel!(copyFromTensor: sourceOrigin: sourceDimensions: toTensor: destinationOrigin: destinationDimensions:),
200                source_tensor,
201                source_origin,
202                source_dimensions,
203                destination_tensor,
204                destination_origin,
205                destination_dimensions,
206            );
207        }
208    }
209
210    // =========================================================================
211    // Buffer to Buffer Copy
212    // =========================================================================
213
214    /// Copy data from one buffer to another.
215    ///
216    /// C++ equivalent: `void copyFromBuffer(const Buffer*, NS::UInteger, const Buffer*, NS::UInteger, NS::UInteger)`
217    #[inline]
218    pub fn copy_from_buffer_to_buffer(
219        &self,
220        source_buffer: &Buffer,
221        source_offset: UInteger,
222        destination_buffer: &Buffer,
223        destination_offset: UInteger,
224        size: UInteger,
225    ) {
226        unsafe {
227            mtl_sys::msg_send_5::<(), *const c_void, UInteger, *const c_void, UInteger, UInteger>(
228                self.as_ptr(),
229                sel!(copyFromBuffer: sourceOffset: toBuffer: destinationOffset: size:),
230                source_buffer.as_ptr(),
231                source_offset,
232                destination_buffer.as_ptr(),
233                destination_offset,
234                size,
235            );
236        }
237    }
238
239    // =========================================================================
240    // Buffer to Texture Copy
241    // =========================================================================
242
243    /// Copy data from a buffer to a texture.
244    ///
245    /// C++ equivalent: `void copyFromBuffer(...toTexture...)`
246    #[allow(clippy::too_many_arguments)]
247    pub fn copy_from_buffer_to_texture(
248        &self,
249        source_buffer: &Buffer,
250        source_offset: UInteger,
251        source_bytes_per_row: UInteger,
252        source_bytes_per_image: UInteger,
253        source_size: Size,
254        destination_texture: &Texture,
255        destination_slice: UInteger,
256        destination_level: UInteger,
257        destination_origin: Origin,
258    ) {
259        unsafe {
260            mtl_sys::msg_send_9::<
261                (),
262                *const c_void,
263                UInteger,
264                UInteger,
265                UInteger,
266                Size,
267                *const c_void,
268                UInteger,
269                UInteger,
270                Origin,
271            >(
272                self.as_ptr(),
273                sel!(copyFromBuffer: sourceOffset: sourceBytesPerRow: sourceBytesPerImage: sourceSize: toTexture: destinationSlice: destinationLevel: destinationOrigin:),
274                source_buffer.as_ptr(),
275                source_offset,
276                source_bytes_per_row,
277                source_bytes_per_image,
278                source_size,
279                destination_texture.as_ptr(),
280                destination_slice,
281                destination_level,
282                destination_origin,
283            );
284        }
285    }
286
287    /// Copy data from a buffer to a texture with options.
288    ///
289    /// C++ equivalent: `void copyFromBuffer(...toTexture...options:)`
290    #[allow(clippy::too_many_arguments)]
291    pub fn copy_from_buffer_to_texture_with_options(
292        &self,
293        source_buffer: &Buffer,
294        source_offset: UInteger,
295        source_bytes_per_row: UInteger,
296        source_bytes_per_image: UInteger,
297        source_size: Size,
298        destination_texture: &Texture,
299        destination_slice: UInteger,
300        destination_level: UInteger,
301        destination_origin: Origin,
302        options: BlitOption,
303    ) {
304        unsafe {
305            mtl_sys::msg_send_10::<
306                (),
307                *const c_void,
308                UInteger,
309                UInteger,
310                UInteger,
311                Size,
312                *const c_void,
313                UInteger,
314                UInteger,
315                Origin,
316                BlitOption,
317            >(
318                self.as_ptr(),
319                sel!(copyFromBuffer: sourceOffset: sourceBytesPerRow: sourceBytesPerImage: sourceSize: toTexture: destinationSlice: destinationLevel: destinationOrigin: options:),
320                source_buffer.as_ptr(),
321                source_offset,
322                source_bytes_per_row,
323                source_bytes_per_image,
324                source_size,
325                destination_texture.as_ptr(),
326                destination_slice,
327                destination_level,
328                destination_origin,
329                options,
330            );
331        }
332    }
333
334    // =========================================================================
335    // Texture to Buffer Copy
336    // =========================================================================
337
338    /// Copy data from a texture to a buffer.
339    ///
340    /// C++ equivalent: `void copyFromTexture(...toBuffer...)`
341    #[allow(clippy::too_many_arguments)]
342    pub fn copy_from_texture_to_buffer(
343        &self,
344        source_texture: &Texture,
345        source_slice: UInteger,
346        source_level: UInteger,
347        source_origin: Origin,
348        source_size: Size,
349        destination_buffer: &Buffer,
350        destination_offset: UInteger,
351        destination_bytes_per_row: UInteger,
352        destination_bytes_per_image: UInteger,
353    ) {
354        unsafe {
355            mtl_sys::msg_send_9::<
356                (),
357                *const c_void,
358                UInteger,
359                UInteger,
360                Origin,
361                Size,
362                *const c_void,
363                UInteger,
364                UInteger,
365                UInteger,
366            >(
367                self.as_ptr(),
368                sel!(copyFromTexture: sourceSlice: sourceLevel: sourceOrigin: sourceSize: toBuffer: destinationOffset: destinationBytesPerRow: destinationBytesPerImage:),
369                source_texture.as_ptr(),
370                source_slice,
371                source_level,
372                source_origin,
373                source_size,
374                destination_buffer.as_ptr(),
375                destination_offset,
376                destination_bytes_per_row,
377                destination_bytes_per_image,
378            );
379        }
380    }
381
382    /// Copy data from a texture to a buffer with options.
383    ///
384    /// C++ equivalent: `void copyFromTexture(...toBuffer...options:)`
385    #[allow(clippy::too_many_arguments)]
386    pub fn copy_from_texture_to_buffer_with_options(
387        &self,
388        source_texture: &Texture,
389        source_slice: UInteger,
390        source_level: UInteger,
391        source_origin: Origin,
392        source_size: Size,
393        destination_buffer: &Buffer,
394        destination_offset: UInteger,
395        destination_bytes_per_row: UInteger,
396        destination_bytes_per_image: UInteger,
397        options: BlitOption,
398    ) {
399        unsafe {
400            mtl_sys::msg_send_10::<
401                (),
402                *const c_void,
403                UInteger,
404                UInteger,
405                Origin,
406                Size,
407                *const c_void,
408                UInteger,
409                UInteger,
410                UInteger,
411                BlitOption,
412            >(
413                self.as_ptr(),
414                sel!(copyFromTexture: sourceSlice: sourceLevel: sourceOrigin: sourceSize: toBuffer: destinationOffset: destinationBytesPerRow: destinationBytesPerImage: options:),
415                source_texture.as_ptr(),
416                source_slice,
417                source_level,
418                source_origin,
419                source_size,
420                destination_buffer.as_ptr(),
421                destination_offset,
422                destination_bytes_per_row,
423                destination_bytes_per_image,
424                options,
425            );
426        }
427    }
428
429    // =========================================================================
430    // Texture to Texture Copy
431    // =========================================================================
432
433    /// Copy data from one texture to another (full copy).
434    ///
435    /// C++ equivalent: `void copyFromTexture(const Texture*, const Texture*)`
436    #[inline]
437    pub fn copy_from_texture_to_texture(
438        &self,
439        source_texture: &Texture,
440        destination_texture: &Texture,
441    ) {
442        unsafe {
443            mtl_sys::msg_send_2::<(), *const c_void, *const c_void>(
444                self.as_ptr(),
445                sel!(copyFromTexture: toTexture:),
446                source_texture.as_ptr(),
447                destination_texture.as_ptr(),
448            );
449        }
450    }
451
452    /// Copy data from one texture to another (region copy).
453    ///
454    /// C++ equivalent: `void copyFromTexture(...toTexture...)`
455    #[allow(clippy::too_many_arguments)]
456    pub fn copy_from_texture_to_texture_region(
457        &self,
458        source_texture: &Texture,
459        source_slice: UInteger,
460        source_level: UInteger,
461        source_origin: Origin,
462        source_size: Size,
463        destination_texture: &Texture,
464        destination_slice: UInteger,
465        destination_level: UInteger,
466        destination_origin: Origin,
467    ) {
468        unsafe {
469            mtl_sys::msg_send_9::<
470                (),
471                *const c_void,
472                UInteger,
473                UInteger,
474                Origin,
475                Size,
476                *const c_void,
477                UInteger,
478                UInteger,
479                Origin,
480            >(
481                self.as_ptr(),
482                sel!(copyFromTexture: sourceSlice: sourceLevel: sourceOrigin: sourceSize: toTexture: destinationSlice: destinationLevel: destinationOrigin:),
483                source_texture.as_ptr(),
484                source_slice,
485                source_level,
486                source_origin,
487                source_size,
488                destination_texture.as_ptr(),
489                destination_slice,
490                destination_level,
491                destination_origin,
492            );
493        }
494    }
495
496    /// Copy slices and levels between textures.
497    ///
498    /// C++ equivalent: `void copyFromTexture(...sliceCount: levelCount:)`
499    #[allow(clippy::too_many_arguments)]
500    pub fn copy_from_texture_to_texture_slices(
501        &self,
502        source_texture: &Texture,
503        source_slice: UInteger,
504        source_level: UInteger,
505        destination_texture: &Texture,
506        destination_slice: UInteger,
507        destination_level: UInteger,
508        slice_count: UInteger,
509        level_count: UInteger,
510    ) {
511        unsafe {
512            mtl_sys::msg_send_8::<
513                (),
514                *const c_void,
515                UInteger,
516                UInteger,
517                *const c_void,
518                UInteger,
519                UInteger,
520                UInteger,
521                UInteger,
522            >(
523                self.as_ptr(),
524                sel!(copyFromTexture: sourceSlice: sourceLevel: toTexture: destinationSlice: destinationLevel: sliceCount: levelCount:),
525                source_texture.as_ptr(),
526                source_slice,
527                source_level,
528                destination_texture.as_ptr(),
529                destination_slice,
530                destination_level,
531                slice_count,
532                level_count,
533            );
534        }
535    }
536
537    // =========================================================================
538    // Fill Operations
539    // =========================================================================
540
541    /// Fill a buffer with a value.
542    ///
543    /// C++ equivalent: `void fillBuffer(const Buffer*, NS::Range, uint8_t)`
544    pub fn fill_buffer(&self, buffer: &Buffer, offset: UInteger, length: UInteger, value: u8) {
545        let range = mtl_foundation::Range::new(offset, length);
546        unsafe {
547            mtl_sys::msg_send_3::<(), *const c_void, mtl_foundation::Range, u8>(
548                self.as_ptr(),
549                sel!(fillBuffer: range: value:),
550                buffer.as_ptr(),
551                range,
552                value,
553            );
554        }
555    }
556
557    // =========================================================================
558    // Mipmap Generation
559    // =========================================================================
560
561    /// Generate mipmaps for a texture.
562    ///
563    /// C++ equivalent: `void generateMipmaps(const Texture*)`
564    #[inline]
565    pub fn generate_mipmaps(&self, texture: &Texture) {
566        unsafe {
567            msg_send_1::<(), *const c_void>(
568                self.as_ptr(),
569                sel!(generateMipmapsForTexture:),
570                texture.as_ptr(),
571            );
572        }
573    }
574
575    // =========================================================================
576    // Optimization Operations
577    // =========================================================================
578
579    /// Optimize a texture's contents for CPU access.
580    ///
581    /// C++ equivalent: `void optimizeContentsForCPUAccess(const Texture*)`
582    #[inline]
583    pub fn optimize_contents_for_cpu_access(&self, texture: &Texture) {
584        unsafe {
585            msg_send_1::<(), *const c_void>(
586                self.as_ptr(),
587                sel!(optimizeContentsForCPUAccess:),
588                texture.as_ptr(),
589            );
590        }
591    }
592
593    /// Optimize a texture slice's contents for CPU access.
594    ///
595    /// C++ equivalent: `void optimizeContentsForCPUAccess(const Texture*, NS::UInteger, NS::UInteger)`
596    #[inline]
597    pub fn optimize_contents_for_cpu_access_slice(
598        &self,
599        texture: &Texture,
600        slice: UInteger,
601        level: UInteger,
602    ) {
603        unsafe {
604            mtl_sys::msg_send_3::<(), *const c_void, UInteger, UInteger>(
605                self.as_ptr(),
606                sel!(optimizeContentsForCPUAccess: slice: level:),
607                texture.as_ptr(),
608                slice,
609                level,
610            );
611        }
612    }
613
614    /// Optimize a texture's contents for GPU access.
615    ///
616    /// C++ equivalent: `void optimizeContentsForGPUAccess(const Texture*)`
617    #[inline]
618    pub fn optimize_contents_for_gpu_access(&self, texture: &Texture) {
619        unsafe {
620            msg_send_1::<(), *const c_void>(
621                self.as_ptr(),
622                sel!(optimizeContentsForGPUAccess:),
623                texture.as_ptr(),
624            );
625        }
626    }
627
628    /// Optimize a texture slice's contents for GPU access.
629    ///
630    /// C++ equivalent: `void optimizeContentsForGPUAccess(const Texture*, NS::UInteger, NS::UInteger)`
631    #[inline]
632    pub fn optimize_contents_for_gpu_access_slice(
633        &self,
634        texture: &Texture,
635        slice: UInteger,
636        level: UInteger,
637    ) {
638        unsafe {
639            mtl_sys::msg_send_3::<(), *const c_void, UInteger, UInteger>(
640                self.as_ptr(),
641                sel!(optimizeContentsForGPUAccess: slice: level:),
642                texture.as_ptr(),
643                slice,
644                level,
645            );
646        }
647    }
648
649    // =========================================================================
650    // Synchronization
651    // =========================================================================
652
653    /// Synchronize a managed resource (raw pointer version).
654    ///
655    /// This ensures the GPU's copy of a managed resource is synchronized with the CPU.
656    ///
657    /// C++ equivalent: `void synchronizeResource(const Resource*)`
658    ///
659    /// # Safety
660    ///
661    /// The resource pointer must be a valid Metal resource object.
662    #[inline]
663    pub unsafe fn synchronize_resource_ptr(&self, resource: *const c_void) {
664        unsafe {
665            msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(synchronizeResource:), resource);
666        }
667    }
668
669    /// Synchronize a managed buffer.
670    ///
671    /// C++ equivalent: `void synchronizeResource(const Resource*)`
672    #[inline]
673    pub fn synchronize_buffer(&self, buffer: &Buffer) {
674        unsafe { self.synchronize_resource_ptr(buffer.as_ptr()) };
675    }
676
677    /// Synchronize a managed texture.
678    ///
679    /// C++ equivalent: `void synchronizeResource(const Resource*)`
680    #[inline]
681    pub fn synchronize_texture(&self, texture: &Texture) {
682        unsafe { self.synchronize_resource_ptr(texture.as_ptr()) };
683    }
684
685    /// Synchronize a texture slice.
686    ///
687    /// C++ equivalent: `void synchronizeTexture(const Texture*, NS::UInteger, NS::UInteger)`
688    #[inline]
689    pub fn synchronize_texture_slice(&self, texture: &Texture, slice: UInteger, level: UInteger) {
690        unsafe {
691            mtl_sys::msg_send_3::<(), *const c_void, UInteger, UInteger>(
692                self.as_ptr(),
693                sel!(synchronizeTexture: slice: level:),
694                texture.as_ptr(),
695                slice,
696                level,
697            );
698        }
699    }
700
701    // =========================================================================
702    // Fence Operations
703    // =========================================================================
704
705    /// Update a fence (raw pointer version).
706    ///
707    /// C++ equivalent: `void updateFence(const Fence*)`
708    ///
709    /// # Safety
710    ///
711    /// The fence pointer must be a valid Metal fence object.
712    #[inline]
713    pub unsafe fn update_fence_ptr(&self, fence: *const c_void) {
714        unsafe {
715            msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(updateFence:), fence);
716        }
717    }
718
719    /// Update a fence.
720    ///
721    /// C++ equivalent: `void updateFence(const Fence*)`
722    #[inline]
723    pub fn update_fence(&self, fence: &crate::Fence) {
724        unsafe { self.update_fence_ptr(fence.as_ptr()) };
725    }
726
727    /// Wait for a fence (raw pointer version).
728    ///
729    /// C++ equivalent: `void waitForFence(const Fence*)`
730    ///
731    /// # Safety
732    ///
733    /// The fence pointer must be a valid Metal fence object.
734    #[inline]
735    pub unsafe fn wait_for_fence_ptr(&self, fence: *const c_void) {
736        unsafe {
737            msg_send_1::<(), *const c_void>(self.as_ptr(), sel!(waitForFence:), fence);
738        }
739    }
740
741    /// Wait for a fence.
742    ///
743    /// C++ equivalent: `void waitForFence(const Fence*)`
744    #[inline]
745    pub fn wait_for_fence(&self, fence: &crate::Fence) {
746        unsafe { self.wait_for_fence_ptr(fence.as_ptr()) };
747    }
748
749    // =========================================================================
750    // Texture Access Counters
751    // =========================================================================
752
753    /// Get texture access counters.
754    ///
755    /// C++ equivalent: `void getTextureAccessCounters(...)`
756    #[allow(clippy::too_many_arguments)]
757    pub fn get_texture_access_counters(
758        &self,
759        texture: &Texture,
760        region: Region,
761        mip_level: UInteger,
762        slice: UInteger,
763        reset_counters: bool,
764        counters_buffer: &Buffer,
765        counters_buffer_offset: UInteger,
766    ) {
767        unsafe {
768            mtl_sys::msg_send_7::<
769                (),
770                *const c_void,
771                Region,
772                UInteger,
773                UInteger,
774                bool,
775                *const c_void,
776                UInteger,
777            >(
778                self.as_ptr(),
779                sel!(getTextureAccessCounters: region: mipLevel: slice: resetCounters: countersBuffer: countersBufferOffset:),
780                texture.as_ptr(),
781                region,
782                mip_level,
783                slice,
784                reset_counters,
785                counters_buffer.as_ptr(),
786                counters_buffer_offset,
787            );
788        }
789    }
790
791    /// Reset texture access counters.
792    ///
793    /// C++ equivalent: `void resetTextureAccessCounters(...)`
794    pub fn reset_texture_access_counters(
795        &self,
796        texture: &Texture,
797        region: Region,
798        mip_level: UInteger,
799        slice: UInteger,
800    ) {
801        unsafe {
802            mtl_sys::msg_send_4::<(), *const c_void, Region, UInteger, UInteger>(
803                self.as_ptr(),
804                sel!(resetTextureAccessCounters: region: mipLevel: slice:),
805                texture.as_ptr(),
806                region,
807                mip_level,
808                slice,
809            );
810        }
811    }
812
813    // =========================================================================
814    // Indirect Command Buffer Operations
815    // =========================================================================
816
817    /// Copy an indirect command buffer (raw pointer version).
818    ///
819    /// C++ equivalent: `void copyIndirectCommandBuffer(...)`
820    ///
821    /// # Safety
822    ///
823    /// The source and destination pointers must be valid indirect command buffer objects.
824    pub unsafe fn copy_indirect_command_buffer_ptr(
825        &self,
826        source: *const c_void,
827        source_offset: UInteger,
828        source_length: UInteger,
829        destination: *const c_void,
830        destination_index: UInteger,
831    ) {
832        let range = mtl_foundation::Range::new(source_offset, source_length);
833        unsafe {
834            mtl_sys::msg_send_4::<
835                (),
836                *const c_void,
837                mtl_foundation::Range,
838                *const c_void,
839                UInteger,
840            >(
841                self.as_ptr(),
842                sel!(copyIndirectCommandBuffer: sourceRange: destination: destinationIndex:),
843                source,
844                range,
845                destination,
846                destination_index,
847            );
848        }
849    }
850
851    /// Optimize an indirect command buffer (raw pointer version).
852    ///
853    /// C++ equivalent: `void optimizeIndirectCommandBuffer(...)`
854    ///
855    /// # Safety
856    ///
857    /// The indirect command buffer pointer must be valid.
858    pub unsafe fn optimize_indirect_command_buffer_ptr(
859        &self,
860        indirect_command_buffer: *const c_void,
861        offset: UInteger,
862        length: UInteger,
863    ) {
864        let range = mtl_foundation::Range::new(offset, length);
865        unsafe {
866            mtl_sys::msg_send_2::<(), *const c_void, mtl_foundation::Range>(
867                self.as_ptr(),
868                sel!(optimizeIndirectCommandBuffer: withRange:),
869                indirect_command_buffer,
870                range,
871            );
872        }
873    }
874
875    /// Reset commands in an indirect command buffer (raw pointer version).
876    ///
877    /// C++ equivalent: `void resetCommandsInBuffer(...)`
878    ///
879    /// # Safety
880    ///
881    /// The buffer pointer must be a valid indirect command buffer object.
882    pub unsafe fn reset_commands_in_buffer_ptr(
883        &self,
884        buffer: *const c_void,
885        offset: UInteger,
886        length: UInteger,
887    ) {
888        let range = mtl_foundation::Range::new(offset, length);
889        unsafe {
890            mtl_sys::msg_send_2::<(), *const c_void, mtl_foundation::Range>(
891                self.as_ptr(),
892                sel!(resetCommandsInBuffer: withRange:),
893                buffer,
894                range,
895            );
896        }
897    }
898
899    // =========================================================================
900    // Counter Sampling
901    // =========================================================================
902
903    /// Sample counters (raw pointer version).
904    ///
905    /// C++ equivalent: `void sampleCountersInBuffer(...)`
906    ///
907    /// # Safety
908    ///
909    /// The sample buffer pointer must be a valid counter sample buffer object.
910    pub unsafe fn sample_counters_in_buffer_ptr(
911        &self,
912        sample_buffer: *const c_void,
913        sample_index: UInteger,
914        barrier: bool,
915    ) {
916        unsafe {
917            mtl_sys::msg_send_3::<(), *const c_void, UInteger, bool>(
918                self.as_ptr(),
919                sel!(sampleCountersInBuffer: atSampleIndex: withBarrier:),
920                sample_buffer,
921                sample_index,
922                barrier,
923            );
924        }
925    }
926
927    /// Resolve counters (raw pointer version).
928    ///
929    /// C++ equivalent: `void resolveCounters(...)`
930    ///
931    /// # Safety
932    ///
933    /// The sample buffer pointer must be a valid counter sample buffer object.
934    pub unsafe fn resolve_counters_ptr(
935        &self,
936        sample_buffer: *const c_void,
937        offset: UInteger,
938        length: UInteger,
939        destination_buffer: &Buffer,
940        destination_offset: UInteger,
941    ) {
942        let range = mtl_foundation::Range::new(offset, length);
943        unsafe {
944            mtl_sys::msg_send_4::<
945                (),
946                *const c_void,
947                mtl_foundation::Range,
948                *const c_void,
949                UInteger,
950            >(
951                self.as_ptr(),
952                sel!(resolveCounters: inRange: destinationBuffer: destinationOffset:),
953                sample_buffer,
954                range,
955                destination_buffer.as_ptr(),
956                destination_offset,
957            );
958        }
959    }
960}
961
962impl Clone for BlitCommandEncoder {
963    fn clone(&self) -> Self {
964        unsafe {
965            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
966        }
967        Self(self.0)
968    }
969}
970
971impl Drop for BlitCommandEncoder {
972    fn drop(&mut self) {
973        unsafe {
974            msg_send_0::<()>(self.as_ptr(), sel!(release));
975        }
976    }
977}
978
979impl Referencing for BlitCommandEncoder {
980    #[inline]
981    fn as_ptr(&self) -> *const c_void {
982        self.0.as_ptr()
983    }
984}
985
986unsafe impl Send for BlitCommandEncoder {}
987unsafe impl Sync for BlitCommandEncoder {}
988
989impl std::fmt::Debug for BlitCommandEncoder {
990    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
991        f.debug_struct("BlitCommandEncoder")
992            .field("label", &self.label())
993            .finish()
994    }
995}
996
997#[cfg(test)]
998mod tests {
999    use super::*;
1000
1001    #[test]
1002    fn test_blit_encoder_size() {
1003        assert_eq!(
1004            std::mem::size_of::<BlitCommandEncoder>(),
1005            std::mem::size_of::<*mut c_void>()
1006        );
1007    }
1008}