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::validation::InvalidWorkgroupSizeError;
10use crate::{
11 binding_model::{BindingError, ImmediateUploadError, LateMinBufferBindingSizeMismatch},
12 resource::{
13 DestroyedResourceError, MissingBufferUsageError, MissingTextureUsageError,
14 ResourceErrorIdent,
15 },
16 track::ResourceUsageCompatibilityError,
17};
18
19#[derive(Clone, Debug, Error)]
21#[non_exhaustive]
22pub enum DrawError {
23 #[error("Blend constant needs to be set")]
24 MissingBlendConstant,
25 #[error("Render pipeline must be set")]
26 MissingPipeline(#[from] pass::MissingPipeline),
27 #[error("Currently set {pipeline} requires vertex buffer {index} to be set")]
28 MissingVertexBuffer {
29 pipeline: ResourceErrorIdent,
30 index: usize,
31 },
32 #[error("Index buffer must be set")]
33 MissingIndexBuffer,
34 #[error(transparent)]
35 IncompatibleBindGroup(#[from] Box<BinderError>),
36 #[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?")]
37 VertexBeyondLimit {
38 last_vertex: u64,
39 vertex_limit: u64,
40 slot: u32,
41 },
42 #[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?")]
43 InstanceBeyondLimit {
44 last_instance: u64,
45 instance_limit: u64,
46 slot: u32,
47 },
48 #[error("Index {last_index} extends beyond limit {index_limit}. Did you bind the correct index buffer?")]
49 IndexBeyondLimit { last_index: u64, index_limit: u64 },
50 #[error("For indexed drawing with strip topology, {pipeline}'s strip index format {strip_index_format:?} must match index buffer format {buffer_format:?}")]
51 UnmatchedStripIndexFormat {
52 pipeline: ResourceErrorIdent,
53 strip_index_format: Option<wgt::IndexFormat>,
54 buffer_format: wgt::IndexFormat,
55 },
56 #[error(transparent)]
57 BindingSizeTooSmall(#[from] LateMinBufferBindingSizeMismatch),
58 #[error(
59 "Wrong pipeline type for this draw command. Attempted to call {} draw command on {} pipeline",
60 if *wanted_mesh_pipeline {"mesh shader"} else {"standard"},
61 if *wanted_mesh_pipeline {"standard"} else {"mesh shader"},
62 )]
63 WrongPipelineType { wanted_mesh_pipeline: bool },
64 #[error(transparent)]
65 InvalidGroupSize(#[from] InvalidWorkgroupSizeError),
66 #[error(
67 "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})"
68 )]
69 MeshPipelineMultiviewLimitsViolated {
70 highest_view_index: u32,
71 max_multiviews: u32,
72 },
73 #[error("Not all immediate data required by the pipeline has been set via set_immediates (missing byte ranges: {missing})")]
74 MissingImmediateData {
75 missing: naga::valid::ImmediateSlots,
76 },
77 #[error("The number of bind groups + vertex buffers {given} exceeds the limit {limit}")]
78 TooManyBindGroupsPlusVertexBuffers { given: u32, limit: u32 },
79}
80
81impl WebGpuError for DrawError {
82 fn webgpu_error_type(&self) -> ErrorType {
83 ErrorType::Validation
84 }
85}
86
87#[derive(Clone, Debug, Error)]
90#[non_exhaustive]
91pub enum RenderCommandError {
92 #[error(transparent)]
93 BindGroupIndexOutOfRange(#[from] pass::BindGroupIndexOutOfRange),
94 #[error("Vertex buffer index {index} is greater than the device's requested `max_vertex_buffers` limit {max}")]
95 VertexBufferIndexOutOfRange { index: u32, max: u32 },
96 #[error(
97 "Offset {offset} for vertex buffer in slot {slot} is not a multiple of `VERTEX_ALIGNMENT`"
98 )]
99 UnalignedVertexBuffer { slot: u32, offset: u64 },
100 #[error("Offset {offset} for index buffer is not a multiple of {alignment}")]
101 UnalignedIndexBuffer { offset: u64, alignment: usize },
102 #[error("Render pipeline targets are incompatible with render pass")]
103 IncompatiblePipelineTargets(#[from] crate::device::RenderPassCompatibilityError),
104 #[error("{0} writes to depth, while the pass has read-only depth access")]
105 IncompatibleDepthAccess(ResourceErrorIdent),
106 #[error("{0} writes to stencil, while the pass has read-only stencil access")]
107 IncompatibleStencilAccess(ResourceErrorIdent),
108 #[error(transparent)]
109 ResourceUsageCompatibility(#[from] ResourceUsageCompatibilityError),
110 #[error(transparent)]
111 DestroyedResource(#[from] DestroyedResourceError),
112 #[error(transparent)]
113 MissingBufferUsage(#[from] MissingBufferUsageError),
114 #[error(transparent)]
115 MissingTextureUsage(#[from] MissingTextureUsageError),
116 #[error(transparent)]
117 ImmediateData(#[from] ImmediateUploadError),
118 #[error(transparent)]
119 BindingError(#[from] BindingError),
120 #[error("Viewport size {{ w: {w}, h: {h} }} greater than device's requested `max_texture_dimension_2d` limit {max}, or less than zero")]
121 InvalidViewportRectSize { w: f32, h: f32, max: u32 },
122 #[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})")]
123 InvalidViewportRectPosition { rect: Rect<f32>, min: f32, max: f32 },
124 #[error("Viewport minDepth {0} and/or maxDepth {1} are not in [0, 1]")]
125 InvalidViewportDepth(f32, f32),
126 #[error("Scissor {0:?} is not contained in the render target {1:?}")]
127 InvalidScissorRect(Rect<u32>, wgt::Extent3d),
128 #[error("Support for {0} is not implemented yet")]
129 Unimplemented(&'static str),
130}
131
132impl WebGpuError for RenderCommandError {
133 fn webgpu_error_type(&self) -> ErrorType {
134 match self {
135 Self::IncompatiblePipelineTargets(e) => e.webgpu_error_type(),
136 Self::ResourceUsageCompatibility(e) => e.webgpu_error_type(),
137 Self::DestroyedResource(e) => e.webgpu_error_type(),
138 Self::MissingBufferUsage(e) => e.webgpu_error_type(),
139 Self::MissingTextureUsage(e) => e.webgpu_error_type(),
140 Self::ImmediateData(e) => e.webgpu_error_type(),
141 Self::BindingError(e) => e.webgpu_error_type(),
142
143 Self::BindGroupIndexOutOfRange { .. }
144 | Self::VertexBufferIndexOutOfRange { .. }
145 | Self::UnalignedIndexBuffer { .. }
146 | Self::UnalignedVertexBuffer { .. }
147 | Self::IncompatibleDepthAccess(..)
148 | Self::IncompatibleStencilAccess(..)
149 | Self::InvalidViewportRectSize { .. }
150 | Self::InvalidViewportRectPosition { .. }
151 | Self::InvalidViewportDepth(..)
152 | Self::InvalidScissorRect(..)
153 | Self::Unimplemented(..) => ErrorType::Validation,
154 }
155 }
156}
157
158#[derive(Clone, Copy, Debug, Default)]
159#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
160pub struct Rect<T> {
161 pub x: T,
162 pub y: T,
163 pub w: T,
164 pub h: T,
165}