trustformers-mobile 0.1.1

Mobile deployment support for TrustformeRS (iOS, Android)
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
//! Metal API Bindings for iOS
//!
//! This module provides low-level Metal API bindings for GPU computation on iOS devices.
//! Metal is Apple's low-level graphics and compute API for high-performance computation.

use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_float, c_int, c_uint, c_void};
use std::ptr;

#[cfg(target_os = "ios")]
use core_foundation::{
    base::{CFRelease, CFTypeRef},
    string::{CFString, CFStringRef},
};

// Metal API types
#[cfg(target_os = "ios")]
#[repr(C)]
pub struct MTLDevice;

#[cfg(target_os = "ios")]
#[repr(C)]
pub struct MTLLibrary;

#[cfg(target_os = "ios")]
#[repr(C)]
pub struct MTLFunction;

#[cfg(target_os = "ios")]
#[repr(C)]
pub struct MTLComputePipelineState;

#[cfg(target_os = "ios")]
#[repr(C)]
pub struct MTLCommandQueue;

#[cfg(target_os = "ios")]
#[repr(C)]
pub struct MTLCommandBuffer;

#[cfg(target_os = "ios")]
#[repr(C)]
pub struct MTLComputeCommandEncoder;

#[cfg(target_os = "ios")]
#[repr(C)]
pub struct MTLBuffer;

#[cfg(target_os = "ios")]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct MTLSize {
    pub width: usize,
    pub height: usize,
    pub depth: usize,
}

#[cfg(target_os = "ios")]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct MTLOrigin {
    pub x: usize,
    pub y: usize,
    pub z: usize,
}

#[cfg(target_os = "ios")]
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct MTLRegion {
    pub origin: MTLOrigin,
    pub size: MTLSize,
}

// Metal resource options
#[cfg(target_os = "ios")]
pub const MTL_RESOURCE_STORAGE_MODE_SHARED: c_uint = 0;
#[cfg(target_os = "ios")]
pub const MTL_RESOURCE_STORAGE_MODE_MANAGED: c_uint = 1;
#[cfg(target_os = "ios")]
pub const MTL_RESOURCE_STORAGE_MODE_PRIVATE: c_uint = 2;
#[cfg(target_os = "ios")]
pub const MTL_RESOURCE_STORAGE_MODE_MEMORYLESS: c_uint = 3;

// Metal GPU families
#[cfg(target_os = "ios")]
pub const MTL_GPU_FAMILY_APPLE_1: u32 = 1001;
#[cfg(target_os = "ios")]
pub const MTL_GPU_FAMILY_APPLE_2: u32 = 1002;
#[cfg(target_os = "ios")]
pub const MTL_GPU_FAMILY_APPLE_3: u32 = 1003;
#[cfg(target_os = "ios")]
pub const MTL_GPU_FAMILY_APPLE_4: u32 = 1004;
#[cfg(target_os = "ios")]
pub const MTL_GPU_FAMILY_APPLE_5: u32 = 1005;
#[cfg(target_os = "ios")]
pub const MTL_GPU_FAMILY_APPLE_6: u32 = 1006;
#[cfg(target_os = "ios")]
pub const MTL_GPU_FAMILY_APPLE_7: u32 = 1007;
#[cfg(target_os = "ios")]
pub const MTL_GPU_FAMILY_APPLE_8: u32 = 1008;

