summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wgpu-core/src/device
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/wgpu-core/src/device')
-rw-r--r--third_party/rust/wgpu-core/src/device/global.rs33
-rw-r--r--third_party/rust/wgpu-core/src/device/life.rs15
-rw-r--r--third_party/rust/wgpu-core/src/device/mod.rs11
-rw-r--r--third_party/rust/wgpu-core/src/device/queue.rs17
-rw-r--r--third_party/rust/wgpu-core/src/device/resource.rs20
5 files changed, 74 insertions, 22 deletions
diff --git a/third_party/rust/wgpu-core/src/device/global.rs b/third_party/rust/wgpu-core/src/device/global.rs
index 539b92e0f3..0c97e1b504 100644
--- a/third_party/rust/wgpu-core/src/device/global.rs
+++ b/third_party/rust/wgpu-core/src/device/global.rs
@@ -192,7 +192,15 @@ impl Global {
let ptr = if map_size == 0 {
std::ptr::NonNull::dangling()
} else {
- match map_buffer(device.raw(), &buffer, 0, map_size, HostMap::Write) {
+ let snatch_guard = device.snatchable_lock.read();
+ match map_buffer(
+ device.raw(),
+ &buffer,
+ 0,
+ map_size,
+ HostMap::Write,
+ &snatch_guard,
+ ) {
Ok(ptr) => ptr,
Err(e) => {
to_destroy.push(buffer);
@@ -2008,9 +2016,10 @@ impl Global {
}
// Wait for all work to finish before configuring the surface.
+ let snatch_guard = device.snatchable_lock.read();
let fence = device.fence.read();
let fence = fence.as_ref().unwrap();
- match device.maintain(fence, wgt::Maintain::Wait) {
+ match device.maintain(fence, wgt::Maintain::Wait, snatch_guard) {
Ok((closures, _)) => {
user_callbacks = closures;
}
@@ -2120,9 +2129,10 @@ impl Global {
device: &crate::device::Device<A>,
maintain: wgt::Maintain<queue::WrappedSubmissionIndex>,
) -> Result<DevicePoll, WaitIdleError> {
+ let snatch_guard = device.snatchable_lock.read();
let fence = device.fence.read();
let fence = fence.as_ref().unwrap();
- let (closures, queue_empty) = device.maintain(fence, maintain)?;
+ let (closures, queue_empty) = device.maintain(fence, maintain, snatch_guard)?;
// Some deferred destroys are scheduled in maintain so run this right after
// to avoid holding on to them until the next device poll.
@@ -2240,6 +2250,15 @@ impl Global {
}
}
+ // This is a test-only function to force the device into an
+ // invalid state by inserting an error value in its place in
+ // the registry.
+ pub fn device_make_invalid<A: HalApi>(&self, device_id: DeviceId) {
+ let hub = A::hub(self);
+ hub.devices
+ .force_replace_with_error(device_id, "Made invalid.");
+ }
+
pub fn device_drop<A: HalApi>(&self, device_id: DeviceId) {
profiling::scope!("Device::drop");
api_log!("Device::drop {device_id:?}");
@@ -2275,7 +2294,7 @@ impl Global {
) {
let hub = A::hub(self);
- if let Ok(device) = hub.devices.get(device_id) {
+ if let Ok(Some(device)) = hub.devices.try_get(device_id) {
let mut life_tracker = device.lock_life();
if let Some(existing_closure) = life_tracker.device_lost_closure.take() {
// It's important to not hold the lock while calling the closure.
@@ -2284,6 +2303,12 @@ impl Global {
life_tracker = device.lock_life();
}
life_tracker.device_lost_closure = Some(device_lost_closure);
+ } else {
+ // No device? Okay. Just like we have to call any existing closure
+ // before we drop it, we need to call this closure before we exit
+ // this function, because there's no device that is ever going to
+ // call it.
+ device_lost_closure.call(DeviceLostReason::DeviceInvalid, "".to_string());
}
}
diff --git a/third_party/rust/wgpu-core/src/device/life.rs b/third_party/rust/wgpu-core/src/device/life.rs
index 7b06a4a30b..af345015df 100644
--- a/third_party/rust/wgpu-core/src/device/life.rs
+++ b/third_party/rust/wgpu-core/src/device/life.rs
@@ -12,6 +12,7 @@ use crate::{
self, Buffer, DestroyedBuffer, DestroyedTexture, QuerySet, Resource, Sampler,
StagingBuffer, Texture, TextureView,
},
+ snatch::SnatchGuard,
track::{ResourceTracker, Tracker, TrackerIndex},
FastHashMap, SubmissionIndex,
};
@@ -309,12 +310,12 @@ impl<A: HalApi> LifetimeTracker<A> {
}
pub fn post_submit(&mut self) {
- for v in self.future_suspected_buffers.drain(..).take(1) {
+ for v in self.future_suspected_buffers.drain(..) {
self.suspected_resources
.buffers
.insert(v.as_info().tracker_index(), v);
}
- for v in self.future_suspected_textures.drain(..).take(1) {
+ for v in self.future_suspected_textures.drain(..) {
self.suspected_resources
.textures
.insert(v.as_info().tracker_index(), v);
@@ -780,6 +781,7 @@ impl<A: HalApi> LifetimeTracker<A> {
&mut self,
raw: &A::Device,
trackers: &Mutex<Tracker<A>>,
+ snatch_guard: &SnatchGuard,
) -> Vec<super::BufferMapPendingClosure> {
if self.ready_to_map.is_empty() {
return Vec::new();
@@ -816,7 +818,14 @@ impl<A: HalApi> LifetimeTracker<A> {
log::debug!("Buffer {tracker_index:?} map state -> Active");
let host = mapping.op.host;
let size = mapping.range.end - mapping.range.start;
- match super::map_buffer(raw, &buffer, mapping.range.start, size, host) {
+ match super::map_buffer(
+ raw,
+ &buffer,
+ mapping.range.start,
+ size,
+ host,
+ snatch_guard,
+ ) {
Ok(ptr) => {
*buffer.map_state.lock() = resource::BufferMapState::Active {
ptr,
diff --git a/third_party/rust/wgpu-core/src/device/mod.rs b/third_party/rust/wgpu-core/src/device/mod.rs
index 7ecda830a3..e2ab6c2690 100644
--- a/third_party/rust/wgpu-core/src/device/mod.rs
+++ b/third_party/rust/wgpu-core/src/device/mod.rs
@@ -3,9 +3,10 @@ use crate::{
hal_api::HalApi,
hub::Hub,
id::{BindGroupLayoutId, PipelineLayoutId},
- resource::{Buffer, BufferAccessResult},
- resource::{BufferAccessError, BufferMapOperation},
- resource_log, Label, DOWNLEVEL_ERROR_MESSAGE,
+ resource::{Buffer, BufferAccessError, BufferAccessResult, BufferMapOperation},
+ resource_log,
+ snatch::SnatchGuard,
+ Label, DOWNLEVEL_ERROR_MESSAGE,
};
use arrayvec::ArrayVec;
@@ -317,10 +318,10 @@ fn map_buffer<A: HalApi>(
offset: BufferAddress,
size: BufferAddress,
kind: HostMap,
+ snatch_guard: &SnatchGuard,
) -> Result<ptr::NonNull<u8>, BufferAccessError> {
- let snatch_guard = buffer.device.snatchable_lock.read();
let raw_buffer = buffer
- .raw(&snatch_guard)
+ .raw(snatch_guard)
.ok_or(BufferAccessError::Destroyed)?;
let mapping = unsafe {
raw.map_buffer(raw_buffer, offset..offset + size)
diff --git a/third_party/rust/wgpu-core/src/device/queue.rs b/third_party/rust/wgpu-core/src/device/queue.rs
index 6ebb9eb09b..3cb5f695a7 100644
--- a/third_party/rust/wgpu-core/src/device/queue.rs
+++ b/third_party/rust/wgpu-core/src/device/queue.rs
@@ -815,6 +815,7 @@ impl Global {
&mut trackers.textures,
&device.alignments,
device.zero_buffer.as_ref().unwrap(),
+ &device.snatchable_lock.read(),
)
.map_err(QueueWriteError::from)?;
}
@@ -1084,6 +1085,7 @@ impl Global {
&mut trackers.textures,
&device.alignments,
device.zero_buffer.as_ref().unwrap(),
+ &device.snatchable_lock.read(),
)
.map_err(QueueWriteError::from)?;
}
@@ -1147,6 +1149,9 @@ impl Global {
let device = queue.device.as_ref().unwrap();
+ let snatch_guard = device.snatchable_lock.read();
+
+ // Fence lock must be acquired after the snatch lock everywhere to avoid deadlocks.
let mut fence = device.fence.write();
let fence = fence.as_mut().unwrap();
let submit_index = device
@@ -1155,9 +1160,7 @@ impl Global {
+ 1;
let mut active_executions = Vec::new();
- let mut used_surface_textures = track::TextureUsageScope::new();
-
- let snatch_guard = device.snatchable_lock.read();
+ let mut used_surface_textures = track::TextureUsageScope::default();
let mut submit_surface_textures_owned = SmallVec::<[_; 2]>::new();
@@ -1391,10 +1394,10 @@ impl Global {
//Note: locking the trackers has to be done after the storages
let mut trackers = device.trackers.lock();
baked
- .initialize_buffer_memory(&mut *trackers)
+ .initialize_buffer_memory(&mut *trackers, &snatch_guard)
.map_err(|err| QueueSubmitError::DestroyedBuffer(err.0))?;
baked
- .initialize_texture_memory(&mut *trackers, device)
+ .initialize_texture_memory(&mut *trackers, device, &snatch_guard)
.map_err(|err| QueueSubmitError::DestroyedTexture(err.0))?;
//Note: stateless trackers are not merged:
// device already knows these resources exist.
@@ -1435,7 +1438,7 @@ impl Global {
baked.encoder.end_encoding().unwrap()
};
baked.list.push(present);
- used_surface_textures = track::TextureUsageScope::new();
+ used_surface_textures = track::TextureUsageScope::default();
}
// done
@@ -1542,7 +1545,7 @@ impl Global {
// This will schedule destruction of all resources that are no longer needed
// by the user but used in the command stream, among other things.
- let (closures, _) = match device.maintain(fence, wgt::Maintain::Poll) {
+ let (closures, _) = match device.maintain(fence, wgt::Maintain::Poll, snatch_guard) {
Ok(closures) => closures,
Err(WaitIdleError::Device(err)) => return Err(QueueSubmitError::Queue(err)),
Err(WaitIdleError::StuckGpu) => return Err(QueueSubmitError::StuckGpu),
diff --git a/third_party/rust/wgpu-core/src/device/resource.rs b/third_party/rust/wgpu-core/src/device/resource.rs
index 28ba0eafb1..4892aecb75 100644
--- a/third_party/rust/wgpu-core/src/device/resource.rs
+++ b/third_party/rust/wgpu-core/src/device/resource.rs
@@ -28,7 +28,10 @@ use crate::{
resource_log,
snatch::{SnatchGuard, SnatchLock, Snatchable},
storage::Storage,
- track::{BindGroupStates, TextureSelector, Tracker, TrackerIndexAllocators},
+ track::{
+ BindGroupStates, TextureSelector, Tracker, TrackerIndexAllocators, UsageScope,
+ UsageScopePool,
+ },
validation::{
self, check_buffer_usage, check_texture_usage, validate_color_attachment_bytes_per_sample,
},
@@ -97,6 +100,8 @@ pub struct Device<A: HalApi> {
pub(crate) command_allocator: Mutex<Option<CommandAllocator<A>>>,
//Note: The submission index here corresponds to the last submission that is done.
pub(crate) active_submission_index: AtomicU64, //SubmissionIndex,
+ // NOTE: if both are needed, the `snatchable_lock` must be consistently acquired before the
+ // `fence` lock to avoid deadlocks.
pub(crate) fence: RwLock<Option<A::Fence>>,
pub(crate) snatchable_lock: SnatchLock,
@@ -135,6 +140,7 @@ pub struct Device<A: HalApi> {
pub(crate) deferred_destroy: Mutex<Vec<DeferredDestroy<A>>>,
#[cfg(feature = "trace")]
pub(crate) trace: Mutex<Option<trace::Trace>>,
+ pub(crate) usage_scopes: UsageScopePool<A>,
}
pub(crate) enum DeferredDestroy<A: HalApi> {
@@ -296,6 +302,7 @@ impl<A: HalApi> Device<A> {
instance_flags,
pending_writes: Mutex::new(Some(pending_writes)),
deferred_destroy: Mutex::new(Vec::new()),
+ usage_scopes: Default::default(),
})
}
@@ -387,6 +394,7 @@ impl<A: HalApi> Device<A> {
&'this self,
fence: &A::Fence,
maintain: wgt::Maintain<queue::WrappedSubmissionIndex>,
+ snatch_guard: SnatchGuard,
) -> Result<(UserClosures, bool), WaitIdleError> {
profiling::scope!("Device::maintain");
let last_done_index = if maintain.is_wait() {
@@ -440,7 +448,8 @@ impl<A: HalApi> Device<A> {
life_tracker.triage_mapped();
}
- let mapping_closures = life_tracker.handle_mapping(self.raw(), &self.trackers);
+ let mapping_closures =
+ life_tracker.handle_mapping(self.raw(), &self.trackers, &snatch_guard);
let queue_empty = life_tracker.queue_empty();
@@ -467,8 +476,9 @@ impl<A: HalApi> Device<A> {
}
}
- // Don't hold the lock while calling release_gpu_resources.
+ // Don't hold the locks while calling release_gpu_resources.
drop(life_tracker);
+ drop(snatch_guard);
if should_release_gpu_resource {
self.release_gpu_resources();
@@ -3568,6 +3578,10 @@ impl<A: HalApi> Device<A> {
let _ = texture.destroy();
}
}
+
+ pub(crate) fn new_usage_scope(&self) -> UsageScope<'_, A> {
+ UsageScope::new_pooled(&self.usage_scopes, &self.tracker_indices)
+ }
}
impl<A: HalApi> Device<A> {