1 /*!
2 # Metal backend internals.
3 
4 ## Pipeline Layout
5 
6 In Metal, push constants, vertex buffers, and resources in the descriptor sets
7 are all placed together in the native resource bindings, which work similarly to D3D11:
8 there are tables of textures, buffers, and samplers.
9 
10 We put push constants first (if any) in the table, followed by descriptor set 0
11 resource, followed by other descriptor sets. The vertex buffers are bound at the very
12 end of the VS buffer table.
13 
14 When argument buffers are supported, each descriptor set becomes a buffer binding,
15 but the general placement rule is the same.
16 
17 ## Command recording
18 
19 One-time-submit primary command buffers are recorded "live" into `MTLCommandBuffer`.
20 Special care is taken to the recording state: active bindings are restored at the
21 start of any render or compute pass.
22 
23 Multi-submit and secondary command buffers are recorded as "soft" commands into
24 `Journal`. Actual native recording is done at either `submit` or `execute_commands`
25 correspondingly. When that happens, we `enqueue` the command buffer at the start
26 of recording, which allows the driver to work on pass translation at the same time
27 as we are recording the following passes.
28 
29 ## Memory
30 
31 In general, "Shared" storage is used for CPU-coherent memory. "Managed" is used for
32 non-coherent CPU-visible memory. Finally, "Private" storage is backing device-local
33 memory types.
34 
35 Metal doesn't have CPU-visible memory for textures. We only allow RGBA8 2D textures
36 to be allocated from it, and only for the matter of transfer operations, which is
37 the minimum required by Vulkan. In fact, these become just glorified staging buffers.
38 
39 ## Events
40 
41 Events are represented by just an atomic bool. When recording, a command buffer keeps
42 track of all events set or reset. Signalling within a command buffer is therefore a
43 matter of simply checking that local list. When making a submission, used events are
44 also accumulated temporarily, so that we can change their values in the completion
45 handler of the last command buffer. We also check this list in order to resolve events
46 fired in one command buffer and waited in another one within the same submission.
47 
48 Waiting for an event from a different submission is accomplished similar to waiting
49 for the host. We block all the submissions until the host blockers are resolved, and
50 these are checked at certain points like setting an event by the device, or waiting
51 for a fence.
52 !*/
53 
54 #[macro_use]
55 extern crate bitflags;
56 #[macro_use]
57 extern crate objc;
58 #[macro_use]
59 extern crate log;
60 
61 use hal::{
62     adapter::{Adapter, AdapterInfo, DeviceType},
63     queue::{QueueFamilyId, QueueType},
64 };
65 use range_alloc::RangeAllocator;
66 
67 use cocoa_foundation::foundation::NSInteger;
68 #[cfg(feature = "dispatch")]
69 use dispatch;
70 use foreign_types::ForeignTypeRef;
71 use metal::MTLFeatureSet;
72 use metal::MTLGPUFamily;
73 use metal::MTLLanguageVersion;
74 use metal::{CGFloat, CGSize, MetalLayer, MetalLayerRef};
75 use objc::{
76     declare::ClassDecl,
77     runtime::{Class, Object, Sel, BOOL, YES},
78 };
79 use parking_lot::{Condvar, Mutex};
80 
81 use std::{
82     collections::HashMap,
83     hash::BuildHasherDefault,
84     mem,
85     os::raw::c_void,
86     ptr::NonNull,
87     sync::{Arc, Once},
88 };
89 
90 mod command;
91 mod conversions;
92 mod device;
93 mod internal;
94 mod native;
95 #[cfg(feature = "pipeline-cache")]
96 mod pipeline_cache;
97 mod soft;
98 mod window;
99 
100 pub use crate::command::CommandPool;
101 pub use crate::device::{Device, LanguageVersion, PhysicalDevice};
102 pub use crate::window::Surface;
103 
104 pub type GraphicsCommandPool = CommandPool;
105 type FastHashMap<K, V> = HashMap<K, V, BuildHasherDefault<fxhash::FxHasher>>;
106 
107 //TODO: investigate why exactly using `u8` here is slower (~5% total).
108 /// A type representing Metal binding's resource index.
109 type ResourceIndex = u32;
110 
111 // For CALayer contentsGravity
112 #[link(name = "QuartzCore", kind = "framework")]
113 extern "C" {
114     #[allow(non_upper_case_globals)]
115     static kCAGravityTopLeft: cocoa_foundation::base::id;
116 }
117 
118 #[repr(C)]
119 #[derive(Clone, Copy, Debug, Default)]
120 pub struct CGPoint {
121     pub x: CGFloat,
122     pub y: CGFloat,
123 }
124 
125 impl CGPoint {
126     #[inline]
new(x: CGFloat, y: CGFloat) -> CGPoint127     pub fn new(x: CGFloat, y: CGFloat) -> CGPoint {
128         CGPoint { x, y }
129     }
130 }
131 
132 #[repr(C)]
133 #[derive(Clone, Copy, Debug, Default)]
134 pub struct CGRect {
135     pub origin: CGPoint,
136     pub size: CGSize,
137 }
138 
139 impl CGRect {
140     #[inline]
new(origin: CGPoint, size: CGSize) -> CGRect141     pub fn new(origin: CGPoint, size: CGSize) -> CGRect {
142         CGRect { origin, size }
143     }
144 }
145 
146 /// Method of recording one-time-submit command buffers.
147 #[derive(Clone, Debug, Hash, PartialEq)]
148 pub enum OnlineRecording {
149     /// Record natively on-the-fly.
150     Immediate,
151     /// Store commands and only start recording at submission time.
152     Deferred,
153     #[cfg(feature = "dispatch")]
154     /// Start recording asynchronously upon finishing each pass.
155     Remote(dispatch::QueuePriority),
156 }
157 
158 impl Default for OnlineRecording {
default() -> Self159     fn default() -> Self {
160         OnlineRecording::Immediate
161     }
162 }
163 
164 const MAX_ACTIVE_COMMAND_BUFFERS: usize = 1 << 14;
165 const MAX_VISIBILITY_QUERIES: usize = 1 << 14;
166 const MAX_COLOR_ATTACHMENTS: usize = 8;
167 const MAX_BOUND_DESCRIPTOR_SETS: usize = 8;
168 
169 #[derive(Debug, Clone, Copy)]
170 pub struct QueueFamily {}
171 
172 impl hal::queue::QueueFamily for QueueFamily {
queue_type(&self) -> QueueType173     fn queue_type(&self) -> QueueType {
174         QueueType::General
175     }
max_queues(&self) -> usize176     fn max_queues(&self) -> usize {
177         1
178     }
id(&self) -> QueueFamilyId179     fn id(&self) -> QueueFamilyId {
180         QueueFamilyId(0)
181     }
supports_sparse_binding(&self) -> bool182     fn supports_sparse_binding(&self) -> bool {
183         false
184     }
185 }
186 
187 #[derive(Debug)]
188 struct VisibilityShared {
189     /// Availability buffer is in shared memory, it has N double words for
190     /// query results followed by N words for the availability.
191     buffer: metal::Buffer,
192     allocator: Mutex<RangeAllocator<hal::query::Id>>,
193     availability_offset: hal::buffer::Offset,
194     condvar: Condvar,
195 }
196 
197 #[derive(Debug)]
198 struct Shared {
199     device: Mutex<metal::Device>,
200     queue: Mutex<command::QueueInner>,
201     queue_blocker: Mutex<command::QueueBlocker>,
202     service_pipes: internal::ServicePipes,
203     disabilities: PrivateDisabilities,
204     private_caps: PrivateCapabilities,
205     visibility: VisibilityShared,
206 }
207 
208 unsafe impl Send for Shared {}
209 unsafe impl Sync for Shared {}
210 
211 impl Shared {
new(device: metal::Device, experiments: &Experiments) -> Self212     fn new(device: metal::Device, experiments: &Experiments) -> Self {
213         let private_caps = PrivateCapabilities::new(&device, experiments);
214         debug!("{:#?}", private_caps);
215 
216         let visibility = VisibilityShared {
217             buffer: device.new_buffer(
218                 MAX_VISIBILITY_QUERIES as u64
219                     * (mem::size_of::<u64>() + mem::size_of::<u32>()) as u64,
220                 metal::MTLResourceOptions::StorageModeShared,
221             ),
222             allocator: Mutex::new(RangeAllocator::new(
223                 0..MAX_VISIBILITY_QUERIES as hal::query::Id,
224             )),
225             availability_offset: (MAX_VISIBILITY_QUERIES * mem::size_of::<u64>())
226                 as hal::buffer::Offset,
227             condvar: Condvar::new(),
228         };
229         Shared {
230             queue: Mutex::new(command::QueueInner::new(
231                 &device,
232                 Some(MAX_ACTIVE_COMMAND_BUFFERS),
233             )),
234             queue_blocker: Mutex::new(command::QueueBlocker::default()),
235             service_pipes: internal::ServicePipes::new(&device),
236             disabilities: PrivateDisabilities {
237                 broken_viewport_near_depth: device.name().starts_with("Intel")
238                     && !device.supports_feature_set(MTLFeatureSet::macOS_GPUFamily1_v4),
239                 broken_layered_clear_image: device.name().starts_with("Intel"),
240             },
241             private_caps,
242             device: Mutex::new(device),
243             visibility,
244         }
245     }
246 }
247 
248 #[derive(Clone, Debug, Default)]
249 pub struct Experiments {
250     pub argument_buffers: bool,
251 }
252 
253 #[derive(Debug)]
254 pub struct Instance {
255     pub experiments: Experiments,
256     gfx_managed_metal_layer_delegate: GfxManagedMetalLayerDelegate,
257 }
258 
259 impl hal::Instance<Backend> for Instance {
create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend>260     fn create(_: &str, _: u32) -> Result<Self, hal::UnsupportedBackend> {
261         Ok(Instance {
262             experiments: Experiments::default(),
263             gfx_managed_metal_layer_delegate: GfxManagedMetalLayerDelegate::new(),
264         })
265     }
266 
enumerate_adapters(&self) -> Vec<Adapter<Backend>>267     fn enumerate_adapters(&self) -> Vec<Adapter<Backend>> {
268         let devices = metal::Device::all();
269         let mut adapters: Vec<Adapter<Backend>> = devices
270             .into_iter()
271             .map(|dev| {
272                 let name = dev.name().into();
273                 let shared = Shared::new(dev, &self.experiments);
274                 let physical_device = device::PhysicalDevice::new(Arc::new(shared));
275                 Adapter {
276                     info: AdapterInfo {
277                         name,
278                         vendor: 0,
279                         device: 0,
280                         device_type: if physical_device.shared.private_caps.low_power {
281                             DeviceType::IntegratedGpu
282                         } else {
283                             DeviceType::DiscreteGpu
284                         },
285                     },
286                     physical_device,
287                     queue_families: vec![QueueFamily {}],
288                 }
289             })
290             .collect();
291         adapters.sort_by_key(|adapt| {
292             (
293                 adapt.physical_device.shared.private_caps.low_power,
294                 adapt.physical_device.shared.private_caps.headless,
295             )
296         });
297         adapters
298     }
299 
create_surface( &self, has_handle: &impl raw_window_handle::HasRawWindowHandle, ) -> Result<Surface, hal::window::InitError>300     unsafe fn create_surface(
301         &self,
302         has_handle: &impl raw_window_handle::HasRawWindowHandle,
303     ) -> Result<Surface, hal::window::InitError> {
304         match has_handle.raw_window_handle() {
305             #[cfg(target_os = "ios")]
306             raw_window_handle::RawWindowHandle::IOS(handle) => {
307                 Ok(self.create_surface_from_uiview(handle.ui_view))
308             }
309             #[cfg(target_os = "macos")]
310             raw_window_handle::RawWindowHandle::MacOS(handle) => {
311                 Ok(self.create_surface_from_nsview(handle.ns_view))
312             }
313             _ => Err(hal::window::InitError::UnsupportedWindowHandle),
314         }
315     }
316 
destroy_surface(&self, surface: Surface)317     unsafe fn destroy_surface(&self, surface: Surface) {
318         surface.dispose();
319     }
320 }
321 
layer_should_inherit_contents_scale_from_window( _: &Class, _: Sel, _layer: *mut Object, _new_scale: CGFloat, _from_window: *mut Object, ) -> BOOL322 extern "C" fn layer_should_inherit_contents_scale_from_window(
323     _: &Class,
324     _: Sel,
325     _layer: *mut Object,
326     _new_scale: CGFloat,
327     _from_window: *mut Object,
328 ) -> BOOL {
329     YES
330 }
331 
332 const CAML_DELEGATE_CLASS: &str = "GfxManagedMetalLayerDelegate";
333 static CAML_DELEGATE_REGISTER: Once = Once::new();
334 
335 #[derive(Debug)]
336 struct GfxManagedMetalLayerDelegate(&'static Class);
337 
338 impl GfxManagedMetalLayerDelegate {
new() -> Self339     pub fn new() -> Self {
340         CAML_DELEGATE_REGISTER.call_once(|| {
341             type Fun = extern "C" fn(&Class, Sel, *mut Object, CGFloat, *mut Object) -> BOOL;
342             let mut decl = ClassDecl::new(CAML_DELEGATE_CLASS, class!(NSObject)).unwrap();
343             unsafe {
344                 decl.add_class_method(
345                     sel!(layer:shouldInheritContentsScale:fromWindow:),
346                     layer_should_inherit_contents_scale_from_window as Fun,
347                 );
348             }
349             decl.register();
350         });
351         GfxManagedMetalLayerDelegate(Class::get(CAML_DELEGATE_CLASS).unwrap())
352     }
353 }
354 
355 impl Instance {
356     #[cfg(target_os = "ios")]
create_from_uiview(&self, uiview: *mut c_void) -> Surface357     unsafe fn create_from_uiview(&self, uiview: *mut c_void) -> Surface {
358         let view: cocoa_foundation::base::id = mem::transmute(uiview);
359         if view.is_null() {
360             panic!("window does not have a valid contentView");
361         }
362 
363         let main_layer: *mut Object = msg_send![view, layer];
364         let class = class!(CAMetalLayer);
365         let is_valid_layer: BOOL = msg_send![main_layer, isKindOfClass: class];
366         let render_layer = if is_valid_layer == YES {
367             mem::transmute::<_, &MetalLayerRef>(main_layer).to_owned()
368         } else {
369             // If the main layer is not a CAMetalLayer, we create a CAMetalLayer sublayer and use it instead.
370             // Unlike on macOS, we cannot replace the main view as UIView does not allow it (when NSView does).
371             let new_layer: MetalLayer = msg_send![class, new];
372             let bounds: CGRect = msg_send![main_layer, bounds];
373             let () = msg_send![new_layer.as_ref(), setFrame: bounds];
374             let () = msg_send![main_layer, addSublayer: new_layer.as_ref()];
375             new_layer
376         };
377 
378         let window: cocoa_foundation::base::id = msg_send![view, window];
379         if !window.is_null() {
380             let screen: cocoa_foundation::base::id = msg_send![window, screen];
381             assert!(!screen.is_null(), "window is not attached to a screen");
382 
383             let scale_factor: CGFloat = msg_send![screen, nativeScale];
384             let () = msg_send![view, setContentScaleFactor: scale_factor];
385         }
386 
387         let _: *mut c_void = msg_send![view, retain];
388         Surface::new(NonNull::new(view), render_layer)
389     }
390 
391     #[cfg(target_os = "macos")]
create_from_nsview(&self, nsview: *mut c_void) -> Surface392     unsafe fn create_from_nsview(&self, nsview: *mut c_void) -> Surface {
393         let view: cocoa_foundation::base::id = mem::transmute(nsview);
394         if view.is_null() {
395             panic!("window does not have a valid contentView");
396         }
397 
398         let class = class!(CAMetalLayer);
399         // Deprecated! Clients should use `create_surface_from_layer` instead.
400         let is_actually_layer: BOOL = msg_send![view, isKindOfClass: class];
401         if is_actually_layer == YES {
402             return self.create_from_layer(mem::transmute(view));
403         }
404 
405         let existing: *mut Object = msg_send![view, layer];
406         let use_current = if existing.is_null() {
407             false
408         } else {
409             let result: BOOL = msg_send![existing, isKindOfClass: class];
410             result == YES
411         };
412 
413         let render_layer: MetalLayer = if use_current {
414             mem::transmute::<_, &MetalLayerRef>(existing).to_owned()
415         } else {
416             let layer: MetalLayer = msg_send![class, new];
417             let () = msg_send![view, setLayer: layer.as_ref()];
418             let () = msg_send![view, setWantsLayer: YES];
419             let bounds: CGRect = msg_send![view, bounds];
420             let () = msg_send![layer.as_ref(), setBounds: bounds];
421 
422             let window: cocoa_foundation::base::id = msg_send![view, window];
423             if !window.is_null() {
424                 let scale_factor: CGFloat = msg_send![window, backingScaleFactor];
425                 let () = msg_send![layer, setContentsScale: scale_factor];
426             }
427             let () = msg_send![layer, setDelegate: self.gfx_managed_metal_layer_delegate.0];
428             layer
429         };
430 
431         let () = msg_send![render_layer, setContentsGravity: kCAGravityTopLeft];
432 
433         let _: *mut c_void = msg_send![view, retain];
434         Surface::new(NonNull::new(view), render_layer)
435     }
436 
create_from_layer(&self, layer: &MetalLayerRef) -> Surface437     unsafe fn create_from_layer(&self, layer: &MetalLayerRef) -> Surface {
438         let class = class!(CAMetalLayer);
439         let proper_kind: BOOL = msg_send![layer, isKindOfClass: class];
440         assert_eq!(proper_kind, YES);
441         Surface::new(None, layer.to_owned())
442     }
443 
create_surface_from_layer(&self, layer: &MetalLayerRef) -> Surface444     pub fn create_surface_from_layer(&self, layer: &MetalLayerRef) -> Surface {
445         unsafe { self.create_from_layer(layer) }
446     }
447 
448     #[cfg(target_os = "macos")]
create_surface_from_nsview(&self, nsview: *mut c_void) -> Surface449     pub fn create_surface_from_nsview(&self, nsview: *mut c_void) -> Surface {
450         unsafe { self.create_from_nsview(nsview) }
451     }
452 
453     #[cfg(target_os = "ios")]
create_surface_from_uiview(&self, uiview: *mut c_void) -> Surface454     pub fn create_surface_from_uiview(&self, uiview: *mut c_void) -> Surface {
455         unsafe { self.create_from_uiview(uiview) }
456     }
457 }
458 
459 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
460 pub enum Backend {}
461 impl hal::Backend for Backend {
462     type Instance = Instance;
463     type PhysicalDevice = device::PhysicalDevice;
464     type Device = device::Device;
465     type Surface = Surface;
466 
467     type QueueFamily = QueueFamily;
468     type Queue = command::Queue;
469     type CommandBuffer = command::CommandBuffer;
470 
471     type Memory = native::Memory;
472     type CommandPool = command::CommandPool;
473 
474     type ShaderModule = native::ShaderModule;
475     type RenderPass = native::RenderPass;
476     type Framebuffer = native::Framebuffer;
477 
478     type Buffer = native::Buffer;
479     type BufferView = native::BufferView;
480     type Image = native::Image;
481     type ImageView = native::ImageView;
482     type Sampler = native::Sampler;
483 
484     type ComputePipeline = native::ComputePipeline;
485     type GraphicsPipeline = native::GraphicsPipeline;
486     type PipelineCache = native::PipelineCache;
487     type PipelineLayout = native::PipelineLayout;
488     type DescriptorSetLayout = native::DescriptorSetLayout;
489     type DescriptorPool = native::DescriptorPool;
490     type DescriptorSet = native::DescriptorSet;
491 
492     type Fence = native::Fence;
493     type Semaphore = native::Semaphore;
494     type Event = native::Event;
495     type QueryPool = native::QueryPool;
496 }
497 
498 const RESOURCE_HEAP_SUPPORT: &[MTLFeatureSet] = &[
499     MTLFeatureSet::iOS_GPUFamily1_v3,
500     MTLFeatureSet::iOS_GPUFamily2_v3,
501     MTLFeatureSet::iOS_GPUFamily3_v2,
502     MTLFeatureSet::iOS_GPUFamily4_v1,
503     MTLFeatureSet::iOS_GPUFamily5_v1,
504     MTLFeatureSet::tvOS_GPUFamily1_v2,
505     MTLFeatureSet::tvOS_GPUFamily2_v1,
506     MTLFeatureSet::macOS_GPUFamily1_v3,
507     MTLFeatureSet::macOS_GPUFamily2_v1,
508 ];
509 
510 const ARGUMENT_BUFFER_SUPPORT: &[MTLFeatureSet] = &[
511     MTLFeatureSet::iOS_GPUFamily1_v4,
512     MTLFeatureSet::iOS_GPUFamily2_v4,
513     MTLFeatureSet::iOS_GPUFamily3_v3,
514     MTLFeatureSet::iOS_GPUFamily4_v1,
515     MTLFeatureSet::iOS_GPUFamily5_v1,
516     MTLFeatureSet::tvOS_GPUFamily1_v3,
517     MTLFeatureSet::macOS_GPUFamily1_v3,
518     MTLFeatureSet::macOS_GPUFamily2_v1,
519 ];
520 
521 const MUTABLE_COMPARISON_SAMPLER_SUPPORT: &[MTLFeatureSet] = &[
522     MTLFeatureSet::iOS_GPUFamily3_v1,
523     MTLFeatureSet::iOS_GPUFamily4_v1,
524     MTLFeatureSet::iOS_GPUFamily5_v1,
525     MTLFeatureSet::macOS_GPUFamily1_v1,
526     MTLFeatureSet::macOS_GPUFamily2_v1,
527 ];
528 
529 const SAMPLER_CLAMP_TO_BORDER_SUPPORT: &[MTLFeatureSet] = &[
530     MTLFeatureSet::macOS_GPUFamily1_v2,
531     MTLFeatureSet::macOS_GPUFamily2_v1,
532 ];
533 
534 const ASTC_PIXEL_FORMAT_FEATURES: &[MTLFeatureSet] = &[
535     MTLFeatureSet::iOS_GPUFamily2_v1,
536     MTLFeatureSet::iOS_GPUFamily3_v1,
537     MTLFeatureSet::iOS_GPUFamily4_v1,
538     MTLFeatureSet::iOS_GPUFamily5_v1,
539     MTLFeatureSet::tvOS_GPUFamily1_v1,
540     MTLFeatureSet::tvOS_GPUFamily2_v1,
541 ];
542 
543 const ANY8_UNORM_SRGB_ALL: &[MTLFeatureSet] = &[
544     MTLFeatureSet::iOS_GPUFamily2_v3,
545     MTLFeatureSet::iOS_GPUFamily3_v1,
546     MTLFeatureSet::iOS_GPUFamily4_v1,
547     MTLFeatureSet::iOS_GPUFamily5_v1,
548     MTLFeatureSet::tvOS_GPUFamily1_v2,
549     MTLFeatureSet::tvOS_GPUFamily2_v1,
550 ];
551 
552 const ANY8_SNORM_RESOLVE: &[MTLFeatureSet] = &[
553     MTLFeatureSet::iOS_GPUFamily2_v1,
554     MTLFeatureSet::iOS_GPUFamily3_v1,
555     MTLFeatureSet::iOS_GPUFamily4_v1,
556     MTLFeatureSet::iOS_GPUFamily5_v1,
557     MTLFeatureSet::tvOS_GPUFamily1_v1,
558     MTLFeatureSet::tvOS_GPUFamily2_v1,
559     MTLFeatureSet::macOS_GPUFamily1_v1,
560     MTLFeatureSet::macOS_GPUFamily2_v1,
561 ];
562 
563 const RGBA8_SRGB: &[MTLFeatureSet] = &[
564     MTLFeatureSet::iOS_GPUFamily2_v3,
565     MTLFeatureSet::iOS_GPUFamily3_v1,
566     MTLFeatureSet::iOS_GPUFamily4_v1,
567     MTLFeatureSet::iOS_GPUFamily5_v1,
568     MTLFeatureSet::tvOS_GPUFamily1_v2,
569     MTLFeatureSet::tvOS_GPUFamily2_v1,
570 ];
571 
572 const RGB10A2UNORM_ALL: &[MTLFeatureSet] = &[
573     MTLFeatureSet::iOS_GPUFamily3_v1,
574     MTLFeatureSet::iOS_GPUFamily4_v1,
575     MTLFeatureSet::iOS_GPUFamily5_v1,
576     MTLFeatureSet::tvOS_GPUFamily2_v1,
577     MTLFeatureSet::macOS_GPUFamily1_v1,
578     MTLFeatureSet::macOS_GPUFamily2_v1,
579 ];
580 
581 const RGB10A2UINT_COLOR_WRITE: &[MTLFeatureSet] = &[
582     MTLFeatureSet::iOS_GPUFamily3_v1,
583     MTLFeatureSet::iOS_GPUFamily4_v1,
584     MTLFeatureSet::iOS_GPUFamily5_v1,
585     MTLFeatureSet::tvOS_GPUFamily2_v1,
586     MTLFeatureSet::macOS_GPUFamily1_v1,
587     MTLFeatureSet::macOS_GPUFamily2_v1,
588 ];
589 
590 const RG11B10FLOAT_ALL: &[MTLFeatureSet] = &[
591     MTLFeatureSet::iOS_GPUFamily3_v1,
592     MTLFeatureSet::iOS_GPUFamily4_v1,
593     MTLFeatureSet::iOS_GPUFamily5_v1,
594     MTLFeatureSet::tvOS_GPUFamily2_v1,
595     MTLFeatureSet::macOS_GPUFamily1_v1,
596     MTLFeatureSet::macOS_GPUFamily2_v1,
597 ];
598 
599 const RGB9E5FLOAT_ALL: &[MTLFeatureSet] = &[
600     MTLFeatureSet::iOS_GPUFamily3_v1,
601     MTLFeatureSet::iOS_GPUFamily4_v1,
602     MTLFeatureSet::iOS_GPUFamily5_v1,
603     MTLFeatureSet::tvOS_GPUFamily2_v1,
604 ];
605 
606 const BGR10A2_ALL: &[MTLFeatureSet] = &[
607     MTLFeatureSet::iOS_GPUFamily1_v4,
608     MTLFeatureSet::iOS_GPUFamily2_v4,
609     MTLFeatureSet::iOS_GPUFamily3_v3,
610     MTLFeatureSet::iOS_GPUFamily4_v1,
611     MTLFeatureSet::iOS_GPUFamily5_v1,
612     MTLFeatureSet::tvOS_GPUFamily1_v3,
613     MTLFeatureSet::tvOS_GPUFamily2_v1,
614     MTLFeatureSet::macOS_GPUFamily1_v3,
615     MTLFeatureSet::macOS_GPUFamily2_v1,
616 ];
617 
618 const BASE_INSTANCE_SUPPORT: &[MTLFeatureSet] = &[
619     MTLFeatureSet::iOS_GPUFamily3_v1,
620     MTLFeatureSet::iOS_GPUFamily4_v1,
621     MTLFeatureSet::iOS_GPUFamily5_v1,
622     MTLFeatureSet::tvOS_GPUFamily2_v1,
623     MTLFeatureSet::macOS_GPUFamily1_v1,
624     MTLFeatureSet::macOS_GPUFamily2_v1,
625 ];
626 
627 const BASE_VERTEX_INSTANCE_SUPPORT: &[MTLFeatureSet] = &[
628     MTLFeatureSet::iOS_GPUFamily3_v1,
629     MTLFeatureSet::iOS_GPUFamily4_v1,
630     MTLFeatureSet::iOS_GPUFamily5_v1,
631     MTLFeatureSet::tvOS_GPUFamily2_v1,
632     MTLFeatureSet::macOS_GPUFamily1_v1,
633     MTLFeatureSet::macOS_GPUFamily2_v1,
634 ];
635 
636 const TEXTURE_CUBE_ARRAY_SUPPORT: &[MTLFeatureSet] = &[
637     MTLFeatureSet::iOS_GPUFamily4_v1,
638     MTLFeatureSet::iOS_GPUFamily5_v1,
639     MTLFeatureSet::tvOS_GPUFamily1_v2,
640     MTLFeatureSet::tvOS_GPUFamily2_v1,
641     MTLFeatureSet::macOS_GPUFamily1_v1,
642     MTLFeatureSet::macOS_GPUFamily2_v1,
643 ];
644 
645 const DUAL_SOURCE_BLEND_SUPPORT: &[MTLFeatureSet] = &[
646     MTLFeatureSet::iOS_GPUFamily1_v4,
647     MTLFeatureSet::iOS_GPUFamily2_v4,
648     MTLFeatureSet::iOS_GPUFamily3_v3,
649     MTLFeatureSet::iOS_GPUFamily4_v1,
650     MTLFeatureSet::iOS_GPUFamily5_v1,
651     MTLFeatureSet::tvOS_GPUFamily1_v3,
652     MTLFeatureSet::tvOS_GPUFamily2_v1,
653     MTLFeatureSet::macOS_GPUFamily1_v2,
654     MTLFeatureSet::macOS_GPUFamily2_v1,
655 ];
656 
657 const LAYERED_RENDERING_SUPPORT: &[MTLFeatureSet] = &[
658     MTLFeatureSet::iOS_GPUFamily5_v1,
659     MTLFeatureSet::macOS_GPUFamily1_v1,
660     MTLFeatureSet::macOS_GPUFamily2_v1,
661 ];
662 
663 const FUNCTION_SPECIALIZATION_SUPPORT: &[MTLFeatureSet] = &[
664     MTLFeatureSet::iOS_GPUFamily1_v3,
665     MTLFeatureSet::iOS_GPUFamily2_v3,
666     MTLFeatureSet::iOS_GPUFamily3_v2,
667     MTLFeatureSet::iOS_GPUFamily4_v1,
668     MTLFeatureSet::iOS_GPUFamily5_v1,
669     MTLFeatureSet::tvOS_GPUFamily1_v2,
670     MTLFeatureSet::macOS_GPUFamily1_v2,
671     MTLFeatureSet::macOS_GPUFamily2_v1,
672 ];
673 
674 const DEPTH_CLIP_MODE: &[MTLFeatureSet] = &[
675     MTLFeatureSet::iOS_GPUFamily4_v1,
676     MTLFeatureSet::iOS_GPUFamily5_v1,
677     MTLFeatureSet::tvOS_GPUFamily1_v3,
678     MTLFeatureSet::macOS_GPUFamily1_v1,
679     MTLFeatureSet::macOS_GPUFamily2_v1,
680 ];
681 
682 #[derive(Clone, Debug)]
683 struct PrivateCapabilities {
684     pub os_is_mac: bool,
685     os_version: (u32, u32),
686     msl_version: metal::MTLLanguageVersion,
687     exposed_queues: usize,
688     read_write_texture_tier: metal::MTLReadWriteTextureTier,
689     // if TRUE, we'll report `NON_FILL_POLYGON_MODE` feature without the points support
690     expose_line_mode: bool,
691     resource_heaps: bool,
692     argument_buffers: bool,
693     shared_textures: bool,
694     mutable_comparison_samplers: bool,
695     sampler_clamp_to_border: bool,
696     base_instance: bool,
697     base_vertex_instance_drawing: bool,
698     dual_source_blending: bool,
699     low_power: bool,
700     headless: bool,
701     layered_rendering: bool,
702     function_specialization: bool,
703     depth_clip_mode: bool,
704     texture_cube_array: bool,
705     format_depth24_stencil8: bool,
706     format_depth32_stencil8_filter: bool,
707     format_depth32_stencil8_none: bool,
708     format_min_srgb_channels: u8,
709     format_b5: bool,
710     format_bc: bool,
711     format_eac_etc: bool,
712     format_astc: bool,
713     format_any8_unorm_srgb_all: bool,
714     format_any8_unorm_srgb_no_write: bool,
715     format_any8_snorm_all: bool,
716     format_r16_norm_all: bool,
717     format_r32_all: bool,
718     format_r32_no_write: bool,
719     format_r32float_no_write_no_filter: bool,
720     format_r32float_no_filter: bool,
721     format_r32float_all: bool,
722     format_rgba8_srgb_all: bool,
723     format_rgba8_srgb_no_write: bool,
724     format_rgb10a2_unorm_all: bool,
725     format_rgb10a2_unorm_no_write: bool,
726     format_rgb10a2_uint_color: bool,
727     format_rgb10a2_uint_color_write: bool,
728     format_rg11b10_all: bool,
729     format_rg11b10_no_write: bool,
730     format_rgb9e5_all: bool,
731     format_rgb9e5_no_write: bool,
732     format_rgb9e5_filter_only: bool,
733     format_rg32_color: bool,
734     format_rg32_color_write: bool,
735     format_rg32float_all: bool,
736     format_rg32float_color_blend: bool,
737     format_rg32float_no_filter: bool,
738     format_rgba32int_color: bool,
739     format_rgba32int_color_write: bool,
740     format_rgba32float_color: bool,
741     format_rgba32float_color_write: bool,
742     format_rgba32float_all: bool,
743     format_depth16unorm: bool,
744     format_depth32float_filter: bool,
745     format_depth32float_none: bool,
746     format_bgr10a2_all: bool,
747     format_bgr10a2_no_write: bool,
748     max_buffers_per_stage: ResourceIndex,
749     max_textures_per_stage: ResourceIndex,
750     max_samplers_per_stage: ResourceIndex,
751     buffer_alignment: u64,
752     max_buffer_size: u64,
753     max_texture_size: u64,
754     max_texture_3d_size: u64,
755     max_texture_layers: u64,
756     max_fragment_input_components: u64,
757     max_color_render_targets: u8,
758     max_total_threadgroup_memory: u32,
759     sample_count_mask: u8,
760     supports_debug_markers: bool,
761     supports_binary_archives: bool,
762 }
763 
764 impl PrivateCapabilities {
version_at_least(major: u32, minor: u32, needed_major: u32, needed_minor: u32) -> bool765     fn version_at_least(major: u32, minor: u32, needed_major: u32, needed_minor: u32) -> bool {
766         major > needed_major || (major == needed_major && minor >= needed_minor)
767     }
768 
supports_any(raw: &metal::DeviceRef, features_sets: &[MTLFeatureSet]) -> bool769     fn supports_any(raw: &metal::DeviceRef, features_sets: &[MTLFeatureSet]) -> bool {
770         features_sets
771             .iter()
772             .cloned()
773             .any(|x| raw.supports_feature_set(x))
774     }
775 
new(device: &metal::Device, experiments: &Experiments) -> Self776     fn new(device: &metal::Device, experiments: &Experiments) -> Self {
777         #[repr(C)]
778         #[derive(Clone, Copy, Debug)]
779         struct NSOperatingSystemVersion {
780             major: NSInteger,
781             minor: NSInteger,
782             patch: NSInteger,
783         }
784 
785         let version: NSOperatingSystemVersion = unsafe {
786             let process_info: *mut Object = msg_send![class!(NSProcessInfo), processInfo];
787             msg_send![process_info, operatingSystemVersion]
788         };
789 
790         let major = version.major as u32;
791         let minor = version.minor as u32;
792         let os_is_mac = device.supports_feature_set(MTLFeatureSet::macOS_GPUFamily1_v1);
793 
794         let mut sample_count_mask: u8 = 1 | 4; // 1 and 4 samples are supported on all devices
795         if device.supports_texture_sample_count(2) {
796             sample_count_mask |= 2;
797         }
798         if device.supports_texture_sample_count(8) {
799             sample_count_mask |= 8;
800         }
801 
802         PrivateCapabilities {
803             os_is_mac,
804             os_version: (major as u32, minor as u32),
805             msl_version: if os_is_mac {
806                 if Self::version_at_least(major, minor, 10, 15) {
807                     MTLLanguageVersion::V2_2
808                 } else if Self::version_at_least(major, minor, 10, 14) {
809                     MTLLanguageVersion::V2_1
810                 } else if Self::version_at_least(major, minor, 10, 13) {
811                     MTLLanguageVersion::V2_0
812                 } else if Self::version_at_least(major, minor, 10, 12) {
813                     MTLLanguageVersion::V1_2
814                 } else if Self::version_at_least(major, minor, 10, 11) {
815                     MTLLanguageVersion::V1_1
816                 } else {
817                     MTLLanguageVersion::V1_0
818                 }
819             } else if Self::version_at_least(major, minor, 13, 0) {
820                 MTLLanguageVersion::V2_2
821             } else if Self::version_at_least(major, minor, 12, 0) {
822                 MTLLanguageVersion::V2_1
823             } else if Self::version_at_least(major, minor, 11, 0) {
824                 MTLLanguageVersion::V2_0
825             } else if Self::version_at_least(major, minor, 10, 0) {
826                 MTLLanguageVersion::V1_2
827             } else if Self::version_at_least(major, minor, 9, 0) {
828                 MTLLanguageVersion::V1_1
829             } else {
830                 MTLLanguageVersion::V1_0
831             },
832             exposed_queues: 1,
833             read_write_texture_tier: device.read_write_texture_support(),
834             expose_line_mode: true,
835             resource_heaps: Self::supports_any(&device, RESOURCE_HEAP_SUPPORT),
836             argument_buffers: experiments.argument_buffers
837                 && Self::supports_any(&device, ARGUMENT_BUFFER_SUPPORT),
838             shared_textures: !os_is_mac,
839             mutable_comparison_samplers: Self::supports_any(
840                 &device,
841                 MUTABLE_COMPARISON_SAMPLER_SUPPORT,
842             ),
843             sampler_clamp_to_border: Self::supports_any(&device, SAMPLER_CLAMP_TO_BORDER_SUPPORT),
844             base_instance: Self::supports_any(&device, BASE_INSTANCE_SUPPORT),
845             base_vertex_instance_drawing: Self::supports_any(&device, BASE_VERTEX_INSTANCE_SUPPORT),
846             dual_source_blending: Self::supports_any(&device, DUAL_SOURCE_BLEND_SUPPORT),
847             low_power: !os_is_mac || device.is_low_power(),
848             headless: os_is_mac && device.is_headless(),
849             layered_rendering: Self::supports_any(&device, LAYERED_RENDERING_SUPPORT),
850             function_specialization: Self::supports_any(&device, FUNCTION_SPECIALIZATION_SUPPORT),
851             depth_clip_mode: Self::supports_any(&device, DEPTH_CLIP_MODE),
852             texture_cube_array: Self::supports_any(&device, TEXTURE_CUBE_ARRAY_SUPPORT),
853             format_depth24_stencil8: os_is_mac && device.d24_s8_supported(),
854             format_depth32_stencil8_filter: os_is_mac,
855             format_depth32_stencil8_none: !os_is_mac,
856             format_min_srgb_channels: if os_is_mac { 4 } else { 1 },
857             format_b5: !os_is_mac,
858             format_bc: os_is_mac,
859             format_eac_etc: !os_is_mac,
860             format_astc: Self::supports_any(&device, ASTC_PIXEL_FORMAT_FEATURES),
861             format_any8_unorm_srgb_all: Self::supports_any(&device, ANY8_UNORM_SRGB_ALL),
862             format_any8_unorm_srgb_no_write: !Self::supports_any(&device, ANY8_UNORM_SRGB_ALL)
863                 && !os_is_mac,
864             format_any8_snorm_all: Self::supports_any(&device, ANY8_SNORM_RESOLVE),
865             format_r16_norm_all: os_is_mac,
866             format_r32_all: !Self::supports_any(
867                 &device,
868                 &[
869                     MTLFeatureSet::iOS_GPUFamily1_v1,
870                     MTLFeatureSet::iOS_GPUFamily2_v1,
871                 ],
872             ),
873             format_r32_no_write: Self::supports_any(
874                 &device,
875                 &[
876                     MTLFeatureSet::iOS_GPUFamily1_v1,
877                     MTLFeatureSet::iOS_GPUFamily2_v1,
878                 ],
879             ),
880             format_r32float_no_write_no_filter: Self::supports_any(
881                 &device,
882                 &[
883                     MTLFeatureSet::iOS_GPUFamily1_v1,
884                     MTLFeatureSet::iOS_GPUFamily2_v1,
885                 ],
886             ) && !os_is_mac,
887             format_r32float_no_filter: !Self::supports_any(
888                 &device,
889                 &[
890                     MTLFeatureSet::iOS_GPUFamily1_v1,
891                     MTLFeatureSet::iOS_GPUFamily2_v1,
892                 ],
893             ) && !os_is_mac,
894             format_r32float_all: os_is_mac,
895             format_rgba8_srgb_all: Self::supports_any(&device, RGBA8_SRGB),
896             format_rgba8_srgb_no_write: !Self::supports_any(&device, RGBA8_SRGB),
897             format_rgb10a2_unorm_all: Self::supports_any(&device, RGB10A2UNORM_ALL),
898             format_rgb10a2_unorm_no_write: !Self::supports_any(&device, RGB10A2UNORM_ALL),
899             format_rgb10a2_uint_color: !Self::supports_any(&device, RGB10A2UINT_COLOR_WRITE),
900             format_rgb10a2_uint_color_write: Self::supports_any(&device, RGB10A2UINT_COLOR_WRITE),
901             format_rg11b10_all: Self::supports_any(&device, RG11B10FLOAT_ALL),
902             format_rg11b10_no_write: !Self::supports_any(&device, RG11B10FLOAT_ALL),
903             format_rgb9e5_all: Self::supports_any(&device, RGB9E5FLOAT_ALL),
904             format_rgb9e5_no_write: !Self::supports_any(&device, RGB9E5FLOAT_ALL) && !os_is_mac,
905             format_rgb9e5_filter_only: os_is_mac,
906             format_rg32_color: Self::supports_any(
907                 &device,
908                 &[
909                     MTLFeatureSet::iOS_GPUFamily1_v1,
910                     MTLFeatureSet::iOS_GPUFamily2_v1,
911                 ],
912             ),
913             format_rg32_color_write: !Self::supports_any(
914                 &device,
915                 &[
916                     MTLFeatureSet::iOS_GPUFamily1_v1,
917                     MTLFeatureSet::iOS_GPUFamily2_v1,
918                 ],
919             ),
920             format_rg32float_all: os_is_mac,
921             format_rg32float_color_blend: Self::supports_any(
922                 &device,
923                 &[
924                     MTLFeatureSet::iOS_GPUFamily1_v1,
925                     MTLFeatureSet::iOS_GPUFamily2_v1,
926                 ],
927             ),
928             format_rg32float_no_filter: !os_is_mac
929                 && !Self::supports_any(
930                     &device,
931                     &[
932                         MTLFeatureSet::iOS_GPUFamily1_v1,
933                         MTLFeatureSet::iOS_GPUFamily2_v1,
934                     ],
935                 ),
936             format_rgba32int_color: Self::supports_any(
937                 &device,
938                 &[
939                     MTLFeatureSet::iOS_GPUFamily1_v1,
940                     MTLFeatureSet::iOS_GPUFamily2_v1,
941                 ],
942             ),
943             format_rgba32int_color_write: !Self::supports_any(
944                 &device,
945                 &[
946                     MTLFeatureSet::iOS_GPUFamily1_v1,
947                     MTLFeatureSet::iOS_GPUFamily2_v1,
948                 ],
949             ),
950             format_rgba32float_color: Self::supports_any(
951                 &device,
952                 &[
953                     MTLFeatureSet::iOS_GPUFamily1_v1,
954                     MTLFeatureSet::iOS_GPUFamily2_v1,
955                 ],
956             ),
957             format_rgba32float_color_write: !Self::supports_any(
958                 &device,
959                 &[
960                     MTLFeatureSet::iOS_GPUFamily1_v1,
961                     MTLFeatureSet::iOS_GPUFamily2_v1,
962                 ],
963             ) && !os_is_mac,
964             format_rgba32float_all: os_is_mac,
965             format_depth16unorm: device.supports_feature_set(MTLFeatureSet::macOS_GPUFamily1_v2),
966             format_depth32float_filter: device
967                 .supports_feature_set(MTLFeatureSet::macOS_GPUFamily1_v1),
968             format_depth32float_none: !device
969                 .supports_feature_set(MTLFeatureSet::macOS_GPUFamily1_v1),
970             format_bgr10a2_all: Self::supports_any(&device, BGR10A2_ALL),
971             format_bgr10a2_no_write: !device
972                 .supports_feature_set(MTLFeatureSet::macOS_GPUFamily1_v3),
973             max_buffers_per_stage: 31,
974             max_textures_per_stage: if os_is_mac { 128 } else { 31 },
975             max_samplers_per_stage: 16,
976             buffer_alignment: if os_is_mac { 256 } else { 64 },
977             max_buffer_size: if device.supports_feature_set(MTLFeatureSet::macOS_GPUFamily1_v2) {
978                 1 << 30 // 1GB on macOS 1.2 and up
979             } else {
980                 1 << 28 // 256MB otherwise
981             },
982             max_texture_size: if Self::supports_any(
983                 &device,
984                 &[
985                     MTLFeatureSet::iOS_GPUFamily3_v1,
986                     MTLFeatureSet::tvOS_GPUFamily2_v1,
987                     MTLFeatureSet::macOS_GPUFamily1_v1,
988                 ],
989             ) {
990                 16384
991             } else if Self::supports_any(
992                 &device,
993                 &[
994                     MTLFeatureSet::iOS_GPUFamily1_v2,
995                     MTLFeatureSet::iOS_GPUFamily2_v2,
996                     MTLFeatureSet::tvOS_GPUFamily1_v1,
997                 ],
998             ) {
999                 8192
1000             } else {
1001                 4096
1002             },
1003             max_texture_3d_size: 2048,
1004             max_texture_layers: 2048,
1005             max_fragment_input_components: if os_is_mac { 128 } else { 60 },
1006             max_color_render_targets: if Self::supports_any(
1007                 &device,
1008                 &[
1009                     MTLFeatureSet::iOS_GPUFamily2_v1,
1010                     MTLFeatureSet::iOS_GPUFamily3_v1,
1011                     MTLFeatureSet::iOS_GPUFamily4_v1,
1012                     MTLFeatureSet::iOS_GPUFamily5_v1,
1013                     MTLFeatureSet::tvOS_GPUFamily1_v1,
1014                     MTLFeatureSet::tvOS_GPUFamily2_v1,
1015                     MTLFeatureSet::macOS_GPUFamily1_v1,
1016                     MTLFeatureSet::macOS_GPUFamily2_v1,
1017                 ],
1018             ) {
1019                 8
1020             } else {
1021                 4
1022             },
1023             max_total_threadgroup_memory: if Self::supports_any(
1024                 &device,
1025                 &[
1026                     MTLFeatureSet::iOS_GPUFamily4_v2,
1027                     MTLFeatureSet::iOS_GPUFamily5_v1,
1028                 ],
1029             ) {
1030                 64 << 10
1031             } else if Self::supports_any(
1032                 &device,
1033                 &[
1034                     MTLFeatureSet::iOS_GPUFamily4_v1,
1035                     MTLFeatureSet::macOS_GPUFamily1_v2,
1036                     MTLFeatureSet::macOS_GPUFamily2_v1,
1037                 ],
1038             ) {
1039                 32 << 10
1040             } else {
1041                 16 << 10
1042             },
1043             sample_count_mask,
1044             supports_debug_markers: Self::supports_any(
1045                 &device,
1046                 &[
1047                     MTLFeatureSet::macOS_GPUFamily1_v2,
1048                     MTLFeatureSet::macOS_GPUFamily2_v1,
1049                     MTLFeatureSet::iOS_GPUFamily1_v3,
1050                     MTLFeatureSet::iOS_GPUFamily2_v3,
1051                     MTLFeatureSet::iOS_GPUFamily3_v2,
1052                     MTLFeatureSet::iOS_GPUFamily4_v1,
1053                     MTLFeatureSet::iOS_GPUFamily5_v1,
1054                     MTLFeatureSet::tvOS_GPUFamily1_v2,
1055                     MTLFeatureSet::tvOS_GPUFamily2_v1,
1056                 ],
1057             ),
1058             supports_binary_archives: cfg!(feature = "pipeline-cache")
1059                 && (device.supports_family(MTLGPUFamily::Apple3)
1060                     || device.supports_family(MTLGPUFamily::Mac1)),
1061         }
1062     }
1063 
has_version_at_least(&self, needed_major: u32, needed_minor: u32) -> bool1064     fn has_version_at_least(&self, needed_major: u32, needed_minor: u32) -> bool {
1065         let (major, minor) = self.os_version;
1066         Self::version_at_least(major, minor, needed_major, needed_minor)
1067     }
1068 }
1069 
1070 #[derive(Clone, Copy, Debug)]
1071 struct PrivateDisabilities {
1072     /// Near depth is not respected properly on some Intel GPUs.
1073     broken_viewport_near_depth: bool,
1074     /// Multi-target clears don't appear to work properly on Intel GPUs.
1075     broken_layered_clear_image: bool,
1076 }
1077 
1078 trait AsNative {
1079     type Native;
from(native: &Self::Native) -> Self1080     fn from(native: &Self::Native) -> Self;
as_native(&self) -> &Self::Native1081     fn as_native(&self) -> &Self::Native;
1082 }
1083 
1084 pub type BufferPtr = NonNull<metal::MTLBuffer>;
1085 pub type TexturePtr = NonNull<metal::MTLTexture>;
1086 pub type SamplerPtr = NonNull<metal::MTLSamplerState>;
1087 pub type ResourcePtr = NonNull<metal::MTLResource>;
1088 
1089 //TODO: make this a generic struct with a single generic implementation
1090 
1091 impl AsNative for BufferPtr {
1092     type Native = metal::BufferRef;
1093     #[inline]
from(native: &metal::BufferRef) -> Self1094     fn from(native: &metal::BufferRef) -> Self {
1095         unsafe { NonNull::new_unchecked(native.as_ptr()) }
1096     }
1097     #[inline]
as_native(&self) -> &metal::BufferRef1098     fn as_native(&self) -> &metal::BufferRef {
1099         unsafe { metal::BufferRef::from_ptr(self.as_ptr()) }
1100     }
1101 }
1102 
1103 impl AsNative for TexturePtr {
1104     type Native = metal::TextureRef;
1105     #[inline]
from(native: &metal::TextureRef) -> Self1106     fn from(native: &metal::TextureRef) -> Self {
1107         unsafe { NonNull::new_unchecked(native.as_ptr()) }
1108     }
1109     #[inline]
as_native(&self) -> &metal::TextureRef1110     fn as_native(&self) -> &metal::TextureRef {
1111         unsafe { metal::TextureRef::from_ptr(self.as_ptr()) }
1112     }
1113 }
1114 
1115 impl AsNative for SamplerPtr {
1116     type Native = metal::SamplerStateRef;
1117     #[inline]
from(native: &metal::SamplerStateRef) -> Self1118     fn from(native: &metal::SamplerStateRef) -> Self {
1119         unsafe { NonNull::new_unchecked(native.as_ptr()) }
1120     }
1121     #[inline]
as_native(&self) -> &metal::SamplerStateRef1122     fn as_native(&self) -> &metal::SamplerStateRef {
1123         unsafe { metal::SamplerStateRef::from_ptr(self.as_ptr()) }
1124     }
1125 }
1126 
1127 impl AsNative for ResourcePtr {
1128     type Native = metal::ResourceRef;
1129     #[inline]
from(native: &metal::ResourceRef) -> Self1130     fn from(native: &metal::ResourceRef) -> Self {
1131         unsafe { NonNull::new_unchecked(native.as_ptr()) }
1132     }
1133     #[inline]
as_native(&self) -> &metal::ResourceRef1134     fn as_native(&self) -> &metal::ResourceRef {
1135         unsafe { metal::ResourceRef::from_ptr(self.as_ptr()) }
1136     }
1137 }
1138