From 38f1f0ede0d197daa50bc2d4b6e00b9141dc992d Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 1 Mar 2023 16:14:49 -0500 Subject: [PATCH] Improve RenderPass/RenderBundle compatibility errors --- wgpu-core/src/command/bundle.rs | 6 +-- wgpu-core/src/command/render.rs | 12 +++-- wgpu-core/src/device/mod.rs | 89 ++++++++++++++++++++++++--------- 3 files changed, 77 insertions(+), 30 deletions(-) diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 2b5b17eae2..7fc934b671 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -86,8 +86,8 @@ use crate::{ }, conv, device::{ - AttachmentData, Device, DeviceError, MissingDownlevelFlags, RenderPassContext, - SHADER_STAGE_COUNT, + AttachmentData, Device, DeviceError, MissingDownlevelFlags, + RenderPassCompatibilityCheckType, RenderPassContext, SHADER_STAGE_COUNT, }, error::{ErrorFormatter, PrettyError}, hub::{GlobalIdentityHandlerFactory, HalApi, Hub, Resource, Storage, Token}, @@ -367,7 +367,7 @@ impl RenderBundleEncoder { .map_pass_err(scope)?; self.context - .check_compatible(&pipeline.pass_context) + .check_compatible(&pipeline.pass_context, RenderPassCompatibilityCheckType::RenderPipeline) .map_err(RenderCommandError::IncompatiblePipelineTargets) .map_pass_err(scope)?; diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index d042b41308..3872ad44f6 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -11,7 +11,7 @@ use crate::{ }, device::{ AttachmentData, Device, MissingDownlevelFlags, MissingFeatures, - RenderPassCompatibilityError, RenderPassContext, + RenderPassCompatibilityCheckType, RenderPassCompatibilityError, RenderPassContext, }, error::{ErrorFormatter, PrettyError}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, @@ -1320,7 +1320,10 @@ impl Global { .map_pass_err(scope)?; info.context - .check_compatible(&pipeline.pass_context) + .check_compatible( + &pipeline.pass_context, + RenderPassCompatibilityCheckType::RenderPipeline, + ) .map_err(RenderCommandError::IncompatiblePipelineTargets) .map_pass_err(scope)?; @@ -1986,7 +1989,10 @@ impl Global { .map_pass_err(scope)?; info.context - .check_compatible(&bundle.context) + .check_compatible( + &bundle.context, + RenderPassCompatibilityCheckType::RenderBundle, + ) .map_err(RenderPassErrorInner::IncompatibleBundleTargets) .map_pass_err(scope)?; diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index c850fcb746..8c39d419ad 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -70,6 +70,12 @@ impl AttachmentData { } } +#[derive(Debug, Copy, Clone)] +pub enum RenderPassCompatibilityCheckType { + RenderPipeline, + RenderBundle, +} + #[derive(Clone, Debug, Hash, PartialEq)] #[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))] pub(crate) struct RenderPassContext { @@ -79,16 +85,37 @@ pub(crate) struct RenderPassContext { } #[derive(Clone, Debug, Error)] pub enum RenderPassCompatibilityError { - #[error("Incompatible color attachment: the renderpass expected {0:?} but was given {1:?}")] - IncompatibleColorAttachment(Vec>, Vec>), #[error( - "Incompatible depth-stencil attachment: the renderpass expected {0:?} but was given {1:?}" + "Incompatible color attachments at indices {indices:?}: the RenderPass uses textures with formats {expected:?} but the {ty:?} uses attachments with formats {actual:?}", )] - IncompatibleDepthStencilAttachment(Option, Option), - #[error("Incompatible sample count: the renderpass expected {0:?} but was given {1:?}")] - IncompatibleSampleCount(u32, u32), - #[error("Incompatible multiview: the renderpass expected {0:?} but was given {1:?}")] - IncompatibleMultiview(Option, Option), + IncompatibleColorAttachment { + indices: Vec, + expected: Vec>, + actual: Vec>, + ty: RenderPassCompatibilityCheckType, + }, + #[error( + "Incompatible depth-stencil attachment format: the RenderPass uses a texture with format {expected:?} but the {ty:?} uses an attachment with format {actual:?}", + )] + IncompatibleDepthStencilAttachment { + expected: Option, + actual: Option, + ty: RenderPassCompatibilityCheckType, + }, + #[error( + "Incompatible sample count: the RenderPass uses textures with sample count {expected:?} but the {ty:?} uses attachments with format {actual:?}", + )] + IncompatibleSampleCount { + expected: u32, + actual: u32, + ty: RenderPassCompatibilityCheckType, + }, + #[error("Incompatible multiview setting: the RenderPass uses setting {expected:?} but the {ty:?} uses setting {actual:?}")] + IncompatibleMultiview { + expected: Option, + actual: Option, + ty: RenderPassCompatibilityCheckType, + }, } impl RenderPassContext { @@ -96,32 +123,46 @@ impl RenderPassContext { pub(crate) fn check_compatible( &self, other: &Self, + ty: RenderPassCompatibilityCheckType, ) -> Result<(), RenderPassCompatibilityError> { if self.attachments.colors != other.attachments.colors { - return Err(RenderPassCompatibilityError::IncompatibleColorAttachment( - self.attachments.colors.iter().cloned().collect(), - other.attachments.colors.iter().cloned().collect(), - )); + let indices = self + .attachments + .colors + .iter() + .zip(&other.attachments.colors) + .enumerate() + .filter_map(|(idx, (left, right))| (left != right).then_some(idx)) + .collect(); + return Err(RenderPassCompatibilityError::IncompatibleColorAttachment { + indices, + expected: self.attachments.colors.iter().cloned().collect(), + actual: other.attachments.colors.iter().cloned().collect(), + ty, + }); } if self.attachments.depth_stencil != other.attachments.depth_stencil { return Err( - RenderPassCompatibilityError::IncompatibleDepthStencilAttachment( - self.attachments.depth_stencil, - other.attachments.depth_stencil, - ), + RenderPassCompatibilityError::IncompatibleDepthStencilAttachment { + expected: self.attachments.depth_stencil, + actual: other.attachments.depth_stencil, + ty, + }, ); } if self.sample_count != other.sample_count { - return Err(RenderPassCompatibilityError::IncompatibleSampleCount( - self.sample_count, - other.sample_count, - )); + return Err(RenderPassCompatibilityError::IncompatibleSampleCount { + expected: self.sample_count, + actual: other.sample_count, + ty, + }); } if self.multiview != other.multiview { - return Err(RenderPassCompatibilityError::IncompatibleMultiview( - self.multiview, - other.multiview, - )); + return Err(RenderPassCompatibilityError::IncompatibleMultiview { + expected: self.multiview, + actual: other.multiview, + ty, + }); } Ok(()) }