mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
* Add serde, serialize, deserialize features to wgpu and wgpu-core Remove trace, replay features from wgpu-types * Do not use trace, replay in wgpu-types anymore * Make use of deserialize, serialize features in wgpu-core * Make use of serialize, deserialize features in wgpu * Run cargo fmt * Use serde(default) for deserialize only * Fix serial-pass feature * Add a comment for new features * Add CHANGELOG entry * Run cargo fmt * serial-pass also needs serde features for Id<T> * Add feature documentation to lib.rs docs * wgpu-types implicit serde feature * wgpu-core explicit serde feature * wgpu explicit serde feature * Update CHANGELOG.md * Fix compilation with default features * Address review comments
248 lines
8.7 KiB
Rust
248 lines
8.7 KiB
Rust
/*! 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),
|
|
}
|