// Metal C API bindings
#[cfg(target_os = "ios")]
extern "C" {
    // Device creation and management
    pub fn MTLCreateSystemDefaultDevice() -> *mut MTLDevice;
    pub fn MTLCopyAllDevices() -> *mut c_void; // Returns NSArray of MTLDevice objects
    pub fn MTLDevice_getName(device: *mut MTLDevice) -> CFStringRef;
    pub fn MTLDevice_getSupportsFamily(device: *mut MTLDevice, family: u32) -> bool;
    pub fn MTLDevice_getRecommendedMaxWorkingSetSize(device: *mut MTLDevice) -> u64;
    pub fn MTLDevice_getMaxThreadsPerThreadgroup(device: *mut MTLDevice) -> MTLSize;
    pub fn MTLDevice_getRegistryID(device: *mut MTLDevice) -> u64;
    pub fn MTLDevice_getArchitecture(device: *mut MTLDevice) -> CFStringRef;

    // Multi-GPU support
    pub fn NSArray_count(array: *mut c_void) -> usize;
    pub fn NSArray_objectAtIndex(array: *mut c_void, index: usize) -> *mut MTLDevice;

    // Library and function management
    pub fn MTLDevice_newDefaultLibrary(device: *mut MTLDevice) -> *mut MTLLibrary;
    pub fn MTLDevice_newLibraryWithSource(
        device: *mut MTLDevice,
        source: *const c_char,
        options: *mut c_void,
        error: *mut *mut c_void,
    ) -> *mut MTLLibrary;
    pub fn MTLLibrary_newFunctionWithName(
        library: *mut MTLLibrary,
        name: *const c_char,
    ) -> *mut MTLFunction;
    pub fn MTLFunction_setName(function: *mut MTLFunction, name: *const c_char);

    // Pipeline state creation
    pub fn MTLDevice_newComputePipelineStateWithFunction(
        device: *mut MTLDevice,
        function: *mut MTLFunction,
        error: *mut *mut c_void,
    ) -> *mut MTLComputePipelineState;
    pub fn MTLComputePipelineState_getMaxTotalThreadsPerThreadgroup(
        state: *mut MTLComputePipelineState,
    ) -> usize;
    pub fn MTLComputePipelineState_getThreadExecutionWidth(
        state: *mut MTLComputePipelineState,
    ) -> usize;

    // Command queue and buffers
    pub fn MTLDevice_newCommandQueue(device: *mut MTLDevice) -> *mut MTLCommandQueue;
    pub fn MTLDevice_newCommandQueueWithMaxCommandBufferCount(
        device: *mut MTLDevice,
        max_buffer_count: usize,
    ) -> *mut MTLCommandQueue;
    pub fn MTLCommandQueue_commandBuffer(queue: *mut MTLCommandQueue) -> *mut MTLCommandBuffer;
    pub fn MTLCommandQueue_commandBufferWithUnretainedReferences(
        queue: *mut MTLCommandQueue,
    ) -> *mut MTLCommandBuffer;

    // Buffer management
    pub fn MTLDevice_newBufferWithLength(
        device: *mut MTLDevice,
        length: usize,
        options: c_uint,
    ) -> *mut MTLBuffer;
    pub fn MTLDevice_newBufferWithBytes(
        device: *mut MTLDevice,
        pointer: *const c_void,
        length: usize,
        options: c_uint,
    ) -> *mut MTLBuffer;
    pub fn MTLBuffer_contents(buffer: *mut MTLBuffer) -> *mut c_void;
    pub fn MTLBuffer_length(buffer: *mut MTLBuffer) -> usize;
    pub fn MTLBuffer_didModifyRange(
        buffer: *mut MTLBuffer,
        range_location: usize,
        range_length: usize,
    );

    // Compute encoding
    pub fn MTLCommandBuffer_computeCommandEncoder(
        buffer: *mut MTLCommandBuffer,
    ) -> *mut MTLComputeCommandEncoder;
    pub fn MTLComputeCommandEncoder_setComputePipelineState(
        encoder: *mut MTLComputeCommandEncoder,
        state: *mut MTLComputePipelineState,
    );
    pub fn MTLComputeCommandEncoder_setBuffer(
        encoder: *mut MTLComputeCommandEncoder,
        buffer: *mut MTLBuffer,
        offset: usize,
        index: c_uint,
    );
    pub fn MTLComputeCommandEncoder_setBytes(
        encoder: *mut MTLComputeCommandEncoder,
        bytes: *const c_void,
        length: usize,
        index: c_uint,
    );
    pub fn MTLComputeCommandEncoder_dispatchThreadgroups(
        encoder: *mut MTLComputeCommandEncoder,
        threadgroupsPerGrid: MTLSize,
        threadsPerThreadgroup: MTLSize,
    );
    pub fn MTLComputeCommandEncoder_dispatchThreads(
        encoder: *mut MTLComputeCommandEncoder,
        threadsPerGrid: MTLSize,
        threadsPerThreadgroup: MTLSize,
    );
    pub fn MTLComputeCommandEncoder_endEncoding(encoder: *mut MTLComputeCommandEncoder);
    pub fn MTLComputeCommandEncoder_setLabel(
        encoder: *mut MTLComputeCommandEncoder,
        label: *const c_char,
    );

    // Command execution and synchronization
    pub fn MTLCommandBuffer_commit(buffer: *mut MTLCommandBuffer);
    pub fn MTLCommandBuffer_waitUntilCompleted(buffer: *mut MTLCommandBuffer);
    pub fn MTLCommandBuffer_waitUntilScheduled(buffer: *mut MTLCommandBuffer);
    pub fn MTLCommandBuffer_addCompletedHandler(
        buffer: *mut MTLCommandBuffer,
        handler: extern "C" fn(*mut MTLCommandBuffer),
    );
    pub fn MTLCommandBuffer_addScheduledHandler(
        buffer: *mut MTLCommandBuffer,
        handler: extern "C" fn(*mut MTLCommandBuffer),
    );
    pub fn MTLCommandBuffer_enqueue(buffer: *mut MTLCommandBuffer);
    pub fn MTLCommandBuffer_setLabel(buffer: *mut MTLCommandBuffer, label: *const c_char);

    // Performance and debugging
    pub fn MTLCommandBuffer_GPUStartTime(buffer: *mut MTLCommandBuffer) -> f64;
    pub fn MTLCommandBuffer_GPUEndTime(buffer: *mut MTLCommandBuffer) -> f64;
    pub fn MTLCommandBuffer_kernelStartTime(buffer: *mut MTLCommandBuffer) -> f64;
    pub fn MTLCommandBuffer_kernelEndTime(buffer: *mut MTLCommandBuffer) -> f64;

    // Memory management and cleanup
    pub fn MTLDevice_release(device: *mut MTLDevice);
    pub fn MTLLibrary_release(library: *mut MTLLibrary);
    pub fn MTLFunction_release(function: *mut MTLFunction);
    pub fn MTLComputePipelineState_release(state: *mut MTLComputePipelineState);
    pub fn MTLCommandQueue_release(queue: *mut MTLCommandQueue);
    pub fn MTLCommandBuffer_release(buffer: *mut MTLCommandBuffer);
    pub fn MTLComputeCommandEncoder_release(encoder: *mut MTLComputeCommandEncoder);
    pub fn MTLBuffer_release(buffer: *mut MTLBuffer);

    // Memory pressure and optimization
    pub fn MTLDevice_currentAllocatedSize(device: *mut MTLDevice) -> usize;
    pub fn MTLDevice_hasUnifiedMemory(device: *mut MTLDevice) -> bool;
    pub fn MTLDevice_isLowPower(device: *mut MTLDevice) -> bool;
    pub fn MTLDevice_isRemovable(device: *mut MTLDevice) -> bool;
    pub fn MTLDevice_locationNumber(device: *mut MTLDevice) -> usize;
    pub fn MTLDevice_maxTransferRate(device: *mut MTLDevice) -> u64;
}

