1use crate::{
5 binding_model::{BindGroup, LateMinBufferBindingSizeMismatch, PushConstantUploadError},
6 error::ErrorFormatter,
7 hal_api::HalApi,
8 id,
9 pipeline::RenderPipeline,
10 resource::{Buffer, QuerySet},
11 track::UsageConflict,
12 validation::{MissingBufferUsageError, MissingTextureUsageError},
13};
14use wgt::{BufferAddress, BufferSize, Color, VertexStepMode};
15
16use std::{num::NonZeroU32, sync::Arc};
17use thiserror::Error;
18
19use super::RenderBundle;
20
21#[derive(Clone, Debug, Error, Eq, PartialEq)]
23#[non_exhaustive]
24pub enum DrawError {
25 #[error("Blend constant needs to be set")]
26 MissingBlendConstant,
27 #[error("Render pipeline must be set")]
28 MissingPipeline,
29 #[error("Vertex buffer {index} must be set")]
30 MissingVertexBuffer { index: u32 },
31 #[error("Index buffer must be set")]
32 MissingIndexBuffer,
33 #[error("Incompatible bind group at index {index} in the current render pipeline")]
34 IncompatibleBindGroup { index: u32, diff: Vec<String> },
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("{step_mode:?} buffer out of bounds at slot {slot}. Offset {offset} beyond limit {limit}. Did you bind the correct `Vertex` step-rate vertex buffer?")]
42 VertexOutOfBounds {
43 step_mode: VertexStepMode,
44 offset: u64,
45 limit: u64,
46 slot: u32,
47 },
48 #[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?")]
49 InstanceBeyondLimit {
50 last_instance: u64,
51 instance_limit: u64,
52 slot: u32,
53 },
54 #[error("Index {last_index} extends beyond limit {index_limit}. Did you bind the correct index buffer?")]
55 IndexBeyondLimit { last_index: u64, index_limit: u64 },
56 #[error(
57 "Pipeline index format ({pipeline:?}) and buffer index format ({buffer:?}) do not match"
58 )]
59 UnmatchedIndexFormats {
60 pipeline: wgt::IndexFormat,
61 buffer: wgt::IndexFormat,
62 },
63 #[error(transparent)]
64 BindingSizeTooSmall(#[from] LateMinBufferBindingSizeMismatch),
65}
66
67#[derive(Clone, Debug, Error)]
70#[non_exhaustive]
71pub enum RenderCommandError {
72 #[error("Bind group {0:?} is invalid")]
73 InvalidBindGroup(id::BindGroupId),
74 #[error("Render bundle {0:?} is invalid")]
75 InvalidRenderBundle(id::RenderBundleId),
76 #[error("Bind group index {index} is greater than the device's requested `max_bind_group` limit {max}")]
77 BindGroupIndexOutOfRange { index: u32, max: u32 },
78 #[error("Vertex buffer index {index} is greater than the device's requested `max_vertex_buffers` limit {max}")]
79 VertexBufferIndexOutOfRange { index: u32, max: u32 },
80 #[error("Dynamic buffer offset {0} does not respect device's requested `{1}` limit {2}")]
81 UnalignedBufferOffset(u64, &'static str, u32),
82 #[error("Number of buffer offsets ({actual}) does not match the number of dynamic bindings ({expected})")]
83 InvalidDynamicOffsetCount { actual: usize, expected: usize },
84 #[error("Render pipeline {0:?} is invalid")]
85 InvalidPipeline(id::RenderPipelineId),
86 #[error("QuerySet {0:?} is invalid")]
87 InvalidQuerySet(id::QuerySetId),
88 #[error("Render pipeline targets are incompatible with render pass")]
89 IncompatiblePipelineTargets(#[from] crate::device::RenderPassCompatibilityError),
90 #[error("Pipeline writes to depth/stencil, while the pass has read-only depth/stencil")]
91 IncompatiblePipelineRods,
92 #[error(transparent)]
93 UsageConflict(#[from] UsageConflict),
94 #[error("Buffer {0:?} is destroyed")]
95 DestroyedBuffer(id::BufferId),
96 #[error(transparent)]
97 MissingBufferUsage(#[from] MissingBufferUsageError),
98 #[error(transparent)]
99 MissingTextureUsage(#[from] MissingTextureUsageError),
100 #[error(transparent)]
101 PushConstants(#[from] PushConstantUploadError),
102 #[error("Viewport has invalid rect {0:?}; origin and/or size is less than or equal to 0, and/or is not contained in the render target {1:?}")]
103 InvalidViewportRect(Rect<f32>, wgt::Extent3d),
104 #[error("Viewport minDepth {0} and/or maxDepth {1} are not in [0, 1]")]
105 InvalidViewportDepth(f32, f32),
106 #[error("Scissor {0:?} is not contained in the render target {1:?}")]
107 InvalidScissorRect(Rect<u32>, wgt::Extent3d),
108 #[error("Support for {0} is not implemented yet")]
109 Unimplemented(&'static str),
110}
111impl crate::error::PrettyError for RenderCommandError {
112 fn fmt_pretty(&self, fmt: &mut ErrorFormatter) {
113 fmt.error(self);
114 match *self {
115 Self::InvalidBindGroup(id) => {
116 fmt.bind_group_label(&id);
117 }
118 Self::InvalidPipeline(id) => {
119 fmt.render_pipeline_label(&id);
120 }
121 Self::UsageConflict(UsageConflict::TextureInvalid { id }) => {
122 fmt.texture_label(&id);
123 }
124 Self::UsageConflict(UsageConflict::BufferInvalid { id })
125 | Self::DestroyedBuffer(id) => {
126 fmt.buffer_label(&id);
127 }
128 _ => {}
129 };
130 }
131}
132
133#[derive(Clone, Copy, Debug, Default)]
134#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
135pub struct Rect<T> {
136 pub x: T,
137 pub y: T,
138 pub w: T,
139 pub h: T,
140}
141
142#[doc(hidden)]
143#[derive(Clone, Copy, Debug)]
144#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
145pub enum RenderCommand {
146 SetBindGroup {
147 index: u32,
148 num_dynamic_offsets: usize,
149 bind_group_id: id::BindGroupId,
150 },
151 SetPipeline(id::RenderPipelineId),
152 SetIndexBuffer {
153 buffer_id: id::BufferId,
154 index_format: wgt::IndexFormat,
155 offset: BufferAddress,
156 size: Option<BufferSize>,
157 },
158 SetVertexBuffer {
159 slot: u32,
160 buffer_id: id::BufferId,
161 offset: BufferAddress,
162 size: Option<BufferSize>,
163 },
164 SetBlendConstant(Color),
165 SetStencilReference(u32),
166 SetViewport {
167 rect: Rect<f32>,
168 depth_min: f32,
170 depth_max: f32,
171 },
172 SetScissor(Rect<u32>),
173
174 SetPushConstant {
179 stages: wgt::ShaderStages,
181
182 offset: u32,
185
186 size_bytes: u32,
188
189 values_offset: Option<u32>,
200 },
201 Draw {
202 vertex_count: u32,
203 instance_count: u32,
204 first_vertex: u32,
205 first_instance: u32,
206 },
207 DrawIndexed {
208 index_count: u32,
209 instance_count: u32,
210 first_index: u32,
211 base_vertex: i32,
212 first_instance: u32,
213 },
214 MultiDrawIndirect {
215 buffer_id: id::BufferId,
216 offset: BufferAddress,
217 count: Option<NonZeroU32>,
219 indexed: bool,
220 },
221 MultiDrawIndirectCount {
222 buffer_id: id::BufferId,
223 offset: BufferAddress,
224 count_buffer_id: id::BufferId,
225 count_buffer_offset: BufferAddress,
226 max_count: u32,
227 indexed: bool,
228 },
229 PushDebugGroup {
230 color: u32,
231 len: usize,
232 },
233 PopDebugGroup,
234 InsertDebugMarker {
235 color: u32,
236 len: usize,
237 },
238 WriteTimestamp {
239 query_set_id: id::QuerySetId,
240 query_index: u32,
241 },
242 BeginOcclusionQuery {
243 query_index: u32,
244 },
245 EndOcclusionQuery,
246 BeginPipelineStatisticsQuery {
247 query_set_id: id::QuerySetId,
248 query_index: u32,
249 },
250 EndPipelineStatisticsQuery,
251 ExecuteBundle(id::RenderBundleId),
252}
253
254#[doc(hidden)]
256#[derive(Clone, Debug)]
257pub enum ArcRenderCommand<A: HalApi> {
258 SetBindGroup {
259 index: u32,
260 num_dynamic_offsets: usize,
261 bind_group: Arc<BindGroup<A>>,
262 },
263 SetPipeline(Arc<RenderPipeline<A>>),
264 SetIndexBuffer {
265 buffer: Arc<Buffer<A>>,
266 index_format: wgt::IndexFormat,
267 offset: BufferAddress,
268 size: Option<BufferSize>,
269 },
270 SetVertexBuffer {
271 slot: u32,
272 buffer: Arc<Buffer<A>>,
273 offset: BufferAddress,
274 size: Option<BufferSize>,
275 },
276 SetBlendConstant(Color),
277 SetStencilReference(u32),
278 SetViewport {
279 rect: Rect<f32>,
280 depth_min: f32,
281 depth_max: f32,
282 },
283 SetScissor(Rect<u32>),
284
285 SetPushConstant {
290 stages: wgt::ShaderStages,
292
293 offset: u32,
296
297 size_bytes: u32,
299
300 values_offset: Option<u32>,
311 },
312 Draw {
313 vertex_count: u32,
314 instance_count: u32,
315 first_vertex: u32,
316 first_instance: u32,
317 },
318 DrawIndexed {
319 index_count: u32,
320 instance_count: u32,
321 first_index: u32,
322 base_vertex: i32,
323 first_instance: u32,
324 },
325 MultiDrawIndirect {
326 buffer: Arc<Buffer<A>>,
327 offset: BufferAddress,
328 count: Option<NonZeroU32>,
330 indexed: bool,
331 },
332 MultiDrawIndirectCount {
333 buffer: Arc<Buffer<A>>,
334 offset: BufferAddress,
335 count_buffer: Arc<Buffer<A>>,
336 count_buffer_offset: BufferAddress,
337 max_count: u32,
338 indexed: bool,
339 },
340 PushDebugGroup {
341 color: u32,
342 len: usize,
343 },
344 PopDebugGroup,
345 InsertDebugMarker {
346 color: u32,
347 len: usize,
348 },
349 WriteTimestamp {
350 query_set: Arc<QuerySet<A>>,
351 query_index: u32,
352 },
353 BeginOcclusionQuery {
354 query_index: u32,
355 },
356 EndOcclusionQuery,
357 BeginPipelineStatisticsQuery {
358 query_set: Arc<QuerySet<A>>,
359 query_index: u32,
360 },
361 EndPipelineStatisticsQuery,
362 ExecuteBundle(Arc<RenderBundle<A>>),
363}