mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-02-16 17:02:32 +00:00
Merge #810
810: Convert the existing error types to `thiserror` r=kvark a=GabrielMajeri **Connections** Part of #638 **Description** Converts the crate's existing error types from a manual `Display` implementation to using `thiserror`. **Testing** Tested with core and `wgpu-rs`. Co-authored-by: Gabriel Majeri <gabriel.majeri6@gmail.com>
This commit is contained in:
commit
a689aea3f2
@ -17,28 +17,31 @@ use serde::Deserialize;
|
||||
#[cfg(feature = "trace")]
|
||||
use serde::Serialize;
|
||||
|
||||
use std::{borrow::Borrow, fmt};
|
||||
use std::{borrow::Borrow, ops::Range};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum BindGroupLayoutError {
|
||||
#[error("conflicting binding at index {0}")]
|
||||
ConflictBinding(u32),
|
||||
#[error("required device feature is missing: {0:?}")]
|
||||
MissingFeature(wgt::Features),
|
||||
/// Arrays of bindings can't be 0 elements long
|
||||
#[error("arrays of bindings can't be 0 elements long")]
|
||||
ZeroCount,
|
||||
/// Arrays of bindings unsupported for this type of binding
|
||||
#[error("arrays of bindings unsupported for this type of binding")]
|
||||
ArrayUnsupported,
|
||||
/// Bindings go over binding count limits
|
||||
#[error(transparent)]
|
||||
TooManyBindings(BindingTypeMaxCountError),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BindGroupError {
|
||||
/// Number of bindings in bind group descriptor does not match
|
||||
/// the number of bindings defined in the bind group layout.
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateBindGroupError {
|
||||
#[error("number of bindings in bind group descriptor ({actual}) does not match the number of bindings defined in the bind group layout ({expected})")]
|
||||
BindingsNumMismatch { actual: usize, expected: usize },
|
||||
/// Unable to find a corresponding declaration for the given binding,
|
||||
#[error("unable to find a corresponding declaration for the given binding {0}")]
|
||||
MissingBindingDeclaration(u32),
|
||||
/// The given binding has a different type than the one in the layout.
|
||||
#[error("binding {binding} has a different type ({actual:?}) than the one in the layout ({expected:?})")]
|
||||
WrongBindingType {
|
||||
// Index of the binding
|
||||
binding: u32,
|
||||
@ -47,14 +50,14 @@ pub enum BindGroupError {
|
||||
// Human-readable description of expected types
|
||||
expected: &'static str,
|
||||
},
|
||||
/// The given sampler is/is not a comparison sampler,
|
||||
/// while the layout type indicates otherwise.
|
||||
#[error("the given sampler is/is not a comparison sampler, while the layout type indicates otherwise")]
|
||||
WrongSamplerComparison,
|
||||
/// Uniform buffer binding range exceeds [`wgt::Limits::max_uniform_buffer_binding_size`] limit
|
||||
#[error("uniform buffer binding range exceeds `max_uniform_buffer_binding_size` limit")]
|
||||
UniformBufferRangeTooLarge,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[error("too many bindings of type {kind:?} in stage {stage:?}, limit is {count}")]
|
||||
pub struct BindingTypeMaxCountError {
|
||||
pub kind: BindingTypeMaxCountErrorKind,
|
||||
pub stage: wgt::ShaderStage,
|
||||
@ -78,6 +81,7 @@ pub(crate) struct PerStageBindingTypeCounter {
|
||||
fragment: u32,
|
||||
compute: u32,
|
||||
}
|
||||
|
||||
impl PerStageBindingTypeCounter {
|
||||
pub(crate) fn add(&mut self, stage: wgt::ShaderStage, count: u32) {
|
||||
if stage.contains(wgt::ShaderStage::VERTEX) {
|
||||
@ -231,84 +235,66 @@ pub struct BindGroupLayout<B: hal::Backend> {
|
||||
pub(crate) count_validator: BindingTypeMaxCountValidator,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum PipelineLayoutError {
|
||||
TooManyGroups(usize),
|
||||
#[error("bind group layout count {actual} exceeds device bind group limit {max}")]
|
||||
TooManyGroups { actual: usize, max: usize },
|
||||
#[error(transparent)]
|
||||
TooManyBindings(BindingTypeMaxCountError),
|
||||
PushConstantRangeTooLarge { index: usize },
|
||||
MoreThanOnePushConstantRangePerStage { index: usize },
|
||||
MisalignedPushConstantRange { index: usize },
|
||||
#[error("push constant at index {index} has range {}..{} which exceeds device push constant size limit 0..{max}", range.start, range.end)]
|
||||
PushConstantRangeTooLarge {
|
||||
index: usize,
|
||||
range: Range<u32>,
|
||||
max: u32,
|
||||
},
|
||||
#[error("push constant range (index {index}) provides for stage(s) {provided:?} but there exists another range that provides stage(s) {intersected:?}. Each stage may only be provided by one range")]
|
||||
MoreThanOnePushConstantRangePerStage {
|
||||
index: usize,
|
||||
provided: wgt::ShaderStage,
|
||||
intersected: wgt::ShaderStage,
|
||||
},
|
||||
#[error(
|
||||
"push constant at index {index} has range bound {bound} not aligned to {}",
|
||||
wgt::PUSH_CONSTANT_ALIGNMENT
|
||||
)]
|
||||
MisalignedPushConstantRange { index: usize, bound: u32 },
|
||||
#[error("device does not have required feature: {0:?}")]
|
||||
MissingFeature(wgt::Features),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[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)]
|
||||
TooLarge {
|
||||
offset: u32,
|
||||
end_offset: u32,
|
||||
idx: usize,
|
||||
range: wgt::PushConstantRange,
|
||||
},
|
||||
#[error("provided push constant is for stage(s) {actual:?}, stage with a partial match found at index {idx} with stage(s) {matched:?}, however push constants must be complete matches")]
|
||||
PartialRangeMatch {
|
||||
actual: wgt::ShaderStage,
|
||||
idx: usize,
|
||||
matched: wgt::ShaderStage,
|
||||
},
|
||||
#[error("provided push constant is for stage(s) {actual:?}, but intersects a push constant range (at index {idx}) with stage(s) {missing:?}. Push constants must provide the stages for all ranges they intersect")]
|
||||
MissingStages {
|
||||
actual: wgt::ShaderStage,
|
||||
idx: usize,
|
||||
missing: wgt::ShaderStage,
|
||||
},
|
||||
#[error("provided push constant is for stage(s) {actual:?}, however the pipeline layout has no push constant range for the stage(s) {unmatched:?}")]
|
||||
UnmatchedStages {
|
||||
actual: wgt::ShaderStage,
|
||||
unmatched: wgt::ShaderStage,
|
||||
},
|
||||
#[error(
|
||||
"provided push constant offset {0} must be aligned to {}",
|
||||
wgt::PUSH_CONSTANT_ALIGNMENT
|
||||
)]
|
||||
Unaligned(u32),
|
||||
}
|
||||
|
||||
impl fmt::Display for PushConstantUploadError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::TooLarge { offset, end_offset, idx, range } => write!(
|
||||
f,
|
||||
"provided push constant with indices {}..{} overruns matching push constant range (index {}) with stage(s) {:?} and indices {}..{}",
|
||||
offset,
|
||||
end_offset,
|
||||
idx,
|
||||
range.stages,
|
||||
range.range.start,
|
||||
range.range.end,
|
||||
),
|
||||
Self::PartialRangeMatch { actual, idx, matched } => write!(
|
||||
f,
|
||||
"provided push constant is for stage(s) {:?}, stage with a partial match found at index {} with stage(s) {:?}, however push constants must be complete matches",
|
||||
actual,
|
||||
idx,
|
||||
matched,
|
||||
),
|
||||
Self::MissingStages { actual, idx, missing } => write!(
|
||||
f,
|
||||
"provided push constant is for stage(s) {:?}, but intersects a push constant range (at index {}) with stage(s) {:?}. Push constants must provide the stages for all ranges they intersect",
|
||||
actual,
|
||||
idx,
|
||||
missing,
|
||||
),
|
||||
Self::UnmatchedStages { actual, unmatched } => write!(
|
||||
f,
|
||||
"provided push constant is for stage(s) {:?}, however the pipeline layout has no push constant range for the stage(s) {:?}",
|
||||
actual,
|
||||
unmatched,
|
||||
),
|
||||
Self::Unaligned(offset) => write!(
|
||||
f,
|
||||
"provided push constant offset {} must be aligned to {}",
|
||||
offset,
|
||||
wgt::PUSH_CONSTANT_ALIGNMENT,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PipelineLayout<B: hal::Backend> {
|
||||
pub(crate) raw: B::PipelineLayout,
|
||||
@ -423,29 +409,16 @@ pub type BindGroupEntry<'a> = wgt::BindGroupEntry<BindingResource<'a>>;
|
||||
pub type BindGroupDescriptor<'a> =
|
||||
wgt::BindGroupDescriptor<'a, BindGroupLayoutId, BindGroupEntry<'a>>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum BindError {
|
||||
#[error("number of dynamic offsets ({actual}) doesn't match the number of dynamic bindings in the bind group layout ({expected})")]
|
||||
MismatchedDynamicOffsetCount { actual: usize, expected: usize },
|
||||
#[error("dynamic binding at index {idx} is not properly aligned")]
|
||||
UnalignedDynamicBinding { idx: usize },
|
||||
#[error("dynamic binding at index {idx} would overrun the buffer")]
|
||||
DynamicBindingOutOfBounds { idx: usize },
|
||||
}
|
||||
|
||||
impl fmt::Display for BindError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::MismatchedDynamicOffsetCount { actual, expected } =>
|
||||
write!(
|
||||
f,
|
||||
"number of dynamic offsets ({}) doesn't match the number of dynamic bindings in the bind group layout ({})",
|
||||
actual,
|
||||
expected,
|
||||
),
|
||||
Self::UnalignedDynamicBinding { idx } => write!(f, "dynamic binding at index {} is not properly aligned", idx),
|
||||
Self::DynamicBindingOutOfBounds { idx } => write!(f, "dynamic binding at index {} would overrun the buffer", idx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BindGroupDynamicBindingData {
|
||||
/// The maximum value the dynamic offset can have before running off the end of the buffer.
|
||||
|
@ -46,10 +46,12 @@ use crate::{
|
||||
resource::BufferUse,
|
||||
span,
|
||||
track::TrackerSet,
|
||||
validation::{check_buffer_usage, MissingBufferUsageError, MissingTextureUsageError},
|
||||
LifeGuard, RefCount, Stored, MAX_BIND_GROUPS,
|
||||
};
|
||||
use arrayvec::ArrayVec;
|
||||
use std::{borrow::Borrow, fmt, iter, marker::PhantomData, ops::Range};
|
||||
use std::{borrow::Borrow, iter, marker::PhantomData, ops::Range};
|
||||
use thiserror::Error;
|
||||
|
||||
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct RenderBundleEncoder {
|
||||
@ -91,19 +93,12 @@ impl RenderBundleEncoder {
|
||||
}
|
||||
|
||||
/// Error type returned from `RenderBundleEncoder::new` if the sample count is invalid.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum CreateRenderBundleError {
|
||||
#[error("invalid number of samples {0}")]
|
||||
InvalidSampleCount(u32),
|
||||
}
|
||||
|
||||
impl fmt::Display for CreateRenderBundleError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::InvalidSampleCount(count) => write!(f, "invalid number of samples {}", count),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Note: here, `RenderBundle` is just wrapping a raw stream of render commands.
|
||||
// The plan is to back it by an actual Vulkan secondary buffer, D3D12 Bundle,
|
||||
// or Metal indirect command buffer.
|
||||
@ -599,119 +594,38 @@ impl State {
|
||||
}
|
||||
|
||||
/// Error encountered when encoding a render command.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum RenderCommandError {
|
||||
BindGroupIndexOutOfRange {
|
||||
index: u8,
|
||||
max: u32,
|
||||
},
|
||||
#[error("bind group index {index} is greater than the device's requested `max_bind_group` limit {max}")]
|
||||
BindGroupIndexOutOfRange { index: u8, max: u32 },
|
||||
#[error(
|
||||
"dynamic buffer offset {0} is not a multiple of the required buffer alignment {}",
|
||||
wgt::BIND_BUFFER_ALIGNMENT
|
||||
)]
|
||||
UnalignedBufferOffset(u64),
|
||||
InvalidDynamicOffsetCount {
|
||||
actual: usize,
|
||||
expected: usize,
|
||||
},
|
||||
#[error("number of buffer offsets ({actual}) does not match the number of dynamic bindings ({expected})")]
|
||||
InvalidDynamicOffsetCount { actual: usize, expected: usize },
|
||||
#[error("render pipeline output formats and sample counts do not match render pass attachment formats")]
|
||||
IncompatiblePipeline,
|
||||
#[error("pipeline is not compatible with the depth-stencil read-only render pass")]
|
||||
IncompatibleReadOnlyDepthStencil,
|
||||
MissingBufferUsage {
|
||||
actual: wgt::BufferUsage,
|
||||
expected: wgt::BufferUsage,
|
||||
},
|
||||
InvalidTextureUsage {
|
||||
actual: wgt::TextureUsage,
|
||||
expected: wgt::TextureUsage,
|
||||
},
|
||||
#[error(transparent)]
|
||||
MissingBufferUsage(#[from] MissingBufferUsageError),
|
||||
#[error(transparent)]
|
||||
MissingTextureUsage(#[from] MissingTextureUsageError),
|
||||
#[error("a render pipeline must be bound")]
|
||||
UnboundPipeline,
|
||||
PushConstants(PushConstantUploadError),
|
||||
VertexBeyondLimit {
|
||||
last_vertex: u32,
|
||||
vertex_limit: u32,
|
||||
},
|
||||
#[error(transparent)]
|
||||
PushConstants(#[from] PushConstantUploadError),
|
||||
#[error("vertex {last_vertex} extends beyond limit {vertex_limit}")]
|
||||
VertexBeyondLimit { last_vertex: u32, vertex_limit: u32 },
|
||||
#[error("instance {last_instance} extends beyond limit {instance_limit}")]
|
||||
InstanceBeyondLimit {
|
||||
last_instance: u32,
|
||||
instance_limit: u32,
|
||||
},
|
||||
IndexBeyondLimit {
|
||||
last_index: u32,
|
||||
index_limit: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<PushConstantUploadError> for RenderCommandError {
|
||||
fn from(error: PushConstantUploadError) -> Self {
|
||||
Self::PushConstants(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RenderCommandError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::BindGroupIndexOutOfRange { index, max } => write!(
|
||||
f,
|
||||
"bind group index {} is greater than the device's requested `max_bind_group` limit {}",
|
||||
index,
|
||||
max,
|
||||
),
|
||||
Self::UnalignedBufferOffset(offset) => write!(
|
||||
f,
|
||||
"dynamic buffer offset {} is not a multiple of the required buffer alignment {}",
|
||||
offset,
|
||||
wgt::BIND_BUFFER_ALIGNMENT,
|
||||
),
|
||||
Self::InvalidDynamicOffsetCount { actual, expected } => write!(
|
||||
f,
|
||||
"number of buffer offsets ({}) does not match the number of dynamic bindings ({})",
|
||||
actual,
|
||||
expected,
|
||||
),
|
||||
Self::IncompatiblePipeline => write!(f, "render pipeline output formats and sample counts do not match render pass attachment formats"),
|
||||
Self::IncompatibleReadOnlyDepthStencil => write!(f, "pipeline is not compatible with the depth-stencil read-only render pass"),
|
||||
Self::MissingBufferUsage { actual, expected } => write!(
|
||||
f,
|
||||
"buffer usage is {:?} which does not contain required usage {:?}",
|
||||
actual,
|
||||
expected,
|
||||
),
|
||||
Self::InvalidTextureUsage { actual, expected } => write!(
|
||||
f,
|
||||
"texture usage is {:?} which does not contain required usage {:?}",
|
||||
actual,
|
||||
expected,
|
||||
),
|
||||
Self::UnboundPipeline => write!(f, "a render pipeline must be bound"),
|
||||
Self::PushConstants(error) => write!(f, "{}", error),
|
||||
Self::VertexBeyondLimit { last_vertex, vertex_limit } => write!(
|
||||
f,
|
||||
"vertex {} extends beyond limit {}",
|
||||
last_vertex,
|
||||
vertex_limit,
|
||||
),
|
||||
Self::InstanceBeyondLimit { last_instance, instance_limit } => write!(
|
||||
f,
|
||||
"instance {} extends beyond limit {}",
|
||||
last_instance,
|
||||
instance_limit,
|
||||
),
|
||||
Self::IndexBeyondLimit { last_index, index_limit } => write!(
|
||||
f,
|
||||
"index {} extends beyond limit {}",
|
||||
last_index,
|
||||
index_limit,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks that the given buffer usage contains the required buffer usage,
|
||||
/// returns an error otherwise.
|
||||
pub fn check_buffer_usage(
|
||||
actual: wgt::BufferUsage,
|
||||
expected: wgt::BufferUsage,
|
||||
) -> Result<(), RenderCommandError> {
|
||||
if !actual.contains(expected) {
|
||||
Err(RenderCommandError::MissingBufferUsage { actual, expected })
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
#[error("index {last_index} extends beyond limit {index_limit}")]
|
||||
IndexBeyondLimit { last_index: u32, index_limit: u32 },
|
||||
}
|
||||
|
||||
impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
|
@ -13,9 +13,11 @@ use crate::{
|
||||
id,
|
||||
resource::BufferUse,
|
||||
span,
|
||||
validation::{check_buffer_usage, MissingBufferUsageError},
|
||||
};
|
||||
|
||||
use hal::command::CommandBuffer as _;
|
||||
use thiserror::Error;
|
||||
use wgt::{BufferAddress, BufferUsage};
|
||||
|
||||
use std::{fmt, iter, str};
|
||||
@ -108,55 +110,20 @@ struct State {
|
||||
debug_scope_depth: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum ComputePassError {
|
||||
BindGroupIndexOutOfRange {
|
||||
index: u8,
|
||||
max: u32,
|
||||
},
|
||||
#[error("bind group index {index} is greater than the device's requested `max_bind_group` limit {max}")]
|
||||
BindGroupIndexOutOfRange { index: u8, max: u32 },
|
||||
#[error("a compute pipeline must be bound")]
|
||||
UnboundPipeline,
|
||||
MissingBufferUsage {
|
||||
actual: BufferUsage,
|
||||
expected: BufferUsage,
|
||||
},
|
||||
#[error(transparent)]
|
||||
MissingBufferUsage(#[from] MissingBufferUsageError),
|
||||
#[error("cannot pop debug group, because number of pushed debug groups is zero")]
|
||||
InvalidPopDebugGroup,
|
||||
Bind(BindError),
|
||||
PushConstants(PushConstantUploadError),
|
||||
}
|
||||
|
||||
impl From<PushConstantUploadError> for ComputePassError {
|
||||
fn from(error: PushConstantUploadError) -> Self {
|
||||
Self::PushConstants(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BindError> for ComputePassError {
|
||||
fn from(error: BindError) -> Self {
|
||||
Self::Bind(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ComputePassError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::BindGroupIndexOutOfRange { index, max } => write!(
|
||||
f,
|
||||
"bind group index {} is greater than the device's requested `max_bind_group` limit {}",
|
||||
index,
|
||||
max,
|
||||
),
|
||||
Self::UnboundPipeline => write!(f, "a compute pipeline must be bound"),
|
||||
Self::MissingBufferUsage { actual, expected } => write!(
|
||||
f,
|
||||
"buffer usage is {:?} which does not contain required usage {:?}",
|
||||
actual,
|
||||
expected,
|
||||
),
|
||||
Self::InvalidPopDebugGroup => write!(f, "cannot pop debug group, because number of pushed debug groups is zero"),
|
||||
Self::Bind(error) => write!(f, "{}", error),
|
||||
Self::PushConstants(error) => write!(f, "{}", error),
|
||||
}
|
||||
}
|
||||
#[error(transparent)]
|
||||
Bind(#[from] BindError),
|
||||
#[error(transparent)]
|
||||
PushConstants(#[from] PushConstantUploadError),
|
||||
}
|
||||
|
||||
// Common routines between render/compute
|
||||
@ -381,12 +348,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
(),
|
||||
BufferUse::INDIRECT,
|
||||
);
|
||||
if !src_buffer.usage.contains(BufferUsage::INDIRECT) {
|
||||
return Err(ComputePassError::MissingBufferUsage {
|
||||
actual: src_buffer.usage,
|
||||
expected: BufferUsage::INDIRECT,
|
||||
});
|
||||
}
|
||||
check_buffer_usage(src_buffer.usage, BufferUsage::INDIRECT)?;
|
||||
|
||||
let barriers = src_pending.map(|pending| pending.into_hal(src_buffer));
|
||||
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
binding_model::BindError,
|
||||
command::{
|
||||
bind::{Binder, LayoutChange},
|
||||
check_buffer_usage, BasePass, BasePassRef, RenderCommandError,
|
||||
BasePass, BasePassRef, RenderCommandError,
|
||||
},
|
||||
conv,
|
||||
device::{
|
||||
@ -19,11 +19,15 @@ use crate::{
|
||||
resource::{BufferUse, TextureUse, TextureViewInner},
|
||||
span,
|
||||
track::TrackerSet,
|
||||
validation::{
|
||||
check_buffer_usage, check_texture_usage, MissingBufferUsageError, MissingTextureUsageError,
|
||||
},
|
||||
Stored,
|
||||
};
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use hal::command::CommandBuffer as _;
|
||||
use thiserror::Error;
|
||||
use wgt::{
|
||||
BufferAddress, BufferSize, BufferUsage, Color, IndexFormat, InputStepMode, TextureUsage,
|
||||
};
|
||||
@ -270,11 +274,15 @@ impl OptionalState {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[derive(Clone, Debug, Error, PartialEq)]
|
||||
pub enum DrawError {
|
||||
#[error("blend color needs to be set")]
|
||||
MissingBlendColor,
|
||||
#[error("stencil reference needs to be set")]
|
||||
MissingStencilReference,
|
||||
#[error("render pipeline must be set")]
|
||||
MissingPipeline,
|
||||
#[error("current render pipeline has a layout which is incompatible with a currently set bind group, first differing at entry index {index}")]
|
||||
IncompatibleBindGroup {
|
||||
index: u32,
|
||||
//expected: BindGroupLayoutId,
|
||||
@ -282,17 +290,6 @@ pub enum DrawError {
|
||||
},
|
||||
}
|
||||
|
||||
impl fmt::Display for DrawError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
DrawError::MissingBlendColor => write!(f, "blend color needs to be set"),
|
||||
DrawError::MissingStencilReference => write!(f, "stencil reference needs to be set"),
|
||||
DrawError::MissingPipeline => write!(f, "render pipeline must be set"),
|
||||
DrawError::IncompatibleBindGroup { index } => write!(f, "current render pipeline has a layout which is incompatible with a currently set bind group, first differing at entry index {}", index),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct IndexState {
|
||||
bound_buffer_view: Option<(id::BufferId, Range<BufferAddress>)>,
|
||||
@ -408,25 +405,34 @@ impl State {
|
||||
}
|
||||
|
||||
/// Error encountered when performing a render pass.
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum RenderPassError {
|
||||
#[error("attachment's sample count {0} is invalid")]
|
||||
InvalidSampleCount(u8),
|
||||
#[error("attachment with resolve target must be multi-sampled")]
|
||||
InvalidResolveSourceSampleCount,
|
||||
#[error("resolve target must have a sample count of 1")]
|
||||
InvalidResolveTargetSampleCount,
|
||||
#[error("extent state {state_extent:?} must match extent from view {view_extent:?}")]
|
||||
ExtentStateMismatch {
|
||||
state_extent: hal::image::Extent,
|
||||
view_extent: hal::image::Extent,
|
||||
},
|
||||
#[error("attempted to use a swap chain image as a depth/stencil attachment")]
|
||||
SwapChainImageAsDepthStencil,
|
||||
#[error("unable to clear non-present/read-only depth")]
|
||||
InvalidDepthOps,
|
||||
#[error("unable to clear non-present/read-only stencil")]
|
||||
InvalidStencilOps,
|
||||
SampleCountMismatch {
|
||||
actual: u8,
|
||||
expected: u8,
|
||||
},
|
||||
#[error("all attachments must have the same sample count, found {actual} != {expected}")]
|
||||
SampleCountMismatch { actual: u8, expected: u8 },
|
||||
#[error("texture view's swap chain must match swap chain in use")]
|
||||
SwapChainMismatch,
|
||||
#[error("setting `values_offset` to be `None` is only for internal use in render bundles")]
|
||||
InvalidValuesOffset,
|
||||
#[error("required device features not enabled: {0:?}")]
|
||||
MissingDeviceFeatures(wgt::Features),
|
||||
#[error("indirect draw with offset {offset}{} uses bytes {begin_offset}..{end_offset} which overruns indirect buffer of size {buffer_size}", count.map_or_else(String::new, |v| format!(" and count {}", v)))]
|
||||
IndirectBufferOverrun {
|
||||
offset: u64,
|
||||
count: Option<u32>,
|
||||
@ -434,90 +440,33 @@ pub enum RenderPassError {
|
||||
end_offset: u64,
|
||||
buffer_size: u64,
|
||||
},
|
||||
#[error("indirect draw uses bytes {begin_count_offset}..{end_count_offset} which overruns indirect buffer of size {count_buffer_size}")]
|
||||
IndirectCountBufferOverrun {
|
||||
begin_count_offset: u64,
|
||||
end_count_offset: u64,
|
||||
count_buffer_size: u64,
|
||||
},
|
||||
#[error("cannot pop debug group, because number of pushed debug groups is zero")]
|
||||
InvalidPopDebugGroup,
|
||||
#[error("render bundle output formats do not match render pass attachment formats")]
|
||||
IncompatibleRenderBundle,
|
||||
RenderCommand(RenderCommandError),
|
||||
Draw(DrawError),
|
||||
Bind(BindError),
|
||||
#[error(transparent)]
|
||||
RenderCommand(#[from] RenderCommandError),
|
||||
#[error(transparent)]
|
||||
Draw(#[from] DrawError),
|
||||
#[error(transparent)]
|
||||
Bind(#[from] BindError),
|
||||
}
|
||||
|
||||
impl From<RenderCommandError> for RenderPassError {
|
||||
fn from(error: RenderCommandError) -> Self {
|
||||
Self::RenderCommand(error)
|
||||
impl From<MissingBufferUsageError> for RenderPassError {
|
||||
fn from(error: MissingBufferUsageError) -> Self {
|
||||
Self::RenderCommand(error.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DrawError> for RenderPassError {
|
||||
fn from(error: DrawError) -> Self {
|
||||
Self::Draw(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BindError> for RenderPassError {
|
||||
fn from(error: BindError) -> Self {
|
||||
Self::Bind(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RenderPassError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::InvalidSampleCount(count) => write!(
|
||||
f,
|
||||
"attachment's sample count {} is invalid",
|
||||
count,
|
||||
),
|
||||
Self::InvalidResolveSourceSampleCount => write!(f, "attachment with resolve target must be multi-sampled"),
|
||||
Self::InvalidResolveTargetSampleCount => write!(f, "resolve target must have a sample count of 1"),
|
||||
Self::ExtentStateMismatch { state_extent, view_extent } => write!(
|
||||
f,
|
||||
"extent state {:?} must match extent from view {:?}",
|
||||
state_extent,
|
||||
view_extent,
|
||||
),
|
||||
Self::SwapChainImageAsDepthStencil => write!(f, "attempted to use a swap chain image as a depth/stencil attachment"),
|
||||
Self::InvalidDepthOps => write!(f, "unable to clear non-present/read-only depth"),
|
||||
Self::InvalidStencilOps => write!(f, "unable to clear non-present/read-only stencil"),
|
||||
Self::SampleCountMismatch { actual, expected } => write!(
|
||||
f,
|
||||
"all attachments must have the same sample count, found {} != {}",
|
||||
actual,
|
||||
expected,
|
||||
),
|
||||
Self::SwapChainMismatch => write!(f, "texture view's swap chain must match swap chain in use"),
|
||||
Self::InvalidValuesOffset => write!(f, "setting `values_offset` to be `None` is only for internal use in render bundles"),
|
||||
Self::MissingDeviceFeatures(expected) => write!(
|
||||
f,
|
||||
"required device features not enabled: {:?}",
|
||||
expected,
|
||||
),
|
||||
Self::IndirectBufferOverrun { offset, count, begin_offset, end_offset, buffer_size } => write!(
|
||||
f,
|
||||
"indirect draw with offset {}{} uses bytes {}..{} which overruns indirect buffer of size {}",
|
||||
offset,
|
||||
count.map_or_else(String::new, |v| format!(" and count {}", v)),
|
||||
begin_offset,
|
||||
end_offset,
|
||||
buffer_size,
|
||||
),
|
||||
Self::IndirectCountBufferOverrun { begin_count_offset, end_count_offset, count_buffer_size } => write!(
|
||||
f,
|
||||
"indirect draw uses bytes {}..{} which overruns indirect buffer of size {}",
|
||||
begin_count_offset,
|
||||
end_count_offset,
|
||||
count_buffer_size,
|
||||
),
|
||||
Self::InvalidPopDebugGroup => write!(f, "cannot pop debug group, because number of pushed debug groups is zero"),
|
||||
Self::IncompatibleRenderBundle => write!(f, "render bundle output formats do not match render pass attachment formats"),
|
||||
Self::RenderCommand(error) => write!(f, "{}", error),
|
||||
Self::Draw(error) => write!(f, "{}", error),
|
||||
Self::Bind(error) => write!(f, "{}", error),
|
||||
}
|
||||
impl From<MissingTextureUsageError> for RenderPassError {
|
||||
fn from(error: MissingTextureUsageError) -> Self {
|
||||
Self::RenderCommand(error.into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1642,13 +1591,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
|
||||
for ot in output_attachments {
|
||||
let texture = &texture_guard[ot.texture_id.value];
|
||||
if !texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT) {
|
||||
return Err(RenderCommandError::InvalidTextureUsage {
|
||||
actual: texture.usage,
|
||||
expected: TextureUsage::OUTPUT_ATTACHMENT,
|
||||
}
|
||||
.into());
|
||||
}
|
||||
check_texture_usage(texture.usage, TextureUsage::OUTPUT_ATTACHMENT)?;
|
||||
|
||||
// the tracker set of the pass is always in "extend" mode
|
||||
trackers
|
||||
|
@ -14,6 +14,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use hal::command::CommandBuffer as _;
|
||||
use thiserror::Error;
|
||||
use wgt::{BufferAddress, BufferUsage, Extent3d, TextureDataLayout, TextureUsage};
|
||||
|
||||
use std::iter;
|
||||
@ -27,36 +28,33 @@ pub type BufferCopyView = wgt::BufferCopyView<BufferId>;
|
||||
pub type TextureCopyView = wgt::TextureCopyView<TextureId>;
|
||||
|
||||
/// Error encountered while attempting a data transfer.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug, Error, Eq, PartialEq)]
|
||||
pub enum TransferError {
|
||||
/// The source buffer/texture is missing the `COPY_SRC` usage flag.
|
||||
#[error("source buffer/texture is missing the `COPY_SRC` usage flag")]
|
||||
MissingCopySrcUsageFlag,
|
||||
/// The destination buffer/texture is missing the `COPY_DST` usage flag.
|
||||
#[error("destination buffer/texture is missing the `COPY_DST` usage flag")]
|
||||
MissingCopyDstUsageFlag,
|
||||
/// Copy would end up overruning the bounds of the destination buffer/texture.
|
||||
#[error("copy would end up overruning the bounds of the destination buffer/texture")]
|
||||
BufferOverrun,
|
||||
/// Buffer offset is not aligned to block size.
|
||||
#[error("buffer offset is not aligned to block size")]
|
||||
UnalignedBufferOffset,
|
||||
/// Copy size is not a multiple of block size.
|
||||
#[error("copy size is not a multiple of block size")]
|
||||
UnalignedCopySize,
|
||||
/// Copy width is not a multiple of block size.
|
||||
#[error("copy width is not a multiple of block size")]
|
||||
UnalignedCopyWidth,
|
||||
/// Copy height is not a multiple of block size.
|
||||
#[error("copy height is not a multiple of block size")]
|
||||
UnalignedCopyHeight,
|
||||
/// Bytes per row is not a multiple of the required alignment.
|
||||
#[error("bytes per row is not a multiple of the required alignment")]
|
||||
UnalignedBytesPerRow,
|
||||
/// Number of rows per image is not a multiple of the required alignment.
|
||||
#[error("number of rows per image is not a multiple of the required alignment")]
|
||||
UnalignedRowsPerImage,
|
||||
/// Number of bytes per row is less than the number of bytes in a complete row.
|
||||
#[error("number of bytes per row is less than the number of bytes in a complete row")]
|
||||
InvalidBytesPerRow,
|
||||
/// Copy size is invalid.
|
||||
///
|
||||
/// This can happen if the image is 1D and the copy height and depth
|
||||
/// are not both set to 1.
|
||||
#[error("image is 1D and the copy height and depth are not both set to 1")]
|
||||
InvalidCopySize,
|
||||
/// Number of rows per image is invalid.
|
||||
#[error("number of rows per image is invalid")]
|
||||
InvalidRowsPerImage,
|
||||
/// The source and destination layers have different aspects.
|
||||
#[error("source and destination layers have different aspects")]
|
||||
MismatchedAspects,
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::{
|
||||
binding_model::{self, BindGroupError},
|
||||
binding_model::{self, CreateBindGroupError, PipelineLayoutError},
|
||||
command, conv,
|
||||
hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Hub, Input, Token},
|
||||
id, pipeline, resource, span, swap_chain,
|
||||
@ -1350,7 +1350,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
device_id: id::DeviceId,
|
||||
desc: &wgt::PipelineLayoutDescriptor<id::BindGroupLayoutId>,
|
||||
id_in: Input<G, id::PipelineLayoutId>,
|
||||
) -> Result<id::PipelineLayoutId, binding_model::PipelineLayoutError> {
|
||||
) -> Result<id::PipelineLayoutId, PipelineLayoutError> {
|
||||
span!(_guard, INFO, "Device::create_pipeline_layout");
|
||||
|
||||
let hub = B::hub(self);
|
||||
@ -1358,75 +1358,53 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
|
||||
let (device_guard, mut token) = hub.devices.read(&mut token);
|
||||
let device = &device_guard[device_id];
|
||||
if desc.bind_group_layouts.len() > (device.limits.max_bind_groups as usize) {
|
||||
log::error!(
|
||||
"Bind group layout count {} exceeds device bind group limit {}",
|
||||
desc.bind_group_layouts.len(),
|
||||
device.limits.max_bind_groups
|
||||
);
|
||||
return Err(binding_model::PipelineLayoutError::TooManyGroups(
|
||||
desc.bind_group_layouts.len(),
|
||||
));
|
||||
let bind_group_layouts_count = desc.bind_group_layouts.len();
|
||||
let device_max_bind_groups = device.limits.max_bind_groups as usize;
|
||||
if bind_group_layouts_count > device_max_bind_groups {
|
||||
return Err(PipelineLayoutError::TooManyGroups {
|
||||
actual: bind_group_layouts_count,
|
||||
max: device_max_bind_groups,
|
||||
});
|
||||
}
|
||||
|
||||
if !desc.push_constant_ranges.is_empty()
|
||||
&& !device.features.contains(wgt::Features::PUSH_CONSTANTS)
|
||||
{
|
||||
return Err(binding_model::PipelineLayoutError::MissingFeature(
|
||||
return Err(PipelineLayoutError::MissingFeature(
|
||||
wgt::Features::PUSH_CONSTANTS,
|
||||
));
|
||||
}
|
||||
let mut used_stages = wgt::ShaderStage::empty();
|
||||
for (index, pc) in desc.push_constant_ranges.iter().enumerate() {
|
||||
if pc.stages.intersects(used_stages) {
|
||||
log::error!(
|
||||
"Push constant range (index {}) provides for stage(s) {:?} but there exists another range that provides stage(s) {:?}. Each stage may only be provided by one range.",
|
||||
return Err(PipelineLayoutError::MoreThanOnePushConstantRangePerStage {
|
||||
index,
|
||||
pc.stages,
|
||||
pc.stages & used_stages,
|
||||
);
|
||||
return Err(
|
||||
binding_model::PipelineLayoutError::MoreThanOnePushConstantRangePerStage {
|
||||
index,
|
||||
},
|
||||
);
|
||||
provided: pc.stages,
|
||||
intersected: pc.stages & used_stages,
|
||||
});
|
||||
}
|
||||
used_stages |= pc.stages;
|
||||
|
||||
if device.limits.max_push_constant_size < pc.range.end {
|
||||
log::error!(
|
||||
"Push constant range (index {}) has range {}..{} which exceeds device push constant size limit 0..{}",
|
||||
let device_max_pc_size = device.limits.max_push_constant_size;
|
||||
if device_max_pc_size < pc.range.end {
|
||||
return Err(PipelineLayoutError::PushConstantRangeTooLarge {
|
||||
index,
|
||||
pc.range.start,
|
||||
pc.range.end,
|
||||
device.limits.max_push_constant_size
|
||||
);
|
||||
return Err(
|
||||
binding_model::PipelineLayoutError::PushConstantRangeTooLarge { index },
|
||||
);
|
||||
range: pc.range.clone(),
|
||||
max: device_max_pc_size,
|
||||
});
|
||||
}
|
||||
|
||||
if pc.range.start % wgt::PUSH_CONSTANT_ALIGNMENT != 0 {
|
||||
log::error!(
|
||||
"Push constant range (index {}) start {} must be aligned to {}",
|
||||
return Err(PipelineLayoutError::MisalignedPushConstantRange {
|
||||
index,
|
||||
pc.range.start,
|
||||
wgt::PUSH_CONSTANT_ALIGNMENT
|
||||
);
|
||||
return Err(
|
||||
binding_model::PipelineLayoutError::MisalignedPushConstantRange { index },
|
||||
);
|
||||
bound: pc.range.start,
|
||||
});
|
||||
}
|
||||
if pc.range.end % wgt::PUSH_CONSTANT_ALIGNMENT != 0 {
|
||||
log::error!(
|
||||
"Push constant range (index {}) end {} must be aligned to {}",
|
||||
return Err(PipelineLayoutError::MisalignedPushConstantRange {
|
||||
index,
|
||||
pc.range.end,
|
||||
wgt::PUSH_CONSTANT_ALIGNMENT
|
||||
);
|
||||
return Err(
|
||||
binding_model::PipelineLayoutError::MisalignedPushConstantRange { index },
|
||||
);
|
||||
bound: pc.range.end,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1454,7 +1432,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
};
|
||||
count_validator
|
||||
.validate(&device.limits)
|
||||
.map_err(binding_model::PipelineLayoutError::TooManyBindings)?;
|
||||
.map_err(PipelineLayoutError::TooManyBindings)?;
|
||||
|
||||
let layout = binding_model::PipelineLayout {
|
||||
raw: pipeline_layout,
|
||||
@ -1521,7 +1499,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
device_id: id::DeviceId,
|
||||
desc: &binding_model::BindGroupDescriptor,
|
||||
id_in: Input<G, id::BindGroupId>,
|
||||
) -> Result<id::BindGroupId, BindGroupError> {
|
||||
) -> Result<id::BindGroupId, CreateBindGroupError> {
|
||||
use crate::binding_model::BindingResource as Br;
|
||||
|
||||
span!(_guard, INFO, "Device::create_bind_group");
|
||||
@ -1539,7 +1517,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let actual = desc.entries.len();
|
||||
let expected = bind_group_layout.entries.len();
|
||||
if actual != expected {
|
||||
return Err(BindGroupError::BindingsNumMismatch { expected, actual });
|
||||
return Err(CreateBindGroupError::BindingsNumMismatch { expected, actual });
|
||||
}
|
||||
|
||||
let mut desc_set = {
|
||||
@ -1590,7 +1568,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let decl = bind_group_layout
|
||||
.entries
|
||||
.get(&binding)
|
||||
.ok_or(BindGroupError::MissingBindingDeclaration(binding))?;
|
||||
.ok_or(CreateBindGroupError::MissingBindingDeclaration(binding))?;
|
||||
let descriptors: SmallVec<[_; 1]> = match entry.resource {
|
||||
Br::Buffer(ref bb) => {
|
||||
let (pub_usage, internal_use, min_size, dynamic) = match decl.ty {
|
||||
@ -1618,7 +1596,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
dynamic,
|
||||
),
|
||||
_ => {
|
||||
return Err(BindGroupError::WrongBindingType {
|
||||
return Err(CreateBindGroupError::WrongBindingType {
|
||||
binding,
|
||||
actual: decl.ty.clone(),
|
||||
expected:
|
||||
@ -1661,7 +1639,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
if pub_usage == wgt::BufferUsage::UNIFORM
|
||||
&& (device.limits.max_uniform_buffer_binding_size as u64) < bind_size
|
||||
{
|
||||
return Err(BindGroupError::UniformBufferRangeTooLarge);
|
||||
return Err(CreateBindGroupError::UniformBufferRangeTooLarge);
|
||||
}
|
||||
|
||||
// Record binding info for validating dynamic offsets
|
||||
@ -1696,13 +1674,13 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
|
||||
// Check the actual sampler to also (not) be a comparison sampler
|
||||
if sampler.comparison != comparison {
|
||||
return Err(BindGroupError::WrongSamplerComparison);
|
||||
return Err(CreateBindGroupError::WrongSamplerComparison);
|
||||
}
|
||||
|
||||
SmallVec::from([hal::pso::Descriptor::Sampler(&sampler.raw)])
|
||||
}
|
||||
_ => {
|
||||
return Err(BindGroupError::WrongBindingType {
|
||||
return Err(CreateBindGroupError::WrongBindingType {
|
||||
binding,
|
||||
actual: decl.ty.clone(),
|
||||
expected: "Sampler",
|
||||
@ -1728,7 +1706,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
resource::TextureUse::STORAGE_STORE
|
||||
},
|
||||
),
|
||||
_ => return Err(BindGroupError::WrongBindingType {
|
||||
_ => return Err(CreateBindGroupError::WrongBindingType {
|
||||
binding,
|
||||
actual: decl.ty.clone(),
|
||||
expected: "SampledTexture, ReadonlyStorageTexture or WriteonlyStorageTexture"
|
||||
@ -1790,7 +1768,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
(wgt::TextureUsage::SAMPLED, resource::TextureUse::SAMPLED)
|
||||
}
|
||||
_ => {
|
||||
return Err(BindGroupError::WrongBindingType {
|
||||
return Err(CreateBindGroupError::WrongBindingType {
|
||||
binding,
|
||||
actual: decl.ty.clone(),
|
||||
expected: "SampledTextureArray",
|
||||
|
@ -2,23 +2,16 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::fmt;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
#[error("battery status is unsupported on this platform")]
|
||||
Unsupported,
|
||||
#[error("battery status retrieval failed: {0}")]
|
||||
Error(Box<dyn std::error::Error>),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::Unsupported => write!(f, "Battery status is unsupported on this platform"),
|
||||
Error::Error(err) => write!(f, "Battery status retrieval failed: {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(
|
||||
feature = "battery",
|
||||
any(
|
||||
|
@ -7,6 +7,46 @@ use spirv_headers as spirv;
|
||||
use thiserror::Error;
|
||||
use wgt::{BindGroupLayoutEntry, BindingType};
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[error("buffer usage is {actual:?} which does not contain required usage {expected:?}")]
|
||||
pub struct MissingBufferUsageError {
|
||||
pub(crate) actual: wgt::BufferUsage,
|
||||
pub(crate) expected: wgt::BufferUsage,
|
||||
}
|
||||
|
||||
/// Checks that the given buffer usage contains the required buffer usage,
|
||||
/// returns an error otherwise.
|
||||
pub fn check_buffer_usage(
|
||||
actual: wgt::BufferUsage,
|
||||
expected: wgt::BufferUsage,
|
||||
) -> Result<(), MissingBufferUsageError> {
|
||||
if !actual.contains(expected) {
|
||||
Err(MissingBufferUsageError { actual, expected })
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
#[error("texture usage is {actual:?} which does not contain required usage {expected:?}")]
|
||||
pub struct MissingTextureUsageError {
|
||||
pub(crate) actual: wgt::TextureUsage,
|
||||
pub(crate) expected: wgt::TextureUsage,
|
||||
}
|
||||
|
||||
/// Checks that the given texture usage contains the required texture usage,
|
||||
/// returns an error otherwise.
|
||||
pub fn check_texture_usage(
|
||||
actual: wgt::TextureUsage,
|
||||
expected: wgt::TextureUsage,
|
||||
) -> Result<(), MissingTextureUsageError> {
|
||||
if !actual.contains(expected) {
|
||||
Err(MissingTextureUsageError { actual, expected })
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Error)]
|
||||
pub enum BindingError {
|
||||
#[error("binding is missing from the pipeline layout")]
|
||||
|
Loading…
Reference in New Issue
Block a user