// High-level Metal wrapper types
#[cfg(target_os = "ios")]
pub struct MetalDevice {
    device: *mut MTLDevice,
    command_queue: *mut MTLCommandQueue,
    device_name: String,
    supports_apple_gpu: bool,
    max_working_set_size: u64,
    max_threads_per_threadgroup: MTLSize,
}

#[cfg(target_os = "ios")]
pub struct MetalBuffer {
    buffer: *mut MTLBuffer,
    length: usize,
}

#[cfg(target_os = "ios")]
pub struct MetalComputePipeline {
    pipeline_state: *mut MTLComputePipelineState,
    max_total_threads: usize,
    thread_execution_width: usize,
}

#[cfg(target_os = "ios")]
pub struct MetalCommandBuffer {
    command_buffer: *mut MTLCommandBuffer,
    label: Option<String>,
}

#[cfg(target_os = "ios")]
impl MetalDevice {
    /// Create Metal device from system default
    pub fn create_system_default() -> Result<Self, String> {
        unsafe {
            let device = MTLCreateSystemDefaultDevice();
            if device.is_null() {
                return Err("Failed to create Metal device".to_string());
            }

            let command_queue = MTLDevice_newCommandQueue(device);
            if command_queue.is_null() {
                MTLDevice_release(device);
                return Err("Failed to create command queue".to_string());
            }

            let name_ref = MTLDevice_getName(device);
            let device_name = if !name_ref.is_null() {
                CFString::from_CFTypeRef(name_ref as CFTypeRef).to_string()
            } else {
                "Unknown Device".to_string()
            };

            let supports_apple_gpu = MTLDevice_getSupportsFamily(device, MTL_GPU_FAMILY_APPLE_1);
            let max_working_set_size = MTLDevice_getRecommendedMaxWorkingSetSize(device);
            let max_threads_per_threadgroup = MTLDevice_getMaxThreadsPerThreadgroup(device);

            Ok(Self {
                device,
                command_queue,
                device_name,
                supports_apple_gpu,
                max_working_set_size,
                max_threads_per_threadgroup,
            })
        }
    }

