use block::{Block, ConcreteBlock};
use cocoa::base::id;
use cocoa::foundation::{NSUInteger};
use foreign_types::ForeignType;
use libc;
use objc::runtime::{Object, BOOL, YES, NO};
use objc_foundation::{NSString, INSString};
use super::*;
use std::ffi::CStr;
use std::path::Path;
use std::ptr;
#[allow(non_camel_case_types)]
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum MTLFeatureSet {
iOS_GPUFamily1_v1 = 0,
iOS_GPUFamily2_v1 = 1,
iOS_GPUFamily1_v2 = 2,
iOS_GPUFamily2_v2 = 3,
iOS_GPUFamily3_v1 = 4,
iOS_GPUFamily1_v3 = 5,
iOS_GPUFamily2_v3 = 6,
iOS_GPUFamily3_v2 = 7,
iOS_GPUFamily1_v4 = 8,
iOS_GPUFamily2_v4 = 9,
iOS_GPUFamily3_v3 = 10,
iOS_GPUFamily4_v1 = 11,
tvOS_GPUFamily1_v1 = 30000,
tvOS_GPUFamily1_v2 = 30001,
tvOS_GPUFamily1_v3 = 30002,
tvOS_GPUFamily2_v1 = 30003,
macOS_GPUFamily1_v1 = 10000,
macOS_GPUFamily1_v2 = 10001,
macOS_GPUFamily1_v3 = 10003,
}
bitflags! {
pub struct PixelFormatCapabilities: u32 {
const Filter = 1 << 0;
const Write = 1 << 1;
const Color = 1 << 2;
const Blend = 1 << 3;
const Msaa = 1 << 4;
const Resolve = 1 << 5;
}
}
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum OS {
iOS, tvOS, macOS
}
const KB: u32 = 1024;
const MB: u32 = 1024 * KB;
const GB: u32 = 1024 * MB;
impl MTLFeatureSet {
fn os(&self) -> OS {
let value = *self as u64;
if value < 10_000 {
OS::iOS
} else if value < 20_000 {
OS::macOS
} else if value >= 30_000 || value < 40_000 {
OS::tvOS
} else {
unreachable!()
}
}
fn os_version(&self) -> u32 {
use MTLFeatureSet::*;
match self {
iOS_GPUFamily1_v1 | iOS_GPUFamily2_v1 => 8,
iOS_GPUFamily1_v2 | iOS_GPUFamily2_v2 | iOS_GPUFamily3_v1 => 9,
iOS_GPUFamily1_v3 | iOS_GPUFamily2_v3 | iOS_GPUFamily3_v2 => 10,
iOS_GPUFamily1_v4 | iOS_GPUFamily2_v4 | iOS_GPUFamily3_v3 | iOS_GPUFamily4_v1 => 11,
tvOS_GPUFamily1_v1 => 9,
tvOS_GPUFamily1_v2 => 10,
tvOS_GPUFamily1_v3 | tvOS_GPUFamily2_v1 => 11,
macOS_GPUFamily1_v1 | macOS_GPUFamily1_v2 | macOS_GPUFamily1_v3 => 10,
}
}
fn gpu_family(&self) -> u32 {
use MTLFeatureSet::*;
match self {
iOS_GPUFamily1_v1
| iOS_GPUFamily1_v2
| iOS_GPUFamily1_v3
| iOS_GPUFamily1_v4
| tvOS_GPUFamily1_v1
| tvOS_GPUFamily1_v2
| tvOS_GPUFamily1_v3
| macOS_GPUFamily1_v1
| macOS_GPUFamily1_v2
| macOS_GPUFamily1_v3 => 1,
iOS_GPUFamily2_v1
| iOS_GPUFamily2_v2
| iOS_GPUFamily2_v3
| iOS_GPUFamily2_v4
| tvOS_GPUFamily2_v1 => 2,
iOS_GPUFamily3_v1
| iOS_GPUFamily3_v2
| iOS_GPUFamily3_v3 => 3,
iOS_GPUFamily4_v1 => 4,
}
}
fn version(&self) -> u32 {
use MTLFeatureSet::*;
match self {
iOS_GPUFamily1_v1
| iOS_GPUFamily2_v1
| iOS_GPUFamily3_v1
| iOS_GPUFamily4_v1
| macOS_GPUFamily1_v1
| tvOS_GPUFamily1_v1
| tvOS_GPUFamily2_v1 => 1,
iOS_GPUFamily1_v2
| iOS_GPUFamily2_v2
| iOS_GPUFamily3_v2
| macOS_GPUFamily1_v2
| tvOS_GPUFamily1_v2 => 2,
iOS_GPUFamily1_v3
| iOS_GPUFamily2_v3
| iOS_GPUFamily3_v3
| macOS_GPUFamily1_v3
| tvOS_GPUFamily1_v3 => 3,
iOS_GPUFamily1_v4
| iOS_GPUFamily2_v4 => 4,
}
}
pub fn supports_metal_kit(&self) -> bool {
true
}
pub fn supports_metal_performance_shaders(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 2,
OS::tvOS => true,
OS::macOS => self.version() >= 3,
}
}
pub fn supports_programmable_blending(&self) -> bool {
self.os() != OS::macOS
}
pub fn supports_pvrtc_pixel_formats(&self) -> bool {
self.os() != OS::macOS
}
pub fn supports_eac_etc_pixel_formats(&self) -> bool {
self.os() != OS::macOS
}
pub fn supports_astc_pixel_formats(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 2,
OS::tvOS => true,
OS::macOS => false,
}
}
pub fn supports_linear_textures(&self) -> bool {
self.os() != OS::macOS || self.version() >= 3
}
pub fn supports_bc_pixel_formats(&self) -> bool {
self.os() == OS::macOS
}
pub fn supports_msaa_depth_resolve(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 3,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => false,
}
}
pub fn supports_counting_occlusion_query(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 3,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => true,
}
}
pub fn supports_base_vertex_instance_drawing(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 3,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => true,
}
}
pub fn supports_indirect_buffers(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 3,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => true,
}
}
pub fn supports_cube_map_texture_arrays(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 4,
OS::tvOS => false,
OS::macOS => true,
}
}
pub fn supports_texture_barriers(&self) -> bool {
self.os() == OS::macOS
}
pub fn supports_layered_rendering(&self) -> bool {
self.os() == OS::macOS
}
pub fn supports_tessellation(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 3 && self.os_version() >= 10,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => self.version() >= 2,
}
}
pub fn supports_resource_heaps(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 10,
OS::tvOS => self.os_version() >= 10,
OS::macOS => self.version() >= 3,
}
}
pub fn supports_memoryless_render_targets(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 10,
OS::tvOS => self.os_version() >= 10,
OS::macOS => false,
}
}
pub fn supports_function_specialization(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 10,
OS::tvOS => self.os_version() >= 10,
OS::macOS => self.version() >= 2,
}
}
pub fn supports_function_buffer_read_writes(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 3 && self.os_version() >= 10,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => self.version() >= 2,
}
}
pub fn supports_function_texture_read_writes(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 4,
OS::tvOS => false,
OS::macOS => self.version() >= 2,
}
}
pub fn supports_array_of_textures(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 3 && self.os_version() >= 10,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => self.version() >= 3,
}
}
pub fn supports_array_of_samplers(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 3 && self.os_version() >= 11,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => self.version() >= 2,
}
}
pub fn supports_stencil_texture_views(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 10,
OS::tvOS => self.os_version() >= 10,
OS::macOS => self.version() >= 2,
}
}
pub fn supports_depth_16_pixel_format(&self) -> bool {
self.os() == OS::macOS && self.version() >= 2
}
pub fn supports_extended_range_pixel_formats(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 3 && self.os_version() >= 10,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => false,
}
}
pub fn supports_wide_color_pixel_format(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 11,
OS::tvOS => self.os_version() >= 11,
OS::macOS => self.version() >= 3,
}
}
pub fn supports_combined_msaa_store_and_resolve_action(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 3 && self.os_version() >= 10,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => self.version() >= 2,
}
}
pub fn supports_deferred_store_action(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 10,
OS::tvOS => self.os_version() >= 10,
OS::macOS => self.version() >= 2,
}
}
pub fn supports_msaa_blits(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 10,
OS::tvOS => self.os_version() >= 10,
OS::macOS => true,
}
}
pub fn supports_srgb_writes(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 3 || (self.gpu_family() >= 2 && self.version() >= 3),
OS::tvOS => self.os_version() >= 10,
OS::macOS => false,
}
}
pub fn supports_16_bit_unsigned_integer_coordinates(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 10,
OS::tvOS => self.os_version() >= 10,
OS::macOS => self.version() >= 2,
}
}
pub fn supports_extract_insert_and_reverse_bits(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 10,
OS::tvOS => self.os_version() >= 10,
OS::macOS => self.version() >= 2,
}
}
pub fn supports_simd_barrier(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 10,
OS::tvOS => self.os_version() >= 10,
OS::macOS => false,
}
}
pub fn supports_sampler_max_anisotropy(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 10,
OS::tvOS => self.os_version() >= 10,
OS::macOS => false,
}
}
pub fn supports_sampler_lod_clamp(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 10,
OS::tvOS => self.os_version() >= 10,
OS::macOS => false,
}
}
pub fn supports_border_color(&self) -> bool {
self.os() == OS::macOS && self.version() >= 2
}
pub fn supports_dual_source_blending(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 11,
OS::tvOS => self.os_version() >= 11,
OS::macOS => self.version() >= 2,
}
}
pub fn supports_argument_buffers(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 11,
OS::tvOS => self.os_version() >= 11,
OS::macOS => self.version() >= 3,
}
}
pub fn supports_programmable_sample_positions(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 11,
OS::tvOS => self.os_version() >= 11,
OS::macOS => self.version() >= 3,
}
}
pub fn supports_uniform_type(&self) -> bool {
match self.os() {
OS::iOS => self.os_version() >= 11,
OS::tvOS => self.os_version() >= 11,
OS::macOS => self.version() >= 3,
}
}
pub fn supports_imageblocks(&self) -> bool {
self.os() == OS::iOS && self.gpu_family() >= 4
}
pub fn supports_tile_shaders(&self) -> bool {
self.os() == OS::iOS && self.gpu_family() >= 4
}
pub fn supports_imageblock_sample_coverage_control(&self) -> bool {
self.os() == OS::iOS && self.gpu_family() >= 4
}
pub fn supports_threadgroup_sharing(&self) -> bool {
self.os() == OS::iOS && self.gpu_family() >= 4
}
pub fn supports_post_depth_coverage(&self) -> bool {
self.os() == OS::iOS && self.gpu_family() >= 4
}
pub fn supports_quad_scoped_permute_operations(&self) -> bool {
self.os() == OS::iOS && self.gpu_family() >= 4
}
pub fn supports_raster_order_groups(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 4,
OS::tvOS => false,
OS::macOS => self.version() >= 3,
}
}
pub fn supports_non_uniform_threadgroup_size(&self) -> bool {
match self.os() {
OS::iOS => self.gpu_family() >= 4,
OS::tvOS => false,
OS::macOS => self.version() >= 3,
}
}
pub fn supports_multiple_viewports(&self) -> bool {
self.os() == OS::macOS && self.version() >= 3
}
pub fn supports_device_notifications(&self) -> bool {
self.os() == OS::macOS && self.version() >= 3
}
pub fn max_vertex_attributes(&self) -> u32 {
31
}
pub fn max_buffer_argument_entries(&self) -> u32 {
31
}
pub fn max_texture_argument_entries(&self) -> u32 {
if self.os() == OS::macOS {
128
} else {
31
}
}
pub fn max_sampler_state_argument_entries(&self) -> u32 {
16
}
pub fn max_threadgroup_memory_argument_entries(&self) -> u32 {
31
}
pub fn max_inlined_constant_data_buffers(&self) -> u32 {
if self.os() == OS::macOS {
14
} else {
31
}
}
pub fn max_inline_constant_buffer_length(&self) -> u32 {
4 * KB
}
pub fn max_threads_per_threadgroup(&self) -> u32 {
if self.os() == OS::macOS || self.gpu_family() == 4 {
1024
} else {
512
}
}
pub fn max_total_threadgroup_memory_allocation(&self) -> u32 {
match (self.os(), self.gpu_family()) {
(OS::iOS, 4) => 32 * KB,
(OS::iOS, 3) => 16 * KB,
(OS::iOS, _) => 16 * KB - 32,
(OS::tvOS, 1) => 16 * KB - 32,
(OS::tvOS, _) => 16 * KB,
(OS::macOS, _) => 32 * KB,
}
}
pub fn max_total_tile_memory_allocation(&self) -> u32 {
if self.os() == OS::iOS && self.gpu_family() == 4 {
32 * KB
} else {
0
}
}
pub fn threadgroup_memory_length_alignment(&self) -> u32 {
16
}
pub fn max_constant_buffer_function_memory_allocation(&self) -> Option<u32> {
if self.os() == OS::macOS {
Some(64 * KB)
} else {
None
}
}
pub fn max_fragment_inputs(&self) -> u32 {
if self.os() == OS::macOS {
32
} else {
60
}
}
pub fn max_fragment_input_components(&self) -> u32 {
if self.os() == OS::macOS {
128
} else {
60
}
}
pub fn max_function_constants(&self) -> u32 {
match self.os() {
OS::iOS if self.os_version() >= 11 => 65536,
OS::tvOS if self.os_version() >= 10 => 65536,
OS::macOS if self.version() >= 2 => 65536,
_ => 0,
}
}
pub fn max_tessellation_factor(&self) -> u32 {
if self.supports_tessellation() {
match self.os() {
OS::iOS => 16,
OS::tvOS => 16,
OS::macOS => 64,
}
} else {
0
}
}
pub fn max_viewports_and_scissor_rectangles(&self) -> u32 {
if self.supports_multiple_viewports() {
16
} else {
1
}
}
pub fn max_raster_order_groups(&self) -> u32 {
if self.supports_raster_order_groups() {
8
} else {
0
}
}
pub fn max_buffer_length(&self) -> u32 {
if self.os() == OS::macOS && self.version() >= 2 {
1 * GB
} else {
256 * MB
}
}
pub fn min_buffer_offset_alignment(&self) -> u32 {
if self.os() == OS::macOS {
256
} else {
4
}
}
pub fn max_1d_texture_size(&self) -> u32 {
match (self.os(), self.gpu_family()) {
(OS::iOS, 1) | (OS::iOS, 2) => if self.version() <= 2 { 4096 } else { 8192 },
(OS::tvOS, 1) => 8192,
_ => 16384,
}
}
pub fn max_2d_texture_size(&self) -> u32 {
match (self.os(), self.gpu_family()) {
(OS::iOS, 1) | (OS::iOS, 2) => if self.version() <= 2 { 4096 } else { 8192 },
(OS::tvOS, 1) => 8192,
_ => 16384,
}
}
pub fn max_cube_map_texture_size(&self) -> u32 {
match (self.os(), self.gpu_family()) {
(OS::iOS, 1) | (OS::iOS, 2) => if self.version() <= 2 { 4096 } else { 8192 },
(OS::tvOS, 1) => 8192,
_ => 16384,
}
}
pub fn max_3d_texture_size(&self) -> u32 {
2048
}
pub fn max_array_layers(&self) -> u32 {
2048
}
pub fn copy_texture_buffer_alignment(&self) -> u32 {
match (self.os(), self.gpu_family()) {
(OS::iOS, 1) | (OS::iOS, 2) | (OS::tvOS, 1) => 64,
(OS::iOS, _) | (OS::tvOS, _) => 16,
(OS::macOS, _) => 256,
}
}
pub fn new_texture_buffer_alignment(&self) -> Option<u32> {
match self.os() {
OS::iOS => if self.os_version() >= 11 {
None
} else if self.gpu_family() == 3 {
Some(16)
} else {
Some(64)
},
OS::tvOS => if self.os_version() >= 11 {
None
} else {
Some(64)
},
OS::macOS => None,
}
}
pub fn max_color_render_targets(&self) -> u32 {
if self.os() == OS::iOS && self.gpu_family() == 1 {
4
} else {
8
}
}
pub fn max_point_primitive_size(&self) -> u32 {
511
}
pub fn max_total_color_render_target_size(&self) -> Option<u32> {
match (self.os(), self.gpu_family()) {
(OS::iOS, 1) => Some(128),
(OS::iOS, 2) | (OS::iOS, 3) => Some(256),
(OS::iOS, _) => Some(512),
(OS::tvOS, _) => Some(256),
(OS::macOS, _) => None,
}
}
pub fn max_visibility_query_offset(&self) -> u32 {
64 * KB - 8
}
pub fn a8_unorm_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Filter
}
pub fn r8_unorm_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::all()
}
pub fn r8_unorm_srgb_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::empty()
} else if self.supports_srgb_writes() {
PixelFormatCapabilities::all()
} else {
!PixelFormatCapabilities::Write
}
}
pub fn r8_snorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::iOS && self.gpu_family() == 1 {
!PixelFormatCapabilities::Resolve
} else {
PixelFormatCapabilities::all()
}
}
pub fn r8_uint_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
}
pub fn r8_sint_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
}
pub fn r16_unorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() != OS::macOS {
!PixelFormatCapabilities::Resolve
} else {
PixelFormatCapabilities::all()
}
}
pub fn r16_snorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() != OS::macOS {
!PixelFormatCapabilities::Resolve
} else {
PixelFormatCapabilities::all()
}
}
pub fn r16_uint_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
}
pub fn r16_sint_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
}
pub fn r16_float_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::all()
}
pub fn rg8_unorm_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::all()
}
pub fn rg8_unorm_srgb_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::empty()
} else if self.supports_srgb_writes() {
PixelFormatCapabilities::all()
} else {
!PixelFormatCapabilities::Write
}
}
pub fn rg8_snorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::iOS && self.gpu_family() == 1 {
!PixelFormatCapabilities::Resolve
} else {
PixelFormatCapabilities::all()
}
}
pub fn rg8_uint_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
}
pub fn rg8_sint_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
}
pub fn b5_g6_r5_unorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::empty()
} else {
!PixelFormatCapabilities::Write
}
}
pub fn a1_bgr5_unorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::empty()
} else {
!PixelFormatCapabilities::Write
}
}
pub fn abgr4_unorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::empty()
} else {
!PixelFormatCapabilities::Write
}
}
pub fn bgr5_a1_unorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::empty()
} else {
!PixelFormatCapabilities::Write
}
}
pub fn r32_uint_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::iOS && self.os_version() == 8 {
PixelFormatCapabilities::Color
} else if self.os() == OS::macOS {
PixelFormatCapabilities::Color
| PixelFormatCapabilities::Write
| PixelFormatCapabilities::Msaa
} else {
PixelFormatCapabilities::Color | PixelFormatCapabilities::Write
}
}
pub fn r32_sint_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::iOS && self.os_version() == 8 {
PixelFormatCapabilities::Color
} else if self.os() == OS::macOS {
PixelFormatCapabilities::Color
| PixelFormatCapabilities::Write
| PixelFormatCapabilities::Msaa
} else {
PixelFormatCapabilities::Color | PixelFormatCapabilities::Write
}
}
pub fn r32_float_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::iOS && self.os_version() == 8 {
PixelFormatCapabilities::Color
| PixelFormatCapabilities::Blend
| PixelFormatCapabilities::Msaa
} else if self.os() == OS::macOS {
PixelFormatCapabilities::all()
} else {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Blend
| PixelFormatCapabilities::Msaa
}
}
pub fn rg16_unorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::all()
} else {
!PixelFormatCapabilities::Resolve
}
}
pub fn rg16_snorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::all()
} else {
!PixelFormatCapabilities::Resolve
}
}
pub fn rg16_uint_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
}
pub fn rg16_sint_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
}
pub fn rg16_float_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::all()
}
pub fn rgba8_unorm_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::all()
}
pub fn rgba8_unorm_srgb_capabilities(&self) -> PixelFormatCapabilities {
if self.supports_srgb_writes() {
PixelFormatCapabilities::all()
} else {
!PixelFormatCapabilities::Write
}
}
pub fn rgba8_snorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::iOS && self.gpu_family() == 1 {
!PixelFormatCapabilities::Resolve
} else {
PixelFormatCapabilities::all()
}
}
pub fn rgba8_uint_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
}
pub fn rgba8_sint_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
}
pub fn bgra8_unorm_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::all()
}
pub fn bgra8_unorm_srgb_capabilities(&self) -> PixelFormatCapabilities {
if self.supports_srgb_writes() {
PixelFormatCapabilities::all()
} else {
!PixelFormatCapabilities::Write
}
}
pub fn rgb10_a2_unorm_capabilities(&self) -> PixelFormatCapabilities {
let supports_writes = match self.os() {
OS::iOS => self.gpu_family() >= 3,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => true,
};
if supports_writes {
PixelFormatCapabilities::all()
} else {
!PixelFormatCapabilities::Write
}
}
pub fn rgb10_a2_uint_capabilities(&self) -> PixelFormatCapabilities {
let supports_writes = match self.os() {
OS::iOS => self.gpu_family() >= 3,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => true,
};
if supports_writes {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
} else {
PixelFormatCapabilities::Color | PixelFormatCapabilities::Msaa
}
}
pub fn rg11_b10_float_capabilities(&self) -> PixelFormatCapabilities {
let supports_writes = match self.os() {
OS::iOS => self.gpu_family() >= 3,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => true,
};
if supports_writes {
PixelFormatCapabilities::all()
} else {
!PixelFormatCapabilities::Write
}
}
pub fn rgb9_e5_float_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::Filter
} else {
let supports_writes = match self.os() {
OS::iOS => self.gpu_family() >= 3,
OS::tvOS => self.gpu_family() >= 2,
OS::macOS => false,
};
if supports_writes {
PixelFormatCapabilities::all()
} else {
!PixelFormatCapabilities::Write
}
}
}
pub fn rg32_uint_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::iOS && self.os_version() == 8 {
PixelFormatCapabilities::Color
} else if self.os() == OS::macOS {
PixelFormatCapabilities::Color
| PixelFormatCapabilities::Write
| PixelFormatCapabilities::Msaa
} else {
PixelFormatCapabilities::Color | PixelFormatCapabilities::Write
}
}
pub fn rg32_sint_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::iOS && self.os_version() == 8 {
PixelFormatCapabilities::Color
} else if self.os() == OS::macOS {
PixelFormatCapabilities::Color
| PixelFormatCapabilities::Write
| PixelFormatCapabilities::Msaa
} else {
PixelFormatCapabilities::Color | PixelFormatCapabilities::Write
}
}
pub fn rg32_float_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::all()
} else if self.os() == OS::iOS && self.os_version() == 8 {
PixelFormatCapabilities::Color | PixelFormatCapabilities::Blend
} else {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Blend
}
}
pub fn rgba16_unorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::all()
} else {
!PixelFormatCapabilities::Write
}
}
pub fn rgba16_snorm_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::all()
} else {
!PixelFormatCapabilities::Write
}
}
pub fn rgba16_uint_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
}
pub fn rgba16_sint_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Write
| PixelFormatCapabilities::Color
| PixelFormatCapabilities::Msaa
}
pub fn rgba16_float_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::all()
}
pub fn rgba32_uint_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::iOS && self.os_version() == 8 {
PixelFormatCapabilities::Color
} else if self.os() == OS::macOS {
PixelFormatCapabilities::Color
| PixelFormatCapabilities::Write
| PixelFormatCapabilities::Msaa
} else {
PixelFormatCapabilities::Color | PixelFormatCapabilities::Write
}
}
pub fn rgba32_sint_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::iOS && self.os_version() == 8 {
PixelFormatCapabilities::Color
} else if self.os() == OS::macOS {
PixelFormatCapabilities::Color
| PixelFormatCapabilities::Write
| PixelFormatCapabilities::Msaa
} else {
PixelFormatCapabilities::Color | PixelFormatCapabilities::Write
}
}
pub fn rgba32_float_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::all()
} else if self.os() == OS::iOS && self.version() == 8 {
PixelFormatCapabilities::Color
} else {
PixelFormatCapabilities::Write | PixelFormatCapabilities::Color
}
}
pub fn pvrtc_pixel_formats_capabilities(&self) -> PixelFormatCapabilities {
if self.supports_pvrtc_pixel_formats() {
PixelFormatCapabilities::Filter
} else {
PixelFormatCapabilities::empty()
}
}
pub fn eac_etc_pixel_formats_capabilities(&self) -> PixelFormatCapabilities {
if self.supports_eac_etc_pixel_formats() {
PixelFormatCapabilities::Filter
} else {
PixelFormatCapabilities::empty()
}
}
pub fn astc_pixel_formats_capabilities(&self) -> PixelFormatCapabilities {
if self.supports_astc_pixel_formats() {
PixelFormatCapabilities::Filter
} else {
PixelFormatCapabilities::empty()
}
}
pub fn bc_pixel_formats_capabilities(&self) -> PixelFormatCapabilities {
if self.supports_bc_pixel_formats() {
PixelFormatCapabilities::Filter
} else {
PixelFormatCapabilities::empty()
}
}
pub fn gbgr422_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Filter
}
pub fn bgrg422_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Filter
}
pub fn depth16_unorm_capabilities(&self) -> PixelFormatCapabilities {
if self.supports_depth_16_pixel_format() {
PixelFormatCapabilities::Filter
| PixelFormatCapabilities::Msaa
| PixelFormatCapabilities::Resolve
} else {
PixelFormatCapabilities::empty()
}
}
pub fn depth32_float_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::Filter
| PixelFormatCapabilities::Msaa
| PixelFormatCapabilities::Resolve
} else if self.supports_msaa_depth_resolve() {
PixelFormatCapabilities::Msaa | PixelFormatCapabilities::Resolve
} else {
PixelFormatCapabilities::Msaa
}
}
pub fn stencil8_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Msaa
}
pub fn depth24_unorm_stencil8_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::Filter
| PixelFormatCapabilities::Msaa
| PixelFormatCapabilities::Resolve
} else {
PixelFormatCapabilities::empty()
}
}
pub fn depth32_float_stencil8_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::Filter
| PixelFormatCapabilities::Msaa
| PixelFormatCapabilities::Resolve
} else if self.supports_msaa_depth_resolve() {
PixelFormatCapabilities::Msaa | PixelFormatCapabilities::Resolve
} else {
PixelFormatCapabilities::Msaa
}
}
pub fn x24_stencil8_capabilities(&self) -> PixelFormatCapabilities {
if self.os() == OS::macOS {
PixelFormatCapabilities::Msaa
} else {
PixelFormatCapabilities::empty()
}
}
pub fn x32_stencil8_capabilities(&self) -> PixelFormatCapabilities {
PixelFormatCapabilities::Msaa
}
pub fn bgra10_xr_capabilities(&self) -> PixelFormatCapabilities {
if self.supports_extended_range_pixel_formats() {
PixelFormatCapabilities::all()
} else {
PixelFormatCapabilities::empty()
}
}
pub fn bgra10_xr_srgb_capabilities(&self) -> PixelFormatCapabilities {
if self.supports_extended_range_pixel_formats() {
PixelFormatCapabilities::all()
} else {
PixelFormatCapabilities::empty()
}
}
pub fn bgr10_xr_capabilities(&self) -> PixelFormatCapabilities {
if self.supports_extended_range_pixel_formats() {
PixelFormatCapabilities::all()
} else {
PixelFormatCapabilities::empty()
}
}
pub fn bgr10_xr_srgb_capabilities(&self) -> PixelFormatCapabilities {
if self.supports_extended_range_pixel_formats() {
PixelFormatCapabilities::all()
} else {
PixelFormatCapabilities::empty()
}
}
pub fn bgr10_a2_unorm_capabilities(&self) -> PixelFormatCapabilities {
if self.supports_wide_color_pixel_format() {
if self.os() == OS::macOS {
!PixelFormatCapabilities::Write
} else {
PixelFormatCapabilities::all()
}
} else {
PixelFormatCapabilities::empty()
}
}
}
#[allow(non_camel_case_types)]
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub enum MTLArgumentBuffersTier {
tier1 = 0,
tier2 = 1,
}
bitflags! {
struct MTLPipelineOption: NSUInteger {
const ArgumentInfo = 1 << 0;
const BufferTypeInfo = 1 << 1;
}
}
#[link(name = "Metal", kind = "framework")]
extern {
fn MTLCreateSystemDefaultDevice() -> *mut MTLDevice;
fn MTLCopyAllDevices() -> *mut Object; }
#[allow(non_camel_case_types)]
type dispatch_data_t = id;
#[allow(non_camel_case_types)]
type dispatch_queue_t = id;
#[allow(non_camel_case_types)]
type dispatch_block_t = *const Block<(), ()>;
#[cfg_attr(any(target_os = "macos", target_os = "ios"),
link(name = "System", kind = "dylib"))]
#[cfg_attr(not(any(target_os = "macos", target_os = "ios")),
link(name = "dispatch", kind = "dylib"))]
#[allow(improper_ctypes)]
extern {
static _dispatch_main_q: dispatch_queue_t;
fn dispatch_data_create(
buffer: *const libc::c_void,
size: libc::size_t,
queue: dispatch_queue_t,
destructor: dispatch_block_t
) -> dispatch_data_t;
}
pub enum MTLDevice {}
foreign_obj_type! {
type CType = MTLDevice;
pub struct Device;
pub struct DeviceRef;
}
impl Device {
pub fn system_default() -> Self {
unsafe { Device(MTLCreateSystemDefaultDevice()) }
}
pub fn all() -> Vec<Device> {
if cfg!(target_os = "ios") {
vec![Device::system_default()]
} else {
unsafe {
let array = MTLCopyAllDevices();
let count: NSUInteger = msg_send![array, count];
(0 .. count)
.map(|i| msg_send![array, objectAtIndex: i])
.collect()
}
}
}
}
impl DeviceRef {
pub fn name(&self) -> &str {
unsafe {
let name: &NSString = msg_send![self, name];
name.as_str()
}
}
#[cfg(feature = "private")]
pub unsafe fn vendor(&self) -> &str {
let name: &NSString = msg_send![self, vendorName];
name.as_str()
}
#[cfg(feature = "private")]
pub unsafe fn family_name(&self) -> &str {
let name: &NSString = msg_send![self, familyName];
name.as_str()
}
pub fn registry_id(&self) -> u64 {
unsafe {
msg_send![self, registryID]
}
}
pub fn max_threads_per_threadgroup(&self) -> MTLSize {
unsafe {
msg_send![self, maxThreadsPerThreadgroup]
}
}
pub fn is_low_power(&self) -> bool {
unsafe {
match msg_send![self, isLowPower] {
YES => true,
NO => false,
_ => unreachable!()
}
}
}
pub fn is_headless(&self) -> bool {
unsafe {
match msg_send![self, isHeadless] {
YES => true,
NO => false,
_ => unreachable!()
}
}
}
pub fn is_removable(&self) -> bool {
unsafe {
match msg_send![self, isRemovable] {
YES => true,
NO => false,
_ => unreachable!()
}
}
}
pub fn supports_feature_set(&self, feature: MTLFeatureSet) -> bool {
unsafe {
match msg_send![self, supportsFeatureSet:feature] {
YES => true,
NO => false,
_ => unreachable!()
}
}
}
pub fn supports_sample_count(&self, count: NSUInteger) -> bool {
unsafe {
match msg_send![self, supportsTextureSampleCount:count] {
YES => true,
NO => false,
_ => unreachable!()
}
}
}
pub fn d24_s8_supported(&self) -> bool {
unsafe {
match msg_send![self, isDepth24Stencil8PixelFormatSupported] {
YES => true,
NO => false,
_ => unreachable!()
}
}
}
pub fn new_command_queue(&self) -> CommandQueue {
unsafe {
msg_send![self, newCommandQueue]
}
}
pub fn new_command_queue_with_max_command_buffer_count(&self, count: NSUInteger) -> CommandQueue {
unsafe {
msg_send![self, newCommandQueueWithMaxCommandBufferCount:count]
}
}
pub fn new_default_library(&self) -> Library {
unsafe {
msg_send![self, newDefaultLibrary]
}
}
pub fn new_library_with_source(&self, src: &str, options: &CompileOptionsRef) -> Result<Library, String> {
use cocoa::foundation::NSString as cocoa_NSString;
use cocoa::base::nil as cocoa_nil;
unsafe {
let source = cocoa_NSString::alloc(cocoa_nil).init_str(src);
let mut err: *mut Object = ptr::null_mut();
let library: *mut MTLLibrary = msg_send![self, newLibraryWithSource:source
options:options
error:&mut err];
if !err.is_null() {
let desc: *mut Object = msg_send![err, localizedDescription];
let compile_error: *const libc::c_char = msg_send![desc, UTF8String];
let message = CStr::from_ptr(compile_error).to_string_lossy().into_owned();
if library.is_null() {
msg_send![err, release];
return Err(message);
} else {
warn!("Shader warnings: {}", message);
}
}
assert!(!library.is_null());
Ok(Library::from_ptr(library))
}
}
pub fn new_library_with_file<P: AsRef<Path>>(&self, file: P) -> Result<Library, String> {
use cocoa::foundation::NSString as cocoa_NSString;
use cocoa::base::nil as cocoa_nil;
unsafe {
let filename = cocoa_NSString::alloc(cocoa_nil)
.init_str(file.as_ref().to_string_lossy().as_ref());
let library: *mut MTLLibrary = try_objc!{ err =>
msg_send![self, newLibraryWithFile:filename
error:&mut err]
};
Ok(Library::from_ptr(library))
}
}
pub fn new_library_with_data(&self, library_data: &[u8]) -> Result<Library, String> {
unsafe {
let destructor_block = ConcreteBlock::new(|| {}).copy();
let data = dispatch_data_create(
library_data.as_ptr() as *const libc::c_void,
library_data.len() as libc::size_t,
&_dispatch_main_q as *const _ as dispatch_queue_t,
&*destructor_block.deref()
);
let library: *mut MTLLibrary = try_objc! { err =>
msg_send![self, newLibraryWithData:data
error:&mut err]
};
Ok(Library::from_ptr(library))
}
}
pub fn new_render_pipeline_state_with_reflection(&self, descriptor: &RenderPipelineDescriptorRef, reflection: &RenderPipelineReflectionRef) -> Result<RenderPipelineState, String> {
unsafe {
let reflection_options = MTLPipelineOption::ArgumentInfo | MTLPipelineOption::BufferTypeInfo;
let pipeline_state: *mut MTLRenderPipelineState = try_objc!{ err =>
msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
options:reflection_options
reflection:reflection
error:&mut err]
};
Ok(RenderPipelineState::from_ptr(pipeline_state))
}
}
pub fn new_render_pipeline_state(&self, descriptor: &RenderPipelineDescriptorRef) -> Result<RenderPipelineState, String> {
unsafe {
let pipeline_state: *mut MTLRenderPipelineState = try_objc!{ err =>
msg_send![self, newRenderPipelineStateWithDescriptor:descriptor
error:&mut err]
};
Ok(RenderPipelineState::from_ptr(pipeline_state))
}
}
pub fn new_compute_pipeline_state_with_function(&self, function: &FunctionRef) -> Result<ComputePipelineState, String> {
unsafe {
let pipeline_state: *mut MTLComputePipelineState = try_objc!{ err =>
msg_send![self, newComputePipelineStateWithFunction:function
error:&mut err]
};
Ok(ComputePipelineState::from_ptr(pipeline_state))
}
}
#[cfg(feature = "private")]
pub unsafe fn new_compute_pipeline_state(&self, descriptor: &ComputePipelineDescriptorRef) -> Result<ComputePipelineState, String> {
let pipeline_state: *mut MTLComputePipelineState = try_objc!{ err =>
msg_send![self, newComputePipelineStateWithDescriptor:descriptor
error:&mut err]
};
Ok(ComputePipelineState::from_ptr(pipeline_state))
}
pub fn new_buffer(&self, length: u64, options: MTLResourceOptions) -> Buffer {
unsafe {
msg_send![self, newBufferWithLength:length
options:options]
}
}
pub fn new_buffer_with_data(&self, bytes: *const libc::c_void, length: NSUInteger, options: MTLResourceOptions) -> Buffer {
unsafe {
msg_send![self, newBufferWithBytes:bytes
length:length
options:options]
}
}
pub fn new_texture(&self, descriptor: &TextureDescriptorRef) -> Texture {
unsafe {
msg_send![self, newTextureWithDescriptor:descriptor]
}
}
pub fn new_sampler(&self, descriptor: &SamplerDescriptorRef) -> SamplerState {
unsafe {
msg_send![self, newSamplerStateWithDescriptor:descriptor]
}
}
pub fn new_depth_stencil_state(&self, descriptor: &DepthStencilDescriptorRef) -> DepthStencilState {
unsafe {
msg_send![self, newDepthStencilStateWithDescriptor:descriptor]
}
}
pub fn argument_buffers_support(&self) -> Option<MTLArgumentBuffersTier> {
unsafe {
let has_arg_buffers: BOOL = msg_send![self, respondsToSelector: sel!(argumentBuffersSupport)];
if has_arg_buffers == YES {
Some(msg_send![self, argumentBuffersSupport])
} else {
None
}
}
}
pub fn new_argument_encoder(&self, arguments: &ArrayRef<ArgumentDescriptor>) -> ArgumentEncoder {
unsafe {
msg_send![self, newArgumentEncoderWithArguments:arguments]
}
}
pub fn new_heap(&self, descriptor: &HeapDescriptorRef) -> Heap {
unsafe {
msg_send![self, newHeapWithDescriptor: descriptor]
}
}
pub fn heap_buffer_size_and_align(&self, length: NSUInteger, options: MTLResourceOptions) -> MTLSizeAndAlign {
unsafe {
msg_send![self, heapBufferSizeAndAlignWithLength: length options: options]
}
}
pub fn heap_texture_size_and_align(&self, descriptor: &TextureDescriptorRef) -> MTLSizeAndAlign {
unsafe {
msg_send![self, heapTextureSizeAndAlignWithDescriptor: descriptor]
}
}
pub fn minimum_linear_texture_alignment_for_pixel_format(&self, format: MTLPixelFormat) -> NSUInteger {
unsafe {
msg_send![self, minimumLinearTextureAlignmentForPixelFormat: format]
}
}
}