Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 on the input and SPIR-V, and WGSL on the output are supported. By @atlv in [#8821](https://github.com/gfx-rs/wgpu/issues/8821).
Comment thread
atlv24 marked this conversation as resolved.
Outdated

### Bug Fixes

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 @@ -159,6 +159,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 @@ -210,6 +210,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
3 changes: 3 additions & 0 deletions naga/src/front/spv/mod.rs
Comment thread
atlv24 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,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 @@ -111,6 +111,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
45 changes: 35 additions & 10 deletions naga/src/valid/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,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 @@ -443,8 +445,18 @@ impl VaryingContext<'_> {
Capabilities::MESH_SHADER,
));
}
if interpolation == Some(crate::Interpolation::PerVertex) {
if !self.capabilities.contains(Capabilities::SHADER_PER_VERTEX)
|| self.stage != crate::ShaderStage::Fragment
{
return Err(VaryingError::UnsupportedCapability(
Capabilities::SHADER_PER_VERTEX,
));
Comment thread
atlv24 marked this conversation as resolved.
}
}
// Only IO-shareable types may be stored in locations.
if !self.type_info[ty.index()]
// Per Vertex case is checked later.
else if !self.type_info[ty.index()]
Comment thread
atlv24 marked this conversation as resolved.
Outdated
.flags
.contains(super::TypeFlags::IO_SHAREABLE)
{
Expand Down Expand Up @@ -550,19 +562,32 @@ 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) {
let three = crate::ArraySize::Constant(core::num::NonZeroU32::new(3).unwrap());
match ty_inner {
&Ti::Array { base, size, .. } if size == three => {
if self.types[base].inner.scalar_kind().is_none() {
return Err(VaryingError::InvalidType(base));
}
Comment thread
atlv24 marked this conversation as resolved.
Outdated
}
_ => return Err(VaryingError::PerVertexNotArrayOfThree),
}
Some(_) => {
if needs_interpolation && interpolation != Some(crate::Interpolation::Flat)
{
return Err(VaryingError::InvalidInterpolation);
} else {
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);
}
}
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 @@ -202,6 +202,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 SHADER_PER_VERTEX = 1 << 37;
Comment thread
atlv24 marked this conversation as resolved.
Outdated
}
}

Expand Down
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 = "SHADER_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
Comment thread
atlv24 marked this conversation as resolved.
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
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
4 changes: 4 additions & 0 deletions naga/tests/out/wgsl/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<f32>(v[0], v[1], v[2], 1f);
}
2 changes: 2 additions & 0 deletions tests/tests/wgpu-gpu/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ mod occlusion_query;
mod oob_indexing;
mod oom;
mod pass_ops;
mod per_vertex;
mod pipeline;
mod pipeline_cache;
mod planar_texture;
Expand Down Expand Up @@ -106,6 +107,7 @@ fn all_tests() -> Vec<wgpu_test::GpuTestInitializer> {
oob_indexing::all_tests(&mut tests);
oom::all_tests(&mut tests);
pass_ops::all_tests(&mut tests);
per_vertex::all_tests(&mut tests);
pipeline_cache::all_tests(&mut tests);
pipeline::all_tests(&mut tests);
planar_texture::all_tests(&mut tests);
Expand Down
Loading
Loading