    /// Get all available Metal devices
    pub fn get_all_devices() -> Result<Vec<Self>, String> {
        unsafe {
            let devices_array = MTLCopyAllDevices();
            if devices_array.is_null() {
                return Err("Failed to get Metal devices".to_string());
            }

            let device_count = NSArray_count(devices_array);
            let mut devices = Vec::with_capacity(device_count);

            for i in 0..device_count {
                let device = NSArray_objectAtIndex(devices_array, i);
                if !device.is_null() {
                    let command_queue = MTLDevice_newCommandQueue(device);
                    if !command_queue.is_null() {
                        let name_ref = MTLDevice_getName(device);
                        let device_name = if !name_ref.is_null() {
                            CFString::from_CFTypeRef(name_ref as CFTypeRef).to_string()
                        } else {
                            format!("Device {}", i)
                        };

                        let supports_apple_gpu =
                            MTLDevice_getSupportsFamily(device, MTL_GPU_FAMILY_APPLE_1);
                        let max_working_set_size =
                            MTLDevice_getRecommendedMaxWorkingSetSize(device);
                        let max_threads_per_threadgroup =
                            MTLDevice_getMaxThreadsPerThreadgroup(device);

                        devices.push(Self {
                            device,
                            command_queue,
                            device_name,
                            supports_apple_gpu,
                            max_working_set_size,
                            max_threads_per_threadgroup,
                        });
                    }
                }
            }

            // Note: devices_array should be released, but we'll let ARC handle it
            Ok(devices)
        }
    }

    /// Create buffer with data
    pub fn create_buffer_with_data(&self, data: &[u8]) -> Result<MetalBuffer, String> {
        unsafe {
            let buffer = MTLDevice_newBufferWithBytes(
                self.device,
                data.as_ptr() as *const c_void,
                data.len(),
                MTL_RESOURCE_STORAGE_MODE_SHARED,
            );

            if buffer.is_null() {
                return Err("Failed to create Metal buffer".to_string());
            }

            Ok(MetalBuffer {
                buffer,
                length: data.len(),
            })
        }
    }

    /// Create buffer with size
    pub fn create_buffer_with_size(&self, size: usize) -> Result<MetalBuffer, String> {
        unsafe {
            let buffer =
                MTLDevice_newBufferWithLength(self.device, size, MTL_RESOURCE_STORAGE_MODE_SHARED);

            if buffer.is_null() {
                return Err("Failed to create Metal buffer".to_string());
            }

            Ok(MetalBuffer {
                buffer,
                length: size,
            })
        }
    }

