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 @@ -44,6 +44,7 @@ Bottom level categories:
### New Features

- Added support for cooperative load/store operations in shaders. Currently only WGSL on the input and SPIR-V, METAL, and WGSL on the output are supported. By @kvark in [#8251](https://github.com/gfx-rs/wgpu/issues/8251).
- Added support for per-vertex attributes in fragment shaders. Currently only WGSL input is supported, and only SPIR-V or WGSL output is supported. By @atlv24 in [#8821](https://github.com/gfx-rs/wgpu/issues/8821).
- Added support for no-perspective barycentric coordinates. By @atlv24 in [#8852](https://github.com/gfx-rs/wgpu/issues/8852).
- Added support for obtaining `AdapterInfo` from `Device`. By @sagudev in [#8807](https://github.com/gfx-rs/wgpu/pull/8807).
- Added `Limits::or_worse_values_from`. By @atlv24 in [#8870](https://github.com/gfx-rs/wgpu/pull/8870).
Expand Down
1 change: 1 addition & 0 deletions naga/src/back/glsl/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ pub(in crate::back::glsl) const fn glsl_interpolation(
I::Perspective => "smooth",
I::Linear => "noperspective",
I::Flat => "flat",
I::PerVertex => unreachable!(),
}
}

Expand Down
1 change: 1 addition & 0 deletions naga/src/back/hlsl/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ impl crate::Interpolation {
Self::Perspective => None,
Self::Linear => Some("noperspective"),
Self::Flat => Some("nointerpolation"),
Self::PerVertex => unreachable!(),
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions naga/src/back/spv/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2987,6 +2987,14 @@ impl Writer {
Some(crate::Interpolation::Linear) => {
others.push(Decoration::NoPerspective);
}
Some(crate::Interpolation::PerVertex) => {
others.push(Decoration::PerVertexKHR);
self.require_any(
"`per_vertex` interpolation",
&[spirv::Capability::FragmentBarycentricKHR],
)?;
self.use_extension("SPV_KHR_fragment_shader_barycentric");
}
}
match sampling {
// Center sampling is the default in SPIR-V.
Expand Down
1 change: 1 addition & 0 deletions naga/src/common/wgsl/to_wgsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ impl ToWgsl for crate::Interpolation {
crate::Interpolation::Perspective => "perspective",
crate::Interpolation::Linear => "linear",
crate::Interpolation::Flat => "flat",
crate::Interpolation::PerVertex => "per_vertex",
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions naga/src/front/spv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub const SUPPORTED_EXTENSIONS: &[&str] = &[
"SPV_EXT_descriptor_indexing",
"SPV_EXT_shader_atomic_float_add",
"SPV_KHR_16bit_storage",
"SPV_KHR_fragment_shader_barycentric",
];
pub const SUPPORTED_EXT_SETS: &[&str] = &["GLSL.std.450"];

Expand Down Expand Up @@ -778,6 +779,9 @@ impl<I: Iterator<Item = u32>> Frontend<I> {
spirv::Decoration::Flat => {
dec.interpolation = Some(crate::Interpolation::Flat);
}
spirv::Decoration::PerVertexKHR => {
dec.interpolation = Some(crate::Interpolation::PerVertex);
}
spirv::Decoration::Centroid => {
dec.sampling = Some(crate::Sampling::Centroid);
}
Expand Down
1 change: 1 addition & 0 deletions naga/src/front/wgsl/parse/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ pub fn map_interpolation(word: &str, span: Span) -> Result<'_, crate::Interpolat
"linear" => Ok(crate::Interpolation::Linear),
"flat" => Ok(crate::Interpolation::Flat),
"perspective" => Ok(crate::Interpolation::Perspective),
"per_vertex" => Ok(crate::Interpolation::PerVertex),
_ => Err(Box::new(Error::UnknownAttribute(span))),
}
}
Expand Down
3 changes: 3 additions & 0 deletions naga/src/ir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,9 @@ pub enum Interpolation {
Linear,
/// Indicates that no interpolation will be performed.
Flat,
/// Indicates the fragment input binding holds an array of per-vertex values.
/// This is typically used with barycentrics.
PerVertex,
}

/// The sampling qualifiers of a binding or struct field.
Expand Down
54 changes: 44 additions & 10 deletions naga/src/valid/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ pub enum VaryingError {
NotIOShareableType(Handle<crate::Type>),
#[error("Interpolation is not valid")]
InvalidInterpolation,
#[error("Interpolation {0:?} is only valid for stage {1:?}")]
InvalidInterpolationInStage(crate::Interpolation, crate::ShaderStage),
#[error("Cannot combine {interpolation:?} interpolation with the {sampling:?} sample type")]
InvalidInterpolationSamplingCombination {
interpolation: crate::Interpolation,
Expand Down Expand Up @@ -100,6 +102,8 @@ pub enum VaryingError {
InvalidPerPrimitive,
#[error("Non-builtin members of a mesh primitive output struct must be decorated with `@per_primitive`")]
MissingPerPrimitive,
#[error("Per vertex fragment inputs must be an array of length 3.")]
PerVertexNotArrayOfThree,
}

#[derive(Clone, Debug, thiserror::Error)]
Expand Down Expand Up @@ -447,6 +451,33 @@ impl VaryingContext<'_> {
Capabilities::MESH_SHADER,
));
}
if interpolation == Some(crate::Interpolation::PerVertex) {
if self.stage != crate::ShaderStage::Fragment {
return Err(VaryingError::InvalidInterpolationInStage(
crate::Interpolation::PerVertex,
crate::ShaderStage::Fragment,
));
}
if !self.capabilities.contains(Capabilities::PER_VERTEX) {
return Err(VaryingError::UnsupportedCapability(
Capabilities::PER_VERTEX,
));
}
}
// If this is per-vertex, we change the type we validate to the inner type, otherwise we leave it be.
// This lets all validation be done on the inner type once we've ensured the per-vertex is array<T, 3>
let (ty, ty_inner) = if interpolation == Some(crate::Interpolation::PerVertex) {
let three = crate::ArraySize::Constant(core::num::NonZeroU32::new(3).unwrap());
match ty_inner {
&Ti::Array { base, size, .. } if size == three => {
(base, &self.types[base].inner)
}
_ => return Err(VaryingError::PerVertexNotArrayOfThree),
}
} else {
(ty, ty_inner)
};

// Only IO-shareable types may be stored in locations.
if !self.type_info[ty.index()]
.flags
Expand Down Expand Up @@ -554,19 +585,22 @@ impl VaryingContext<'_> {
return Err(VaryingError::UnsupportedCapability(required));
}

match ty_inner.scalar_kind() {
Some(crate::ScalarKind::Float) => {
if needs_interpolation && interpolation.is_none() {
return Err(VaryingError::MissingInterpolation);
if interpolation != Some(crate::Interpolation::PerVertex) {
match ty_inner.scalar_kind() {
Some(crate::ScalarKind::Float) => {
if needs_interpolation && interpolation.is_none() {
return Err(VaryingError::MissingInterpolation);
}
}
}
Some(_) => {
if needs_interpolation && interpolation != Some(crate::Interpolation::Flat)
{
return Err(VaryingError::InvalidInterpolation);
Some(_) => {
if needs_interpolation
&& interpolation != Some(crate::Interpolation::Flat)
{
return Err(VaryingError::InvalidInterpolation);
}
}
None => return Err(VaryingError::InvalidType(ty)),
}
None => return Err(VaryingError::InvalidType(ty)),
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions naga/src/valid/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ bitflags::bitflags! {
const STORAGE_BUFFER_BINDING_ARRAY_NON_UNIFORM_INDEXING = 1 << 35;
/// Support for cooperative matrix types and operations
const COOPERATIVE_MATRIX = 1 << 36;
/// Support for per-vertex fragment input.
const PER_VERTEX = 1 << 37;
}
}

Expand Down
39 changes: 39 additions & 0 deletions naga/tests/in/spv/per-vertex.spvasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
; SPIR-V
; Version: 1.1
; Generator: rspirv
; Bound: 22
OpCapability Shader
OpCapability FragmentBarycentricKHR
OpExtension "SPV_KHR_fragment_shader_barycentric"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %14 "fs_main" %9 %12
OpExecutionMode %14 OriginUpperLeft
OpDecorate %4 ArrayStride 4
OpDecorate %9 Location 0
OpDecorate %9 PerVertexKHR
OpDecorate %12 Location 0
%2 = OpTypeVoid
%3 = OpTypeFloat 32
%6 = OpTypeInt 32 0
%5 = OpConstant %6 3
%4 = OpTypeArray %3 %5
%7 = OpTypeVector %3 4
%10 = OpTypePointer Input %4
%9 = OpVariable %10 Input
%13 = OpTypePointer Output %7
%12 = OpVariable %13 Output
%15 = OpTypeFunction %2
%16 = OpConstant %3 1
%14 = OpFunction %2 None %15
%8 = OpLabel
%11 = OpLoad %4 %9
OpBranch %17
%17 = OpLabel
%18 = OpCompositeExtract %3 %11 0
%19 = OpCompositeExtract %3 %11 1
%20 = OpCompositeExtract %3 %11 2
%21 = OpCompositeConstruct %7 %18 %19 %20 %16
OpStore %12 %21
OpReturn
OpFunctionEnd
2 changes: 2 additions & 0 deletions naga/tests/in/spv/per-vertex.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
capabilities = "PER_VERTEX"
targets = "SPIRV | WGSL"
2 changes: 2 additions & 0 deletions naga/tests/in/wgsl/per-vertex.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
capabilities = "PER_VERTEX"
targets = "WGSL | SPIRV"
4 changes: 4 additions & 0 deletions naga/tests/in/wgsl/per-vertex.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@fragment
fn fs_main(@location(0) @interpolate(per_vertex) v: array<f32, 3>) -> @location(0) vec4<f32> {
return vec4(v[0], v[1], v[2], 1.0);
}
3 changes: 3 additions & 0 deletions naga/tests/naga/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ fn incompatible_interpolation_and_sampling_types() {
naga::Interpolation::Flat,
naga::Interpolation::Linear,
naga::Interpolation::Perspective,
naga::Interpolation::PerVertex,
]
.into_iter()
.cartesian_product(
Expand Down Expand Up @@ -498,6 +499,7 @@ mod dummy_interpolation_shader {
naga::Interpolation::Flat => "flat",
naga::Interpolation::Linear => "linear",
naga::Interpolation::Perspective => "perspective",
naga::Interpolation::PerVertex => "per_vertex",
};
let sampling_str = match sampling {
None => String::new(),
Expand All @@ -515,6 +517,7 @@ mod dummy_interpolation_shader {
let member_type = match interpolation {
naga::Interpolation::Perspective | naga::Interpolation::Linear => "f32",
naga::Interpolation::Flat => "u32",
naga::Interpolation::PerVertex => "array<u32, 3>",
};

let interpolate_attr = format!("@interpolate({interpolation_str}{sampling_str})");
Expand Down
25 changes: 25 additions & 0 deletions naga/tests/naga/wgsl_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,31 @@ fn int64_capability() {
}
}

#[test]
fn per_vertex_capability() {
check_validation! {
r#"
@fragment
fn fs_main(@location(0) @interpolate(per_vertex) v: array<f32, 3>) -> @location(0) vec4<f32> {
return vec4(v[0], v[1], v[2], 1.0);
}
"#:
Err(
naga::valid::ValidationError::EntryPoint {
stage: naga::ShaderStage::Fragment,
source: valid::EntryPointError::Argument(
0,
valid::VaryingError::UnsupportedCapability(
Capabilities::PER_VERTEX,

),
),
..
},
)
}
}

#[test]
fn multiple_enables_valid() {
check_success(
Expand Down
56 changes: 56 additions & 0 deletions naga/tests/out/spv/spv-per-vertex.spvasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
; SPIR-V
; Version: 1.1
; Generator: rspirv
; Bound: 34
OpCapability Shader
OpCapability FragmentBarycentricKHR
OpExtension "SPV_KHR_fragment_shader_barycentric"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %30 "fs_main" %25 %28
OpExecutionMode %30 OriginUpperLeft
OpDecorate %4 ArrayStride 4
OpDecorate %25 Location 0
OpDecorate %25 PerVertexKHR
OpDecorate %28 Location 0
%2 = OpTypeVoid
%3 = OpTypeFloat 32
%6 = OpTypeInt 32 0
%5 = OpConstant %6 3
%4 = OpTypeArray %3 %5
%7 = OpTypeVector %3 4
%8 = OpConstant %3 1
%10 = OpTypePointer Private %4
%11 = OpConstantNull %4
%9 = OpVariable %10 Private %11
%13 = OpTypePointer Private %7
%14 = OpConstantNull %7
%12 = OpVariable %13 Private %14
%17 = OpTypeFunction %2
%26 = OpTypePointer Input %4
%25 = OpVariable %26 Input
%29 = OpTypePointer Output %7
%28 = OpVariable %29 Output
%16 = OpFunction %2 None %17
%15 = OpLabel
OpBranch %18
%18 = OpLabel
%19 = OpLoad %4 %9
%20 = OpCompositeExtract %3 %19 0
%21 = OpCompositeExtract %3 %19 1
%22 = OpCompositeExtract %3 %19 2
%23 = OpCompositeConstruct %7 %20 %21 %22 %8
OpStore %12 %23
OpReturn
OpFunctionEnd
%30 = OpFunction %2 None %17
%24 = OpLabel
%27 = OpLoad %4 %25
OpBranch %31
%31 = OpLabel
OpStore %9 %27
%32 = OpFunctionCall %2 %16
%33 = OpLoad %7 %12
OpStore %28 %33
OpReturn
OpFunctionEnd
39 changes: 39 additions & 0 deletions naga/tests/out/spv/wgsl-per-vertex.spvasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
; SPIR-V
; Version: 1.1
; Generator: rspirv
; Bound: 22
OpCapability Shader
OpCapability FragmentBarycentricKHR
OpExtension "SPV_KHR_fragment_shader_barycentric"
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %14 "fs_main" %9 %12
OpExecutionMode %14 OriginUpperLeft
OpDecorate %4 ArrayStride 4
OpDecorate %9 Location 0
OpDecorate %9 PerVertexKHR
OpDecorate %12 Location 0
%2 = OpTypeVoid
%3 = OpTypeFloat 32
%6 = OpTypeInt 32 0
%5 = OpConstant %6 3
%4 = OpTypeArray %3 %5
%7 = OpTypeVector %3 4
%10 = OpTypePointer Input %4
%9 = OpVariable %10 Input
%13 = OpTypePointer Output %7
%12 = OpVariable %13 Output
%15 = OpTypeFunction %2
%16 = OpConstant %3 1
%14 = OpFunction %2 None %15
%8 = OpLabel
%11 = OpLoad %4 %9
OpBranch %17
%17 = OpLabel
%18 = OpCompositeExtract %3 %11 0
%19 = OpCompositeExtract %3 %11 1
%20 = OpCompositeExtract %3 %11 2
%21 = OpCompositeConstruct %7 %18 %19 %20 %16
OpStore %12 %21
OpReturn
OpFunctionEnd
Loading