diff --git a/CHANGELOG.md b/CHANGELOG.md index fc094bcfb0..4bfc4b4282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -137,6 +137,10 @@ By @bradwerth [#6216](https://github.com/gfx-rs/wgpu/pull/6216). - Vulkan debug labels assumed no interior nul byte. By @DJMcNab in [#6257](https://github.com/gfx-rs/wgpu/pull/6257) - Add `.index_type(vk::IndexType::NONE_KHR)` when creating `AccelerationStructureGeometryTrianglesDataKHR` in the raytraced triangle example to prevent a validation error. By @Vecvec in [#6282](https://github.com/gfx-rs/wgpu/pull/6282) +#### Metal + +- Use autogenerated `objc2` bindings internally, which should resolve a lot of leaks and unsoundness. By @madsmtm in [#5641](https://github.com/gfx-rs/wgpu/pull/5641). + ### Changes - `wgpu_hal::gles::Adapter::new_external` now requires the context to be current when dropping the adapter and related objects. By @Imberflur in [#6114](https://github.com/gfx-rs/wgpu/pull/6114). diff --git a/Cargo.lock b/Cargo.lock index 74910d9290..3980dd15bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -337,12 +337,6 @@ dependencies = [ "serde", ] -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - [[package]] name = "block-sys" version = "0.2.1" @@ -359,7 +353,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" dependencies = [ "block-sys", - "objc2", + "objc2 0.4.1", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", ] [[package]] @@ -1333,7 +1336,7 @@ dependencies = [ "glutin_wgl_sys 0.5.0", "icrate", "libloading", - "objc2", + "objc2 0.4.1", "once_cell", "raw-window-handle 0.5.2", "wayland-sys", @@ -1520,9 +1523,9 @@ version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" dependencies = [ - "block2", + "block2 0.3.0", "dispatch", - "objc2", + "objc2 0.4.1", ] [[package]] @@ -1769,15 +1772,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - [[package]] name = "matchers" version = "0.1.0" @@ -1811,21 +1805,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "metal" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" -dependencies = [ - "bitflags 2.6.0", - "block", - "core-graphics-types", - "foreign-types", - "log", - "objc", - "paste", -] - [[package]] name = "minicov" version = "0.3.5" @@ -2076,15 +2055,6 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "059c95245738cdc7b40078cdd51a23200252a4c0a0a6dd005136152b3f467a4a" -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - [[package]] name = "objc-sys" version = "0.3.5" @@ -2098,7 +2068,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" dependencies = [ "objc-sys", - "objc2-encode", + "objc2-encode 3.0.0", +] + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode 4.0.3", ] [[package]] @@ -2107,6 +2087,49 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" +[[package]] +name = "objc2-encode" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.6.0", + "block2 0.5.1", + "libc", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.6.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.6.0", + "block2 0.5.1", + "objc2 0.5.2", + "objc2-foundation", + "objc2-metal", +] + [[package]] name = "object" version = "0.36.4" @@ -2199,12 +2222,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "percent-encoding" version = "2.3.1" @@ -3680,11 +3697,10 @@ dependencies = [ "ash", "bit-set", "bitflags 2.6.0", - "block", + "block2 0.5.1", "bytemuck", "cfg-if", "cfg_aliases", - "core-graphics-types", "env_logger", "glam", "glow", @@ -3699,10 +3715,12 @@ dependencies = [ "libc", "libloading", "log", - "metal", "naga", "ndk-sys", - "objc", + "objc2 0.5.2", + "objc2-foundation", + "objc2-metal", + "objc2-quartz-core", "once_cell", "parking_lot", "profiling", @@ -4134,7 +4152,7 @@ dependencies = [ "memmap2", "ndk", "ndk-sys", - "objc2", + "objc2 0.4.1", "once_cell", "orbclient", "percent-encoding", diff --git a/Cargo.toml b/Cargo.toml index 68c29b671b..1ae18d6ed0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -134,10 +134,51 @@ wgpu-types = { version = "22.0.0", path = "./wgpu-types" } winit = { version = "0.29", features = ["android-native-activity"] } # Metal dependencies -block = "0.1" -core-graphics-types = "0.1" -metal = { version = "0.29.0" } -objc = "0.2.5" +block2 = "0.5.1" +objc2 = "0.5.2" +objc2-foundation = { version = "0.2.2", features = [ + "NSError", + "NSGeometry", + "NSProcessInfo", + "NSRange", + "NSString", + "NSThread", +] } +objc2-metal = { version = "0.2.2", features = [ + "block2", + "MTLBlitCommandEncoder", + "MTLBlitPass", + "MTLBuffer", + "MTLCaptureManager", + "MTLCaptureScope", + "MTLCommandBuffer", + "MTLCommandEncoder", + "MTLCommandQueue", + "MTLComputeCommandEncoder", + "MTLComputePass", + "MTLComputePipeline", + "MTLCounters", + "MTLDepthStencil", + "MTLDevice", + "MTLDrawable", + "MTLLibrary", + "MTLPipeline", + "MTLPixelFormat", + "MTLRenderCommandEncoder", + "MTLRenderPass", + "MTLRenderPipeline", + "MTLResource", + "MTLSampler", + "MTLStageInputOutputDescriptor", + "MTLTexture", + "MTLTypes", + "MTLVertexDescriptor", +] } +objc2-quartz-core = { version = "0.2.2", features = [ + "CALayer", + "CAMetalLayer", + "objc2-metal", +] } # Vulkan dependencies android_system_properties = "0.1.1" diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 03af10b96e..9d9b772e42 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -18,10 +18,9 @@ rust-version = "1.76" [package.metadata.docs.rs] # Ideally we would enable all the features. # -# However, the metal features fail to be documented because the docs.rs runner cross-compiling under -# x86_64-unknown-linux-gnu and metal-rs cannot compile in that environment at the moment. The same applies -# for the dx12 feature. -features = ["vulkan", "gles", "renderdoc"] +# However, the dx12 features fail to be documented because the docs.rs runner cross-compiling under +# x86_64-unknown-linux-gnu cannot compile in that environment at the moment. +features = ["metal", "vulkan", "gles", "renderdoc"] rustdoc-args = ["--cfg", "docsrs"] targets = [ "x86_64-unknown-linux-gnu", @@ -43,7 +42,6 @@ ignored = ["cfg_aliases"] metal = [ # Metal is only available on Apple platforms, therefore request MSL output also only if we target an Apple platform. "naga/msl-out-if-target-apple", - "dep:block", ] vulkan = [ "naga/spv-out", @@ -166,11 +164,11 @@ glutin_wgl_sys = { workspace = true, optional = true } [target.'cfg(any(target_os="macos", target_os="ios"))'.dependencies] # backend: Metal -block = { workspace = true, optional = true } - -metal.workspace = true -objc.workspace = true -core-graphics-types.workspace = true +block2.workspace = true +objc2.workspace = true +objc2-foundation.workspace = true +objc2-metal.workspace = true +objc2-quartz-core.workspace = true [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] wasm-bindgen.workspace = true diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index 42aec2b253..6ceb57b664 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -1313,10 +1313,11 @@ impl crate::Surface for Surface { let window_ptr = handle.ns_view.as_ptr(); #[cfg(target_os = "macos")] let window_ptr = { - use objc::{msg_send, runtime::Object, sel, sel_impl}; + use objc2::msg_send; + use objc2::runtime::AnyObject; // ns_view always have a layer and don't need to verify that it exists. - let layer: *mut Object = - msg_send![handle.ns_view.as_ptr().cast::(), layer]; + let layer: *mut AnyObject = + msg_send![handle.ns_view.as_ptr().cast::(), layer]; layer.cast::() }; window_ptr diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index e7db97a1f9..a1e23cf882 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -1,5 +1,9 @@ -use metal::{MTLFeatureSet, MTLGPUFamily, MTLLanguageVersion, MTLReadWriteTextureTier}; -use objc::{class, msg_send, sel, sel_impl}; +use objc2::runtime::ProtocolObject; +use objc2_foundation::{NSOperatingSystemVersion, NSProcessInfo}; +use objc2_metal::{ + MTLCounterSamplingPoint, MTLDevice, MTLFeatureSet, MTLGPUFamily, MTLLanguageVersion, + MTLPixelFormat, MTLReadWriteTextureTier, +}; use parking_lot::Mutex; use wgt::{AstcBlock, AstcChannel}; @@ -7,7 +11,7 @@ use std::{sync::Arc, thread}; use super::TimestampQuerySupport; -const MAX_COMMAND_BUFFERS: u64 = 2048; +const MAX_COMMAND_BUFFERS: usize = 2048; unsafe impl Send for super::Adapter {} unsafe impl Sync for super::Adapter {} @@ -31,7 +35,8 @@ impl crate::Adapter for super::Adapter { .shared .device .lock() - .new_command_queue_with_max_command_buffer_count(MAX_COMMAND_BUFFERS); + .newCommandQueueWithMaxCommandBufferCount(MAX_COMMAND_BUFFERS) + .unwrap(); // Acquiring the meaning of timestamp ticks is hard with Metal! // The only thing there is is a method correlating cpu & gpu timestamps (`device.sample_timestamps`). @@ -52,7 +57,14 @@ impl crate::Adapter for super::Adapter { // Based on: // * https://github.com/gfx-rs/wgpu/pull/2528 // * https://github.com/gpuweb/gpuweb/issues/1325#issuecomment-761041326 - let timestamp_period = if self.shared.device.lock().name().starts_with("Intel") { + let timestamp_period = if self + .shared + .device + .lock() + .name() + .to_string() + .starts_with("Intel") + { 83.333 } else { // Known for Apple Silicon (at least M1 & M2, iPad Pro 2018) and AMD GPUs. @@ -84,9 +96,15 @@ impl crate::Adapter for super::Adapter { // https://developer.apple.com/documentation/metal/mtlreadwritetexturetier/mtlreadwritetexturetier1?language=objc // https://developer.apple.com/documentation/metal/mtlreadwritetexturetier/mtlreadwritetexturetier2?language=objc let (read_write_tier1_if, read_write_tier2_if) = match pc.read_write_texture_tier { - MTLReadWriteTextureTier::TierNone => (Tfc::empty(), Tfc::empty()), - MTLReadWriteTextureTier::Tier1 => (Tfc::STORAGE_READ_WRITE, Tfc::empty()), - MTLReadWriteTextureTier::Tier2 => (Tfc::STORAGE_READ_WRITE, Tfc::STORAGE_READ_WRITE), + MTLReadWriteTextureTier::None => (Tfc::empty(), Tfc::empty()), + MTLReadWriteTextureTier::MTLReadWriteTextureTier1 => { + (Tfc::STORAGE_READ_WRITE, Tfc::empty()) + } + MTLReadWriteTextureTier::MTLReadWriteTextureTier2 => { + (Tfc::STORAGE_READ_WRITE, Tfc::STORAGE_READ_WRITE) + } + // Fall back to `MTLReadWriteTextureTier2` + _ => (Tfc::STORAGE_READ_WRITE, Tfc::STORAGE_READ_WRITE), }; let msaa_count = pc.sample_count_mask; @@ -103,9 +121,9 @@ impl crate::Adapter for super::Adapter { let is_not_apple1x = super::PrivateCapabilities::supports_any( self.shared.device.lock().as_ref(), &[ - MTLFeatureSet::iOS_GPUFamily2_v1, - MTLFeatureSet::macOS_GPUFamily1_v1, - MTLFeatureSet::tvOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily2_v1, + MTLFeatureSet::_macOS_GPUFamily1_v1, + MTLFeatureSet::_tvOS_GPUFamily1_v1, ], ); @@ -356,79 +374,79 @@ impl crate::Adapter for super::Adapter { } const RESOURCE_HEAP_SUPPORT: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily1_v3, - MTLFeatureSet::tvOS_GPUFamily1_v2, - MTLFeatureSet::macOS_GPUFamily1_v3, + MTLFeatureSet::_iOS_GPUFamily1_v3, + MTLFeatureSet::_tvOS_GPUFamily1_v2, + MTLFeatureSet::_macOS_GPUFamily1_v3, ]; const ARGUMENT_BUFFER_SUPPORT: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily1_v4, - MTLFeatureSet::tvOS_GPUFamily1_v3, - MTLFeatureSet::macOS_GPUFamily1_v3, + MTLFeatureSet::_iOS_GPUFamily1_v4, + MTLFeatureSet::_tvOS_GPUFamily1_v3, + MTLFeatureSet::_macOS_GPUFamily1_v3, ]; const MUTABLE_COMPARISON_SAMPLER_SUPPORT: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily3_v1, - MTLFeatureSet::macOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily3_v1, + MTLFeatureSet::_macOS_GPUFamily1_v1, ]; -const SAMPLER_CLAMP_TO_BORDER_SUPPORT: &[MTLFeatureSet] = &[MTLFeatureSet::macOS_GPUFamily1_v2]; +const SAMPLER_CLAMP_TO_BORDER_SUPPORT: &[MTLFeatureSet] = &[MTLFeatureSet::_macOS_GPUFamily1_v2]; const ASTC_PIXEL_FORMAT_FEATURES: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily2_v1, - MTLFeatureSet::tvOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily2_v1, + MTLFeatureSet::_tvOS_GPUFamily1_v1, ]; const ANY8_UNORM_SRGB_ALL: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily2_v3, - MTLFeatureSet::tvOS_GPUFamily1_v2, + MTLFeatureSet::_iOS_GPUFamily2_v3, + MTLFeatureSet::_tvOS_GPUFamily1_v2, ]; const ANY8_SNORM_RESOLVE: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily2_v1, - MTLFeatureSet::tvOS_GPUFamily1_v1, - MTLFeatureSet::macOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily2_v1, + MTLFeatureSet::_tvOS_GPUFamily1_v1, + MTLFeatureSet::_macOS_GPUFamily1_v1, ]; const RGBA8_SRGB: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily2_v3, - MTLFeatureSet::tvOS_GPUFamily1_v2, + MTLFeatureSet::_iOS_GPUFamily2_v3, + MTLFeatureSet::_tvOS_GPUFamily1_v2, ]; const RGB10A2UNORM_ALL: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily3_v1, - MTLFeatureSet::tvOS_GPUFamily2_v1, - MTLFeatureSet::macOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily3_v1, + MTLFeatureSet::_tvOS_GPUFamily2_v1, + MTLFeatureSet::_macOS_GPUFamily1_v1, ]; const RGB10A2UINT_WRITE: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily3_v1, - MTLFeatureSet::tvOS_GPUFamily2_v1, - MTLFeatureSet::macOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily3_v1, + MTLFeatureSet::_tvOS_GPUFamily2_v1, + MTLFeatureSet::_macOS_GPUFamily1_v1, ]; const RG11B10FLOAT_ALL: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily3_v1, - MTLFeatureSet::tvOS_GPUFamily2_v1, - MTLFeatureSet::macOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily3_v1, + MTLFeatureSet::_tvOS_GPUFamily2_v1, + MTLFeatureSet::_macOS_GPUFamily1_v1, ]; const RGB9E5FLOAT_ALL: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily3_v1, - MTLFeatureSet::tvOS_GPUFamily2_v1, + MTLFeatureSet::_iOS_GPUFamily3_v1, + MTLFeatureSet::_tvOS_GPUFamily2_v1, ]; const BGR10A2_ALL: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily1_v4, - MTLFeatureSet::tvOS_GPUFamily1_v3, - MTLFeatureSet::macOS_GPUFamily2_v1, + MTLFeatureSet::_iOS_GPUFamily1_v4, + MTLFeatureSet::_tvOS_GPUFamily1_v3, + MTLFeatureSet::_macOS_GPUFamily2_v1, ]; /// "Indirect draw & dispatch arguments" in the Metal feature set tables const INDIRECT_DRAW_DISPATCH_SUPPORT: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily3_v1, - MTLFeatureSet::tvOS_GPUFamily2_v1, - MTLFeatureSet::macOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily3_v1, + MTLFeatureSet::_tvOS_GPUFamily2_v1, + MTLFeatureSet::_macOS_GPUFamily1_v1, ]; /// "Base vertex/instance drawing" in the Metal feature set tables @@ -437,124 +455,121 @@ const INDIRECT_DRAW_DISPATCH_SUPPORT: &[MTLFeatureSet] = &[ const BASE_VERTEX_FIRST_INSTANCE_SUPPORT: &[MTLFeatureSet] = INDIRECT_DRAW_DISPATCH_SUPPORT; const TEXTURE_CUBE_ARRAY_SUPPORT: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily4_v1, - MTLFeatureSet::tvOS_GPUFamily1_v2, - MTLFeatureSet::macOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily4_v1, + MTLFeatureSet::_tvOS_GPUFamily1_v2, + MTLFeatureSet::_macOS_GPUFamily1_v1, ]; const DUAL_SOURCE_BLEND_SUPPORT: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily1_v4, - MTLFeatureSet::tvOS_GPUFamily1_v3, - MTLFeatureSet::macOS_GPUFamily1_v2, + MTLFeatureSet::_iOS_GPUFamily1_v4, + MTLFeatureSet::_tvOS_GPUFamily1_v3, + MTLFeatureSet::_macOS_GPUFamily1_v2, ]; const LAYERED_RENDERING_SUPPORT: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily5_v1, - MTLFeatureSet::macOS_GPUFamily1_v1, - MTLFeatureSet::macOS_GPUFamily2_v1, + MTLFeatureSet::_iOS_GPUFamily5_v1, + MTLFeatureSet::_macOS_GPUFamily1_v1, + MTLFeatureSet::_macOS_GPUFamily2_v1, ]; const FUNCTION_SPECIALIZATION_SUPPORT: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily1_v3, - MTLFeatureSet::tvOS_GPUFamily1_v2, - MTLFeatureSet::macOS_GPUFamily1_v2, + MTLFeatureSet::_iOS_GPUFamily1_v3, + MTLFeatureSet::_tvOS_GPUFamily1_v2, + MTLFeatureSet::_macOS_GPUFamily1_v2, ]; const DEPTH_CLIP_MODE: &[MTLFeatureSet] = &[ - MTLFeatureSet::iOS_GPUFamily4_v1, - MTLFeatureSet::tvOS_GPUFamily1_v3, - MTLFeatureSet::macOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily4_v1, + MTLFeatureSet::_tvOS_GPUFamily1_v3, + MTLFeatureSet::_macOS_GPUFamily1_v1, ]; -const OS_NOT_SUPPORT: (usize, usize) = (10000, 0); +const OS_NOT_SUPPORT: (isize, isize) = (10000, 0); impl super::PrivateCapabilities { - fn supports_any(raw: &metal::DeviceRef, features_sets: &[MTLFeatureSet]) -> bool { + fn supports_any(raw: &ProtocolObject, features_sets: &[MTLFeatureSet]) -> bool { features_sets .iter() .cloned() - .any(|x| raw.supports_feature_set(x)) + .any(|x| raw.supportsFeatureSet(x)) } - pub fn new(device: &metal::Device) -> Self { - #[repr(C)] - #[derive(Clone, Copy, Debug)] - #[allow(clippy::upper_case_acronyms)] - struct NSOperatingSystemVersion { - major: usize, - minor: usize, - patch: usize, + pub fn new(device: &ProtocolObject) -> Self { + trait AtLeast { + fn at_least( + &self, + mac_version: (isize, isize), + ios_version: (isize, isize), + is_mac: bool, + ) -> bool; } - impl NSOperatingSystemVersion { + impl AtLeast for NSOperatingSystemVersion { fn at_least( &self, - mac_version: (usize, usize), - ios_version: (usize, usize), + mac_version: (isize, isize), + ios_version: (isize, isize), is_mac: bool, ) -> bool { if is_mac { - self.major > mac_version.0 - || (self.major == mac_version.0 && self.minor >= mac_version.1) + self.majorVersion > mac_version.0 + || (self.majorVersion == mac_version.0 + && self.minorVersion >= mac_version.1) } else { - self.major > ios_version.0 - || (self.major == ios_version.0 && self.minor >= ios_version.1) + self.majorVersion > ios_version.0 + || (self.majorVersion == ios_version.0 + && self.minorVersion >= ios_version.1) } } } - let version: NSOperatingSystemVersion = unsafe { - let process_info: *mut objc::runtime::Object = - msg_send![class!(NSProcessInfo), processInfo]; - msg_send![process_info, operatingSystemVersion] - }; + let version = NSProcessInfo::processInfo().operatingSystemVersion(); - let os_is_mac = device.supports_feature_set(MTLFeatureSet::macOS_GPUFamily1_v1); + let os_is_mac = device.supportsFeatureSet(MTLFeatureSet::_macOS_GPUFamily1_v1); // Metal was first introduced in OS X 10.11 and iOS 8. The current version number of visionOS is 1.0.0. Additionally, // on the Simulator, Apple only provides the Apple2 GPU capability, and the Apple2+ GPU capability covers the capabilities of Apple2. // Therefore, the following conditions can be used to determine if it is visionOS. // https://developer.apple.com/documentation/metal/developing_metal_apps_that_run_in_simulator - let os_is_xr = version.major < 8 && device.supports_family(MTLGPUFamily::Apple2); + let os_is_xr = version.majorVersion < 8 && device.supportsFamily(MTLGPUFamily::Apple2); let family_check = os_is_xr || version.at_least((10, 15), (13, 0), os_is_mac); let mut sample_count_mask = crate::TextureFormatCapabilities::MULTISAMPLE_X4; // 1 and 4 samples are supported on all devices - if device.supports_texture_sample_count(2) { + if device.supportsTextureSampleCount(2) { sample_count_mask |= crate::TextureFormatCapabilities::MULTISAMPLE_X2; } - if device.supports_texture_sample_count(8) { + if device.supportsTextureSampleCount(8) { sample_count_mask |= crate::TextureFormatCapabilities::MULTISAMPLE_X8; } - if device.supports_texture_sample_count(16) { + if device.supportsTextureSampleCount(16) { sample_count_mask |= crate::TextureFormatCapabilities::MULTISAMPLE_X16; } let rw_texture_tier = if version.at_least((10, 13), (11, 0), os_is_mac) { - device.read_write_texture_support() + device.readWriteTextureSupport() } else if version.at_least((10, 12), OS_NOT_SUPPORT, os_is_mac) { - if Self::supports_any(device, &[MTLFeatureSet::macOS_ReadWriteTextureTier2]) { - MTLReadWriteTextureTier::Tier2 + if Self::supports_any(device, &[MTLFeatureSet::_macOS_ReadWriteTextureTier2]) { + MTLReadWriteTextureTier::MTLReadWriteTextureTier2 } else { - MTLReadWriteTextureTier::Tier1 + MTLReadWriteTextureTier::MTLReadWriteTextureTier1 } } else { - MTLReadWriteTextureTier::TierNone + MTLReadWriteTextureTier::None }; let mut timestamp_query_support = TimestampQuerySupport::empty(); if version.at_least((11, 0), (14, 0), os_is_mac) - && device.supports_counter_sampling(metal::MTLCounterSamplingPoint::AtStageBoundary) + && device.supportsCounterSampling(MTLCounterSamplingPoint::AtStageBoundary) { // If we don't support at stage boundary, don't support anything else. timestamp_query_support.insert(TimestampQuerySupport::STAGE_BOUNDARIES); - if device.supports_counter_sampling(metal::MTLCounterSamplingPoint::AtDrawBoundary) { + if device.supportsCounterSampling(MTLCounterSamplingPoint::AtDrawBoundary) { timestamp_query_support.insert(TimestampQuerySupport::ON_RENDER_ENCODER); } - if device.supports_counter_sampling(metal::MTLCounterSamplingPoint::AtDispatchBoundary) - { + if device.supportsCounterSampling(MTLCounterSamplingPoint::AtDispatchBoundary) { timestamp_query_support.insert(TimestampQuerySupport::ON_COMPUTE_ENCODER); } - if device.supports_counter_sampling(metal::MTLCounterSamplingPoint::AtBlitBoundary) { + if device.supportsCounterSampling(MTLCounterSamplingPoint::AtBlitBoundary) { timestamp_query_support.insert(TimestampQuerySupport::ON_BLIT_ENCODER); } // `TimestampQuerySupport::INSIDE_WGPU_PASSES` emerges from the other flags. @@ -563,36 +578,36 @@ impl super::PrivateCapabilities { Self { family_check, msl_version: if os_is_xr || version.at_least((14, 0), (17, 0), os_is_mac) { - MTLLanguageVersion::V3_1 + MTLLanguageVersion::MTLLanguageVersion3_1 } else if version.at_least((13, 0), (16, 0), os_is_mac) { - MTLLanguageVersion::V3_0 + MTLLanguageVersion::MTLLanguageVersion3_0 } else if version.at_least((12, 0), (15, 0), os_is_mac) { - MTLLanguageVersion::V2_4 + MTLLanguageVersion::MTLLanguageVersion2_4 } else if version.at_least((11, 0), (14, 0), os_is_mac) { - MTLLanguageVersion::V2_3 + MTLLanguageVersion::MTLLanguageVersion2_3 } else if version.at_least((10, 15), (13, 0), os_is_mac) { - MTLLanguageVersion::V2_2 + MTLLanguageVersion::MTLLanguageVersion2_2 } else if version.at_least((10, 14), (12, 0), os_is_mac) { - MTLLanguageVersion::V2_1 + MTLLanguageVersion::MTLLanguageVersion2_1 } else if version.at_least((10, 13), (11, 0), os_is_mac) { - MTLLanguageVersion::V2_0 + MTLLanguageVersion::MTLLanguageVersion2_0 } else if version.at_least((10, 12), (10, 0), os_is_mac) { - MTLLanguageVersion::V1_2 + MTLLanguageVersion::MTLLanguageVersion1_2 } else if version.at_least((10, 11), (9, 0), os_is_mac) { - MTLLanguageVersion::V1_1 + MTLLanguageVersion::MTLLanguageVersion1_1 } else { - MTLLanguageVersion::V1_0 + MTLLanguageVersion::MTLLanguageVersion1_0 }, // macOS 10.11 doesn't support read-write resources fragment_rw_storage: version.at_least((10, 12), (8, 0), os_is_mac), read_write_texture_tier: rw_texture_tier, msaa_desktop: os_is_mac, msaa_apple3: if family_check { - device.supports_family(MTLGPUFamily::Apple3) + device.supportsFamily(MTLGPUFamily::Apple3) } else { - device.supports_feature_set(MTLFeatureSet::iOS_GPUFamily3_v4) + device.supportsFeatureSet(MTLFeatureSet::_iOS_GPUFamily3_v4) }, - msaa_apple7: family_check && device.supports_family(MTLGPUFamily::Apple7), + msaa_apple7: family_check && device.supportsFamily(MTLGPUFamily::Apple7), resource_heaps: Self::supports_any(device, RESOURCE_HEAP_SUPPORT), argument_buffers: Self::supports_any(device, ARGUMENT_BUFFER_SUPPORT), shared_textures: !os_is_mac, @@ -607,16 +622,16 @@ impl super::PrivateCapabilities { BASE_VERTEX_FIRST_INSTANCE_SUPPORT, ), dual_source_blending: Self::supports_any(device, DUAL_SOURCE_BLEND_SUPPORT), - low_power: !os_is_mac || device.is_low_power(), - headless: os_is_mac && device.is_headless(), + low_power: !os_is_mac || device.isLowPower(), + headless: os_is_mac && device.isHeadless(), layered_rendering: Self::supports_any(device, LAYERED_RENDERING_SUPPORT), function_specialization: Self::supports_any(device, FUNCTION_SPECIALIZATION_SUPPORT), depth_clip_mode: Self::supports_any(device, DEPTH_CLIP_MODE), texture_cube_array: Self::supports_any(device, TEXTURE_CUBE_ARRAY_SUPPORT), supports_float_filtering: os_is_mac || (version.at_least((11, 0), (14, 0), os_is_mac) - && device.supports_32bit_float_filtering()), - format_depth24_stencil8: os_is_mac && device.d24_s8_supported(), + && device.supports32BitFloatFiltering()), + format_depth24_stencil8: os_is_mac && device.isDepth24Stencil8PixelFormatSupported(), format_depth32_stencil8_filter: os_is_mac, format_depth32_stencil8_none: !os_is_mac, format_min_srgb_channels: if os_is_mac { 4 } else { 1 }, @@ -624,12 +639,12 @@ impl super::PrivateCapabilities { format_bc: os_is_mac, format_eac_etc: !os_is_mac // M1 in macOS supports EAC/ETC2 - || (family_check && device.supports_family(MTLGPUFamily::Apple7)), + || (family_check && device.supportsFamily(MTLGPUFamily::Apple7)), // A8(Apple2) and later always support ASTC pixel formats - format_astc: (family_check && device.supports_family(MTLGPUFamily::Apple2)) + format_astc: (family_check && device.supportsFamily(MTLGPUFamily::Apple2)) || Self::supports_any(device, ASTC_PIXEL_FORMAT_FEATURES), // A13(Apple6) M1(Apple7) and later always support HDR ASTC pixel formats - format_astc_hdr: family_check && device.supports_family(MTLGPUFamily::Apple6), + format_astc_hdr: family_check && device.supportsFamily(MTLGPUFamily::Apple6), format_any8_unorm_srgb_all: Self::supports_any(device, ANY8_UNORM_SRGB_ALL), format_any8_unorm_srgb_no_write: !Self::supports_any(device, ANY8_UNORM_SRGB_ALL) && !os_is_mac, @@ -673,8 +688,8 @@ impl super::PrivateCapabilities { format_depth16unorm: Self::supports_any( device, &[ - MTLFeatureSet::iOS_GPUFamily3_v3, - MTLFeatureSet::macOS_GPUFamily1_v2, + MTLFeatureSet::_iOS_GPUFamily3_v3, + MTLFeatureSet::_macOS_GPUFamily1_v2, ], ), format_depth32float_filter: os_is_mac, @@ -684,10 +699,10 @@ impl super::PrivateCapabilities { max_buffers_per_stage: 31, max_vertex_buffers: 31.min(crate::MAX_VERTEX_BUFFERS as u32), max_textures_per_stage: if os_is_mac - || (family_check && device.supports_family(MTLGPUFamily::Apple6)) + || (family_check && device.supportsFamily(MTLGPUFamily::Apple6)) { 128 - } else if family_check && device.supports_family(MTLGPUFamily::Apple4) { + } else if family_check && device.supportsFamily(MTLGPUFamily::Apple4) { 96 } else { 31 @@ -696,9 +711,7 @@ impl super::PrivateCapabilities { buffer_alignment: if os_is_mac || os_is_xr { 256 } else { 64 }, max_buffer_size: if version.at_least((10, 14), (12, 0), os_is_mac) { // maxBufferLength available on macOS 10.14+ and iOS 12.0+ - let buffer_size: metal::NSInteger = - unsafe { msg_send![device.as_ref(), maxBufferLength] }; - buffer_size as _ + device.maxBufferLength() as u64 } else if os_is_mac { 1 << 30 // 1GB on macOS 10.11 and up } else { @@ -707,9 +720,9 @@ impl super::PrivateCapabilities { max_texture_size: if Self::supports_any( device, &[ - MTLFeatureSet::iOS_GPUFamily3_v1, - MTLFeatureSet::tvOS_GPUFamily2_v1, - MTLFeatureSet::macOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily3_v1, + MTLFeatureSet::_tvOS_GPUFamily2_v1, + MTLFeatureSet::_macOS_GPUFamily1_v1, ], ) { 16384 @@ -719,7 +732,7 @@ impl super::PrivateCapabilities { max_texture_3d_size: 2048, max_texture_layers: 2048, max_fragment_input_components: if os_is_mac - || device.supports_feature_set(MTLFeatureSet::iOS_GPUFamily4_v1) + || device.supportsFeatureSet(MTLFeatureSet::_iOS_GPUFamily4_v1) { 124 } else { @@ -728,9 +741,9 @@ impl super::PrivateCapabilities { max_color_render_targets: if Self::supports_any( device, &[ - MTLFeatureSet::iOS_GPUFamily2_v1, - MTLFeatureSet::tvOS_GPUFamily1_v1, - MTLFeatureSet::macOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily2_v1, + MTLFeatureSet::_tvOS_GPUFamily1_v1, + MTLFeatureSet::_macOS_GPUFamily1_v1, ], ) { 8 @@ -739,14 +752,14 @@ impl super::PrivateCapabilities { }, // Per https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf max_color_attachment_bytes_per_sample: if family_check - && device.supports_family(MTLGPUFamily::Apple4) + && device.supportsFamily(MTLGPUFamily::Apple4) { 64 } else { 32 }, max_varying_components: if device - .supports_feature_set(MTLFeatureSet::macOS_GPUFamily1_v1) + .supportsFeatureSet(MTLFeatureSet::_macOS_GPUFamily1_v1) { 124 } else { @@ -755,8 +768,8 @@ impl super::PrivateCapabilities { max_threads_per_group: if Self::supports_any( device, &[ - MTLFeatureSet::iOS_GPUFamily4_v2, - MTLFeatureSet::macOS_GPUFamily1_v1, + MTLFeatureSet::_iOS_GPUFamily4_v2, + MTLFeatureSet::_macOS_GPUFamily1_v1, ], ) { 1024 @@ -766,8 +779,8 @@ impl super::PrivateCapabilities { max_total_threadgroup_memory: if Self::supports_any( device, &[ - MTLFeatureSet::iOS_GPUFamily4_v1, - MTLFeatureSet::macOS_GPUFamily1_v2, + MTLFeatureSet::_iOS_GPUFamily4_v1, + MTLFeatureSet::_macOS_GPUFamily1_v2, ], ) { 32 << 10 @@ -778,14 +791,14 @@ impl super::PrivateCapabilities { supports_debug_markers: Self::supports_any( device, &[ - MTLFeatureSet::macOS_GPUFamily1_v2, - MTLFeatureSet::iOS_GPUFamily1_v3, - MTLFeatureSet::tvOS_GPUFamily1_v2, + MTLFeatureSet::_macOS_GPUFamily1_v2, + MTLFeatureSet::_iOS_GPUFamily1_v3, + MTLFeatureSet::_tvOS_GPUFamily1_v2, ], ), supports_binary_archives: family_check - && (device.supports_family(MTLGPUFamily::Apple3) - || device.supports_family(MTLGPUFamily::Mac1)), + && (device.supportsFamily(MTLGPUFamily::Apple3) + || device.supportsFamily(MTLGPUFamily::Mac1)), supports_capture_manager: version.at_least((10, 13), (11, 0), os_is_mac), can_set_maximum_drawables_count: version.at_least((10, 14), (11, 2), os_is_mac), can_set_display_sync: version.at_least((10, 13), OS_NOT_SUPPORT, os_is_mac), @@ -793,41 +806,41 @@ impl super::PrivateCapabilities { supports_arrays_of_textures: Self::supports_any( device, &[ - MTLFeatureSet::iOS_GPUFamily3_v2, - MTLFeatureSet::tvOS_GPUFamily2_v1, - MTLFeatureSet::macOS_GPUFamily1_v3, + MTLFeatureSet::_iOS_GPUFamily3_v2, + MTLFeatureSet::_tvOS_GPUFamily2_v1, + MTLFeatureSet::_macOS_GPUFamily1_v3, ], ), supports_arrays_of_textures_write: family_check - && (device.supports_family(MTLGPUFamily::Apple6) - || device.supports_family(MTLGPUFamily::Mac1) - || device.supports_family(MTLGPUFamily::MacCatalyst1)), + && (device.supportsFamily(MTLGPUFamily::Apple6) + || device.supportsFamily(MTLGPUFamily::Mac1) + || device.supportsFamily(MTLGPUFamily::MacCatalyst1)), supports_mutability: version.at_least((10, 13), (11, 0), os_is_mac), //Depth clipping is supported on all macOS GPU families and iOS family 4 and later supports_depth_clip_control: os_is_mac - || device.supports_feature_set(MTLFeatureSet::iOS_GPUFamily4_v1), + || device.supportsFeatureSet(MTLFeatureSet::_iOS_GPUFamily4_v1), supports_preserve_invariance: version.at_least((11, 0), (13, 0), os_is_mac), // Metal 2.2 on mac, 2.3 on iOS. supports_shader_primitive_index: version.at_least((10, 15), (14, 0), os_is_mac), has_unified_memory: if version.at_least((10, 15), (13, 0), os_is_mac) { - Some(device.has_unified_memory()) + Some(device.hasUnifiedMemory()) } else { None }, timestamp_query_support, supports_simd_scoped_operations: family_check - && (device.supports_family(MTLGPUFamily::Metal3) - || device.supports_family(MTLGPUFamily::Mac2) - || device.supports_family(MTLGPUFamily::Apple7)), + && (device.supportsFamily(MTLGPUFamily::Metal3) + || device.supportsFamily(MTLGPUFamily::Mac2) + || device.supportsFamily(MTLGPUFamily::Apple7)), // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=5 int64: family_check - && (device.supports_family(MTLGPUFamily::Apple3) - || device.supports_family(MTLGPUFamily::Metal3)), + && (device.supportsFamily(MTLGPUFamily::Apple3) + || device.supportsFamily(MTLGPUFamily::Metal3)), // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf#page=6 int64_atomics: family_check - && ((device.supports_family(MTLGPUFamily::Apple8) - && device.supports_family(MTLGPUFamily::Mac2)) - || device.supports_family(MTLGPUFamily::Apple9)), + && ((device.supportsFamily(MTLGPUFamily::Apple8) + && device.supportsFamily(MTLGPUFamily::Mac2)) + || device.supportsFamily(MTLGPUFamily::Apple9)), } } @@ -871,7 +884,8 @@ impl super::PrivateCapabilities { ); features.set( F::DUAL_SOURCE_BLENDING, - self.msl_version >= MTLLanguageVersion::V1_2 && self.dual_source_blending, + self.msl_version >= MTLLanguageVersion::MTLLanguageVersion1_2 + && self.dual_source_blending, ); features.set(F::TEXTURE_COMPRESSION_ASTC, self.format_astc); features.set(F::TEXTURE_COMPRESSION_ASTC_HDR, self.format_astc_hdr); @@ -889,12 +903,13 @@ impl super::PrivateCapabilities { F::TEXTURE_BINDING_ARRAY | F::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING | F::UNIFORM_BUFFER_AND_STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING, - self.msl_version >= MTLLanguageVersion::V2_0 && self.supports_arrays_of_textures, + self.msl_version >= MTLLanguageVersion::MTLLanguageVersion2_0 + && self.supports_arrays_of_textures, ); //// XXX: this is technically not true, as read-only storage images can be used in arrays //// on precisely the same conditions that sampled textures can. But texel fetch from a //// sampled texture is a thing; should we bother introducing another feature flag? - if self.msl_version >= MTLLanguageVersion::V2_2 + if self.msl_version >= MTLLanguageVersion::MTLLanguageVersion2_2 && self.supports_arrays_of_textures && self.supports_arrays_of_textures_write { @@ -902,11 +917,11 @@ impl super::PrivateCapabilities { } features.set( F::SHADER_INT64, - self.int64 && self.msl_version >= MTLLanguageVersion::V2_3, + self.int64 && self.msl_version >= MTLLanguageVersion::MTLLanguageVersion2_3, ); features.set( F::SHADER_INT64_ATOMIC_MIN_MAX, - self.int64_atomics && self.msl_version >= MTLLanguageVersion::V2_4, + self.int64_atomics && self.msl_version >= MTLLanguageVersion::MTLLanguageVersion2_4, ); features.set( @@ -1006,144 +1021,144 @@ impl super::PrivateCapabilities { } } - pub fn map_format(&self, format: wgt::TextureFormat) -> metal::MTLPixelFormat { - use metal::MTLPixelFormat::*; + pub fn map_format(&self, format: wgt::TextureFormat) -> MTLPixelFormat { use wgt::TextureFormat as Tf; + use MTLPixelFormat as MTL; match format { - Tf::R8Unorm => R8Unorm, - Tf::R8Snorm => R8Snorm, - Tf::R8Uint => R8Uint, - Tf::R8Sint => R8Sint, - Tf::R16Uint => R16Uint, - Tf::R16Sint => R16Sint, - Tf::R16Unorm => R16Unorm, - Tf::R16Snorm => R16Snorm, - Tf::R16Float => R16Float, - Tf::Rg8Unorm => RG8Unorm, - Tf::Rg8Snorm => RG8Snorm, - Tf::Rg8Uint => RG8Uint, - Tf::Rg8Sint => RG8Sint, - Tf::Rg16Unorm => RG16Unorm, - Tf::Rg16Snorm => RG16Snorm, - Tf::R32Uint => R32Uint, - Tf::R32Sint => R32Sint, - Tf::R32Float => R32Float, - Tf::Rg16Uint => RG16Uint, - Tf::Rg16Sint => RG16Sint, - Tf::Rg16Float => RG16Float, - Tf::Rgba8Unorm => RGBA8Unorm, - Tf::Rgba8UnormSrgb => RGBA8Unorm_sRGB, - Tf::Bgra8UnormSrgb => BGRA8Unorm_sRGB, - Tf::Rgba8Snorm => RGBA8Snorm, - Tf::Bgra8Unorm => BGRA8Unorm, - Tf::Rgba8Uint => RGBA8Uint, - Tf::Rgba8Sint => RGBA8Sint, - Tf::Rgb10a2Uint => RGB10A2Uint, - Tf::Rgb10a2Unorm => RGB10A2Unorm, - Tf::Rg11b10Ufloat => RG11B10Float, - Tf::Rg32Uint => RG32Uint, - Tf::Rg32Sint => RG32Sint, - Tf::Rg32Float => RG32Float, - Tf::Rgba16Uint => RGBA16Uint, - Tf::Rgba16Sint => RGBA16Sint, - Tf::Rgba16Unorm => RGBA16Unorm, - Tf::Rgba16Snorm => RGBA16Snorm, - Tf::Rgba16Float => RGBA16Float, - Tf::Rgba32Uint => RGBA32Uint, - Tf::Rgba32Sint => RGBA32Sint, - Tf::Rgba32Float => RGBA32Float, - Tf::Stencil8 => Stencil8, - Tf::Depth16Unorm => Depth16Unorm, - Tf::Depth32Float => Depth32Float, - Tf::Depth32FloatStencil8 => Depth32Float_Stencil8, + Tf::R8Unorm => MTL::R8Unorm, + Tf::R8Snorm => MTL::R8Snorm, + Tf::R8Uint => MTL::R8Uint, + Tf::R8Sint => MTL::R8Sint, + Tf::R16Uint => MTL::R16Uint, + Tf::R16Sint => MTL::R16Sint, + Tf::R16Unorm => MTL::R16Unorm, + Tf::R16Snorm => MTL::R16Snorm, + Tf::R16Float => MTL::R16Float, + Tf::Rg8Unorm => MTL::RG8Unorm, + Tf::Rg8Snorm => MTL::RG8Snorm, + Tf::Rg8Uint => MTL::RG8Uint, + Tf::Rg8Sint => MTL::RG8Sint, + Tf::Rg16Unorm => MTL::RG16Unorm, + Tf::Rg16Snorm => MTL::RG16Snorm, + Tf::R32Uint => MTL::R32Uint, + Tf::R32Sint => MTL::R32Sint, + Tf::R32Float => MTL::R32Float, + Tf::Rg16Uint => MTL::RG16Uint, + Tf::Rg16Sint => MTL::RG16Sint, + Tf::Rg16Float => MTL::RG16Float, + Tf::Rgba8Unorm => MTL::RGBA8Unorm, + Tf::Rgba8UnormSrgb => MTL::RGBA8Unorm_sRGB, + Tf::Bgra8UnormSrgb => MTL::BGRA8Unorm_sRGB, + Tf::Rgba8Snorm => MTL::RGBA8Snorm, + Tf::Bgra8Unorm => MTL::BGRA8Unorm, + Tf::Rgba8Uint => MTL::RGBA8Uint, + Tf::Rgba8Sint => MTL::RGBA8Sint, + Tf::Rgb10a2Uint => MTL::RGB10A2Uint, + Tf::Rgb10a2Unorm => MTL::RGB10A2Unorm, + Tf::Rg11b10Ufloat => MTL::RG11B10Float, + Tf::Rg32Uint => MTL::RG32Uint, + Tf::Rg32Sint => MTL::RG32Sint, + Tf::Rg32Float => MTL::RG32Float, + Tf::Rgba16Uint => MTL::RGBA16Uint, + Tf::Rgba16Sint => MTL::RGBA16Sint, + Tf::Rgba16Unorm => MTL::RGBA16Unorm, + Tf::Rgba16Snorm => MTL::RGBA16Snorm, + Tf::Rgba16Float => MTL::RGBA16Float, + Tf::Rgba32Uint => MTL::RGBA32Uint, + Tf::Rgba32Sint => MTL::RGBA32Sint, + Tf::Rgba32Float => MTL::RGBA32Float, + Tf::Stencil8 => MTL::Stencil8, + Tf::Depth16Unorm => MTL::Depth16Unorm, + Tf::Depth32Float => MTL::Depth32Float, + Tf::Depth32FloatStencil8 => MTL::Depth32Float_Stencil8, Tf::Depth24Plus => { if self.format_depth24_stencil8 { - Depth24Unorm_Stencil8 + MTL::Depth24Unorm_Stencil8 } else { - Depth32Float + MTL::Depth32Float } } Tf::Depth24PlusStencil8 => { if self.format_depth24_stencil8 { - Depth24Unorm_Stencil8 + MTL::Depth24Unorm_Stencil8 } else { - Depth32Float_Stencil8 + MTL::Depth32Float_Stencil8 } } Tf::NV12 => unreachable!(), - Tf::Rgb9e5Ufloat => RGB9E5Float, - Tf::Bc1RgbaUnorm => BC1_RGBA, - Tf::Bc1RgbaUnormSrgb => BC1_RGBA_sRGB, - Tf::Bc2RgbaUnorm => BC2_RGBA, - Tf::Bc2RgbaUnormSrgb => BC2_RGBA_sRGB, - Tf::Bc3RgbaUnorm => BC3_RGBA, - Tf::Bc3RgbaUnormSrgb => BC3_RGBA_sRGB, - Tf::Bc4RUnorm => BC4_RUnorm, - Tf::Bc4RSnorm => BC4_RSnorm, - Tf::Bc5RgUnorm => BC5_RGUnorm, - Tf::Bc5RgSnorm => BC5_RGSnorm, - Tf::Bc6hRgbFloat => BC6H_RGBFloat, - Tf::Bc6hRgbUfloat => BC6H_RGBUfloat, - Tf::Bc7RgbaUnorm => BC7_RGBAUnorm, - Tf::Bc7RgbaUnormSrgb => BC7_RGBAUnorm_sRGB, - Tf::Etc2Rgb8Unorm => ETC2_RGB8, - Tf::Etc2Rgb8UnormSrgb => ETC2_RGB8_sRGB, - Tf::Etc2Rgb8A1Unorm => ETC2_RGB8A1, - Tf::Etc2Rgb8A1UnormSrgb => ETC2_RGB8A1_sRGB, - Tf::Etc2Rgba8Unorm => EAC_RGBA8, - Tf::Etc2Rgba8UnormSrgb => EAC_RGBA8_sRGB, - Tf::EacR11Unorm => EAC_R11Unorm, - Tf::EacR11Snorm => EAC_R11Snorm, - Tf::EacRg11Unorm => EAC_RG11Unorm, - Tf::EacRg11Snorm => EAC_RG11Snorm, + Tf::Rgb9e5Ufloat => MTL::RGB9E5Float, + Tf::Bc1RgbaUnorm => MTL::BC1_RGBA, + Tf::Bc1RgbaUnormSrgb => MTL::BC1_RGBA_sRGB, + Tf::Bc2RgbaUnorm => MTL::BC2_RGBA, + Tf::Bc2RgbaUnormSrgb => MTL::BC2_RGBA_sRGB, + Tf::Bc3RgbaUnorm => MTL::BC3_RGBA, + Tf::Bc3RgbaUnormSrgb => MTL::BC3_RGBA_sRGB, + Tf::Bc4RUnorm => MTL::BC4_RUnorm, + Tf::Bc4RSnorm => MTL::BC4_RSnorm, + Tf::Bc5RgUnorm => MTL::BC5_RGUnorm, + Tf::Bc5RgSnorm => MTL::BC5_RGSnorm, + Tf::Bc6hRgbFloat => MTL::BC6H_RGBFloat, + Tf::Bc6hRgbUfloat => MTL::BC6H_RGBUfloat, + Tf::Bc7RgbaUnorm => MTL::BC7_RGBAUnorm, + Tf::Bc7RgbaUnormSrgb => MTL::BC7_RGBAUnorm_sRGB, + Tf::Etc2Rgb8Unorm => MTL::ETC2_RGB8, + Tf::Etc2Rgb8UnormSrgb => MTL::ETC2_RGB8_sRGB, + Tf::Etc2Rgb8A1Unorm => MTL::ETC2_RGB8A1, + Tf::Etc2Rgb8A1UnormSrgb => MTL::ETC2_RGB8A1_sRGB, + Tf::Etc2Rgba8Unorm => MTL::EAC_RGBA8, + Tf::Etc2Rgba8UnormSrgb => MTL::EAC_RGBA8_sRGB, + Tf::EacR11Unorm => MTL::EAC_R11Unorm, + Tf::EacR11Snorm => MTL::EAC_R11Snorm, + Tf::EacRg11Unorm => MTL::EAC_RG11Unorm, + Tf::EacRg11Snorm => MTL::EAC_RG11Snorm, Tf::Astc { block, channel } => match channel { AstcChannel::Unorm => match block { - AstcBlock::B4x4 => ASTC_4x4_LDR, - AstcBlock::B5x4 => ASTC_5x4_LDR, - AstcBlock::B5x5 => ASTC_5x5_LDR, - AstcBlock::B6x5 => ASTC_6x5_LDR, - AstcBlock::B6x6 => ASTC_6x6_LDR, - AstcBlock::B8x5 => ASTC_8x5_LDR, - AstcBlock::B8x6 => ASTC_8x6_LDR, - AstcBlock::B8x8 => ASTC_8x8_LDR, - AstcBlock::B10x5 => ASTC_10x5_LDR, - AstcBlock::B10x6 => ASTC_10x6_LDR, - AstcBlock::B10x8 => ASTC_10x8_LDR, - AstcBlock::B10x10 => ASTC_10x10_LDR, - AstcBlock::B12x10 => ASTC_12x10_LDR, - AstcBlock::B12x12 => ASTC_12x12_LDR, + AstcBlock::B4x4 => MTL::ASTC_4x4_LDR, + AstcBlock::B5x4 => MTL::ASTC_5x4_LDR, + AstcBlock::B5x5 => MTL::ASTC_5x5_LDR, + AstcBlock::B6x5 => MTL::ASTC_6x5_LDR, + AstcBlock::B6x6 => MTL::ASTC_6x6_LDR, + AstcBlock::B8x5 => MTL::ASTC_8x5_LDR, + AstcBlock::B8x6 => MTL::ASTC_8x6_LDR, + AstcBlock::B8x8 => MTL::ASTC_8x8_LDR, + AstcBlock::B10x5 => MTL::ASTC_10x5_LDR, + AstcBlock::B10x6 => MTL::ASTC_10x6_LDR, + AstcBlock::B10x8 => MTL::ASTC_10x8_LDR, + AstcBlock::B10x10 => MTL::ASTC_10x10_LDR, + AstcBlock::B12x10 => MTL::ASTC_12x10_LDR, + AstcBlock::B12x12 => MTL::ASTC_12x12_LDR, }, AstcChannel::UnormSrgb => match block { - AstcBlock::B4x4 => ASTC_4x4_sRGB, - AstcBlock::B5x4 => ASTC_5x4_sRGB, - AstcBlock::B5x5 => ASTC_5x5_sRGB, - AstcBlock::B6x5 => ASTC_6x5_sRGB, - AstcBlock::B6x6 => ASTC_6x6_sRGB, - AstcBlock::B8x5 => ASTC_8x5_sRGB, - AstcBlock::B8x6 => ASTC_8x6_sRGB, - AstcBlock::B8x8 => ASTC_8x8_sRGB, - AstcBlock::B10x5 => ASTC_10x5_sRGB, - AstcBlock::B10x6 => ASTC_10x6_sRGB, - AstcBlock::B10x8 => ASTC_10x8_sRGB, - AstcBlock::B10x10 => ASTC_10x10_sRGB, - AstcBlock::B12x10 => ASTC_12x10_sRGB, - AstcBlock::B12x12 => ASTC_12x12_sRGB, + AstcBlock::B4x4 => MTL::ASTC_4x4_sRGB, + AstcBlock::B5x4 => MTL::ASTC_5x4_sRGB, + AstcBlock::B5x5 => MTL::ASTC_5x5_sRGB, + AstcBlock::B6x5 => MTL::ASTC_6x5_sRGB, + AstcBlock::B6x6 => MTL::ASTC_6x6_sRGB, + AstcBlock::B8x5 => MTL::ASTC_8x5_sRGB, + AstcBlock::B8x6 => MTL::ASTC_8x6_sRGB, + AstcBlock::B8x8 => MTL::ASTC_8x8_sRGB, + AstcBlock::B10x5 => MTL::ASTC_10x5_sRGB, + AstcBlock::B10x6 => MTL::ASTC_10x6_sRGB, + AstcBlock::B10x8 => MTL::ASTC_10x8_sRGB, + AstcBlock::B10x10 => MTL::ASTC_10x10_sRGB, + AstcBlock::B12x10 => MTL::ASTC_12x10_sRGB, + AstcBlock::B12x12 => MTL::ASTC_12x12_sRGB, }, AstcChannel::Hdr => match block { - AstcBlock::B4x4 => ASTC_4x4_HDR, - AstcBlock::B5x4 => ASTC_5x4_HDR, - AstcBlock::B5x5 => ASTC_5x5_HDR, - AstcBlock::B6x5 => ASTC_6x5_HDR, - AstcBlock::B6x6 => ASTC_6x6_HDR, - AstcBlock::B8x5 => ASTC_8x5_HDR, - AstcBlock::B8x6 => ASTC_8x6_HDR, - AstcBlock::B8x8 => ASTC_8x8_HDR, - AstcBlock::B10x5 => ASTC_10x5_HDR, - AstcBlock::B10x6 => ASTC_10x6_HDR, - AstcBlock::B10x8 => ASTC_10x8_HDR, - AstcBlock::B10x10 => ASTC_10x10_HDR, - AstcBlock::B12x10 => ASTC_12x10_HDR, - AstcBlock::B12x12 => ASTC_12x12_HDR, + AstcBlock::B4x4 => MTL::ASTC_4x4_HDR, + AstcBlock::B5x4 => MTL::ASTC_5x4_HDR, + AstcBlock::B5x5 => MTL::ASTC_5x5_HDR, + AstcBlock::B6x5 => MTL::ASTC_6x5_HDR, + AstcBlock::B6x6 => MTL::ASTC_6x6_HDR, + AstcBlock::B8x5 => MTL::ASTC_8x5_HDR, + AstcBlock::B8x6 => MTL::ASTC_8x6_HDR, + AstcBlock::B8x8 => MTL::ASTC_8x8_HDR, + AstcBlock::B10x5 => MTL::ASTC_10x5_HDR, + AstcBlock::B10x6 => MTL::ASTC_10x6_HDR, + AstcBlock::B10x8 => MTL::ASTC_10x8_HDR, + AstcBlock::B10x10 => MTL::ASTC_10x10_HDR, + AstcBlock::B12x10 => MTL::ASTC_12x10_HDR, + AstcBlock::B12x12 => MTL::ASTC_12x12_HDR, }, }, } @@ -1153,21 +1168,20 @@ impl super::PrivateCapabilities { &self, format: wgt::TextureFormat, aspects: crate::FormatAspects, - ) -> metal::MTLPixelFormat { + ) -> MTLPixelFormat { use crate::FormatAspects as Fa; - use metal::MTLPixelFormat::*; use wgt::TextureFormat as Tf; match (format, aspects) { // map combined depth-stencil format to their stencil-only format // see https://developer.apple.com/library/archive/documentation/Miscellaneous/Conceptual/MetalProgrammingGuide/WhatsNewiniOS10tvOS10andOSX1012/WhatsNewiniOS10tvOS10andOSX1012.html#//apple_ref/doc/uid/TP40014221-CH14-DontLinkElementID_77 (Tf::Depth24PlusStencil8, Fa::STENCIL) => { if self.format_depth24_stencil8 { - X24_Stencil8 + MTLPixelFormat::X24_Stencil8 } else { - X32_Stencil8 + MTLPixelFormat::X32_Stencil8 } } - (Tf::Depth32FloatStencil8, Fa::STENCIL) => X32_Stencil8, + (Tf::Depth32FloatStencil8, Fa::STENCIL) => MTLPixelFormat::X32_Stencil8, _ => self.map_format(format), } @@ -1175,11 +1189,11 @@ impl super::PrivateCapabilities { } impl super::PrivateDisabilities { - pub fn new(device: &metal::Device) -> Self { - let is_intel = device.name().starts_with("Intel"); + pub fn new(device: &ProtocolObject) -> Self { + let is_intel = device.name().to_string().starts_with("Intel"); Self { broken_viewport_near_depth: is_intel - && !device.supports_feature_set(MTLFeatureSet::macOS_GPUFamily1_v4), + && !device.supportsFeatureSet(MTLFeatureSet::_macOS_GPUFamily1_v4), broken_layered_clear_image: is_intel, } } diff --git a/wgpu-hal/src/metal/command.rs b/wgpu-hal/src/metal/command.rs index 9e38cf8656..a8a51ba445 100644 --- a/wgpu-hal/src/metal/command.rs +++ b/wgpu-hal/src/metal/command.rs @@ -1,6 +1,16 @@ -use super::{conv, AsNative, TimestampQuerySupport}; +use objc2::{rc::Retained, runtime::ProtocolObject}; +use objc2_foundation::{NSRange, NSString}; +use objc2_metal::{ + MTLBlitCommandEncoder, MTLBlitPassDescriptor, MTLCommandBuffer, MTLCommandEncoder, + MTLCommandQueue, MTLComputeCommandEncoder, MTLComputePassDescriptor, MTLCounterDontSample, + MTLIndexType, MTLLoadAction, MTLPrimitiveType, MTLRenderCommandEncoder, + MTLRenderPassDescriptor, MTLScissorRect, MTLSize, MTLStoreAction, MTLTexture, MTLViewport, + MTLVisibilityResultMode, +}; + +use super::{conv, TimestampQuerySupport}; use crate::CommandEncoder as _; -use std::{borrow::Cow, mem::size_of, ops::Range}; +use std::{borrow::Cow, mem::size_of, ops::Range, ptr::NonNull}; // has to match `Temp::binding_sizes` const WORD_SIZE: usize = 4; @@ -11,9 +21,13 @@ impl Default for super::CommandState { blit: None, render: None, compute: None, - raw_primitive_type: metal::MTLPrimitiveType::Point, + raw_primitive_type: MTLPrimitiveType::Point, index: None, - raw_wg_size: metal::MTLSize::new(0, 0, 0), + raw_wg_size: MTLSize { + width: 0, + depth: 0, + height: 0, + }, stage_infos: Default::default(), storage_buffer_length_map: Default::default(), vertex_buffer_size_map: Default::default(), @@ -25,7 +39,7 @@ impl Default for super::CommandState { } impl super::CommandEncoder { - fn enter_blit(&mut self) -> &metal::BlitCommandEncoderRef { + fn enter_blit(&mut self) -> Retained> { if self.state.blit.is_none() { debug_assert!(self.state.render.is_none() && self.state.compute.is_none()); let cmd_buf = self.raw_cmd_buf.as_ref().unwrap(); @@ -52,47 +66,48 @@ impl super::CommandEncoder { .contains(TimestampQuerySupport::ON_BLIT_ENCODER); if !self.state.pending_timer_queries.is_empty() && !supports_sample_counters_in_buffer { - objc::rc::autoreleasepool(|| { - let descriptor = metal::BlitPassDescriptor::new(); + objc2::rc::autoreleasepool(|_| unsafe { + let descriptor = MTLBlitPassDescriptor::new(); let mut last_query = None; for (i, (set, index)) in self.state.pending_timer_queries.drain(..).enumerate() { let sba_descriptor = descriptor - .sample_buffer_attachments() - .object_at(i as _) - .unwrap(); + .sampleBufferAttachments() + .objectAtIndexedSubscript(i); sba_descriptor - .set_sample_buffer(set.counter_sample_buffer.as_ref().unwrap()); + .setSampleBuffer(Some(set.counter_sample_buffer.as_ref().unwrap())); // Here be dragons: // As mentioned above, for some reasons using the start of the encoder won't yield any results sometimes! - sba_descriptor - .set_start_of_encoder_sample_index(metal::COUNTER_DONT_SAMPLE); - sba_descriptor.set_end_of_encoder_sample_index(index as _); + sba_descriptor.setStartOfEncoderSampleIndex(MTLCounterDontSample); + sba_descriptor.setEndOfEncoderSampleIndex(index as _); last_query = Some((set, index)); } - let encoder = cmd_buf.blit_command_encoder_with_descriptor(descriptor); + let encoder = cmd_buf + .blitCommandEncoderWithDescriptor(&descriptor) + .unwrap(); // As explained above, we need to do some write: // Conveniently, we have a buffer with every query set, that we can use for this for a dummy write, // since we know that it is going to be overwritten again on timer resolve and HAL doesn't define its state before that. - let raw_range = metal::NSRange { - location: last_query.as_ref().unwrap().1 as u64 * crate::QUERY_SIZE, + let raw_range = NSRange { + location: last_query.as_ref().unwrap().1 as usize + * crate::QUERY_SIZE as usize, length: 1, }; - encoder.fill_buffer( + encoder.fillBuffer_range_value( &last_query.as_ref().unwrap().0.raw_buffer, raw_range, 255, // Don't write 0, so it's easier to identify if something went wrong. ); - encoder.end_encoding(); + encoder.endEncoding(); }); } - objc::rc::autoreleasepool(|| { - self.state.blit = Some(cmd_buf.new_blit_command_encoder().to_owned()); + objc2::rc::autoreleasepool(|_| { + self.state.blit = Some(cmd_buf.blitCommandEncoder().unwrap()); }); let encoder = self.state.blit.as_ref().unwrap(); @@ -101,29 +116,31 @@ impl super::CommandEncoder { // If the above described issue with empty blit encoder applies to `sample_counters_in_buffer` as well, we should use the same workaround instead! for (set, index) in self.state.pending_timer_queries.drain(..) { debug_assert!(supports_sample_counters_in_buffer); - encoder.sample_counters_in_buffer( - set.counter_sample_buffer.as_ref().unwrap(), - index as _, - true, - ) + unsafe { + encoder.sampleCountersInBuffer_atSampleIndex_withBarrier( + set.counter_sample_buffer.as_ref().unwrap(), + index as _, + true, + ) + } } } - self.state.blit.as_ref().unwrap() + self.state.blit.as_ref().unwrap().clone() } pub(super) fn leave_blit(&mut self) { if let Some(encoder) = self.state.blit.take() { - encoder.end_encoding(); + encoder.endEncoding(); } } - fn active_encoder(&mut self) -> Option<&metal::CommandEncoderRef> { + fn active_encoder(&mut self) -> Option<&ProtocolObject> { if let Some(ref encoder) = self.state.render { - Some(encoder) + Some(ProtocolObject::from_ref(&**encoder)) } else if let Some(ref encoder) = self.state.compute { - Some(encoder) + Some(ProtocolObject::from_ref(&**encoder)) } else if let Some(ref encoder) = self.state.blit { - Some(encoder) + Some(ProtocolObject::from_ref(&**encoder)) } else { None } @@ -185,14 +202,15 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn begin_encoding(&mut self, label: crate::Label) -> Result<(), crate::DeviceError> { let queue = &self.raw_queue.lock(); let retain_references = self.shared.settings.retain_command_buffer_references; - let raw = objc::rc::autoreleasepool(move || { + let raw = objc2::rc::autoreleasepool(move |_| { let cmd_buf_ref = if retain_references { - queue.new_command_buffer() + queue.commandBuffer() } else { - queue.new_command_buffer_with_unretained_references() - }; + queue.commandBufferWithUnretainedReferences() + } + .unwrap(); if let Some(label) = label { - cmd_buf_ref.set_label(label); + cmd_buf_ref.setLabel(Some(&NSString::from_str(label))); } cmd_buf_ref.to_owned() }); @@ -207,10 +225,10 @@ impl crate::CommandEncoder for super::CommandEncoder { // when discarding, we don't have a guarantee that // everything is in a good state, so check carefully if let Some(encoder) = self.state.render.take() { - encoder.end_encoding(); + encoder.endEncoding(); } if let Some(encoder) = self.state.compute.take() { - encoder.end_encoding(); + encoder.endEncoding(); } self.raw_cmd_buf = None; } @@ -253,7 +271,7 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn clear_buffer(&mut self, buffer: &super::Buffer, range: crate::MemoryRange) { let encoder = self.enter_blit(); - encoder.fill_buffer(&buffer.raw, conv::map_range(&range), 0); + encoder.fillBuffer_range_value(&buffer.raw, conv::map_range(&range), 0); } unsafe fn copy_buffer_to_buffer( @@ -266,12 +284,12 @@ impl crate::CommandEncoder for super::CommandEncoder { { let encoder = self.enter_blit(); for copy in regions { - encoder.copy_from_buffer( + encoder.copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size( &src.raw, - copy.src_offset, + copy.src_offset as usize, &dst.raw, - copy.dst_offset, - copy.size.get(), + copy.dst_offset as usize, + copy.size.get() as usize, ); } } @@ -287,8 +305,8 @@ impl crate::CommandEncoder for super::CommandEncoder { { let dst_texture = if src.format != dst.format { let raw_format = self.shared.private_caps.map_format(src.format); - Cow::Owned(objc::rc::autoreleasepool(|| { - dst.raw.new_texture_view(raw_format) + Cow::Owned(objc2::rc::autoreleasepool(|_| { + dst.raw.newTextureViewWithPixelFormat(raw_format).unwrap() })) } else { Cow::Borrowed(&dst.raw) @@ -299,15 +317,15 @@ impl crate::CommandEncoder for super::CommandEncoder { let dst_origin = conv::map_origin(©.dst_base.origin); // no clamping is done: Metal expects physical sizes here let extent = conv::map_copy_extent(©.size); - encoder.copy_from_texture( + encoder.copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin( &src.raw, - copy.src_base.array_layer as u64, - copy.src_base.mip_level as u64, + copy.src_base.array_layer as usize, + copy.src_base.mip_level as usize, src_origin, extent, &dst_texture, - copy.dst_base.array_layer as u64, - copy.dst_base.mip_level as u64, + copy.dst_base.array_layer as usize, + copy.dst_base.mip_level as usize, dst_origin, ); } @@ -340,15 +358,15 @@ impl crate::CommandEncoder for super::CommandEncoder { // the amount of data to copy. 0 }; - encoder.copy_from_buffer_to_texture( + encoder.copyFromBuffer_sourceOffset_sourceBytesPerRow_sourceBytesPerImage_sourceSize_toTexture_destinationSlice_destinationLevel_destinationOrigin_options( &src.raw, - copy.buffer_layout.offset, - bytes_per_row, - image_byte_stride, + copy.buffer_layout.offset as usize, + bytes_per_row as usize, + image_byte_stride as usize, conv::map_copy_extent(&extent), &dst.raw, - copy.texture_base.array_layer as u64, - copy.texture_base.mip_level as u64, + copy.texture_base.array_layer as usize, + copy.texture_base.mip_level as usize, dst_origin, conv::get_blit_option(dst.format, copy.texture_base.aspect), ); @@ -377,16 +395,16 @@ impl crate::CommandEncoder for super::CommandEncoder { .buffer_layout .rows_per_image .map_or(0, |v| v as u64 * bytes_per_row); - encoder.copy_from_texture_to_buffer( + encoder.copyFromTexture_sourceSlice_sourceLevel_sourceOrigin_sourceSize_toBuffer_destinationOffset_destinationBytesPerRow_destinationBytesPerImage_options( &src.raw, - copy.texture_base.array_layer as u64, - copy.texture_base.mip_level as u64, + copy.texture_base.array_layer as usize, + copy.texture_base.mip_level as usize, src_origin, conv::map_copy_extent(&extent), &dst.raw, - copy.buffer_layout.offset, - bytes_per_row, - bytes_per_image, + copy.buffer_layout.offset as usize, + bytes_per_row as usize, + bytes_per_image as usize, conv::get_blit_option(src.format, copy.texture_base.aspect), ); } @@ -399,9 +417,9 @@ impl crate::CommandEncoder for super::CommandEncoder { .render .as_ref() .unwrap() - .set_visibility_result_mode( - metal::MTLVisibilityResultMode::Boolean, - index as u64 * crate::QUERY_SIZE, + .setVisibilityResultMode_offset( + MTLVisibilityResultMode::Boolean, + index as usize * crate::QUERY_SIZE as usize, ); } _ => {} @@ -414,7 +432,7 @@ impl crate::CommandEncoder for super::CommandEncoder { .render .as_ref() .unwrap() - .set_visibility_result_mode(metal::MTLVisibilityResultMode::Disabled, 0); + .setVisibilityResultMode_offset(MTLVisibilityResultMode::Disabled, 0); } _ => {} } @@ -434,17 +452,29 @@ impl crate::CommandEncoder for super::CommandEncoder { support.contains(TimestampQuerySupport::ON_BLIT_ENCODER), self.state.blit.as_ref(), ) { - encoder.sample_counters_in_buffer(sample_buffer, index as _, with_barrier); + encoder.sampleCountersInBuffer_atSampleIndex_withBarrier( + sample_buffer, + index as _, + with_barrier, + ); } else if let (true, Some(encoder)) = ( support.contains(TimestampQuerySupport::ON_RENDER_ENCODER), self.state.render.as_ref(), ) { - encoder.sample_counters_in_buffer(sample_buffer, index as _, with_barrier); + encoder.sampleCountersInBuffer_atSampleIndex_withBarrier( + sample_buffer, + index as _, + with_barrier, + ); } else if let (true, Some(encoder)) = ( support.contains(TimestampQuerySupport::ON_COMPUTE_ENCODER), self.state.compute.as_ref(), ) { - encoder.sample_counters_in_buffer(sample_buffer, index as _, with_barrier); + encoder.sampleCountersInBuffer_atSampleIndex_withBarrier( + sample_buffer, + index as _, + with_barrier, + ); } else { // If we're here it means we either have no encoder open, or it's not supported to sample within them. // If this happens with render/compute open, this is an invalid usage! @@ -460,11 +490,11 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn reset_queries(&mut self, set: &super::QuerySet, range: Range) { let encoder = self.enter_blit(); - let raw_range = metal::NSRange { - location: range.start as u64 * crate::QUERY_SIZE, - length: (range.end - range.start) as u64 * crate::QUERY_SIZE, + let raw_range = NSRange { + location: range.start as usize * crate::QUERY_SIZE as usize, + length: (range.end - range.start) as usize * crate::QUERY_SIZE as usize, }; - encoder.fill_buffer(&set.raw_buffer, raw_range, 0); + encoder.fillBuffer_range_value(&set.raw_buffer, raw_range, 0); } unsafe fn copy_query_results( @@ -479,20 +509,20 @@ impl crate::CommandEncoder for super::CommandEncoder { match set.ty { wgt::QueryType::Occlusion => { let size = (range.end - range.start) as u64 * crate::QUERY_SIZE; - encoder.copy_from_buffer( + encoder.copyFromBuffer_sourceOffset_toBuffer_destinationOffset_size( &set.raw_buffer, - range.start as u64 * crate::QUERY_SIZE, + range.start as usize * crate::QUERY_SIZE as usize, &buffer.raw, - offset, - size, + offset as usize, + size as usize, ); } wgt::QueryType::Timestamp => { - encoder.resolve_counters( + encoder.resolveCounters_inRange_destinationBuffer_destinationOffset( set.counter_sample_buffer.as_ref().unwrap(), - metal::NSRange::new(range.start as u64, (range.end - range.start) as u64), + NSRange::new(range.start as usize, (range.end - range.start) as usize), &buffer.raw, - offset, + offset as usize, ); } wgt::QueryType::PipelineStatistics(_) => todo!(), @@ -512,50 +542,50 @@ impl crate::CommandEncoder for super::CommandEncoder { assert!(self.state.compute.is_none()); assert!(self.state.render.is_none()); - objc::rc::autoreleasepool(|| { - let descriptor = metal::RenderPassDescriptor::new(); + objc2::rc::autoreleasepool(|_| { + let descriptor = MTLRenderPassDescriptor::new(); for (i, at) in desc.color_attachments.iter().enumerate() { if let Some(at) = at.as_ref() { - let at_descriptor = descriptor.color_attachments().object_at(i as u64).unwrap(); - at_descriptor.set_texture(Some(&at.target.view.raw)); + let at_descriptor = descriptor.colorAttachments().objectAtIndexedSubscript(i); + at_descriptor.setTexture(Some(&at.target.view.raw)); if let Some(ref resolve) = at.resolve_target { //Note: the selection of levels and slices is already handled by `TextureView` - at_descriptor.set_resolve_texture(Some(&resolve.view.raw)); + at_descriptor.setResolveTexture(Some(&resolve.view.raw)); } let load_action = if at.ops.contains(crate::AttachmentOps::LOAD) { - metal::MTLLoadAction::Load + MTLLoadAction::Load } else { - at_descriptor.set_clear_color(conv::map_clear_color(&at.clear_value)); - metal::MTLLoadAction::Clear + at_descriptor.setClearColor(conv::map_clear_color(&at.clear_value)); + MTLLoadAction::Clear }; let store_action = conv::map_store_action( at.ops.contains(crate::AttachmentOps::STORE), at.resolve_target.is_some(), ); - at_descriptor.set_load_action(load_action); - at_descriptor.set_store_action(store_action); + at_descriptor.setLoadAction(load_action); + at_descriptor.setStoreAction(store_action); } } if let Some(ref at) = desc.depth_stencil_attachment { if at.target.view.aspects.contains(crate::FormatAspects::DEPTH) { - let at_descriptor = descriptor.depth_attachment().unwrap(); - at_descriptor.set_texture(Some(&at.target.view.raw)); + let at_descriptor = descriptor.depthAttachment(); + at_descriptor.setTexture(Some(&at.target.view.raw)); let load_action = if at.depth_ops.contains(crate::AttachmentOps::LOAD) { - metal::MTLLoadAction::Load + MTLLoadAction::Load } else { - at_descriptor.set_clear_depth(at.clear_value.0 as f64); - metal::MTLLoadAction::Clear + at_descriptor.setClearDepth(at.clear_value.0 as f64); + MTLLoadAction::Clear }; let store_action = if at.depth_ops.contains(crate::AttachmentOps::STORE) { - metal::MTLStoreAction::Store + MTLStoreAction::Store } else { - metal::MTLStoreAction::DontCare + MTLStoreAction::DontCare }; - at_descriptor.set_load_action(load_action); - at_descriptor.set_store_action(store_action); + at_descriptor.setLoadAction(load_action); + at_descriptor.setStoreAction(store_action); } if at .target @@ -563,34 +593,33 @@ impl crate::CommandEncoder for super::CommandEncoder { .aspects .contains(crate::FormatAspects::STENCIL) { - let at_descriptor = descriptor.stencil_attachment().unwrap(); - at_descriptor.set_texture(Some(&at.target.view.raw)); + let at_descriptor = descriptor.stencilAttachment(); + at_descriptor.setTexture(Some(&at.target.view.raw)); let load_action = if at.stencil_ops.contains(crate::AttachmentOps::LOAD) { - metal::MTLLoadAction::Load + MTLLoadAction::Load } else { - at_descriptor.set_clear_stencil(at.clear_value.1); - metal::MTLLoadAction::Clear + at_descriptor.setClearStencil(at.clear_value.1); + MTLLoadAction::Clear }; let store_action = if at.stencil_ops.contains(crate::AttachmentOps::STORE) { - metal::MTLStoreAction::Store + MTLStoreAction::Store } else { - metal::MTLStoreAction::DontCare + MTLStoreAction::DontCare }; - at_descriptor.set_load_action(load_action); - at_descriptor.set_store_action(store_action); + at_descriptor.setLoadAction(load_action); + at_descriptor.setStoreAction(store_action); } } let mut sba_index = 0; let mut next_sba_descriptor = || { let sba_descriptor = descriptor - .sample_buffer_attachments() - .object_at(sba_index) - .unwrap(); + .sampleBufferAttachments() + .objectAtIndexedSubscript(sba_index); - sba_descriptor.set_end_of_vertex_sample_index(metal::COUNTER_DONT_SAMPLE); - sba_descriptor.set_start_of_fragment_sample_index(metal::COUNTER_DONT_SAMPLE); + sba_descriptor.setEndOfVertexSampleIndex(MTLCounterDontSample); + sba_descriptor.setStartOfFragmentSampleIndex(MTLCounterDontSample); sba_index += 1; sba_descriptor @@ -598,49 +627,48 @@ impl crate::CommandEncoder for super::CommandEncoder { for (set, index) in self.state.pending_timer_queries.drain(..) { let sba_descriptor = next_sba_descriptor(); - sba_descriptor.set_sample_buffer(set.counter_sample_buffer.as_ref().unwrap()); - sba_descriptor.set_start_of_vertex_sample_index(index as _); - sba_descriptor.set_end_of_fragment_sample_index(metal::COUNTER_DONT_SAMPLE); + sba_descriptor.setSampleBuffer(Some(set.counter_sample_buffer.as_ref().unwrap())); + sba_descriptor.setStartOfVertexSampleIndex(index as _); + sba_descriptor.setEndOfFragmentSampleIndex(MTLCounterDontSample); } if let Some(ref timestamp_writes) = desc.timestamp_writes { let sba_descriptor = next_sba_descriptor(); - sba_descriptor.set_sample_buffer( + sba_descriptor.setSampleBuffer(Some( timestamp_writes .query_set .counter_sample_buffer .as_ref() .unwrap(), - ); + )); - sba_descriptor.set_start_of_vertex_sample_index( + sba_descriptor.setStartOfVertexSampleIndex( timestamp_writes .beginning_of_pass_write_index - .map_or(metal::COUNTER_DONT_SAMPLE, |i| i as _), + .map_or(MTLCounterDontSample, |i| i as _), ); - sba_descriptor.set_end_of_fragment_sample_index( + sba_descriptor.setEndOfFragmentSampleIndex( timestamp_writes .end_of_pass_write_index - .map_or(metal::COUNTER_DONT_SAMPLE, |i| i as _), + .map_or(MTLCounterDontSample, |i| i as _), ); } if let Some(occlusion_query_set) = desc.occlusion_query_set { - descriptor - .set_visibility_result_buffer(Some(occlusion_query_set.raw_buffer.as_ref())) + descriptor.setVisibilityResultBuffer(Some(occlusion_query_set.raw_buffer.as_ref())) } let raw = self.raw_cmd_buf.as_ref().unwrap(); - let encoder = raw.new_render_command_encoder(descriptor); + let encoder = raw.renderCommandEncoderWithDescriptor(&descriptor).unwrap(); if let Some(label) = desc.label { - encoder.set_label(label); + encoder.setLabel(Some(&NSString::from_str(label))); } - self.state.render = Some(encoder.to_owned()); + self.state.render = Some(encoder); }); } unsafe fn end_render_pass(&mut self) { - self.state.render.take().unwrap().end_encoding(); + self.state.render.take().unwrap().endEncoding(); } unsafe fn set_bind_group( @@ -660,10 +688,10 @@ impl crate::CommandEncoder for super::CommandEncoder { if let Some(dyn_index) = buf.dynamic_index { offset += dynamic_offsets[dyn_index as usize] as wgt::BufferAddress; } - encoder.set_vertex_buffer( - (bg_info.base_resource_indices.vs.buffers + index) as u64, - Some(buf.ptr.as_native()), - offset, + encoder.setVertexBuffer_offset_atIndex( + Some(buf.ptr.as_ref()), + offset as usize, + (bg_info.base_resource_indices.vs.buffers + index) as usize, ); if let Some(size) = buf.binding_size { let br = naga::ResourceBinding { @@ -679,10 +707,10 @@ impl crate::CommandEncoder for super::CommandEncoder { naga::ShaderStage::Vertex, &mut self.temp.binding_sizes, ) { - encoder.set_vertex_bytes( + encoder.setVertexBytes_length_atIndex( + NonNull::new(sizes.as_ptr().cast_mut().cast()).unwrap(), + sizes.len() * WORD_SIZE, index as _, - (sizes.len() * WORD_SIZE) as u64, - sizes.as_ptr().cast(), ); } } @@ -694,10 +722,10 @@ impl crate::CommandEncoder for super::CommandEncoder { if let Some(dyn_index) = buf.dynamic_index { offset += dynamic_offsets[dyn_index as usize] as wgt::BufferAddress; } - encoder.set_fragment_buffer( - (bg_info.base_resource_indices.fs.buffers + index) as u64, - Some(buf.ptr.as_native()), - offset, + encoder.setFragmentBuffer_offset_atIndex( + Some(buf.ptr.as_ref()), + offset as usize, + (bg_info.base_resource_indices.fs.buffers + index) as usize, ); if let Some(size) = buf.binding_size { let br = naga::ResourceBinding { @@ -713,41 +741,41 @@ impl crate::CommandEncoder for super::CommandEncoder { naga::ShaderStage::Fragment, &mut self.temp.binding_sizes, ) { - encoder.set_fragment_bytes( + encoder.setFragmentBytes_length_atIndex( + NonNull::new(sizes.as_ptr().cast_mut().cast()).unwrap(), + sizes.len() * WORD_SIZE, index as _, - (sizes.len() * WORD_SIZE) as u64, - sizes.as_ptr().cast(), ); } } for index in 0..group.counters.vs.samplers { let res = group.samplers[index as usize]; - encoder.set_vertex_sampler_state( - (bg_info.base_resource_indices.vs.samplers + index) as u64, - Some(res.as_native()), + encoder.setVertexSamplerState_atIndex( + Some(res.as_ref()), + (bg_info.base_resource_indices.vs.samplers + index) as usize, ); } for index in 0..group.counters.fs.samplers { let res = group.samplers[(group.counters.vs.samplers + index) as usize]; - encoder.set_fragment_sampler_state( - (bg_info.base_resource_indices.fs.samplers + index) as u64, - Some(res.as_native()), + encoder.setFragmentSamplerState_atIndex( + Some(res.as_ref()), + (bg_info.base_resource_indices.fs.samplers + index) as usize, ); } for index in 0..group.counters.vs.textures { let res = group.textures[index as usize]; - encoder.set_vertex_texture( - (bg_info.base_resource_indices.vs.textures + index) as u64, - Some(res.as_native()), + encoder.setVertexTexture_atIndex( + Some(res.as_ref()), + (bg_info.base_resource_indices.vs.textures + index) as usize, ); } for index in 0..group.counters.fs.textures { let res = group.textures[(group.counters.vs.textures + index) as usize]; - encoder.set_fragment_texture( - (bg_info.base_resource_indices.fs.textures + index) as u64, - Some(res.as_native()), + encoder.setFragmentTexture_atIndex( + Some(res.as_ref()), + (bg_info.base_resource_indices.fs.textures + index) as usize, ); } } @@ -766,10 +794,10 @@ impl crate::CommandEncoder for super::CommandEncoder { if let Some(dyn_index) = buf.dynamic_index { offset += dynamic_offsets[dyn_index as usize] as wgt::BufferAddress; } - encoder.set_buffer( - (bg_info.base_resource_indices.cs.buffers + index) as u64, - Some(buf.ptr.as_native()), - offset, + encoder.setBuffer_offset_atIndex( + Some(buf.ptr.as_ref()), + offset as usize, + (bg_info.base_resource_indices.cs.buffers + index) as usize, ); if let Some(size) = buf.binding_size { let br = naga::ResourceBinding { @@ -785,26 +813,26 @@ impl crate::CommandEncoder for super::CommandEncoder { naga::ShaderStage::Compute, &mut self.temp.binding_sizes, ) { - encoder.set_bytes( + encoder.setBytes_length_atIndex( + NonNull::new(sizes.as_ptr().cast_mut().cast()).unwrap(), + sizes.len() * WORD_SIZE, index as _, - (sizes.len() * WORD_SIZE) as u64, - sizes.as_ptr().cast(), ); } } for index in 0..group.counters.cs.samplers { let res = group.samplers[(index_base.samplers + index) as usize]; - encoder.set_sampler_state( - (bg_info.base_resource_indices.cs.samplers + index) as u64, - Some(res.as_native()), + encoder.setSamplerState_atIndex( + Some(res.as_ref()), + (bg_info.base_resource_indices.cs.samplers + index) as usize, ); } for index in 0..group.counters.cs.textures { let res = group.textures[(index_base.textures + index) as usize]; - encoder.set_texture( - (bg_info.base_resource_indices.cs.textures + index) as u64, - Some(res.as_native()), + encoder.setTexture_atIndex( + Some(res.as_ref()), + (bg_info.base_resource_indices.cs.textures + index) as usize, ); } } @@ -826,46 +854,59 @@ impl crate::CommandEncoder for super::CommandEncoder { let offset_words = offset_bytes as usize / WORD_SIZE; state_pc[offset_words..offset_words + data.len()].copy_from_slice(data); + let bytes = NonNull::new(state_pc.as_ptr().cast_mut().cast()).unwrap(); if stages.contains(wgt::ShaderStages::COMPUTE) { - self.state.compute.as_ref().unwrap().set_bytes( - layout.push_constants_infos.cs.unwrap().buffer_index as _, - (layout.total_push_constants as usize * WORD_SIZE) as _, - state_pc.as_ptr().cast(), - ) + self.state + .compute + .as_ref() + .unwrap() + .setBytes_length_atIndex( + bytes, + layout.total_push_constants as usize * WORD_SIZE, + layout.push_constants_infos.cs.unwrap().buffer_index as _, + ) } if stages.contains(wgt::ShaderStages::VERTEX) { - self.state.render.as_ref().unwrap().set_vertex_bytes( - layout.push_constants_infos.vs.unwrap().buffer_index as _, - (layout.total_push_constants as usize * WORD_SIZE) as _, - state_pc.as_ptr().cast(), - ) + self.state + .render + .as_ref() + .unwrap() + .setVertexBytes_length_atIndex( + bytes, + layout.total_push_constants as usize * WORD_SIZE, + layout.push_constants_infos.vs.unwrap().buffer_index as _, + ) } if stages.contains(wgt::ShaderStages::FRAGMENT) { - self.state.render.as_ref().unwrap().set_fragment_bytes( - layout.push_constants_infos.fs.unwrap().buffer_index as _, - (layout.total_push_constants as usize * WORD_SIZE) as _, - state_pc.as_ptr().cast(), - ) + self.state + .render + .as_ref() + .unwrap() + .setFragmentBytes_length_atIndex( + bytes, + layout.total_push_constants as usize * WORD_SIZE, + layout.push_constants_infos.fs.unwrap().buffer_index as _, + ) } } unsafe fn insert_debug_marker(&mut self, label: &str) { if let Some(encoder) = self.active_encoder() { - encoder.insert_debug_signpost(label); + encoder.insertDebugSignpost(&NSString::from_str(label)); } } unsafe fn begin_debug_marker(&mut self, group_label: &str) { if let Some(encoder) = self.active_encoder() { - encoder.push_debug_group(group_label); + encoder.pushDebugGroup(&NSString::from_str(group_label)); } else if let Some(ref buf) = self.raw_cmd_buf { - buf.push_debug_group(group_label); + buf.pushDebugGroup(&NSString::from_str(group_label)); } } unsafe fn end_debug_marker(&mut self) { if let Some(encoder) = self.active_encoder() { - encoder.pop_debug_group(); + encoder.popDebugGroup(); } else if let Some(ref buf) = self.raw_cmd_buf { - buf.pop_debug_group(); + buf.popDebugGroup(); } } @@ -878,16 +919,20 @@ impl crate::CommandEncoder for super::CommandEncoder { } let encoder = self.state.render.as_ref().unwrap(); - encoder.set_render_pipeline_state(&pipeline.raw); - encoder.set_front_facing_winding(pipeline.raw_front_winding); - encoder.set_cull_mode(pipeline.raw_cull_mode); - encoder.set_triangle_fill_mode(pipeline.raw_triangle_fill_mode); + encoder.setRenderPipelineState(&pipeline.raw); + encoder.setFrontFacingWinding(pipeline.raw_front_winding); + encoder.setCullMode(pipeline.raw_cull_mode); + encoder.setTriangleFillMode(pipeline.raw_triangle_fill_mode); if let Some(depth_clip) = pipeline.raw_depth_clip_mode { - encoder.set_depth_clip_mode(depth_clip); + encoder.setDepthClipMode(depth_clip); } if let Some((ref state, bias)) = pipeline.depth_stencil { - encoder.set_depth_stencil_state(state); - encoder.set_depth_bias(bias.constant as f32, bias.slope_scale, bias.clamp); + encoder.setDepthStencilState(Some(state)); + encoder.setDepthBias_slopeScale_clamp( + bias.constant as f32, + bias.slope_scale, + bias.clamp, + ); } { @@ -895,10 +940,10 @@ impl crate::CommandEncoder for super::CommandEncoder { .state .make_sizes_buffer_update(naga::ShaderStage::Vertex, &mut self.temp.binding_sizes) { - encoder.set_vertex_bytes( + encoder.setVertexBytes_length_atIndex( + NonNull::new(sizes.as_ptr().cast_mut().cast()).unwrap(), + sizes.len() * WORD_SIZE, index as _, - (sizes.len() * WORD_SIZE) as u64, - sizes.as_ptr().cast(), ); } } @@ -907,10 +952,10 @@ impl crate::CommandEncoder for super::CommandEncoder { .state .make_sizes_buffer_update(naga::ShaderStage::Fragment, &mut self.temp.binding_sizes) { - encoder.set_fragment_bytes( + encoder.setFragmentBytes_length_atIndex( + NonNull::new(sizes.as_ptr().cast_mut().cast()).unwrap(), + sizes.len() * WORD_SIZE, index as _, - (sizes.len() * WORD_SIZE) as u64, - sizes.as_ptr().cast(), ); } } @@ -922,11 +967,11 @@ impl crate::CommandEncoder for super::CommandEncoder { format: wgt::IndexFormat, ) { let (stride, raw_type) = match format { - wgt::IndexFormat::Uint16 => (2, metal::MTLIndexType::UInt16), - wgt::IndexFormat::Uint32 => (4, metal::MTLIndexType::UInt32), + wgt::IndexFormat::Uint16 => (2, MTLIndexType::UInt16), + wgt::IndexFormat::Uint32 => (4, MTLIndexType::UInt32), }; self.state.index = Some(super::IndexState { - buffer_ptr: AsNative::from(binding.buffer.raw.as_ref()), + buffer_ptr: NonNull::from(&*binding.buffer.raw), offset: binding.offset, stride, raw_type, @@ -940,7 +985,11 @@ impl crate::CommandEncoder for super::CommandEncoder { ) { let buffer_index = self.shared.private_caps.max_vertex_buffers as u64 - 1 - index as u64; let encoder = self.state.render.as_ref().unwrap(); - encoder.set_vertex_buffer(buffer_index, Some(&binding.buffer.raw), binding.offset); + encoder.setVertexBuffer_offset_atIndex( + Some(&binding.buffer.raw), + binding.offset as usize, + buffer_index as usize, + ); let buffer_size = binding.resolve_size(); if buffer_size > 0 { @@ -956,10 +1005,10 @@ impl crate::CommandEncoder for super::CommandEncoder { .state .make_sizes_buffer_update(naga::ShaderStage::Vertex, &mut self.temp.binding_sizes) { - encoder.set_vertex_bytes( + encoder.setVertexBytes_length_atIndex( + NonNull::new(sizes.as_ptr().cast_mut().cast()).unwrap(), + sizes.len() * WORD_SIZE, index as _, - (sizes.len() * WORD_SIZE) as u64, - sizes.as_ptr().cast(), ); } } @@ -971,7 +1020,7 @@ impl crate::CommandEncoder for super::CommandEncoder { depth_range.end }; let encoder = self.state.render.as_ref().unwrap(); - encoder.set_viewport(metal::MTLViewport { + encoder.setViewport(MTLViewport { originX: rect.x as _, originY: rect.y as _, width: rect.w as _, @@ -982,22 +1031,22 @@ impl crate::CommandEncoder for super::CommandEncoder { } unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect) { //TODO: support empty scissors by modifying the viewport - let scissor = metal::MTLScissorRect { + let scissor = MTLScissorRect { x: rect.x as _, y: rect.y as _, width: rect.w as _, height: rect.h as _, }; let encoder = self.state.render.as_ref().unwrap(); - encoder.set_scissor_rect(scissor); + encoder.setScissorRect(scissor); } unsafe fn set_stencil_reference(&mut self, value: u32) { let encoder = self.state.render.as_ref().unwrap(); - encoder.set_stencil_front_back_reference_value(value, value); + encoder.setStencilFrontReferenceValue_backReferenceValue(value, value); } unsafe fn set_blend_constants(&mut self, color: &[f32; 4]) { let encoder = self.state.render.as_ref().unwrap(); - encoder.set_blend_color(color[0], color[1], color[2], color[3]); + encoder.setBlendColorRed_green_blue_alpha(color[0], color[1], color[2], color[3]); } unsafe fn draw( @@ -1009,7 +1058,7 @@ impl crate::CommandEncoder for super::CommandEncoder { ) { let encoder = self.state.render.as_ref().unwrap(); if first_instance != 0 { - encoder.draw_primitives_instanced_base_instance( + encoder.drawPrimitives_vertexStart_vertexCount_instanceCount_baseInstance( self.state.raw_primitive_type, first_vertex as _, vertex_count as _, @@ -1017,14 +1066,14 @@ impl crate::CommandEncoder for super::CommandEncoder { first_instance as _, ); } else if instance_count != 1 { - encoder.draw_primitives_instanced( + encoder.drawPrimitives_vertexStart_vertexCount_instanceCount( self.state.raw_primitive_type, first_vertex as _, vertex_count as _, instance_count as _, ); } else { - encoder.draw_primitives( + encoder.drawPrimitives_vertexStart_vertexCount( self.state.raw_primitive_type, first_vertex as _, vertex_count as _, @@ -1042,33 +1091,33 @@ impl crate::CommandEncoder for super::CommandEncoder { ) { let encoder = self.state.render.as_ref().unwrap(); let index = self.state.index.as_ref().unwrap(); - let offset = index.offset + index.stride * first_index as wgt::BufferAddress; + let offset = (index.offset + index.stride * first_index as wgt::BufferAddress) as usize; if base_vertex != 0 || first_instance != 0 { - encoder.draw_indexed_primitives_instanced_base_instance( + encoder.drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount_baseVertex_baseInstance( self.state.raw_primitive_type, index_count as _, index.raw_type, - index.buffer_ptr.as_native(), + index.buffer_ptr.as_ref(), offset, instance_count as _, base_vertex as _, first_instance as _, ); } else if instance_count != 1 { - encoder.draw_indexed_primitives_instanced( + encoder.drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset_instanceCount( self.state.raw_primitive_type, index_count as _, index.raw_type, - index.buffer_ptr.as_native(), + index.buffer_ptr.as_ref(), offset, instance_count as _, ); } else { - encoder.draw_indexed_primitives( + encoder.drawIndexedPrimitives_indexCount_indexType_indexBuffer_indexBufferOffset( self.state.raw_primitive_type, index_count as _, index.raw_type, - index.buffer_ptr.as_native(), + index.buffer_ptr.as_ref(), offset, ); } @@ -1082,7 +1131,11 @@ impl crate::CommandEncoder for super::CommandEncoder { ) { let encoder = self.state.render.as_ref().unwrap(); for _ in 0..draw_count { - encoder.draw_primitives_indirect(self.state.raw_primitive_type, &buffer.raw, offset); + encoder.drawPrimitives_indirectBuffer_indirectBufferOffset( + self.state.raw_primitive_type, + &buffer.raw, + offset as usize, + ); offset += size_of::() as wgt::BufferAddress; } } @@ -1096,14 +1149,15 @@ impl crate::CommandEncoder for super::CommandEncoder { let encoder = self.state.render.as_ref().unwrap(); let index = self.state.index.as_ref().unwrap(); for _ in 0..draw_count { - encoder.draw_indexed_primitives_indirect( - self.state.raw_primitive_type, - index.raw_type, - index.buffer_ptr.as_native(), - index.offset, - &buffer.raw, - offset, - ); + encoder + .drawIndexedPrimitives_indexType_indexBuffer_indexBufferOffset_indirectBuffer_indirectBufferOffset( + self.state.raw_primitive_type, + index.raw_type, + index.buffer_ptr.as_ref(), + index.offset as usize, + &buffer.raw, + offset as usize, + ); offset += size_of::() as wgt::BufferAddress; } } @@ -1140,65 +1194,66 @@ impl crate::CommandEncoder for super::CommandEncoder { let raw = self.raw_cmd_buf.as_ref().unwrap(); - objc::rc::autoreleasepool(|| { + objc2::rc::autoreleasepool(|_| { // TimeStamp Queries and ComputePassDescriptor were both introduced in Metal 2.3 (macOS 11, iOS 14) // and we currently only need ComputePassDescriptor for timestamp queries let encoder = if self.shared.private_caps.timestamp_query_support.is_empty() { - raw.new_compute_command_encoder() + raw.computeCommandEncoder().unwrap() } else { - let descriptor = metal::ComputePassDescriptor::new(); + let descriptor = MTLComputePassDescriptor::new(); let mut sba_index = 0; let mut next_sba_descriptor = || { let sba_descriptor = descriptor - .sample_buffer_attachments() - .object_at(sba_index) - .unwrap(); + .sampleBufferAttachments() + .objectAtIndexedSubscript(sba_index); sba_index += 1; sba_descriptor }; for (set, index) in self.state.pending_timer_queries.drain(..) { let sba_descriptor = next_sba_descriptor(); - sba_descriptor.set_sample_buffer(set.counter_sample_buffer.as_ref().unwrap()); - sba_descriptor.set_start_of_encoder_sample_index(index as _); - sba_descriptor.set_end_of_encoder_sample_index(metal::COUNTER_DONT_SAMPLE); + sba_descriptor + .setSampleBuffer(Some(set.counter_sample_buffer.as_ref().unwrap())); + sba_descriptor.setStartOfEncoderSampleIndex(index as _); + sba_descriptor.setEndOfEncoderSampleIndex(MTLCounterDontSample); } if let Some(timestamp_writes) = desc.timestamp_writes.as_ref() { let sba_descriptor = next_sba_descriptor(); - sba_descriptor.set_sample_buffer( + sba_descriptor.setSampleBuffer(Some( timestamp_writes .query_set .counter_sample_buffer .as_ref() .unwrap(), - ); + )); - sba_descriptor.set_start_of_encoder_sample_index( + sba_descriptor.setStartOfEncoderSampleIndex( timestamp_writes .beginning_of_pass_write_index - .map_or(metal::COUNTER_DONT_SAMPLE, |i| i as _), + .map_or(MTLCounterDontSample, |i| i as _), ); - sba_descriptor.set_end_of_encoder_sample_index( + sba_descriptor.setEndOfEncoderSampleIndex( timestamp_writes .end_of_pass_write_index - .map_or(metal::COUNTER_DONT_SAMPLE, |i| i as _), + .map_or(MTLCounterDontSample, |i| i as _), ); } - raw.compute_command_encoder_with_descriptor(descriptor) + raw.computeCommandEncoderWithDescriptor(&descriptor) + .unwrap() }; if let Some(label) = desc.label { - encoder.set_label(label); + encoder.setLabel(Some(&NSString::from_str(label))); } self.state.compute = Some(encoder.to_owned()); }); } unsafe fn end_compute_pass(&mut self) { - self.state.compute.take().unwrap().end_encoding(); + self.state.compute.take().unwrap().endEncoding(); } unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) { @@ -1206,16 +1261,16 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.stage_infos.cs.assign_from(&pipeline.cs_info); let encoder = self.state.compute.as_ref().unwrap(); - encoder.set_compute_pipeline_state(&pipeline.raw); + encoder.setComputePipelineState(&pipeline.raw); if let Some((index, sizes)) = self .state .make_sizes_buffer_update(naga::ShaderStage::Compute, &mut self.temp.binding_sizes) { - encoder.set_bytes( + encoder.setBytes_length_atIndex( + NonNull::new(sizes.as_ptr().cast_mut().cast()).unwrap(), + sizes.len() * WORD_SIZE, index as _, - (sizes.len() * WORD_SIZE) as u64, - sizes.as_ptr().cast(), ); } @@ -1234,24 +1289,28 @@ impl crate::CommandEncoder for super::CommandEncoder { let size = ((*pipeline_size - 1) | ALIGN_MASK) + 1; if *cur_size != size { *cur_size = size; - encoder.set_threadgroup_memory_length(index as _, size as _); + encoder.setThreadgroupMemoryLength_atIndex(size as _, index); } } } unsafe fn dispatch(&mut self, count: [u32; 3]) { let encoder = self.state.compute.as_ref().unwrap(); - let raw_count = metal::MTLSize { - width: count[0] as u64, - height: count[1] as u64, - depth: count[2] as u64, + let raw_count = MTLSize { + width: count[0] as usize, + height: count[1] as usize, + depth: count[2] as usize, }; - encoder.dispatch_thread_groups(raw_count, self.state.raw_wg_size); + encoder.dispatchThreadgroups_threadsPerThreadgroup(raw_count, self.state.raw_wg_size); } unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) { let encoder = self.state.compute.as_ref().unwrap(); - encoder.dispatch_thread_groups_indirect(&buffer.raw, offset, self.state.raw_wg_size); + encoder.dispatchThreadgroupsWithIndirectBuffer_indirectBufferOffset_threadsPerThreadgroup( + &buffer.raw, + offset as usize, + self.state.raw_wg_size, + ); } unsafe fn build_acceleration_structures<'a, T>( @@ -1289,7 +1348,7 @@ impl Drop for super::CommandEncoder { // appears to be a requirement for all MTLCommandEncoder objects. Failing to call // endEncoding causes a crash with the message 'Command encoder released without // endEncoding'. To prevent this, we explicitiy call discard_encoding, which - // calls end_encoding on any still-held metal::CommandEncoders. + // calls endEncoding on any still-held MTLCommandEncoders. unsafe { self.discard_encoding(); } diff --git a/wgpu-hal/src/metal/conv.rs b/wgpu-hal/src/metal/conv.rs index 6ebabee1a6..0fa9a7bd2d 100644 --- a/wgpu-hal/src/metal/conv.rs +++ b/wgpu-hal/src/metal/conv.rs @@ -1,185 +1,178 @@ -pub fn map_texture_usage( - format: wgt::TextureFormat, - usage: crate::TextureUses, -) -> metal::MTLTextureUsage { +use objc2_foundation::NSRange; +use objc2_metal::{ + MTLBlendFactor, MTLBlendOperation, MTLBlitOption, MTLClearColor, MTLColorWriteMask, + MTLCompareFunction, MTLCullMode, MTLOrigin, MTLPrimitiveTopologyClass, MTLPrimitiveType, + MTLSamplerAddressMode, MTLSamplerBorderColor, MTLSamplerMinMagFilter, MTLSize, + MTLStencilOperation, MTLStoreAction, MTLTextureType, MTLTextureUsage, MTLVertexFormat, + MTLVertexStepFunction, MTLWinding, +}; + +pub fn map_texture_usage(format: wgt::TextureFormat, usage: crate::TextureUses) -> MTLTextureUsage { use crate::TextureUses as Tu; - let mut mtl_usage = metal::MTLTextureUsage::Unknown; + let mut mtl_usage = MTLTextureUsage::Unknown; mtl_usage.set( - metal::MTLTextureUsage::RenderTarget, + MTLTextureUsage::RenderTarget, usage.intersects(Tu::COLOR_TARGET | Tu::DEPTH_STENCIL_READ | Tu::DEPTH_STENCIL_WRITE), ); mtl_usage.set( - metal::MTLTextureUsage::ShaderRead, + MTLTextureUsage::ShaderRead, usage.intersects( Tu::RESOURCE | Tu::DEPTH_STENCIL_READ | Tu::STORAGE_READ | Tu::STORAGE_READ_WRITE, ), ); mtl_usage.set( - metal::MTLTextureUsage::ShaderWrite, + MTLTextureUsage::ShaderWrite, usage.intersects(Tu::STORAGE_READ_WRITE), ); // needed for combined depth/stencil formats since we might // create a stencil-only view from them mtl_usage.set( - metal::MTLTextureUsage::PixelFormatView, + MTLTextureUsage::PixelFormatView, format.is_combined_depth_stencil_format(), ); mtl_usage } -pub fn map_texture_view_dimension(dim: wgt::TextureViewDimension) -> metal::MTLTextureType { - use metal::MTLTextureType::*; +pub fn map_texture_view_dimension(dim: wgt::TextureViewDimension) -> MTLTextureType { use wgt::TextureViewDimension as Tvd; + use MTLTextureType as MTL; match dim { - Tvd::D1 => D1, - Tvd::D2 => D2, - Tvd::D2Array => D2Array, - Tvd::D3 => D3, - Tvd::Cube => Cube, - Tvd::CubeArray => CubeArray, + Tvd::D1 => MTL::MTLTextureType1D, + Tvd::D2 => MTL::MTLTextureType2D, + Tvd::D2Array => MTL::MTLTextureType2DArray, + Tvd::D3 => MTL::MTLTextureType3D, + Tvd::Cube => MTL::Cube, + Tvd::CubeArray => MTL::CubeArray, } } -pub fn map_compare_function(fun: wgt::CompareFunction) -> metal::MTLCompareFunction { - use metal::MTLCompareFunction::*; +pub fn map_compare_function(fun: wgt::CompareFunction) -> MTLCompareFunction { use wgt::CompareFunction as Cf; + use MTLCompareFunction as MTL; match fun { - Cf::Never => Never, - Cf::Less => Less, - Cf::LessEqual => LessEqual, - Cf::Equal => Equal, - Cf::GreaterEqual => GreaterEqual, - Cf::Greater => Greater, - Cf::NotEqual => NotEqual, - Cf::Always => Always, + Cf::Never => MTL::Never, + Cf::Less => MTL::Less, + Cf::LessEqual => MTL::LessEqual, + Cf::Equal => MTL::Equal, + Cf::GreaterEqual => MTL::GreaterEqual, + Cf::Greater => MTL::Greater, + Cf::NotEqual => MTL::NotEqual, + Cf::Always => MTL::Always, } } -pub fn map_filter_mode(filter: wgt::FilterMode) -> metal::MTLSamplerMinMagFilter { - use metal::MTLSamplerMinMagFilter::*; +pub fn map_filter_mode(filter: wgt::FilterMode) -> MTLSamplerMinMagFilter { + use MTLSamplerMinMagFilter as MTL; match filter { - wgt::FilterMode::Nearest => Nearest, - wgt::FilterMode::Linear => Linear, + wgt::FilterMode::Nearest => MTL::Nearest, + wgt::FilterMode::Linear => MTL::Linear, } } -pub fn map_address_mode(address: wgt::AddressMode) -> metal::MTLSamplerAddressMode { - use metal::MTLSamplerAddressMode::*; +pub fn map_address_mode(address: wgt::AddressMode) -> MTLSamplerAddressMode { use wgt::AddressMode as Fm; + use MTLSamplerAddressMode as MTL; match address { - Fm::Repeat => Repeat, - Fm::MirrorRepeat => MirrorRepeat, - Fm::ClampToEdge => ClampToEdge, - Fm::ClampToBorder => ClampToBorderColor, - //Fm::MirrorClamp => MirrorClampToEdge, + Fm::Repeat => MTL::Repeat, + Fm::MirrorRepeat => MTL::MirrorRepeat, + Fm::ClampToEdge => MTL::ClampToEdge, + Fm::ClampToBorder => MTL::ClampToBorderColor, + //Fm::MirrorClamp => MTL::MirrorClampToEdge, } } -pub fn map_border_color(border_color: wgt::SamplerBorderColor) -> metal::MTLSamplerBorderColor { - use metal::MTLSamplerBorderColor::*; +pub fn map_border_color(border_color: wgt::SamplerBorderColor) -> MTLSamplerBorderColor { + use MTLSamplerBorderColor as MTL; match border_color { - wgt::SamplerBorderColor::TransparentBlack => TransparentBlack, - wgt::SamplerBorderColor::OpaqueBlack => OpaqueBlack, - wgt::SamplerBorderColor::OpaqueWhite => OpaqueWhite, + wgt::SamplerBorderColor::TransparentBlack => MTL::TransparentBlack, + wgt::SamplerBorderColor::OpaqueBlack => MTL::OpaqueBlack, + wgt::SamplerBorderColor::OpaqueWhite => MTL::OpaqueWhite, wgt::SamplerBorderColor::Zero => unreachable!(), } } pub fn map_primitive_topology( topology: wgt::PrimitiveTopology, -) -> (metal::MTLPrimitiveTopologyClass, metal::MTLPrimitiveType) { +) -> (MTLPrimitiveTopologyClass, MTLPrimitiveType) { use wgt::PrimitiveTopology as Pt; match topology { - Pt::PointList => ( - metal::MTLPrimitiveTopologyClass::Point, - metal::MTLPrimitiveType::Point, - ), - Pt::LineList => ( - metal::MTLPrimitiveTopologyClass::Line, - metal::MTLPrimitiveType::Line, - ), - Pt::LineStrip => ( - metal::MTLPrimitiveTopologyClass::Line, - metal::MTLPrimitiveType::LineStrip, - ), + Pt::PointList => (MTLPrimitiveTopologyClass::Point, MTLPrimitiveType::Point), + Pt::LineList => (MTLPrimitiveTopologyClass::Line, MTLPrimitiveType::Line), + Pt::LineStrip => (MTLPrimitiveTopologyClass::Line, MTLPrimitiveType::LineStrip), Pt::TriangleList => ( - metal::MTLPrimitiveTopologyClass::Triangle, - metal::MTLPrimitiveType::Triangle, + MTLPrimitiveTopologyClass::Triangle, + MTLPrimitiveType::Triangle, ), Pt::TriangleStrip => ( - metal::MTLPrimitiveTopologyClass::Triangle, - metal::MTLPrimitiveType::TriangleStrip, + MTLPrimitiveTopologyClass::Triangle, + MTLPrimitiveType::TriangleStrip, ), } } -pub fn map_color_write(mask: wgt::ColorWrites) -> metal::MTLColorWriteMask { - let mut raw_mask = metal::MTLColorWriteMask::empty(); +pub fn map_color_write(mask: wgt::ColorWrites) -> MTLColorWriteMask { + let mut raw_mask = MTLColorWriteMask::empty(); if mask.contains(wgt::ColorWrites::RED) { - raw_mask |= metal::MTLColorWriteMask::Red; + raw_mask |= MTLColorWriteMask::Red; } if mask.contains(wgt::ColorWrites::GREEN) { - raw_mask |= metal::MTLColorWriteMask::Green; + raw_mask |= MTLColorWriteMask::Green; } if mask.contains(wgt::ColorWrites::BLUE) { - raw_mask |= metal::MTLColorWriteMask::Blue; + raw_mask |= MTLColorWriteMask::Blue; } if mask.contains(wgt::ColorWrites::ALPHA) { - raw_mask |= metal::MTLColorWriteMask::Alpha; + raw_mask |= MTLColorWriteMask::Alpha; } raw_mask } -pub fn map_blend_factor(factor: wgt::BlendFactor) -> metal::MTLBlendFactor { - use metal::MTLBlendFactor::*; +pub fn map_blend_factor(factor: wgt::BlendFactor) -> MTLBlendFactor { use wgt::BlendFactor as Bf; + use MTLBlendFactor as MTL; match factor { - Bf::Zero => Zero, - Bf::One => One, - Bf::Src => SourceColor, - Bf::OneMinusSrc => OneMinusSourceColor, - Bf::Dst => DestinationColor, - Bf::OneMinusDst => OneMinusDestinationColor, - Bf::SrcAlpha => SourceAlpha, - Bf::OneMinusSrcAlpha => OneMinusSourceAlpha, - Bf::DstAlpha => DestinationAlpha, - Bf::OneMinusDstAlpha => OneMinusDestinationAlpha, - Bf::Constant => BlendColor, - Bf::OneMinusConstant => OneMinusBlendColor, - Bf::SrcAlphaSaturated => SourceAlphaSaturated, - Bf::Src1 => Source1Color, - Bf::OneMinusSrc1 => OneMinusSource1Color, - Bf::Src1Alpha => Source1Alpha, - Bf::OneMinusSrc1Alpha => OneMinusSource1Alpha, + Bf::Zero => MTL::Zero, + Bf::One => MTL::One, + Bf::Src => MTL::SourceColor, + Bf::OneMinusSrc => MTL::OneMinusSourceColor, + Bf::Dst => MTL::DestinationColor, + Bf::OneMinusDst => MTL::OneMinusDestinationColor, + Bf::SrcAlpha => MTL::SourceAlpha, + Bf::OneMinusSrcAlpha => MTL::OneMinusSourceAlpha, + Bf::DstAlpha => MTL::DestinationAlpha, + Bf::OneMinusDstAlpha => MTL::OneMinusDestinationAlpha, + Bf::Constant => MTL::BlendColor, + Bf::OneMinusConstant => MTL::OneMinusBlendColor, + Bf::SrcAlphaSaturated => MTL::SourceAlphaSaturated, + Bf::Src1 => MTL::Source1Color, + Bf::OneMinusSrc1 => MTL::OneMinusSource1Color, + Bf::Src1Alpha => MTL::Source1Alpha, + Bf::OneMinusSrc1Alpha => MTL::OneMinusSource1Alpha, } } -pub fn map_blend_op(operation: wgt::BlendOperation) -> metal::MTLBlendOperation { - use metal::MTLBlendOperation::*; +pub fn map_blend_op(operation: wgt::BlendOperation) -> MTLBlendOperation { use wgt::BlendOperation as Bo; + use MTLBlendOperation as MTL; match operation { - Bo::Add => Add, - Bo::Subtract => Subtract, - Bo::ReverseSubtract => ReverseSubtract, - Bo::Min => Min, - Bo::Max => Max, + Bo::Add => MTL::Add, + Bo::Subtract => MTL::Subtract, + Bo::ReverseSubtract => MTL::ReverseSubtract, + Bo::Min => MTL::Min, + Bo::Max => MTL::Max, } } pub fn map_blend_component( component: &wgt::BlendComponent, -) -> ( - metal::MTLBlendOperation, - metal::MTLBlendFactor, - metal::MTLBlendFactor, -) { +) -> (MTLBlendOperation, MTLBlendFactor, MTLBlendFactor) { ( map_blend_op(component.operation), map_blend_factor(component.src_factor), @@ -187,119 +180,118 @@ pub fn map_blend_component( ) } -pub fn map_vertex_format(format: wgt::VertexFormat) -> metal::MTLVertexFormat { - use metal::MTLVertexFormat::*; +pub fn map_vertex_format(format: wgt::VertexFormat) -> MTLVertexFormat { use wgt::VertexFormat as Vf; + use MTLVertexFormat as MTL; match format { - Vf::Unorm8x2 => UChar2Normalized, - Vf::Snorm8x2 => Char2Normalized, - Vf::Uint8x2 => UChar2, - Vf::Sint8x2 => Char2, - Vf::Unorm8x4 => UChar4Normalized, - Vf::Snorm8x4 => Char4Normalized, - Vf::Uint8x4 => UChar4, - Vf::Sint8x4 => Char4, - Vf::Unorm16x2 => UShort2Normalized, - Vf::Snorm16x2 => Short2Normalized, - Vf::Uint16x2 => UShort2, - Vf::Sint16x2 => Short2, - Vf::Float16x2 => Half2, - Vf::Unorm16x4 => UShort4Normalized, - Vf::Snorm16x4 => Short4Normalized, - Vf::Uint16x4 => UShort4, - Vf::Sint16x4 => Short4, - Vf::Float16x4 => Half4, - Vf::Uint32 => UInt, - Vf::Sint32 => Int, - Vf::Float32 => Float, - Vf::Uint32x2 => UInt2, - Vf::Sint32x2 => Int2, - Vf::Float32x2 => Float2, - Vf::Uint32x3 => UInt3, - Vf::Sint32x3 => Int3, - Vf::Float32x3 => Float3, - Vf::Uint32x4 => UInt4, - Vf::Sint32x4 => Int4, - Vf::Float32x4 => Float4, - Vf::Unorm10_10_10_2 => UInt1010102Normalized, + Vf::Unorm8x2 => MTL::UChar2Normalized, + Vf::Snorm8x2 => MTL::Char2Normalized, + Vf::Uint8x2 => MTL::UChar2, + Vf::Sint8x2 => MTL::Char2, + Vf::Unorm8x4 => MTL::UChar4Normalized, + Vf::Snorm8x4 => MTL::Char4Normalized, + Vf::Uint8x4 => MTL::UChar4, + Vf::Sint8x4 => MTL::Char4, + Vf::Unorm16x2 => MTL::UShort2Normalized, + Vf::Snorm16x2 => MTL::Short2Normalized, + Vf::Uint16x2 => MTL::UShort2, + Vf::Sint16x2 => MTL::Short2, + Vf::Float16x2 => MTL::Half2, + Vf::Unorm16x4 => MTL::UShort4Normalized, + Vf::Snorm16x4 => MTL::Short4Normalized, + Vf::Uint16x4 => MTL::UShort4, + Vf::Sint16x4 => MTL::Short4, + Vf::Float16x4 => MTL::Half4, + Vf::Uint32 => MTL::UInt, + Vf::Sint32 => MTL::Int, + Vf::Float32 => MTL::Float, + Vf::Uint32x2 => MTL::UInt2, + Vf::Sint32x2 => MTL::Int2, + Vf::Float32x2 => MTL::Float2, + Vf::Uint32x3 => MTL::UInt3, + Vf::Sint32x3 => MTL::Int3, + Vf::Float32x3 => MTL::Float3, + Vf::Uint32x4 => MTL::UInt4, + Vf::Sint32x4 => MTL::Int4, + Vf::Float32x4 => MTL::Float4, + Vf::Unorm10_10_10_2 => MTL::UInt1010102Normalized, Vf::Float64 | Vf::Float64x2 | Vf::Float64x3 | Vf::Float64x4 => unimplemented!(), } } -pub fn map_step_mode(mode: wgt::VertexStepMode) -> metal::MTLVertexStepFunction { +pub fn map_step_mode(mode: wgt::VertexStepMode) -> MTLVertexStepFunction { match mode { - wgt::VertexStepMode::Vertex => metal::MTLVertexStepFunction::PerVertex, - wgt::VertexStepMode::Instance => metal::MTLVertexStepFunction::PerInstance, + wgt::VertexStepMode::Vertex => MTLVertexStepFunction::PerVertex, + wgt::VertexStepMode::Instance => MTLVertexStepFunction::PerInstance, } } -pub fn map_stencil_op(op: wgt::StencilOperation) -> metal::MTLStencilOperation { - use metal::MTLStencilOperation::*; +pub fn map_stencil_op(op: wgt::StencilOperation) -> MTLStencilOperation { use wgt::StencilOperation as So; + use MTLStencilOperation as MTL; match op { - So::Keep => Keep, - So::Zero => Zero, - So::Replace => Replace, - So::IncrementClamp => IncrementClamp, - So::IncrementWrap => IncrementWrap, - So::DecrementClamp => DecrementClamp, - So::DecrementWrap => DecrementWrap, - So::Invert => Invert, + So::Keep => MTL::Keep, + So::Zero => MTL::Zero, + So::Replace => MTL::Replace, + So::IncrementClamp => MTL::IncrementClamp, + So::IncrementWrap => MTL::IncrementWrap, + So::DecrementClamp => MTL::DecrementClamp, + So::DecrementWrap => MTL::DecrementWrap, + So::Invert => MTL::Invert, } } -pub fn map_winding(winding: wgt::FrontFace) -> metal::MTLWinding { +pub fn map_winding(winding: wgt::FrontFace) -> MTLWinding { match winding { - wgt::FrontFace::Cw => metal::MTLWinding::Clockwise, - wgt::FrontFace::Ccw => metal::MTLWinding::CounterClockwise, + wgt::FrontFace::Cw => MTLWinding::Clockwise, + wgt::FrontFace::Ccw => MTLWinding::CounterClockwise, } } -pub fn map_cull_mode(face: Option) -> metal::MTLCullMode { +pub fn map_cull_mode(face: Option) -> MTLCullMode { match face { - None => metal::MTLCullMode::None, - Some(wgt::Face::Front) => metal::MTLCullMode::Front, - Some(wgt::Face::Back) => metal::MTLCullMode::Back, + None => MTLCullMode::None, + Some(wgt::Face::Front) => MTLCullMode::Front, + Some(wgt::Face::Back) => MTLCullMode::Back, } } -pub fn map_range(range: &crate::MemoryRange) -> metal::NSRange { - metal::NSRange { - location: range.start, - length: range.end - range.start, +pub fn map_range(range: &crate::MemoryRange) -> NSRange { + NSRange { + location: range.start as usize, + length: (range.end - range.start) as usize, } } -pub fn map_copy_extent(extent: &crate::CopyExtent) -> metal::MTLSize { - metal::MTLSize { - width: extent.width as u64, - height: extent.height as u64, - depth: extent.depth as u64, +pub fn map_copy_extent(extent: &crate::CopyExtent) -> MTLSize { + MTLSize { + width: extent.width as usize, + height: extent.height as usize, + depth: extent.depth as usize, } } -pub fn map_origin(origin: &wgt::Origin3d) -> metal::MTLOrigin { - metal::MTLOrigin { - x: origin.x as u64, - y: origin.y as u64, - z: origin.z as u64, +pub fn map_origin(origin: &wgt::Origin3d) -> MTLOrigin { + MTLOrigin { + x: origin.x as usize, + y: origin.y as usize, + z: origin.z as usize, } } -pub fn map_store_action(store: bool, resolve: bool) -> metal::MTLStoreAction { - use metal::MTLStoreAction::*; +pub fn map_store_action(store: bool, resolve: bool) -> MTLStoreAction { match (store, resolve) { - (true, true) => StoreAndMultisampleResolve, - (false, true) => MultisampleResolve, - (true, false) => Store, - (false, false) => DontCare, + (true, true) => MTLStoreAction::StoreAndMultisampleResolve, + (false, true) => MTLStoreAction::MultisampleResolve, + (true, false) => MTLStoreAction::Store, + (false, false) => MTLStoreAction::DontCare, } } -pub fn map_clear_color(color: &wgt::Color) -> metal::MTLClearColor { - metal::MTLClearColor { +pub fn map_clear_color(color: &wgt::Color) -> MTLClearColor { + MTLClearColor { red: color.r, green: color.g, blue: color.b, @@ -307,17 +299,14 @@ pub fn map_clear_color(color: &wgt::Color) -> metal::MTLClearColor { } } -pub fn get_blit_option( - format: wgt::TextureFormat, - aspect: crate::FormatAspects, -) -> metal::MTLBlitOption { +pub fn get_blit_option(format: wgt::TextureFormat, aspect: crate::FormatAspects) -> MTLBlitOption { if format.is_combined_depth_stencil_format() { match aspect { - crate::FormatAspects::DEPTH => metal::MTLBlitOption::DepthFromDepthStencil, - crate::FormatAspects::STENCIL => metal::MTLBlitOption::StencilFromDepthStencil, + crate::FormatAspects::DEPTH => MTLBlitOption::DepthFromDepthStencil, + crate::FormatAspects::STENCIL => MTLBlitOption::StencilFromDepthStencil, _ => unreachable!(), } } else { - metal::MTLBlitOption::None + MTLBlitOption::None } } diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 347a97a086..937af143bd 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -1,7 +1,20 @@ +use objc2::{msg_send_id, rc::Retained, runtime::ProtocolObject}; +use objc2_foundation::{ns_string, NSError, NSRange, NSString}; +use objc2_metal::{ + MTLBuffer, MTLCaptureManager, MTLCaptureScope, MTLCommandBuffer, MTLCommandBufferStatus, + MTLCompileOptions, MTLComputePipelineDescriptor, MTLComputePipelineState, + MTLCounterSampleBufferDescriptor, MTLCounterSet, MTLDepthClipMode, MTLDepthStencilDescriptor, + MTLDevice, MTLFunction, MTLLanguageVersion, MTLLibrary, MTLMutability, + MTLPipelineBufferDescriptorArray, MTLPixelFormat, MTLPrimitiveTopologyClass, + MTLRenderPipelineDescriptor, MTLResource, MTLResourceOptions, MTLSamplerAddressMode, + MTLSamplerDescriptor, MTLSamplerMipFilter, MTLSize, MTLStencilDescriptor, MTLStorageMode, + MTLTexture, MTLTextureDescriptor, MTLTextureType, MTLTriangleFillMode, MTLVertexDescriptor, + MTLVertexStepFunction, +}; use parking_lot::Mutex; use std::{ num::NonZeroU32, - ptr, + ptr::NonNull, sync::{atomic, Arc}, thread, time, }; @@ -12,9 +25,9 @@ use crate::auxil::map_naga_stage; type DeviceResult = Result; struct CompiledShader { - library: metal::Library, - function: metal::Function, - wg_size: metal::MTLSize, + library: Retained>, + function: Retained>, + wg_size: MTLSize, wg_memory_sizes: Vec, /// Bindings of WGSL `storage` globals that contain variable-sized arrays. @@ -34,27 +47,29 @@ fn create_stencil_desc( face: &wgt::StencilFaceState, read_mask: u32, write_mask: u32, -) -> metal::StencilDescriptor { - let desc = metal::StencilDescriptor::new(); - desc.set_stencil_compare_function(conv::map_compare_function(face.compare)); - desc.set_read_mask(read_mask); - desc.set_write_mask(write_mask); - desc.set_stencil_failure_operation(conv::map_stencil_op(face.fail_op)); - desc.set_depth_failure_operation(conv::map_stencil_op(face.depth_fail_op)); - desc.set_depth_stencil_pass_operation(conv::map_stencil_op(face.pass_op)); +) -> Retained { + let desc = unsafe { MTLStencilDescriptor::new() }; + desc.setStencilCompareFunction(conv::map_compare_function(face.compare)); + desc.setReadMask(read_mask); + desc.setWriteMask(write_mask); + desc.setStencilFailureOperation(conv::map_stencil_op(face.fail_op)); + desc.setDepthFailureOperation(conv::map_stencil_op(face.depth_fail_op)); + desc.setDepthStencilPassOperation(conv::map_stencil_op(face.pass_op)); desc } -fn create_depth_stencil_desc(state: &wgt::DepthStencilState) -> metal::DepthStencilDescriptor { - let desc = metal::DepthStencilDescriptor::new(); - desc.set_depth_compare_function(conv::map_compare_function(state.depth_compare)); - desc.set_depth_write_enabled(state.depth_write_enabled); +fn create_depth_stencil_desc( + state: &wgt::DepthStencilState, +) -> Retained { + let desc = unsafe { MTLDepthStencilDescriptor::new() }; + desc.setDepthCompareFunction(conv::map_compare_function(state.depth_compare)); + desc.setDepthWriteEnabled(state.depth_write_enabled); let s = &state.stencil; if s.is_enabled() { let front_desc = create_stencil_desc(&s.front, s.read_mask, s.write_mask); - desc.set_front_face_stencil(Some(&front_desc)); + desc.setFrontFaceStencil(Some(&front_desc)); let back_desc = create_stencil_desc(&s.back, s.read_mask, s.write_mask); - desc.set_back_face_stencil(Some(&back_desc)); + desc.setBackFaceStencil(Some(&back_desc)); } desc } @@ -102,7 +117,7 @@ impl super::Device { stage: &crate::ProgrammableStage, vertex_buffer_mappings: &[naga::back::msl::VertexBufferMapping], layout: &super::PipelineLayout, - primitive_class: metal::MTLPrimitiveTopologyClass, + primitive_class: MTLPrimitiveTopologyClass, naga_stage: naga::ShaderStage, ) -> Result { let stage_bit = map_naga_stage(naga_stage); @@ -124,16 +139,19 @@ impl super::Device { let options = naga::back::msl::Options { lang_version: match self.shared.private_caps.msl_version { - metal::MTLLanguageVersion::V1_0 => (1, 0), - metal::MTLLanguageVersion::V1_1 => (1, 1), - metal::MTLLanguageVersion::V1_2 => (1, 2), - metal::MTLLanguageVersion::V2_0 => (2, 0), - metal::MTLLanguageVersion::V2_1 => (2, 1), - metal::MTLLanguageVersion::V2_2 => (2, 2), - metal::MTLLanguageVersion::V2_3 => (2, 3), - metal::MTLLanguageVersion::V2_4 => (2, 4), - metal::MTLLanguageVersion::V3_0 => (3, 0), - metal::MTLLanguageVersion::V3_1 => (3, 1), + #[allow(deprecated)] + MTLLanguageVersion::MTLLanguageVersion1_0 => (1, 0), + MTLLanguageVersion::MTLLanguageVersion1_1 => (1, 1), + MTLLanguageVersion::MTLLanguageVersion1_2 => (1, 2), + MTLLanguageVersion::MTLLanguageVersion2_0 => (2, 0), + MTLLanguageVersion::MTLLanguageVersion2_1 => (2, 1), + MTLLanguageVersion::MTLLanguageVersion2_2 => (2, 2), + MTLLanguageVersion::MTLLanguageVersion2_3 => (2, 3), + MTLLanguageVersion::MTLLanguageVersion2_4 => (2, 4), + MTLLanguageVersion::MTLLanguageVersion3_0 => (3, 0), + MTLLanguageVersion::MTLLanguageVersion3_1 => (3, 1), + // Newer version, fall back to 3.1 + _ => (3, 1), }, inline_samplers: Default::default(), spirv_cross_compatibility: false, @@ -154,7 +172,7 @@ impl super::Device { let pipeline_options = naga::back::msl::PipelineOptions { allow_and_force_point_size: match primitive_class { - metal::MTLPrimitiveTopologyClass::Point => true, + MTLPrimitiveTopologyClass::Point => true, _ => false, }, vertex_pulling_transform: true, @@ -172,18 +190,18 @@ impl super::Device { &source ); - let options = metal::CompileOptions::new(); - options.set_language_version(self.shared.private_caps.msl_version); + let options = MTLCompileOptions::new(); + options.setLanguageVersion(self.shared.private_caps.msl_version); if self.shared.private_caps.supports_preserve_invariance { - options.set_preserve_invariance(true); + options.setPreserveInvariance(true); } let library = self .shared .device .lock() - .new_library_with_source(source.as_ref(), &options) + .newLibraryWithSource_options_error(&NSString::from_str(&source), Some(&options)) .map_err(|err| { log::warn!("Naga generated shader:\n{}", source); crate::PipelineError::Linkage(stage_bit, format!("Metal: {}", err)) @@ -199,16 +217,18 @@ impl super::Device { .as_ref() .map_err(|e| crate::PipelineError::Linkage(stage_bit, format!("{}", e)))?; - let wg_size = metal::MTLSize { + let wg_size = MTLSize { width: ep.workgroup_size[0] as _, height: ep.workgroup_size[1] as _, depth: ep.workgroup_size[2] as _, }; - let function = library.get_function(ep_name, None).map_err(|e| { - log::error!("get_function: {:?}", e); - crate::PipelineError::EntryPoint(naga_stage) - })?; + let function = library + .newFunctionWithName(&NSString::from_str(ep_name)) + .ok_or_else(|| { + log::error!("Function '{ep_name}' does not exist"); + crate::PipelineError::EntryPoint(naga_stage) + })?; // collect sizes indices, immutable buffers, and work group memory sizes let ep_info = &module_info.get_entry_point(ep_index); @@ -269,23 +289,21 @@ impl super::Device { } fn set_buffers_mutability( - buffers: &metal::PipelineBufferDescriptorArrayRef, + buffers: &MTLPipelineBufferDescriptorArray, mut immutable_mask: usize, ) { while immutable_mask != 0 { let slot = immutable_mask.trailing_zeros(); immutable_mask ^= 1 << slot; - buffers - .object_at(slot as u64) - .unwrap() - .set_mutability(metal::MTLMutability::Immutable); + unsafe { buffers.objectAtIndexedSubscript(slot as usize) } + .setMutability(MTLMutability::Immutable); } } pub unsafe fn texture_from_raw( - raw: metal::Texture, + raw: Retained>, format: wgt::TextureFormat, - raw_type: metal::MTLTextureType, + raw_type: MTLTextureType, array_layers: u32, mip_levels: u32, copy_size: crate::CopyExtent, @@ -300,7 +318,10 @@ impl super::Device { } } - pub unsafe fn device_from_raw(raw: metal::Device, features: wgt::Features) -> super::Device { + pub unsafe fn device_from_raw( + raw: Retained>, + features: wgt::Features, + ) -> super::Device { super::Device { shared: Arc::new(super::AdapterShared::new(raw)), features, @@ -308,11 +329,14 @@ impl super::Device { } } - pub unsafe fn buffer_from_raw(raw: metal::Buffer, size: wgt::BufferAddress) -> super::Buffer { + pub unsafe fn buffer_from_raw( + raw: Retained>, + size: wgt::BufferAddress, + ) -> super::Buffer { super::Buffer { raw, size } } - pub fn raw_device(&self) -> &Mutex { + pub fn raw_device(&self) -> &Mutex>> { &self.shared.device } } @@ -326,24 +350,29 @@ impl crate::Device for super::Device { let map_read = desc.usage.contains(crate::BufferUses::MAP_READ); let map_write = desc.usage.contains(crate::BufferUses::MAP_WRITE); - let mut options = metal::MTLResourceOptions::empty(); + let mut options = MTLResourceOptions::empty(); options |= if map_read || map_write { // `crate::MemoryFlags::PREFER_COHERENT` is ignored here - metal::MTLResourceOptions::StorageModeShared + MTLResourceOptions::MTLResourceStorageModeShared } else { - metal::MTLResourceOptions::StorageModePrivate + MTLResourceOptions::MTLResourceStorageModePrivate }; options.set( - metal::MTLResourceOptions::CPUCacheModeWriteCombined, + MTLResourceOptions::MTLResourceCPUCacheModeWriteCombined, map_write, ); //TODO: HazardTrackingModeUntracked - objc::rc::autoreleasepool(|| { - let raw = self.shared.device.lock().new_buffer(desc.size, options); + objc2::rc::autoreleasepool(|_| { + let raw = self + .shared + .device + .lock() + .newBufferWithLength_options(desc.size as usize, options) + .unwrap(); if let Some(label) = desc.label { - raw.set_label(label); + raw.setLabel(Some(&NSString::from_str(label))); } self.counters.buffers.add(1); Ok(super::Buffer { @@ -365,10 +394,9 @@ impl crate::Device for super::Device { buffer: &super::Buffer, range: crate::MemoryRange, ) -> DeviceResult { - let ptr = buffer.raw.contents().cast::(); - assert!(!ptr.is_null()); + let ptr: NonNull = buffer.raw.contents().cast(); Ok(crate::BufferMapping { - ptr: ptr::NonNull::new(unsafe { ptr.offset(range.start as isize) }).unwrap(), + ptr: unsafe { NonNull::new(ptr.as_ptr().offset(range.start as isize)).unwrap() }, is_coherent: true, }) } @@ -381,46 +409,46 @@ impl crate::Device for super::Device { &self, desc: &crate::TextureDescriptor, ) -> DeviceResult { - use metal::foreign_types::ForeignType as _; - let mtl_format = self.shared.private_caps.map_format(desc.format); - objc::rc::autoreleasepool(|| { - let descriptor = metal::TextureDescriptor::new(); + objc2::rc::autoreleasepool(|_| { + let descriptor = MTLTextureDescriptor::new(); let mtl_type = match desc.dimension { - wgt::TextureDimension::D1 => metal::MTLTextureType::D1, + wgt::TextureDimension::D1 => MTLTextureType::MTLTextureType1D, wgt::TextureDimension::D2 => { if desc.sample_count > 1 { - descriptor.set_sample_count(desc.sample_count as u64); - metal::MTLTextureType::D2Multisample + descriptor.setSampleCount(desc.sample_count as usize); + MTLTextureType::MTLTextureType2DMultisample } else if desc.size.depth_or_array_layers > 1 { - descriptor.set_array_length(desc.size.depth_or_array_layers as u64); - metal::MTLTextureType::D2Array + descriptor.setArrayLength(desc.size.depth_or_array_layers as usize); + MTLTextureType::MTLTextureType2DArray } else { - metal::MTLTextureType::D2 + MTLTextureType::MTLTextureType2D } } wgt::TextureDimension::D3 => { - descriptor.set_depth(desc.size.depth_or_array_layers as u64); - metal::MTLTextureType::D3 + descriptor.setDepth(desc.size.depth_or_array_layers as usize); + MTLTextureType::MTLTextureType3D } }; - descriptor.set_texture_type(mtl_type); - descriptor.set_width(desc.size.width as u64); - descriptor.set_height(desc.size.height as u64); - descriptor.set_mipmap_level_count(desc.mip_level_count as u64); - descriptor.set_pixel_format(mtl_format); - descriptor.set_usage(conv::map_texture_usage(desc.format, desc.usage)); - descriptor.set_storage_mode(metal::MTLStorageMode::Private); + descriptor.setTextureType(mtl_type); + descriptor.setWidth(desc.size.width as usize); + descriptor.setHeight(desc.size.height as usize); + descriptor.setMipmapLevelCount(desc.mip_level_count as usize); + descriptor.setPixelFormat(mtl_format); + descriptor.setUsage(conv::map_texture_usage(desc.format, desc.usage)); + descriptor.setStorageMode(MTLStorageMode::Private); - let raw = self.shared.device.lock().new_texture(&descriptor); - if raw.as_ptr().is_null() { - return Err(crate::DeviceError::OutOfMemory); - } + let raw = self + .shared + .device + .lock() + .newTextureWithDescriptor(&descriptor) + .ok_or(crate::DeviceError::OutOfMemory)?; if let Some(label) = desc.label { - raw.set_label(label); + raw.setLabel(Some(&NSString::from_str(label))); } self.counters.textures.add(1); @@ -449,7 +477,7 @@ impl crate::Device for super::Device { texture: &super::Texture, desc: &crate::TextureViewDescriptor, ) -> DeviceResult { - let raw_type = if texture.raw_type == metal::MTLTextureType::D2Multisample { + let raw_type = if texture.raw_type == MTLTextureType::MTLTextureType2DMultisample { texture.raw_type } else { conv::map_texture_view_dimension(desc.dimension) @@ -482,21 +510,24 @@ impl crate::Device for super::Device { .array_layer_count .unwrap_or(texture.array_layers - desc.range.base_array_layer); - objc::rc::autoreleasepool(|| { - let raw = texture.raw.new_texture_view_from_slice( - raw_format, - raw_type, - metal::NSRange { - location: desc.range.base_mip_level as _, - length: mip_level_count as _, - }, - metal::NSRange { - location: desc.range.base_array_layer as _, - length: array_layer_count as _, - }, - ); + objc2::rc::autoreleasepool(|_| { + let raw = texture + .raw + .newTextureViewWithPixelFormat_textureType_levels_slices( + raw_format, + raw_type, + NSRange { + location: desc.range.base_mip_level as _, + length: mip_level_count as _, + }, + NSRange { + location: desc.range.base_array_layer as _, + length: array_layer_count as _, + }, + ) + .unwrap(); if let Some(label) = desc.label { - raw.set_label(label); + raw.setLabel(Some(&NSString::from_str(label))); } raw }) @@ -515,56 +546,61 @@ impl crate::Device for super::Device { &self, desc: &crate::SamplerDescriptor, ) -> DeviceResult { - objc::rc::autoreleasepool(|| { - let descriptor = metal::SamplerDescriptor::new(); + objc2::rc::autoreleasepool(|_| { + let descriptor = MTLSamplerDescriptor::new(); - descriptor.set_min_filter(conv::map_filter_mode(desc.min_filter)); - descriptor.set_mag_filter(conv::map_filter_mode(desc.mag_filter)); - descriptor.set_mip_filter(match desc.mipmap_filter { + descriptor.setMinFilter(conv::map_filter_mode(desc.min_filter)); + descriptor.setMagFilter(conv::map_filter_mode(desc.mag_filter)); + descriptor.setMipFilter(match desc.mipmap_filter { wgt::FilterMode::Nearest if desc.lod_clamp == (0.0..0.0) => { - metal::MTLSamplerMipFilter::NotMipmapped + MTLSamplerMipFilter::NotMipmapped } - wgt::FilterMode::Nearest => metal::MTLSamplerMipFilter::Nearest, - wgt::FilterMode::Linear => metal::MTLSamplerMipFilter::Linear, + wgt::FilterMode::Nearest => MTLSamplerMipFilter::Nearest, + wgt::FilterMode::Linear => MTLSamplerMipFilter::Linear, }); let [s, t, r] = desc.address_modes; - descriptor.set_address_mode_s(conv::map_address_mode(s)); - descriptor.set_address_mode_t(conv::map_address_mode(t)); - descriptor.set_address_mode_r(conv::map_address_mode(r)); + descriptor.setSAddressMode(conv::map_address_mode(s)); + descriptor.setTAddressMode(conv::map_address_mode(t)); + descriptor.setRAddressMode(conv::map_address_mode(r)); // Anisotropy is always supported on mac up to 16x - descriptor.set_max_anisotropy(desc.anisotropy_clamp as _); + descriptor.setMaxAnisotropy(desc.anisotropy_clamp as _); - descriptor.set_lod_min_clamp(desc.lod_clamp.start); - descriptor.set_lod_max_clamp(desc.lod_clamp.end); + descriptor.setLodMinClamp(desc.lod_clamp.start); + descriptor.setLodMaxClamp(desc.lod_clamp.end); if let Some(fun) = desc.compare { - descriptor.set_compare_function(conv::map_compare_function(fun)); + descriptor.setCompareFunction(conv::map_compare_function(fun)); } if let Some(border_color) = desc.border_color { if let wgt::SamplerBorderColor::Zero = border_color { if s == wgt::AddressMode::ClampToBorder { - descriptor.set_address_mode_s(metal::MTLSamplerAddressMode::ClampToZero); + descriptor.setSAddressMode(MTLSamplerAddressMode::ClampToZero); } if t == wgt::AddressMode::ClampToBorder { - descriptor.set_address_mode_t(metal::MTLSamplerAddressMode::ClampToZero); + descriptor.setTAddressMode(MTLSamplerAddressMode::ClampToZero); } if r == wgt::AddressMode::ClampToBorder { - descriptor.set_address_mode_r(metal::MTLSamplerAddressMode::ClampToZero); + descriptor.setRAddressMode(MTLSamplerAddressMode::ClampToZero); } } else { - descriptor.set_border_color(conv::map_border_color(border_color)); + descriptor.setBorderColor(conv::map_border_color(border_color)); } } if let Some(label) = desc.label { - descriptor.set_label(label); + descriptor.setLabel(Some(&NSString::from_str(label))); } - let raw = self.shared.device.lock().new_sampler(&descriptor); + let raw = self + .shared + .device + .lock() + .newSamplerStateWithDescriptor(&descriptor) + .unwrap(); self.counters.samplers.add(1); @@ -912,12 +948,12 @@ impl crate::Device for super::Device { super::PipelineCache, >, ) -> Result { - objc::rc::autoreleasepool(|| { - let descriptor = metal::RenderPipelineDescriptor::new(); + objc2::rc::autoreleasepool(|_| { + let descriptor = MTLRenderPipelineDescriptor::new(); let raw_triangle_fill_mode = match desc.primitive.polygon_mode { - wgt::PolygonMode::Fill => metal::MTLTriangleFillMode::Fill, - wgt::PolygonMode::Line => metal::MTLTriangleFillMode::Lines, + wgt::PolygonMode::Fill => MTLTriangleFillMode::Fill, + wgt::PolygonMode::Line => MTLTriangleFillMode::Lines, wgt::PolygonMode::Point => panic!( "{:?} is not enabled for this backend", wgt::Features::POLYGON_MODE_POINT @@ -966,10 +1002,10 @@ impl crate::Device for super::Device { naga::ShaderStage::Vertex, )?; - descriptor.set_vertex_function(Some(&vs.function)); + descriptor.setVertexFunction(Some(&vs.function)); if self.shared.private_caps.supports_mutability { Self::set_buffers_mutability( - descriptor.vertex_buffers().unwrap(), + &descriptor.vertexBuffers(), vs.immutable_buffer_mask, ); } @@ -995,10 +1031,10 @@ impl crate::Device for super::Device { naga::ShaderStage::Fragment, )?; - descriptor.set_fragment_function(Some(&fs.function)); + descriptor.setFragmentFunction(Some(&fs.function)); if self.shared.private_caps.supports_mutability { Self::set_buffers_mutability( - descriptor.fragment_buffers().unwrap(), + &descriptor.fragmentBuffers(), fs.immutable_buffer_mask, ); } @@ -1016,38 +1052,37 @@ impl crate::Device for super::Device { // TODO: This is a workaround for what appears to be a Metal validation bug // A pixel format is required even though no attachments are provided if desc.color_targets.is_empty() && desc.depth_stencil.is_none() { - descriptor - .set_depth_attachment_pixel_format(metal::MTLPixelFormat::Depth32Float); + descriptor.setDepthAttachmentPixelFormat(MTLPixelFormat::Depth32Float); } (None, None) } }; for (i, ct) in desc.color_targets.iter().enumerate() { - let at_descriptor = descriptor.color_attachments().object_at(i as u64).unwrap(); + let at_descriptor = descriptor.colorAttachments().objectAtIndexedSubscript(i); let ct = if let Some(color_target) = ct.as_ref() { color_target } else { - at_descriptor.set_pixel_format(metal::MTLPixelFormat::Invalid); + at_descriptor.setPixelFormat(MTLPixelFormat::Invalid); continue; }; let raw_format = self.shared.private_caps.map_format(ct.format); - at_descriptor.set_pixel_format(raw_format); - at_descriptor.set_write_mask(conv::map_color_write(ct.write_mask)); + at_descriptor.setPixelFormat(raw_format); + at_descriptor.setWriteMask(conv::map_color_write(ct.write_mask)); if let Some(ref blend) = ct.blend { - at_descriptor.set_blending_enabled(true); + at_descriptor.setBlendingEnabled(true); let (color_op, color_src, color_dst) = conv::map_blend_component(&blend.color); let (alpha_op, alpha_src, alpha_dst) = conv::map_blend_component(&blend.alpha); - at_descriptor.set_rgb_blend_operation(color_op); - at_descriptor.set_source_rgb_blend_factor(color_src); - at_descriptor.set_destination_rgb_blend_factor(color_dst); + at_descriptor.setRgbBlendOperation(color_op); + at_descriptor.setSourceRGBBlendFactor(color_src); + at_descriptor.setDestinationRGBBlendFactor(color_dst); - at_descriptor.set_alpha_blend_operation(alpha_op); - at_descriptor.set_source_alpha_blend_factor(alpha_src); - at_descriptor.set_destination_alpha_blend_factor(alpha_dst); + at_descriptor.setAlphaBlendOperation(alpha_op); + at_descriptor.setSourceAlphaBlendFactor(alpha_src); + at_descriptor.setDestinationAlphaBlendFactor(alpha_dst); } } @@ -1056,10 +1091,10 @@ impl crate::Device for super::Device { let raw_format = self.shared.private_caps.map_format(ds.format); let aspects = crate::FormatAspects::from(ds.format); if aspects.contains(crate::FormatAspects::DEPTH) { - descriptor.set_depth_attachment_pixel_format(raw_format); + descriptor.setDepthAttachmentPixelFormat(raw_format); } if aspects.contains(crate::FormatAspects::STENCIL) { - descriptor.set_stencil_attachment_pixel_format(raw_format); + descriptor.setStencilAttachmentPixelFormat(raw_format); } let ds_descriptor = create_depth_stencil_desc(ds); @@ -1067,7 +1102,8 @@ impl crate::Device for super::Device { .shared .device .lock() - .new_depth_stencil_state(&ds_descriptor); + .newDepthStencilStateWithDescriptor(&ds_descriptor) + .unwrap(); Some((raw, ds.bias)) } None => None, @@ -1088,11 +1124,13 @@ impl crate::Device for super::Device { } if !desc.vertex_buffers.is_empty() { - let vertex_descriptor = metal::VertexDescriptor::new(); + let vertex_descriptor = MTLVertexDescriptor::new(); for (i, vb) in desc.vertex_buffers.iter().enumerate() { let buffer_index = self.shared.private_caps.max_vertex_buffers as u64 - 1 - i as u64; - let buffer_desc = vertex_descriptor.layouts().object_at(buffer_index).unwrap(); + let buffer_desc = vertex_descriptor + .layouts() + .objectAtIndexedSubscript(buffer_index as usize); // Metal expects the stride to be the actual size of the attributes. // The semantics of array_stride == 0 can be achieved by setting @@ -1104,44 +1142,43 @@ impl crate::Device for super::Device { .map(|attribute| attribute.offset + attribute.format.size()) .max() .unwrap_or(0); - buffer_desc.set_stride(wgt::math::align_to(stride, 4)); - buffer_desc.set_step_function(metal::MTLVertexStepFunction::Constant); - buffer_desc.set_step_rate(0); + buffer_desc.setStride(wgt::math::align_to(stride as usize, 4)); + buffer_desc.setStepFunction(MTLVertexStepFunction::Constant); + buffer_desc.setStepRate(0); } else { - buffer_desc.set_stride(vb.array_stride); - buffer_desc.set_step_function(conv::map_step_mode(vb.step_mode)); + buffer_desc.setStride(vb.array_stride as usize); + buffer_desc.setStepFunction(conv::map_step_mode(vb.step_mode)); } for at in vb.attributes { let attribute_desc = vertex_descriptor .attributes() - .object_at(at.shader_location as u64) - .unwrap(); - attribute_desc.set_format(conv::map_vertex_format(at.format)); - attribute_desc.set_buffer_index(buffer_index); - attribute_desc.set_offset(at.offset); + .objectAtIndexedSubscript(at.shader_location as usize); + attribute_desc.setFormat(conv::map_vertex_format(at.format)); + attribute_desc.setBufferIndex(buffer_index as usize); + attribute_desc.setOffset(at.offset as usize); } } - descriptor.set_vertex_descriptor(Some(vertex_descriptor)); + descriptor.setVertexDescriptor(Some(&vertex_descriptor)); } if desc.multisample.count != 1 { //TODO: handle sample mask - descriptor.set_sample_count(desc.multisample.count as u64); - descriptor - .set_alpha_to_coverage_enabled(desc.multisample.alpha_to_coverage_enabled); + #[allow(deprecated)] + descriptor.setSampleCount(desc.multisample.count as usize); + descriptor.setAlphaToCoverageEnabled(desc.multisample.alpha_to_coverage_enabled); //descriptor.set_alpha_to_one_enabled(desc.multisample.alpha_to_one_enabled); } if let Some(name) = desc.label { - descriptor.set_label(name); + descriptor.setLabel(Some(&NSString::from_str(name))); } let raw = self .shared .device .lock() - .new_render_pipeline_state(&descriptor) + .newRenderPipelineStateWithDescriptor_error(&descriptor) .map_err(|e| { crate::PipelineError::Linkage( wgt::ShaderStages::VERTEX | wgt::ShaderStages::FRAGMENT, @@ -1163,9 +1200,9 @@ impl crate::Device for super::Device { raw_cull_mode: conv::map_cull_mode(desc.primitive.cull_mode), raw_depth_clip_mode: if self.features.contains(wgt::Features::DEPTH_CLIP_CONTROL) { Some(if desc.primitive.unclipped_depth { - metal::MTLDepthClipMode::Clamp + MTLDepthClipMode::Clamp } else { - metal::MTLDepthClipMode::Clip + MTLDepthClipMode::Clip }) } else { None @@ -1187,23 +1224,20 @@ impl crate::Device for super::Device { super::PipelineCache, >, ) -> Result { - objc::rc::autoreleasepool(|| { - let descriptor = metal::ComputePipelineDescriptor::new(); + objc2::rc::autoreleasepool(|_| { + let descriptor = MTLComputePipelineDescriptor::new(); let cs = self.load_shader( &desc.stage, &[], desc.layout, - metal::MTLPrimitiveTopologyClass::Unspecified, + MTLPrimitiveTopologyClass::Unspecified, naga::ShaderStage::Compute, )?; - descriptor.set_compute_function(Some(&cs.function)); + descriptor.setComputeFunction(Some(&cs.function)); if self.shared.private_caps.supports_mutability { - Self::set_buffers_mutability( - descriptor.buffers().unwrap(), - cs.immutable_buffer_mask, - ); + Self::set_buffers_mutability(&descriptor.buffers(), cs.immutable_buffer_mask); } let cs_info = super::PipelineStageInfo { @@ -1214,20 +1248,17 @@ impl crate::Device for super::Device { }; if let Some(name) = desc.label { - descriptor.set_label(name); + descriptor.setLabel(Some(&NSString::from_str(name))); } - let raw = self - .shared - .device - .lock() - .new_compute_pipeline_state(&descriptor) - .map_err(|e| { - crate::PipelineError::Linkage( - wgt::ShaderStages::COMPUTE, - format!("new_compute_pipeline_state: {:?}", e), - ) - })?; + let raw = + new_compute_pipeline_state_with_descriptor(&self.shared.device.lock(), &descriptor) + .map_err(|e| { + crate::PipelineError::Linkage( + wgt::ShaderStages::COMPUTE, + format!("new_compute_pipeline_state: {:?}", e), + ) + })?; self.counters.compute_pipelines.add(1); @@ -1257,15 +1288,20 @@ impl crate::Device for super::Device { &self, desc: &wgt::QuerySetDescriptor, ) -> DeviceResult { - objc::rc::autoreleasepool(|| { + objc2::rc::autoreleasepool(|_| { match desc.ty { wgt::QueryType::Occlusion => { let size = desc.count as u64 * crate::QUERY_SIZE; - let options = metal::MTLResourceOptions::empty(); + let options = MTLResourceOptions::empty(); //TODO: HazardTrackingModeUntracked - let raw_buffer = self.shared.device.lock().new_buffer(size, options); + let raw_buffer = self + .shared + .device + .lock() + .newBufferWithLength_options(size as usize, options) + .unwrap(); if let Some(label) = desc.label { - raw_buffer.set_label(label); + raw_buffer.setLabel(Some(&NSString::from_str(label))); } Ok(super::QuerySet { raw_buffer, @@ -1276,29 +1312,32 @@ impl crate::Device for super::Device { wgt::QueryType::Timestamp => { let size = desc.count as u64 * crate::QUERY_SIZE; let device = self.shared.device.lock(); - let destination_buffer = - device.new_buffer(size, metal::MTLResourceOptions::empty()); + let destination_buffer = device + .newBufferWithLength_options(size as usize, MTLResourceOptions::empty()) + .unwrap(); - let csb_desc = metal::CounterSampleBufferDescriptor::new(); - csb_desc.set_storage_mode(metal::MTLStorageMode::Shared); - csb_desc.set_sample_count(desc.count as _); + let csb_desc = MTLCounterSampleBufferDescriptor::new(); + csb_desc.setStorageMode(MTLStorageMode::Shared); + csb_desc.setSampleCount(desc.count as _); if let Some(label) = desc.label { - csb_desc.set_label(label); + csb_desc.setLabel(&NSString::from_str(label)); } - let counter_sets = device.counter_sets(); - let timestamp_counter = - match counter_sets.iter().find(|cs| cs.name() == "timestamp") { - Some(counter) => counter, - None => { - log::error!("Failed to obtain timestamp counter set."); - return Err(crate::DeviceError::ResourceCreationFailed); - } - }; - csb_desc.set_counter_set(timestamp_counter); + let counter_sets = device.counterSets().unwrap(); + let timestamp_counter = match counter_sets + .iter() + .find(|cs| &*cs.name() == ns_string!("timestamp")) + { + Some(counter) => counter, + None => { + log::error!("Failed to obtain timestamp counter set."); + return Err(crate::DeviceError::ResourceCreationFailed); + } + }; + csb_desc.setCounterSet(Some(timestamp_counter)); let counter_sample_buffer = - match device.new_counter_sample_buffer_with_descriptor(&csb_desc) { + match device.newCounterSampleBufferWithDescriptor_error(&csb_desc) { Ok(buffer) => buffer, Err(err) => { log::error!("Failed to create counter sample buffer: {:?}", err); @@ -1340,7 +1379,7 @@ impl crate::Device for super::Device { unsafe fn get_fence_value(&self, fence: &super::Fence) -> DeviceResult { let mut max_value = fence.completed_value.load(atomic::Ordering::Acquire); for &(value, ref cmd_buf) in fence.pending_command_buffers.iter() { - if cmd_buf.status() == metal::MTLCommandBufferStatus::Completed { + if cmd_buf.status() == MTLCommandBufferStatus::Completed { max_value = value; } } @@ -1370,7 +1409,7 @@ impl crate::Device for super::Device { let start = time::Instant::now(); loop { - if let metal::MTLCommandBufferStatus::Completed = cmd_buf.status() { + if let MTLCommandBufferStatus::Completed = cmd_buf.status() { return Ok(true); } if start.elapsed().as_millis() >= timeout_ms as u128 { @@ -1385,19 +1424,20 @@ impl crate::Device for super::Device { return false; } let device = self.shared.device.lock(); - let shared_capture_manager = metal::CaptureManager::shared(); - let default_capture_scope = shared_capture_manager.new_capture_scope_with_device(&device); - shared_capture_manager.set_default_capture_scope(&default_capture_scope); - shared_capture_manager.start_capture_with_scope(&default_capture_scope); - default_capture_scope.begin_scope(); + let shared_capture_manager = MTLCaptureManager::sharedCaptureManager(); + let default_capture_scope = shared_capture_manager.newCaptureScopeWithDevice(&device); + shared_capture_manager.setDefaultCaptureScope(Some(&default_capture_scope)); + #[allow(deprecated)] + shared_capture_manager.startCaptureWithScope(&default_capture_scope); + default_capture_scope.beginScope(); true } unsafe fn stop_capture(&self) { - let shared_capture_manager = metal::CaptureManager::shared(); - if let Some(default_capture_scope) = shared_capture_manager.default_capture_scope() { - default_capture_scope.end_scope(); + let shared_capture_manager = MTLCaptureManager::sharedCaptureManager(); + if let Some(default_capture_scope) = shared_capture_manager.defaultCaptureScope() { + default_capture_scope.endScope(); } - shared_capture_manager.stop_capture(); + shared_capture_manager.stopCapture(); } unsafe fn get_acceleration_structure_build_sizes( @@ -1432,3 +1472,12 @@ impl crate::Device for super::Device { self.counters.clone() } } + +// TODO: `newComputePipelineStateWithDescriptor:error:` is not exposed on +// `MTLDevice`, is this always correct? +fn new_compute_pipeline_state_with_descriptor( + device: &ProtocolObject, + descriptor: &MTLComputePipelineDescriptor, +) -> Result>, Retained> { + unsafe { msg_send_id![device, newComputePipelineStateWithDescriptor: descriptor, error: _] } +} diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index 1935e843ec..8e8ec92016 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -12,6 +12,7 @@ resources, followed by other bind groups. The vertex buffers are bound at the ve end of the VS buffer table. !*/ +#![allow(unsafe_op_in_unsafe_fn)] // `MTLFeatureSet` is superseded by `MTLGpuFamily`. // However, `MTLGpuFamily` is only supported starting MacOS 10.15, whereas our minimum target is MacOS 10.13, @@ -34,7 +35,17 @@ use std::{ use arrayvec::ArrayVec; use bitflags::bitflags; -use metal::foreign_types::ForeignTypeRef as _; +use objc2::{rc::Retained, runtime::ProtocolObject}; +use objc2_foundation::ns_string; +use objc2_metal::{ + MTLBlitCommandEncoder, MTLBuffer, MTLCommandBuffer, MTLCommandBufferStatus, MTLCommandQueue, + MTLComputeCommandEncoder, MTLComputePipelineState, MTLCopyAllDevices, MTLCounterSampleBuffer, + MTLCullMode, MTLDepthClipMode, MTLDepthStencilState, MTLDevice, MTLDrawable, MTLIndexType, + MTLLanguageVersion, MTLLibrary, MTLPrimitiveType, MTLReadWriteTextureTier, + MTLRenderCommandEncoder, MTLRenderPipelineState, MTLSamplerState, MTLSize, MTLTexture, + MTLTextureType, MTLTriangleFillMode, MTLWinding, +}; +use objc2_quartz_core::CAMetalLayer; use parking_lot::{Mutex, RwLock}; #[derive(Clone, Debug)] @@ -99,7 +110,7 @@ crate::impl_dyn_resource!( pub struct Instance {} impl Instance { - pub fn create_surface_from_layer(&self, layer: &metal::MetalLayerRef) -> Surface { + pub fn create_surface_from_layer(&self, layer: &CAMetalLayer) -> Surface { unsafe { Surface::from_layer(layer) } } } @@ -138,11 +149,11 @@ impl crate::Instance for Instance { &self, _surface_hint: Option<&Surface>, ) -> Vec> { - let devices = metal::Device::all(); + let devices = unsafe { Retained::from_raw(MTLCopyAllDevices().as_ptr()).unwrap() }; let mut adapters: Vec> = devices .into_iter() .map(|dev| { - let name = dev.name().into(); + let name = dev.name().to_string(); let shared = AdapterShared::new(dev); crate::ExposedAdapter { info: wgt::AdapterInfo { @@ -192,9 +203,9 @@ bitflags!( #[derive(Clone, Debug)] struct PrivateCapabilities { family_check: bool, - msl_version: metal::MTLLanguageVersion, + msl_version: MTLLanguageVersion, fragment_rw_storage: bool, - read_write_texture_tier: metal::MTLReadWriteTextureTier, + read_write_texture_tier: MTLReadWriteTextureTier, msaa_desktop: bool, msaa_apple3: bool, msaa_apple7: bool, @@ -306,7 +317,7 @@ struct Settings { } struct AdapterShared { - device: Mutex, + device: Mutex>>, disabilities: PrivateDisabilities, private_caps: PrivateCapabilities, settings: Settings, @@ -317,7 +328,7 @@ unsafe impl Send for AdapterShared {} unsafe impl Sync for AdapterShared {} impl AdapterShared { - fn new(device: metal::Device) -> Self { + fn new(device: Retained>) -> Self { let private_caps = PrivateCapabilities::new(&device); log::debug!("{:#?}", private_caps); @@ -336,7 +347,7 @@ pub struct Adapter { } pub struct Queue { - raw: Arc>, + raw: Arc>>>, timestamp_period: f32, } @@ -344,7 +355,10 @@ unsafe impl Send for Queue {} unsafe impl Sync for Queue {} impl Queue { - pub unsafe fn queue_from_raw(raw: metal::CommandQueue, timestamp_period: f32) -> Self { + pub unsafe fn queue_from_raw( + raw: Retained>, + timestamp_period: f32, + ) -> Self { Self { raw: Arc::new(Mutex::new(raw)), timestamp_period, @@ -359,7 +373,7 @@ pub struct Device { } pub struct Surface { - render_layer: Mutex, + render_layer: Mutex>, swapchain_format: RwLock>, extent: RwLock, main_thread_id: thread::ThreadId, @@ -374,7 +388,7 @@ unsafe impl Sync for Surface {} #[derive(Debug)] pub struct SurfaceTexture { texture: Texture, - drawable: metal::MetalDrawable, + drawable: Retained>, present_with_transaction: bool, } @@ -404,30 +418,28 @@ impl crate::Queue for Queue { _surface_textures: &[&SurfaceTexture], (signal_fence, signal_value): (&mut Fence, crate::FenceValue), ) -> Result<(), crate::DeviceError> { - objc::rc::autoreleasepool(|| { + objc2::rc::autoreleasepool(|_| { let extra_command_buffer = { let completed_value = Arc::clone(&signal_fence.completed_value); - let block = block::ConcreteBlock::new(move |_cmd_buf| { + let block = block2::RcBlock::new(move |_cmd_buf| { completed_value.store(signal_value, atomic::Ordering::Release); - }) - .copy(); + }); + let block: *const _ = &*block; let raw = match command_buffers.last() { - Some(&cmd_buf) => cmd_buf.raw.to_owned(), + Some(&cmd_buf) => cmd_buf.raw.clone(), None => { let queue = self.raw.lock(); - queue - .new_command_buffer_with_unretained_references() - .to_owned() + queue.commandBufferWithUnretainedReferences().unwrap() } }; - raw.set_label("(wgpu internal) Signal"); - raw.add_completed_handler(&block); + raw.setLabel(Some(ns_string!("(wgpu internal) Signal"))); + raw.addCompletedHandler(block.cast_mut()); signal_fence.maintain(); signal_fence .pending_command_buffers - .push((signal_value, raw.to_owned())); + .push((signal_value, raw.clone())); // only return an extra one if it's extra match command_buffers.last() { Some(_) => None, @@ -451,19 +463,19 @@ impl crate::Queue for Queue { texture: SurfaceTexture, ) -> Result<(), crate::SurfaceError> { let queue = &self.raw.lock(); - objc::rc::autoreleasepool(|| { - let command_buffer = queue.new_command_buffer(); - command_buffer.set_label("(wgpu internal) Present"); + objc2::rc::autoreleasepool(|_| { + let command_buffer = queue.commandBuffer().unwrap(); + command_buffer.setLabel(Some(ns_string!("(wgpu internal) Present"))); // https://developer.apple.com/documentation/quartzcore/cametallayer/1478157-presentswithtransaction?language=objc if !texture.present_with_transaction { - command_buffer.present_drawable(&texture.drawable); + command_buffer.presentDrawable(&texture.drawable); } command_buffer.commit(); if texture.present_with_transaction { - command_buffer.wait_until_scheduled(); + command_buffer.waitUntilScheduled(); texture.drawable.present(); } }); @@ -477,7 +489,7 @@ impl crate::Queue for Queue { #[derive(Debug)] pub struct Buffer { - raw: metal::Buffer, + raw: Retained>, size: wgt::BufferAddress, } @@ -487,8 +499,8 @@ unsafe impl Sync for Buffer {} impl crate::DynBuffer for Buffer {} impl Buffer { - fn as_raw(&self) -> BufferPtr { - unsafe { NonNull::new_unchecked(self.raw.as_ptr()) } + fn as_raw(&self) -> NonNull> { + unsafe { NonNull::new_unchecked(Retained::as_ptr(&self.raw) as *mut _) } } } @@ -503,9 +515,9 @@ impl crate::BufferBinding<'_, Buffer> { #[derive(Debug)] pub struct Texture { - raw: metal::Texture, + raw: Retained>, format: wgt::TextureFormat, - raw_type: metal::MTLTextureType, + raw_type: MTLTextureType, array_layers: u32, mip_levels: u32, copy_size: crate::CopyExtent, @@ -518,7 +530,7 @@ unsafe impl Sync for Texture {} #[derive(Debug)] pub struct TextureView { - raw: metal::Texture, + raw: Retained>, aspects: crate::FormatAspects, } @@ -528,14 +540,14 @@ unsafe impl Send for TextureView {} unsafe impl Sync for TextureView {} impl TextureView { - fn as_raw(&self) -> TexturePtr { - unsafe { NonNull::new_unchecked(self.raw.as_ptr()) } + fn as_raw(&self) -> NonNull> { + unsafe { NonNull::new_unchecked(Retained::as_ptr(&self.raw) as *mut _) } } } #[derive(Debug)] pub struct Sampler { - raw: metal::SamplerState, + raw: Retained>, } impl crate::DynSampler for Sampler {} @@ -544,8 +556,8 @@ unsafe impl Send for Sampler {} unsafe impl Sync for Sampler {} impl Sampler { - fn as_raw(&self) -> SamplerPtr { - unsafe { NonNull::new_unchecked(self.raw.as_ptr()) } + fn as_raw(&self) -> NonNull> { + unsafe { NonNull::new_unchecked(Retained::as_ptr(&self.raw) as *mut _) } } } @@ -640,55 +652,9 @@ pub struct PipelineLayout { impl crate::DynPipelineLayout for PipelineLayout {} -trait AsNative { - type Native; - fn from(native: &Self::Native) -> Self; - fn as_native(&self) -> &Self::Native; -} - -type BufferPtr = NonNull; -type TexturePtr = NonNull; -type SamplerPtr = NonNull; - -impl AsNative for BufferPtr { - type Native = metal::BufferRef; - #[inline] - fn from(native: &Self::Native) -> Self { - unsafe { NonNull::new_unchecked(native.as_ptr()) } - } - #[inline] - fn as_native(&self) -> &Self::Native { - unsafe { Self::Native::from_ptr(self.as_ptr()) } - } -} - -impl AsNative for TexturePtr { - type Native = metal::TextureRef; - #[inline] - fn from(native: &Self::Native) -> Self { - unsafe { NonNull::new_unchecked(native.as_ptr()) } - } - #[inline] - fn as_native(&self) -> &Self::Native { - unsafe { Self::Native::from_ptr(self.as_ptr()) } - } -} - -impl AsNative for SamplerPtr { - type Native = metal::SamplerStateRef; - #[inline] - fn from(native: &Self::Native) -> Self { - unsafe { NonNull::new_unchecked(native.as_ptr()) } - } - #[inline] - fn as_native(&self) -> &Self::Native { - unsafe { Self::Native::from_ptr(self.as_ptr()) } - } -} - #[derive(Debug)] struct BufferResource { - ptr: BufferPtr, + ptr: NonNull>, offset: wgt::BufferAddress, dynamic_index: Option, @@ -709,8 +675,8 @@ struct BufferResource { pub struct BindGroup { counters: MultiStageResourceCounters, buffers: Vec, - samplers: Vec, - textures: Vec, + samplers: Vec>>, + textures: Vec>>, } impl crate::DynBindGroup for BindGroup {} @@ -765,19 +731,22 @@ impl PipelineStageInfo { #[derive(Debug)] pub struct RenderPipeline { - raw: metal::RenderPipelineState, + raw: Retained>, #[allow(dead_code)] - vs_lib: metal::Library, + vs_lib: Retained>, #[allow(dead_code)] - fs_lib: Option, + fs_lib: Option>>, vs_info: PipelineStageInfo, fs_info: Option, - raw_primitive_type: metal::MTLPrimitiveType, - raw_triangle_fill_mode: metal::MTLTriangleFillMode, - raw_front_winding: metal::MTLWinding, - raw_cull_mode: metal::MTLCullMode, - raw_depth_clip_mode: Option, - depth_stencil: Option<(metal::DepthStencilState, wgt::DepthBiasState)>, + raw_primitive_type: MTLPrimitiveType, + raw_triangle_fill_mode: MTLTriangleFillMode, + raw_front_winding: MTLWinding, + raw_cull_mode: MTLCullMode, + raw_depth_clip_mode: Option, + depth_stencil: Option<( + Retained>, + wgt::DepthBiasState, + )>, } unsafe impl Send for RenderPipeline {} @@ -787,11 +756,11 @@ impl crate::DynRenderPipeline for RenderPipeline {} #[derive(Debug)] pub struct ComputePipeline { - raw: metal::ComputePipelineState, + raw: Retained>, #[allow(dead_code)] - cs_lib: metal::Library, + cs_lib: Retained>, cs_info: PipelineStageInfo, - work_group_size: metal::MTLSize, + work_group_size: MTLSize, work_group_memory_sizes: Vec, } @@ -802,9 +771,9 @@ impl crate::DynComputePipeline for ComputePipeline {} #[derive(Debug, Clone)] pub struct QuerySet { - raw_buffer: metal::Buffer, + raw_buffer: Retained>, //Metal has a custom buffer for counters. - counter_sample_buffer: Option, + counter_sample_buffer: Option>>, ty: wgt::QueryType, } @@ -817,7 +786,10 @@ unsafe impl Sync for QuerySet {} pub struct Fence { completed_value: Arc, /// The pending fence values have to be ascending. - pending_command_buffers: Vec<(crate::FenceValue, metal::CommandBuffer)>, + pending_command_buffers: Vec<( + crate::FenceValue, + Retained>, + )>, } impl crate::DynFence for Fence {} @@ -829,7 +801,7 @@ impl Fence { fn get_latest(&self) -> crate::FenceValue { let mut max_value = self.completed_value.load(atomic::Ordering::Acquire); for &(value, ref cmd_buf) in self.pending_command_buffers.iter() { - if cmd_buf.status() == metal::MTLCommandBufferStatus::Completed { + if cmd_buf.status() == MTLCommandBufferStatus::Completed { max_value = value; } } @@ -844,10 +816,10 @@ impl Fence { } struct IndexState { - buffer_ptr: BufferPtr, + buffer_ptr: NonNull>, offset: wgt::BufferAddress, stride: wgt::BufferAddress, - raw_type: metal::MTLIndexType, + raw_type: MTLIndexType, } #[derive(Default)] @@ -856,12 +828,12 @@ struct Temp { } struct CommandState { - blit: Option, - render: Option, - compute: Option, - raw_primitive_type: metal::MTLPrimitiveType, + blit: Option>>, + render: Option>>, + compute: Option>>, + raw_primitive_type: MTLPrimitiveType, index: Option, - raw_wg_size: metal::MTLSize, + raw_wg_size: MTLSize, stage_infos: MultiStageData, /// Sizes of currently bound [`wgt::BufferBindingType::Storage`] buffers. @@ -896,8 +868,8 @@ struct CommandState { pub struct CommandEncoder { shared: Arc, - raw_queue: Arc>, - raw_cmd_buf: Option, + raw_queue: Arc>>>, + raw_cmd_buf: Option>>, state: CommandState, temp: Temp, } @@ -916,7 +888,7 @@ unsafe impl Sync for CommandEncoder {} #[derive(Debug)] pub struct CommandBuffer { - raw: metal::CommandBuffer, + raw: Retained>, } impl crate::DynCommandBuffer for CommandBuffer {} diff --git a/wgpu-hal/src/metal/surface.rs b/wgpu-hal/src/metal/surface.rs index 668b602474..7aff84d4fd 100644 --- a/wgpu-hal/src/metal/surface.rs +++ b/wgpu-hal/src/metal/surface.rs @@ -1,69 +1,61 @@ #![allow(clippy::let_unit_value)] // `let () =` being used to constrain result type -use std::ffi::c_uint; -use std::mem::ManuallyDrop; use std::ptr::NonNull; use std::sync::Once; use std::thread; -use core_graphics_types::{ - base::CGFloat, - geometry::{CGRect, CGSize}, -}; -use metal::foreign_types::ForeignType; -use objc::{ +use objc2::{ class, - declare::ClassDecl, - msg_send, - rc::{autoreleasepool, StrongPtr}, - runtime::{Class, Object, Sel, BOOL, NO, YES}, - sel, sel_impl, + declare::ClassBuilder, + msg_send, msg_send_id, + rc::{autoreleasepool, Retained}, + runtime::{AnyClass, AnyObject, Bool, ProtocolObject, Sel}, + sel, ClassType, +}; +use objc2_foundation::{CGFloat, CGSize, MainThreadMarker, NSObject, NSObjectProtocol}; +use objc2_metal::MTLTextureType; +use objc2_quartz_core::{ + kCAGravityResize, CAAutoresizingMask, CALayer, CAMetalDrawable, CAMetalLayer, }; use parking_lot::{Mutex, RwLock}; -#[link(name = "QuartzCore", kind = "framework")] -extern "C" { - #[allow(non_upper_case_globals)] - static kCAGravityResize: *mut Object; -} - extern "C" fn layer_should_inherit_contents_scale_from_window( - _: &Class, + _: &AnyClass, _: Sel, - _layer: *mut Object, + _layer: *mut AnyObject, _new_scale: CGFloat, - _from_window: *mut Object, -) -> BOOL { - YES + _from_window: *mut AnyObject, +) -> Bool { + Bool::YES } static CAML_DELEGATE_REGISTER: Once = Once::new(); #[derive(Debug)] -pub struct HalManagedMetalLayerDelegate(&'static Class); +pub struct HalManagedMetalLayerDelegate(&'static AnyClass); impl HalManagedMetalLayerDelegate { pub fn new() -> Self { let class_name = format!("HalManagedMetalLayerDelegate@{:p}", &CAML_DELEGATE_REGISTER); CAML_DELEGATE_REGISTER.call_once(|| { - type Fun = extern "C" fn(&Class, Sel, *mut Object, CGFloat, *mut Object) -> BOOL; - let mut decl = ClassDecl::new(&class_name, class!(NSObject)).unwrap(); + let mut decl = ClassBuilder::new(&class_name, class!(NSObject)).unwrap(); + #[allow(trivial_casts)] // false positive unsafe { // - decl.add_class_method::( + decl.add_class_method:: _>( sel!(layer:shouldInheritContentsScale:fromWindow:), layer_should_inherit_contents_scale_from_window, ); } decl.register(); }); - Self(Class::get(&class_name).unwrap()) + Self(AnyClass::get(&class_name).unwrap()) } } impl super::Surface { - fn new(layer: metal::MetalLayer) -> Self { + fn new(layer: Retained) -> Self { Self { render_layer: Mutex::new(layer), swapchain_format: RwLock::new(None), @@ -74,21 +66,14 @@ impl super::Surface { } /// If not called on the main thread, this will panic. - #[allow(clippy::transmute_ptr_to_ref)] - pub unsafe fn from_view(view: NonNull) -> Self { + pub unsafe fn from_view(view: NonNull) -> Self { let layer = unsafe { Self::get_metal_layer(view) }; - let layer = ManuallyDrop::new(layer); - // SAFETY: The layer is an initialized instance of `CAMetalLayer`, and - // we transfer the retain count to `MetalLayer` using `ManuallyDrop`. - let layer = unsafe { metal::MetalLayer::from_ptr(layer.cast()) }; Self::new(layer) } - pub unsafe fn from_layer(layer: &metal::MetalLayerRef) -> Self { - let class = class!(CAMetalLayer); - let proper_kind: BOOL = msg_send![layer, isKindOfClass: class]; - assert_eq!(proper_kind, YES); - Self::new(layer.to_owned()) + pub unsafe fn from_layer(layer: &CAMetalLayer) -> Self { + assert!(layer.isKindOfClass(CAMetalLayer::class())); + Self::new(layer.retain()) } /// Get or create a new `CAMetalLayer` associated with the given `NSView` @@ -101,21 +86,20 @@ impl super::Surface { /// # Safety /// /// The `view` must be a valid instance of `NSView` or `UIView`. - pub(crate) unsafe fn get_metal_layer(view: NonNull) -> StrongPtr { - let is_main_thread: BOOL = msg_send![class!(NSThread), isMainThread]; - if is_main_thread == NO { + pub(crate) unsafe fn get_metal_layer(view: NonNull) -> Retained { + let Some(_mtm) = MainThreadMarker::new() else { panic!("get_metal_layer cannot be called in non-ui thread."); - } + }; // Ensure that the view is layer-backed. // Views are always layer-backed in UIKit. #[cfg(target_os = "macos")] - let () = msg_send![view.as_ptr(), setWantsLayer: YES]; + let () = msg_send![view.as_ptr(), setWantsLayer: true]; - let root_layer: *mut Object = msg_send![view.as_ptr(), layer]; + let root_layer: Option> = msg_send_id![view.as_ptr(), layer]; // `-[NSView layer]` can return `NULL`, while `-[UIView layer]` should // always be available. - assert!(!root_layer.is_null(), "failed making the view layer-backed"); + let root_layer = root_layer.expect("failed making the view layer-backed"); // NOTE: We explicitly do not touch properties such as // `layerContentsPlacement`, `needsDisplayOnBoundsChange` and @@ -125,8 +109,7 @@ impl super::Surface { // `NSViewLayerContentsRedrawDuringViewResize`, which allows the view // to receive `drawRect:`/`updateLayer` calls). - let is_metal_layer: BOOL = msg_send![root_layer, isKindOfClass: class!(CAMetalLayer)]; - if is_metal_layer == YES { + if root_layer.isKindOfClass(CAMetalLayer::class()) { // The view has a `CAMetalLayer` as the root layer, which can // happen for example if user overwrote `-[NSView layerClass]` or // the view is `MTKView`. @@ -135,7 +118,7 @@ impl super::Surface { // render directly into that; after all, the user passed a view // with an explicit Metal layer to us, so this is very likely what // they expect us to do. - unsafe { StrongPtr::retain(root_layer) } + unsafe { Retained::cast(root_layer) } } else { // The view does not have a `CAMetalLayer` as the root layer (this // is the default for most views). @@ -204,8 +187,8 @@ impl super::Surface { // we're going to do. // Create a new sublayer. - let new_layer: *mut Object = msg_send![class!(CAMetalLayer), new]; - let () = msg_send![root_layer, addSublayer: new_layer]; + let new_layer = CAMetalLayer::new(); + root_layer.addSublayer(&new_layer); // Automatically resize the sublayer's frame to match the // superlayer's bounds. @@ -220,15 +203,15 @@ impl super::Surface { // We _could_ also let `configure` set the `bounds` size, however // that would be inconsistent with using the root layer directly // (as we may do, see above). - let width_sizable = 1 << 1; // kCALayerWidthSizable - let height_sizable = 1 << 4; // kCALayerHeightSizable - let mask: c_uint = width_sizable | height_sizable; - let () = msg_send![new_layer, setAutoresizingMask: mask]; + new_layer.setAutoresizingMask( + CAAutoresizingMask::kCALayerWidthSizable + | CAAutoresizingMask::kCALayerHeightSizable, + ); // Specify the relative size that the auto resizing mask above // will keep (i.e. tell it to fill out its superlayer). - let frame: CGRect = msg_send![root_layer, bounds]; - let () = msg_send![new_layer, setFrame: frame]; + let frame = root_layer.bounds(); + new_layer.setFrame(frame); // The gravity to use when the layer's `drawableSize` isn't the // same as the bounds rectangle. @@ -241,26 +224,25 @@ impl super::Surface { // Unfortunately, it also makes it harder to see changes to // `width` and `height` in `configure`. When debugging resize // issues, swap this for `kCAGravityTopLeft` instead. - let _: () = msg_send![new_layer, setContentsGravity: unsafe { kCAGravityResize }]; + new_layer.setContentsGravity(unsafe { kCAGravityResize }); // Set initial scale factor of the layer. This is kept in sync by // `configure` (on UIKit), and the delegate below (on AppKit). - let scale_factor: CGFloat = msg_send![root_layer, contentsScale]; - let () = msg_send![new_layer, setContentsScale: scale_factor]; + let scale_factor = root_layer.contentsScale(); + new_layer.setContentsScale(scale_factor); let delegate = HalManagedMetalLayerDelegate::new(); - let () = msg_send![new_layer, setDelegate: delegate.0]; + new_layer.setDelegate(std::mem::transmute(delegate.0)); - unsafe { StrongPtr::new(new_layer) } + new_layer } } pub(super) fn dimensions(&self) -> wgt::Extent3d { - let (size, scale): (CGSize, CGFloat) = unsafe { - let render_layer_borrow = self.render_layer.lock(); - let render_layer = render_layer_borrow.as_ref(); - let bounds: CGRect = msg_send![render_layer, bounds]; - let contents_scale: CGFloat = msg_send![render_layer, contentsScale]; + let (size, scale): (CGSize, CGFloat) = { + let render_layer = self.render_layer.lock(); + let bounds = render_layer.bounds(); + let contents_scale = render_layer.contentsScale(); (bounds.size, contents_scale) }; @@ -296,8 +278,8 @@ impl crate::Surface for super::Surface { let drawable_size = CGSize::new(config.extent.width as f64, config.extent.height as f64); match config.composite_alpha_mode { - wgt::CompositeAlphaMode::Opaque => render_layer.set_opaque(true), - wgt::CompositeAlphaMode::PostMultiplied => render_layer.set_opaque(false), + wgt::CompositeAlphaMode::Opaque => render_layer.setOpaque(true), + wgt::CompositeAlphaMode::PostMultiplied => render_layer.setOpaque(false), _ => (), } @@ -317,33 +299,32 @@ impl crate::Surface for super::Surface { // TODO: Is there a way that we could listen to such changes instead? #[cfg(not(target_os = "macos"))] { - let superlayer: *mut Object = msg_send![render_layer.as_ptr(), superlayer]; - if !superlayer.is_null() { - let scale_factor: CGFloat = msg_send![superlayer, contentsScale]; - let () = msg_send![render_layer.as_ptr(), setContentsScale: scale_factor]; + if let Some(superlayer) = render_layer.superlayer() { + let scale_factor = superlayer.contentsScale(); + render_layer.setContentsScale(scale_factor); } } let device_raw = device.shared.device.lock(); - render_layer.set_device(&device_raw); - render_layer.set_pixel_format(caps.map_format(config.format)); - render_layer.set_framebuffer_only(framebuffer_only); - render_layer.set_presents_with_transaction(self.present_with_transaction); + render_layer.setDevice(Some(&device_raw)); + render_layer.setPixelFormat(caps.map_format(config.format)); + render_layer.setFramebufferOnly(framebuffer_only); + render_layer.setPresentsWithTransaction(self.present_with_transaction); // opt-in to Metal EDR // EDR potentially more power used in display and more bandwidth, memory footprint. let wants_edr = config.format == wgt::TextureFormat::Rgba16Float; - if wants_edr != render_layer.wants_extended_dynamic_range_content() { - render_layer.set_wants_extended_dynamic_range_content(wants_edr); + if wants_edr != render_layer.wantsExtendedDynamicRangeContent() { + render_layer.setWantsExtendedDynamicRangeContent(wants_edr); } // this gets ignored on iOS for certain OS/device combinations (iphone5s iOS 10.3) - render_layer.set_maximum_drawable_count(config.maximum_frame_latency as u64 + 1); - render_layer.set_drawable_size(drawable_size); + render_layer.setMaximumDrawableCount(config.maximum_frame_latency as usize + 1); + render_layer.setDrawableSize(drawable_size); if caps.can_set_next_drawable_timeout { - let () = msg_send![*render_layer, setAllowsNextDrawableTimeout:false]; + render_layer.setAllowsNextDrawableTimeout(false); } if caps.can_set_display_sync { - let () = msg_send![*render_layer, setDisplaySyncEnabled: display_sync]; + render_layer.setDisplaySyncEnabled(display_sync); } Ok(()) @@ -359,9 +340,9 @@ impl crate::Surface for super::Surface { _fence: &super::Fence, ) -> Result>, crate::SurfaceError> { let render_layer = self.render_layer.lock(); - let (drawable, texture) = match autoreleasepool(|| { + let (drawable, texture) = match autoreleasepool(|_| { render_layer - .next_drawable() + .nextDrawable() .map(|drawable| (drawable.to_owned(), drawable.texture().to_owned())) }) { Some(pair) => pair, @@ -374,7 +355,7 @@ impl crate::Surface for super::Surface { texture: super::Texture { raw: texture, format: swapchain_format, - raw_type: metal::MTLTextureType::D2, + raw_type: MTLTextureType::MTLTextureType2D, array_layers: 1, mip_levels: 1, copy_size: crate::CopyExtent { @@ -383,7 +364,7 @@ impl crate::Surface for super::Surface { depth: 1, }, }, - drawable, + drawable: ProtocolObject::from_retained(drawable), present_with_transaction: self.present_with_transaction, }; diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 6d56ecf964..02f48aea90 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -525,7 +525,7 @@ impl super::Instance { let layer = unsafe { crate::metal::Surface::get_metal_layer(view.cast()) }; // NOTE: The layer is retained by Vulkan's `vkCreateMetalSurfaceEXT`, // so no need to retain it beyond the scope of this function. - let layer_ptr = (*layer).cast(); + let layer_ptr = objc2::rc::Retained::as_ptr(&layer).cast(); let surface = { let metal_loader =