usecrate::span::{AddSpan as _, MapErrWithSpan as _, SpanProvider as _, WithSpan}; use bit_set::BitSet;
const MAX_WORKGROUP_SIZE: u32 = 0x4000;
#[derive(Clone, Debug, thiserror::Error)] #[cfg_attr(test, derive(PartialEq))] pubenum GlobalVariableError { #[error("Usage isn't compatible with address space {0:?}")]
InvalidUsage(crate::AddressSpace), #[error("Type isn't compatible with address space {0:?}")]
InvalidType(crate::AddressSpace), #[error("Type flags {seen:?} do not meet the required {required:?}")]
MissingTypeFlags {
required: super::TypeFlags,
seen: super::TypeFlags,
}, #[error("Capability {0:?} is not supported")]
UnsupportedCapability(Capabilities), #[error("Binding decoration is missing or not applicable")]
InvalidBinding, #[error("Alignment requirements for address space {0:?} are not met by {1:?}")]
Alignment( crate::AddressSpace,
Handle<crate::Type>, #[source] Disalignment,
), #[error("Initializer must be an override-expression")]
InitializerExprType, #[error("Initializer doesn't match the variable type")]
InitializerType, #[error("Initializer can't be used with address space {0:?}")]
InitializerNotAllowed(crate::AddressSpace), #[error("Storage address space doesn't support write-only access")]
StorageAddressSpaceWriteOnlyNotSupported,
}
#[derive(Clone, Debug, thiserror::Error)] #[cfg_attr(test, derive(PartialEq))] pubenum VaryingError { #[error("The type {0:?} does not match the varying")]
InvalidType(Handle<crate::Type>), #[error("The type {0:?} cannot be used for user-defined entry point inputs or outputs")]
NotIOShareableType(Handle<crate::Type>), #[error("Interpolation is not valid")]
InvalidInterpolation, #[error("Cannot combine {interpolation:?} interpolation with the {sampling:?} sample type")]
InvalidInterpolationSamplingCombination {
interpolation: crate::Interpolation,
sampling: crate::Sampling,
}, #[error("Interpolation must be specified on vertex shader outputs and fragment shader inputs")]
MissingInterpolation, #[error("Built-in {0:?} is not available at this stage")]
InvalidBuiltInStage(crate::BuiltIn), #[error("Built-in type for {0:?} is invalid")]
InvalidBuiltInType(crate::BuiltIn), #[error("Entry point arguments and return values must all have bindings")]
MissingBinding, #[error("Struct member {0} is missing a binding")]
MemberMissingBinding(u32), #[error("Multiple bindings at location {location} are present")]
BindingCollision { location: u32 }, #[error("Built-in {0:?} is present more than once")]
DuplicateBuiltIn(crate::BuiltIn), #[error("Capability {0:?} is not supported")]
UnsupportedCapability(Capabilities), #[error("The attribute {0:?} is only valid as an output for stage {1:?}")]
InvalidInputAttributeInStage(&'static str, crate::ShaderStage), #[error("The attribute {0:?} is not valid for stage {1:?}")]
InvalidAttributeInStage(&'static str, crate::ShaderStage), #[error( "The location index {location} cannot be used together with the attribute {attribute:?}"
)]
InvalidLocationAttributeCombination {
location: u32,
attribute: &'static str,
}, #[error("Workgroup size is multi dimensional, @builtin(subgroup_id) and @builtin(subgroup_invocation_id) are not supported.")]
InvalidMultiDimensionalSubgroupBuiltIn,
}
#[derive(Clone, Debug, thiserror::Error)] #[cfg_attr(test, derive(PartialEq))] pubenum EntryPointError { #[error("Multiple conflicting entry points")]
Conflict, #[error("Vertex shaders must return a `@builtin(position)` output value")]
MissingVertexOutputPosition, #[error("Early depth test is not applicable")]
UnexpectedEarlyDepthTest, #[error("Workgroup size is not applicable")]
UnexpectedWorkgroupSize, #[error("Workgroup size is out of range")]
OutOfRangeWorkgroupSize, #[error("Uses operations forbidden at this stage")]
ForbiddenStageOperations, #[error("Global variable {0:?} is used incorrectly as {1:?}")]
InvalidGlobalUsage(Handle<crate::GlobalVariable>, GlobalUse), #[error("More than 1 push constant variable is used")]
MoreThanOnePushConstantUsed, #[error("Bindings for {0:?} conflict with other resource")]
BindingCollision(Handle<crate::GlobalVariable>), #[error("Argument {0} varying error")]
Argument(u32, #[source] VaryingError), #[error(transparent)]
Result(#[from] VaryingError), #[error("Location {location} interpolation of an integer has to be flat")]
InvalidIntegerInterpolation { location: u32 }, #[error(transparent)]
Function(#[from] FunctionError), #[error( "Invalid locations {location_mask:?} are set while dual source blending. Only location 0 may be set."
)]
InvalidLocationsWhileDualSourceBlending { location_mask: BitSet },
}
impl VaryingContext<'_> { fn validate_impl(
&mutself,
ep: &crate::EntryPoint,
ty: Handle<crate::Type>,
binding: &crate::Binding,
) -> Result<(), VaryingError> { usecrate::{BuiltIn as Bi, ShaderStage as St, TypeInner as Ti, VectorSize as Vs};
let ty_inner = &self.types[ty].inner; match *binding { crate::Binding::BuiltIn(built_in) => { // Ignore the `invariant` field for the sake of duplicate checks, // but use the original in error messages. let canonical = ifletcrate::BuiltIn::Position { .. } = built_in { crate::BuiltIn::Position { invariant: false }
} else {
built_in
};
// It doesn't make sense to specify a sampling when `interpolation` is `Flat`, but // SPIR-V and GLSL both explicitly tolerate such combinations of decorators / // qualifiers, so we won't complain about that here. let _ = sampling;
let required = match sampling {
Some(crate::Sampling::Sample) => Capabilities::MULTISAMPLED_SHADING,
_ => Capabilities::empty(),
}; if !self.capabilities.contains(required) { return Err(VaryingError::UnsupportedCapability(required));
}
log::debug!("var {:?}", var); let inner_ty = match gctx.types[var.ty].inner { // A binding array is (mostly) supposed to behave the same as a // series of individually bound resources, so we can (mostly) // validate a `binding_array<T>` as if it were just a plain `T`. crate::TypeInner::BindingArray { base, .. } => match var.space { crate::AddressSpace::Storage { .. }
| crate::AddressSpace::Uniform
| crate::AddressSpace::Handle => base,
_ => return Err(GlobalVariableError::InvalidUsage(var.space)),
},
_ => var.ty,
}; let type_info = &self.types[inner_ty.index()];
{ letmut used_push_constants = module
.global_variables
.iter()
.filter(|&(_, var)| var.space == crate::AddressSpace::PushConstant)
.map(|(handle, _)| handle)
.filter(|&handle| !info[handle].is_empty()); // Check if there is more than one push constant, and error if so. // Use a loop for when returning multiple errors is supported. iflet Some(handle) = used_push_constants.nth(1) { return Err(EntryPointError::MoreThanOnePushConstantUsed
.with_span_handle(handle, &module.global_variables));
}
}
self.ep_resource_bindings.clear(); for (var_handle, var) in module.global_variables.iter() { let usage = info[var_handle]; if usage.is_empty() { continue;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.