From ce716adb5e391510048bba96df53657d15d8fd91 Mon Sep 17 00:00:00 2001 From: teoxoy <28601907+teoxoy@users.noreply.github.com> Date: Tue, 18 Jun 2024 20:36:51 +0200 Subject: [PATCH] improve device mismatch errors --- wgpu-core/src/binding_model.rs | 21 +++++++- wgpu-core/src/command/bundle.rs | 8 ++- wgpu-core/src/command/clear.rs | 6 +-- wgpu-core/src/command/compute.rs | 19 +++---- wgpu-core/src/command/mod.rs | 11 ++-- wgpu-core/src/command/query.rs | 6 +-- wgpu-core/src/command/render.rs | 22 +++++--- wgpu-core/src/command/transfer.rs | 18 +++---- wgpu-core/src/device/global.rs | 3 +- wgpu-core/src/device/mod.rs | 32 ++++++++++-- wgpu-core/src/device/queue.rs | 21 +++++--- wgpu-core/src/device/resource.rs | 32 +++++------- wgpu-core/src/pipeline.rs | 26 +++++++++- wgpu-core/src/resource.rs | 86 ++++++++++++++++++++++++++++++- 14 files changed, 242 insertions(+), 69 deletions(-) diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 732c152dc..fce70e27b 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -8,7 +8,7 @@ use crate::{ hal_api::HalApi, id::{BindGroupLayoutId, BufferId, SamplerId, TextureId, TextureViewId}, init_tracker::{BufferInitTrackerAction, TextureInitTrackerAction}, - resource::{Resource, ResourceInfo, ResourceType}, + resource::{ParentDevice, Resource, ResourceInfo, ResourceType}, resource_log, snatch::{SnatchGuard, Snatchable}, track::{BindGroupStates, UsageConflict}, @@ -518,6 +518,13 @@ impl Resource for BindGroupLayout { &self.label } } + +impl ParentDevice for BindGroupLayout { + fn device(&self) -> &Arc> { + &self.device + } +} + impl BindGroupLayout { pub(crate) fn raw(&self) -> &A::BindGroupLayout { self.raw.as_ref().unwrap() @@ -751,6 +758,12 @@ impl Resource for PipelineLayout { } } +impl ParentDevice for PipelineLayout { + fn device(&self) -> &Arc> { + &self.device + } +} + #[repr(C)] #[derive(Clone, Debug, Hash, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -956,6 +969,12 @@ impl Resource for BindGroup { } } +impl ParentDevice for BindGroup { + fn device(&self) -> &Arc> { + &self.device + } +} + #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum GetBindGroupLayoutError { diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 8701a0cb8..1a7733e65 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -97,7 +97,7 @@ use crate::{ id, init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction}, pipeline::{PipelineFlags, RenderPipeline, VertexStep}, - resource::{Buffer, Resource, ResourceInfo, ResourceType}, + resource::{Buffer, ParentDevice, Resource, ResourceInfo, ResourceType}, resource_log, snatch::SnatchGuard, track::RenderBundleScope, @@ -1104,6 +1104,12 @@ impl Resource for RenderBundle { } } +impl ParentDevice for RenderBundle { + fn device(&self) -> &Arc> { + &self.device + } +} + /// A render bundle's current index buffer state. /// /// [`RenderBundleEncoder::finish`] records the currently set index buffer here, diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 71f8c0441..80167d2c2 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -11,7 +11,7 @@ use crate::{ hal_api::HalApi, id::{BufferId, CommandEncoderId, DeviceId, TextureId}, init_tracker::{MemoryInitKind, TextureInitRange}, - resource::{Resource, Texture, TextureClearMode}, + resource::{ParentDevice, Resource, Texture, TextureClearMode}, snatch::SnatchGuard, track::{TextureSelector, TextureTracker}, }; @@ -104,7 +104,7 @@ impl Global { .get(dst) .map_err(|_| ClearError::InvalidBuffer(dst))?; - dst_buffer.device.same_device(&cmd_buf.device)?; + dst_buffer.same_device_as(cmd_buf.as_ref())?; cmd_buf_data .trackers @@ -201,7 +201,7 @@ impl Global { .get(dst) .map_err(|_| ClearError::InvalidTexture(dst))?; - dst_texture.device.same_device(&cmd_buf.device)?; + dst_texture.same_device_as(cmd_buf.as_ref())?; // Check if subresource aspects are valid. let clear_aspects = diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index bd5523efd..3e19caf51 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -15,7 +15,7 @@ use crate::{ hal_api::HalApi, hal_label, id, init_tracker::MemoryInitKind, - resource::{self, Resource}, + resource::{self, ParentDevice, Resource}, snatch::SnatchGuard, track::{Tracker, TrackerIndex, UsageConflict, UsageScope}, validation::{check_buffer_usage, MissingBufferUsageError}, @@ -350,11 +350,8 @@ impl Global { ); }; - if query_set.device.same_device(&cmd_buf.device).is_err() { - return ( - ComputePass::new(None, arc_desc), - Some(CommandEncoderError::WrongDeviceForTimestampWritesQuerySet), - ); + if let Err(e) = query_set.same_device_as(cmd_buf.as_ref()) { + return (ComputePass::new(None, arc_desc), Some(e.into())); } Some(ArcComputePassTimestampWrites { @@ -582,7 +579,7 @@ impl Global { } => { let scope = PassErrorScope::SetBindGroup(bind_group.as_info().id()); - bind_group.device.same_device(device).map_pass_err(scope)?; + bind_group.same_device_as(cmd_buf).map_pass_err(scope)?; let max_bind_groups = cmd_buf.limits.max_bind_groups; if index >= max_bind_groups { @@ -649,7 +646,7 @@ impl Global { let pipeline_id = pipeline.as_info().id(); let scope = PassErrorScope::SetPipelineCompute(pipeline_id); - pipeline.device.same_device(device).map_pass_err(scope)?; + pipeline.same_device_as(cmd_buf).map_pass_err(scope)?; state.pipeline = Some(pipeline_id); @@ -790,7 +787,7 @@ impl Global { pipeline: state.pipeline, }; - buffer.device.same_device(device).map_pass_err(scope)?; + buffer.same_device_as(cmd_buf).map_pass_err(scope)?; state.is_ready().map_pass_err(scope)?; @@ -885,7 +882,7 @@ impl Global { } => { let scope = PassErrorScope::WriteTimestamp; - query_set.device.same_device(device).map_pass_err(scope)?; + query_set.same_device_as(cmd_buf).map_pass_err(scope)?; device .require_features(wgt::Features::TIMESTAMP_QUERY_INSIDE_PASSES) @@ -903,7 +900,7 @@ impl Global { } => { let scope = PassErrorScope::BeginPipelineStatisticsQuery; - query_set.device.same_device(device).map_pass_err(scope)?; + query_set.same_device_as(cmd_buf).map_pass_err(scope)?; let query_set = tracker.query_sets.insert_single(query_set); diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 874e207a2..9c8bb7170 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -29,7 +29,7 @@ use crate::lock::{rank, Mutex}; use crate::snatch::SnatchGuard; use crate::init_tracker::BufferInitTrackerAction; -use crate::resource::{Resource, ResourceInfo, ResourceType}; +use crate::resource::{ParentDevice, Resource, ResourceInfo, ResourceType}; use crate::track::{Tracker, UsageScope}; use crate::{api_log, global::Global, hal_api::HalApi, id, resource_log, Label}; @@ -541,6 +541,12 @@ impl Resource for CommandBuffer { } } +impl ParentDevice for CommandBuffer { + fn device(&self) -> &Arc> { + &self.device + } +} + #[derive(Copy, Clone, Debug)] pub struct BasePassRef<'a, C> { pub label: Option<&'a str>, @@ -633,11 +639,8 @@ pub enum CommandEncoderError { Device(#[from] DeviceError), #[error("Command encoder is locked by a previously created render/compute pass. Before recording any new commands, the pass must be ended.")] Locked, - #[error("QuerySet provided for pass timestamp writes is invalid.")] InvalidTimestampWritesQuerySetId, - #[error("QuerySet provided for pass timestamp writes that was created by a different device.")] - WrongDeviceForTimestampWritesQuerySet, } impl Global { diff --git a/wgpu-core/src/command/query.rs b/wgpu-core/src/command/query.rs index dce8bfe10..96831c1d1 100644 --- a/wgpu-core/src/command/query.rs +++ b/wgpu-core/src/command/query.rs @@ -9,7 +9,7 @@ use crate::{ hal_api::HalApi, id::{self, Id}, init_tracker::MemoryInitKind, - resource::QuerySet, + resource::{ParentDevice, QuerySet}, storage::Storage, Epoch, FastHashMap, Index, }; @@ -405,7 +405,7 @@ impl Global { .add_single(&*query_set_guard, query_set_id) .ok_or(QueryError::InvalidQuerySet(query_set_id))?; - query_set.device.same_device(&cmd_buf.device)?; + query_set.same_device_as(cmd_buf.as_ref())?; let (dst_buffer, dst_pending) = { let buffer_guard = hub.buffers.read(); @@ -413,7 +413,7 @@ impl Global { .get(destination) .map_err(|_| QueryError::InvalidBuffer(destination))?; - dst_buffer.device.same_device(&cmd_buf.device)?; + dst_buffer.same_device_as(cmd_buf.as_ref())?; tracker .buffers diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index e08dd9f02..5f0dde1db 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -25,7 +25,7 @@ use crate::{ hal_label, id, init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction}, pipeline::{self, PipelineFlags}, - resource::{QuerySet, Texture, TextureView, TextureViewNotRenderableReason}, + resource::{ParentDevice, QuerySet, Texture, TextureView, TextureViewNotRenderableReason}, storage::Storage, track::{TextureSelector, Tracker, UsageConflict, UsageScope}, validation::{ @@ -1476,7 +1476,9 @@ impl Global { .ok_or(RenderCommandError::InvalidBindGroup(bind_group_id)) .map_pass_err(scope)?; - bind_group.device.same_device(device).map_pass_err(scope)?; + bind_group + .same_device_as(cmd_buf.as_ref()) + .map_pass_err(scope)?; bind_group .validate_dynamic_bindings(index, &temp_offsets, &cmd_buf.limits) @@ -1542,7 +1544,9 @@ impl Global { .ok_or(RenderCommandError::InvalidPipeline(pipeline_id)) .map_pass_err(scope)?; - pipeline.device.same_device(device).map_pass_err(scope)?; + pipeline + .same_device_as(cmd_buf.as_ref()) + .map_pass_err(scope)?; info.context .check_compatible( @@ -1669,7 +1673,9 @@ impl Global { .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDEX) .map_pass_err(scope)?; - buffer.device.same_device(device).map_pass_err(scope)?; + buffer + .same_device_as(cmd_buf.as_ref()) + .map_pass_err(scope)?; check_buffer_usage(buffer_id, buffer.usage, BufferUsages::INDEX) .map_pass_err(scope)?; @@ -1720,7 +1726,9 @@ impl Global { .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::VERTEX) .map_pass_err(scope)?; - buffer.device.same_device(device).map_pass_err(scope)?; + buffer + .same_device_as(cmd_buf.as_ref()) + .map_pass_err(scope)?; let max_vertex_buffers = device.limits.max_vertex_buffers; if slot >= max_vertex_buffers { @@ -2325,7 +2333,9 @@ impl Global { .ok_or(RenderCommandError::InvalidRenderBundle(bundle_id)) .map_pass_err(scope)?; - bundle.device.same_device(device).map_pass_err(scope)?; + bundle + .same_device_as(cmd_buf.as_ref()) + .map_pass_err(scope)?; info.context .check_compatible( diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index bf5ce67e1..d04510f83 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -13,7 +13,7 @@ use crate::{ has_copy_partial_init_tracker_coverage, MemoryInitKind, TextureInitRange, TextureInitTrackerAction, }, - resource::{Resource, Texture, TextureErrorDimension}, + resource::{ParentDevice, Resource, Texture, TextureErrorDimension}, snatch::SnatchGuard, track::{TextureSelector, Tracker}, }; @@ -602,7 +602,7 @@ impl Global { .get(source) .map_err(|_| TransferError::InvalidBuffer(source))?; - src_buffer.device.same_device(device)?; + src_buffer.same_device_as(cmd_buf.as_ref())?; cmd_buf_data .trackers @@ -626,7 +626,7 @@ impl Global { .get(destination) .map_err(|_| TransferError::InvalidBuffer(destination))?; - dst_buffer.device.same_device(device)?; + dst_buffer.same_device_as(cmd_buf.as_ref())?; cmd_buf_data .trackers @@ -777,7 +777,7 @@ impl Global { .get(destination.texture) .map_err(|_| TransferError::InvalidTexture(destination.texture))?; - dst_texture.device.same_device(device)?; + dst_texture.same_device_as(cmd_buf.as_ref())?; let (hal_copy_size, array_layer_count) = validate_texture_copy_range( destination, @@ -810,7 +810,7 @@ impl Global { .get(source.buffer) .map_err(|_| TransferError::InvalidBuffer(source.buffer))?; - src_buffer.device.same_device(device)?; + src_buffer.same_device_as(cmd_buf.as_ref())?; tracker .buffers @@ -943,7 +943,7 @@ impl Global { .get(source.texture) .map_err(|_| TransferError::InvalidTexture(source.texture))?; - src_texture.device.same_device(device)?; + src_texture.same_device_as(cmd_buf.as_ref())?; let (hal_copy_size, array_layer_count) = validate_texture_copy_range(source, &src_texture.desc, CopySide::Source, copy_size)?; @@ -997,7 +997,7 @@ impl Global { .get(destination.buffer) .map_err(|_| TransferError::InvalidBuffer(destination.buffer))?; - dst_buffer.device.same_device(device)?; + dst_buffer.same_device_as(cmd_buf.as_ref())?; tracker .buffers @@ -1127,8 +1127,8 @@ impl Global { .get(destination.texture) .map_err(|_| TransferError::InvalidTexture(source.texture))?; - src_texture.device.same_device(device)?; - dst_texture.device.same_device(device)?; + src_texture.same_device_as(cmd_buf.as_ref())?; + dst_texture.same_device_as(cmd_buf.as_ref())?; // src and dst texture format must be copy-compatible // https://gpuweb.github.io/gpuweb/#copy-compatible diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index e9863376b..7f0c9db43 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -15,6 +15,7 @@ use crate::{ pipeline, present, resource::{ self, BufferAccessError, BufferAccessResult, BufferMapOperation, CreateBufferError, + ParentDevice, }, validation::check_buffer_usage, Label, LabelHelpers as _, @@ -1124,7 +1125,7 @@ impl Global { Err(..) => break 'error binding_model::CreateBindGroupError::InvalidLayout, }; - if let Err(e) = bind_group_layout.device.same_device(&device) { + if let Err(e) = bind_group_layout.same_device(&device) { break 'error e.into(); } diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index e52f611f8..05d05483a 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -3,7 +3,9 @@ use crate::{ hal_api::HalApi, hub::Hub, id::{BindGroupLayoutId, PipelineLayoutId}, - resource::{Buffer, BufferAccessError, BufferAccessResult, BufferMapOperation}, + resource::{ + Buffer, BufferAccessError, BufferAccessResult, BufferMapOperation, ResourceErrorIdent, + }, snatch::SnatchGuard, Label, DOWNLEVEL_ERROR_MESSAGE, }; @@ -382,6 +384,30 @@ fn map_buffer( #[error("Device is invalid")] pub struct InvalidDevice; +#[derive(Clone, Debug)] +pub struct WrongDevice { + pub(super) res: ResourceErrorIdent, + pub(super) res_device: ResourceErrorIdent, + pub(super) target: Option, + pub(super) target_device: ResourceErrorIdent, +} + +impl std::fmt::Display for WrongDevice { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!( + f, + "{} of {} doesn't match {}", + self.res_device, self.res, self.target_device + )?; + if let Some(target) = self.target.as_ref() { + write!(f, " of {target}")?; + } + Ok(()) + } +} + +impl std::error::Error for WrongDevice {} + #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum DeviceError { @@ -395,8 +421,8 @@ pub enum DeviceError { ResourceCreationFailed, #[error("QueueId is invalid")] InvalidQueueId, - #[error("Attempt to use a resource with a different device from the one that created it")] - WrongDevice, + #[error(transparent)] + WrongDevice(#[from] Box), } impl From for DeviceError { diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index eab96eed6..5724b9447 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -16,8 +16,8 @@ use crate::{ init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange}, lock::{rank, Mutex, RwLockWriteGuard}, resource::{ - Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, DestroyedTexture, Resource, - ResourceInfo, ResourceType, StagingBuffer, Texture, TextureInner, + Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, DestroyedTexture, ParentDevice, + Resource, ResourceInfo, ResourceType, StagingBuffer, Texture, TextureInner, }, resource_log, track, FastHashMap, SubmissionIndex, }; @@ -53,6 +53,12 @@ impl Resource for Queue { } } +impl ParentDevice for Queue { + fn device(&self) -> &Arc> { + self.device.as_ref().unwrap() + } +} + impl Drop for Queue { fn drop(&mut self) { let queue = self.raw.take().unwrap(); @@ -408,7 +414,7 @@ impl Global { let device = queue.device.as_ref().unwrap(); - buffer.device.same_device(device)?; + buffer.same_device_as(queue.as_ref())?; let data_size = data.len() as wgt::BufferAddress; @@ -449,6 +455,7 @@ impl Global { } let result = self.queue_write_staging_buffer_impl( + &queue, device, pending_writes, &staging_buffer, @@ -523,6 +530,7 @@ impl Global { } let result = self.queue_write_staging_buffer_impl( + &queue, device, pending_writes, &staging_buffer, @@ -587,6 +595,7 @@ impl Global { fn queue_write_staging_buffer_impl( &self, + queue: &Arc>, device: &Arc>, pending_writes: &mut PendingWrites, staging_buffer: &StagingBuffer, @@ -612,7 +621,7 @@ impl Global { .get(&snatch_guard) .ok_or(TransferError::InvalidBuffer(buffer_id))?; - dst.device.same_device(device)?; + dst.same_device_as(queue.as_ref())?; let src_buffer_size = staging_buffer.size; self.queue_validate_write_buffer_impl(&dst, buffer_id, buffer_offset, src_buffer_size)?; @@ -695,7 +704,7 @@ impl Global { .get(destination.texture) .map_err(|_| TransferError::InvalidTexture(destination.texture))?; - dst.device.same_device(device)?; + dst.same_device_as(queue.as_ref())?; if !dst.desc.usage.contains(wgt::TextureUsages::COPY_DST) { return Err( @@ -1176,7 +1185,7 @@ impl Global { Err(_) => continue, }; - cmdbuf.device.same_device(device)?; + cmdbuf.same_device_as(queue.as_ref())?; #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 6cb6653d0..f7c2b522c 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -24,8 +24,8 @@ use crate::{ pool::ResourcePool, registry::Registry, resource::{ - self, Buffer, QuerySet, Resource, ResourceInfo, ResourceType, Sampler, Texture, - TextureView, TextureViewNotRenderableReason, + self, Buffer, ParentDevice, QuerySet, Resource, ResourceInfo, ResourceType, Sampler, + Texture, TextureView, TextureViewNotRenderableReason, }, resource_log, snatch::{SnatchGuard, SnatchLock, Snatchable}, @@ -313,12 +313,6 @@ impl Device { self.valid.load(Ordering::Acquire) } - pub fn same_device(self: &Arc, other: &Arc) -> Result<(), DeviceError> { - Arc::ptr_eq(self, other) - .then_some(()) - .ok_or(DeviceError::WrongDevice) - } - pub(crate) fn release_queue(&self, queue: A::Queue) { assert!(self.queue_to_drop.set(queue).is_ok()); } @@ -1904,7 +1898,7 @@ impl Device { .add_single(storage, bb.buffer_id, internal_use) .ok_or(Error::InvalidBuffer(bb.buffer_id))?; - buffer.device.same_device(self)?; + buffer.same_device(self)?; check_buffer_usage(bb.buffer_id, buffer.usage, pub_usage)?; let raw_buffer = buffer @@ -1997,7 +1991,7 @@ impl Device { .add_single(storage, id) .ok_or(Error::InvalidSampler(id))?; - sampler.device.same_device(self)?; + sampler.same_device(self)?; Ok(sampler) } @@ -2019,7 +2013,7 @@ impl Device { .add_single(storage, id) .ok_or(Error::InvalidTextureView(id))?; - view.device.same_device(self)?; + view.same_device(self)?; let (pub_usage, internal_use) = self.texture_use_parameters( binding, @@ -2038,7 +2032,7 @@ impl Device { texture_id, ))?; - texture.device.same_device(&view.device)?; + texture.same_device_as(view)?; check_texture_usage(texture.desc.usage, pub_usage)?; @@ -2523,7 +2517,7 @@ impl Device { // Validate total resource counts and check for a matching device for bgl in &bind_group_layouts { - bgl.device.same_device(self)?; + bgl.same_device(self)?; count_validator.merge(&bgl.binding_count_validator); } @@ -2631,7 +2625,7 @@ impl Device { .get(desc.stage.module) .map_err(|_| validation::StageError::InvalidModule)?; - shader_module.device.same_device(self)?; + shader_module.same_device(self)?; // Get the pipeline layout from the desc if it is provided. let pipeline_layout = match desc.layout { @@ -2641,7 +2635,7 @@ impl Device { .get(pipeline_layout_id) .map_err(|_| pipeline::CreateComputePipelineError::InvalidLayout)?; - pipeline_layout.device.same_device(self)?; + pipeline_layout.same_device(self)?; Some(pipeline_layout) } @@ -2703,7 +2697,7 @@ impl Device { break 'cache None; }; - cache.device.same_device(self)?; + cache.same_device(self)?; Some(cache) }; @@ -3081,7 +3075,7 @@ impl Device { .get(pipeline_layout_id) .map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?; - pipeline_layout.device.same_device(self)?; + pipeline_layout.same_device(self)?; Some(pipeline_layout) } @@ -3116,7 +3110,7 @@ impl Device { error: validation::StageError::InvalidModule, } })?; - vertex_shader_module.device.same_device(self)?; + vertex_shader_module.same_device(self)?; let stage_err = |error| pipeline::CreateRenderPipelineError::Stage { stage, error }; @@ -3308,7 +3302,7 @@ impl Device { break 'cache None; }; - cache.device.same_device(self)?; + cache.same_device(self)?; Some(cache) }; diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index f3e7dbacb..78cf3d567 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -7,7 +7,7 @@ use crate::{ device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures, RenderPassContext}, hal_api::HalApi, id::{PipelineCacheId, PipelineLayoutId, ShaderModuleId}, - resource::{Resource, ResourceInfo, ResourceType}, + resource::{ParentDevice, Resource, ResourceInfo, ResourceType}, resource_log, validation, Label, }; use arrayvec::ArrayVec; @@ -90,6 +90,12 @@ impl Resource for ShaderModule { } } +impl ParentDevice for ShaderModule { + fn device(&self) -> &Arc> { + &self.device + } +} + impl ShaderModule { pub(crate) fn raw(&self) -> &A::ShaderModule { self.raw.as_ref().unwrap() @@ -258,6 +264,12 @@ impl Resource for ComputePipeline { } } +impl ParentDevice for ComputePipeline { + fn device(&self) -> &Arc> { + &self.device + } +} + impl ComputePipeline { pub(crate) fn raw(&self) -> &A::ComputePipeline { self.raw.as_ref().unwrap() @@ -326,6 +338,12 @@ impl Resource for PipelineCache { } } +impl ParentDevice for PipelineCache { + fn device(&self) -> &Arc> { + &self.device + } +} + /// Describes how the vertex buffer is interpreted. #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -585,6 +603,12 @@ impl Resource for RenderPipeline { } } +impl ParentDevice for RenderPipeline { + fn device(&self) -> &Arc> { + &self.device + } +} + impl RenderPipeline { pub(crate) fn raw(&self) -> &A::RenderPipeline { self.raw.as_ref().unwrap() diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 9ae275615..e6389b206 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -4,7 +4,7 @@ use crate::{ binding_model::BindGroup, device::{ queue, resource::DeferredDestroy, BufferMapPendingClosure, Device, DeviceError, HostMap, - MissingDownlevelFlags, MissingFeatures, + MissingDownlevelFlags, MissingFeatures, WrongDevice, }, global::Global, hal_api::HalApi, @@ -143,6 +143,48 @@ impl ResourceInfo { } } +#[derive(Clone, Debug)] +pub struct ResourceErrorIdent { + r#type: ResourceType, + label: String, +} + +impl std::fmt::Display for ResourceErrorIdent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!(f, "{} with '{}' label", self.r#type, self.label) + } +} + +pub(crate) trait ParentDevice: Resource { + fn device(&self) -> &Arc>; + + fn same_device_as>(&self, other: &O) -> Result<(), DeviceError> { + Arc::ptr_eq(self.device(), other.device()) + .then_some(()) + .ok_or_else(|| { + DeviceError::WrongDevice(Box::new(WrongDevice { + res: self.error_ident(), + res_device: self.device().error_ident(), + target: Some(other.error_ident()), + target_device: other.device().error_ident(), + })) + }) + } + + fn same_device(&self, device: &Arc>) -> Result<(), DeviceError> { + Arc::ptr_eq(self.device(), device) + .then_some(()) + .ok_or_else(|| { + DeviceError::WrongDevice(Box::new(WrongDevice { + res: self.error_ident(), + res_device: self.device().error_ident(), + target: None, + target_device: device.error_ident(), + })) + }) + } +} + pub(crate) type ResourceType = &'static str; pub(crate) trait Resource: 'static + Sized + WasmNotSendSync { @@ -169,6 +211,12 @@ pub(crate) trait Resource: 'static + Sized + WasmNotSendSync { fn is_equal(&self, other: &Self) -> bool { self.as_info().id().unzip() == other.as_info().id().unzip() } + fn error_ident(&self) -> ResourceErrorIdent { + ResourceErrorIdent { + r#type: Self::TYPE, + label: self.label().to_owned(), + } + } } /// The status code provided to the buffer mapping callback. @@ -627,6 +675,12 @@ impl Resource for Buffer { } } +impl ParentDevice for Buffer { + fn device(&self) -> &Arc> { + &self.device + } +} + /// A buffer that has been marked as destroyed and is staged for actual deletion soon. #[derive(Debug)] pub struct DestroyedBuffer { @@ -731,6 +785,12 @@ impl Resource for StagingBuffer { } } +impl ParentDevice for StagingBuffer { + fn device(&self) -> &Arc> { + &self.device + } +} + pub type TextureDescriptor<'a> = wgt::TextureDescriptor, Vec>; #[derive(Debug)] @@ -1245,6 +1305,12 @@ impl Resource for Texture { } } +impl ParentDevice for Texture { + fn device(&self) -> &Arc> { + &self.device + } +} + impl Borrow for Texture { fn borrow(&self) -> &TextureSelector { &self.full_range @@ -1410,6 +1476,12 @@ impl Resource for TextureView { } } +impl ParentDevice for TextureView { + fn device(&self) -> &Arc> { + &self.device + } +} + /// Describes a [`Sampler`] #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -1531,6 +1603,12 @@ impl Resource for Sampler { } } +impl ParentDevice for Sampler { + fn device(&self) -> &Arc> { + &self.device + } +} + #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum CreateQuerySetError { @@ -1571,6 +1649,12 @@ impl Drop for QuerySet { } } +impl ParentDevice for QuerySet { + fn device(&self) -> &Arc> { + &self.device + } +} + impl Resource for QuerySet { const TYPE: ResourceType = "QuerySet";