1use alloc::boxed::Box;
2
3use thiserror::Error;
4
5use wgt::error::{ErrorType, WebGpuError};
6
7use super::bind::BinderError;
8use crate::command::pass;
9use crate::{
10 binding_model::{BindingError, LateMinBufferBindingSizeMismatch, PushConstantUploadError},
11 resource::{
12 DestroyedResourceError, MissingBufferUsageError, MissingTextureUsageError,
13 ResourceErrorIdent,
14 },
15 track::ResourceUsageCompatibilityError,
16};
17
18#[derive(Clone, Debug, Error)]
20#[non_exhaustive]
21pub enum DrawError {
22 #[error("Blend constant needs to be set")]
23 MissingBlendConstant,
24 #[error("Render pipeline must be set")]
25 MissingPipeline(#[from] pass::MissingPipeline),
26 #[error("Currently set {pipeline} requires vertex buffer {index} to be set")]
27 MissingVertexBuffer {
28 pipeline: ResourceErrorIdent,
29 index: u32,
30 },
31 #[error("Index buffer must be set")]
32 MissingIndexBuffer,
33 #[error(transparent)]
34 IncompatibleBindGroup(#[from] Box<BinderError>),
35 #[error("Vertex {last_vertex} extends beyond limit {vertex_limit} imposed by the buffer in slot {slot}. Did you bind the correct `Vertex` step-rate vertex buffer?")]
36 VertexBeyondLimit {
37 last_vertex: u64,
38 vertex_limit: u64,
39 slot: u32,
40 },
41 #[error("Instance {last_instance} extends beyond limit {instance_limit} imposed by the buffer in slot {slot}. Did you bind the correct `Instance` step-rate vertex buffer?")]
42 InstanceBeyondLimit {
43 last_instance: u64,
44 instance_limit: u64,
45 slot: u32,
46 },
47 #[error("Index {last_index} extends beyond limit {index_limit}. Did you bind the correct index buffer?")]
48 IndexBeyondLimit { last_index: u64, index_limit: u64 },
49 #[error(
50 "Index buffer format {buffer_format:?} doesn't match {pipeline}'s index format {pipeline_format:?}"
51 )]
52 UnmatchedIndexFormats {
53 pipeline: ResourceErrorIdent,
54 pipeline_format: wgt::IndexFormat,
55 buffer_format: wgt::IndexFormat,
56 },
57 #[error(transparent)]
58 BindingSizeTooSmall(#[from] LateMinBufferBindingSizeMismatch),
59
60 #[error(
61 "Wrong pipeline type for this draw command. Attempted to call {} draw command on {} pipeline",
62 if *wanted_mesh_pipeline {"mesh shader"} else {"standard"},
63 if *wanted_mesh_pipeline {"standard"} else {"mesh shader"},
64 )]
65 WrongPipelineType { wanted_mesh_pipeline: bool },
66 #[error(
67 "Each current draw group size dimension ({current:?}) must be less or equal to {limit}, and the product must be less or equal to {max_total}"
68 )]
69 InvalidGroupSize {
70 current: [u32; 3],
71 limit: u32,
72 max_total: u32,
73 },
74 #[error(
75 "Mesh shader calls in multiview render passes require enabling the `EXPERIMENTAL_MESH_SHADER_MULTIVIEW` feature, and the highest bit ({highest_view_index}) in the multiview mask must be <= `Limits::max_multiview_view_count` ({max_multiviews})"
76 )]
77 MeshPipelineMultiviewLimitsViolated {
78 highest_view_index: u32,
79 max_multiviews: u32,
80 },
81}
82
83impl WebGpuError for DrawError {
84 fn webgpu_error_type(&self) -> ErrorType {
85 ErrorType::Validation
86 }
87}
88
89#[derive(Clone, Debug, Error)]
92#[non_exhaustive]
93pub enum RenderCommandError {
94 #[error(transparent)]
95 BindGroupIndexOutOfRange(#[from] pass::BindGroupIndexOutOfRange),
96 #[error("Vertex buffer index {index} is greater than the device's requested `max_vertex_buffers` limit {max}")]
97 VertexBufferIndexOutOfRange { index: u32, max: u32 },
98 #[error(
99 "Offset {offset} for vertex buffer in slot {slot} is not a multiple of `VERTEX_ALIGNMENT`"
100 )]
101 UnalignedVertexBuffer { slot: u32, offset: u64 },
102 #[error("Offset {offset} for index buffer is not a multiple of {alignment}")]
103 UnalignedIndexBuffer { offset: u64, alignment: usize },
104 #[error("Render pipeline targets are incompatible with render pass")]
105 IncompatiblePipelineTargets(#[from] crate::device::RenderPassCompatibilityError),
106 #[error("{0} writes to depth, while the pass has read-only depth access")]
107 IncompatibleDepthAccess(ResourceErrorIdent),
108 #[error("{0} writes to stencil, while the pass has read-only stencil access")]
109 IncompatibleStencilAccess(ResourceErrorIdent),
110 #[error(transparent)]
111 ResourceUsageCompatibility(#[from] ResourceUsageCompatibilityError),
112 #[error(transparent)]
113 DestroyedResource(#[from] DestroyedResourceError),
114 #[error(transparent)]
115 MissingBufferUsage(#[from] MissingBufferUsageError),
116 #[error(transparent)]
117 MissingTextureUsage(#[from] MissingTextureUsageError),
118 #[error(transparent)]
119 PushConstants(#[from] PushConstantUploadError),
120 #[error(transparent)]
121 BindingError(#[from] BindingError),
122 #[error("Viewport size {{ w: {w}, h: {h} }} greater than device's requested `max_texture_dimension_2d` limit {max}, or less than zero")]
123 InvalidViewportRectSize { w: f32, h: f32, max: u32 },
124 #[error("Viewport has invalid rect {rect:?} for device's requested `max_texture_dimension_2d` limit; Origin less than -2 * `max_texture_dimension_2d` ({min}), or rect extends past 2 * `max_texture_dimension_2d` - 1 ({max})")]
125 InvalidViewportRectPosition { rect: Rect<f32>, min: f32, max: f32 },
126 #[error("Viewport minDepth {0} and/or maxDepth {1} are not in [0, 1]")]
127 InvalidViewportDepth(f32, f32),
128 #[error("Scissor {0:?} is not contained in the render target {1:?}")]
129 InvalidScissorRect(Rect<u32>, wgt::Extent3d),
130 #[error("Support for {0} is not implemented yet")]
131 Unimplemented(&'static str),
132}
133
134impl WebGpuError for RenderCommandError {
135 fn webgpu_error_type(&self) -> ErrorType {
136 let e: &dyn WebGpuError = match self {
137 Self::IncompatiblePipelineTargets(e) => e,
138 Self::ResourceUsageCompatibility(e) => e,
139 Self::DestroyedResource(e) => e,
140 Self::MissingBufferUsage(e) => e,
141 Self::MissingTextureUsage(e) => e,
142 Self::PushConstants(e) => e,
143 Self::BindingError(e) => e,
144
145 Self::BindGroupIndexOutOfRange { .. }
146 | Self::VertexBufferIndexOutOfRange { .. }
147 | Self::UnalignedIndexBuffer { .. }
148 | Self::UnalignedVertexBuffer { .. }
149 | Self::IncompatibleDepthAccess(..)
150 | Self::IncompatibleStencilAccess(..)
151 | Self::InvalidViewportRectSize { .. }
152 | Self::InvalidViewportRectPosition { .. }
153 | Self::InvalidViewportDepth(..)
154 | Self::InvalidScissorRect(..)
155 | Self::Unimplemented(..) => return ErrorType::Validation,
156 };
157 e.webgpu_error_type()
158 }
159}
160
161#[derive(Clone, Copy, Debug, Default)]
162#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
163pub struct Rect<T> {
164 pub x: T,
165 pub y: T,
166 pub w: T,
167 pub h: T,
168}