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 <noreply+kokoro@google.com> Reviewed-by: David Neto <dneto@google.com> Commit-Queue: James Price <jrprice@google.com>
This commit is contained in:
parent
d5560400a3
commit
1c02eb8cb0
|
@ -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
|
||||
|
|
|
@ -303,7 +303,7 @@ TEST_P(InspectorGetEntryPointComponentAndCompositionTest, Test) {
|
|||
std::function<const ast::Type*()> 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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<ast::InterpolateDecoration>(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<ast::InterpolateDecoration>(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
|
||||
|
|
|
@ -1790,6 +1790,10 @@ bool ParserImpl::ConvertPipelineDecorations(const Type* store_type,
|
|||
}
|
||||
SetLocation(ast_decos,
|
||||
create<ast::LocationDecoration>(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;
|
||||
|
|
|
@ -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<f32>) ->
|
|||
|
||||
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<private> x_1 : u32;
|
||||
|
||||
var<private> x_2 : vec2<u32>;
|
||||
|
||||
var<private> x_3 : i32;
|
||||
|
||||
var<private> x_4 : vec2<i32>;
|
||||
|
||||
var<private> x_5 : f32;
|
||||
|
||||
var<private> x_6 : vec2<f32>;
|
||||
|
||||
var<private> x_10 : vec4<f32>;
|
||||
|
||||
fn main_1() {
|
||||
return;
|
||||
}
|
||||
|
||||
struct main_out {
|
||||
@location(1) @interpolate(flat)
|
||||
x_1_1 : u32;
|
||||
@location(2) @interpolate(flat)
|
||||
x_2_1 : vec2<u32>;
|
||||
@location(3) @interpolate(flat)
|
||||
x_3_1 : i32;
|
||||
@location(4) @interpolate(flat)
|
||||
x_4_1 : vec2<i32>;
|
||||
@location(5)
|
||||
x_5_1 : f32;
|
||||
@location(6)
|
||||
x_6_1 : vec2<f32>;
|
||||
@builtin(position)
|
||||
x_10_1 : vec4<f32>;
|
||||
}
|
||||
|
||||
@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<private> x_1 : u32;
|
||||
|
||||
var<private> x_2 : vec2<u32>;
|
||||
|
||||
var<private> x_3 : i32;
|
||||
|
||||
var<private> x_4 : vec2<i32>;
|
||||
|
||||
var<private> x_5 : f32;
|
||||
|
||||
var<private> x_6 : vec2<f32>;
|
||||
|
||||
fn main_1() {
|
||||
return;
|
||||
}
|
||||
|
||||
@stage(fragment)
|
||||
fn main(@location(1) @interpolate(flat) x_1_param : u32, @location(2) @interpolate(flat) x_2_param : vec2<u32>, @location(3) @interpolate(flat) x_3_param : i32, @location(4) @interpolate(flat) x_4_param : vec2<i32>, @location(5) x_5_param : f32, @location(6) x_6_param : vec2<f32>) {
|
||||
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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)});
|
||||
|
||||
|
|
|
@ -1055,21 +1055,21 @@ bool Resolver::ValidateEntryPoint(const sem::Function* func) {
|
|||
if (pipeline_io_attribute &&
|
||||
pipeline_io_attribute->Is<ast::LocationDecoration>()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<u32>,
|
||||
@location(2) @interpolate(flat) loc2 : vec4<u32>,
|
||||
@builtin(position) coord : vec4<f32>) {
|
||||
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<u32>,
|
||||
@location(2) @interpolate(flat) loc2 : vec4<u32>,
|
||||
@builtin(position) coord : vec4<f32>) {
|
||||
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<u32>;
|
||||
}
|
||||
|
||||
|
@ -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<u32>,
|
||||
@location(2) @interpolate(flat) loc2 : vec4<u32>,
|
||||
@builtin(position) coord : vec4<f32>) {
|
||||
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<u32>;
|
||||
@builtin(position)
|
||||
coord : vec4<f32>;
|
||||
|
@ -222,7 +222,7 @@ struct FragBuiltins {
|
|||
};
|
||||
struct FragLocations {
|
||||
@location(1) loc1 : f32;
|
||||
@location(2) loc2 : vec4<u32>;
|
||||
@location(2) @interpolate(flat) loc2 : vec4<u32>;
|
||||
};
|
||||
|
||||
@stage(fragment)
|
||||
|
@ -276,7 +276,7 @@ struct FragBuiltins {
|
|||
};
|
||||
struct FragLocations {
|
||||
@location(1) loc1 : f32;
|
||||
@location(2) loc2 : vec4<u32>;
|
||||
@location(2) @interpolate(flat) loc2 : vec4<u32>;
|
||||
};
|
||||
|
||||
@stage(fragment)
|
||||
|
@ -302,7 +302,7 @@ struct tint_symbol_1 {
|
|||
loc0 : f32;
|
||||
@location(1)
|
||||
loc1 : f32;
|
||||
@location(2)
|
||||
@location(2) @interpolate(flat)
|
||||
loc2 : vec4<u32>;
|
||||
}
|
||||
|
||||
|
@ -331,7 +331,7 @@ struct FragBuiltins {
|
|||
};
|
||||
struct FragLocations {
|
||||
@location(1) loc1 : f32;
|
||||
@location(2) loc2 : vec4<u32>;
|
||||
@location(2) @interpolate(flat) loc2 : vec4<u32>;
|
||||
};
|
||||
|
||||
@stage(fragment)
|
||||
|
@ -357,7 +357,7 @@ struct tint_symbol_1 {
|
|||
loc0 : f32;
|
||||
@location(1)
|
||||
loc1 : f32;
|
||||
@location(2)
|
||||
@location(2) @interpolate(flat)
|
||||
loc2 : vec4<u32>;
|
||||
@builtin(position)
|
||||
coord : vec4<f32>;
|
||||
|
@ -1134,18 +1134,18 @@ struct VertexIn {
|
|||
};
|
||||
|
||||
struct VertexOut {
|
||||
@location(0) i : i32;
|
||||
@location(1) u : u32;
|
||||
@location(2) vi : vec4<i32>;
|
||||
@location(3) vu : vec4<u32>;
|
||||
@location(0) @interpolate(flat) i : i32;
|
||||
@location(1) @interpolate(flat) u : u32;
|
||||
@location(2) @interpolate(flat) vi : vec4<i32>;
|
||||
@location(3) @interpolate(flat) vu : vec4<u32>;
|
||||
@builtin(position) pos : vec4<f32>;
|
||||
};
|
||||
|
||||
struct FragmentInterface {
|
||||
@location(0) i : i32;
|
||||
@location(1) u : u32;
|
||||
@location(2) vi : vec4<i32>;
|
||||
@location(3) vu : vec4<u32>;
|
||||
@location(0) @interpolate(flat) i : i32;
|
||||
@location(1) @interpolate(flat) u : u32;
|
||||
@location(2) @interpolate(flat) vi : vec4<i32>;
|
||||
@location(3) @interpolate(flat) vu : vec4<u32>;
|
||||
};
|
||||
|
||||
@stage(vertex)
|
||||
|
@ -1187,13 +1187,13 @@ fn frag_main(inputs : FragmentInterface) -> FragmentInterface {
|
|||
|
||||
@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> vu_3 : vec4<u32>;
|
||||
|
||||
@location(0) @internal(disable_validation__ignore_storage_class) var<out> i_4 : i32;
|
||||
@location(0) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> i_4 : i32;
|
||||
|
||||
@location(1) @internal(disable_validation__ignore_storage_class) var<out> u_4 : u32;
|
||||
@location(1) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> u_4 : u32;
|
||||
|
||||
@location(2) @internal(disable_validation__ignore_storage_class) var<out> vi_4 : vec4<i32>;
|
||||
@location(2) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vi_4 : vec4<i32>;
|
||||
|
||||
@location(3) @internal(disable_validation__ignore_storage_class) var<out> vu_4 : vec4<u32>;
|
||||
@location(3) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<out> vu_4 : vec4<u32>;
|
||||
|
||||
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<f32>;
|
||||
@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<f32>;
|
||||
@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<f32>;
|
||||
|
@ -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<f32>;
|
||||
|
|
|
@ -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::BinaryExpression>(ast::BinaryOp::kGreaterThan,
|
||||
Expr("loc_in"), Expr(10u));
|
||||
Func("frag_main", ast::VariableList{loc_in}, ty.f32(),
|
||||
|
|
|
@ -6,7 +6,7 @@ fn f(x : i32) -> i32 {
|
|||
}
|
||||
|
||||
@stage(fragment)
|
||||
fn main(@location(1) x: vec3<i32>) -> @location(2) i32 {
|
||||
fn main(@location(1) @interpolate(flat) x: vec3<i32>) -> @location(2) i32 {
|
||||
var y = x.x;
|
||||
loop {
|
||||
let r = f(y);
|
||||
|
|
|
@ -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<i32>) -> @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;
|
||||
|
|
|
@ -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<i32>) -> @location(2) i32 {
|
||||
^
|
||||
|
||||
#include <metal_stdlib>
|
||||
|
||||
using namespace metal;
|
||||
struct tint_symbol_2 {
|
||||
int3 x [[user(locn1)]];
|
||||
int3 x [[user(locn1)]] [[flat]];
|
||||
};
|
||||
struct tint_symbol_3 {
|
||||
int value [[color(2)]];
|
||||
|
|
|
@ -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<i32>) -> @location(2) i32 {
|
||||
^
|
||||
|
||||
; SPIR-V
|
||||
; Version: 1.3
|
||||
; Generator: Google Tint Compiler; 0
|
||||
|
|
|
@ -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<i32>) -> @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<i32>) -> @location(2) i32 {
|
||||
fn main(@location(1) @interpolate(flat) x : vec3<i32>) -> @location(2) i32 {
|
||||
var y = x.x;
|
||||
loop {
|
||||
let r = f(y);
|
||||
|
|
|
@ -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<f32>;
|
||||
|
|
|
@ -14,7 +14,7 @@ fn main_1() {
|
|||
struct main_out {
|
||||
@builtin(position)
|
||||
gl_Position : vec4<f32>;
|
||||
@location(0)
|
||||
@location(0) @interpolate(flat)
|
||||
pos_1 : u32;
|
||||
};
|
||||
|
||||
|
|
|
@ -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<f32>;
|
||||
|
|
|
@ -24,7 +24,7 @@ struct main_out {
|
|||
};
|
||||
|
||||
@stage(fragment)
|
||||
fn main(@builtin(position) x_2_param : vec4<f32>, @location(0) x_3_param : i32) -> main_out {
|
||||
fn main(@builtin(position) x_2_param : vec4<f32>, @location(0) @interpolate(flat) x_3_param : i32) -> main_out {
|
||||
x_2 = x_2_param;
|
||||
x_3 = x_3_param;
|
||||
main_1();
|
||||
|
|
|
@ -19,7 +19,7 @@ struct main_out {
|
|||
};
|
||||
|
||||
@stage(fragment)
|
||||
fn main(@builtin(position) x_2_param : vec4<f32>, @location(0) x_3_param : i32) -> main_out {
|
||||
fn main(@builtin(position) x_2_param : vec4<f32>, @location(0) @interpolate(flat) x_3_param : i32) -> main_out {
|
||||
x_2 = x_2_param;
|
||||
x_3 = x_3_param;
|
||||
main_1();
|
||||
|
|
|
@ -19,7 +19,7 @@ struct main_out {
|
|||
};
|
||||
|
||||
@stage(fragment)
|
||||
fn main(@builtin(position) x_2_param : vec4<f32>, @location(0) x_3_param : i32) -> main_out {
|
||||
fn main(@builtin(position) x_2_param : vec4<f32>, @location(0) @interpolate(flat) x_3_param : i32) -> main_out {
|
||||
x_2 = x_2_param;
|
||||
x_3 = x_3_param;
|
||||
main_1();
|
||||
|
|
|
@ -30,7 +30,7 @@ struct main_out {
|
|||
};
|
||||
|
||||
@stage(fragment)
|
||||
fn main(@builtin(position) x_2_param : vec4<f32>, @location(0) x_3_param : i32) -> main_out {
|
||||
fn main(@builtin(position) x_2_param : vec4<f32>, @location(0) @interpolate(flat) x_3_param : i32) -> main_out {
|
||||
x_2 = x_2_param;
|
||||
x_3 = x_3_param;
|
||||
main_1();
|
||||
|
|
|
@ -30,7 +30,7 @@ struct main_out {
|
|||
};
|
||||
|
||||
@stage(fragment)
|
||||
fn main(@builtin(position) x_2_param : vec4<f32>, @location(0) x_3_param : i32) -> main_out {
|
||||
fn main(@builtin(position) x_2_param : vec4<f32>, @location(0) @interpolate(flat) x_3_param : i32) -> main_out {
|
||||
x_2 = x_2_param;
|
||||
x_3 = x_3_param;
|
||||
main_1();
|
||||
|
|
|
@ -34,7 +34,7 @@ struct main_out {
|
|||
};
|
||||
|
||||
@stage(fragment)
|
||||
fn main(@builtin(position) x_2_param : vec4<f32>, @location(0) x_3_param : i32) -> main_out {
|
||||
fn main(@builtin(position) x_2_param : vec4<f32>, @location(0) @interpolate(flat) x_3_param : i32) -> main_out {
|
||||
x_2 = x_2_param;
|
||||
x_3 = x_3_param;
|
||||
main_1();
|
||||
|
|
Loading…
Reference in New Issue