1use std::ffi::{c_void, CStr};
72use std::ptr::NonNull;
73
74use crate::cm::IOSurface;
75use crate::FourCharCode;
76
77pub mod pixel_format {
81 use crate::FourCharCode;
82
83 pub const BGRA: FourCharCode = FourCharCode::from_bytes(*b"BGRA");
85
86 pub const L10R: FourCharCode = FourCharCode::from_bytes(*b"l10r");
88
89 pub const YCBCR_420V: FourCharCode = FourCharCode::from_bytes(*b"420v");
91
92 pub const YCBCR_420F: FourCharCode = FourCharCode::from_bytes(*b"420f");
94
95 #[must_use]
99 pub fn is_ycbcr_biplanar(format: impl Into<FourCharCode>) -> bool {
100 let f = format.into();
101 f.equals(YCBCR_420V) || f.equals(YCBCR_420F)
102 }
103
104 #[must_use]
108 pub fn is_full_range(format: impl Into<FourCharCode>) -> bool {
109 format.into().equals(YCBCR_420F)
110 }
111}
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
117#[repr(u64)]
118pub enum MetalPixelFormat {
119 BGRA8Unorm = 80,
121 BGR10A2Unorm = 94,
123 R8Unorm = 10,
125 RG8Unorm = 30,
127}
128
129impl MetalPixelFormat {
130 #[must_use]
132 pub const fn raw(self) -> u64 {
133 self as u64
134 }
135
136 #[must_use]
138 pub const fn from_raw(value: u64) -> Option<Self> {
139 match value {
140 80 => Some(Self::BGRA8Unorm),
141 94 => Some(Self::BGR10A2Unorm),
142 10 => Some(Self::R8Unorm),
143 30 => Some(Self::RG8Unorm),
144 _ => None,
145 }
146 }
147}
148
149#[derive(Debug, Clone)]
151pub struct IOSurfaceInfo {
152 pub width: usize,
154 pub height: usize,
156 pub bytes_per_row: usize,
158 pub pixel_format: FourCharCode,
160 pub plane_count: usize,
162 pub planes: Vec<PlaneInfo>,
164}
165
166#[derive(Debug, Clone)]
168pub struct PlaneInfo {
169 pub index: usize,
171 pub width: usize,
173 pub height: usize,
175 pub bytes_per_row: usize,
177}
178
179#[derive(Debug, Clone, Copy)]
183pub struct TextureParams {
184 pub width: usize,
186 pub height: usize,
188 pub format: MetalPixelFormat,
190 pub plane: usize,
192}
193
194impl TextureParams {
195 #[must_use]
197 pub const fn metal_pixel_format(&self) -> u64 {
198 self.format.raw()
199 }
200}
201
202#[derive(Debug)]
204pub struct CapturedTextures<T> {
205 pub plane0: T,
207 pub plane1: Option<T>,
209 pub pixel_format: FourCharCode,
211 pub width: usize,
213 pub height: usize,
215}
216
217impl<T> CapturedTextures<T> {
218 #[must_use]
220 pub fn is_ycbcr(&self) -> bool {
221 pixel_format::is_ycbcr_biplanar(self.pixel_format)
222 }
223}
224
225pub const SHADER_SOURCE: &str = r"
247#include <metal_stdlib>
248using namespace metal;
249
250struct Uniforms {
251 float2 viewport_size;
252 float2 texture_size;
253 float time;
254 uint pixel_format;
255 float padding[2];
256};
257
258struct TexturedVertexOut {
259 float4 position [[position]];
260 float2 texcoord;
261};
262
263// Fullscreen quad vertex shader with aspect ratio correction
264vertex TexturedVertexOut vertex_fullscreen(uint vid [[vertex_id]], constant Uniforms& uniforms [[buffer(0)]]) {
265 TexturedVertexOut out;
266 float va = uniforms.viewport_size.x / uniforms.viewport_size.y;
267 float ta = uniforms.texture_size.x / uniforms.texture_size.y;
268 float sx = ta > va ? 1.0 : ta / va;
269 float sy = ta > va ? va / ta : 1.0;
270 float2 positions[4] = { float2(-sx, -sy), float2(sx, -sy), float2(-sx, sy), float2(sx, sy) };
271 float2 texcoords[4] = { float2(0.0, 1.0), float2(1.0, 1.0), float2(0.0, 0.0), float2(1.0, 0.0) };
272 out.position = float4(positions[vid], 0.0, 1.0);
273 out.texcoord = texcoords[vid];
274 return out;
275}
276
277// BGRA/RGB texture fragment shader
278fragment float4 fragment_textured(TexturedVertexOut in [[stage_in]], texture2d<float> tex [[texture(0)]]) {
279 constexpr sampler s(mag_filter::linear, min_filter::linear);
280 return tex.sample(s, in.texcoord);
281}
282
283// YCbCr to RGB conversion (BT.709 matrix for HD video)
284float4 ycbcr_to_rgb(float y, float2 cbcr, bool full_range) {
285 float y_adj = full_range ? y : (y - 16.0/255.0) * (255.0/219.0);
286 float cb = cbcr.x - 0.5;
287 float cr = cbcr.y - 0.5;
288 // BT.709 conversion matrix
289 float r = y_adj + 1.5748 * cr;
290 float g = y_adj - 0.1873 * cb - 0.4681 * cr;
291 float b = y_adj + 1.8556 * cb;
292 return float4(saturate(float3(r, g, b)), 1.0);
293}
294
295// YCbCr biplanar (420v/420f) fragment shader
296fragment float4 fragment_ycbcr(TexturedVertexOut in [[stage_in]],
297 texture2d<float> y_tex [[texture(0)]],
298 texture2d<float> cbcr_tex [[texture(1)]],
299 constant Uniforms& uniforms [[buffer(0)]]) {
300 constexpr sampler s(mag_filter::linear, min_filter::linear);
301 float y = y_tex.sample(s, in.texcoord).r;
302 float2 cbcr = cbcr_tex.sample(s, in.texcoord).rg;
303 bool full_range = (uniforms.pixel_format == 0x34323066); // '420f'
304 return ycbcr_to_rgb(y, cbcr, full_range);
305}
306
307// Colored vertex input/output for UI overlays
308struct ColoredVertex {
309 float2 position [[attribute(0)]];
310 float4 color [[attribute(1)]];
311};
312
313struct ColoredVertexOut {
314 float4 position [[position]];
315 float4 color;
316};
317
318// Colored vertex shader for UI elements (position in pixels, converted to NDC)
319vertex ColoredVertexOut vertex_colored(ColoredVertex in [[stage_in]], constant Uniforms& uniforms [[buffer(1)]]) {
320 ColoredVertexOut out;
321 float2 ndc = (in.position / uniforms.viewport_size) * 2.0 - 1.0;
322 ndc.y = -ndc.y;
323 out.position = float4(ndc, 0.0, 1.0);
324 out.color = in.color;
325 return out;
326}
327
328// Colored fragment shader for UI elements
329fragment float4 fragment_colored(ColoredVertexOut in [[stage_in]]) {
330 return in.color;
331}
332";
333
334#[repr(C)]
338#[derive(Debug, Clone, Copy, Default)]
339pub struct Uniforms {
340 pub viewport_size: [f32; 2],
342 pub texture_size: [f32; 2],
344 pub time: f32,
346 pub pixel_format: u32,
348 #[doc(hidden)]
350 pub _padding: [f32; 2],
351}
352
353impl Uniforms {
354 #[must_use]
356 pub fn new(
357 viewport_width: f32,
358 viewport_height: f32,
359 texture_width: f32,
360 texture_height: f32,
361 ) -> Self {
362 Self {
363 viewport_size: [viewport_width, viewport_height],
364 texture_size: [texture_width, texture_height],
365 time: 0.0,
366 pixel_format: 0,
367 _padding: [0.0; 2],
368 }
369 }
370
371 #[must_use]
388 #[allow(clippy::cast_precision_loss)] pub fn from_captured_textures<T>(
390 viewport_width: f32,
391 viewport_height: f32,
392 textures: &CapturedTextures<T>,
393 ) -> Self {
394 Self {
395 viewport_size: [viewport_width, viewport_height],
396 texture_size: [textures.width as f32, textures.height as f32],
397 time: 0.0,
398 pixel_format: textures.pixel_format.as_u32(),
399 _padding: [0.0; 2],
400 }
401 }
402
403 #[must_use]
413 pub fn with_pixel_format(mut self, format: impl Into<FourCharCode>) -> Self {
414 self.pixel_format = format.into().as_u32();
415 self
416 }
417
418 #[must_use]
420 pub fn with_time(mut self, time: f32) -> Self {
421 self.time = time;
422 self
423 }
424}
425
426#[link(name = "Metal", kind = "framework")]
429extern "C" {}
430
431#[link(name = "QuartzCore", kind = "framework")]
432extern "C" {}
433
434extern "C" {
435 fn metal_create_system_default_device() -> *mut c_void;
437 fn metal_device_release(device: *mut c_void);
438 fn metal_device_get_name(device: *mut c_void) -> *const std::ffi::c_char;
439 fn metal_device_retain(device: *mut c_void) -> *mut c_void;
440 fn metal_string_free(ptr: *mut std::ffi::c_char);
441 fn metal_device_create_command_queue(device: *mut c_void) -> *mut c_void;
442 fn metal_device_create_render_pipeline_state(
443 device: *mut c_void,
444 desc: *mut c_void,
445 ) -> *mut c_void;
446
447 fn metal_create_texture_from_iosurface(
449 device: *mut c_void,
450 iosurface: *mut c_void,
451 plane: usize,
452 width: usize,
453 height: usize,
454 pixel_format: u64,
455 ) -> *mut c_void;
456 fn metal_texture_release(texture: *mut c_void);
457 fn metal_texture_retain(texture: *mut c_void) -> *mut c_void;
458 fn metal_texture_get_width(texture: *mut c_void) -> usize;
459 fn metal_texture_get_height(texture: *mut c_void) -> usize;
460 fn metal_texture_get_pixel_format(texture: *mut c_void) -> u64;
461
462 fn metal_command_queue_release(queue: *mut c_void);
464 fn metal_command_queue_command_buffer(queue: *mut c_void) -> *mut c_void;
465
466 fn metal_device_create_library_with_source(
468 device: *mut c_void,
469 source: *const std::ffi::c_char,
470 error_out: *mut *const std::ffi::c_char,
471 ) -> *mut c_void;
472 fn metal_library_release(library: *mut c_void);
473 fn metal_library_get_function(
474 library: *mut c_void,
475 name: *const std::ffi::c_char,
476 ) -> *mut c_void;
477 fn metal_function_release(function: *mut c_void);
478
479 fn metal_device_create_buffer(device: *mut c_void, length: usize, options: u64) -> *mut c_void;
481 fn metal_buffer_contents(buffer: *mut c_void) -> *mut c_void;
482 fn metal_buffer_length(buffer: *mut c_void) -> usize;
483 fn metal_buffer_did_modify_range(buffer: *mut c_void, location: usize, length: usize);
484 fn metal_buffer_release(buffer: *mut c_void);
485
486 fn metal_layer_create() -> *mut c_void;
488 fn metal_layer_set_device(layer: *mut c_void, device: *mut c_void);
489 fn metal_layer_set_pixel_format(layer: *mut c_void, format: u64);
490 fn metal_layer_set_drawable_size(layer: *mut c_void, width: f64, height: f64);
491 fn metal_layer_set_presents_with_transaction(layer: *mut c_void, value: bool);
492 fn metal_layer_next_drawable(layer: *mut c_void) -> *mut c_void;
493 fn metal_layer_release(layer: *mut c_void);
494
495 fn metal_drawable_texture(drawable: *mut c_void) -> *mut c_void;
497 fn metal_drawable_release(drawable: *mut c_void);
498
499 fn metal_command_buffer_present_drawable(cmd_buffer: *mut c_void, drawable: *mut c_void);
501 fn metal_command_buffer_commit(cmd_buffer: *mut c_void);
502 fn metal_command_buffer_release(cmd_buffer: *mut c_void);
503
504 fn metal_render_pass_descriptor_create() -> *mut c_void;
506 fn metal_render_pass_set_color_attachment_texture(
507 desc: *mut c_void,
508 index: usize,
509 texture: *mut c_void,
510 );
511 fn metal_render_pass_set_color_attachment_load_action(
512 desc: *mut c_void,
513 index: usize,
514 action: u64,
515 );
516 fn metal_render_pass_set_color_attachment_store_action(
517 desc: *mut c_void,
518 index: usize,
519 action: u64,
520 );
521 fn metal_render_pass_set_color_attachment_clear_color(
522 desc: *mut c_void,
523 index: usize,
524 r: f64,
525 g: f64,
526 b: f64,
527 a: f64,
528 );
529 fn metal_render_pass_descriptor_release(desc: *mut c_void);
530
531 fn metal_vertex_descriptor_create() -> *mut c_void;
533 fn metal_vertex_descriptor_set_attribute(
534 desc: *mut c_void,
535 index: usize,
536 format: u64,
537 offset: usize,
538 buffer_index: usize,
539 );
540 fn metal_vertex_descriptor_set_layout(
541 desc: *mut c_void,
542 buffer_index: usize,
543 stride: usize,
544 step_function: u64,
545 );
546 fn metal_vertex_descriptor_release(desc: *mut c_void);
547
548 fn metal_render_pipeline_descriptor_create() -> *mut c_void;
550 fn metal_render_pipeline_descriptor_set_vertex_function(
551 desc: *mut c_void,
552 function: *mut c_void,
553 );
554 fn metal_render_pipeline_descriptor_set_fragment_function(
555 desc: *mut c_void,
556 function: *mut c_void,
557 );
558 fn metal_render_pipeline_descriptor_set_vertex_descriptor(
559 desc: *mut c_void,
560 vertex_descriptor: *mut c_void,
561 );
562 fn metal_render_pipeline_descriptor_set_color_attachment_pixel_format(
563 desc: *mut c_void,
564 index: usize,
565 format: u64,
566 );
567 fn metal_render_pipeline_descriptor_set_blending_enabled(
568 desc: *mut c_void,
569 index: usize,
570 enabled: bool,
571 );
572 fn metal_render_pipeline_descriptor_set_blend_operations(
573 desc: *mut c_void,
574 index: usize,
575 rgb_op: u64,
576 alpha_op: u64,
577 );
578 fn metal_render_pipeline_descriptor_set_blend_factors(
579 desc: *mut c_void,
580 index: usize,
581 src_rgb: u64,
582 dst_rgb: u64,
583 src_alpha: u64,
584 dst_alpha: u64,
585 );
586 fn metal_render_pipeline_descriptor_release(desc: *mut c_void);
587 fn metal_render_pipeline_state_release(state: *mut c_void);
588
589 fn metal_command_buffer_render_command_encoder(
591 cmd_buffer: *mut c_void,
592 render_pass: *mut c_void,
593 ) -> *mut c_void;
594 fn metal_render_encoder_set_pipeline_state(encoder: *mut c_void, state: *mut c_void);
595 fn metal_render_encoder_set_vertex_buffer(
596 encoder: *mut c_void,
597 buffer: *mut c_void,
598 offset: usize,
599 index: usize,
600 );
601 fn metal_render_encoder_set_fragment_buffer(
602 encoder: *mut c_void,
603 buffer: *mut c_void,
604 offset: usize,
605 index: usize,
606 );
607 fn metal_render_encoder_set_fragment_texture(
608 encoder: *mut c_void,
609 texture: *mut c_void,
610 index: usize,
611 );
612 fn metal_render_encoder_draw_primitives(
613 encoder: *mut c_void,
614 primitive_type: u64,
615 vertex_start: usize,
616 vertex_count: usize,
617 );
618 fn metal_render_encoder_end_encoding(encoder: *mut c_void);
619 fn metal_render_encoder_release(encoder: *mut c_void);
620
621 fn nsview_set_wants_layer(view: *mut c_void);
623 fn nsview_set_layer(view: *mut c_void, layer: *mut c_void);
624}
625
626#[derive(Debug)]
632pub struct MetalDevice {
633 ptr: NonNull<c_void>,
634 owned: bool,
637}
638
639impl MetalDevice {
640 #[must_use]
644 pub fn system_default() -> Option<Self> {
645 let ptr = unsafe { metal_create_system_default_device() };
646 NonNull::new(ptr).map(|ptr| Self { ptr, owned: true })
647 }
648
649 #[must_use]
661 pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> {
662 NonNull::new(ptr).map(|ptr| Self { ptr, owned: false })
663 }
664
665 #[must_use]
675 pub unsafe fn from_ptr_retained(ptr: *mut c_void) -> Option<Self> {
676 if ptr.is_null() {
677 return None;
678 }
679 let retained = unsafe { metal_device_retain(ptr) };
680 NonNull::new(retained).map(|ptr| Self { ptr, owned: true })
681 }
682
683 #[must_use]
685 pub fn name(&self) -> String {
686 unsafe {
687 let name_ptr = metal_device_get_name(self.ptr.as_ptr());
688 if name_ptr.is_null() {
689 return String::new();
690 }
691 let name = CStr::from_ptr(name_ptr).to_string_lossy().into_owned();
692 metal_string_free(name_ptr.cast_mut());
694 name
695 }
696 }
697
698 #[must_use]
700 pub fn create_command_queue(&self) -> Option<MetalCommandQueue> {
701 let ptr = unsafe { metal_device_create_command_queue(self.ptr.as_ptr()) };
702 NonNull::new(ptr).map(|ptr| MetalCommandQueue { ptr })
703 }
704
705 pub fn create_library_with_source(&self, source: &str) -> Result<MetalLibrary, String> {
710 use std::ffi::CString;
711 let source_c = CString::new(source).map_err(|e| e.to_string())?;
712 let mut error_ptr: *const std::ffi::c_char = std::ptr::null();
713
714 let ptr = unsafe {
715 metal_device_create_library_with_source(
716 self.ptr.as_ptr(),
717 source_c.as_ptr(),
718 &mut error_ptr,
719 )
720 };
721
722 NonNull::new(ptr).map_or_else(
723 || {
724 let error = if error_ptr.is_null() {
725 "Unknown shader compilation error".to_string()
726 } else {
727 let msg = unsafe { CStr::from_ptr(error_ptr).to_string_lossy().into_owned() };
728 unsafe { metal_string_free(error_ptr.cast_mut()) };
730 msg
731 };
732 Err(error)
733 },
734 |ptr| Ok(MetalLibrary { ptr }),
735 )
736 }
737
738 #[must_use]
740 pub fn create_buffer(&self, length: usize, options: ResourceOptions) -> Option<MetalBuffer> {
741 let ptr = unsafe { metal_device_create_buffer(self.ptr.as_ptr(), length, options.0) };
742 NonNull::new(ptr).map(|ptr| MetalBuffer { ptr })
743 }
744
745 #[must_use]
762 pub fn create_buffer_with_data<T>(&self, data: &T) -> Option<MetalBuffer> {
763 let size = std::mem::size_of::<T>();
764 let buffer = self.create_buffer(size, ResourceOptions::CPU_CACHE_MODE_DEFAULT_CACHE)?;
765 unsafe {
766 std::ptr::copy_nonoverlapping(
767 std::ptr::addr_of!(*data).cast::<u8>(),
768 buffer.contents().cast(),
769 size,
770 );
771 }
772 Some(buffer)
773 }
774
775 #[must_use]
777 pub fn create_render_pipeline_state(
778 &self,
779 descriptor: &MetalRenderPipelineDescriptor,
780 ) -> Option<MetalRenderPipelineState> {
781 let ptr = unsafe {
782 metal_device_create_render_pipeline_state(self.ptr.as_ptr(), descriptor.as_ptr())
783 };
784 NonNull::new(ptr).map(|ptr| MetalRenderPipelineState { ptr })
785 }
786
787 #[must_use]
789 pub fn as_ptr(&self) -> *mut c_void {
790 self.ptr.as_ptr()
791 }
792
793 #[must_use]
802 pub fn as_apple_metal(&self) -> apple_metal::ManuallyDropDevice {
803 unsafe { apple_metal::MetalDevice::from_raw_borrowed(self.ptr.as_ptr()) }
804 }
805}
806
807impl Drop for MetalDevice {
808 fn drop(&mut self) {
809 if self.owned {
810 unsafe { metal_device_release(self.ptr.as_ptr()) }
811 }
812 }
813}
814
815unsafe impl Send for MetalDevice {}
818unsafe impl Sync for MetalDevice {}
819
820#[derive(Debug)]
826pub struct MetalTexture {
827 ptr: NonNull<c_void>,
828}
829
830impl MetalTexture {
831 #[must_use]
833 pub fn width(&self) -> usize {
834 unsafe { metal_texture_get_width(self.ptr.as_ptr()) }
835 }
836
837 #[must_use]
839 pub fn height(&self) -> usize {
840 unsafe { metal_texture_get_height(self.ptr.as_ptr()) }
841 }
842
843 #[must_use]
845 pub fn pixel_format(&self) -> MetalPixelFormat {
846 let raw = unsafe { metal_texture_get_pixel_format(self.ptr.as_ptr()) };
847 MetalPixelFormat::from_raw(raw).unwrap_or(MetalPixelFormat::BGRA8Unorm)
848 }
849
850 #[must_use]
852 pub fn as_ptr(&self) -> *mut c_void {
853 self.ptr.as_ptr()
854 }
855}
856
857impl Clone for MetalTexture {
858 fn clone(&self) -> Self {
859 let ptr = unsafe { metal_texture_retain(self.ptr.as_ptr()) };
860 Self {
865 ptr: NonNull::new(ptr).unwrap_or(self.ptr),
866 }
867 }
868}
869
870impl Drop for MetalTexture {
871 fn drop(&mut self) {
872 unsafe { metal_texture_release(self.ptr.as_ptr()) }
873 }
874}
875
876unsafe impl Send for MetalTexture {}
880unsafe impl Sync for MetalTexture {}
881
882#[derive(Debug)]
886pub struct MetalCommandQueue {
887 ptr: NonNull<c_void>,
888}
889
890impl MetalCommandQueue {
891 #[must_use]
893 pub fn command_buffer(&self) -> Option<MetalCommandBuffer> {
894 let ptr = unsafe { metal_command_queue_command_buffer(self.ptr.as_ptr()) };
895 NonNull::new(ptr).map(|ptr| MetalCommandBuffer { ptr })
896 }
897
898 #[must_use]
900 pub fn as_ptr(&self) -> *mut c_void {
901 self.ptr.as_ptr()
902 }
903}
904
905impl Drop for MetalCommandQueue {
906 fn drop(&mut self) {
907 unsafe { metal_command_queue_release(self.ptr.as_ptr()) }
908 }
909}
910
911unsafe impl Send for MetalCommandQueue {}
914unsafe impl Sync for MetalCommandQueue {}
915
916#[derive(Debug)]
920pub struct MetalLibrary {
921 ptr: NonNull<c_void>,
922}
923
924impl MetalLibrary {
925 #[must_use]
927 pub fn get_function(&self, name: &str) -> Option<MetalFunction> {
928 use std::ffi::CString;
929 let name_c = CString::new(name).ok()?;
930 let ptr = unsafe { metal_library_get_function(self.ptr.as_ptr(), name_c.as_ptr()) };
931 NonNull::new(ptr).map(|ptr| MetalFunction { ptr })
932 }
933
934 #[must_use]
936 pub fn as_ptr(&self) -> *mut c_void {
937 self.ptr.as_ptr()
938 }
939}
940
941impl Drop for MetalLibrary {
942 fn drop(&mut self) {
943 unsafe { metal_library_release(self.ptr.as_ptr()) }
944 }
945}
946
947unsafe impl Send for MetalLibrary {}
950unsafe impl Sync for MetalLibrary {}
951
952#[derive(Debug)]
956pub struct MetalFunction {
957 ptr: NonNull<c_void>,
958}
959
960impl MetalFunction {
961 #[must_use]
963 pub fn as_ptr(&self) -> *mut c_void {
964 self.ptr.as_ptr()
965 }
966}
967
968impl Drop for MetalFunction {
969 fn drop(&mut self) {
970 unsafe { metal_function_release(self.ptr.as_ptr()) }
971 }
972}
973
974unsafe impl Send for MetalFunction {}
977unsafe impl Sync for MetalFunction {}
978
979#[derive(Debug)]
983pub struct MetalBuffer {
984 ptr: NonNull<c_void>,
985}
986
987#[derive(Debug, Clone, Copy, Default)]
989pub struct ResourceOptions(u64);
990
991impl ResourceOptions {
992 pub const CPU_CACHE_MODE_DEFAULT_CACHE: Self = Self(0);
994 pub const STORAGE_MODE_SHARED: Self = Self(0);
996 pub const STORAGE_MODE_MANAGED: Self = Self(1 << 4);
998}
999
1000impl MetalBuffer {
1001 #[must_use]
1003 pub fn contents(&self) -> *mut c_void {
1004 unsafe { metal_buffer_contents(self.ptr.as_ptr()) }
1005 }
1006
1007 #[must_use]
1009 pub fn length(&self) -> usize {
1010 unsafe { metal_buffer_length(self.ptr.as_ptr()) }
1011 }
1012
1013 pub fn did_modify_range(&self, range: std::ops::Range<usize>) {
1015 unsafe { metal_buffer_did_modify_range(self.ptr.as_ptr(), range.start, range.len()) }
1016 }
1017
1018 #[must_use]
1020 pub fn as_ptr(&self) -> *mut c_void {
1021 self.ptr.as_ptr()
1022 }
1023}
1024
1025impl Drop for MetalBuffer {
1026 fn drop(&mut self) {
1027 unsafe { metal_buffer_release(self.ptr.as_ptr()) }
1028 }
1029}
1030
1031unsafe impl Send for MetalBuffer {}
1036unsafe impl Sync for MetalBuffer {}
1037
1038#[derive(Debug)]
1042pub struct MetalLayer {
1043 ptr: NonNull<c_void>,
1044}
1045
1046impl MetalLayer {
1047 #[must_use]
1052 pub fn new() -> Self {
1053 let ptr = unsafe { metal_layer_create() };
1054 Self {
1055 ptr: NonNull::new(ptr).expect("metal_layer_create returned null"),
1056 }
1057 }
1058
1059 pub fn set_device(&self, device: &MetalDevice) {
1061 unsafe { metal_layer_set_device(self.ptr.as_ptr(), device.as_ptr()) }
1062 }
1063
1064 pub fn set_pixel_format(&self, format: MTLPixelFormat) {
1066 unsafe { metal_layer_set_pixel_format(self.ptr.as_ptr(), format.raw()) }
1067 }
1068
1069 pub fn set_drawable_size(&self, width: f64, height: f64) {
1071 unsafe { metal_layer_set_drawable_size(self.ptr.as_ptr(), width, height) }
1072 }
1073
1074 pub fn set_presents_with_transaction(&self, value: bool) {
1076 unsafe { metal_layer_set_presents_with_transaction(self.ptr.as_ptr(), value) }
1077 }
1078
1079 #[must_use]
1081 pub fn next_drawable(&self) -> Option<MetalDrawable> {
1082 let ptr = unsafe { metal_layer_next_drawable(self.ptr.as_ptr()) };
1083 NonNull::new(ptr).map(|ptr| MetalDrawable { ptr })
1084 }
1085
1086 #[must_use]
1088 pub fn as_ptr(&self) -> *mut c_void {
1089 self.ptr.as_ptr()
1090 }
1091}
1092
1093impl Default for MetalLayer {
1094 fn default() -> Self {
1095 Self::new()
1096 }
1097}
1098
1099impl Drop for MetalLayer {
1100 fn drop(&mut self) {
1101 unsafe { metal_layer_release(self.ptr.as_ptr()) }
1102 }
1103}
1104
1105#[derive(Debug)]
1109pub struct MetalDrawable {
1110 ptr: NonNull<c_void>,
1111}
1112
1113impl MetalDrawable {
1114 #[must_use]
1119 pub fn texture(&self) -> MetalTexture {
1120 let ptr = unsafe { metal_drawable_texture(self.ptr.as_ptr()) };
1121 let ptr = NonNull::new(ptr).expect("drawable texture is null");
1123 let retained = unsafe { metal_texture_retain(ptr.as_ptr()) };
1125 MetalTexture {
1126 ptr: NonNull::new(retained).unwrap_or(ptr),
1127 }
1128 }
1129
1130 #[must_use]
1132 pub fn as_ptr(&self) -> *mut c_void {
1133 self.ptr.as_ptr()
1134 }
1135}
1136
1137impl Drop for MetalDrawable {
1138 fn drop(&mut self) {
1139 unsafe { metal_drawable_release(self.ptr.as_ptr()) }
1140 }
1141}
1142
1143#[derive(Debug)]
1147pub struct MetalCommandBuffer {
1148 ptr: NonNull<c_void>,
1149}
1150
1151impl MetalCommandBuffer {
1152 #[must_use]
1154 pub fn render_command_encoder(
1155 &self,
1156 render_pass: &MetalRenderPassDescriptor,
1157 ) -> Option<MetalRenderCommandEncoder> {
1158 let ptr = unsafe {
1159 metal_command_buffer_render_command_encoder(self.ptr.as_ptr(), render_pass.as_ptr())
1160 };
1161 NonNull::new(ptr).map(|ptr| MetalRenderCommandEncoder { ptr })
1162 }
1163
1164 pub fn present_drawable(&self, drawable: &MetalDrawable) {
1166 unsafe { metal_command_buffer_present_drawable(self.ptr.as_ptr(), drawable.as_ptr()) }
1167 }
1168
1169 pub fn commit(&self) {
1171 unsafe { metal_command_buffer_commit(self.ptr.as_ptr()) }
1172 }
1173
1174 #[must_use]
1176 pub fn as_ptr(&self) -> *mut c_void {
1177 self.ptr.as_ptr()
1178 }
1179}
1180
1181impl Drop for MetalCommandBuffer {
1182 fn drop(&mut self) {
1183 unsafe { metal_command_buffer_release(self.ptr.as_ptr()) }
1184 }
1185}
1186
1187#[derive(Debug)]
1191pub struct MetalRenderPassDescriptor {
1192 ptr: NonNull<c_void>,
1193}
1194
1195#[derive(Debug, Clone, Copy, Default)]
1197#[repr(u64)]
1198pub enum MTLLoadAction {
1199 DontCare = 0,
1201 Load = 1,
1203 #[default]
1205 Clear = 2,
1206}
1207
1208#[derive(Debug, Clone, Copy, Default)]
1210#[repr(u64)]
1211pub enum MTLStoreAction {
1212 DontCare = 0,
1214 #[default]
1216 Store = 1,
1217}
1218
1219#[derive(Debug, Clone, Copy, Default)]
1221#[repr(u64)]
1222pub enum MTLPixelFormat {
1223 Invalid = 0,
1225 #[default]
1227 BGRA8Unorm = 80,
1228 BGR10A2Unorm = 94,
1230 R8Unorm = 10,
1232 RG8Unorm = 30,
1234}
1235
1236impl MTLPixelFormat {
1237 #[must_use]
1239 pub const fn raw(self) -> u64 {
1240 self as u64
1241 }
1242}
1243
1244#[derive(Debug, Clone, Copy, Default)]
1246#[repr(u64)]
1247pub enum MTLVertexFormat {
1248 Invalid = 0,
1250 #[default]
1252 Float2 = 29,
1253 Float3 = 30,
1255 Float4 = 31,
1257}
1258
1259impl MTLVertexFormat {
1260 #[must_use]
1262 pub const fn raw(self) -> u64 {
1263 self as u64
1264 }
1265}
1266
1267#[derive(Debug, Clone, Copy, Default)]
1269#[repr(u64)]
1270pub enum MTLVertexStepFunction {
1271 Constant = 0,
1273 #[default]
1275 PerVertex = 1,
1276 PerInstance = 2,
1278}
1279
1280impl MTLVertexStepFunction {
1281 #[must_use]
1283 pub const fn raw(self) -> u64 {
1284 self as u64
1285 }
1286}
1287
1288#[derive(Debug, Clone, Copy, Default)]
1290#[repr(u64)]
1291pub enum MTLPrimitiveType {
1292 Point = 0,
1294 Line = 1,
1296 LineStrip = 2,
1298 #[default]
1300 Triangle = 3,
1301 TriangleStrip = 4,
1303}
1304
1305impl MTLPrimitiveType {
1306 #[must_use]
1308 pub const fn raw(self) -> u64 {
1309 self as u64
1310 }
1311}
1312
1313#[derive(Debug, Clone, Copy, Default)]
1315#[repr(u64)]
1316pub enum MTLBlendOperation {
1317 #[default]
1319 Add = 0,
1320 Subtract = 1,
1322 ReverseSubtract = 2,
1324 Min = 3,
1326 Max = 4,
1328}
1329
1330#[derive(Debug, Clone, Copy, Default)]
1332#[repr(u64)]
1333pub enum MTLBlendFactor {
1334 Zero = 0,
1336 #[default]
1338 One = 1,
1339 SourceColor = 2,
1341 OneMinusSourceColor = 3,
1343 SourceAlpha = 4,
1345 OneMinusSourceAlpha = 5,
1347 DestinationColor = 6,
1349 OneMinusDestinationColor = 7,
1351 DestinationAlpha = 8,
1353 OneMinusDestinationAlpha = 9,
1355}
1356
1357impl MetalRenderPassDescriptor {
1358 #[must_use]
1363 pub fn new() -> Self {
1364 let ptr = unsafe { metal_render_pass_descriptor_create() };
1365 Self {
1366 ptr: NonNull::new(ptr).expect("render pass descriptor create failed"),
1367 }
1368 }
1369
1370 pub fn set_color_attachment_texture(&self, index: usize, texture: &MetalTexture) {
1372 unsafe {
1373 metal_render_pass_set_color_attachment_texture(
1374 self.ptr.as_ptr(),
1375 index,
1376 texture.as_ptr(),
1377 );
1378 }
1379 }
1380
1381 pub fn set_color_attachment_load_action(&self, index: usize, action: MTLLoadAction) {
1383 unsafe {
1384 metal_render_pass_set_color_attachment_load_action(
1385 self.ptr.as_ptr(),
1386 index,
1387 action as u64,
1388 );
1389 }
1390 }
1391
1392 pub fn set_color_attachment_store_action(&self, index: usize, action: MTLStoreAction) {
1394 unsafe {
1395 metal_render_pass_set_color_attachment_store_action(
1396 self.ptr.as_ptr(),
1397 index,
1398 action as u64,
1399 );
1400 }
1401 }
1402
1403 pub fn set_color_attachment_clear_color(&self, index: usize, r: f64, g: f64, b: f64, a: f64) {
1405 unsafe {
1406 metal_render_pass_set_color_attachment_clear_color(
1407 self.ptr.as_ptr(),
1408 index,
1409 r,
1410 g,
1411 b,
1412 a,
1413 );
1414 }
1415 }
1416
1417 #[must_use]
1419 pub fn as_ptr(&self) -> *mut c_void {
1420 self.ptr.as_ptr()
1421 }
1422}
1423
1424impl Default for MetalRenderPassDescriptor {
1425 fn default() -> Self {
1426 Self::new()
1427 }
1428}
1429
1430impl Drop for MetalRenderPassDescriptor {
1431 fn drop(&mut self) {
1432 unsafe { metal_render_pass_descriptor_release(self.ptr.as_ptr()) }
1433 }
1434}
1435
1436#[derive(Debug)]
1440pub struct MetalVertexDescriptor {
1441 ptr: NonNull<c_void>,
1442}
1443
1444impl MetalVertexDescriptor {
1445 #[must_use]
1450 pub fn new() -> Self {
1451 let ptr = unsafe { metal_vertex_descriptor_create() };
1452 Self {
1453 ptr: NonNull::new(ptr).expect("vertex descriptor create failed"),
1454 }
1455 }
1456
1457 pub fn set_attribute(
1459 &self,
1460 index: usize,
1461 format: MTLVertexFormat,
1462 offset: usize,
1463 buffer_index: usize,
1464 ) {
1465 unsafe {
1466 metal_vertex_descriptor_set_attribute(
1467 self.ptr.as_ptr(),
1468 index,
1469 format.raw(),
1470 offset,
1471 buffer_index,
1472 );
1473 }
1474 }
1475
1476 pub fn set_layout(
1478 &self,
1479 buffer_index: usize,
1480 stride: usize,
1481 step_function: MTLVertexStepFunction,
1482 ) {
1483 unsafe {
1484 metal_vertex_descriptor_set_layout(
1485 self.ptr.as_ptr(),
1486 buffer_index,
1487 stride,
1488 step_function.raw(),
1489 );
1490 }
1491 }
1492
1493 #[must_use]
1495 pub fn as_ptr(&self) -> *mut c_void {
1496 self.ptr.as_ptr()
1497 }
1498}
1499
1500impl Default for MetalVertexDescriptor {
1501 fn default() -> Self {
1502 Self::new()
1503 }
1504}
1505
1506impl Drop for MetalVertexDescriptor {
1507 fn drop(&mut self) {
1508 unsafe { metal_vertex_descriptor_release(self.ptr.as_ptr()) }
1509 }
1510}
1511
1512#[derive(Debug)]
1516pub struct MetalRenderPipelineDescriptor {
1517 ptr: NonNull<c_void>,
1518}
1519
1520impl MetalRenderPipelineDescriptor {
1521 #[must_use]
1526 pub fn new() -> Self {
1527 let ptr = unsafe { metal_render_pipeline_descriptor_create() };
1528 Self {
1529 ptr: NonNull::new(ptr).expect("render pipeline descriptor create failed"),
1530 }
1531 }
1532
1533 pub fn set_vertex_function(&self, function: &MetalFunction) {
1535 unsafe {
1536 metal_render_pipeline_descriptor_set_vertex_function(
1537 self.ptr.as_ptr(),
1538 function.as_ptr(),
1539 );
1540 }
1541 }
1542
1543 pub fn set_fragment_function(&self, function: &MetalFunction) {
1545 unsafe {
1546 metal_render_pipeline_descriptor_set_fragment_function(
1547 self.ptr.as_ptr(),
1548 function.as_ptr(),
1549 );
1550 }
1551 }
1552
1553 pub fn set_vertex_descriptor(&self, descriptor: &MetalVertexDescriptor) {
1555 unsafe {
1556 metal_render_pipeline_descriptor_set_vertex_descriptor(
1557 self.ptr.as_ptr(),
1558 descriptor.as_ptr(),
1559 );
1560 }
1561 }
1562
1563 pub fn set_color_attachment_pixel_format(&self, index: usize, format: MTLPixelFormat) {
1565 unsafe {
1566 metal_render_pipeline_descriptor_set_color_attachment_pixel_format(
1567 self.ptr.as_ptr(),
1568 index,
1569 format.raw(),
1570 );
1571 }
1572 }
1573
1574 pub fn set_blending_enabled(&self, index: usize, enabled: bool) {
1576 unsafe {
1577 metal_render_pipeline_descriptor_set_blending_enabled(
1578 self.ptr.as_ptr(),
1579 index,
1580 enabled,
1581 );
1582 }
1583 }
1584
1585 pub fn set_blend_operations(
1587 &self,
1588 index: usize,
1589 rgb_op: MTLBlendOperation,
1590 alpha_op: MTLBlendOperation,
1591 ) {
1592 unsafe {
1593 metal_render_pipeline_descriptor_set_blend_operations(
1594 self.ptr.as_ptr(),
1595 index,
1596 rgb_op as u64,
1597 alpha_op as u64,
1598 );
1599 }
1600 }
1601
1602 pub fn set_blend_factors(
1604 &self,
1605 index: usize,
1606 src_rgb: MTLBlendFactor,
1607 dst_rgb: MTLBlendFactor,
1608 src_alpha: MTLBlendFactor,
1609 dst_alpha: MTLBlendFactor,
1610 ) {
1611 unsafe {
1612 metal_render_pipeline_descriptor_set_blend_factors(
1613 self.ptr.as_ptr(),
1614 index,
1615 src_rgb as u64,
1616 dst_rgb as u64,
1617 src_alpha as u64,
1618 dst_alpha as u64,
1619 );
1620 }
1621 }
1622
1623 #[must_use]
1625 pub fn as_ptr(&self) -> *mut c_void {
1626 self.ptr.as_ptr()
1627 }
1628}
1629
1630impl Default for MetalRenderPipelineDescriptor {
1631 fn default() -> Self {
1632 Self::new()
1633 }
1634}
1635
1636impl Drop for MetalRenderPipelineDescriptor {
1637 fn drop(&mut self) {
1638 unsafe { metal_render_pipeline_descriptor_release(self.ptr.as_ptr()) }
1639 }
1640}
1641
1642#[derive(Debug)]
1646pub struct MetalRenderPipelineState {
1647 ptr: NonNull<c_void>,
1648}
1649
1650impl MetalRenderPipelineState {
1651 #[must_use]
1653 pub fn as_ptr(&self) -> *mut c_void {
1654 self.ptr.as_ptr()
1655 }
1656}
1657
1658impl Drop for MetalRenderPipelineState {
1659 fn drop(&mut self) {
1660 unsafe { metal_render_pipeline_state_release(self.ptr.as_ptr()) }
1661 }
1662}
1663
1664unsafe impl Send for MetalRenderPipelineState {}
1667unsafe impl Sync for MetalRenderPipelineState {}
1668
1669#[derive(Debug)]
1673pub struct MetalRenderCommandEncoder {
1674 ptr: NonNull<c_void>,
1675}
1676
1677impl MetalRenderCommandEncoder {
1678 pub fn set_render_pipeline_state(&self, state: &MetalRenderPipelineState) {
1680 unsafe { metal_render_encoder_set_pipeline_state(self.ptr.as_ptr(), state.as_ptr()) }
1681 }
1682
1683 pub fn set_vertex_buffer(&self, buffer: &MetalBuffer, offset: usize, index: usize) {
1685 unsafe {
1686 metal_render_encoder_set_vertex_buffer(
1687 self.ptr.as_ptr(),
1688 buffer.as_ptr(),
1689 offset,
1690 index,
1691 );
1692 }
1693 }
1694
1695 pub fn set_fragment_buffer(&self, buffer: &MetalBuffer, offset: usize, index: usize) {
1697 unsafe {
1698 metal_render_encoder_set_fragment_buffer(
1699 self.ptr.as_ptr(),
1700 buffer.as_ptr(),
1701 offset,
1702 index,
1703 );
1704 }
1705 }
1706
1707 pub fn set_fragment_texture(&self, texture: &MetalTexture, index: usize) {
1709 unsafe {
1710 metal_render_encoder_set_fragment_texture(self.ptr.as_ptr(), texture.as_ptr(), index);
1711 }
1712 }
1713
1714 pub fn draw_primitives(
1716 &self,
1717 primitive_type: MTLPrimitiveType,
1718 vertex_start: usize,
1719 vertex_count: usize,
1720 ) {
1721 unsafe {
1722 metal_render_encoder_draw_primitives(
1723 self.ptr.as_ptr(),
1724 primitive_type.raw(),
1725 vertex_start,
1726 vertex_count,
1727 );
1728 }
1729 }
1730
1731 pub fn end_encoding(&self) {
1733 unsafe { metal_render_encoder_end_encoding(self.ptr.as_ptr()) }
1734 }
1735
1736 #[must_use]
1738 pub fn as_ptr(&self) -> *mut c_void {
1739 self.ptr.as_ptr()
1740 }
1741}
1742
1743impl Drop for MetalRenderCommandEncoder {
1744 fn drop(&mut self) {
1745 unsafe { metal_render_encoder_release(self.ptr.as_ptr()) }
1746 }
1747}
1748
1749pub type MetalCapturedTextures = CapturedTextures<MetalTexture>;
1753
1754pub trait IOSurfaceMetalExt {
1764 fn info(&self) -> IOSurfaceInfo;
1766 fn is_ycbcr_biplanar(&self) -> bool;
1768 fn texture_params(&self) -> Vec<TextureParams>;
1770 fn metal_textures<T, F>(&self, create_texture: F) -> Option<CapturedTextures<T>>
1772 where
1773 F: Fn(&TextureParams, *const c_void) -> Option<T>;
1774 fn create_metal_textures(&self, device: &MetalDevice) -> Option<MetalCapturedTextures>;
1776}
1777
1778impl IOSurfaceMetalExt for IOSurface {
1779 fn info(&self) -> IOSurfaceInfo {
1781 let width = self.width();
1782 let height = self.height();
1783 let bytes_per_row = self.bytes_per_row();
1784 let pix_format: FourCharCode = self.pixel_format().into();
1785 let plane_count = self.plane_count();
1786
1787 let planes = if plane_count > 0 {
1788 (0..plane_count)
1789 .map(|i| PlaneInfo {
1790 index: i,
1791 width: self.width_of_plane(i),
1792 height: self.height_of_plane(i),
1793 bytes_per_row: self.bytes_per_row_of_plane(i),
1794 })
1795 .collect()
1796 } else {
1797 vec![]
1798 };
1799
1800 IOSurfaceInfo {
1801 width,
1802 height,
1803 bytes_per_row,
1804 pixel_format: pix_format,
1805 plane_count,
1806 planes,
1807 }
1808 }
1809
1810 fn is_ycbcr_biplanar(&self) -> bool {
1812 pixel_format::is_ycbcr_biplanar(self.pixel_format())
1813 }
1814
1815 fn texture_params(&self) -> Vec<TextureParams> {
1821 let pix_format: FourCharCode = self.pixel_format().into();
1822 let plane_count = self.plane_count();
1823
1824 if pix_format == pixel_format::BGRA {
1825 vec![TextureParams {
1826 width: self.width(),
1827 height: self.height(),
1828 format: MetalPixelFormat::BGRA8Unorm,
1829 plane: 0,
1830 }]
1831 } else if pix_format == pixel_format::L10R {
1832 vec![TextureParams {
1833 width: self.width(),
1834 height: self.height(),
1835 format: MetalPixelFormat::BGR10A2Unorm,
1836 plane: 0,
1837 }]
1838 } else if pixel_format::is_ycbcr_biplanar(pix_format) && plane_count >= 2 {
1839 vec![
1840 TextureParams {
1842 width: self.width_of_plane(0),
1843 height: self.height_of_plane(0),
1844 format: MetalPixelFormat::R8Unorm,
1845 plane: 0,
1846 },
1847 TextureParams {
1849 width: self.width_of_plane(1),
1850 height: self.height_of_plane(1),
1851 format: MetalPixelFormat::RG8Unorm,
1852 plane: 1,
1853 },
1854 ]
1855 } else {
1856 vec![TextureParams {
1858 width: self.width(),
1859 height: self.height(),
1860 format: MetalPixelFormat::BGRA8Unorm,
1861 plane: 0,
1862 }]
1863 }
1864 }
1865
1866 fn metal_textures<T, F>(&self, create_texture: F) -> Option<CapturedTextures<T>>
1900 where
1901 F: Fn(&TextureParams, *const c_void) -> Option<T>,
1902 {
1903 let width = self.width();
1904 let height = self.height();
1905 let pix_format: FourCharCode = self.pixel_format().into();
1906
1907 if width == 0 || height == 0 {
1908 return None;
1909 }
1910
1911 let iosurface_ptr = self.as_ptr();
1912 let params = self.texture_params();
1913
1914 if params.len() == 1 {
1915 let texture = create_texture(¶ms[0], iosurface_ptr)?;
1917 Some(CapturedTextures {
1918 plane0: texture,
1919 plane1: None,
1920 pixel_format: pix_format,
1921 width,
1922 height,
1923 })
1924 } else if params.len() >= 2 {
1925 let y_texture = create_texture(¶ms[0], iosurface_ptr)?;
1927 let uv_texture = create_texture(¶ms[1], iosurface_ptr)?;
1928 Some(CapturedTextures {
1929 plane0: y_texture,
1930 plane1: Some(uv_texture),
1931 pixel_format: pix_format,
1932 width,
1933 height,
1934 })
1935 } else {
1936 None
1937 }
1938 }
1939
1940 fn create_metal_textures(&self, device: &MetalDevice) -> Option<MetalCapturedTextures> {
1960 let width = self.width();
1961 let height = self.height();
1962 let pix_format: FourCharCode = self.pixel_format().into();
1963
1964 if width == 0 || height == 0 {
1965 return None;
1966 }
1967
1968 let params = self.texture_params();
1969
1970 if params.len() == 1 {
1971 let texture = create_texture_for_plane(self, device, ¶ms[0])?;
1973 Some(CapturedTextures {
1974 plane0: texture,
1975 plane1: None,
1976 pixel_format: pix_format,
1977 width,
1978 height,
1979 })
1980 } else if params.len() >= 2 {
1981 let y_texture = create_texture_for_plane(self, device, ¶ms[0])?;
1983 let uv_texture = create_texture_for_plane(self, device, ¶ms[1])?;
1984 Some(CapturedTextures {
1985 plane0: y_texture,
1986 plane1: Some(uv_texture),
1987 pixel_format: pix_format,
1988 width,
1989 height,
1990 })
1991 } else {
1992 None
1993 }
1994 }
1995}
1996
1997fn create_texture_for_plane(
2002 surface: &IOSurface,
2003 device: &MetalDevice,
2004 params: &TextureParams,
2005) -> Option<MetalTexture> {
2006 let ptr = unsafe {
2007 metal_create_texture_from_iosurface(
2008 device.as_ptr(),
2009 surface.as_ptr(),
2010 params.plane,
2011 params.width,
2012 params.height,
2013 params.format.raw(),
2014 )
2015 };
2016 NonNull::new(ptr).map(|ptr| MetalTexture { ptr })
2017}
2018
2019#[link(name = "Foundation", kind = "framework")]
2022extern "C" {
2023 fn objc_autoreleasePoolPush() -> *mut c_void;
2024 fn objc_autoreleasePoolPop(pool: *mut c_void);
2025}
2026
2027pub fn autoreleasepool<F, R>(f: F) -> R
2044where
2045 F: FnOnce() -> R,
2046{
2047 unsafe {
2048 let pool = objc_autoreleasePoolPush();
2049 let result = f();
2050 objc_autoreleasePoolPop(pool);
2051 result
2052 }
2053}
2054
2055pub unsafe fn setup_metal_view(view: *mut c_void, layer: &MetalLayer) {
2077 unsafe {
2078 nsview_set_wants_layer(view);
2079 nsview_set_layer(view, layer.as_ptr());
2080 }
2081}