Skip to content
Draft
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
3 changes: 3 additions & 0 deletions naga/src/back/glsl/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,9 @@ impl<W> Writer<'_, W> {
if interpolation == Some(Interpolation::Linear) {
self.features.request(Features::NOPERSPECTIVE_QUALIFIER);
}
if interpolation == Some(Interpolation::PerVertex) {
self.features.request(Features::SHADER_BARYCENTRICS);
}
if sampling == Some(Sampling::Sample) {
self.features.request(Features::SAMPLE_QUALIFIER);
}
Expand Down
1 change: 1 addition & 0 deletions naga/src/back/glsl/mod.rs
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to be worrying about GLSL output, especially if this is only for Vulkan accepted GLSL

Original file line number Diff line number Diff line change
Expand Up @@ -5299,6 +5299,7 @@ const fn glsl_interpolation(interpolation: crate::Interpolation) -> &'static str
I::Perspective => "smooth",
I::Linear => "noperspective",
I::Flat => "flat",
I::PerVertex => "pervertexEXT",
}
}

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 => Some("nointerpolation"),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions naga/src/back/msl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,7 @@ impl ResolvedInterpolation {
(I::Linear, S::Centroid) => Self::CentroidNoPerspective,
(I::Linear, S::Sample) => Self::SampleNoPerspective,
(I::Flat, _) => Self::Flat,
(I::PerVertex, _) => Self::Flat,
_ => 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 @@ -2081,6 +2081,14 @@ impl Writer {
Some(crate::Interpolation::Linear) => {
self.decorate(id, Decoration::NoPerspective, &[]);
}
Some(crate::Interpolation::PerVertex) => {
self.decorate(id, 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 @@ -209,6 +209,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
1 change: 1 addition & 0 deletions naga/src/front/glsl/lex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ impl Iterator for Lexer<'_> {
"invariant" => TokenValue::Invariant,
"flat" => TokenValue::Interpolation(crate::Interpolation::Flat),
"noperspective" => TokenValue::Interpolation(crate::Interpolation::Linear),
"pervertexEXT" => TokenValue::Interpolation(crate::Interpolation::PerVertex),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that we need to be parsing this for GLSL. If its super simple then why not, but otherwise I'll probably ignore or remove it.

"smooth" => TokenValue::Interpolation(crate::Interpolation::Perspective),
"centroid" => TokenValue::Sampling(crate::Sampling::Centroid),
"sample" => TokenValue::Sampling(crate::Sampling::Sample),
Expand Down
3 changes: 3 additions & 0 deletions naga/src/front/spv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -777,6 +777,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 @@ -565,6 +565,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 @@ -98,6 +98,10 @@ pub enum VaryingError {
InvalidPerPrimitive,
#[error("Non-builtin members of a mesh primitive output struct must be decorated with `@per_primitive`")]
MissingPerPrimitive,
#[error("The `PER_VERTEX` capability must be enabled to use per-vertex fragment inputs.")]
PerVertexNotAllowed,
Comment on lines +101 to +102
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably just be a MissingCapability error

#[error("Per vertex fragment inputs must be an array of length 3.")]
PerVertexNotArrayOfThree,
}

#[derive(Clone, Debug, thiserror::Error)]
Expand Down Expand Up @@ -441,8 +445,16 @@ 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::PerVertexNotAllowed);
}
}
// 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()]
.flags
.contains(super::TypeFlags::IO_SHAREABLE)
{
Expand Down Expand Up @@ -548,19 +560,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));
}
}
_ => 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
4 changes: 3 additions & 1 deletion naga/src/valid/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ bitflags::bitflags! {
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Capabilities: u32 {
pub struct Capabilities: u64 {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been waiting for the day!

/// Support for [`AddressSpace::PushConstant`][1].
///
/// [1]: crate::AddressSpace::PushConstant
Expand Down Expand Up @@ -192,6 +192,8 @@ bitflags::bitflags! {
const MESH_SHADER = 1 << 30;
/// Support for mesh shaders which output points.
const MESH_SHADER_POINT_TOPOLOGY = 1 << 31;
/// Support for per-vertex fragment input.
const SHADER_PER_VERTEX = 1 << 32;
}
}

Expand Down
10 changes: 10 additions & 0 deletions naga/tests/in/wgsl/per-vertex.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
god_mode = true

[msl]
lang_version = [4, 0]

[hlsl]
shader_model = "V6_1"

[glsl]
version.Desktop = 450
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
11 changes: 11 additions & 0 deletions naga/tests/out/glsl/wgsl-per-vertex.fs_main.Fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#version 450 core
#extension GL_EXT_fragment_shader_barycentric : require
layout(location = 0) pervertexEXT in float _vs2fs_location0;
layout(location = 0) out vec4 _fs2p_location0;

void main() {
float v = _vs2fs_location0;
_fs2p_location0 = vec4(v[0], v[1], v[2], 1.0);
return;
}

9 changes: 9 additions & 0 deletions naga/tests/out/hlsl/wgsl-per-vertex.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
struct FragmentInput_fs_main {
nointerpolation float v_1 : LOC0;
};

float4 fs_main(FragmentInput_fs_main fragmentinput_fs_main) : SV_Target0
{
float v[3] = fragmentinput_fs_main.v_1;
return float4(v[0], v[1], v[2], 1.0);
}
12 changes: 12 additions & 0 deletions naga/tests/out/hlsl/wgsl-per-vertex.ron
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
(
vertex:[
],
fragment:[
(
entry_point:"fs_main",
target_profile:"ps_6_1",
),
],
compute:[
],
)
22 changes: 22 additions & 0 deletions naga/tests/out/msl/wgsl-per-vertex.msl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// language: metal4.0
#include <metal_stdlib>
#include <simd/simd.h>

using metal::uint;

struct type_1 {
float inner[3];
};

struct fs_mainInput {
type_1 v [[user(loc0), flat]];
};
struct fs_mainOutput {
metal::float4 member [[color(0)]];
};
fragment fs_mainOutput fs_main(
fs_mainInput varyings [[stage_in]]
) {
const auto v = varyings.v;
return fs_mainOutput { metal::float4(v.inner[0], v.inner[1], v.inner[2], 1.0) };
}
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 @@ -40,6 +40,7 @@ mod multiview;
mod occlusion_query;
mod oob_indexing;
mod oom;
mod per_vertex;
mod pipeline;
mod pipeline_cache;
mod planar_texture;
Expand Down Expand Up @@ -104,6 +105,7 @@ fn all_tests() -> Vec<wgpu_test::GpuTestInitializer> {
occlusion_query::all_tests(&mut tests);
oob_indexing::all_tests(&mut tests);
oom::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