feat: add AsWebGpuErrorType and ErrorType APIs

This commit is contained in:
Erich Gubler 2024-11-14 14:50:01 -05:00
parent 6f528e2ebc
commit e5121e0fa9
18 changed files with 771 additions and 1 deletions

View File

@ -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 {

View File

@ -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 {

View File

@ -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,

View File

@ -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<Arc<ComputePipeline>>,

View File

@ -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<T> {

View File

@ -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,

View File

@ -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<Self>,

View File

@ -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<Texture>,
selector: TextureSelector,

View File

@ -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<DeviceError> 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<T>(
copy_texture: &wgt::ImageCopyTexture<T>,
copy_size: &Extent3d,

View File

@ -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<T: Labeled>(
@ -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<DeviceMismatch>),
}
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 {

View File

@ -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 {

View File

@ -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
}
}

View File

@ -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<FailedLimit> {
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 {

View File

@ -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<Box<dyn hal::DynComputePipeline>>,
@ -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)]

View File

@ -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,

View File

@ -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<T: ParentDevice> {
Valid(Arc<T>),
Invalid(Arc<String>),
@ -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<TextureSelector> 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<Label<'a>>;
pub type TlasDescriptor<'a> = wgt::CreateTlasDescriptor<Label<'a>>;

View File

@ -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,

View File

@ -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<naga::Sampling>),
}
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<naga::StorageFormat> {
use naga::StorageFormat as Sf;
use wgt::TextureFormat as Tf;