    /// Create compute pipeline from source
    pub fn create_compute_pipeline_from_source(
        &self,
        source: &str,
        function_name: &str,
    ) -> Result<MetalComputePipeline, String> {
        unsafe {
            let source_cstr = CString::new(source).map_err(|e| format!("Invalid source: {}", e))?;
            let function_name_cstr =
                CString::new(function_name).map_err(|e| format!("Invalid function name: {}", e))?;

            let mut error: *mut c_void = ptr::null_mut();
            let library = MTLDevice_newLibraryWithSource(
                self.device,
                source_cstr.as_ptr(),
                ptr::null_mut(),
                &mut error,
            );

            if library.is_null() {
                return Err("Failed to create Metal library".to_string());
            }

            let function = MTLLibrary_newFunctionWithName(library, function_name_cstr.as_ptr());
            if function.is_null() {
                MTLLibrary_release(library);
                return Err(format!("Failed to find function: {}", function_name));
            }

            let pipeline_state =
                MTLDevice_newComputePipelineStateWithFunction(self.device, function, &mut error);

            MTLFunction_release(function);
            MTLLibrary_release(library);

            if pipeline_state.is_null() {
                return Err("Failed to create compute pipeline state".to_string());
            }

            let max_total_threads =
                MTLComputePipelineState_getMaxTotalThreadsPerThreadgroup(pipeline_state);
            let thread_execution_width =
                MTLComputePipelineState_getThreadExecutionWidth(pipeline_state);

            Ok(MetalComputePipeline {
                pipeline_state,
                max_total_threads,
                thread_execution_width,
            })
        }
    }

    /// Create command buffer
    pub fn create_command_buffer(&self) -> Result<MetalCommandBuffer, String> {
        unsafe {
            let command_buffer = MTLCommandQueue_commandBuffer(self.command_queue);
            if command_buffer.is_null() {
                return Err("Failed to create command buffer".to_string());
            }

            Ok(MetalCommandBuffer {
                command_buffer,
                label: None,
            })
        }
    }

    /// Get device information
    pub fn get_device_info(&self) -> MetalDeviceInfo {
        unsafe {
            MetalDeviceInfo {
                name: self.device_name.clone(),
                supports_apple_gpu: self.supports_apple_gpu,
                max_working_set_size: self.max_working_set_size,
                max_threads_per_threadgroup: self.max_threads_per_threadgroup,
                current_allocated_size: MTLDevice_currentAllocatedSize(self.device),
                has_unified_memory: MTLDevice_hasUnifiedMemory(self.device),
                is_low_power: MTLDevice_isLowPower(self.device),
                is_removable: MTLDevice_isRemovable(self.device),
                location_number: MTLDevice_locationNumber(self.device),
                max_transfer_rate: MTLDevice_maxTransferRate(self.device),
                registry_id: MTLDevice_getRegistryID(self.device),
                architecture: {
                    let arch_ref = MTLDevice_getArchitecture(self.device);
                    if !arch_ref.is_null() {
                        CFString::from_CFTypeRef(arch_ref as CFTypeRef).to_string()
                    } else {
                        "Unknown".to_string()
                    }
                },
            }
        }
    }
}

#[cfg(target_os = "ios")]
impl Drop for MetalDevice {
    fn drop(&mut self) {
        unsafe {
            if !self.command_queue.is_null() {
                MTLCommandQueue_release(self.command_queue);
            }
            if !self.device.is_null() {
                MTLDevice_release(self.device);
            }
        }
    }
}

#[cfg(target_os = "ios")]
impl MetalBuffer {
    /// Get buffer contents as mutable slice
    pub fn contents_mut<T>(&mut self) -> &mut [T] {
        unsafe {
            let ptr = MTLBuffer_contents(self.buffer) as *mut T;
            let len = self.length / std::mem::size_of::<T>();
            std::slice::from_raw_parts_mut(ptr, len)
        }
    }

    /// Get buffer contents as slice
    pub fn contents<T>(&self) -> &[T] {
        unsafe {
            let ptr = MTLBuffer_contents(self.buffer) as *const T;
            let len = self.length / std::mem::size_of::<T>();
            std::slice::from_raw_parts(ptr, len)
        }
    }

