From 019dca3cfaf227642fbed0f3698f896d4e20f12a Mon Sep 17 00:00:00 2001 From: Mikko Lehtonen Date: Thu, 29 Jul 2021 23:13:25 +0300 Subject: [PATCH] Error formatting impls closer to errors This is achieved by making a ErrorFormatter helper that is passed to fmt_pretty, making the impls a lot simpler. --- wgpu-core/src/binding_model.rs | 37 ++++ wgpu-core/src/command/bundle.rs | 20 ++ wgpu-core/src/command/compute.rs | 27 +++ wgpu-core/src/command/draw.rs | 18 ++ wgpu-core/src/command/mod.rs | 38 ++++ wgpu-core/src/command/render.rs | 18 ++ wgpu-core/src/command/transfer.rs | 33 +++ wgpu-core/src/error.rs | 338 +++++++++--------------------- wgpu/src/backend/direct.rs | 10 +- 9 files changed, 300 insertions(+), 239 deletions(-) diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index b20e314825..3c1b507e11 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -1,5 +1,6 @@ use crate::{ device::{DeviceError, MissingDownlevelFlags, MissingFeatures, SHADER_STAGE_COUNT}, + error::{ErrorFormatter, PrettyError}, hub::Resource, id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId, Valid}, memory_init_tracker::MemoryInitTrackerAction, @@ -155,6 +156,33 @@ pub enum CreateBindGroupError { ResourceUsageConflict(#[from] UsageConflict), } +impl PrettyError for CreateBindGroupError { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + fmt.error(self); + match *self { + Self::BindingZeroSize(id) => { + fmt.buffer_label(&id); + } + Self::BindingRangeTooLarge { buffer, .. } => { + fmt.buffer_label(&buffer); + } + Self::BindingSizeTooSmall { buffer, .. } => { + fmt.buffer_label(&buffer); + } + Self::InvalidBuffer(id) => { + fmt.buffer_label(&id); + } + Self::InvalidTextureView(id) => { + fmt.texture_view_label(&id); + } + Self::InvalidSampler(id) => { + fmt.sampler_label(&id); + } + _ => {} + }; + } +} + #[derive(Clone, Debug, Error)] pub enum BindingZone { #[error("stage {0:?}")] @@ -441,6 +469,15 @@ pub enum CreatePipelineLayoutError { TooManyGroups { actual: usize, max: usize }, } +impl PrettyError for CreatePipelineLayoutError { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + fmt.error(self); + if let Self::InvalidBindGroupLayout(id) = *self { + fmt.bind_group_layout_label(&id); + }; + } +} + #[derive(Clone, Debug, Error)] pub enum PushConstantUploadError { #[error("provided push constant with indices {offset}..{end_offset} overruns matching push constant range at index {idx}, with stage(s) {:?} and indices {:?}", range.stages, range.range)] diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 3ba7a1e567..d51e543d19 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -43,6 +43,7 @@ use crate::{ AttachmentData, Device, DeviceError, MissingDownlevelFlags, RenderPassContext, SHADER_STAGE_COUNT, }, + error::{ErrorFormatter, PrettyError}, hub::{GlobalIdentityHandlerFactory, HalApi, Hub, Resource, Storage, Token}, id, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, @@ -560,6 +561,17 @@ pub enum ExecutionError { #[error("using {0} in a render bundle is not implemented")] Unimplemented(&'static str), } +impl PrettyError for ExecutionError { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + fmt.error(self); + match *self { + Self::DestroyedBuffer(id) => { + fmt.buffer_label(&id); + } + Self::Unimplemented(_reason) => {} + }; + } +} pub type RenderBundleDescriptor<'a> = wgt::RenderBundleDescriptor>; @@ -1161,6 +1173,14 @@ impl RenderBundleError { inner: RenderBundleErrorInner::Device(DeviceError::Invalid), }; } +impl PrettyError for RenderBundleError { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + // This error is wrapper for the inner error, + // but the scope has useful labels + fmt.error(self); + self.scope.fmt_pretty(fmt); + } +} impl MapPassErr for Result where diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index c8c444aa62..23f080cc13 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -6,6 +6,7 @@ use crate::{ StateChange, }, device::MissingDownlevelFlags, + error::{ErrorFormatter, PrettyError}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, @@ -161,6 +162,24 @@ pub enum ComputePassErrorInner { MissingDownlevelFlags(#[from] MissingDownlevelFlags), } +impl PrettyError for ComputePassErrorInner { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + fmt.error(self); + match *self { + Self::InvalidBindGroup(id) => { + fmt.bind_group_label(&id); + } + Self::InvalidPipeline(id) => { + fmt.compute_pipeline_label(&id); + } + Self::InvalidIndirectBuffer(id) => { + fmt.buffer_label(&id); + } + _ => {} + }; + } +} + /// Error encountered when performing a compute pass. #[derive(Clone, Debug, Error)] #[error("{scope}")] @@ -169,6 +188,14 @@ pub struct ComputePassError { #[source] inner: ComputePassErrorInner, } +impl PrettyError for ComputePassError { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + // This error is wrapper for the inner error, + // but the scope has useful labels + fmt.error(self); + self.scope.fmt_pretty(fmt); + } +} impl MapPassErr for Result where diff --git a/wgpu-core/src/command/draw.rs b/wgpu-core/src/command/draw.rs index e9b266392e..0a1e422e83 100644 --- a/wgpu-core/src/command/draw.rs +++ b/wgpu-core/src/command/draw.rs @@ -3,6 +3,7 @@ use crate::{ binding_model::PushConstantUploadError, + error::ErrorFormatter, id, track::UseExtendError, validation::{MissingBufferUsageError, MissingTextureUsageError}, @@ -93,6 +94,23 @@ pub enum RenderCommandError { #[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::Buffer(id, ..) | Self::DestroyedBuffer(id) => { + fmt.buffer_label(&id); + } + _ => {} + }; + } +} #[derive(Clone, Copy, Debug, Default)] #[cfg_attr( diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 16ffc7b70c..610a547a5b 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -14,6 +14,7 @@ pub use self::query::*; pub use self::render::*; pub use self::transfer::*; +use crate::error::{ErrorFormatter, PrettyError}; use crate::{ hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id, @@ -499,3 +500,40 @@ pub enum PassErrorScope { #[error("In a pop_debug_group command")] PopDebugGroup, } + +impl PrettyError for PassErrorScope { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + // This error is not in the error chain, only notes are needed + match *self { + Self::Pass(id) => { + fmt.command_buffer_label(&id); + } + Self::SetBindGroup(id) => { + fmt.bind_group_label(&id); + } + Self::SetPipelineRender(id) => { + fmt.render_pipeline_label(&id); + } + Self::SetPipelineCompute(id) => { + fmt.compute_pipeline_label(&id); + } + Self::SetVertexBuffer(id) => { + fmt.buffer_label(&id); + } + Self::SetIndexBuffer(id) => { + fmt.buffer_label(&id); + } + Self::Draw { + pipeline: Some(id), .. + } => { + fmt.render_pipeline_label(&id); + } + Self::Dispatch { + pipeline: Some(id), .. + } => { + fmt.compute_pipeline_label(&id); + } + _ => {} + } + } +} diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 3bfcb7a8ff..9d5c9e1ee3 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -10,6 +10,7 @@ use crate::{ AttachmentData, MissingDownlevelFlags, MissingFeatures, RenderPassCompatibilityError, RenderPassContext, }, + error::{ErrorFormatter, PrettyError}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, @@ -458,6 +459,15 @@ pub enum RenderPassErrorInner { QueryUse(#[from] QueryUseError), } +impl PrettyError for RenderPassErrorInner { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + fmt.error(self); + if let Self::InvalidAttachment(id) = *self { + fmt.texture_view_label_with_key(&id, "attachment"); + }; + } +} + impl From for RenderPassErrorInner { fn from(error: MissingBufferUsageError) -> Self { Self::RenderCommand(error.into()) @@ -478,6 +488,14 @@ pub struct RenderPassError { #[source] inner: RenderPassErrorInner, } +impl PrettyError for RenderPassError { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + // This error is wrapper for the inner error, + // but the scope has useful labels + fmt.error(self); + self.scope.fmt_pretty(fmt); + } +} impl MapPassErr for Result where diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index 03928b4e5e..ee945216dd 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -3,6 +3,7 @@ use crate::device::trace::Command as TraceCommand; use crate::{ command::{CommandBuffer, CommandEncoderError}, conv, + error::{ErrorFormatter, PrettyError}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id::{BufferId, CommandEncoderId, TextureId}, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, @@ -92,6 +93,38 @@ pub enum TransferError { CopyToForbiddenTextureFormat(wgt::TextureFormat), } +impl PrettyError for TransferError { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + fmt.error(self); + match *self { + Self::InvalidBuffer(id) => { + fmt.buffer_label(&id); + } + Self::InvalidTexture(id) => { + fmt.texture_label(&id); + } + // Self::MissingCopySrcUsageFlag(buf_opt, tex_opt) => { + // if let Some(buf) = buf_opt { + // let name = crate::gfx_select!(buf => global.buffer_label(buf)); + // ret.push_str(&format_label_line("source", &name)); + // } + // if let Some(tex) = tex_opt { + // let name = crate::gfx_select!(tex => global.texture_label(tex)); + // ret.push_str(&format_label_line("source", &name)); + // } + // } + Self::MissingCopyDstUsageFlag(buf_opt, tex_opt) => { + if let Some(buf) = buf_opt { + fmt.buffer_label_with_key(&buf, "destination"); + } + if let Some(tex) = tex_opt { + fmt.texture_label_with_key(&tex, "destination"); + } + } + _ => {} + }; + } +} /// Error encountered while attempting to do a copy on a command encoder. #[derive(Clone, Debug, Error)] pub enum CopyError { diff --git a/wgpu-core/src/error.rs b/wgpu-core/src/error.rs index 8c47028fa6..4b4b1fb6d2 100644 --- a/wgpu-core/src/error.rs +++ b/wgpu-core/src/error.rs @@ -16,288 +16,145 @@ impl AsDisplay for T { } } -pub trait PrettyError: Error { - fn fmt_pretty(&self, _global: &Global) -> String { - format_error_line(self.as_display()) - } +pub struct ErrorFormatter<'a> { + writer: &'a mut dyn fmt::Write, + global: &'a Global, } -impl PrettyError for super::command::RenderCommandError { - fn fmt_pretty(&self, global: &Global) -> String { - let mut ret = format_error_line(self); - match *self { - Self::InvalidBindGroup(id) => { - let name = gfx_select!(id => global.bind_group_label(id)); - ret.push_str(&format_label_line("bind group", &name)); - } - Self::InvalidPipeline(id) => { - let name = gfx_select!(id => global.render_pipeline_label(id)); - ret.push_str(&format_label_line("render pipeline", &name)); - } - Self::Buffer(id, ..) | Self::DestroyedBuffer(id) => { - let name = gfx_select!(id => global.buffer_label(id)); - ret.push_str(&format_label_line("buffer", &name)); - } - _ => {} - }; - ret +impl<'a> ErrorFormatter<'a> { + pub fn error(&mut self, err: &dyn fmt::Display) { + writeln!(self.writer, " {}", err).expect("Error formatting error"); } -} -impl PrettyError for crate::binding_model::CreateBindGroupError { - fn fmt_pretty(&self, global: &Global) -> String { - let mut ret = format_error_line(self); - match *self { - Self::InvalidBuffer(id) => { - let name = crate::gfx_select!(id => global.buffer_label(id)); - ret.push_str(&format_label_line("buffer", &name)); - } - Self::InvalidTextureView(id) => { - let name = crate::gfx_select!(id => global.texture_view_label(id)); - ret.push_str(&format_label_line("texture view", &name)); - } - Self::InvalidSampler(id) => { - let name = crate::gfx_select!(id => global.sampler_label(id)); - ret.push_str(&format_label_line("sampler", &name)); - } - _ => {} - }; - ret - } -} -impl PrettyError for crate::binding_model::CreatePipelineLayoutError { - fn fmt_pretty(&self, global: &Global) -> String { - let mut ret = format_error_line(self); - if let Self::InvalidBindGroupLayout(id) = *self { - let name = crate::gfx_select!(id => global.bind_group_layout_label(id)); - ret.push_str(&format_label_line("bind group layout", &name)); - }; - ret + pub fn note(&mut self, note: &dyn fmt::Display) { + writeln!(self.writer, " note: {}", note).expect("Error formatting error"); } -} -impl PrettyError for crate::command::ExecutionError { - fn fmt_pretty(&self, global: &Global) -> String { - let mut ret = format_error_line(self); - match *self { - Self::DestroyedBuffer(id) => { - let name = crate::gfx_select!(id => global.buffer_label(id)); - ret.push_str(&format_label_line("buffer", &name)); - } - Self::Unimplemented(_reason) => {} - }; - ret - } -} - -impl PrettyError for crate::command::RenderPassErrorInner { - fn fmt_pretty(&self, global: &Global) -> String { - let mut ret = format_error_line(self); - if let Self::InvalidAttachment(id) = *self { - let name = crate::gfx_select!(id => global.texture_view_label(id)); - ret.push_str(&format_label_line("attachment", &name)); - }; - ret - } -} - -impl PrettyError for crate::command::RenderPassError { - fn fmt_pretty(&self, global: &Global) -> String { - // This error is wrapper for the inner error, - // but the scope has useful labels - format_error_line(self) + &self.scope.fmt_pretty(global) - } -} - -impl PrettyError for crate::command::ComputePassError { - fn fmt_pretty(&self, global: &Global) -> String { - // This error is wrapper for the inner error, - // but the scope has useful labels - format_error_line(self) + &self.scope.fmt_pretty(global) - } -} -impl PrettyError for crate::command::RenderBundleError { - fn fmt_pretty(&self, global: &Global) -> String { - // This error is wrapper for the inner error, - // but the scope has useful labels - format_error_line(self) + &self.scope.fmt_pretty(global) - } -} - -impl PrettyError for crate::command::ComputePassErrorInner { - fn fmt_pretty(&self, global: &Global) -> String { - let mut ret = format_error_line(self); - match *self { - Self::InvalidBindGroup(id) => { - let name = crate::gfx_select!(id => global.bind_group_label(id)); - ret.push_str(&format_label_line("bind group", &name)); - } - Self::InvalidPipeline(id) => { - let name = crate::gfx_select!(id => global.compute_pipeline_label(id)); - ret.push_str(&format_label_line("pipeline", &name)); - } - Self::InvalidIndirectBuffer(id) => { - let name = crate::gfx_select!(id => global.buffer_label(id)); - ret.push_str(&format_label_line("indirect buffer", &name)); - } - _ => {} - }; - ret - } -} - -impl PrettyError for crate::command::TransferError { - fn fmt_pretty(&self, global: &Global) -> String { - let mut ret = format_error_line(self); - match *self { - Self::InvalidBuffer(id) => { - let name = crate::gfx_select!(id => global.buffer_label(id)); - ret.push_str(&format_label_line("label", &name)); - } - Self::InvalidTexture(id) => { - let name = crate::gfx_select!(id => global.texture_label(id)); - ret.push_str(&format_label_line("texture", &name)); - } - // Self::MissingCopySrcUsageFlag(buf_opt, tex_opt) => { - // if let Some(buf) = buf_opt { - // let name = crate::gfx_select!(buf => global.buffer_label(buf)); - // ret.push_str(&format_label_line("source", &name)); - // } - // if let Some(tex) = tex_opt { - // let name = crate::gfx_select!(tex => global.texture_label(tex)); - // ret.push_str(&format_label_line("source", &name)); - // } - // } - Self::MissingCopyDstUsageFlag(buf_opt, tex_opt) => { - if let Some(buf) = buf_opt { - let name = crate::gfx_select!(buf => global.buffer_label(buf)); - ret.push_str(&format_label_line("destination", &name)); - } - if let Some(tex) = tex_opt { - let name = crate::gfx_select!(tex => global.texture_label(tex)); - ret.push_str(&format_label_line("destination", &name)); - } - } - _ => {} - }; - ret - } -} - -impl PrettyError for crate::command::PassErrorScope { - fn fmt_pretty(&self, global: &Global) -> String { - // This error is not in the error chain, only notes are needed - match *self { - Self::Pass(id) => { - let name = crate::gfx_select!(id => global.command_buffer_label(id)); - format_label_line("command buffer", &name) - } - Self::SetBindGroup(id) => { - let name = crate::gfx_select!(id => global.bind_group_label(id)); - format_label_line("bind group", &name) - } - Self::SetPipelineRender(id) => { - let name = crate::gfx_select!(id => global.render_pipeline_label(id)); - format_label_line("render pipeline", &name) - } - Self::SetPipelineCompute(id) => { - let name = crate::gfx_select!(id => global.compute_pipeline_label(id)); - format_label_line("compute pipeline", &name) - } - Self::SetVertexBuffer(id) => { - let name = crate::gfx_select!(id => global.buffer_label(id)); - format_label_line("buffer", &name) - } - Self::SetIndexBuffer(id) => { - let name = crate::gfx_select!(id => global.buffer_label(id)); - format_label_line("buffer", &name) - } - Self::Draw { pipeline, .. } => { - if let Some(id) = pipeline { - let name = crate::gfx_select!(id => global.render_pipeline_label(id)); - format_label_line("render pipeline", &name) - } else { - String::new() - } - } - Self::Dispatch { pipeline, .. } => { - if let Some(id) = pipeline { - let name = crate::gfx_select!(id => global.compute_pipeline_label(id)); - format_label_line("compute pipeline", &name) - } else { - String::new() - } - } - _ => String::new(), + pub fn label(&mut self, label_key: &str, label_value: &str) { + if !label_key.is_empty() && !label_value.is_empty() { + self.note(&format!("{} = `{}`", label_key, label_value)); } } -} -impl PrettyError for ContextError { - fn fmt_pretty(&self, _global: &Global) -> String { - format_error_line(self.as_display()) + &format_label_line(self.label_key, &self.label) + pub fn bind_group_label(&mut self, id: &crate::id::BindGroupId) { + let global = self.global; + let label = gfx_select!(id => global.bind_group_label(*id)); + self.label("bind group", &label); + } + + pub fn bind_group_layout_label(&mut self, id: &crate::id::BindGroupLayoutId) { + let global = self.global; + let label = gfx_select!(id => global.bind_group_layout_label(*id)); + self.label("bind group layout", &label); + } + + pub fn render_pipeline_label(&mut self, id: &crate::id::RenderPipelineId) { + let global = self.global; + let label = gfx_select!(id => global.render_pipeline_label(*id)); + self.label("render pipeline", &label); + } + + pub fn compute_pipeline_label(&mut self, id: &crate::id::ComputePipelineId) { + let global = self.global; + let label = gfx_select!(id => global.compute_pipeline_label(*id)); + self.label("compute pipeline", &label); + } + + pub fn buffer_label_with_key(&mut self, id: &crate::id::BufferId, key: &str) { + let global = self.global; + let label = gfx_select!(id => global.buffer_label(*id)); + self.label(key, &label); + } + + pub fn buffer_label(&mut self, id: &crate::id::BufferId) { + self.buffer_label_with_key(id, "buffer"); + } + + pub fn texture_label_with_key(&mut self, id: &crate::id::TextureId, key: &str) { + let global = self.global; + let label = gfx_select!(id => global.texture_label(*id)); + self.label(key, &label); + } + + pub fn texture_label(&mut self, id: &crate::id::TextureId) { + self.texture_label_with_key(id, "texture"); + } + + pub fn texture_view_label_with_key(&mut self, id: &crate::id::TextureViewId, key: &str) { + let global = self.global; + let label = gfx_select!(id => global.texture_view_label(*id)); + self.label(key, &label); + } + + pub fn texture_view_label(&mut self, id: &crate::id::TextureViewId) { + self.texture_view_label_with_key(id, "texture view"); + } + + pub fn sampler_label(&mut self, id: &crate::id::SamplerId) { + let global = self.global; + let label = gfx_select!(id => global.sampler_label(*id)); + self.label("sampler", &label); + } + + pub fn command_buffer_label(&mut self, id: &crate::id::CommandBufferId) { + let global = self.global; + let label = gfx_select!(id => global.command_buffer_label(*id)); + self.label("command buffer", &label); } } -pub fn format_error_line(err: &dyn fmt::Display) -> String { - format!(" {}\n", err) -} - -pub fn format_note_line(note: &dyn fmt::Display) -> String { - format!(" note: {}\n", note) -} - -pub fn format_label_line(label_key: &str, label_value: &str) -> String { - if label_key.is_empty() || label_value.is_empty() { - String::new() - } else { - format_note_line(&format!("{} = `{}`", label_key, label_value)) +pub trait PrettyError: Error { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + fmt.error(self.as_display()); } } pub fn format_pretty_any( + writer: &mut dyn fmt::Write, global: &Global, error: &(dyn Error + 'static), -) -> String { +) { + let mut fmt = ErrorFormatter { writer, global }; + if let Some(pretty_err) = error.downcast_ref::() { - return pretty_err.fmt_pretty(global); + return pretty_err.fmt_pretty(&mut fmt); } if let Some(pretty_err) = error.downcast_ref::() { - return pretty_err.fmt_pretty(global); + return pretty_err.fmt_pretty(&mut fmt); } if let Some(pretty_err) = error.downcast_ref::() { - return pretty_err.fmt_pretty(global); + return pretty_err.fmt_pretty(&mut fmt); } if let Some(pretty_err) = error.downcast_ref::() { - return pretty_err.fmt_pretty(global); + return pretty_err.fmt_pretty(&mut fmt); } if let Some(pretty_err) = error.downcast_ref::() { - return pretty_err.fmt_pretty(global); + return pretty_err.fmt_pretty(&mut fmt); } if let Some(pretty_err) = error.downcast_ref::() { - return pretty_err.fmt_pretty(global); + return pretty_err.fmt_pretty(&mut fmt); } if let Some(pretty_err) = error.downcast_ref::() { - return pretty_err.fmt_pretty(global); + return pretty_err.fmt_pretty(&mut fmt); } if let Some(pretty_err) = error.downcast_ref::() { - return pretty_err.fmt_pretty(global); + return pretty_err.fmt_pretty(&mut fmt); } if let Some(pretty_err) = error.downcast_ref::() { - return pretty_err.fmt_pretty(global); + return pretty_err.fmt_pretty(&mut fmt); } if let Some(pretty_err) = error.downcast_ref::() { - return pretty_err.fmt_pretty(global); + return pretty_err.fmt_pretty(&mut fmt); } if let Some(pretty_err) = error.downcast_ref::() { - return pretty_err.fmt_pretty(global); + return pretty_err.fmt_pretty(&mut fmt); } // default - format_error_line(error.as_display()) + fmt.error(error.as_display()) } #[derive(Debug)] @@ -308,6 +165,13 @@ pub struct ContextError { pub label: String, } +impl PrettyError for ContextError { + fn fmt_pretty(&self, fmt: &mut ErrorFormatter) { + fmt.error(self.as_display()); + fmt.label(self.label_key, &self.label); + } +} + impl fmt::Display for ContextError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "In {}", self.string) diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index d2dbdb7910..b3e4530f39 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -188,11 +188,17 @@ impl Context { fn format_error(&self, err: &(impl Error + 'static)) -> String { let global = self.global(); - let mut err_descs = vec![wgc::error::format_pretty_any(global, err)]; + let mut err_descs = vec![]; + + let mut err_str = String::new(); + wgc::error::format_pretty_any(&mut err_str, global, err); + err_descs.push(err_str); let mut source_opt = err.source(); while let Some(source) = source_opt { - err_descs.push(wgc::error::format_pretty_any(global, source)); + let mut source_str = String::new(); + wgc::error::format_pretty_any(&mut source_str, global, source); + err_descs.push(source_str); source_opt = source.source(); }