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::{
10    binding_model::{BindingError, ImmediateUploadError, LateMinBufferBindingSizeMismatch},
11    resource::{
12        DestroyedResourceError, MissingBufferUsageError, MissingTextureUsageError,
13        ResourceErrorIdent,
14    },
15    track::ResourceUsageCompatibilityError,
16};
17
18/// Error validating a draw call.
19#[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("For indexed drawing with strip topology, {pipeline}'s strip index format {strip_index_format:?} must match index buffer format {buffer_format:?}")]
50    UnmatchedStripIndexFormat {
51        pipeline: ResourceErrorIdent,
52        strip_index_format: Option<wgt::IndexFormat>,
53        buffer_format: wgt::IndexFormat,
54    },
55    #[error(transparent)]
56    BindingSizeTooSmall(#[from] LateMinBufferBindingSizeMismatch),
57    #[error(
58        "Wrong pipeline type for this draw command. Attempted to call {} draw command on {} pipeline",
59        if *wanted_mesh_pipeline {"mesh shader"} else {"standard"},
60        if *wanted_mesh_pipeline {"standard"} else {"mesh shader"},
61    )]
62    WrongPipelineType { wanted_mesh_pipeline: bool },
63    #[error(
64        "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}"
65    )]
66    InvalidGroupSize {
67        current: [u32; 3],
68        limit: u32,
69        max_total: u32,
70    },
71    #[error(
72        "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})"
73    )]
74    MeshPipelineMultiviewLimitsViolated {
75        highest_view_index: u32,
76        max_multiviews: u32,
77    },
78}
79
80impl WebGpuError for DrawError {
81    fn webgpu_error_type(&self) -> ErrorType {
82        ErrorType::Validation
83    }
84}
85
86/// Error encountered when encoding a render command.
87/// This is the shared error set between render bundles and passes.
88#[derive(Clone, Debug, Error)]
89#[non_exhaustive]
90pub enum RenderCommandError {
91    #[error(transparent)]
92    BindGroupIndexOutOfRange(#[from] pass::BindGroupIndexOutOfRange),
93    #[error("Vertex buffer index {index} is greater than the device's requested `max_vertex_buffers` limit {max}")]
94    VertexBufferIndexOutOfRange { index: u32, max: u32 },
95    #[error(
96        "Offset {offset} for vertex buffer in slot {slot} is not a multiple of `VERTEX_ALIGNMENT`"
97    )]
98    UnalignedVertexBuffer { slot: u32, offset: u64 },
99    #[error("Offset {offset} for index buffer is not a multiple of {alignment}")]
100    UnalignedIndexBuffer { offset: u64, alignment: usize },
101    #[error("Render pipeline targets are incompatible with render pass")]
102    IncompatiblePipelineTargets(#[from] crate::device::RenderPassCompatibilityError),
103    #[error("{0} writes to depth, while the pass has read-only depth access")]
104    IncompatibleDepthAccess(ResourceErrorIdent),
105    #[error("{0} writes to stencil, while the pass has read-only stencil access")]
106    IncompatibleStencilAccess(ResourceErrorIdent),
107    #[error(transparent)]
108    ResourceUsageCompatibility(#[from] ResourceUsageCompatibilityError),
109    #[error(transparent)]
110    DestroyedResource(#[from] DestroyedResourceError),
111    #[error(transparent)]
112    MissingBufferUsage(#[from] MissingBufferUsageError),
113    #[error(transparent)]
114    MissingTextureUsage(#[from] MissingTextureUsageError),
115    #[error(transparent)]
116    ImmediateData(#[from] ImmediateUploadError),
117    #[error(transparent)]
118    BindingError(#[from] BindingError),
119    #[error("Viewport size {{ w: {w}, h: {h} }} greater than device's requested `max_texture_dimension_2d` limit {max}, or less than zero")]
120    InvalidViewportRectSize { w: f32, h: f32, max: u32 },
121    #[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})")]
122    InvalidViewportRectPosition { rect: Rect<f32>, min: f32, max: f32 },
123    #[error("Viewport minDepth {0} and/or maxDepth {1} are not in [0, 1]")]
124    InvalidViewportDepth(f32, f32),
125    #[error("Scissor {0:?} is not contained in the render target {1:?}")]
126    InvalidScissorRect(Rect<u32>, wgt::Extent3d),
127    #[error("Support for {0} is not implemented yet")]
128    Unimplemented(&'static str),
129}
130
131impl WebGpuError for RenderCommandError {
132    fn webgpu_error_type(&self) -> ErrorType {
133        let e: &dyn WebGpuError = match self {
134            Self::IncompatiblePipelineTargets(e) => e,
135            Self::ResourceUsageCompatibility(e) => e,
136            Self::DestroyedResource(e) => e,
137            Self::MissingBufferUsage(e) => e,
138            Self::MissingTextureUsage(e) => e,
139            Self::ImmediateData(e) => e,
140            Self::BindingError(e) => e,
141
142            Self::BindGroupIndexOutOfRange { .. }
143            | Self::VertexBufferIndexOutOfRange { .. }
144            | Self::UnalignedIndexBuffer { .. }
145            | Self::UnalignedVertexBuffer { .. }
146            | Self::IncompatibleDepthAccess(..)
147            | Self::IncompatibleStencilAccess(..)
148            | Self::InvalidViewportRectSize { .. }
149            | Self::InvalidViewportRectPosition { .. }
150            | Self::InvalidViewportDepth(..)
151            | Self::InvalidScissorRect(..)
152            | Self::Unimplemented(..) => return ErrorType::Validation,
153        };
154        e.webgpu_error_type()
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}