diff options
Diffstat (limited to 'third_party/rust/wgpu-core/src/command/draw.rs')
-rw-r--r-- | third_party/rust/wgpu-core/src/command/draw.rs | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/third_party/rust/wgpu-core/src/command/draw.rs b/third_party/rust/wgpu-core/src/command/draw.rs new file mode 100644 index 0000000000..e03a78ee93 --- /dev/null +++ b/third_party/rust/wgpu-core/src/command/draw.rs @@ -0,0 +1,247 @@ +/*! Draw structures - shared between render passes and bundles. +!*/ + +use crate::{ + binding_model::{LateMinBufferBindingSizeMismatch, PushConstantUploadError}, + error::ErrorFormatter, + id, + track::UsageConflict, + validation::{MissingBufferUsageError, MissingTextureUsageError}, +}; +use wgt::{BufferAddress, BufferSize, Color, VertexStepMode}; + +use std::num::NonZeroU32; +use thiserror::Error; + +/// Error validating a draw call. +#[derive(Clone, Debug, Error, Eq, PartialEq)] +#[non_exhaustive] +pub enum DrawError { + #[error("Blend constant needs to be set")] + MissingBlendConstant, + #[error("Render pipeline must be set")] + MissingPipeline, + #[error("Vertex buffer {index} must be set")] + MissingVertexBuffer { index: u32 }, + #[error("Index buffer must be set")] + MissingIndexBuffer, + #[error("Incompatible bind group at index {index} in the current render pipeline")] + IncompatibleBindGroup { index: u32, diff: Vec<String> }, + #[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?")] + VertexBeyondLimit { + last_vertex: u64, + vertex_limit: u64, + slot: u32, + }, + #[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?")] + VertexOutOfBounds { + step_mode: VertexStepMode, + offset: u64, + limit: u64, + slot: u32, + }, + #[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?")] + InstanceBeyondLimit { + last_instance: u64, + instance_limit: u64, + slot: u32, + }, + #[error("Index {last_index} extends beyond limit {index_limit}. Did you bind the correct index buffer?")] + IndexBeyondLimit { last_index: u64, index_limit: u64 }, + #[error( + "Pipeline index format ({pipeline:?}) and buffer index format ({buffer:?}) do not match" + )] + UnmatchedIndexFormats { + pipeline: wgt::IndexFormat, + buffer: wgt::IndexFormat, + }, + #[error(transparent)] + BindingSizeTooSmall(#[from] LateMinBufferBindingSizeMismatch), +} + +/// Error encountered when encoding a render command. +/// This is the shared error set between render bundles and passes. +#[derive(Clone, Debug, Error)] +#[non_exhaustive] +pub enum RenderCommandError { + #[error("Bind group {0:?} is invalid")] + InvalidBindGroup(id::BindGroupId), + #[error("Render bundle {0:?} is invalid")] + InvalidRenderBundle(id::RenderBundleId), + #[error("Bind group index {index} is greater than the device's requested `max_bind_group` limit {max}")] + BindGroupIndexOutOfRange { index: u32, max: u32 }, + #[error("Vertex buffer index {index} is greater than the device's requested `max_vertex_buffers` limit {max}")] + VertexBufferIndexOutOfRange { index: u32, max: u32 }, + #[error("Dynamic buffer offset {0} does not respect device's requested `{1}` limit {2}")] + UnalignedBufferOffset(u64, &'static str, u32), + #[error("Number of buffer offsets ({actual}) does not match the number of dynamic bindings ({expected})")] + InvalidDynamicOffsetCount { actual: usize, expected: usize }, + #[error("Render pipeline {0:?} is invalid")] + InvalidPipeline(id::RenderPipelineId), + #[error("QuerySet {0:?} is invalid")] + InvalidQuerySet(id::QuerySetId), + #[error("Render pipeline targets are incompatible with render pass")] + IncompatiblePipelineTargets(#[from] crate::device::RenderPassCompatibilityError), + #[error("Pipeline writes to depth/stencil, while the pass has read-only depth/stencil")] + IncompatiblePipelineRods, + #[error(transparent)] + UsageConflict(#[from] UsageConflict), + #[error("Buffer {0:?} is destroyed")] + DestroyedBuffer(id::BufferId), + #[error(transparent)] + MissingBufferUsage(#[from] MissingBufferUsageError), + #[error(transparent)] + MissingTextureUsage(#[from] MissingTextureUsageError), + #[error(transparent)] + PushConstants(#[from] PushConstantUploadError), + #[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:?}")] + InvalidViewportRect(Rect<f32>, wgt::Extent3d), + #[error("Viewport minDepth {0} and/or maxDepth {1} are not in [0, 1]")] + InvalidViewportDepth(f32, f32), + #[error("Scissor {0:?} is not contained in the render target {1:?}")] + InvalidScissorRect(Rect<u32>, wgt::Extent3d), + #[error("Support for {0} is not implemented yet")] + Unimplemented(&'static str), +} +impl crate::error::PrettyError for RenderCommandError { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + fmt.error(self); + match *self { + Self::InvalidBindGroup(id) => { + fmt.bind_group_label(&id); + } + Self::InvalidPipeline(id) => { + fmt.render_pipeline_label(&id); + } + Self::UsageConflict(UsageConflict::TextureInvalid { id }) => { + fmt.texture_label(&id); + } + Self::UsageConflict(UsageConflict::BufferInvalid { id }) + | Self::DestroyedBuffer(id) => { + fmt.buffer_label(&id); + } + _ => {} + }; + } +} + +#[derive(Clone, Copy, Debug, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct Rect<T> { + pub x: T, + pub y: T, + pub w: T, + pub h: T, +} + +#[doc(hidden)] +#[derive(Clone, Copy, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum RenderCommand { + SetBindGroup { + index: u32, + num_dynamic_offsets: usize, + bind_group_id: id::BindGroupId, + }, + SetPipeline(id::RenderPipelineId), + SetIndexBuffer { + buffer_id: id::BufferId, + index_format: wgt::IndexFormat, + offset: BufferAddress, + size: Option<BufferSize>, + }, + SetVertexBuffer { + slot: u32, + buffer_id: id::BufferId, + offset: BufferAddress, + size: Option<BufferSize>, + }, + SetBlendConstant(Color), + SetStencilReference(u32), + SetViewport { + rect: Rect<f32>, + //TODO: use half-float to reduce the size? + depth_min: f32, + depth_max: f32, + }, + SetScissor(Rect<u32>), + + /// Set a range of push constants to values stored in [`BasePass::push_constant_data`]. + /// + /// See [`wgpu::RenderPass::set_push_constants`] for a detailed explanation + /// of the restrictions these commands must satisfy. + SetPushConstant { + /// Which stages we are setting push constant values for. + stages: wgt::ShaderStages, + + /// The byte offset within the push constant storage to write to. This + /// must be a multiple of four. + offset: u32, + + /// The number of bytes to write. This must be a multiple of four. + size_bytes: u32, + + /// Index in [`BasePass::push_constant_data`] of the start of the data + /// to be written. + /// + /// Note: this is not a byte offset like `offset`. Rather, it is the + /// index of the first `u32` element in `push_constant_data` to read. + /// + /// `None` means zeros should be written to the destination range, and + /// there is no corresponding data in `push_constant_data`. This is used + /// by render bundles, which explicitly clear out any state that + /// post-bundle code might see. + values_offset: Option<u32>, + }, + Draw { + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, + }, + DrawIndexed { + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, + }, + MultiDrawIndirect { + buffer_id: id::BufferId, + offset: BufferAddress, + /// Count of `None` represents a non-multi call. + count: Option<NonZeroU32>, + indexed: bool, + }, + MultiDrawIndirectCount { + buffer_id: id::BufferId, + offset: BufferAddress, + count_buffer_id: id::BufferId, + count_buffer_offset: BufferAddress, + max_count: u32, + indexed: bool, + }, + PushDebugGroup { + color: u32, + len: usize, + }, + PopDebugGroup, + InsertDebugMarker { + color: u32, + len: usize, + }, + WriteTimestamp { + query_set_id: id::QuerySetId, + query_index: u32, + }, + BeginOcclusionQuery { + query_index: u32, + }, + EndOcclusionQuery, + BeginPipelineStatisticsQuery { + query_set_id: id::QuerySetId, + query_index: u32, + }, + EndPipelineStatisticsQuery, + ExecuteBundle(id::RenderBundleId), +} |