    /// Mark buffer range as modified
    pub fn did_modify_range(&self, location: usize, length: usize) {
        unsafe {
            MTLBuffer_didModifyRange(self.buffer, location, length);
        }
    }

    /// Get buffer length
    pub fn length(&self) -> usize {
        self.length
    }
}

#[cfg(target_os = "ios")]
impl Drop for MetalBuffer {
    fn drop(&mut self) {
        unsafe {
            if !self.buffer.is_null() {
                MTLBuffer_release(self.buffer);
            }
        }
    }
}

#[cfg(target_os = "ios")]
impl MetalComputePipeline {
    /// Get maximum total threads per threadgroup
    pub fn max_total_threads_per_threadgroup(&self) -> usize {
        self.max_total_threads
    }

    /// Get thread execution width
    pub fn thread_execution_width(&self) -> usize {
        self.thread_execution_width
    }
}

#[cfg(target_os = "ios")]
impl Drop for MetalComputePipeline {
    fn drop(&mut self) {
        unsafe {
            if !self.pipeline_state.is_null() {
                MTLComputePipelineState_release(self.pipeline_state);
            }
        }
    }
}

#[cfg(target_os = "ios")]
impl MetalCommandBuffer {
    /// Create compute command encoder
    pub fn create_compute_encoder(&self) -> Result<MetalComputeEncoder, String> {
        unsafe {
            let encoder = MTLCommandBuffer_computeCommandEncoder(self.command_buffer);
            if encoder.is_null() {
                return Err("Failed to create compute command encoder".to_string());
            }

            Ok(MetalComputeEncoder { encoder })
        }
    }

    /// Set command buffer label
    pub fn set_label(&mut self, label: &str) {
        self.label = Some(label.to_string());
        let label_cstr = CString::new(label).expect("label should not contain null bytes");
        unsafe {
            MTLCommandBuffer_setLabel(self.command_buffer, label_cstr.as_ptr());
        }
    }

    /// Commit command buffer
    pub fn commit(&self) {
        unsafe {
            MTLCommandBuffer_commit(self.command_buffer);
        }
    }

    /// Wait until completed
    pub fn wait_until_completed(&self) {
        unsafe {
            MTLCommandBuffer_waitUntilCompleted(self.command_buffer);
        }
    }

    /// Get GPU execution times
    pub fn get_gpu_times(&self) -> (f64, f64) {
        unsafe {
            let start_time = MTLCommandBuffer_GPUStartTime(self.command_buffer);
            let end_time = MTLCommandBuffer_GPUEndTime(self.command_buffer);
            (start_time, end_time)
        }
    }
}

#[cfg(target_os = "ios")]
impl Drop for MetalCommandBuffer {
    fn drop(&mut self) {
        unsafe {
            if !self.command_buffer.is_null() {
                MTLCommandBuffer_release(self.command_buffer);
            }
        }
    }
}

/// Metal compute command encoder wrapper
#[cfg(target_os = "ios")]
pub struct MetalComputeEncoder {
    encoder: *mut MTLComputeCommandEncoder,
}

#[cfg(target_os = "ios")]
impl MetalComputeEncoder {
    /// Set compute pipeline state
    pub fn set_compute_pipeline_state(&self, pipeline: &MetalComputePipeline) {
        unsafe {
            MTLComputeCommandEncoder_setComputePipelineState(self.encoder, pipeline.pipeline_state);
        }
    }

    /// Set buffer at index
    pub fn set_buffer(&self, buffer: &MetalBuffer, offset: usize, index: u32) {
        unsafe {
            MTLComputeCommandEncoder_setBuffer(self.encoder, buffer.buffer, offset, index);
        }
    }

    /// Set bytes at index
    pub fn set_bytes(&self, bytes: &[u8], index: u32) {
        unsafe {
            MTLComputeCommandEncoder_setBytes(
                self.encoder,
                bytes.as_ptr() as *const c_void,
                bytes.len(),
                index,
            );
        }
    }

