wgpu_core/command/
draw.rs

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/// Error validating a draw call.
20#[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/// Error encountered when encoding a render command.
88/// This is the shared error set between render bundles and passes.
89#[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}