From ea8fa57526e774b741a02459e53d85d3994d071b Mon Sep 17 00:00:00 2001 From: Abel Lucas Date: Thu, 28 Aug 2025 23:19:36 +0200 Subject: [PATCH] [metal] MTLDevice is thread-safe --- wgpu-hal/src/metal/adapter.rs | 5 ++--- wgpu-hal/src/metal/device.rs | 33 ++++++++++++--------------------- wgpu-hal/src/metal/mod.rs | 4 ++-- wgpu-hal/src/metal/surface.rs | 2 +- 4 files changed, 17 insertions(+), 27 deletions(-) diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 47ffbd3c6c1..a6b900f7c8d 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -50,7 +50,6 @@ impl crate::Adapter for super::Adapter { let queue = self .shared .device - .lock() .new_command_queue_with_max_command_buffer_count(MAX_COMMAND_BUFFERS); // Acquiring the meaning of timestamp ticks is hard with Metal! @@ -72,7 +71,7 @@ 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.name().starts_with("Intel") { 83.333 } else { // Known for Apple Silicon (at least M1 & M2, iPad Pro 2018) and AMD GPUs. @@ -121,7 +120,7 @@ impl crate::Adapter for super::Adapter { Tfc::empty() }; let is_not_apple1x = super::PrivateCapabilities::supports_any( - self.shared.device.lock().as_ref(), + self.shared.device.as_ref(), &[ MTLFeatureSet::iOS_GPUFamily2_v1, MTLFeatureSet::macOS_GPUFamily1_v1, diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index dd5d05b6d50..2a3b6c82a07 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -2,8 +2,6 @@ use alloc::{borrow::ToOwned as _, sync::Arc, vec::Vec}; use core::{ptr::NonNull, sync::atomic}; use std::{thread, time}; -use parking_lot::Mutex; - use super::{conv, PassthroughShader}; use crate::auxil::map_naga_stage; use crate::metal::ShaderModuleSource; @@ -215,7 +213,6 @@ impl super::Device { let library = self .shared .device - .lock() .new_library_with_source(source.as_ref(), &options) .map_err(|err| { log::warn!("Naga generated shader:\n{source}"); @@ -362,7 +359,7 @@ impl super::Device { super::Buffer { raw, size } } - pub fn raw_device(&self) -> &Mutex { + pub fn raw_device(&self) -> &metal::Device { &self.shared.device } } @@ -386,7 +383,7 @@ impl crate::Device for super::Device { //TODO: HazardTrackingModeUntracked objc::rc::autoreleasepool(|| { - let raw = self.shared.device.lock().new_buffer(desc.size, options); + let raw = self.shared.device.new_buffer(desc.size, options); if let Some(label) = desc.label { raw.set_label(label); } @@ -460,7 +457,7 @@ impl crate::Device for super::Device { descriptor.set_usage(conv::map_texture_usage(desc.format, desc.usage)); descriptor.set_storage_mode(MTLStorageMode::Private); - let raw = self.shared.device.lock().new_texture(&descriptor); + let raw = self.shared.device.new_texture(&descriptor); if raw.as_ptr().is_null() { return Err(crate::DeviceError::OutOfMemory); } @@ -612,7 +609,7 @@ impl crate::Device for super::Device { if self.features.contains(wgt::Features::TEXTURE_BINDING_ARRAY) { descriptor.set_support_argument_buffers(true); } - let raw = self.shared.device.lock().new_sampler(&descriptor); + let raw = self.shared.device.new_sampler(&descriptor); self.counters.samplers.add(1); @@ -883,7 +880,7 @@ impl crate::Device for super::Device { let uses = conv::map_resource_usage(&layout.ty); // Create argument buffer for this array - let buffer = self.shared.device.lock().new_buffer( + let buffer = self.shared.device.new_buffer( 8 * count as u64, MTLResourceOptions::HazardTrackingModeUntracked | MTLResourceOptions::StorageModeShared, @@ -1065,8 +1062,8 @@ impl crate::Device for super::Device { num_workgroups, } => { let options = metal::CompileOptions::new(); - // Obtain the locked device from shared - let device = self.shared.device.lock(); + // Obtain the device from shared + let device = &self.shared.device; let library = device .new_library_with_source(source, &options) .map_err(|e| crate::ShaderError::Compilation(format!("MSL: {e:?}")))?; @@ -1263,11 +1260,7 @@ impl crate::Device for super::Device { } let ds_descriptor = create_depth_stencil_desc(ds); - let raw = self - .shared - .device - .lock() - .new_depth_stencil_state(&ds_descriptor); + let raw = self.shared.device.new_depth_stencil_state(&ds_descriptor); Some((raw, ds.bias)) } None => None, @@ -1340,7 +1333,6 @@ impl crate::Device for super::Device { let raw = self .shared .device - .lock() .new_render_pipeline_state(&descriptor) .map_err(|e| { crate::PipelineError::Linkage( @@ -1437,7 +1429,6 @@ impl crate::Device for super::Device { let raw = self .shared .device - .lock() .new_compute_pipeline_state(&descriptor) .map_err(|e| { crate::PipelineError::Linkage( @@ -1480,7 +1471,7 @@ impl crate::Device for super::Device { let size = desc.count as u64 * crate::QUERY_SIZE; let options = MTLResourceOptions::empty(); //TODO: HazardTrackingModeUntracked - let raw_buffer = self.shared.device.lock().new_buffer(size, options); + let raw_buffer = self.shared.device.new_buffer(size, options); if let Some(label) = desc.label { raw_buffer.set_label(label); } @@ -1492,7 +1483,7 @@ 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 device = &self.shared.device; let destination_buffer = device.new_buffer(size, MTLResourceOptions::empty()); let csb_desc = metal::CounterSampleBufferDescriptor::new(); @@ -1544,7 +1535,7 @@ impl crate::Device for super::Device { unsafe fn create_fence(&self) -> DeviceResult { self.counters.fences.add(1); let shared_event = if self.shared.private_caps.supports_shared_event { - Some(self.shared.device.lock().new_shared_event()) + Some(self.shared.device.new_shared_event()) } else { None }; @@ -1606,7 +1597,7 @@ impl crate::Device for super::Device { if !self.shared.private_caps.supports_capture_manager { return false; } - let device = self.shared.device.lock(); + let device = &self.shared.device; 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); diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index 00223b2f778..ea1541e2009 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -325,7 +325,7 @@ impl Default for Settings { } struct AdapterShared { - device: Mutex, + device: metal::Device, disabilities: PrivateDisabilities, private_caps: PrivateCapabilities, settings: Settings, @@ -343,7 +343,7 @@ impl AdapterShared { Self { disabilities: PrivateDisabilities::new(&device), private_caps, - device: Mutex::new(device), + device, settings: Settings::default(), presentation_timer: time::PresentationTimer::new(), } diff --git a/wgpu-hal/src/metal/surface.rs b/wgpu-hal/src/metal/surface.rs index 2a705cd7901..07fc37900d5 100644 --- a/wgpu-hal/src/metal/surface.rs +++ b/wgpu-hal/src/metal/surface.rs @@ -160,7 +160,7 @@ impl crate::Surface for super::Surface { _ => (), } - let device_raw = device.shared.device.lock(); + let device_raw = &device.shared.device; render_layer.set_device(&device_raw); render_layer.set_pixel_format(caps.map_format(config.format)); render_layer.set_framebuffer_only(framebuffer_only);