transform: Propagate interpolate attributes
Transforms that handle entry point IO need to strip interpolate
attributes when creating undecorated structures, and not strip them
when recreating the IO parameters and return types.
Bug: tint:746
Change-Id: Ifa7d3b9fe3950154689417ad387026ece3df81bb
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/56243
Kokoro: Kokoro <noreply+kokoro@google.com>
Auto-Submit: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/transform/canonicalize_entry_point_io.cc b/src/transform/canonicalize_entry_point_io.cc
index 34ef071..db1ce66 100644
--- a/src/transform/canonicalize_entry_point_io.cc
+++ b/src/transform/canonicalize_entry_point_io.cc
@@ -84,7 +84,8 @@
ast::DecorationList new_decorations = RemoveDecorations(
&ctx, member->decorations(), [](const ast::Decoration* deco) {
return deco
- ->IsAnyOf<ast::BuiltinDecoration, ast::LocationDecoration>();
+ ->IsAnyOf<ast::BuiltinDecoration, ast::InterpolateDecoration,
+ ast::LocationDecoration>();
});
new_struct_members.push_back(
ctx.dst->Member(ctx.Clone(member->symbol()),
@@ -155,6 +156,7 @@
&ctx, member->Declaration()->decorations(),
[](const ast::Decoration* deco) {
return !deco->IsAnyOf<ast::BuiltinDecoration,
+ ast::InterpolateDecoration,
ast::LocationDecoration>();
});
@@ -182,14 +184,9 @@
func_const_initializer =
ctx.dst->Construct(ctx.Clone(param_declared_ty), init_values);
} else {
- ast::DecorationList new_decorations = RemoveDecorations(
- &ctx, param->Declaration()->decorations(),
- [](const ast::Decoration* deco) {
- return !deco->IsAnyOf<ast::BuiltinDecoration,
- ast::LocationDecoration>();
- });
- new_struct_members.push_back(ctx.dst->Member(
- param_name, ctx.Clone(param_declared_ty), new_decorations));
+ new_struct_members.push_back(
+ ctx.dst->Member(param_name, ctx.Clone(param_declared_ty),
+ ctx.Clone(param->Declaration()->decorations())));
func_const_initializer =
ctx.dst->MemberAccessor(new_struct_param_symbol, param_name);
}
@@ -249,6 +246,7 @@
&ctx, member->Declaration()->decorations(),
[](const ast::Decoration* deco) {
return !deco->IsAnyOf<ast::BuiltinDecoration,
+ ast::InterpolateDecoration,
ast::LocationDecoration>();
});
auto symbol = ctx.Clone(member->Declaration()->symbol());
diff --git a/src/transform/canonicalize_entry_point_io_test.cc b/src/transform/canonicalize_entry_point_io_test.cc
index 42153a4..4289f47 100644
--- a/src/transform/canonicalize_entry_point_io_test.cc
+++ b/src/transform/canonicalize_entry_point_io_test.cc
@@ -608,21 +608,103 @@
EXPECT_EQ(expect, str(got));
}
+TEST_F(CanonicalizeEntryPointIOTest, InterpolateAttributes) {
+ auto* src = R"(
+struct VertexOut {
+ [[builtin(position)]] pos : vec4<f32>;
+ [[location(1), interpolate(flat)]] loc1: f32;
+ [[location(2), interpolate(linear, sample)]] loc2 : f32;
+ [[location(3), interpolate(perspective, centroid)]] loc3 : f32;
+};
+
+struct FragmentIn {
+ [[location(1), interpolate(flat)]] loc1: f32;
+ [[location(2), interpolate(linear, sample)]] loc2 : f32;
+};
+
+[[stage(vertex)]]
+fn vert_main() -> VertexOut {
+ return VertexOut();
+}
+
+[[stage(fragment)]]
+fn frag_main(inputs : FragmentIn,
+ [[location(3), interpolate(perspective, centroid)]] loc3 : f32) {
+ let x = inputs.loc1 + inputs.loc2 + loc3;
+}
+)";
+
+ auto* expect = R"(
+struct VertexOut {
+ pos : vec4<f32>;
+ loc1 : f32;
+ loc2 : f32;
+ loc3 : f32;
+};
+
+struct FragmentIn {
+ loc1 : f32;
+ loc2 : f32;
+};
+
+struct tint_symbol {
+ [[location(1), interpolate(flat)]]
+ loc1 : f32;
+ [[location(2), interpolate(linear, sample)]]
+ loc2 : f32;
+ [[location(3), interpolate(perspective, centroid)]]
+ loc3 : f32;
+ [[builtin(position)]]
+ pos : vec4<f32>;
+};
+
+[[stage(vertex)]]
+fn vert_main() -> tint_symbol {
+ let tint_symbol_1 : VertexOut = VertexOut();
+ return tint_symbol(tint_symbol_1.loc1, tint_symbol_1.loc2, tint_symbol_1.loc3, tint_symbol_1.pos);
+}
+
+struct tint_symbol_3 {
+ [[location(1), interpolate(flat)]]
+ loc1 : f32;
+ [[location(2), interpolate(linear, sample)]]
+ loc2 : f32;
+ [[location(3), interpolate(perspective, centroid)]]
+ loc3 : f32;
+};
+
+[[stage(fragment)]]
+fn frag_main(tint_symbol_2 : tint_symbol_3) {
+ let inputs : FragmentIn = FragmentIn(tint_symbol_2.loc1, tint_symbol_2.loc2);
+ let loc3 : f32 = tint_symbol_2.loc3;
+ let x = ((inputs.loc1 + inputs.loc2) + loc3);
+}
+)";
+
+ DataMap data;
+ data.Add<CanonicalizeEntryPointIO::Config>(
+ CanonicalizeEntryPointIO::BuiltinStyle::kStructMember);
+ auto got = Run<CanonicalizeEntryPointIO>(src, data);
+
+ EXPECT_EQ(expect, str(got));
+}
+
TEST_F(CanonicalizeEntryPointIOTest, Struct_LayoutDecorations) {
auto* src = R"(
[[block]]
struct FragmentInput {
[[size(16), location(1)]] value : f32;
[[builtin(position)]] [[align(32)]] coord : vec4<f32>;
+ [[location(0), interpolate(linear, sample)]] [[align(128)]] loc0 : f32;
};
struct FragmentOutput {
- [[size(16), location(1)]] value : f32;
+ [[size(16), location(1), interpolate(flat)]] value : f32;
};
[[stage(fragment)]]
fn frag_main(inputs : FragmentInput) -> FragmentOutput {
- return FragmentOutput(inputs.coord.x * inputs.value);
+ return FragmentOutput(inputs.coord.x * inputs.value + inputs.loc0);
}
)";
@@ -633,6 +715,8 @@
value : f32;
[[align(32)]]
coord : vec4<f32>;
+ [[align(128)]]
+ loc0 : f32;
};
struct FragmentOutput {
@@ -641,6 +725,8 @@
};
struct tint_symbol_1 {
+ [[location(0), interpolate(linear, sample)]]
+ loc0 : f32;
[[location(1)]]
value : f32;
[[builtin(position)]]
@@ -648,14 +734,14 @@
};
struct tint_symbol_2 {
- [[location(1)]]
+ [[location(1), interpolate(flat)]]
value : f32;
};
[[stage(fragment)]]
fn frag_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
- let inputs : FragmentInput = FragmentInput(tint_symbol.value, tint_symbol.coord);
- let tint_symbol_3 : FragmentOutput = FragmentOutput((inputs.coord.x * inputs.value));
+ let inputs : FragmentInput = FragmentInput(tint_symbol.value, tint_symbol.coord, tint_symbol.loc0);
+ let tint_symbol_3 : FragmentOutput = FragmentOutput(((inputs.coord.x * inputs.value) + inputs.loc0));
return tint_symbol_2(tint_symbol_3.value);
}
)";
diff --git a/src/transform/spirv.cc b/src/transform/spirv.cc
index b88a427..c67f8af 100644
--- a/src/transform/spirv.cc
+++ b/src/transform/spirv.cc
@@ -144,7 +144,8 @@
ast::DecorationList new_decorations = RemoveDecorations(
&ctx, member->decorations(), [](const ast::Decoration* deco) {
return deco
- ->IsAnyOf<ast::BuiltinDecoration, ast::LocationDecoration>();
+ ->IsAnyOf<ast::BuiltinDecoration, ast::InterpolateDecoration,
+ ast::LocationDecoration>();
});
new_struct_members.push_back(
ctx.dst->Member(ctx.Clone(member->symbol()),
@@ -313,6 +314,7 @@
ast::DecorationList new_decorations =
RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) {
return !deco->IsAnyOf<ast::BuiltinDecoration,
+ ast::InterpolateDecoration,
ast::LocationDecoration>();
});
new_decorations.push_back(
@@ -370,6 +372,7 @@
ast::DecorationList new_decorations =
RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) {
return !deco->IsAnyOf<ast::BuiltinDecoration,
+ ast::InterpolateDecoration,
ast::LocationDecoration>();
});
new_decorations.push_back(
diff --git a/src/transform/spirv_test.cc b/src/transform/spirv_test.cc
index cf15d8c..4a2c45b 100644
--- a/src/transform/spirv_test.cc
+++ b/src/transform/spirv_test.cc
@@ -394,21 +394,100 @@
EXPECT_EQ(expect, str(got));
}
+TEST_F(SpirvTest, HandleEntryPointIOTypes_InterpolateAttributes) {
+ auto* src = R"(
+struct VertexOut {
+ [[builtin(position)]] pos : vec4<f32>;
+ [[location(1), interpolate(flat)]] loc1: f32;
+ [[location(2), interpolate(linear, sample)]] loc2 : f32;
+ [[location(3), interpolate(perspective, centroid)]] loc3 : f32;
+};
+
+struct FragmentIn {
+ [[location(1), interpolate(flat)]] loc1: f32;
+ [[location(2), interpolate(linear, sample)]] loc2 : f32;
+};
+
+[[stage(vertex)]]
+fn vert_main() -> VertexOut {
+ return VertexOut();
+}
+
+[[stage(fragment)]]
+fn frag_main(inputs : FragmentIn,
+ [[location(3), interpolate(perspective, centroid)]] loc3 : f32) {
+ let x = inputs.loc1 + inputs.loc2 + loc3;
+}
+)";
+
+ auto* expect = R"(
+struct VertexOut {
+ pos : vec4<f32>;
+ loc1 : f32;
+ loc2 : f32;
+ loc3 : f32;
+};
+
+struct FragmentIn {
+ loc1 : f32;
+ loc2 : f32;
+};
+
+[[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_1 : vec4<f32>;
+
+[[location(1), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_2 : f32;
+
+[[location(2), interpolate(linear, sample), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_3 : f32;
+
+[[location(3), interpolate(perspective, centroid), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_4 : f32;
+
+fn tint_symbol_5(tint_symbol : VertexOut) {
+ tint_symbol_1 = tint_symbol.pos;
+ tint_symbol_2 = tint_symbol.loc1;
+ tint_symbol_3 = tint_symbol.loc2;
+ tint_symbol_4 = tint_symbol.loc3;
+}
+
+[[stage(vertex)]]
+fn vert_main() {
+ tint_symbol_5(VertexOut());
+ return;
+}
+
+[[location(1), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_6 : f32;
+
+[[location(2), interpolate(linear, sample), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_7 : f32;
+
+[[location(3), interpolate(perspective, centroid), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_9 : f32;
+
+[[stage(fragment)]]
+fn frag_main() {
+ let tint_symbol_8 : FragmentIn = FragmentIn(tint_symbol_6, tint_symbol_7);
+ let x = ((tint_symbol_8.loc1 + tint_symbol_8.loc2) + tint_symbol_9);
+}
+)";
+
+ auto got = Run<Spirv>(src);
+
+ EXPECT_EQ(expect, str(got));
+}
+
TEST_F(SpirvTest, HandleEntryPointIOTypes_StructLayoutDecorations) {
auto* src = R"(
[[block]]
struct FragmentInput {
[[size(16), location(1)]] value : f32;
[[builtin(position)]] [[align(32)]] coord : vec4<f32>;
+ [[location(0), interpolate(linear, sample)]] [[align(128)]] loc0 : f32;
};
struct FragmentOutput {
- [[size(16), location(1)]] value : f32;
+ [[size(16), location(1), interpolate(flat)]] value : f32;
};
[[stage(fragment)]]
fn frag_main(inputs : FragmentInput) -> FragmentOutput {
- return FragmentOutput(inputs.coord.x * inputs.value);
+ return FragmentOutput(inputs.coord.x * inputs.value + inputs.loc0);
}
)";
@@ -419,6 +498,8 @@
value : f32;
[[align(32)]]
coord : vec4<f32>;
+ [[align(128)]]
+ loc0 : f32;
};
struct FragmentOutput {
@@ -430,16 +511,18 @@
[[builtin(position), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_1 : vec4<f32>;
-[[location(1), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_4 : f32;
+[[location(0), interpolate(linear, sample), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_2 : f32;
-fn tint_symbol_5(tint_symbol_3 : FragmentOutput) {
- tint_symbol_4 = tint_symbol_3.value;
+[[location(1), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_5 : f32;
+
+fn tint_symbol_6(tint_symbol_4 : FragmentOutput) {
+ tint_symbol_5 = tint_symbol_4.value;
}
[[stage(fragment)]]
fn frag_main() {
- let tint_symbol_2 : FragmentInput = FragmentInput(tint_symbol, tint_symbol_1);
- tint_symbol_5(FragmentOutput((tint_symbol_2.coord.x * tint_symbol_2.value)));
+ let tint_symbol_3 : FragmentInput = FragmentInput(tint_symbol, tint_symbol_1, tint_symbol_2);
+ tint_symbol_6(FragmentOutput(((tint_symbol_3.coord.x * tint_symbol_3.value) + tint_symbol_3.loc0)));
return;
}
)";