From 4baf0b9a3314708e8df11d53360c7d046a9247cf Mon Sep 17 00:00:00 2001 From: Matt Hargett Date: Thu, 9 Apr 2026 23:02:18 -0700 Subject: [PATCH 1/3] [metal] Use Shared texture storage mode on arm64_32 (watchOS) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AGXMetalS4 driver (A13/S6 GPU, used in Apple Watch Series 6-9 and SE2) crashes with KERN_INVALID_ADDRESS at offset 0x50 during copyFromTexture:toBuffer: on MTLStorageMode::Private textures when called via objc_msgSend on the ILP32 (arm64_32) ABI. The native Swift Metal implementation that works on the same hardware uses MTLStorageMode::Shared for render textures. Apple's unified memory architecture makes Shared equally performant for GPU access while enabling the blit DMA path that the driver expects on ILP32. This change is gated behind cfg!(target_pointer_width = "32") and has zero effect on 64-bit platforms. Tested on: - Apple Watch SE2 (arm64_32, S6/A13, watchOS 11.6) - Apple Watch Series 10 (arm64, S9/A15, watchOS 26.4) — no regression --- wgpu-hal/src/metal/device.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 02ef3bffa35..3013441e544 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -521,6 +521,14 @@ impl crate::Device for super::Device { && self.shared.private_caps.supports_memoryless_storage { MTLStorageMode::Memoryless + } else if cfg!(target_pointer_width = "32") { + // On arm64_32 (watchOS ILP32), the AGXMetalS4 driver (A13/S6 GPU) + // crashes in copyFromTexture:toBuffer: on Private textures — null + // deref at offset 0x50 in the driver's internal texture state. Use + // Shared storage which works correctly on Apple's unified memory + // architecture and matches what native Swift Metal code uses on + // these devices. + MTLStorageMode::Shared } else { MTLStorageMode::Private }; From 1e66cdb4f23a71c06faddba5c94c5a347b26a96a Mon Sep 17 00:00:00 2001 From: Matt Hargett Date: Thu, 9 Apr 2026 23:02:53 -0700 Subject: [PATCH 2/3] [metal] Disable buffer mutability hints on arm64_32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the Shared texture storage mode fix, the AGXMetalS4 driver (A13/S6 GPU on watchOS arm64_32) still exhibits instability when MTLMutability hints are set on pipeline buffer descriptors. Conservatively disable supports_mutability on 32-bit targets. Can be re-enabled per-device once broader watchOS test coverage confirms stability. Gated behind cfg!(target_pointer_width = "32") — no effect on 64-bit platforms. --- wgpu-hal/src/metal/device.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 3013441e544..234b9cee9f0 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -1280,8 +1280,11 @@ impl crate::Device for super::Device { } // https://developer.apple.com/documentation/metal/mtlpipelinebufferdescriptor/mutability - let supports_mutability = - available!(macos = 10.13, ios = 11.0, tvos = 11.0, visionos = 1.0); + // Disabled on arm64_32 (watchOS ILP32): the AGXMetalS4 driver exhibits + // instability when mutability hints are combined with Shared storage + // mode textures. Conservative disable until broader device coverage. + let supports_mutability = !cfg!(target_pointer_width = "32") + && available!(macos = 10.13, ios = 11.0, tvos = 11.0, visionos = 1.0); let (primitive_class, raw_primitive_type) = conv::map_primitive_topology(desc.primitive.topology); From 20edfc116efae85e74d0dc0342712e228d6c1a56 Mon Sep 17 00:00:00 2001 From: Matt Hargett Date: Fri, 10 Apr 2026 17:32:37 -0700 Subject: [PATCH 3/3] [metal] Fix CGFloat type for ILP32 (arm64_32) CGFloat is f64 on LP64 but f32 on ILP32 (arm64_32, used by watchOS). CGSize::new() expects CGFloat, so use `as _` to let the compiler infer the correct type instead of hardcoding `as f64`. --- wgpu-hal/src/metal/surface.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wgpu-hal/src/metal/surface.rs b/wgpu-hal/src/metal/surface.rs index e08ac591e6e..1b08c53d4e5 100644 --- a/wgpu-hal/src/metal/surface.rs +++ b/wgpu-hal/src/metal/surface.rs @@ -76,7 +76,8 @@ impl crate::Surface for super::Surface { wgt::PresentMode::Immediate => false, m => unreachable!("Unsupported present mode: {m:?}"), }; - let drawable_size = CGSize::new(config.extent.width as f64, config.extent.height as f64); + // CGFloat is f64 on 64-bit, f32 on 32-bit (arm64_32/ILP32) + let drawable_size = CGSize::new(config.extent.width as _, config.extent.height as _); match config.composite_alpha_mode { wgt::CompositeAlphaMode::Opaque => render_layer.setOpaque(true),