1 /*! Draw structures - shared between render passes and bundles. 2 !*/ 3 4 use crate::{ 5 binding_model::{LateMinBufferBindingSizeMismatch, PushConstantUploadError}, 6 error::ErrorFormatter, 7 id, 8 track::UseExtendError, 9 validation::{MissingBufferUsageError, MissingTextureUsageError}, 10 }; 11 use wgt::{BufferAddress, BufferSize, Color}; 12 13 use std::num::NonZeroU32; 14 use thiserror::Error; 15 16 pub type BufferError = UseExtendError<hal::BufferUses>; 17 18 /// Error validating a draw call. 19 #[derive(Clone, Debug, Error, PartialEq)] 20 pub enum DrawError { 21 #[error("blend constant needs to be set")] 22 MissingBlendConstant, 23 #[error("render pipeline must be set")] 24 MissingPipeline, 25 #[error("vertex buffer {index} must be set")] 26 MissingVertexBuffer { index: u32 }, 27 #[error("index buffer must be set")] 28 MissingIndexBuffer, 29 #[error("current render pipeline has a layout which is incompatible with a currently set bind group, first differing at entry index {index}")] 30 IncompatibleBindGroup { 31 index: u32, 32 //expected: BindGroupLayoutId, 33 //provided: Option<(BindGroupLayoutId, BindGroupId)>, 34 }, 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: u32, 38 vertex_limit: u32, 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: u32, 44 instance_limit: u32, 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: u32, index_limit: u32 }, 49 #[error( 50 "pipeline index format ({pipeline:?}) and buffer index format ({buffer:?}) do not match" 51 )] 52 UnmatchedIndexFormats { 53 pipeline: wgt::IndexFormat, 54 buffer: wgt::IndexFormat, 55 }, 56 #[error(transparent)] 57 BindingSizeTooSmall(#[from] LateMinBufferBindingSizeMismatch), 58 } 59 60 /// Error encountered when encoding a render command. 61 /// This is the shared error set between render bundles and passes. 62 #[derive(Clone, Debug, Error)] 63 pub 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: u8, 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("buffer {0:?} is in error {1:?}")] 83 Buffer(id::BufferId, BufferError), 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("Invalid Viewport parameters")] 93 InvalidViewport, 94 #[error("Invalid ScissorRect parameters")] 95 InvalidScissorRect, 96 #[error("Support for {0} is not implemented yet")] 97 Unimplemented(&'static str), 98 } 99 impl crate::error::PrettyError for RenderCommandError { fmt_pretty(&self, fmt: &mut ErrorFormatter)100 fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { 101 fmt.error(self); 102 match *self { 103 Self::InvalidBindGroup(id) => { 104 fmt.bind_group_label(&id); 105 } 106 Self::InvalidPipeline(id) => { 107 fmt.render_pipeline_label(&id); 108 } 109 Self::Buffer(id, ..) | Self::DestroyedBuffer(id) => { 110 fmt.buffer_label(&id); 111 } 112 _ => {} 113 }; 114 } 115 } 116 117 #[derive(Clone, Copy, Debug, Default)] 118 #[cfg_attr( 119 any(feature = "serial-pass", feature = "trace"), 120 derive(serde::Serialize) 121 )] 122 #[cfg_attr( 123 any(feature = "serial-pass", feature = "replay"), 124 derive(serde::Deserialize) 125 )] 126 pub struct Rect<T> { 127 pub x: T, 128 pub y: T, 129 pub w: T, 130 pub h: T, 131 } 132 133 #[doc(hidden)] 134 #[derive(Clone, Copy, Debug)] 135 #[cfg_attr( 136 any(feature = "serial-pass", feature = "trace"), 137 derive(serde::Serialize) 138 )] 139 #[cfg_attr( 140 any(feature = "serial-pass", feature = "replay"), 141 derive(serde::Deserialize) 142 )] 143 pub enum RenderCommand { 144 SetBindGroup { 145 index: u8, 146 num_dynamic_offsets: u8, 147 bind_group_id: id::BindGroupId, 148 }, 149 SetPipeline(id::RenderPipelineId), 150 SetIndexBuffer { 151 buffer_id: id::BufferId, 152 index_format: wgt::IndexFormat, 153 offset: BufferAddress, 154 size: Option<BufferSize>, 155 }, 156 SetVertexBuffer { 157 slot: u32, 158 buffer_id: id::BufferId, 159 offset: BufferAddress, 160 size: Option<BufferSize>, 161 }, 162 SetBlendConstant(Color), 163 SetStencilReference(u32), 164 SetViewport { 165 rect: Rect<f32>, 166 //TODO: use half-float to reduce the size? 167 depth_min: f32, 168 depth_max: f32, 169 }, 170 SetScissor(Rect<u32>), 171 SetPushConstant { 172 stages: wgt::ShaderStages, 173 offset: u32, 174 size_bytes: u32, 175 /// None means there is no data and the data should be an array of zeros. 176 /// 177 /// Facilitates clears in renderbundles which explicitly do their clears. 178 values_offset: Option<u32>, 179 }, 180 Draw { 181 vertex_count: u32, 182 instance_count: u32, 183 first_vertex: u32, 184 first_instance: u32, 185 }, 186 DrawIndexed { 187 index_count: u32, 188 instance_count: u32, 189 first_index: u32, 190 base_vertex: i32, 191 first_instance: u32, 192 }, 193 MultiDrawIndirect { 194 buffer_id: id::BufferId, 195 offset: BufferAddress, 196 /// Count of `None` represents a non-multi call. 197 count: Option<NonZeroU32>, 198 indexed: bool, 199 }, 200 MultiDrawIndirectCount { 201 buffer_id: id::BufferId, 202 offset: BufferAddress, 203 count_buffer_id: id::BufferId, 204 count_buffer_offset: BufferAddress, 205 max_count: u32, 206 indexed: bool, 207 }, 208 PushDebugGroup { 209 color: u32, 210 len: usize, 211 }, 212 PopDebugGroup, 213 InsertDebugMarker { 214 color: u32, 215 len: usize, 216 }, 217 WriteTimestamp { 218 query_set_id: id::QuerySetId, 219 query_index: u32, 220 }, 221 BeginPipelineStatisticsQuery { 222 query_set_id: id::QuerySetId, 223 query_index: u32, 224 }, 225 EndPipelineStatisticsQuery, 226 ExecuteBundle(id::RenderBundleId), 227 } 228