mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-23 23:34:29 +00:00
Merge #1728
1728: Move error formatting functionality r=kvark a=scoopr **Connections** This is an attempt to implement #1082 **Description** This is a fairly straightforward move of the error formatting that were in wgpu-rs in to wgpu-code. The enriching of some of the errors with the additional `ContextError` were still left with the wgpu-rs code, as I realised the current error messages refer to the API names as they appear in rust code and might not make sense for all the consumers of wgpu-core. It could be left as is and other consumers might enrich in their own ways, or the messages could be reformatted to be more conversational **Testing** Limited testing with the examples Co-authored-by: Mikko Lehtonen <scoopr@iki.fi>
This commit is contained in:
commit
da39957062
@ -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)]
|
||||
|
@ -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<Label<'a>>;
|
||||
|
||||
@ -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<T, E> MapPassErr<T, RenderBundleError> for Result<T, E>
|
||||
where
|
||||
|
@ -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<T, E> MapPassErr<T, ComputePassError> for Result<T, E>
|
||||
where
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<MissingBufferUsageError> 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<T, E> MapPassErr<T, RenderPassError> for Result<T, E>
|
||||
where
|
||||
|
@ -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 {
|
||||
|
175
wgpu-core/src/error.rs
Normal file
175
wgpu-core/src/error.rs
Normal file
@ -0,0 +1,175 @@
|
||||
use core::fmt;
|
||||
use std::error::Error;
|
||||
|
||||
use crate::{
|
||||
gfx_select,
|
||||
hub::{Global, IdentityManagerFactory},
|
||||
};
|
||||
|
||||
pub struct ErrorFormatter<'a> {
|
||||
writer: &'a mut dyn fmt::Write,
|
||||
global: &'a Global<IdentityManagerFactory>,
|
||||
}
|
||||
|
||||
impl<'a> ErrorFormatter<'a> {
|
||||
pub fn error(&mut self, err: &dyn Error) {
|
||||
writeln!(self.writer, " {}", err).expect("Error formatting error");
|
||||
}
|
||||
|
||||
pub fn note(&mut self, note: &dyn fmt::Display) {
|
||||
writeln!(self.writer, " note: {}", note).expect("Error formatting error");
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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 trait PrettyError: Error + Sized {
|
||||
fn fmt_pretty(&self, fmt: &mut ErrorFormatter) {
|
||||
fmt.error(self);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_pretty_any(
|
||||
writer: &mut dyn fmt::Write,
|
||||
global: &Global<IdentityManagerFactory>,
|
||||
error: &(dyn Error + 'static),
|
||||
) {
|
||||
let mut fmt = ErrorFormatter { writer, global };
|
||||
|
||||
if let Some(pretty_err) = error.downcast_ref::<ContextError>() {
|
||||
return pretty_err.fmt_pretty(&mut fmt);
|
||||
}
|
||||
|
||||
if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderCommandError>() {
|
||||
return pretty_err.fmt_pretty(&mut fmt);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<crate::binding_model::CreateBindGroupError>() {
|
||||
return pretty_err.fmt_pretty(&mut fmt);
|
||||
}
|
||||
if let Some(pretty_err) =
|
||||
error.downcast_ref::<crate::binding_model::CreatePipelineLayoutError>()
|
||||
{
|
||||
return pretty_err.fmt_pretty(&mut fmt);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<crate::command::ExecutionError>() {
|
||||
return pretty_err.fmt_pretty(&mut fmt);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderPassErrorInner>() {
|
||||
return pretty_err.fmt_pretty(&mut fmt);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderPassError>() {
|
||||
return pretty_err.fmt_pretty(&mut fmt);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<crate::command::ComputePassErrorInner>() {
|
||||
return pretty_err.fmt_pretty(&mut fmt);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<crate::command::ComputePassError>() {
|
||||
return pretty_err.fmt_pretty(&mut fmt);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<crate::command::RenderBundleError>() {
|
||||
return pretty_err.fmt_pretty(&mut fmt);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<crate::command::TransferError>() {
|
||||
return pretty_err.fmt_pretty(&mut fmt);
|
||||
}
|
||||
|
||||
// default
|
||||
fmt.error(error)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ContextError {
|
||||
pub string: &'static str,
|
||||
pub cause: Box<dyn Error + Send + Sync + 'static>,
|
||||
pub label_key: &'static str,
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
impl PrettyError for ContextError {
|
||||
fn fmt_pretty(&self, fmt: &mut ErrorFormatter) {
|
||||
fmt.error(self);
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ContextError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
Some(self.cause.as_ref())
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ pub mod binding_model;
|
||||
pub mod command;
|
||||
mod conv;
|
||||
pub mod device;
|
||||
pub mod error;
|
||||
pub mod hub;
|
||||
pub mod id;
|
||||
pub mod instance;
|
||||
|
@ -1,9 +1,8 @@
|
||||
use crate::{
|
||||
backend::{error::ContextError, native_gpu_future},
|
||||
AdapterInfo, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource, BufferBinding,
|
||||
CommandEncoderDescriptor, ComputePassDescriptor, ComputePipelineDescriptor,
|
||||
DownlevelCapabilities, Features, Label, Limits, LoadOp, MapMode, Operations,
|
||||
PipelineLayoutDescriptor, RenderBundleEncoderDescriptor, RenderPipelineDescriptor,
|
||||
backend::native_gpu_future, AdapterInfo, BindGroupDescriptor, BindGroupLayoutDescriptor,
|
||||
BindingResource, BufferBinding, CommandEncoderDescriptor, ComputePassDescriptor,
|
||||
ComputePipelineDescriptor, DownlevelCapabilities, Features, Label, Limits, LoadOp, MapMode,
|
||||
Operations, PipelineLayoutDescriptor, RenderBundleEncoderDescriptor, RenderPipelineDescriptor,
|
||||
SamplerDescriptor, ShaderModuleDescriptor, ShaderModuleDescriptorSpirV, ShaderSource,
|
||||
SwapChainStatus, TextureDescriptor, TextureFormat, TextureViewDescriptor,
|
||||
};
|
||||
@ -144,7 +143,7 @@ impl Context {
|
||||
label: Label,
|
||||
string: &'static str,
|
||||
) {
|
||||
let error = ContextError {
|
||||
let error = wgc::error::ContextError {
|
||||
string,
|
||||
cause: Box::new(cause),
|
||||
label: label.unwrap_or_default().to_string(),
|
||||
@ -186,6 +185,25 @@ impl Context {
|
||||
) -> ! {
|
||||
panic!("Error in {}: {}", string, cause);
|
||||
}
|
||||
|
||||
fn format_error(&self, err: &(impl Error + 'static)) -> String {
|
||||
let global = self.global();
|
||||
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 {
|
||||
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();
|
||||
}
|
||||
|
||||
format!("Validation Error\n\nCaused by:\n{}", err_descs.join(""))
|
||||
}
|
||||
}
|
||||
|
||||
mod pass_impl {
|
||||
|
@ -1,333 +0,0 @@
|
||||
use std::{error::Error, fmt};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct ContextError {
|
||||
pub string: &'static str,
|
||||
pub cause: Box<dyn Error + Send + Sync + 'static>,
|
||||
pub label_key: &'static str,
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
impl fmt::Display for ContextError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "In {}", self.string)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ContextError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
Some(self.cause.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl super::Context {
|
||||
pub(super) fn format_error(&self, err: &(impl Error + 'static)) -> String {
|
||||
let mut err_descs = vec![self.format_pretty_any(err)];
|
||||
|
||||
let mut source_opt = err.source();
|
||||
while let Some(source) = source_opt {
|
||||
err_descs.push(self.format_pretty_any(source));
|
||||
source_opt = source.source();
|
||||
}
|
||||
|
||||
format!("Validation Error\n\nCaused by:\n{}", err_descs.join(""))
|
||||
}
|
||||
|
||||
fn format_pretty_any(&self, error: &(dyn Error + 'static)) -> String {
|
||||
if let Some(pretty_err) = error.downcast_ref::<ContextError>() {
|
||||
return pretty_err.fmt_pretty(self);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<wgc::command::RenderCommandError>() {
|
||||
return pretty_err.fmt_pretty(self);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<wgc::binding_model::CreateBindGroupError>() {
|
||||
return pretty_err.fmt_pretty(self);
|
||||
}
|
||||
if let Some(pretty_err) =
|
||||
error.downcast_ref::<wgc::binding_model::CreatePipelineLayoutError>()
|
||||
{
|
||||
return pretty_err.fmt_pretty(self);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<wgc::command::ExecutionError>() {
|
||||
return pretty_err.fmt_pretty(self);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<wgc::command::RenderPassErrorInner>() {
|
||||
return pretty_err.fmt_pretty(self);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<wgc::command::RenderPassError>() {
|
||||
return pretty_err.fmt_pretty(self);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<wgc::command::ComputePassErrorInner>() {
|
||||
return pretty_err.fmt_pretty(self);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<wgc::command::ComputePassError>() {
|
||||
return pretty_err.fmt_pretty(self);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<wgc::command::RenderBundleError>() {
|
||||
return pretty_err.fmt_pretty(self);
|
||||
}
|
||||
if let Some(pretty_err) = error.downcast_ref::<wgc::command::TransferError>() {
|
||||
return pretty_err.fmt_pretty(self);
|
||||
}
|
||||
|
||||
// default
|
||||
format_error_line(error.as_display())
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn format_error_line(err: &dyn fmt::Display) -> String {
|
||||
format!(" {}\n", err)
|
||||
}
|
||||
|
||||
pub(super) fn format_note_line(note: &dyn fmt::Display) -> String {
|
||||
format!(" note: {}\n", note)
|
||||
}
|
||||
|
||||
pub(super) 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))
|
||||
}
|
||||
}
|
||||
|
||||
trait AsDisplay {
|
||||
fn as_display(&self) -> &dyn fmt::Display;
|
||||
}
|
||||
|
||||
impl<T: fmt::Display> AsDisplay for T {
|
||||
fn as_display(&self) -> &dyn fmt::Display {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PrettyError: Error {
|
||||
fn fmt_pretty(&self, _context: &super::Context) -> String {
|
||||
format_error_line(self.as_display())
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyError for ContextError {
|
||||
fn fmt_pretty(&self, _context: &super::Context) -> String {
|
||||
format_error_line(self.as_display()) + &format_label_line(self.label_key, &self.label)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyError for wgc::command::RenderCommandError {
|
||||
fn fmt_pretty(&self, context: &super::Context) -> String {
|
||||
let global = context.global();
|
||||
let mut ret = format_error_line(self);
|
||||
match *self {
|
||||
Self::InvalidBindGroup(id) => {
|
||||
let name = wgc::gfx_select!(id => global.bind_group_label(id));
|
||||
ret.push_str(&format_label_line("bind group", &name));
|
||||
}
|
||||
Self::InvalidPipeline(id) => {
|
||||
let name = wgc::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 = wgc::gfx_select!(id => global.buffer_label(id));
|
||||
ret.push_str(&format_label_line("buffer", &name));
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
ret
|
||||
}
|
||||
}
|
||||
impl PrettyError for wgc::binding_model::CreateBindGroupError {
|
||||
fn fmt_pretty(&self, context: &super::Context) -> String {
|
||||
let global = context.global();
|
||||
let mut ret = format_error_line(self);
|
||||
match *self {
|
||||
Self::InvalidBuffer(id) => {
|
||||
let name = wgc::gfx_select!(id => global.buffer_label(id));
|
||||
ret.push_str(&format_label_line("buffer", &name));
|
||||
}
|
||||
Self::InvalidTextureView(id) => {
|
||||
let name = wgc::gfx_select!(id => global.texture_view_label(id));
|
||||
ret.push_str(&format_label_line("texture view", &name));
|
||||
}
|
||||
Self::InvalidSampler(id) => {
|
||||
let name = wgc::gfx_select!(id => global.sampler_label(id));
|
||||
ret.push_str(&format_label_line("sampler", &name));
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyError for wgc::binding_model::CreatePipelineLayoutError {
|
||||
fn fmt_pretty(&self, context: &super::Context) -> String {
|
||||
let global = context.global();
|
||||
let mut ret = format_error_line(self);
|
||||
if let Self::InvalidBindGroupLayout(id) = *self {
|
||||
let name = wgc::gfx_select!(id => global.bind_group_layout_label(id));
|
||||
ret.push_str(&format_label_line("bind group layout", &name));
|
||||
};
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyError for wgc::command::ExecutionError {
|
||||
fn fmt_pretty(&self, context: &super::Context) -> String {
|
||||
let global = context.global();
|
||||
let mut ret = format_error_line(self);
|
||||
match *self {
|
||||
Self::DestroyedBuffer(id) => {
|
||||
let name = wgc::gfx_select!(id => global.buffer_label(id));
|
||||
ret.push_str(&format_label_line("buffer", &name));
|
||||
}
|
||||
Self::Unimplemented(_reason) => {}
|
||||
};
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyError for wgc::command::RenderPassErrorInner {
|
||||
fn fmt_pretty(&self, context: &super::Context) -> String {
|
||||
let global = context.global();
|
||||
let mut ret = format_error_line(self);
|
||||
if let Self::InvalidAttachment(id) = *self {
|
||||
let name = wgc::gfx_select!(id => global.texture_view_label(id));
|
||||
ret.push_str(&format_label_line("attachment", &name));
|
||||
};
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyError for wgc::command::RenderPassError {
|
||||
fn fmt_pretty(&self, context: &super::Context) -> String {
|
||||
// This error is wrapper for the inner error,
|
||||
// but the scope has useful labels
|
||||
format_error_line(self) + &self.scope.fmt_pretty(context)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyError for wgc::command::ComputePassError {
|
||||
fn fmt_pretty(&self, context: &super::Context) -> String {
|
||||
// This error is wrapper for the inner error,
|
||||
// but the scope has useful labels
|
||||
format_error_line(self) + &self.scope.fmt_pretty(context)
|
||||
}
|
||||
}
|
||||
impl PrettyError for wgc::command::RenderBundleError {
|
||||
fn fmt_pretty(&self, context: &super::Context) -> String {
|
||||
// This error is wrapper for the inner error,
|
||||
// but the scope has useful labels
|
||||
format_error_line(self) + &self.scope.fmt_pretty(context)
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyError for wgc::command::ComputePassErrorInner {
|
||||
fn fmt_pretty(&self, context: &super::Context) -> String {
|
||||
let global = context.global();
|
||||
let mut ret = format_error_line(self);
|
||||
match *self {
|
||||
Self::InvalidBindGroup(id) => {
|
||||
let name = wgc::gfx_select!(id => global.bind_group_label(id));
|
||||
ret.push_str(&format_label_line("bind group", &name));
|
||||
}
|
||||
Self::InvalidPipeline(id) => {
|
||||
let name = wgc::gfx_select!(id => global.compute_pipeline_label(id));
|
||||
ret.push_str(&format_label_line("pipeline", &name));
|
||||
}
|
||||
Self::InvalidIndirectBuffer(id) => {
|
||||
let name = wgc::gfx_select!(id => global.buffer_label(id));
|
||||
ret.push_str(&format_label_line("indirect buffer", &name));
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyError for wgc::command::TransferError {
|
||||
fn fmt_pretty(&self, context: &super::Context) -> String {
|
||||
let global = context.global();
|
||||
let mut ret = format_error_line(self);
|
||||
match *self {
|
||||
Self::InvalidBuffer(id) => {
|
||||
let name = wgc::gfx_select!(id => global.buffer_label(id));
|
||||
ret.push_str(&format_label_line("label", &name));
|
||||
}
|
||||
Self::InvalidTexture(id) => {
|
||||
let name = wgc::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 = wgc::gfx_select!(buf => global.buffer_label(buf));
|
||||
// ret.push_str(&format_label_line("source", &name));
|
||||
// }
|
||||
// if let Some(tex) = tex_opt {
|
||||
// let name = wgc::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 = wgc::gfx_select!(buf => global.buffer_label(buf));
|
||||
ret.push_str(&format_label_line("destination", &name));
|
||||
}
|
||||
if let Some(tex) = tex_opt {
|
||||
let name = wgc::gfx_select!(tex => global.texture_label(tex));
|
||||
ret.push_str(&format_label_line("destination", &name));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyError for wgc::command::PassErrorScope {
|
||||
fn fmt_pretty(&self, context: &super::Context) -> String {
|
||||
// This error is not in the error chain, only notes are needed
|
||||
let global = context.global();
|
||||
match *self {
|
||||
Self::Pass(id) => {
|
||||
let name = wgc::gfx_select!(id => global.command_buffer_label(id));
|
||||
format_label_line("command buffer", &name)
|
||||
}
|
||||
Self::SetBindGroup(id) => {
|
||||
let name = wgc::gfx_select!(id => global.bind_group_label(id));
|
||||
format_label_line("bind group", &name)
|
||||
}
|
||||
Self::SetPipelineRender(id) => {
|
||||
let name = wgc::gfx_select!(id => global.render_pipeline_label(id));
|
||||
format_label_line("render pipeline", &name)
|
||||
}
|
||||
Self::SetPipelineCompute(id) => {
|
||||
let name = wgc::gfx_select!(id => global.compute_pipeline_label(id));
|
||||
format_label_line("compute pipeline", &name)
|
||||
}
|
||||
Self::SetVertexBuffer(id) => {
|
||||
let name = wgc::gfx_select!(id => global.buffer_label(id));
|
||||
format_label_line("buffer", &name)
|
||||
}
|
||||
Self::SetIndexBuffer(id) => {
|
||||
let name = wgc::gfx_select!(id => global.buffer_label(id));
|
||||
format_label_line("buffer", &name)
|
||||
}
|
||||
Self::Draw { pipeline, .. } => {
|
||||
if let Some(id) = pipeline {
|
||||
let name = wgc::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 = wgc::gfx_select!(id => global.compute_pipeline_label(id));
|
||||
format_label_line("compute pipeline", &name)
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
_ => String::new(),
|
||||
}
|
||||
}
|
||||
}
|
@ -6,8 +6,6 @@ pub(crate) use web::{BufferMappedRange, Context};
|
||||
#[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))]
|
||||
mod direct;
|
||||
#[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))]
|
||||
mod error;
|
||||
|
||||
#[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))]
|
||||
pub(crate) use direct::{BufferMappedRange, Context};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user