diff --git a/wgpu-core/src/command/bind.rs b/wgpu-core/src/command/bind.rs index 8830ec00e3..bd0ddc70ff 100644 --- a/wgpu-core/src/command/bind.rs +++ b/wgpu-core/src/command/bind.rs @@ -5,10 +5,11 @@ use crate::{ device::SHADER_STAGE_COUNT, hal_api::HalApi, pipeline::LateSizedBufferGroup, - resource::Labeled, + resource::{Labeled, ResourceErrorIdent}, }; use arrayvec::ArrayVec; +use thiserror::Error; type BindGroupMask = u8; @@ -214,6 +215,14 @@ mod compat { } } +#[derive(Clone, Debug, Error)] +#[error("Bind group at index {index} is incompatible with the current set {pipeline}")] +pub struct IncompatibleBindGroupError { + index: u32, + pipeline: ResourceErrorIdent, + diff: Vec, +} + #[derive(Debug)] struct LateBufferBinding { shader_expect_size: wgt::BufferAddress, @@ -358,12 +367,20 @@ impl Binder { .map(move |index| payloads[index].group.as_ref().unwrap()) } - pub(super) fn invalid_mask(&self) -> BindGroupMask { - self.manager.invalid_mask() - } - - pub(super) fn bgl_diff(&self) -> Vec { - self.manager.bgl_diff() + pub(super) fn check_compatibility( + &self, + pipeline: &T, + ) -> Result<(), IncompatibleBindGroupError> { + let bind_mask = self.manager.invalid_mask(); + if bind_mask == 0 { + Ok(()) + } else { + Err(IncompatibleBindGroupError { + index: bind_mask.trailing_zeros(), + pipeline: pipeline.error_ident(), + diff: self.manager.bgl_diff(), + }) + } } /// Scan active buffer bindings corresponding to layouts without `min_binding_size` specified. diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index 04d5f10df1..b02a10c1d1 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -20,7 +20,7 @@ use crate::{ pipeline::ComputePipeline, resource::{ self, Buffer, DestroyedResourceError, Labeled, MissingBufferUsageError, ParentDevice, - ResourceErrorIdent, Trackable, + Trackable, }, snatch::SnatchGuard, track::{ResourceUsageCompatibilityError, Tracker, TrackerIndex, UsageScope}, @@ -35,7 +35,10 @@ use wgt::{BufferAddress, DynamicOffset}; use std::sync::Arc; use std::{fmt, mem, str}; -use super::{memory_init::CommandBufferTextureMemoryActions, DynComputePass}; +use super::{ + bind::IncompatibleBindGroupError, memory_init::CommandBufferTextureMemoryActions, + DynComputePass, +}; pub struct ComputePass { /// All pass data & records is stored here. @@ -117,12 +120,8 @@ struct ArcComputePassDescriptor<'a, A: HalApi> { pub enum DispatchError { #[error("Compute pipeline must be set")] MissingPipeline, - #[error("Bind group at index {index} is incompatible with the current set {pipeline}")] - IncompatibleBindGroup { - index: u32, - pipeline: ResourceErrorIdent, - diff: Vec, - }, + #[error(transparent)] + IncompatibleBindGroup(#[from] IncompatibleBindGroupError), #[error( "Each current dispatch group size dimension ({current:?}) must be less or equal to {limit}" )] @@ -186,16 +185,7 @@ pub enum ComputePassErrorInner { PassEnded, } -impl PrettyError for ComputePassErrorInner { - fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { - fmt.error(self); - if let Self::Dispatch(DispatchError::IncompatibleBindGroup { ref diff, .. }) = *self { - for d in diff { - fmt.note(&d); - } - } - } -} +impl PrettyError for ComputePassErrorInner {} /// Error encountered when performing a compute pass. #[derive(Clone, Debug, Error)] @@ -259,14 +249,7 @@ impl<'scope, 'snatch_guard, 'cmd_buf, 'raw_encoder, A: HalApi> { fn is_ready(&self) -> Result<(), DispatchError> { if let Some(pipeline) = self.pipeline.as_ref() { - let bind_mask = self.binder.invalid_mask(); - if bind_mask != 0 { - return Err(DispatchError::IncompatibleBindGroup { - index: bind_mask.trailing_zeros(), - pipeline: pipeline.error_ident(), - diff: self.binder.bgl_diff(), - }); - } + self.binder.check_compatibility(pipeline.as_ref())?; self.binder.check_late_buffer_bindings()?; Ok(()) } else { diff --git a/wgpu-core/src/command/draw.rs b/wgpu-core/src/command/draw.rs index 6df9371b15..6eb4e4aa76 100644 --- a/wgpu-core/src/command/draw.rs +++ b/wgpu-core/src/command/draw.rs @@ -11,6 +11,8 @@ use wgt::VertexStepMode; use thiserror::Error; +use super::bind::IncompatibleBindGroupError; + /// Error validating a draw call. #[derive(Clone, Debug, Error)] #[non_exhaustive] @@ -26,12 +28,8 @@ pub enum DrawError { }, #[error("Index buffer must be set")] MissingIndexBuffer, - #[error("Bind group at index {index} is incompatible with the current set {pipeline}")] - IncompatibleBindGroup { - index: u32, - pipeline: ResourceErrorIdent, - diff: Vec, - }, + #[error(transparent)] + IncompatibleBindGroup(#[from] IncompatibleBindGroupError), #[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, diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index f27972e481..04760d9ae7 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -481,14 +481,7 @@ impl<'scope, 'snatch_guard, 'cmd_buf, 'raw_encoder, A: HalApi> { fn is_ready(&self, indexed: bool) -> Result<(), DrawError> { if let Some(pipeline) = self.pipeline.as_ref() { - let bind_mask = self.binder.invalid_mask(); - if bind_mask != 0 { - return Err(DrawError::IncompatibleBindGroup { - index: bind_mask.trailing_zeros(), - pipeline: pipeline.error_ident(), - diff: self.binder.bgl_diff(), - }); - } + self.binder.check_compatibility(pipeline.as_ref())?; self.binder.check_late_buffer_bindings()?; if self.blend_constant == OptionalState::Required { @@ -717,16 +710,7 @@ pub enum RenderPassErrorInner { PassEnded, } -impl PrettyError for RenderPassErrorInner { - fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { - fmt.error(self); - if let Self::Draw(DrawError::IncompatibleBindGroup { diff, .. }) = self { - for d in diff { - fmt.note(&d); - } - }; - } -} +impl PrettyError for RenderPassErrorInner {} impl From for RenderPassErrorInner { fn from(error: MissingBufferUsageError) -> Self {