1use crate::{
5 binding_model::{LateMinBufferBindingSizeMismatch, PushConstantUploadError},
6 error::ErrorFormatter,
7 id,
8 track::UsageConflict,
9 validation::{MissingBufferUsageError, MissingTextureUsageError},
10};
11use wgt::{BufferAddress, BufferSize, Color};
12
13use std::num::NonZeroU32;
14use thiserror::Error;
15
16#[derive(Clone, Debug, Error, Eq, PartialEq)]
18#[non_exhaustive]
19pub enum DrawError {
20 #[error("Blend constant needs to be set")]
21 MissingBlendConstant,
22 #[error("Render pipeline must be set")]
23 MissingPipeline,
24 #[error("Vertex buffer {index} must be set")]
25 MissingVertexBuffer { index: u32 },
26 #[error("Index buffer must be set")]
27 MissingIndexBuffer,
28 #[error("The pipeline layout, associated with the current render pipeline, contains a bind group layout at index {index} which is incompatible with the bind group layout associated with the bind group at {index}")]
29 IncompatibleBindGroup {
30 index: u32,
31 },
34 #[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?")]
35 VertexBeyondLimit {
36 last_vertex: u32,
37 vertex_limit: u32,
38 slot: u32,
39 },
40 #[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?")]
41 InstanceBeyondLimit {
42 last_instance: u32,
43 instance_limit: u32,
44 slot: u32,
45 },
46 #[error("Index {last_index} extends beyond limit {index_limit}. Did you bind the correct index buffer?")]
47 IndexBeyondLimit { last_index: u32, index_limit: u32 },
48 #[error(
49 "Pipeline index format ({pipeline:?}) and buffer index format ({buffer:?}) do not match"
50 )]
51 UnmatchedIndexFormats {
52 pipeline: wgt::IndexFormat,
53 buffer: wgt::IndexFormat,
54 },
55 #[error(transparent)]
56 BindingSizeTooSmall(#[from] LateMinBufferBindingSizeMismatch),
57}
58
59#[derive(Clone, Debug, Error)]
62#[non_exhaustive]
63pub enum RenderCommandError {
64 #[error("Bind group {0:?} is invalid")]
65 InvalidBindGroup(id::BindGroupId),
66 #[error("Render bundle {0:?} is invalid")]
67 InvalidRenderBundle(id::RenderBundleId),
68 #[error("Bind group index {index} is greater than the device's requested `max_bind_group` limit {max}")]
69 BindGroupIndexOutOfRange { index: u32, max: u32 },
70 #[error("Dynamic buffer offset {0} does not respect device's requested `{1}` limit {2}")]
71 UnalignedBufferOffset(u64, &'static str, u32),
72 #[error("Number of buffer offsets ({actual}) does not match the number of dynamic bindings ({expected})")]
73 InvalidDynamicOffsetCount { actual: usize, expected: usize },
74 #[error("Render pipeline {0:?} is invalid")]
75 InvalidPipeline(id::RenderPipelineId),
76 #[error("QuerySet {0:?} is invalid")]
77 InvalidQuerySet(id::QuerySetId),
78 #[error("Render pipeline targets are incompatible with render pass")]
79 IncompatiblePipelineTargets(#[from] crate::device::RenderPassCompatibilityError),
80 #[error("Pipeline writes to depth/stencil, while the pass has read-only depth/stencil")]
81 IncompatiblePipelineRods,
82 #[error(transparent)]
83 UsageConflict(#[from] UsageConflict),
84 #[error("Buffer {0:?} is destroyed")]
85 DestroyedBuffer(id::BufferId),
86 #[error(transparent)]
87 MissingBufferUsage(#[from] MissingBufferUsageError),
88 #[error(transparent)]
89 MissingTextureUsage(#[from] MissingTextureUsageError),
90 #[error(transparent)]
91 PushConstants(#[from] PushConstantUploadError),
92 #[error("Viewport width {0} and/or height {1} are less than or equal to 0")]
93 InvalidViewportDimension(f32, f32),
94 #[error("Viewport minDepth {0} and/or maxDepth {1} are not in [0, 1]")]
95 InvalidViewportDepth(f32, f32),
96 #[error("Scissor {0:?} is not contained in the render target {1:?}")]
97 InvalidScissorRect(Rect<u32>, wgt::Extent3d),
98 #[error("Support for {0} is not implemented yet")]
99 Unimplemented(&'static str),
100}
101impl crate::error::PrettyError for RenderCommandError {
102 fn fmt_pretty(&self, fmt: &mut ErrorFormatter) {
103 fmt.error(self);
104 match *self {
105 Self::InvalidBindGroup(id) => {
106 fmt.bind_group_label(&id);
107 }
108 Self::InvalidPipeline(id) => {
109 fmt.render_pipeline_label(&id);
110 }
111 Self::UsageConflict(UsageConflict::TextureInvalid { id }) => {
112 fmt.texture_label(&id);
113 }
114 Self::UsageConflict(UsageConflict::BufferInvalid { id })
115 | Self::DestroyedBuffer(id) => {
116 fmt.buffer_label(&id);
117 }
118 _ => {}
119 };
120 }
121}
122
123#[derive(Clone, Copy, Debug, Default)]
124#[cfg_attr(
125 any(feature = "serial-pass", feature = "trace"),
126 derive(serde::Serialize)
127)]
128#[cfg_attr(
129 any(feature = "serial-pass", feature = "replay"),
130 derive(serde::Deserialize)
131)]
132pub struct Rect<T> {
133 pub x: T,
134 pub y: T,
135 pub w: T,
136 pub h: T,
137}
138
139#[doc(hidden)]
140#[derive(Clone, Copy, Debug)]
141#[cfg_attr(
142 any(feature = "serial-pass", feature = "trace"),
143 derive(serde::Serialize)
144)]
145#[cfg_attr(
146 any(feature = "serial-pass", feature = "replay"),
147 derive(serde::Deserialize)
148)]
149pub enum RenderCommand {
150 SetBindGroup {
151 index: u32,
152 num_dynamic_offsets: u8,
153 bind_group_id: id::BindGroupId,
154 },
155 SetPipeline(id::RenderPipelineId),
156 SetIndexBuffer {
157 buffer_id: id::BufferId,
158 index_format: wgt::IndexFormat,
159 offset: BufferAddress,
160 size: Option<BufferSize>,
161 },
162 SetVertexBuffer {
163 slot: u32,
164 buffer_id: id::BufferId,
165 offset: BufferAddress,
166 size: Option<BufferSize>,
167 },
168 SetBlendConstant(Color),
169 SetStencilReference(u32),
170 SetViewport {
171 rect: Rect<f32>,
172 depth_min: f32,
174 depth_max: f32,
175 },
176 SetScissor(Rect<u32>),
177
178 SetPushConstant {
183 stages: wgt::ShaderStages,
185
186 offset: u32,
189
190 size_bytes: u32,
192
193 values_offset: Option<u32>,
204 },
205 Draw {
206 vertex_count: u32,
207 instance_count: u32,
208 first_vertex: u32,
209 first_instance: u32,
210 },
211 DrawIndexed {
212 index_count: u32,
213 instance_count: u32,
214 first_index: u32,
215 base_vertex: i32,
216 first_instance: u32,
217 },
218 MultiDrawIndirect {
219 buffer_id: id::BufferId,
220 offset: BufferAddress,
221 count: Option<NonZeroU32>,
223 indexed: bool,
224 },
225 MultiDrawIndirectCount {
226 buffer_id: id::BufferId,
227 offset: BufferAddress,
228 count_buffer_id: id::BufferId,
229 count_buffer_offset: BufferAddress,
230 max_count: u32,
231 indexed: bool,
232 },
233 PushDebugGroup {
234 color: u32,
235 len: usize,
236 },
237 PopDebugGroup,
238 InsertDebugMarker {
239 color: u32,
240 len: usize,
241 },
242 WriteTimestamp {
243 query_set_id: id::QuerySetId,
244 query_index: u32,
245 },
246 BeginPipelineStatisticsQuery {
247 query_set_id: id::QuerySetId,
248 query_index: u32,
249 },
250 EndPipelineStatisticsQuery,
251 ExecuteBundle(id::RenderBundleId),
252}