From 1c02eb8cb08c85934166d7b4b71dc65e819529d9 Mon Sep 17 00:00:00 2001 From: James Price Date: Tue, 25 Jan 2022 01:01:39 +0000 Subject: [PATCH] validation: Require interpolate(flat) for integers This was made a warning in M97, and can now become a hard error. Fixed: tint:1224 Change-Id: Ied72f6e28b3dc64a6ab832e0eac53f62ce045d40 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/77700 Kokoro: Kokoro Reviewed-by: David Neto Commit-Queue: James Price --- docs/origin-trial-changes.md | 7 + src/inspector/inspector_test.cc | 22 ++- src/inspector/test_inspector_builder.cc | 3 +- src/program_builder.h | 17 +- src/reader/spirv/parser_impl.cc | 4 + .../spirv/parser_impl_module_var_test.cc | 167 +++++++++++++++++- src/resolver/decoration_validation_test.cc | 19 +- src/resolver/entry_point_validation_test.cc | 14 +- src/resolver/resolver_validation.cc | 8 +- .../canonicalize_entry_point_io_test.cc | 68 +++---- src/writer/spirv/builder_entry_point_test.cc | 5 +- test/bug/tint/1081.wgsl | 2 +- test/bug/tint/1081.wgsl.expected.hlsl | 6 +- test/bug/tint/1081.wgsl.expected.msl | 6 +- test/bug/tint/1081.wgsl.expected.spvasm | 4 - test/bug/tint/1081.wgsl.expected.wgsl | 6 +- .../comparison/frexpstruct_1_frag/0.wgsl | 2 +- .../decorate_string/0.wgsl | 2 +- .../no_image_atomic/0-opt.wgsl | 2 +- .../no_image_store/1.wgsl | 2 +- .../no_output_write/1.wgsl | 2 +- .../no_output_write_before_terminate/1.wgsl | 2 +- .../terminate_invocation/no_ssbo_store/1.wgsl | 2 +- .../ssbo_store_before_terminate/1.wgsl | 2 +- .../terminate_loop/1.wgsl | 2 +- 25 files changed, 273 insertions(+), 103 deletions(-) diff --git a/docs/origin-trial-changes.md b/docs/origin-trial-changes.md index 435934ecbf..92c7a22df2 100644 --- a/docs/origin-trial-changes.md +++ b/docs/origin-trial-changes.md @@ -1,5 +1,12 @@ # Tint changes during Origin Trial +## Changes for M100 + +### Breaking changes + +* The `@interpolate(flat)` attribute must now be specified on integral user-defined IO. [tint:1224](crbug.com/tint/1224) + + ## Changes for M99 ### Breaking changes diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc index 713887b00d..aeef3651cd 100644 --- a/src/inspector/inspector_test.cc +++ b/src/inspector/inspector_test.cc @@ -303,7 +303,7 @@ TEST_P(InspectorGetEntryPointComponentAndCompositionTest, Test) { std::function tint_type = GetTypeFunction(component, composition); - auto* in_var = Param("in_var", tint_type(), {Location(0u)}); + auto* in_var = Param("in_var", tint_type(), {Location(0u), Flat()}); Func("foo", {in_var}, tint_type(), {Return("in_var")}, {Stage(ast::PipelineStage::kFragment)}, {Location(0u)}); Inspector& inspector = Build(); @@ -337,9 +337,9 @@ INSTANTIATE_TEST_SUITE_P( CompositionType::kVec4))); TEST_F(InspectorGetEntryPointTest, MultipleInOutVariables) { - auto* in_var0 = Param("in_var0", ty.u32(), {Location(0u)}); - auto* in_var1 = Param("in_var1", ty.u32(), {Location(1u)}); - auto* in_var4 = Param("in_var4", ty.u32(), {Location(4u)}); + auto* in_var0 = Param("in_var0", ty.u32(), {Location(0u), Flat()}); + auto* in_var1 = Param("in_var1", ty.u32(), {Location(1u), Flat()}); + auto* in_var4 = Param("in_var4", ty.u32(), {Location(4u), Flat()}); Func("foo", {in_var0, in_var1, in_var4}, ty.u32(), {Return("in_var0")}, {Stage(ast::PipelineStage::kFragment)}, {Location(0u)}); Inspector& inspector = Build(); @@ -353,14 +353,20 @@ TEST_F(InspectorGetEntryPointTest, MultipleInOutVariables) { EXPECT_EQ("in_var0", result[0].input_variables[0].name); EXPECT_TRUE(result[0].input_variables[0].has_location_decoration); EXPECT_EQ(0u, result[0].input_variables[0].location_decoration); + EXPECT_EQ(InterpolationType::kFlat, + result[0].input_variables[0].interpolation_type); EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type); EXPECT_EQ("in_var1", result[0].input_variables[1].name); EXPECT_TRUE(result[0].input_variables[1].has_location_decoration); EXPECT_EQ(1u, result[0].input_variables[1].location_decoration); + EXPECT_EQ(InterpolationType::kFlat, + result[0].input_variables[1].interpolation_type); EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type); EXPECT_EQ("in_var4", result[0].input_variables[2].name); EXPECT_TRUE(result[0].input_variables[2].has_location_decoration); EXPECT_EQ(4u, result[0].input_variables[2].location_decoration); + EXPECT_EQ(InterpolationType::kFlat, + result[0].input_variables[2].interpolation_type); EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[2].component_type); ASSERT_EQ(1u, result[0].output_variables.size()); @@ -371,11 +377,11 @@ TEST_F(InspectorGetEntryPointTest, MultipleInOutVariables) { } TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) { - auto* in_var_foo = Param("in_var_foo", ty.u32(), {Location(0u)}); + auto* in_var_foo = Param("in_var_foo", ty.u32(), {Location(0u), Flat()}); Func("foo", {in_var_foo}, ty.u32(), {Return("in_var_foo")}, {Stage(ast::PipelineStage::kFragment)}, {Location(0u)}); - auto* in_var_bar = Param("in_var_bar", ty.u32(), {Location(0u)}); + auto* in_var_bar = Param("in_var_bar", ty.u32(), {Location(0u), Flat()}); Func("bar", {in_var_bar}, ty.u32(), {Return("in_var_bar")}, {Stage(ast::PipelineStage::kFragment)}, {Location(1u)}); @@ -390,6 +396,8 @@ TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) { EXPECT_EQ("in_var_foo", result[0].input_variables[0].name); EXPECT_TRUE(result[0].input_variables[0].has_location_decoration); EXPECT_EQ(0u, result[0].input_variables[0].location_decoration); + EXPECT_EQ(InterpolationType::kFlat, + result[0].input_variables[0].interpolation_type); EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type); ASSERT_EQ(1u, result[0].output_variables.size()); @@ -402,6 +410,8 @@ TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) { EXPECT_EQ("in_var_bar", result[1].input_variables[0].name); EXPECT_TRUE(result[1].input_variables[0].has_location_decoration); EXPECT_EQ(0u, result[1].input_variables[0].location_decoration); + EXPECT_EQ(InterpolationType::kFlat, + result[1].input_variables[0].interpolation_type); EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[0].component_type); ASSERT_EQ(1u, result[1].output_variables.size()); diff --git a/src/inspector/test_inspector_builder.cc b/src/inspector/test_inspector_builder.cc index 3548eea7da..734fc5a53e 100644 --- a/src/inspector/test_inspector_builder.cc +++ b/src/inspector/test_inspector_builder.cc @@ -55,7 +55,8 @@ const ast::Struct* InspectorBuilder::MakeInOutStruct( std::string member_name; uint32_t location; std::tie(member_name, location) = var; - members.push_back(Member(member_name, ty.u32(), {Location(location)})); + members.push_back( + Member(member_name, ty.u32(), {Location(location), Flat()})); } return Structure(name, members); } diff --git a/src/program_builder.h b/src/program_builder.h index 2d97ad628f..0fd946fb25 100644 --- a/src/program_builder.h +++ b/src/program_builder.h @@ -2300,7 +2300,7 @@ class ProgramBuilder { const ast::InterpolateDecoration* Interpolate( const Source& source, ast::InterpolationType type, - ast::InterpolationSampling sampling) { + ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone) { return create(source, type, sampling); } @@ -2310,10 +2310,23 @@ class ProgramBuilder { /// @returns the interpolate decoration pointer const ast::InterpolateDecoration* Interpolate( ast::InterpolationType type, - ast::InterpolationSampling sampling) { + ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone) { return create(source_, type, sampling); } + /// Creates an ast::InterpolateDecoration using flat interpolation + /// @param source the source information + /// @returns the interpolate decoration pointer + const ast::InterpolateDecoration* Flat(const Source& source) { + return Interpolate(source, ast::InterpolationType::kFlat); + } + + /// Creates an ast::InterpolateDecoration using flat interpolation + /// @returns the interpolate decoration pointer + const ast::InterpolateDecoration* Flat() { + return Interpolate(ast::InterpolationType::kFlat); + } + /// Creates an ast::InvariantDecoration /// @param source the source information /// @returns the invariant decoration pointer diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc index 226fa2573e..f36a8db1ee 100644 --- a/src/reader/spirv/parser_impl.cc +++ b/src/reader/spirv/parser_impl.cc @@ -1790,6 +1790,10 @@ bool ParserImpl::ConvertPipelineDecorations(const Type* store_type, } SetLocation(ast_decos, create(Source{}, deco[1])); + if (store_type->IsIntegerScalarOrVector()) { + // Default to flat interpolation for integral user-defined IO types. + type = ast::InterpolationType::kFlat; + } break; case SpvDecorationFlat: type = ast::InterpolationType::kFlat; diff --git a/src/reader/spirv/parser_impl_module_var_test.cc b/src/reader/spirv/parser_impl_module_var_test.cc index 31007f3b9d..5e1051819e 100644 --- a/src/reader/spirv/parser_impl_module_var_test.cc +++ b/src/reader/spirv/parser_impl_module_var_test.cc @@ -3727,14 +3727,14 @@ fn main_1() { } struct main_out { - @location(0) + @location(0) @interpolate(flat) x_2_1 : u32; - @location(6) + @location(6) @interpolate(flat) x_4_1 : u32; } @stage(fragment) -fn main(@location(0) x_1_param : u32, @location(30) x_3_param : u32) -> main_out { +fn main(@location(0) @interpolate(flat) x_1_param : u32, @location(30) @interpolate(flat) x_3_param : u32) -> main_out { x_1 = x_1_param; x_3 = x_3_param; main_1(); @@ -4679,7 +4679,6 @@ fn main(@location(9) x_1_param : f32, @location(11) x_1_param_1 : vec4) -> TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Interpolation_Flat_Vertex_In) { - // Flat decorations are dropped for integral const auto assembly = CommonCapabilities() + R"( OpEntryPoint Vertex %main "main" %1 %2 %3 %4 %5 %6 %10 OpDecorate %1 Location 1 @@ -4764,7 +4763,6 @@ fn main(@location(1) @interpolate(flat) x_1_param : u32, @location(2) @interpola TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Interpolation_Flat_Vertex_Output) { - // Flat decorations are dropped for integral const auto assembly = CommonCapabilities() + R"( OpEntryPoint Vertex %main "main" %1 %2 %3 %4 %5 %6 %10 OpDecorate %1 Location 1 @@ -4855,7 +4853,6 @@ fn main() -> main_out { TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Flatten_Interpolation_Flat_Fragment_In) { - // Flat decorations are dropped for integral const auto assembly = CommonCapabilities() + R"( OpEntryPoint Fragment %main "main" %1 %2 OpExecutionMode %main OriginUpperLeft @@ -4910,7 +4907,6 @@ fn main(@location(1) @interpolate(flat) x_1_param : f32, @location(2) @interpola TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Interpolation_Floating_Fragment_In) { - // Flat decorations are dropped for integral const auto assembly = CommonCapabilities() + R"( OpEntryPoint Fragment %main "main" %1 %2 %3 %4 %5 %6 OpExecutionMode %main OriginUpperLeft @@ -5056,7 +5052,6 @@ fn main(@location(1) x_1_param : f32, @location(2) @interpolate(perspective, cen TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Interpolation_Floating_Fragment_Out) { - // Flat decorations are dropped for integral const auto assembly = CommonCapabilities() + R"( OpEntryPoint Fragment %main "main" %1 %2 %3 %4 %5 %6 OpExecutionMode %main OriginUpperLeft @@ -5221,6 +5216,162 @@ fn main() -> main_out { EXPECT_EQ(got, expected) << got; } +TEST_F(SpvModuleScopeVarParserTest, + EntryPointWrapping_Interpolation_Default_Vertex_Output) { + // Integral types default to @interpolate(flat). + // Floating types default to @interpolate(perspective, center), which is the + // same as WGSL and therefore dropped. + const auto assembly = CommonCapabilities() + R"( + OpEntryPoint Vertex %main "main" %1 %2 %3 %4 %5 %6 %10 + OpDecorate %1 Location 1 + OpDecorate %2 Location 2 + OpDecorate %3 Location 3 + OpDecorate %4 Location 4 + OpDecorate %5 Location 5 + OpDecorate %6 Location 6 + OpDecorate %10 BuiltIn Position +)" + CommonTypes() + + R"( + %ptr_out_uint = OpTypePointer Output %uint + %ptr_out_v2uint = OpTypePointer Output %v2uint + %ptr_out_int = OpTypePointer Output %int + %ptr_out_v2int = OpTypePointer Output %v2int + %ptr_out_float = OpTypePointer Output %float + %ptr_out_v2float = OpTypePointer Output %v2float + %1 = OpVariable %ptr_out_uint Output + %2 = OpVariable %ptr_out_v2uint Output + %3 = OpVariable %ptr_out_int Output + %4 = OpVariable %ptr_out_v2int Output + %5 = OpVariable %ptr_out_float Output + %6 = OpVariable %ptr_out_v2float Output + + %ptr_out_v4float = OpTypePointer Output %v4float + %10 = OpVariable %ptr_out_v4float Output + + %main = OpFunction %void None %voidfn + %entry = OpLabel + OpReturn + OpFunctionEnd + )"; + auto p = parser(test::Assemble(assembly)); + + ASSERT_TRUE(p->BuildAndParseInternalModule()); + EXPECT_TRUE(p->error().empty()); + const auto got = test::ToString(p->program()); + const std::string expected = + R"(var x_1 : u32; + +var x_2 : vec2; + +var x_3 : i32; + +var x_4 : vec2; + +var x_5 : f32; + +var x_6 : vec2; + +var x_10 : vec4; + +fn main_1() { + return; +} + +struct main_out { + @location(1) @interpolate(flat) + x_1_1 : u32; + @location(2) @interpolate(flat) + x_2_1 : vec2; + @location(3) @interpolate(flat) + x_3_1 : i32; + @location(4) @interpolate(flat) + x_4_1 : vec2; + @location(5) + x_5_1 : f32; + @location(6) + x_6_1 : vec2; + @builtin(position) + x_10_1 : vec4; +} + +@stage(vertex) +fn main() -> main_out { + main_1(); + return main_out(x_1, x_2, x_3, x_4, x_5, x_6, x_10); +} +)"; + EXPECT_EQ(got, expected) << got; +} + +TEST_F(SpvModuleScopeVarParserTest, + EntryPointWrapping_Interpolation_Default_Fragment_In) { + // Integral types default to @interpolate(flat). + // Floating types default to @interpolate(perspective, center), which is the + // same as WGSL and therefore dropped. + const auto assembly = CommonCapabilities() + R"( + OpEntryPoint Fragment %main "main" %1 %2 %3 %4 %5 %6 + OpDecorate %1 Location 1 + OpDecorate %2 Location 2 + OpDecorate %3 Location 3 + OpDecorate %4 Location 4 + OpDecorate %5 Location 5 + OpDecorate %6 Location 6 +)" + CommonTypes() + + R"( + %ptr_in_uint = OpTypePointer Input %uint + %ptr_in_v2uint = OpTypePointer Input %v2uint + %ptr_in_int = OpTypePointer Input %int + %ptr_in_v2int = OpTypePointer Input %v2int + %ptr_in_float = OpTypePointer Input %float + %ptr_in_v2float = OpTypePointer Input %v2float + %1 = OpVariable %ptr_in_uint Input + %2 = OpVariable %ptr_in_v2uint Input + %3 = OpVariable %ptr_in_int Input + %4 = OpVariable %ptr_in_v2int Input + %5 = OpVariable %ptr_in_float Input + %6 = OpVariable %ptr_in_v2float Input + + %main = OpFunction %void None %voidfn + %entry = OpLabel + OpReturn + OpFunctionEnd + )"; + auto p = parser(test::Assemble(assembly)); + + ASSERT_TRUE(p->BuildAndParseInternalModule()); + EXPECT_TRUE(p->error().empty()); + const auto got = test::ToString(p->program()); + const std::string expected = + R"(var x_1 : u32; + +var x_2 : vec2; + +var x_3 : i32; + +var x_4 : vec2; + +var x_5 : f32; + +var x_6 : vec2; + +fn main_1() { + return; +} + +@stage(fragment) +fn main(@location(1) @interpolate(flat) x_1_param : u32, @location(2) @interpolate(flat) x_2_param : vec2, @location(3) @interpolate(flat) x_3_param : i32, @location(4) @interpolate(flat) x_4_param : vec2, @location(5) x_5_param : f32, @location(6) x_6_param : vec2) { + x_1 = x_1_param; + x_2 = x_2_param; + x_3 = x_3_param; + x_4 = x_4_param; + x_5 = x_5_param; + x_6 = x_6_param; + main_1(); +} +)"; + EXPECT_EQ(got, expected) << got; +} + } // namespace } // namespace spirv } // namespace reader diff --git a/src/resolver/decoration_validation_test.cc b/src/resolver/decoration_validation_test.cc index 592ba15fc9..6f8983b49f 100644 --- a/src/resolver/decoration_validation_test.cc +++ b/src/resolver/decoration_validation_test.cc @@ -1332,11 +1332,10 @@ TEST_F(InterpolateTest, FragmentInput_Integer_MissingFlatInterpolation) { ty.void_(), {}, ast::DecorationList{Stage(ast::PipelineStage::kFragment)}); - // TODO(crbug.com/tint/1224): Make this an error. - EXPECT_TRUE(r()->Resolve()); - EXPECT_EQ(r()->error(), - "12:34 warning: integral user-defined fragment inputs must have a " - "flat interpolation attribute"); + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + R"(12:34 error: integral user-defined fragment inputs must have a flat interpolation attribute)"); } TEST_F(InterpolateTest, VertexOutput_Integer_MissingFlatInterpolation) { @@ -1350,11 +1349,11 @@ TEST_F(InterpolateTest, VertexOutput_Integer_MissingFlatInterpolation) { Func("main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))}, ast::DecorationList{Stage(ast::PipelineStage::kVertex)}); - // TODO(crbug.com/tint/1224): Make this an error. - EXPECT_TRUE(r()->Resolve()); - EXPECT_EQ(r()->error(), - "12:34 warning: integral user-defined vertex outputs must have a " - "flat interpolation attribute"); + EXPECT_FALSE(r()->Resolve()); + EXPECT_EQ( + r()->error(), + R"(12:34 error: integral user-defined vertex outputs must have a flat interpolation attribute +note: while analysing entry point 'main')"); } TEST_F(InterpolateTest, MissingLocationAttribute_Parameter) { diff --git a/src/resolver/entry_point_validation_test.cc b/src/resolver/entry_point_validation_test.cc index a2c0eace43..1df0c33847 100644 --- a/src/resolver/entry_point_validation_test.cc +++ b/src/resolver/entry_point_validation_test.cc @@ -371,9 +371,9 @@ static constexpr Params cases[] = { TEST_P(TypeValidationTest, BareInputs) { // @stage(fragment) - // fn main(@location(0) a : *) {} + // fn main(@location(0) @interpolate(flat) a : *) {} auto params = GetParam(); - auto* a = Param("a", params.create_ast_type(*this), {Location(0)}); + auto* a = Param("a", params.create_ast_type(*this), {Location(0), Flat()}); Func(Source{{12, 34}}, "main", {a}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)}); @@ -386,13 +386,13 @@ TEST_P(TypeValidationTest, BareInputs) { TEST_P(TypeValidationTest, StructInputs) { // struct Input { - // @location(0) a : *; + // @location(0) @interpolate(flat) a : *; // }; // @stage(fragment) // fn main(a : Input) {} auto params = GetParam(); - auto* input = Structure( - "Input", {Member("a", params.create_ast_type(*this), {Location(0)})}); + auto* input = Structure("Input", {Member("a", params.create_ast_type(*this), + {Location(0), Flat()})}); auto* a = Param("a", ty.Of(input), {}); Func(Source{{12, 34}}, "main", {a}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)}); @@ -454,9 +454,9 @@ using LocationDecorationTests = ResolverTest; TEST_F(LocationDecorationTests, Pass) { // @stage(fragment) - // fn frag_main(@location(0) a: i32) {} + // fn frag_main(@location(0) @interpolate(flat) a: i32) {} - auto* p = Param(Source{{12, 34}}, "a", ty.i32(), {Location(0)}); + auto* p = Param(Source{{12, 34}}, "a", ty.i32(), {Location(0), Flat()}); Func("frag_main", {p}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)}); diff --git a/src/resolver/resolver_validation.cc b/src/resolver/resolver_validation.cc index f3e830228e..51e78769ec 100644 --- a/src/resolver/resolver_validation.cc +++ b/src/resolver/resolver_validation.cc @@ -1055,21 +1055,21 @@ bool Resolver::ValidateEntryPoint(const sem::Function* func) { if (pipeline_io_attribute && pipeline_io_attribute->Is()) { if (ty->is_integer_scalar_or_vector() && !interpolate_attribute) { - // TODO(crbug.com/tint/1224): Make these errors once downstream - // usages have caught up (no sooner than M99). if (decl->PipelineStage() == ast::PipelineStage::kVertex && param_or_ret == ParamOrRetType::kReturnType) { - AddWarning( + AddError( "integral user-defined vertex outputs must have a flat " "interpolation attribute", source); + return false; } if (decl->PipelineStage() == ast::PipelineStage::kFragment && param_or_ret == ParamOrRetType::kParameter) { - AddWarning( + AddError( "integral user-defined fragment inputs must have a flat " "interpolation attribute", source); + return false; } } } diff --git a/src/transform/canonicalize_entry_point_io_test.cc b/src/transform/canonicalize_entry_point_io_test.cc index 0219ff2bf5..9a5f184638 100644 --- a/src/transform/canonicalize_entry_point_io_test.cc +++ b/src/transform/canonicalize_entry_point_io_test.cc @@ -74,7 +74,7 @@ TEST_F(CanonicalizeEntryPointIOTest, Parameters_Spirv) { auto* src = R"( @stage(fragment) fn frag_main(@location(1) loc1 : f32, - @location(2) loc2 : vec4, + @location(2) @interpolate(flat) loc2 : vec4, @builtin(position) coord : vec4) { var col : f32 = (coord.x * loc1); } @@ -109,7 +109,7 @@ TEST_F(CanonicalizeEntryPointIOTest, Parameters_Msl) { auto* src = R"( @stage(fragment) fn frag_main(@location(1) loc1 : f32, - @location(2) loc2 : vec4, + @location(2) @interpolate(flat) loc2 : vec4, @builtin(position) coord : vec4) { var col : f32 = (coord.x * loc1); } @@ -119,7 +119,7 @@ fn frag_main(@location(1) loc1 : f32, struct tint_symbol_1 { @location(1) loc1 : f32; - @location(2) + @location(2) @interpolate(flat) loc2 : vec4; } @@ -145,7 +145,7 @@ TEST_F(CanonicalizeEntryPointIOTest, Parameters_Hlsl) { auto* src = R"( @stage(fragment) fn frag_main(@location(1) loc1 : f32, - @location(2) loc2 : vec4, + @location(2) @interpolate(flat) loc2 : vec4, @builtin(position) coord : vec4) { var col : f32 = (coord.x * loc1); } @@ -155,7 +155,7 @@ fn frag_main(@location(1) loc1 : f32, struct tint_symbol_1 { @location(1) loc1 : f32; - @location(2) + @location(2) @interpolate(flat) loc2 : vec4; @builtin(position) coord : vec4; @@ -222,7 +222,7 @@ struct FragBuiltins { }; struct FragLocations { @location(1) loc1 : f32; - @location(2) loc2 : vec4; + @location(2) @interpolate(flat) loc2 : vec4; }; @stage(fragment) @@ -276,7 +276,7 @@ struct FragBuiltins { }; struct FragLocations { @location(1) loc1 : f32; - @location(2) loc2 : vec4; + @location(2) @interpolate(flat) loc2 : vec4; }; @stage(fragment) @@ -302,7 +302,7 @@ struct tint_symbol_1 { loc0 : f32; @location(1) loc1 : f32; - @location(2) + @location(2) @interpolate(flat) loc2 : vec4; } @@ -331,7 +331,7 @@ struct FragBuiltins { }; struct FragLocations { @location(1) loc1 : f32; - @location(2) loc2 : vec4; + @location(2) @interpolate(flat) loc2 : vec4; }; @stage(fragment) @@ -357,7 +357,7 @@ struct tint_symbol_1 { loc0 : f32; @location(1) loc1 : f32; - @location(2) + @location(2) @interpolate(flat) loc2 : vec4; @builtin(position) coord : vec4; @@ -1134,18 +1134,18 @@ struct VertexIn { }; struct VertexOut { - @location(0) i : i32; - @location(1) u : u32; - @location(2) vi : vec4; - @location(3) vu : vec4; + @location(0) @interpolate(flat) i : i32; + @location(1) @interpolate(flat) u : u32; + @location(2) @interpolate(flat) vi : vec4; + @location(3) @interpolate(flat) vu : vec4; @builtin(position) pos : vec4; }; struct FragmentInterface { - @location(0) i : i32; - @location(1) u : u32; - @location(2) vi : vec4; - @location(3) vu : vec4; + @location(0) @interpolate(flat) i : i32; + @location(1) @interpolate(flat) u : u32; + @location(2) @interpolate(flat) vi : vec4; + @location(3) @interpolate(flat) vu : vec4; }; @stage(vertex) @@ -1187,13 +1187,13 @@ fn frag_main(inputs : FragmentInterface) -> FragmentInterface { @location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var vu_3 : vec4; -@location(0) @internal(disable_validation__ignore_storage_class) var i_4 : i32; +@location(0) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var i_4 : i32; -@location(1) @internal(disable_validation__ignore_storage_class) var u_4 : u32; +@location(1) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var u_4 : u32; -@location(2) @internal(disable_validation__ignore_storage_class) var vi_4 : vec4; +@location(2) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var vi_4 : vec4; -@location(3) @internal(disable_validation__ignore_storage_class) var vu_4 : vec4; +@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var vu_4 : vec4; struct VertexIn { i : i32; @@ -1389,15 +1389,15 @@ fn frag_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 { TEST_F(CanonicalizeEntryPointIOTest, SortedMembers) { auto* src = R"( struct VertexOutput { - @location(1) b : u32; + @location(1) @interpolate(flat) b : u32; @builtin(position) pos : vec4; - @location(3) d : u32; + @location(3) @interpolate(flat) d : u32; @location(0) a : f32; - @location(2) c : i32; + @location(2) @interpolate(flat) c : i32; }; struct FragmentInputExtra { - @location(3) d : u32; + @location(3) @interpolate(flat) d : u32; @builtin(position) pos : vec4; @location(0) a : f32; }; @@ -1409,9 +1409,9 @@ fn vert_main() -> VertexOutput { @stage(fragment) fn frag_main(@builtin(front_facing) ff : bool, - @location(2) c : i32, + @location(2) @interpolate(flat) c : i32, inputs : FragmentInputExtra, - @location(1) b : u32) { + @location(1) @interpolate(flat) b : u32) { } )"; @@ -1433,11 +1433,11 @@ struct FragmentInputExtra { struct tint_symbol { @location(0) a : f32; - @location(1) + @location(1) @interpolate(flat) b : u32; - @location(2) + @location(2) @interpolate(flat) c : i32; - @location(3) + @location(3) @interpolate(flat) d : u32; @builtin(position) pos : vec4; @@ -1462,11 +1462,11 @@ fn vert_main() -> tint_symbol { struct tint_symbol_2 { @location(0) a : f32; - @location(1) + @location(1) @interpolate(flat) b : u32; - @location(2) + @location(2) @interpolate(flat) c : i32; - @location(3) + @location(3) @interpolate(flat) d : u32; @builtin(position) pos : vec4; diff --git a/src/writer/spirv/builder_entry_point_test.cc b/src/writer/spirv/builder_entry_point_test.cc index 46d6745a48..8cc75b057f 100644 --- a/src/writer/spirv/builder_entry_point_test.cc +++ b/src/writer/spirv/builder_entry_point_test.cc @@ -107,13 +107,14 @@ OpFunctionEnd TEST_F(BuilderTest, EntryPoint_ReturnValue) { // @stage(fragment) - // fn frag_main(@location(0) loc_in : u32) -> @location(0) f32 { + // fn frag_main(@location(0) @interpolate(flat) loc_in : u32) + // -> @location(0) f32 { // if (loc_in > 10) { // return 0.5; // } // return 1.0; // } - auto* loc_in = Param("loc_in", ty.u32(), {Location(0)}); + auto* loc_in = Param("loc_in", ty.u32(), {Location(0), Flat()}); auto* cond = create(ast::BinaryOp::kGreaterThan, Expr("loc_in"), Expr(10u)); Func("frag_main", ast::VariableList{loc_in}, ty.f32(), diff --git a/test/bug/tint/1081.wgsl b/test/bug/tint/1081.wgsl index 591fb0482b..6d339a87cc 100644 --- a/test/bug/tint/1081.wgsl +++ b/test/bug/tint/1081.wgsl @@ -6,7 +6,7 @@ fn f(x : i32) -> i32 { } @stage(fragment) -fn main(@location(1) x: vec3) -> @location(2) i32 { +fn main(@location(1) @interpolate(flat) x: vec3) -> @location(2) i32 { var y = x.x; loop { let r = f(y); diff --git a/test/bug/tint/1081.wgsl.expected.hlsl b/test/bug/tint/1081.wgsl.expected.hlsl index 73e28307b0..ad9174c07f 100644 --- a/test/bug/tint/1081.wgsl.expected.hlsl +++ b/test/bug/tint/1081.wgsl.expected.hlsl @@ -1,7 +1,3 @@ -bug/tint/1081.wgsl:9:22 warning: integral user-defined fragment inputs must have a flat interpolation attribute -fn main(@location(1) x: vec3) -> @location(2) i32 { - ^ - int f(int x) { if (true) { if ((x == 10)) { @@ -14,7 +10,7 @@ int f(int x) { } struct tint_symbol_1 { - int3 x : TEXCOORD1; + nointerpolation int3 x : TEXCOORD1; }; struct tint_symbol_2 { int value : SV_Target2; diff --git a/test/bug/tint/1081.wgsl.expected.msl b/test/bug/tint/1081.wgsl.expected.msl index 478e1a54b4..3dd960160d 100644 --- a/test/bug/tint/1081.wgsl.expected.msl +++ b/test/bug/tint/1081.wgsl.expected.msl @@ -1,12 +1,8 @@ -bug/tint/1081.wgsl:9:22 warning: integral user-defined fragment inputs must have a flat interpolation attribute -fn main(@location(1) x: vec3) -> @location(2) i32 { - ^ - #include using namespace metal; struct tint_symbol_2 { - int3 x [[user(locn1)]]; + int3 x [[user(locn1)]] [[flat]]; }; struct tint_symbol_3 { int value [[color(2)]]; diff --git a/test/bug/tint/1081.wgsl.expected.spvasm b/test/bug/tint/1081.wgsl.expected.spvasm index b17a7e645e..2f5ee3f55c 100644 --- a/test/bug/tint/1081.wgsl.expected.spvasm +++ b/test/bug/tint/1081.wgsl.expected.spvasm @@ -1,7 +1,3 @@ -bug/tint/1081.wgsl:9:22 warning: integral user-defined fragment inputs must have a flat interpolation attribute -fn main(@location(1) x: vec3) -> @location(2) i32 { - ^ - ; SPIR-V ; Version: 1.3 ; Generator: Google Tint Compiler; 0 diff --git a/test/bug/tint/1081.wgsl.expected.wgsl b/test/bug/tint/1081.wgsl.expected.wgsl index 34d78e1a94..3f7cc7a4d2 100644 --- a/test/bug/tint/1081.wgsl.expected.wgsl +++ b/test/bug/tint/1081.wgsl.expected.wgsl @@ -1,7 +1,3 @@ -bug/tint/1081.wgsl:9:22 warning: integral user-defined fragment inputs must have a flat interpolation attribute -fn main(@location(1) x: vec3) -> @location(2) i32 { - ^ - fn f(x : i32) -> i32 { if ((x == 10)) { discard; @@ -10,7 +6,7 @@ fn f(x : i32) -> i32 { } @stage(fragment) -fn main(@location(1) x : vec3) -> @location(2) i32 { +fn main(@location(1) @interpolate(flat) x : vec3) -> @location(2) i32 { var y = x.x; loop { let r = f(y); diff --git a/test/vk-gl-cts/spirv_assembly/instruction/float32/comparison/frexpstruct_1_frag/0.wgsl b/test/vk-gl-cts/spirv_assembly/instruction/float32/comparison/frexpstruct_1_frag/0.wgsl index 5c734e34aa..db20f9ed7b 100644 --- a/test/vk-gl-cts/spirv_assembly/instruction/float32/comparison/frexpstruct_1_frag/0.wgsl +++ b/test/vk-gl-cts/spirv_assembly/instruction/float32/comparison/frexpstruct_1_frag/0.wgsl @@ -14,7 +14,7 @@ fn main_1() { } struct main_out { - @location(0) + @location(0) @interpolate(flat) x_4_1 : u32; @builtin(position) gl_Position : vec4; diff --git a/test/vk-gl-cts/spirv_assembly/instruction/spirv1p4/hlsl_functionality1/decorate_string/0.wgsl b/test/vk-gl-cts/spirv_assembly/instruction/spirv1p4/hlsl_functionality1/decorate_string/0.wgsl index 1ab42ae3df..ecc89f5766 100644 --- a/test/vk-gl-cts/spirv_assembly/instruction/spirv1p4/hlsl_functionality1/decorate_string/0.wgsl +++ b/test/vk-gl-cts/spirv_assembly/instruction/spirv1p4/hlsl_functionality1/decorate_string/0.wgsl @@ -14,7 +14,7 @@ fn main_1() { struct main_out { @builtin(position) gl_Position : vec4; - @location(0) + @location(0) @interpolate(flat) pos_1 : u32; }; diff --git a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_image_atomic/0-opt.wgsl b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_image_atomic/0-opt.wgsl index 0e32731420..5f9494069f 100644 --- a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_image_atomic/0-opt.wgsl +++ b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_image_atomic/0-opt.wgsl @@ -14,7 +14,7 @@ fn main_1() { } struct main_out { - @location(0) + @location(0) @interpolate(flat) x_4_1 : i32; @builtin(position) gl_Position : vec4; diff --git a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_image_store/1.wgsl b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_image_store/1.wgsl index 2cd673efdf..e2a03ec766 100644 --- a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_image_store/1.wgsl +++ b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_image_store/1.wgsl @@ -24,7 +24,7 @@ struct main_out { }; @stage(fragment) -fn main(@builtin(position) x_2_param : vec4, @location(0) x_3_param : i32) -> main_out { +fn main(@builtin(position) x_2_param : vec4, @location(0) @interpolate(flat) x_3_param : i32) -> main_out { x_2 = x_2_param; x_3 = x_3_param; main_1(); diff --git a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_output_write/1.wgsl b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_output_write/1.wgsl index 07e6992bab..7b3e76a818 100644 --- a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_output_write/1.wgsl +++ b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_output_write/1.wgsl @@ -19,7 +19,7 @@ struct main_out { }; @stage(fragment) -fn main(@builtin(position) x_2_param : vec4, @location(0) x_3_param : i32) -> main_out { +fn main(@builtin(position) x_2_param : vec4, @location(0) @interpolate(flat) x_3_param : i32) -> main_out { x_2 = x_2_param; x_3 = x_3_param; main_1(); diff --git a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_output_write_before_terminate/1.wgsl b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_output_write_before_terminate/1.wgsl index a849b1d02c..cbe07a4a4e 100644 --- a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_output_write_before_terminate/1.wgsl +++ b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_output_write_before_terminate/1.wgsl @@ -19,7 +19,7 @@ struct main_out { }; @stage(fragment) -fn main(@builtin(position) x_2_param : vec4, @location(0) x_3_param : i32) -> main_out { +fn main(@builtin(position) x_2_param : vec4, @location(0) @interpolate(flat) x_3_param : i32) -> main_out { x_2 = x_2_param; x_3 = x_3_param; main_1(); diff --git a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_ssbo_store/1.wgsl b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_ssbo_store/1.wgsl index da18d1228d..7d777c91b0 100644 --- a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_ssbo_store/1.wgsl +++ b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/no_ssbo_store/1.wgsl @@ -30,7 +30,7 @@ struct main_out { }; @stage(fragment) -fn main(@builtin(position) x_2_param : vec4, @location(0) x_3_param : i32) -> main_out { +fn main(@builtin(position) x_2_param : vec4, @location(0) @interpolate(flat) x_3_param : i32) -> main_out { x_2 = x_2_param; x_3 = x_3_param; main_1(); diff --git a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/ssbo_store_before_terminate/1.wgsl b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/ssbo_store_before_terminate/1.wgsl index 48083ee854..f8cd63e613 100644 --- a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/ssbo_store_before_terminate/1.wgsl +++ b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/ssbo_store_before_terminate/1.wgsl @@ -30,7 +30,7 @@ struct main_out { }; @stage(fragment) -fn main(@builtin(position) x_2_param : vec4, @location(0) x_3_param : i32) -> main_out { +fn main(@builtin(position) x_2_param : vec4, @location(0) @interpolate(flat) x_3_param : i32) -> main_out { x_2 = x_2_param; x_3 = x_3_param; main_1(); diff --git a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/terminate_loop/1.wgsl b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/terminate_loop/1.wgsl index 78ca88f2f0..573f508fd1 100644 --- a/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/terminate_loop/1.wgsl +++ b/test/vk-gl-cts/spirv_assembly/instruction/terminate_invocation/terminate_loop/1.wgsl @@ -34,7 +34,7 @@ struct main_out { }; @stage(fragment) -fn main(@builtin(position) x_2_param : vec4, @location(0) x_3_param : i32) -> main_out { +fn main(@builtin(position) x_2_param : vec4, @location(0) @interpolate(flat) x_3_param : i32) -> main_out { x_2 = x_2_param; x_3 = x_3_param; main_1();