    /// Dispatch threadgroups
    pub fn dispatch_threadgroups(
        &self,
        threadgroups_per_grid: MTLSize,
        threads_per_threadgroup: MTLSize,
    ) {
        unsafe {
            MTLComputeCommandEncoder_dispatchThreadgroups(
                self.encoder,
                threadgroups_per_grid,
                threads_per_threadgroup,
            );
        }
    }

    /// Dispatch threads (iOS 11+)
    pub fn dispatch_threads(&self, threads_per_grid: MTLSize, threads_per_threadgroup: MTLSize) {
        unsafe {
            MTLComputeCommandEncoder_dispatchThreads(
                self.encoder,
                threads_per_grid,
                threads_per_threadgroup,
            );
        }
    }

    /// Set encoder label
    pub fn set_label(&self, label: &str) {
        let label_cstr = CString::new(label).expect("label should not contain null bytes");
        unsafe {
            MTLComputeCommandEncoder_setLabel(self.encoder, label_cstr.as_ptr());
        }
    }

    /// End encoding
    pub fn end_encoding(&self) {
        unsafe {
            MTLComputeCommandEncoder_endEncoding(self.encoder);
        }
    }
}

#[cfg(target_os = "ios")]
impl Drop for MetalComputeEncoder {
    fn drop(&mut self) {
        unsafe {
            if !self.encoder.is_null() {
                MTLComputeCommandEncoder_release(self.encoder);
            }
        }
    }
}

/// Metal device information
#[derive(Debug, Clone)]
pub struct MetalDeviceInfo {
    pub name: String,
    pub supports_apple_gpu: bool,
    pub max_working_set_size: u64,
    pub max_threads_per_threadgroup: MTLSize,
    pub current_allocated_size: usize,
    pub has_unified_memory: bool,
    pub is_low_power: bool,
    pub is_removable: bool,
    pub location_number: usize,
    pub max_transfer_rate: u64,
    pub registry_id: u64,
    pub architecture: String,
}

/// Utility functions for Metal size calculations
impl MTLSize {
    /// Create new MTLSize
    pub fn new(width: usize, height: usize, depth: usize) -> Self {
        Self {
            width,
            height,
            depth,
        }
    }

    /// Create 1D size
    pub fn new_1d(width: usize) -> Self {
        Self {
            width,
            height: 1,
            depth: 1,
        }
    }

    /// Create 2D size
    pub fn new_2d(width: usize, height: usize) -> Self {
        Self {
            width,
            height,
            depth: 1,
        }
    }

    /// Get total size
    pub fn total(&self) -> usize {
        self.width * self.height * self.depth
    }
}

impl MTLOrigin {
    /// Create new MTLOrigin
    pub fn new(x: usize, y: usize, z: usize) -> Self {
        Self { x, y, z }
    }

    /// Create zero origin
    pub fn zero() -> Self {
        Self { x: 0, y: 0, z: 0 }
    }
}

impl MTLRegion {
    /// Create new MTLRegion
    pub fn new(origin: MTLOrigin, size: MTLSize) -> Self {
        Self { origin, size }
    }

    /// Create region from size with zero origin
    pub fn from_size(size: MTLSize) -> Self {
        Self {
            origin: MTLOrigin::zero(),
            size,
        }
    }
}

// Non-iOS stub implementations
#[cfg(not(target_os = "ios"))]
pub struct MetalDevice;

#[cfg(not(target_os = "ios"))]
pub struct MetalBuffer;

#[cfg(not(target_os = "ios"))]
pub struct MetalComputePipeline;

#[cfg(not(target_os = "ios"))]
pub struct MetalCommandBuffer;

#[cfg(not(target_os = "ios"))]
pub struct MetalComputeEncoder;

#[cfg(not(target_os = "ios"))]
#[derive(Debug, Clone)]
pub struct MetalDeviceInfo {
    pub name: String,
}

#[cfg(not(target_os = "ios"))]
impl MetalDevice {
    pub fn create_system_default() -> Result<Self, String> {
        Err("Metal not available on this platform".to_string())
    }

    pub fn get_all_devices() -> Result<Vec<Self>, String> {
        Err("Metal not available on this platform".to_string())
    }
}