diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 2cbac7bfa6b..4a08bc5658e 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -25,9 +25,9 @@ use crate::{ init_tracker::{BufferInitTrackerAction, TextureInitTrackerAction}, pipeline::{ComputePipeline, RenderPipeline}, resource::{ - Buffer, DestroyedResourceError, ExternalTexture, InvalidResourceError, Labeled, - MissingBufferUsageError, MissingTextureUsageError, RawResourceAccess, ResourceErrorIdent, - Sampler, TextureView, Tlas, TrackingData, + impl_resource_errors, Buffer, DestroyedResourceError, ExternalTexture, + InvalidResourceError, Labeled, MissingBufferUsageError, MissingTextureUsageError, + RawResourceAccess, ResourceErrorIdent, Sampler, TextureView, Tlas, TrackingData, }, resource_log, snatch::{SnatchGuard, Snatchable}, @@ -134,7 +134,9 @@ pub enum CreateBindGroupError { #[error(transparent)] Device(#[from] DeviceError), #[error(transparent)] - DestroyedResource(#[from] DestroyedResourceError), + InvalidResource(InvalidResourceError), + #[error(transparent)] + DestroyedResource(DestroyedResourceError), #[error(transparent)] BindingError(#[from] BindingError), #[error( @@ -254,10 +256,10 @@ pub enum CreateBindGroupError { StorageReadWriteNotSupported(wgt::TextureFormat), #[error(transparent)] ResourceUsageCompatibility(#[from] ResourceUsageCompatibilityError), - #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), } +impl_resource_errors!(CreateBindGroupError); + impl WebGpuError for CreateBindGroupError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { @@ -800,15 +802,20 @@ pub enum CreatePipelineLayoutError { #[error("Bind group layout count {actual} exceeds device bind group limit {max}")] TooManyGroups { actual: usize, max: usize }, #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), + #[error(transparent)] + DestroyedResource(DestroyedResourceError), } +impl_resource_errors!(CreatePipelineLayoutError); + impl WebGpuError for CreatePipelineLayoutError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { Self::Device(e) => e, Self::MissingFeatures(e) => e, Self::InvalidResource(e) => e, + Self::DestroyedResource(e) => e, Self::TooManyBindings(e) => e, Self::MisalignedPushConstantRange { .. } | Self::MoreThanOnePushConstantRangePerStage { .. } @@ -1275,14 +1282,19 @@ pub enum GetBindGroupLayoutError { #[error("Invalid group index {0}")] InvalidGroupIndex(u32), #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), + #[error(transparent)] + DestroyedResource(DestroyedResourceError), } +impl_resource_errors!(GetBindGroupLayoutError); + impl WebGpuError for GetBindGroupLayoutError { fn webgpu_error_type(&self) -> ErrorType { match self { Self::InvalidGroupIndex(_) => ErrorType::Validation, Self::InvalidResource(e) => e.webgpu_error_type(), + Self::DestroyedResource(e) => e.webgpu_error_type(), } } } diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 8e8bf90b146..2203b3d9c7e 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -111,8 +111,8 @@ use crate::{ init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction}, pipeline::{PipelineFlags, RenderPipeline, VertexStep}, resource::{ - Buffer, DestroyedResourceError, Fallible, InvalidResourceError, Labeled, ParentDevice, - RawResourceAccess, TrackingData, + Buffer, DestroyedResourceError, Fallible, Labeled, ParentDevice, RawResourceAccess, + TrackingData, }, resource_log, snatch::SnatchGuard, @@ -1601,8 +1601,6 @@ pub(super) enum RenderBundleErrorInner { MissingDownlevelFlags(#[from] MissingDownlevelFlags), #[error(transparent)] Bind(#[from] BindError), - #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), } impl From for RenderBundleErrorInner @@ -1632,7 +1630,6 @@ impl WebGpuError for RenderBundleError { RenderBundleErrorInner::Draw(e) => e, RenderBundleErrorInner::MissingDownlevelFlags(e) => e, RenderBundleErrorInner::Bind(e) => e, - RenderBundleErrorInner::InvalidResource(e) => e, }; e.webgpu_error_type() } diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 840e9068125..2d56c63aa32 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -13,8 +13,9 @@ use crate::{ id::{BufferId, CommandEncoderId, TextureId}, init_tracker::{MemoryInitKind, TextureInitRange}, resource::{ - DestroyedResourceError, InvalidResourceError, Labeled, MissingBufferUsageError, - ParentDevice, RawResourceAccess, ResourceErrorIdent, Texture, TextureClearMode, + impl_resource_errors, DestroyedResourceError, InvalidResourceError, Labeled, + MissingBufferUsageError, ParentDevice, RawResourceAccess, ResourceErrorIdent, Texture, + TextureClearMode, }, snatch::SnatchGuard, track::TextureTrackerSetSingle, @@ -31,8 +32,6 @@ use wgt::{ #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum ClearError { - #[error(transparent)] - DestroyedResource(#[from] DestroyedResourceError), #[error(transparent)] MissingFeatures(#[from] MissingFeatures), #[error("{0} can not be cleared")] @@ -78,9 +77,13 @@ whereas subesource range specified start {subresource_base_array_layer} and coun #[error(transparent)] EncoderState(#[from] EncoderStateError), #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), + #[error(transparent)] + DestroyedResource(DestroyedResourceError), } +impl_resource_errors!(ClearError); + impl WebGpuError for ClearError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index 0d8aaf27eb2..8d5bfb60f0c 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -7,9 +7,6 @@ use wgt::{ use alloc::{borrow::Cow, boxed::Box, sync::Arc, vec::Vec}; use core::{fmt, str}; -use crate::command::{ - pass, CommandEncoder, DebugGroupError, EncoderStateError, PassStateError, TimestampWritesError, -}; use crate::resource::DestroyedResourceError; use crate::{binding_model::BindError, resource::RawResourceAccess}; use crate::{ @@ -34,6 +31,13 @@ use crate::{ track::{ResourceUsageCompatibilityError, Tracker, TrackerIndex}, Label, }; +use crate::{ + command::{ + pass, CommandEncoder, DebugGroupError, EncoderStateError, PassStateError, + TimestampWritesError, + }, + resource::impl_resource_errors, +}; pub type ComputeBasePass = BasePass; @@ -150,7 +154,9 @@ pub enum ComputePassErrorInner { #[error(transparent)] BindGroupIndexOutOfRange(#[from] pass::BindGroupIndexOutOfRange), #[error(transparent)] - DestroyedResource(#[from] DestroyedResourceError), + InvalidResource(InvalidResourceError), + #[error(transparent)] + DestroyedResource(DestroyedResourceError), #[error("Indirect buffer offset {0:?} is not a multiple of 4")] UnalignedIndirectBufferOffset(BufferAddress), #[error("Indirect buffer uses bytes {offset}..{end_offset} which overruns indirect buffer of size {buffer_size}")] @@ -184,14 +190,14 @@ pub enum ComputePassErrorInner { #[error("The compute pass has already been ended and no further commands can be recorded")] PassEnded, #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), - #[error(transparent)] TimestampWrites(#[from] TimestampWritesError), // This one is unreachable, but required for generic pass support #[error(transparent)] InvalidValuesOffset(#[from] pass::InvalidValuesOffset), } +impl_resource_errors!(ComputePassErrorInner); + /// Error encountered when performing a compute pass, stored for later reporting /// when encoding ends. #[derive(Clone, Debug, Error)] diff --git a/wgpu-core/src/command/draw.rs b/wgpu-core/src/command/draw.rs index 7a57077a4fa..b94e4b78b28 100644 --- a/wgpu-core/src/command/draw.rs +++ b/wgpu-core/src/command/draw.rs @@ -6,6 +6,7 @@ use wgt::error::{ErrorType, WebGpuError}; use super::bind::BinderError; use crate::command::pass; +use crate::resource::{impl_resource_errors, InvalidResourceError}; use crate::{ binding_model::{BindingError, LateMinBufferBindingSizeMismatch, PushConstantUploadError}, resource::{ @@ -103,7 +104,9 @@ pub enum RenderCommandError { #[error(transparent)] ResourceUsageCompatibility(#[from] ResourceUsageCompatibilityError), #[error(transparent)] - DestroyedResource(#[from] DestroyedResourceError), + InvalidResource(InvalidResourceError), + #[error(transparent)] + DestroyedResource(DestroyedResourceError), #[error(transparent)] MissingBufferUsage(#[from] MissingBufferUsageError), #[error(transparent)] @@ -124,11 +127,14 @@ pub enum RenderCommandError { Unimplemented(&'static str), } +impl_resource_errors!(RenderCommandError); + impl WebGpuError for RenderCommandError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { Self::IncompatiblePipelineTargets(e) => e, Self::ResourceUsageCompatibility(e) => e, + Self::InvalidResource(e) => e, Self::DestroyedResource(e) => e, Self::MissingBufferUsage(e) => e, Self::MissingTextureUsage(e) => e, diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 2467784d57a..4f6da124404 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -41,7 +41,8 @@ use crate::snatch::SnatchGuard; use crate::init_tracker::BufferInitTrackerAction; use crate::ray_tracing::{AsAction, BuildAccelerationStructureError}; use crate::resource::{ - DestroyedResourceError, Fallible, InvalidResourceError, Labeled, ParentDevice as _, QuerySet, + impl_resource_errors, BadResourceError, DestroyedResourceError, Fallible, InvalidResourceError, + Labeled, ParentDevice as _, QuerySet, }; use crate::storage::Storage; use crate::track::{DeviceTracker, ResourceUsageCompatibilityError, Tracker, UsageScope}; @@ -1042,9 +1043,9 @@ pub enum CommandEncoderError { #[error(transparent)] Device(#[from] DeviceError), #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), #[error(transparent)] - DestroyedResource(#[from] DestroyedResourceError), + DestroyedResource(DestroyedResourceError), #[error(transparent)] ResourceUsage(#[from] ResourceUsageCompatibilityError), #[error(transparent)] @@ -1067,6 +1068,8 @@ pub enum CommandEncoderError { RenderPass(#[from] RenderPassError), } +impl_resource_errors!(CommandEncoderError); + impl CommandEncoderError { fn is_destroyed_error(&self) -> bool { matches!( @@ -1310,7 +1313,7 @@ impl Global { + From + From + From - + From, + + From, { let &PassTimestampWrites { query_set, diff --git a/wgpu-core/src/command/query.rs b/wgpu-core/src/command/query.rs index c47374b028d..b1e6152374d 100644 --- a/wgpu-core/src/command/query.rs +++ b/wgpu-core/src/command/query.rs @@ -10,8 +10,8 @@ use crate::{ id, init_tracker::MemoryInitKind, resource::{ - DestroyedResourceError, InvalidResourceError, MissingBufferUsageError, ParentDevice, - QuerySet, RawResourceAccess, Trackable, + impl_resource_errors, DestroyedResourceError, InvalidResourceError, + MissingBufferUsageError, ParentDevice, QuerySet, RawResourceAccess, Trackable, }, track::{StatelessTracker, TrackerIndex}, FastHashMap, @@ -107,11 +107,13 @@ pub enum QueryError { #[error("Error encountered while trying to resolve a query")] Resolve(#[from] ResolveError), #[error(transparent)] - DestroyedResource(#[from] DestroyedResourceError), + DestroyedResource(DestroyedResourceError), #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), } +impl_resource_errors!(QueryError); + impl WebGpuError for QueryError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 6546b71c324..26f3ab26bc6 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -9,11 +9,6 @@ use wgt::{ TextureSelector, TextureUsages, TextureViewDimension, VertexStepMode, }; -use crate::command::{ - pass, pass_base, pass_try, validate_and_begin_occlusion_query, - validate_and_begin_pipeline_statistics_query, DebugGroupError, EncoderStateError, - InnerCommandEncoder, PassStateError, TimestampWritesError, -}; use crate::pipeline::{RenderPipeline, VertexStep}; use crate::resource::RawResourceAccess; use crate::resource::{InvalidResourceError, ResourceErrorIdent}; @@ -37,12 +32,21 @@ use crate::{ init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction}, pipeline::PipelineFlags, resource::{ - DestroyedResourceError, Labeled, MissingBufferUsageError, MissingTextureUsageError, - ParentDevice, QuerySet, Texture, TextureView, TextureViewNotRenderableReason, + impl_resource_errors, DestroyedResourceError, Labeled, MissingBufferUsageError, + MissingTextureUsageError, ParentDevice, QuerySet, Texture, TextureView, + TextureViewNotRenderableReason, }, track::{ResourceUsageCompatibilityError, Tracker, UsageScope}, Label, }; +use crate::{ + command::{ + pass, pass_base, pass_try, validate_and_begin_occlusion_query, + validate_and_begin_pipeline_statistics_query, DebugGroupError, EncoderStateError, + InnerCommandEncoder, PassStateError, TimestampWritesError, + }, + resource::BadResourceError, +}; #[cfg(feature = "serde")] use serde::Deserialize; @@ -778,15 +782,17 @@ pub enum RenderPassErrorInner { #[error("missing occlusion query set")] MissingOcclusionQuerySet, #[error(transparent)] - DestroyedResource(#[from] DestroyedResourceError), + DestroyedResource(DestroyedResourceError), #[error("The compute pass has already been ended and no further commands can be recorded")] PassEnded, #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), #[error(transparent)] TimestampWrites(#[from] TimestampWritesError), } +impl_resource_errors!(RenderPassErrorInner); + impl From for RenderPassErrorInner { fn from(error: MissingBufferUsageError) -> Self { Self::RenderCommand(error.into()) @@ -3079,7 +3085,7 @@ impl Global { fn resolve_render_pass_buffer_id( &self, buffer_id: id::Id, - ) -> Result, InvalidResourceError> { + ) -> Result, BadResourceError> { let hub = &self.hub; let buffer = hub.buffers.get(buffer_id).get()?; @@ -3089,7 +3095,7 @@ impl Global { fn resolve_render_pass_query_set( &self, query_set_id: id::Id, - ) -> Result, InvalidResourceError> { + ) -> Result, BadResourceError> { let hub = &self.hub; let query_set = hub.query_sets.get(query_set_id).get()?; diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index d946ec35a0b..e181684ac9c 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -33,8 +33,8 @@ use crate::{ lock::{rank, Mutex, MutexGuard, RwLock, RwLockWriteGuard}, ray_tracing::{BlasCompactReadyPendingClosure, CompactBlasError}, resource::{ - Blas, BlasCompactState, Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, - DestroyedResourceError, DestroyedTexture, Fallible, FlushedStagingBuffer, + impl_resource_errors, Blas, BlasCompactState, Buffer, BufferAccessError, BufferMapState, + DestroyedBuffer, DestroyedResourceError, DestroyedTexture, Fallible, FlushedStagingBuffer, InvalidResourceError, Labeled, ParentDevice, ResourceErrorIdent, StagingBuffer, Texture, TextureInner, Trackable, TrackingData, }, @@ -462,11 +462,13 @@ pub enum QueueWriteError { #[error(transparent)] MemoryInitFailure(#[from] ClearError), #[error(transparent)] - DestroyedResource(#[from] DestroyedResourceError), + DestroyedResource(DestroyedResourceError), #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), } +impl_resource_errors!(QueueWriteError); + impl WebGpuError for QueueWriteError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { diff --git a/wgpu-core/src/device/ray_tracing.rs b/wgpu-core/src/device/ray_tracing.rs index b44a8719d3f..cf3b9f911a2 100644 --- a/wgpu-core/src/device/ray_tracing.rs +++ b/wgpu-core/src/device/ray_tracing.rs @@ -4,6 +4,7 @@ use core::mem::{size_of, ManuallyDrop}; #[cfg(feature = "trace")] use crate::device::trace; use crate::device::DeviceError; +use crate::resource::BadResourceError; use crate::{ api_log, device::Device, @@ -15,9 +16,7 @@ use crate::{ ray_tracing::BlasPrepareCompactError, ray_tracing::{CreateBlasError, CreateTlasError}, resource, - resource::{ - BlasCompactCallback, BlasCompactState, Fallible, InvalidResourceError, TrackingData, - }, + resource::{BlasCompactCallback, BlasCompactState, Fallible, TrackingData}, snatch::Snatchable, LabelHelpers, }; @@ -387,7 +386,7 @@ impl Global { } } - pub fn ready_for_compaction(&self, blas_id: BlasId) -> Result { + pub fn ready_for_compaction(&self, blas_id: BlasId) -> Result { profiling::scope!("Blas::prepare_compact_async"); api_log!("Blas::prepare_compact_async {blas_id:?}"); diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 753518f67ad..66f45805fb4 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -18,7 +18,9 @@ use crate::{ command::ColorAttachmentError, device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures, RenderPassContext}, id::{PipelineCacheId, PipelineLayoutId, ShaderModuleId}, - resource::{InvalidResourceError, Labeled, TrackingData}, + resource::{ + impl_resource_errors, DestroyedResourceError, InvalidResourceError, Labeled, TrackingData, + }, resource_log, validation, Label, }; @@ -250,14 +252,19 @@ pub enum CreateComputePipelineError { #[error(transparent)] MissingDownlevelFlags(#[from] MissingDownlevelFlags), #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), + #[error(transparent)] + DestroyedResource(DestroyedResourceError), } +impl_resource_errors!(CreateComputePipelineError); + impl WebGpuError for CreateComputePipelineError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { Self::Device(e) => e, Self::InvalidResource(e) => e, + Self::DestroyedResource(e) => e, Self::MissingDownlevelFlags(e) => e, Self::Implicit(e) => e, Self::Stage(e) => e, @@ -693,14 +700,19 @@ pub enum CreateRenderPipelineError { ))] NoTargetSpecified, #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), + #[error(transparent)] + DestroyedResource(DestroyedResourceError), } +impl_resource_errors!(CreateRenderPipelineError); + impl WebGpuError for CreateRenderPipelineError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { Self::Device(e) => e, Self::InvalidResource(e) => e, + Self::DestroyedResource(e) => e, Self::MissingFeatures(e) => e, Self::MissingDownlevelFlags(e) => e, diff --git a/wgpu-core/src/ray_tracing.rs b/wgpu-core/src/ray_tracing.rs index 3518375d885..a4d79104f44 100644 --- a/wgpu-core/src/ray_tracing.rs +++ b/wgpu-core/src/ray_tracing.rs @@ -21,8 +21,9 @@ use crate::{ device::{DeviceError, MissingFeatures}, id::{BlasId, BufferId, TlasId}, resource::{ - Blas, BlasCompactCallback, BlasPrepareCompactResult, DestroyedResourceError, - InvalidResourceError, MissingBufferUsageError, ResourceErrorIdent, Tlas, + impl_resource_errors, Blas, BlasCompactCallback, BlasPrepareCompactResult, + DestroyedResourceError, InvalidResourceError, MissingBufferUsageError, ResourceErrorIdent, + Tlas, }, }; @@ -93,10 +94,10 @@ pub enum BuildAccelerationStructureError { Device(#[from] DeviceError), #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), #[error(transparent)] - DestroyedResource(#[from] DestroyedResourceError), + DestroyedResource(DestroyedResourceError), #[error(transparent)] MissingBufferUsage(#[from] MissingBufferUsageError), @@ -181,6 +182,8 @@ pub enum BuildAccelerationStructureError { TlasDependentMissingVertexReturn(ResourceErrorIdent, ResourceErrorIdent), } +impl_resource_errors!(BuildAccelerationStructureError); + impl WebGpuError for BuildAccelerationStructureError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { @@ -352,7 +355,9 @@ pub enum BlasPrepareCompactError { #[error(transparent)] Device(#[from] DeviceError), #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), + #[error(transparent)] + DestroyedResource(DestroyedResourceError), #[error("Compaction is already being prepared")] CompactionPreparingAlready, #[error("Cannot compact an already compacted BLAS")] @@ -363,11 +368,14 @@ pub enum BlasPrepareCompactError { CompactionUnsupported, } +impl_resource_errors!(BlasPrepareCompactError); + impl WebGpuError for BlasPrepareCompactError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { Self::Device(e) => e, Self::InvalidResource(e) => e, + Self::DestroyedResource(e) => e, Self::CompactionPreparingAlready | Self::DoubleCompaction | Self::NotBuilt @@ -386,10 +394,10 @@ pub enum CompactBlasError { Device(#[from] DeviceError), #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), #[error(transparent)] - DestroyedResource(#[from] DestroyedResourceError), + DestroyedResource(DestroyedResourceError), #[error(transparent)] MissingFeatures(#[from] MissingFeatures), @@ -398,6 +406,8 @@ pub enum CompactBlasError { BlasNotReady, } +impl_resource_errors!(CompactBlasError); + impl WebGpuError for CompactBlasError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { diff --git a/wgpu-core/src/registry.rs b/wgpu-core/src/registry.rs index 3ff81dc73e5..9720e61b33d 100644 --- a/wgpu-core/src/registry.rs +++ b/wgpu-core/src/registry.rs @@ -4,6 +4,7 @@ use crate::{ id::Id, identity::IdentityManager, lock::{rank, RwLock, RwLockReadGuard}, + resource::{Fallible, ParentDevice}, storage::{Element, Storage, StorageItem}, }; @@ -121,6 +122,13 @@ impl Registry { } } +impl Registry> { + #[expect(dead_code)] // will be used soon + pub(crate) fn mark_destroyed(&self, id: Id) -> Option> { + self.storage.write().mark_destroyed(id) + } +} + #[cfg(test)] mod tests { use super::Registry; diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 8d51298a711..a130244e361 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -214,6 +214,36 @@ macro_rules! impl_trackable { }; } +macro_rules! impl_resource_errors { + ($err:ty) => { + impl From<$crate::resource::BadResourceError> for $err { + fn from(e: $crate::resource::BadResourceError) -> Self { + match e { + $crate::resource::BadResourceError::Invalid(ident) => { + <$err>::InvalidResource($crate::resource::InvalidResourceError(ident)) + } + $crate::resource::BadResourceError::Destroyed(ident) => { + <$err>::DestroyedResource($crate::resource::DestroyedResourceError(ident)) + } + } + } + } + + impl From<$crate::resource::InvalidResourceError> for $err { + fn from(e: $crate::resource::InvalidResourceError) -> Self { + <$err>::InvalidResource(e) + } + } + + impl From<$crate::resource::DestroyedResourceError> for $err { + fn from(e: $crate::resource::DestroyedResourceError) -> Self { + <$err>::DestroyedResource(e) + } + } + }; +} +pub(crate) use impl_resource_errors; + #[derive(Debug)] pub(crate) enum BufferMapState { /// Mapped at creation. @@ -263,7 +293,7 @@ pub enum BufferAccessError { #[error("Buffer map failed")] Failed, #[error(transparent)] - DestroyedResource(#[from] DestroyedResourceError), + DestroyedResource(DestroyedResourceError), #[error("Buffer is already mapped")] AlreadyMapped, #[error("Buffer map is pending")] @@ -300,9 +330,11 @@ pub enum BufferAccessError { #[error("Buffer map aborted")] MapAborted, #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), } +impl_resource_errors!(BufferAccessError); + impl WebGpuError for BufferAccessError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { @@ -381,18 +413,53 @@ impl WebGpuError for InvalidResourceError { pub enum Fallible { Valid(Arc), Invalid(Arc), + Destroyed(ResourceErrorIdent), +} + +#[derive(Clone, Debug, Error)] +pub enum BadResourceError { + #[error("{0} is invalid")] + Invalid(ResourceErrorIdent), + #[error("{0} was already destroyed")] + Destroyed(ResourceErrorIdent), +} + +impl WebGpuError for BadResourceError { + fn webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + +impl BadResourceError { + pub fn ident(&self) -> &ResourceErrorIdent { + match self { + BadResourceError::Invalid(ident) | BadResourceError::Destroyed(ident) => ident, + } + } } impl Fallible { - pub fn get(self) -> Result, InvalidResourceError> { + pub fn get(self) -> Result, BadResourceError> { match self { Fallible::Valid(v) => Ok(v), - Fallible::Invalid(label) => Err(InvalidResourceError(ResourceErrorIdent { + Fallible::Invalid(label) => Err(BadResourceError::Invalid(ResourceErrorIdent { r#type: Cow::Borrowed(T::TYPE), label: (*label).clone(), })), + Fallible::Destroyed(ident) => Err(BadResourceError::Destroyed(ident)), } } + + pub fn mark_destroyed(&mut self) -> Option> { + let error_ident = match self { + Fallible::Valid(v) => v.error_ident(), + _ => return None, + }; + let Fallible::Valid(v) = mem::replace(self, Fallible::Destroyed(error_ident)) else { + unreachable!(); + }; + Some(v) + } } impl Clone for Fallible { @@ -400,6 +467,7 @@ impl Clone for Fallible { match self { Self::Valid(v) => Self::Valid(v.clone()), Self::Invalid(l) => Self::Invalid(l.clone()), + Self::Destroyed(ident) => Self::Destroyed(ident.clone()), } } } @@ -1708,7 +1776,7 @@ pub enum CreateTextureViewError { #[error(transparent)] Device(#[from] DeviceError), #[error(transparent)] - DestroyedResource(#[from] DestroyedResourceError), + DestroyedResource(DestroyedResourceError), #[error("Invalid texture view dimension `{view:?}` with texture of dimension `{texture:?}`")] InvalidTextureViewDimension { view: wgt::TextureViewDimension, @@ -1757,11 +1825,13 @@ pub enum CreateTextureViewError { view: wgt::TextureFormat, }, #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), #[error(transparent)] MissingFeatures(#[from] MissingFeatures), } +impl_resource_errors!(CreateTextureViewError); + impl WebGpuError for CreateTextureViewError { fn webgpu_error_type(&self) -> ErrorType { match self { @@ -1834,7 +1904,9 @@ pub enum CreateExternalTextureError { #[error(transparent)] MissingFeatures(#[from] MissingFeatures), #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), + #[error(transparent)] + DestroyedResource(DestroyedResourceError), #[error(transparent)] CreateBuffer(#[from] CreateBufferError), #[error(transparent)] @@ -1866,12 +1938,15 @@ pub enum CreateExternalTextureError { }, } +impl_resource_errors!(CreateExternalTextureError); + impl WebGpuError for CreateExternalTextureError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { CreateExternalTextureError::Device(e) => e, CreateExternalTextureError::MissingFeatures(e) => e, CreateExternalTextureError::InvalidResource(e) => e, + CreateExternalTextureError::DestroyedResource(e) => e, CreateExternalTextureError::CreateBuffer(e) => e, CreateExternalTextureError::QueueWrite(e) => e, CreateExternalTextureError::MissingTextureUsage(e) => e, diff --git a/wgpu-core/src/storage.rs b/wgpu-core/src/storage.rs index 8f04261006e..823b65b33df 100644 --- a/wgpu-core/src/storage.rs +++ b/wgpu-core/src/storage.rs @@ -2,7 +2,7 @@ use alloc::{sync::Arc, vec::Vec}; use core::mem; use crate::id::{Id, Marker}; -use crate::resource::ResourceType; +use crate::resource::{Fallible, ParentDevice, ResourceType}; use crate::{Epoch, Index}; /// An entry in a `Storage::map` table. @@ -140,3 +140,20 @@ where result } } + +impl Storage> { + #[allow(dead_code)] + pub(crate) fn mark_destroyed(&mut self, id: Id) -> Option> { + let (index, epoch) = id.unzip(); + let stored = self.map.get_mut(index as usize); + match stored { + Some(&mut Element::Occupied(ref mut value, storage_epoch)) => { + assert_eq!(epoch, storage_epoch, "id epoch mismatch"); + value.mark_destroyed() + } + Some(&mut Element::Vacant) | None => { + panic!("{}[{:?}] does not exist", self.kind, id); + } + } + } +} diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 2c2f4b36c44..087341c102b 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -13,7 +13,11 @@ use wgt::{ BindGroupLayoutEntry, BindingType, }; -use crate::{device::bgl, resource::InvalidResourceError, FastHashMap, FastHashSet}; +use crate::{ + device::bgl, + resource::{impl_resource_errors, DestroyedResourceError, InvalidResourceError}, + FastHashMap, FastHashSet, +}; #[derive(Debug)] enum ResourceType { @@ -312,14 +316,19 @@ pub enum StageError { )] MultipleEntryPointsFound, #[error(transparent)] - InvalidResource(#[from] InvalidResourceError), + InvalidResource(InvalidResourceError), + #[error(transparent)] + DestroyedResource(DestroyedResourceError), } +impl_resource_errors!(StageError); + impl WebGpuError for StageError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { Self::Binding(_, e) => e, Self::InvalidResource(e) => e, + Self::DestroyedResource(e) => e, Self::Filtering { texture: _, sampler: _,