Skip to content
This repository has been archived by the owner on Jan 29, 2025. It is now read-only.

[spirv-out] Fix adding illegal decorators on fragment outputs. #2286

Merged
merged 4 commits into from
Mar 20, 2023
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
44 changes: 24 additions & 20 deletions src/back/spv/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1407,12 +1407,17 @@ impl Writer {
} => {
self.decorate(id, Decoration::Location, &[location]);

// The Vulkan spec says: VUID-StandaloneSpirv-Flat-06202
//
// > The Flat, NoPerspective, Sample, and Centroid decorations
// > must not be used on variables with the Input storage class in
// > a vertex shader
if class != spirv::StorageClass::Input || stage != crate::ShaderStage::Vertex {
let no_decorations =
// VUID-StandaloneSpirv-Flat-06202
// > The Flat, NoPerspective, Sample, and Centroid decorations
// > must not be used on variables with the Input storage class in a vertex shader
(class == spirv::StorageClass::Input && stage == crate::ShaderStage::Vertex) ||
// VUID-StandaloneSpirv-Flat-06201
// > The Flat, NoPerspective, Sample, and Centroid decorations
// > must not be used on variables with the Output storage class in a fragment shader
(class == spirv::StorageClass::Output && stage == crate::ShaderStage::Fragment);

if !no_decorations {
match interpolation {
// Perspective-correct interpolation is the default in SPIR-V.
None | Some(crate::Interpolation::Perspective) => (),
Expand All @@ -1423,20 +1428,19 @@ impl Writer {
self.decorate(id, Decoration::NoPerspective, &[]);
}
}
}

match sampling {
// Center sampling is the default in SPIR-V.
None | Some(crate::Sampling::Center) => (),
Some(crate::Sampling::Centroid) => {
self.decorate(id, Decoration::Centroid, &[]);
}
Some(crate::Sampling::Sample) => {
self.require_any(
"per-sample interpolation",
&[spirv::Capability::SampleRateShading],
)?;
self.decorate(id, Decoration::Sample, &[]);
match sampling {
// Center sampling is the default in SPIR-V.
None | Some(crate::Sampling::Center) => (),
Some(crate::Sampling::Centroid) => {
self.decorate(id, Decoration::Centroid, &[]);
}
Some(crate::Sampling::Sample) => {
self.require_any(
"per-sample interpolation",
&[spirv::Capability::SampleRateShading],
)?;
self.decorate(id, Decoration::Sample, &[]);
}
}
}
}
Expand Down
41 changes: 41 additions & 0 deletions tests/in/fragment-output.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Split up because some output languages limit number of locations to 8.
struct FragmentOutputVec4Vec3 {
@location(0) vec4f: vec4<f32>,
@location(1) vec4i: vec4<i32>,
@location(2) vec4u: vec4<u32>,
@location(3) vec3f: vec3<f32>,
@location(4) vec3i: vec3<i32>,
@location(5) vec3u: vec3<u32>,
}
@fragment
fn main_vec4vec3() -> FragmentOutputVec4Vec3 {
var output: FragmentOutputVec4Vec3;
output.vec4f = vec4<f32>(0.0);
output.vec4i = vec4<i32>(0);
output.vec4u = vec4<u32>(0u);
output.vec3f = vec3<f32>(0.0);
output.vec3i = vec3<i32>(0);
output.vec3u = vec3<u32>(0u);
return output;
}

struct FragmentOutputVec2Scalar {
@location(0) vec2f: vec2<f32>,
@location(1) vec2i: vec2<i32>,
@location(2) vec2u: vec2<u32>,
@location(3) scalarf: f32,
@location(4) scalari: i32,
@location(5) scalaru: u32,
}

@fragment
fn main_vec2scalar() -> FragmentOutputVec2Scalar {
var output: FragmentOutputVec2Scalar;
output.vec2f = vec2<f32>(0.0);
output.vec2i = vec2<i32>(0);
output.vec2u = vec2<u32>(0u);
output.scalarf = 0.0;
output.scalari = 0;
output.scalaru = 0u;
return output;
}
62 changes: 62 additions & 0 deletions tests/out/glsl/fragment-output.main.Fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#version 310 es

precision highp float;
precision highp int;

struct FragmentOutput {
vec4 vec4f;
ivec4 vec4i;
uvec4 vec4u;
vec3 vec3f;
ivec3 vec3i;
uvec3 vec3u;
vec2 vec2f;
ivec2 vec2i;
uvec2 vec2u;
float scalarf;
int scalari;
uint scalaru;
};
layout(location = 0) out vec4 _fs2p_location0;
layout(location = 1) out ivec4 _fs2p_location1;
layout(location = 2) out uvec4 _fs2p_location2;
layout(location = 3) out vec3 _fs2p_location3;
layout(location = 4) out ivec3 _fs2p_location4;
layout(location = 5) out uvec3 _fs2p_location5;
layout(location = 6) out vec2 _fs2p_location6;
layout(location = 7) out ivec2 _fs2p_location7;
layout(location = 8) out uvec2 _fs2p_location8;
layout(location = 9) out float _fs2p_location9;
layout(location = 10) out int _fs2p_location10;
layout(location = 11) out uint _fs2p_location11;

void main() {
FragmentOutput output_ = FragmentOutput(vec4(0.0), ivec4(0), uvec4(0u), vec3(0.0), ivec3(0), uvec3(0u), vec2(0.0), ivec2(0), uvec2(0u), 0.0, 0, 0u);
output_.vec4f = vec4(0.0);
output_.vec4i = ivec4(0);
output_.vec4u = uvec4(0u);
output_.vec3f = vec3(0.0);
output_.vec3i = ivec3(0);
output_.vec3u = uvec3(0u);
output_.vec2f = vec2(0.0);
output_.vec2i = ivec2(0);
output_.vec2u = uvec2(0u);
output_.scalarf = 0.0;
output_.scalari = 0;
output_.scalaru = 0u;
FragmentOutput _e34 = output_;
_fs2p_location0 = _e34.vec4f;
_fs2p_location1 = _e34.vec4i;
_fs2p_location2 = _e34.vec4u;
_fs2p_location3 = _e34.vec3f;
_fs2p_location4 = _e34.vec3i;
_fs2p_location5 = _e34.vec3u;
_fs2p_location6 = _e34.vec2f;
_fs2p_location7 = _e34.vec2i;
_fs2p_location8 = _e34.vec2u;
_fs2p_location9 = _e34.scalarf;
_fs2p_location10 = _e34.scalari;
_fs2p_location11 = _e34.scalaru;
return;
}

46 changes: 46 additions & 0 deletions tests/out/glsl/fragment-output.main_vec2scalar.Fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#version 310 es

precision highp float;
precision highp int;

struct FragmentOutputVec4Vec3_ {
vec4 vec4f;
ivec4 vec4i;
uvec4 vec4u;
vec3 vec3f;
ivec3 vec3i;
uvec3 vec3u;
};
struct FragmentOutputVec2Scalar {
vec2 vec2f;
ivec2 vec2i;
uvec2 vec2u;
float scalarf;
int scalari;
uint scalaru;
};
layout(location = 0) out vec2 _fs2p_location0;
layout(location = 1) out ivec2 _fs2p_location1;
layout(location = 2) out uvec2 _fs2p_location2;
layout(location = 3) out float _fs2p_location3;
layout(location = 4) out int _fs2p_location4;
layout(location = 5) out uint _fs2p_location5;

void main() {
FragmentOutputVec2Scalar output_1 = FragmentOutputVec2Scalar(vec2(0.0), ivec2(0), uvec2(0u), 0.0, 0, 0u);
output_1.vec2f = vec2(0.0);
output_1.vec2i = ivec2(0);
output_1.vec2u = uvec2(0u);
output_1.scalarf = 0.0;
output_1.scalari = 0;
output_1.scalaru = 0u;
FragmentOutputVec2Scalar _e16 = output_1;
_fs2p_location0 = _e16.vec2f;
_fs2p_location1 = _e16.vec2i;
_fs2p_location2 = _e16.vec2u;
_fs2p_location3 = _e16.scalarf;
_fs2p_location4 = _e16.scalari;
_fs2p_location5 = _e16.scalaru;
return;
}

46 changes: 46 additions & 0 deletions tests/out/glsl/fragment-output.main_vec4vec3.Fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#version 310 es

precision highp float;
precision highp int;

struct FragmentOutputVec4Vec3_ {
vec4 vec4f;
ivec4 vec4i;
uvec4 vec4u;
vec3 vec3f;
ivec3 vec3i;
uvec3 vec3u;
};
struct FragmentOutputVec2Scalar {
vec2 vec2f;
ivec2 vec2i;
uvec2 vec2u;
float scalarf;
int scalari;
uint scalaru;
};
layout(location = 0) out vec4 _fs2p_location0;
layout(location = 1) out ivec4 _fs2p_location1;
layout(location = 2) out uvec4 _fs2p_location2;
layout(location = 3) out vec3 _fs2p_location3;
layout(location = 4) out ivec3 _fs2p_location4;
layout(location = 5) out uvec3 _fs2p_location5;

void main() {
FragmentOutputVec4Vec3_ output_ = FragmentOutputVec4Vec3_(vec4(0.0), ivec4(0), uvec4(0u), vec3(0.0), ivec3(0), uvec3(0u));
output_.vec4f = vec4(0.0);
output_.vec4i = ivec4(0);
output_.vec4u = uvec4(0u);
output_.vec3f = vec3(0.0);
output_.vec3i = ivec3(0);
output_.vec3u = uvec3(0u);
FragmentOutputVec4Vec3_ _e19 = output_;
_fs2p_location0 = _e19.vec4f;
_fs2p_location1 = _e19.vec4i;
_fs2p_location2 = _e19.vec4u;
_fs2p_location3 = _e19.vec3f;
_fs2p_location4 = _e19.vec3i;
_fs2p_location5 = _e19.vec3u;
return;
}

48 changes: 48 additions & 0 deletions tests/out/hlsl/fragment-output.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

struct FragmentOutputVec4Vec3_ {
float4 vec4f : SV_Target0;
nointerpolation int4 vec4i : SV_Target1;
nointerpolation uint4 vec4u : SV_Target2;
float3 vec3f : SV_Target3;
nointerpolation int3 vec3i : SV_Target4;
nointerpolation uint3 vec3u : SV_Target5;
};

struct FragmentOutputVec2Scalar {
float2 vec2f : SV_Target0;
nointerpolation int2 vec2i : SV_Target1;
nointerpolation uint2 vec2u : SV_Target2;
float scalarf : SV_Target3;
nointerpolation int scalari : SV_Target4;
nointerpolation uint scalaru : SV_Target5;
};

FragmentOutputVec4Vec3_ main_vec4vec3_()
{
FragmentOutputVec4Vec3_ output = (FragmentOutputVec4Vec3_)0;

output.vec4f = (0.0).xxxx;
output.vec4i = (0).xxxx;
output.vec4u = (0u).xxxx;
output.vec3f = (0.0).xxx;
output.vec3i = (0).xxx;
output.vec3u = (0u).xxx;
FragmentOutputVec4Vec3_ _expr19 = output;
const FragmentOutputVec4Vec3_ fragmentoutputvec4vec3_ = _expr19;
return fragmentoutputvec4vec3_;
}

FragmentOutputVec2Scalar main_vec2scalar()
{
FragmentOutputVec2Scalar output_1 = (FragmentOutputVec2Scalar)0;

output_1.vec2f = (0.0).xx;
output_1.vec2i = (0).xx;
output_1.vec2u = (0u).xx;
output_1.scalarf = 0.0;
output_1.scalari = 0;
output_1.scalaru = 0u;
FragmentOutputVec2Scalar _expr16 = output_1;
const FragmentOutputVec2Scalar fragmentoutputvec2scalar = _expr16;
return fragmentoutputvec2scalar;
}
3 changes: 3 additions & 0 deletions tests/out/hlsl/fragment-output.hlsl.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
vertex=()
fragment=(main_vec4vec3_:ps_5_1 main_vec2scalar:ps_5_1 )
compute=()
67 changes: 67 additions & 0 deletions tests/out/msl/fragment-output.msl
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// language: metal2.0
#include <metal_stdlib>
#include <simd/simd.h>

using metal::uint;

struct FragmentOutputVec4Vec3_ {
metal::float4 vec4f;
metal::int4 vec4i;
metal::uint4 vec4u;
metal::float3 vec3f;
metal::int3 vec3i;
metal::uint3 vec3u;
};
struct FragmentOutputVec2Scalar {
metal::float2 vec2f;
metal::int2 vec2i;
metal::uint2 vec2u;
float scalarf;
int scalari;
uint scalaru;
};

struct main_vec4vec3_Output {
metal::float4 vec4f [[color(0)]];
metal::int4 vec4i [[color(1)]];
metal::uint4 vec4u [[color(2)]];
metal::float3 vec3f [[color(3)]];
metal::int3 vec3i [[color(4)]];
metal::uint3 vec3u [[color(5)]];
};
fragment main_vec4vec3_Output main_vec4vec3_(
) {
FragmentOutputVec4Vec3_ output = {};
output.vec4f = metal::float4(0.0);
output.vec4i = metal::int4(0);
output.vec4u = metal::uint4(0u);
output.vec3f = metal::float3(0.0);
output.vec3i = metal::int3(0);
output.vec3u = metal::uint3(0u);
FragmentOutputVec4Vec3_ _e19 = output;
const auto _tmp = _e19;
return main_vec4vec3_Output { _tmp.vec4f, _tmp.vec4i, _tmp.vec4u, _tmp.vec3f, _tmp.vec3i, _tmp.vec3u };
}


struct main_vec2scalarOutput {
metal::float2 vec2f [[color(0)]];
metal::int2 vec2i [[color(1)]];
metal::uint2 vec2u [[color(2)]];
float scalarf [[color(3)]];
int scalari [[color(4)]];
uint scalaru [[color(5)]];
};
fragment main_vec2scalarOutput main_vec2scalar(
) {
FragmentOutputVec2Scalar output_1 = {};
output_1.vec2f = metal::float2(0.0);
output_1.vec2i = metal::int2(0);
output_1.vec2u = metal::uint2(0u);
output_1.scalarf = 0.0;
output_1.scalari = 0;
output_1.scalaru = 0u;
FragmentOutputVec2Scalar _e16 = output_1;
const auto _tmp = _e16;
return main_vec2scalarOutput { _tmp.vec2f, _tmp.vec2i, _tmp.vec2u, _tmp.scalarf, _tmp.scalari, _tmp.scalaru };
}
Loading