diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 30275f061..05dc0ba51 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -2,6 +2,7 @@ use crate::{ device::{ bgl, Device, DeviceError, MissingDownlevelFlags, MissingFeatures, SHADER_STAGE_COUNT, }, + error::{AsWebGpuErrorType, ErrorType}, id::{BindGroupLayoutId, BufferId, SamplerId, TextureViewId, TlasId}, init_tracker::{BufferInitTrackerAction, TextureInitTrackerAction}, pipeline::{ComputePipeline, RenderPipeline}, @@ -72,6 +73,20 @@ pub enum CreateBindGroupLayoutError { InvalidVisibility(wgt::ShaderStages), } +impl AsWebGpuErrorType for CreateBindGroupLayoutError { + fn as_webgpu_error_type(&self) -> ErrorType { + match self { + Self::Device(e) => e.as_webgpu_error_type(), + + Self::ConflictBinding(_) + | Self::Entry { .. } + | Self::TooManyBindings(_) + | Self::InvalidBindingIndex { .. } + | Self::InvalidVisibility(_) => ErrorType::Validation, + } + } +} + //TODO: refactor this to move out `enum BindingError`. #[derive(Clone, Debug, Error)] @@ -191,6 +206,42 @@ pub enum CreateBindGroupError { InvalidResource(#[from] InvalidResourceError), } +impl AsWebGpuErrorType for CreateBindGroupError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Device(e) => e, + Self::DestroyedResource(e) => e, + Self::MissingBufferUsage(e) => e, + Self::MissingTextureUsage(e) => e, + Self::ResourceUsageCompatibility(e) => e, + Self::InvalidResource(e) => e, + Self::BindingArrayPartialLengthMismatch { .. } + | Self::BindingArrayLengthMismatch { .. } + | Self::BindingArrayZeroLength + | Self::BindingRangeTooLarge { .. } + | Self::BindingSizeTooSmall { .. } + | Self::BindingsNumMismatch { .. } + | Self::BindingZeroSize(_) + | Self::DuplicateBinding(_) + | Self::MissingBindingDeclaration(_) + | Self::SingleBindingExpected + | Self::UnalignedBufferOffset(_, _, _) + | Self::BufferRangeTooLarge { .. } + | Self::WrongBindingType { .. } + | Self::InvalidTextureMultisample { .. } + | Self::InvalidTextureSampleType { .. } + | Self::InvalidTextureDimension { .. } + | Self::InvalidStorageTextureFormat { .. } + | Self::InvalidStorageTextureMipLevelCount { .. } + | Self::WrongSamplerComparison { .. } + | Self::WrongSamplerFiltering { .. } + | Self::DepthStencilAspect + | Self::StorageReadNotSupported(_) => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + #[derive(Clone, Debug, Error)] pub enum BindingZone { #[error("Stage {0:?}")] @@ -208,6 +259,12 @@ pub struct BindingTypeMaxCountError { pub count: u32, } +impl AsWebGpuErrorType for BindingTypeMaxCountError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + #[derive(Clone, Debug)] pub enum BindingTypeMaxCountErrorKind { DynamicUniformBuffers, @@ -572,6 +629,22 @@ pub enum CreatePipelineLayoutError { InvalidResource(#[from] InvalidResourceError), } +impl AsWebGpuErrorType for CreatePipelineLayoutError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Device(e) => e, + Self::MissingFeatures(e) => e, + Self::InvalidResource(e) => e, + Self::TooManyBindings(e) => e, + Self::MisalignedPushConstantRange { .. } + | Self::MoreThanOnePushConstantRangePerStage { .. } + | Self::PushConstantRangeTooLarge { .. } + | Self::TooManyGroups { .. } => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum PushConstantUploadError { @@ -603,6 +676,12 @@ pub enum PushConstantUploadError { Unaligned(u32), } +impl AsWebGpuErrorType for PushConstantUploadError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + /// Describes a pipeline layout. /// /// A `PipelineLayoutDescriptor` can be used to create a pipeline layout. @@ -850,6 +929,12 @@ pub enum BindError { }, } +impl AsWebGpuErrorType for BindError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + #[derive(Debug)] pub struct BindGroupDynamicBindingData { /// The index of the binding. @@ -1011,6 +1096,15 @@ pub enum GetBindGroupLayoutError { InvalidResource(#[from] InvalidResourceError), } +impl AsWebGpuErrorType for GetBindGroupLayoutError { + fn as_webgpu_error_type(&self) -> ErrorType { + match self { + Self::InvalidGroupIndex(_) => ErrorType::Validation, + Self::InvalidResource(e) => e.as_webgpu_error_type(), + } + } +} + #[derive(Clone, Debug, Error, Eq, PartialEq)] #[error("Buffer is bound with size {bound_size} where the shader expects {shader_size} in group[{group_index}] compact index {compact_index}")] pub struct LateMinBufferBindingSizeMismatch { diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index b0d90976d..93b0de232 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -88,6 +88,7 @@ use crate::{ AttachmentData, Device, DeviceError, MissingDownlevelFlags, RenderPassContext, SHADER_STAGE_COUNT, }, + error::{AsWebGpuErrorType, ErrorType}, hub::Hub, id, init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction}, @@ -906,6 +907,15 @@ pub enum CreateRenderBundleError { InvalidSampleCount(u32), } +impl AsWebGpuErrorType for CreateRenderBundleError { + fn as_webgpu_error_type(&self) -> ErrorType { + match self { + Self::ColorAttachment(e) => e.as_webgpu_error_type(), + Self::InvalidSampleCount(_) => ErrorType::Validation, + } + } +} + /// Error type returned from `RenderBundleEncoder::new` if the sample count is invalid. #[derive(Clone, Debug, Error)] #[non_exhaustive] @@ -1553,6 +1563,21 @@ pub struct RenderBundleError { inner: RenderBundleErrorInner, } +impl AsWebGpuErrorType for RenderBundleError { + fn as_webgpu_error_type(&self) -> ErrorType { + let Self { scope: _, inner } = self; + let e: &dyn AsWebGpuErrorType = match inner { + RenderBundleErrorInner::Device(e) => e, + RenderBundleErrorInner::RenderCommand(e) => e, + RenderBundleErrorInner::Draw(e) => e, + RenderBundleErrorInner::MissingDownlevelFlags(e) => e, + RenderBundleErrorInner::Bind(e) => e, + RenderBundleErrorInner::InvalidResource(e) => e, + }; + e.as_webgpu_error_type() + } +} + impl RenderBundleError { pub fn from_device_error(e: DeviceError) -> Self { Self { diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 3a12a5411..98fb7eb33 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -6,6 +6,7 @@ use crate::{ api_log, command::CommandEncoderError, device::DeviceError, + error::{AsWebGpuErrorType, ErrorType}, get_lowest_common_denom, global::Global, id::{BufferId, CommandEncoderId, TextureId}, @@ -75,6 +76,28 @@ whereas subesource range specified start {subresource_base_array_layer} and coun InvalidResource(#[from] InvalidResourceError), } +impl AsWebGpuErrorType for ClearError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::DestroyedResource(e) => e, + Self::MissingBufferUsage(e) => e, + Self::Device(e) => e, + Self::CommandEncoderError(e) => e, + Self::InvalidResource(e) => e, + Self::NoValidTextureClearMode(..) + | Self::MissingClearTextureFeature + | Self::UnalignedFillSize(..) + | Self::UnalignedBufferOffset(..) + | Self::OffsetPlusSizeExceeds64BitBounds { .. } + | Self::BufferOverrun { .. } + | Self::MissingTextureAspect { .. } + | Self::InvalidTextureLevelRange { .. } + | Self::InvalidTextureLayerRange { .. } => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + impl Global { pub fn command_encoder_clear_buffer( &self, diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index 28e76c111..ee6559fb4 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -12,6 +12,7 @@ use crate::{ PassErrorScope, PassTimestampWrites, QueryUseError, StateChange, }, device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures}, + error::{AsWebGpuErrorType, ErrorType}, global::Global, hal_label, id, init_tracker::{BufferInitTrackerAction, MemoryInitKind}, @@ -123,6 +124,12 @@ pub enum DispatchError { BindingSizeTooSmall(#[from] LateMinBufferBindingSizeMismatch), } +impl AsWebGpuErrorType for DispatchError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + /// Error encountered when performing a compute pass. #[derive(Clone, Debug, Error)] pub enum ComputePassErrorInner { @@ -195,6 +202,36 @@ where } } +impl AsWebGpuErrorType for ComputePassError { + fn as_webgpu_error_type(&self) -> ErrorType { + let Self { scope: _, inner } = self; + let e: &dyn AsWebGpuErrorType = match inner { + ComputePassErrorInner::Device(e) => e, + ComputePassErrorInner::Encoder(e) => e, + ComputePassErrorInner::DestroyedResource(e) => e, + ComputePassErrorInner::ResourceUsageCompatibility(e) => e, + ComputePassErrorInner::MissingBufferUsage(e) => e, + ComputePassErrorInner::Dispatch(e) => e, + ComputePassErrorInner::Bind(e) => e, + ComputePassErrorInner::PushConstants(e) => e, + ComputePassErrorInner::QueryUse(e) => e, + ComputePassErrorInner::MissingFeatures(e) => e, + ComputePassErrorInner::MissingDownlevelFlags(e) => e, + ComputePassErrorInner::InvalidResource(e) => e, + ComputePassErrorInner::InvalidParentEncoder + | ComputePassErrorInner::BindGroupIndexOutOfRange { .. } + | ComputePassErrorInner::UnalignedIndirectBufferOffset(_) + | ComputePassErrorInner::IndirectBufferOverrun { .. } + | ComputePassErrorInner::InvalidPopDebugGroup + | ComputePassErrorInner::PushConstantOffsetAlignment + | ComputePassErrorInner::PushConstantSizeAlignment + | ComputePassErrorInner::PushConstantOutOfMemory + | ComputePassErrorInner::PassEnded => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + struct State<'scope, 'snatch_guard, 'cmd_buf, 'raw_encoder> { binder: Binder, pipeline: Option>, diff --git a/wgpu-core/src/command/draw.rs b/wgpu-core/src/command/draw.rs index 76a4cfb06..1508d1ce6 100644 --- a/wgpu-core/src/command/draw.rs +++ b/wgpu-core/src/command/draw.rs @@ -1,5 +1,6 @@ use crate::{ binding_model::{LateMinBufferBindingSizeMismatch, PushConstantUploadError}, + error::{AsWebGpuErrorType, ErrorType}, resource::{ DestroyedResourceError, MissingBufferUsageError, MissingTextureUsageError, ResourceErrorIdent, @@ -62,6 +63,12 @@ pub enum DrawError { BindingSizeTooSmall(#[from] LateMinBufferBindingSizeMismatch), } +impl AsWebGpuErrorType for DrawError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + /// Error encountered when encoding a render command. /// This is the shared error set between render bundles and passes. #[derive(Clone, Debug, Error)] @@ -97,6 +104,29 @@ pub enum RenderCommandError { Unimplemented(&'static str), } +impl AsWebGpuErrorType for RenderCommandError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::IncompatiblePipelineTargets(e) => e, + Self::ResourceUsageCompatibility(e) => e, + Self::DestroyedResource(e) => e, + Self::MissingBufferUsage(e) => e, + Self::MissingTextureUsage(e) => e, + Self::PushConstants(e) => e, + + Self::BindGroupIndexOutOfRange { .. } + | Self::VertexBufferIndexOutOfRange { .. } + | Self::IncompatibleDepthAccess(..) + | Self::IncompatibleStencilAccess(..) + | Self::InvalidViewportRect(..) + | Self::InvalidViewportDepth(..) + | Self::InvalidScissorRect(..) + | Self::Unimplemented(..) => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + #[derive(Clone, Copy, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Rect { diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 6a06d1f83..8bc5463f9 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -28,6 +28,7 @@ pub use timestamp_writes::PassTimestampWrites; use self::memory_init::CommandBufferTextureMemoryActions; use crate::device::{Device, DeviceError, MissingFeatures}; +use crate::error::{AsWebGpuErrorType, ErrorType}; use crate::lock::{rank, Mutex}; use crate::snatch::SnatchGuard; @@ -656,6 +657,20 @@ pub enum CommandEncoderError { MissingFeatures(#[from] MissingFeatures), } +impl AsWebGpuErrorType for CommandEncoderError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Device(e) => e, + Self::InvalidColorAttachment(e) => e, + Self::InvalidResource(e) => e, + Self::MissingFeatures(e) => e, + + Self::Invalid | Self::NotRecording | Self::Locked => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + impl Global { pub fn command_encoder_finish( &self, diff --git a/wgpu-core/src/command/query.rs b/wgpu-core/src/command/query.rs index d783721fb..b8ff7a2a6 100644 --- a/wgpu-core/src/command/query.rs +++ b/wgpu-core/src/command/query.rs @@ -3,6 +3,7 @@ use crate::device::trace::Command as TraceCommand; use crate::{ command::{CommandBuffer, CommandEncoderError}, device::{DeviceError, MissingFeatures}, + error::{AsWebGpuErrorType, ErrorType}, global::Global, id, init_tracker::MemoryInitKind, @@ -107,6 +108,21 @@ pub enum QueryError { InvalidResource(#[from] InvalidResourceError), } +impl AsWebGpuErrorType for QueryError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Encoder(e) => e, + Self::Use(e) => e, + Self::Resolve(e) => e, + Self::InvalidResource(e) => e, + Self::Device(e) => e, + Self::MissingFeature(e) => e, + Self::DestroyedResource(e) => e, + }; + e.as_webgpu_error_type() + } +} + /// Error encountered while trying to use queries #[derive(Clone, Debug, Error)] #[non_exhaustive] @@ -134,6 +150,19 @@ pub enum QueryUseError { }, } +impl AsWebGpuErrorType for QueryUseError { + fn as_webgpu_error_type(&self) -> ErrorType { + match self { + Self::Device(e) => e.as_webgpu_error_type(), + Self::OutOfBounds { .. } + | Self::UsedTwiceInsideRenderpass { .. } + | Self::AlreadyStarted { .. } + | Self::AlreadyStopped + | Self::IncompatibleType { .. } => ErrorType::Validation, + } + } +} + /// Error encountered while trying to resolve a query. #[derive(Clone, Debug, Error)] #[non_exhaustive] @@ -159,6 +188,17 @@ pub enum ResolveError { }, } +impl AsWebGpuErrorType for ResolveError { + fn as_webgpu_error_type(&self) -> ErrorType { + match self { + Self::MissingBufferUsage(e) => e.as_webgpu_error_type(), + Self::BufferOffsetAlignment + | Self::QueryOverrun { .. } + | Self::BufferOverrun { .. } => ErrorType::Validation, + } + } +} + impl QuerySet { fn validate_query( self: &Arc, diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index ad3a5b6ca..f7b3e8899 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -2,6 +2,7 @@ use crate::binding_model::BindGroup; use crate::command::{ validate_and_begin_occlusion_query, validate_and_begin_pipeline_statistics_query, }; +use crate::error::{AsWebGpuErrorType, ErrorType}; use crate::init_tracker::BufferInitTrackerAction; use crate::pipeline::RenderPipeline; use crate::resource::InvalidResourceError; @@ -570,6 +571,12 @@ pub enum ColorAttachmentError { TooManyBytesPerSample { total: u32, limit: u32 }, } +impl AsWebGpuErrorType for ColorAttachmentError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + /// Error encountered when performing a render pass. #[derive(Clone, Debug, Error)] pub enum RenderPassErrorInner { @@ -737,6 +744,53 @@ where } } +impl AsWebGpuErrorType for RenderPassError { + fn as_webgpu_error_type(&self) -> ErrorType { + let Self { scope: _, inner } = self; + let e: &dyn AsWebGpuErrorType = match inner { + RenderPassErrorInner::Device(e) => e, + RenderPassErrorInner::ColorAttachment(e) => e, + RenderPassErrorInner::Encoder(e) => e, + RenderPassErrorInner::MissingFeatures(e) => e, + RenderPassErrorInner::MissingDownlevelFlags(e) => e, + RenderPassErrorInner::RenderCommand(e) => e, + RenderPassErrorInner::Draw(e) => e, + RenderPassErrorInner::Bind(e) => e, + RenderPassErrorInner::QueryUse(e) => e, + RenderPassErrorInner::DestroyedResource(e) => e, + RenderPassErrorInner::InvalidResource(e) => e, + RenderPassErrorInner::IncompatibleBundleTargets(e) => e, + + RenderPassErrorInner::InvalidParentEncoder + | RenderPassErrorInner::InvalidDepthStencilAttachmentFormat(..) + | RenderPassErrorInner::UnsupportedResolveTargetFormat { .. } + | RenderPassErrorInner::MissingAttachments + | RenderPassErrorInner::TextureViewIsNotRenderable { .. } + | RenderPassErrorInner::AttachmentsDimensionMismatch { .. } + | RenderPassErrorInner::AttachmentSampleCountMismatch { .. } + | RenderPassErrorInner::InvalidResolveSampleCounts { .. } + | RenderPassErrorInner::MismatchedResolveTextureFormat { .. } + | RenderPassErrorInner::InvalidDepthOps + | RenderPassErrorInner::InvalidStencilOps + | RenderPassErrorInner::InvalidValuesOffset + | RenderPassErrorInner::UnalignedIndirectBufferOffset(..) + | RenderPassErrorInner::IndirectBufferOverrun { .. } + | RenderPassErrorInner::IndirectCountBufferOverrun { .. } + | RenderPassErrorInner::InvalidPopDebugGroup + | RenderPassErrorInner::ResourceUsageCompatibility(..) + | RenderPassErrorInner::IncompatibleBundleReadOnlyDepthStencil { .. } + | RenderPassErrorInner::PushConstantOffsetAlignment + | RenderPassErrorInner::PushConstantSizeAlignment + | RenderPassErrorInner::PushConstantOutOfMemory + | RenderPassErrorInner::MultiViewMismatch + | RenderPassErrorInner::MultiViewDimensionMismatch + | RenderPassErrorInner::MissingOcclusionQuerySet + | RenderPassErrorInner::PassEnded => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + struct RenderAttachment { texture: Arc, selector: TextureSelector, diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index 2fe6c83f7..1690d4eea 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -5,6 +5,7 @@ use crate::{ command::{clear_texture, CommandEncoderError}, conv, device::{Device, DeviceError, MissingDownlevelFlags}, + error::{AsWebGpuErrorType, ErrorType}, global::Global, id::{BufferId, CommandEncoderId, TextureId}, init_tracker::{ @@ -132,6 +133,45 @@ pub enum TransferError { InvalidMipLevel { requested: u32, count: u32 }, } +impl AsWebGpuErrorType for TransferError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::MemoryInitFailure(e) => e, + Self::MissingBufferUsage(e) => e, + Self::MissingTextureUsage(e) => e, + Self::MissingDownlevelFlags(e) => e, + + Self::SameSourceDestinationBuffer + | Self::BufferOverrun { .. } + | Self::TextureOverrun { .. } + | Self::InvalidTextureAspect { .. } + | Self::InvalidTextureMipLevel { .. } + | Self::InvalidDimensionExternal + | Self::UnalignedBufferOffset(_) + | Self::UnalignedCopySize(_) + | Self::UnalignedCopyWidth + | Self::UnalignedCopyHeight + | Self::UnalignedCopyOriginX + | Self::UnalignedCopyOriginY + | Self::UnalignedBytesPerRow + | Self::UnspecifiedBytesPerRow + | Self::UnspecifiedRowsPerImage + | Self::InvalidBytesPerRow + | Self::InvalidRowsPerImage + | Self::CopySrcMissingAspects + | Self::CopyDstMissingAspects + | Self::CopyAspectNotOne + | Self::CopyFromForbiddenTextureFormat { .. } + | Self::CopyToForbiddenTextureFormat { .. } + | Self::ExternalCopyToForbiddenTextureFormat(_) + | Self::TextureFormatsNotCopyCompatible { .. } + | Self::InvalidSampleCount { .. } + | Self::InvalidMipLevel { .. } => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + /// Error encountered while attempting to do a copy on a command encoder. #[derive(Clone, Debug, Error)] #[non_exhaustive] @@ -152,6 +192,17 @@ impl From for CopyError { } } +impl AsWebGpuErrorType for CopyError { + fn as_webgpu_error_type(&self) -> ErrorType { + match self { + Self::Encoder(e) => e.as_webgpu_error_type(), + Self::Transfer(e) => e.as_webgpu_error_type(), + + Self::InvalidResource(_) | Self::DestroyedResource(_) => ErrorType::Validation, + } + } +} + pub(crate) fn extract_texture_selector( copy_texture: &wgt::ImageCopyTexture, copy_size: &Extent3d, diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 18e35206b..843b5b1b0 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -1,5 +1,6 @@ use crate::{ binding_model, + error::{AsWebGpuErrorType, ErrorType}, hub::Hub, id::{BindGroupLayoutId, PipelineLayoutId}, resource::{ @@ -101,6 +102,12 @@ pub enum RenderPassCompatibilityError { }, } +impl AsWebGpuErrorType for RenderPassCompatibilityError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + impl RenderPassContext { // Assumes the renderpass only contains one subpass pub(crate) fn check_compatible( @@ -404,6 +411,12 @@ impl std::fmt::Display for DeviceMismatch { impl std::error::Error for DeviceMismatch {} +impl AsWebGpuErrorType for DeviceMismatch { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + #[derive(Clone, Debug, Error)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[non_exhaustive] @@ -420,6 +433,17 @@ pub enum DeviceError { DeviceMismatch(#[from] Box), } +impl AsWebGpuErrorType for DeviceError { + fn as_webgpu_error_type(&self) -> ErrorType { + match self { + DeviceError::DeviceMismatch(e) => e.as_webgpu_error_type(), + Self::Invalid(_) => ErrorType::Validation, + Self::Lost | Self::ResourceCreationFailed => ErrorType::Internal, + Self::OutOfMemory => ErrorType::OutOfMemory, + } + } +} + impl DeviceError { /// Only use this function in contexts where there is no `Device`. /// @@ -438,6 +462,8 @@ impl DeviceError { #[error("Features {0:?} are required but not enabled on the device")] pub struct MissingFeatures(pub wgt::Features); +impl AsWebGpuErrorType for MissingFeatures {} + #[derive(Clone, Debug, Error)] #[error( "Downlevel flags {0:?} are required but not supported on the device.\n{}", @@ -445,6 +471,8 @@ pub struct MissingFeatures(pub wgt::Features); )] pub struct MissingDownlevelFlags(pub wgt::DownlevelFlags); +impl AsWebGpuErrorType for MissingDownlevelFlags {} + #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ImplicitPipelineContext { diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 0983eb901..dd400db3c 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -9,6 +9,7 @@ use crate::{ }, conv, device::{DeviceError, WaitIdleError}, + error::{AsWebGpuErrorType, ErrorType}, get_lowest_common_denom, global::Global, hal_label, @@ -526,6 +527,19 @@ pub enum QueueWriteError { InvalidResource(#[from] InvalidResourceError), } +impl AsWebGpuErrorType for QueueWriteError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Queue(e) => e, + Self::Transfer(e) => e, + Self::MemoryInitFailure(e) => e, + Self::DestroyedResource(e) => e, + Self::InvalidResource(e) => e, + }; + e.as_webgpu_error_type() + } +} + #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum QueueSubmitError { @@ -547,6 +561,23 @@ pub enum QueueSubmitError { ValidateTlasActionsError(#[from] crate::ray_tracing::ValidateTlasActionsError), } +impl AsWebGpuErrorType for QueueSubmitError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Queue(e) => e, + Self::Unmap(e) => e, + Self::CommandEncoder(e) => e, + Self::ValidateBlasActionsError(e) => e, + Self::ValidateTlasActionsError(e) => e, + Self::InvalidResource(e) => e, + Self::DestroyedResource(_) | Self::BufferStillMapped(_) => { + return ErrorType::Validation + } + }; + e.as_webgpu_error_type() + } +} + //TODO: move out common parts of write_xxx. impl Queue { diff --git a/wgpu-core/src/error.rs b/wgpu-core/src/error.rs index 519a5f930..bf065752a 100644 --- a/wgpu-core/src/error.rs +++ b/wgpu-core/src/error.rs @@ -62,3 +62,27 @@ impl Error for MultiError { self.inner[0].source() } } + +/// Corresponds to an optional discriminant of [`GPUError`] type in the WebGPU API. Strongly +/// correlates to [`GPUErrorFilter`]s. +/// +/// [`GPUError`]: https://gpuweb.github.io/gpuweb/#gpuerror +/// [`GPUErrorFilter`]: https://gpuweb.github.io/gpuweb/#enumdef-gpuerrorfilter +#[repr(u8)] +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub enum ErrorType { + Internal = 0, + OutOfMemory = 1, + Validation = 2, +} + +/// A trait for querying the [`ErrorType`] classification of an error. +/// +/// This is intended to be used as a convenience by implementations of WebGPU to classify errors +/// returned by [`wgpu_core`](crate). +pub trait AsWebGpuErrorType: Error { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 5c8aef3cd..77eac90e1 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use std::{borrow::Cow, collections::HashMap}; +use crate::error::{AsWebGpuErrorType, ErrorType}; use crate::{ api_log, device::{queue::Queue, resource::Device, DeviceDescriptor, DeviceError}, @@ -28,6 +29,12 @@ pub struct FailedLimit { allowed: u64, } +impl AsWebGpuErrorType for FailedLimit { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + fn check_limits(requested: &wgt::Limits, allowed: &wgt::Limits) -> Vec { let mut failed = Vec::new(); @@ -664,6 +671,17 @@ pub enum RequestDeviceError { UnsupportedFeature(wgt::Features), } +impl AsWebGpuErrorType for RequestDeviceError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Device(e) => e, + Self::LimitsExceeded(e) => e, + Self::UnsupportedFeature(_) => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + #[derive(Clone, Debug, Error)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[non_exhaustive] @@ -672,6 +690,14 @@ pub enum RequestAdapterError { NotFound, } +impl AsWebGpuErrorType for RequestAdapterError { + fn as_webgpu_error_type(&self) -> ErrorType { + match self { + Self::NotFound => ErrorType::Internal, + } + } +} + #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum CreateSurfaceError { diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 07e08cb35..714b07e91 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -3,6 +3,7 @@ use crate::{ binding_model::{CreateBindGroupLayoutError, CreatePipelineLayoutError, PipelineLayout}, command::ColorAttachmentError, device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures, RenderPassContext}, + error::{AsWebGpuErrorType, ErrorType}, id::{PipelineCacheId, PipelineLayoutId, ShaderModuleId}, resource::{InvalidResourceError, Labeled, TrackingData}, resource_log, validation, Label, @@ -119,6 +120,26 @@ pub enum CreateShaderModuleError { }, } +impl AsWebGpuErrorType for CreateShaderModuleError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Device(e) => e, + Self::MissingFeatures(e) => e, + + Self::Generation => return ErrorType::Internal, + + Self::Validation(..) | Self::InvalidGroupIndex { .. } => return ErrorType::Validation, + #[cfg(any(feature = "wgsl", feature = "indirect-validation"))] + Self::Parsing(..) => return ErrorType::Validation, + #[cfg(feature = "glsl")] + Self::ParsingGlsl(..) => return ErrorType::Validation, + #[cfg(feature = "spirv")] + Self::ParsingSpirV(..) => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + /// Describes a programmable pipeline stage. #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -192,6 +213,19 @@ pub enum ImplicitLayoutError { Pipeline(#[from] CreatePipelineLayoutError), } +impl AsWebGpuErrorType for ImplicitLayoutError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::MissingImplicitPipelineIds | Self::MissingIds(_) | Self::ReflectionError(_) => { + return ErrorType::Validation + } + Self::BindGroup(e) => e, + Self::Pipeline(e) => e, + }; + e.as_webgpu_error_type() + } +} + /// Describes a compute pipeline. #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -236,6 +270,21 @@ pub enum CreateComputePipelineError { InvalidResource(#[from] InvalidResourceError), } +impl AsWebGpuErrorType for CreateComputePipelineError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Device(e) => e, + Self::InvalidResource(e) => e, + Self::MissingDownlevelFlags(e) => e, + Self::Implicit(e) => e, + Self::Stage(e) => e, + Self::Internal(_) => return ErrorType::Internal, + Self::PipelineConstants(_) => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + #[derive(Debug)] pub struct ComputePipeline { pub(crate) raw: ManuallyDrop>, @@ -534,6 +583,41 @@ pub enum CreateRenderPipelineError { InvalidResource(#[from] InvalidResourceError), } +impl AsWebGpuErrorType for CreateRenderPipelineError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Device(e) => e, + Self::InvalidResource(e) => e, + Self::MissingFeatures(e) => e, + Self::MissingDownlevelFlags(e) => e, + + Self::Internal { .. } => return ErrorType::Internal, + + Self::ColorAttachment(_) + | Self::Implicit(_) + | Self::ColorState(_, _) + | Self::DepthStencilState(_) + | Self::InvalidSampleCount(_) + | Self::TooManyVertexBuffers { .. } + | Self::TooManyVertexAttributes { .. } + | Self::VertexStrideTooLarge { .. } + | Self::UnalignedVertexStride { .. } + | Self::InvalidVertexAttributeOffset { .. } + | Self::ShaderLocationClash(_) + | Self::StripIndexFormatForNonStripTopology { .. } + | Self::ConservativeRasterizationNonFillPolygonMode + | Self::Stage { .. } + | Self::UnalignedShader { .. } + | Self::BlendFactorOnUnsupportedTarget { .. } + | Self::PipelineExpectsShaderToUseDualSourceBlending + | Self::ShaderExpectsPipelineToUseDualSourceBlending + | Self::NoTargetSpecified + | Self::PipelineConstants { .. } => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + bitflags::bitflags! { #[repr(transparent)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/wgpu-core/src/ray_tracing.rs b/wgpu-core/src/ray_tracing.rs index a094b3530..ca1b18630 100644 --- a/wgpu-core/src/ray_tracing.rs +++ b/wgpu-core/src/ray_tracing.rs @@ -10,6 +10,7 @@ use crate::{ command::CommandEncoderError, device::DeviceError, + error::AsWebGpuErrorType, id::{BlasId, BufferId, TlasId}, resource::CreateBufferError, }; @@ -149,6 +150,12 @@ pub enum ValidateBlasActionsError { UsedUnbuilt(ResourceErrorIdent), } +impl AsWebGpuErrorType for ValidateBlasActionsError { + fn as_webgpu_error_type(&self) -> crate::error::ErrorType { + crate::error::ErrorType::Validation + } +} + #[derive(Clone, Debug, Error)] pub enum ValidateTlasActionsError { #[error("Tlas {0:?} is used before it is built")] @@ -164,6 +171,12 @@ pub enum ValidateTlasActionsError { BlasNewerThenTlas(ResourceErrorIdent, ResourceErrorIdent), } +impl AsWebGpuErrorType for ValidateTlasActionsError { + fn as_webgpu_error_type(&self) -> crate::error::ErrorType { + crate::error::ErrorType::Validation + } +} + #[derive(Debug)] pub struct BlasTriangleGeometry<'a> { pub size: &'a wgt::BlasTriangleGeometrySizeDescriptor, diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 764c5bafe..8d782c80f 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -6,6 +6,7 @@ use crate::{ queue, resource::DeferredDestroy, BufferMapPendingClosure, Device, DeviceError, DeviceMismatch, HostMap, MissingDownlevelFlags, MissingFeatures, }, + error::{AsWebGpuErrorType, ErrorType}, global::Global, hal_api::HalApi, id::{AdapterId, BufferId, CommandEncoderId, DeviceId, SurfaceId, TextureId, TextureViewId}, @@ -389,6 +390,30 @@ pub enum BufferAccessError { InvalidResource(#[from] InvalidResourceError), } +impl AsWebGpuErrorType for BufferAccessError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Device(e) => e, + Self::InvalidResource(e) => e, + Self::DestroyedResource(e) => e, + + Self::Failed + | Self::AlreadyMapped + | Self::MapAlreadyPending + | Self::MissingBufferUsage(_) + | Self::NotMapped + | Self::UnalignedRange + | Self::UnalignedOffset { .. } + | Self::UnalignedRangeSize { .. } + | Self::OutOfBoundsUnderrun { .. } + | Self::OutOfBoundsOverrun { .. } + | Self::NegativeRange { .. } + | Self::MapAborted => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + #[derive(Clone, Debug, Error)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[error("Usage flags {actual:?} of {res} do not contain required usage flags {expected:?}")] @@ -398,6 +423,12 @@ pub struct MissingBufferUsageError { pub(crate) expected: wgt::BufferUsages, } +impl AsWebGpuErrorType for MissingBufferUsageError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + #[derive(Clone, Debug, Error)] #[error("Usage flags {actual:?} of {res} do not contain required usage flags {expected:?}")] pub struct MissingTextureUsageError { @@ -406,16 +437,34 @@ pub struct MissingTextureUsageError { pub(crate) expected: wgt::TextureUsages, } +impl AsWebGpuErrorType for MissingTextureUsageError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + #[derive(Clone, Debug, Error)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[error("{0} has been destroyed")] pub struct DestroyedResourceError(pub ResourceErrorIdent); +impl AsWebGpuErrorType for DestroyedResourceError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + #[derive(Clone, Debug, Error)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[error("{0} is invalid")] pub struct InvalidResourceError(pub ResourceErrorIdent); +impl AsWebGpuErrorType for InvalidResourceError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + pub enum Fallible { Valid(Arc), Invalid(Arc), @@ -885,6 +934,23 @@ crate::impl_parent_device!(Buffer); crate::impl_storage_item!(Buffer); crate::impl_trackable!(Buffer); +impl AsWebGpuErrorType for CreateBufferError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Device(e) => e, + Self::AccessError(e) => e, + Self::IndirectValidationBindGroup(e) => e, + Self::MissingDownlevelFlags(e) => e, + + Self::UnalignedSize + | Self::InvalidUsage(_) + | Self::UsageMismatch(_) + | Self::MaxBufferSize { .. } => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + /// A buffer that has been marked as destroyed and is staged for actual deletion soon. #[derive(Debug)] pub struct DestroyedBuffer { @@ -1581,6 +1647,12 @@ pub enum TextureDimensionError { MultisampledDepthOrArrayLayer(u32), } +impl AsWebGpuErrorType for TextureDimensionError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum CreateTextureError { @@ -1635,6 +1707,31 @@ impl Borrow for Texture { } } +impl AsWebGpuErrorType for CreateTextureError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Device(e) => e, + Self::CreateTextureView(e) => e, + Self::InvalidDimension(e) => e, + Self::MissingFeatures(_, e) => e, + Self::MissingDownlevelFlags(e) => e, + + Self::InvalidUsage(_) + | Self::InvalidDepthDimension(_, _) + | Self::InvalidCompressedDimension(_, _) + | Self::InvalidMipLevelCount { .. } + | Self::InvalidFormatUsages(_, _, _) + | Self::InvalidViewFormat(_, _) + | Self::InvalidDimensionUsages(_, _) + | Self::InvalidMultisampledStorageBinding + | Self::InvalidMultisampledFormat(_) + | Self::InvalidSampleCount(..) + | Self::MultisampledNotRenderAttachment => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + /// Describes a [`TextureView`]. #[derive(Clone, Debug, Default, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -1785,6 +1882,29 @@ pub enum CreateTextureViewError { InvalidResource(#[from] InvalidResourceError), } +impl AsWebGpuErrorType for CreateTextureViewError { + fn as_webgpu_error_type(&self) -> ErrorType { + match self { + Self::Device(e) => e.as_webgpu_error_type(), + + Self::InvalidTextureViewDimension { .. } + | Self::InvalidResource(_) + | Self::InvalidMultisampledTextureViewDimension(_) + | Self::InvalidCubemapTextureDepth { .. } + | Self::InvalidCubemapArrayTextureDepth { .. } + | Self::InvalidCubeTextureViewSize + | Self::ZeroMipLevelCount + | Self::ZeroArrayLayerCount + | Self::TooManyMipLevels { .. } + | Self::TooManyArrayLayers { .. } + | Self::InvalidArrayLayerCount { .. } + | Self::InvalidAspect { .. } + | Self::FormatReinterpretation { .. } + | Self::DestroyedResource(_) => ErrorType::Validation, + } + } +} + #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum TextureViewDestroyError {} @@ -1901,6 +2021,21 @@ crate::impl_parent_device!(Sampler); crate::impl_storage_item!(Sampler); crate::impl_trackable!(Sampler); +impl AsWebGpuErrorType for CreateSamplerError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Device(e) => e, + Self::MissingFeatures(e) => e, + + Self::InvalidLodMinClamp(_) + | Self::InvalidLodMaxClamp { .. } + | Self::InvalidAnisotropy(_) + | Self::InvalidFilterModeWithAnisotropy { .. } => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum CreateQuerySetError { @@ -1958,6 +2093,15 @@ pub enum DestroyError { InvalidResource(#[from] InvalidResourceError), } +impl AsWebGpuErrorType for DestroyError { + fn as_webgpu_error_type(&self) -> ErrorType { + match self { + Self::AlreadyDestroyed => ErrorType::Validation, + Self::InvalidResource(e) => e.as_webgpu_error_type(), + } + } +} + pub type BlasDescriptor<'a> = wgt::CreateBlasDescriptor>; pub type TlasDescriptor<'a> = wgt::CreateTlasDescriptor>; diff --git a/wgpu-core/src/track/mod.rs b/wgpu-core/src/track/mod.rs index 9a66b5f90..2de08a3fa 100644 --- a/wgpu-core/src/track/mod.rs +++ b/wgpu-core/src/track/mod.rs @@ -104,6 +104,7 @@ mod texture; use crate::{ binding_model, command, + error::AsWebGpuErrorType, lock::{rank, Mutex}, pipeline, resource::{self, Labeled, ResourceErrorIdent}, @@ -356,6 +357,8 @@ pub enum ResourceUsageCompatibilityError { }, } +impl AsWebGpuErrorType for ResourceUsageCompatibilityError {} + impl ResourceUsageCompatibilityError { fn from_buffer( buffer: &resource::Buffer, diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 52273b4f8..a0e1a1b6f 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -1,4 +1,9 @@ -use crate::{device::bgl, resource::InvalidResourceError, FastHashMap, FastHashSet}; +use crate::{ + device::bgl, + error::{AsWebGpuErrorType, ErrorType}, + resource::InvalidResourceError, + FastHashMap, FastHashSet, +}; use arrayvec::ArrayVec; use std::{collections::hash_map::Entry, fmt}; use thiserror::Error; @@ -171,6 +176,12 @@ pub enum BindingError { BadStorageFormat(wgt::TextureFormat), } +impl AsWebGpuErrorType for BindingError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum FilteringError { @@ -180,6 +191,12 @@ pub enum FilteringError { Float, } +impl AsWebGpuErrorType for FilteringError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum InputError { @@ -193,6 +210,12 @@ pub enum InputError { SamplingMismatch(Option), } +impl AsWebGpuErrorType for InputError { + fn as_webgpu_error_type(&self) -> ErrorType { + ErrorType::Validation + } +} + /// Errors produced when validating a programmable stage of a pipeline. #[derive(Clone, Debug, Error)] #[non_exhaustive] @@ -240,6 +263,31 @@ pub enum StageError { InvalidResource(#[from] InvalidResourceError), } +impl AsWebGpuErrorType for StageError { + fn as_webgpu_error_type(&self) -> ErrorType { + let e: &dyn AsWebGpuErrorType = match self { + Self::Binding(_, e) => e, + Self::InvalidResource(e) => e, + Self::Filtering { + texture: _, + sampler: _, + error, + } => error, + Self::Input { + location: _, + var: _, + error, + } => error, + Self::InvalidWorkgroupSize { .. } + | Self::TooManyVaryings { .. } + | Self::MissingEntryPoint(_) + | Self::NoEntryPointFound + | Self::MultipleEntryPointsFound => return ErrorType::Validation, + }; + e.as_webgpu_error_type() + } +} + fn map_storage_format_to_naga(format: wgt::TextureFormat) -> Option { use naga::StorageFormat as Sf; use wgt::TextureFormat as Tf;