Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ By @cwfitzgerald in [#8999](https://github.com/gfx-rs/wgpu/pull/8999).
- Check that if the shader outputs `frag_depth`, then the pipeline must have a depth attachment. By @andyleiserson in [#8856](https://github.com/gfx-rs/wgpu/pull/8856).
- Fix incorrect acceptance of some swizzle selectors that are not valid for their operand, e.g. `const v = vec2<i32>(); let r = v.xyz`. By @andyleiserson in [#8949](https://github.com/gfx-rs/wgpu/pull/8949).
- Fixed calculation of the total number of bindings in a pipeline layout when validating against device limits. By @andyleiserson in [#8997](https://github.com/gfx-rs/wgpu/pull/8997).
- Reject non-constructible types (runtime- and override-sized arrays, and structs containing non-constructible types) in more places where they should not be allowed. By @andyleiserson in [#8873](https://github.com/gfx-rs/wgpu/pull/8873).

#### Vulkan
- Fixed a variety of mesh shader SPIR-V writer issues from the original implementation. By @inner-daemons in [#8756](https://github.com/gfx-rs/wgpu/pull/8756)
Expand Down
7 changes: 6 additions & 1 deletion cts_runner/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -378,13 +378,18 @@ webgpu:shader,validation,expression,call,builtin,textureNumSamples:*
fails-if(vulkan) webgpu:shader,validation,expression,call,builtin,textureSampleBaseClampToEdge:*
webgpu:shader,validation,expression,call,builtin,textureStore:*
webgpu:shader,validation,expression,call,builtin,trunc:*
// FAIL: others in `value_constructor` due to https://github.com/gfx-rs/wgpu/issues/4720, possibly more
webgpu:shader,validation,expression,call,builtin,value_constructor:array_value:*
webgpu:shader,validation,expression,call,builtin,value_constructor:array_zero_value:*
webgpu:shader,validation,expression,call,builtin,value_constructor:matrix_zero_value:*
webgpu:shader,validation,expression,call,builtin,value_constructor:must_use:ctor="mat4x4";use=true
webgpu:shader,validation,expression,call,builtin,value_constructor:partial_eval:*
webgpu:shader,validation,expression,call,builtin,value_constructor:scalar_value:*
webgpu:shader,validation,expression,call,builtin,value_constructor:scalar_zero_value:*
webgpu:shader,validation,expression,call,builtin,value_constructor:struct_value:*
webgpu:shader,validation,expression,call,builtin,value_constructor:struct_zero_value:*
webgpu:shader,validation,expression,call,builtin,value_constructor:vector_copy:*
webgpu:shader,validation,expression,call,builtin,value_constructor:vector_elementwise:*
webgpu:shader,validation,expression,call,builtin,value_constructor:vector_mixed:*
webgpu:shader,validation,expression,call,builtin,value_constructor:vector_splat:*
webgpu:shader,validation,expression,call,builtin,value_constructor:vector_zero_value:*
webgpu:shader,validation,expression,call,builtin,workgroupUniformLoad:*
Expand Down
65 changes: 35 additions & 30 deletions naga/src/front/wgsl/lower/construction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,33 +152,35 @@ impl<'source> Lowerer<'source, '_> {

let expr;
match (components, constructor) {
// Empty constructor
(Components::None, dst_ty) => match dst_ty {
Constructor::Type((result_ty, _)) => {
expr = crate::Expression::ZeroValue(result_ty);
}
Constructor::PartialVector { size } => {
// vec2(), vec3(), vec4() return vectors of abstractInts; the same
// is not true of the similar constructors for matrices or arrays.
// See https://www.w3.org/TR/WGSL/#vec2-builtin et seq.
let result_ty = ctx.module.types.insert(
crate::Type {
name: None,
inner: crate::TypeInner::Vector {
size,
scalar: crate::Scalar::ABSTRACT_INT,
},
// Zero-value constructor with explicit type.
(Components::None, Constructor::Type((result_ty, inner)))
if inner.is_constructible(&ctx.module.types) =>
{
expr = crate::Expression::ZeroValue(result_ty);
}
// Zero-value constructor, vector with type inference
(Components::None, Constructor::PartialVector { size }) => {
// vec2(), vec3(), vec4() return vectors of abstractInts; the same
// is not true of the similar constructors for matrices or arrays.
// See https://www.w3.org/TR/WGSL/#vec2-builtin et seq.
let result_ty = ctx.module.types.insert(
crate::Type {
name: None,
inner: crate::TypeInner::Vector {
size,
scalar: crate::Scalar::ABSTRACT_INT,
},
span,
);
expr = crate::Expression::ZeroValue(result_ty);
}
Constructor::PartialMatrix { .. } | Constructor::PartialArray => {
// We have no arguments from which to infer the result type, so
// partial constructors aren't acceptable here.
return Err(Box::new(Error::TypeNotInferable(ty_span)));
}
},
},
span,
);
expr = crate::Expression::ZeroValue(result_ty);
}
// Zero-value constructor, matrix or array with type inference
(Components::None, Constructor::PartialMatrix { .. } | Constructor::PartialArray) => {
// We have no arguments from which to infer the result type, so
// partial constructors aren't acceptable here.
return Err(Box::new(Error::TypeNotInferable(ty_span)));
}

// Scalar constructor & conversion (scalar -> scalar)
(
Expand Down Expand Up @@ -530,8 +532,11 @@ impl<'source> Lowerer<'source, '_> {
expr = crate::Expression::Compose { ty, components };
}

// Array constructor, explicit type
(components, Constructor::Type((ty, &crate::TypeInner::Array { base, .. }))) => {
// Array constructor, explicit type.
(
components,
Constructor::Type((ty, inner @ &crate::TypeInner::Array { base, .. })),
) if inner.is_constructible(&ctx.module.types) => {
let mut components = components.into_components_vec();
ctx.try_automatic_conversions_slice(&mut components, &Tr::Handle(base), ty_span)?;
expr = crate::Expression::Compose { ty, components };
Expand All @@ -540,8 +545,8 @@ impl<'source> Lowerer<'source, '_> {
// Struct constructor
(
components,
Constructor::Type((ty, &crate::TypeInner::Struct { ref members, .. })),
) => {
Constructor::Type((ty, inner @ &crate::TypeInner::Struct { ref members, .. })),
) if inner.is_constructible(&ctx.module.types) => {
let mut components = components.into_components_vec();
let struct_ty_span = ctx.module.types.get_span(ty);

Expand Down
16 changes: 15 additions & 1 deletion naga/src/front/wgsl/lower/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1811,14 +1811,28 @@ impl<'source, 'temp> Lowerer<'source, 'temp> {

let mut ectx = ctx.as_expression(block, &mut emitter);

let (_ty, initializer) = self.type_and_init(
let (ty, initializer) = self.type_and_init(
l.name,
Some(l.init),
explicit_ty,
AbstractRule::Concretize,
&mut ectx,
)?;

// We have this special check here for `let` declarations because the
// validator doesn't check them (they are comingled with other things in
// `named_expressions`; see <https://github.com/gfx-rs/wgpu/issues/7393>).
// The check could go in `type_and_init`, but then we'd have to
// distinguish whether override-sized is allowed. The error ought to use
// the type's span, but `module.types.get_span(ty)` is `Span::UNDEFINED`
// (see <https://github.com/gfx-rs/wgpu/issues/7951>).
if ctx.module.types[ty]
.inner
.is_dynamically_sized(&ctx.module.types)
{
return Err(Box::new(Error::TypeNotConstructible(l.name.span)));
}

// We passed `Some()` to `type_and_init`, so we
// will get a lowered initializer expression back.
let initializer =
Expand Down
39 changes: 38 additions & 1 deletion naga/src/proc/type_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,10 +344,18 @@ impl crate::TypeInner {
left.as_ref().unwrap_or(self) == right.as_ref().unwrap_or(rhs)
}

/// Returns true if `self` is runtime- or override-sized.
pub fn is_dynamically_sized(&self, types: &crate::UniqueArena<crate::Type>) -> bool {
use crate::TypeInner as Ti;
match *self {
Ti::Array { size, .. } => size == crate::ArraySize::Dynamic,
Ti::Array {
size: crate::ArraySize::Constant(_),
..
} => false,
Ti::Array {
size: crate::ArraySize::Pending(_) | crate::ArraySize::Dynamic,
..
} => true,
Ti::Struct { ref members, .. } => members
.last()
.map(|last| types[last.ty].inner.is_dynamically_sized(types))
Expand All @@ -356,6 +364,35 @@ impl crate::TypeInner {
}
}

/// Returns true if `self` is a constructible type.
pub fn is_constructible(&self, types: &crate::UniqueArena<crate::Type>) -> bool {
use crate::TypeInner as Ti;
match *self {
Ti::Array { base, size, .. } => {
let fixed_size = match size {
ir::ArraySize::Constant(_) => true,
ir::ArraySize::Pending(_) | ir::ArraySize::Dynamic => false,
};
fixed_size && types[base].inner.is_constructible(types)
}
Ti::Struct { ref members, .. } => members
.iter()
.all(|member| types[member.ty].inner.is_constructible(types)),
Ti::Atomic(_)
| Ti::Pointer { .. }
| Ti::ValuePointer { .. }
| Ti::Image { .. }
| Ti::Sampler { .. }
| Ti::AccelerationStructure { .. }
| Ti::BindingArray { .. } => false,
Ti::Scalar(_)
| Ti::Vector { .. }
| Ti::Matrix { .. }
| Ti::RayQuery { .. }
| Ti::CooperativeMatrix { .. } => true,
}
}

pub const fn components(&self) -> Option<u32> {
Some(match *self {
Self::Vector { size, .. } => size as u32,
Expand Down
11 changes: 5 additions & 6 deletions naga/src/valid/expression.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
use super::{compose::validate_compose, FunctionInfo, ModuleInfo, ShaderStages, TypeFlags};
use crate::arena::UniqueArena;
use crate::valid::expression::builtin::validate_zero_value;
use crate::{
arena::Handle,
proc::OverloadSet as _,
proc::{IndexableLengthError, ResolveError},
};

pub mod builtin;

#[derive(Clone, Debug, thiserror::Error)]
#[cfg_attr(test, derive(PartialEq))]
pub enum ExpressionError {
Expand Down Expand Up @@ -38,8 +35,8 @@ pub enum ExpressionError {
InvalidSwizzleComponent(crate::SwizzleComponent, crate::VectorSize),
#[error(transparent)]
Compose(#[from] super::ComposeError),
#[error(transparent)]
ZeroValue(#[from] super::ZeroValueError),
#[error("Cannot construct zero value of {0:?} because it is not a constructible type")]
InvalidZeroValue(Handle<crate::Type>),
#[error(transparent)]
IndexableLength(#[from] IndexableLengthError),
#[error("Operation {0:?} can't work with {1:?}")]
Expand Down Expand Up @@ -460,7 +457,9 @@ impl super::Validator {
}
E::Constant(_) | E::Override(_) => ShaderStages::all(),
E::ZeroValue(ty) => {
validate_zero_value(ty, module.to_ctx())?;
if !mod_info[ty].contains(TypeFlags::CONSTRUCTIBLE) {
return Err(ExpressionError::InvalidZeroValue(ty));
}
ShaderStages::all()
}
E::Compose { ref components, ty } => {
Expand Down
26 changes: 0 additions & 26 deletions naga/src/valid/expression/builtin.rs

This file was deleted.

5 changes: 4 additions & 1 deletion naga/src/valid/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ use crate::{
use crate::span::{AddSpan as _, WithSpan};
pub use analyzer::{ExpressionInfo, FunctionInfo, GlobalUse, Uniformity, UniformityRequirements};
pub use compose::ComposeError;
pub use expression::builtin::ZeroValueError;
pub use expression::{check_literal_value, LiteralError};
pub use expression::{ConstExpressionError, ExpressionError};
pub use function::{CallError, FunctionError, LocalVariableError, SubgroupError};
Expand Down Expand Up @@ -771,6 +770,10 @@ impl Validator {
}
.with_span_handle(handle, &module.types)
})?;
debug_assert!(
ty_info.flags.contains(TypeFlags::CONSTRUCTIBLE)
== module.types[handle].inner.is_constructible(&module.types)
);
mod_info.type_flags.push(ty_info.flags);
self.types[handle.index()] = ty_info;
}
Expand Down
Loading
Loading