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>
This commit is contained in:
James Price 2021-06-28 23:04:43 +00:00
parent 545f4e0f77
commit 6a25bf944e
4 changed files with 192 additions and 22 deletions

View File

@ -84,7 +84,8 @@ void CanonicalizeEntryPointIO::Run(CloneContext& ctx,
ast::DecorationList new_decorations = RemoveDecorations( ast::DecorationList new_decorations = RemoveDecorations(
&ctx, member->decorations(), [](const ast::Decoration* deco) { &ctx, member->decorations(), [](const ast::Decoration* deco) {
return deco return deco
->IsAnyOf<ast::BuiltinDecoration, ast::LocationDecoration>(); ->IsAnyOf<ast::BuiltinDecoration, ast::InterpolateDecoration,
ast::LocationDecoration>();
}); });
new_struct_members.push_back( new_struct_members.push_back(
ctx.dst->Member(ctx.Clone(member->symbol()), ctx.dst->Member(ctx.Clone(member->symbol()),
@ -155,6 +156,7 @@ void CanonicalizeEntryPointIO::Run(CloneContext& ctx,
&ctx, member->Declaration()->decorations(), &ctx, member->Declaration()->decorations(),
[](const ast::Decoration* deco) { [](const ast::Decoration* deco) {
return !deco->IsAnyOf<ast::BuiltinDecoration, return !deco->IsAnyOf<ast::BuiltinDecoration,
ast::InterpolateDecoration,
ast::LocationDecoration>(); ast::LocationDecoration>();
}); });
@ -182,14 +184,9 @@ void CanonicalizeEntryPointIO::Run(CloneContext& ctx,
func_const_initializer = func_const_initializer =
ctx.dst->Construct(ctx.Clone(param_declared_ty), init_values); ctx.dst->Construct(ctx.Clone(param_declared_ty), init_values);
} else { } else {
ast::DecorationList new_decorations = RemoveDecorations( new_struct_members.push_back(
&ctx, param->Declaration()->decorations(), ctx.dst->Member(param_name, ctx.Clone(param_declared_ty),
[](const ast::Decoration* deco) { ctx.Clone(param->Declaration()->decorations())));
return !deco->IsAnyOf<ast::BuiltinDecoration,
ast::LocationDecoration>();
});
new_struct_members.push_back(ctx.dst->Member(
param_name, ctx.Clone(param_declared_ty), new_decorations));
func_const_initializer = func_const_initializer =
ctx.dst->MemberAccessor(new_struct_param_symbol, param_name); ctx.dst->MemberAccessor(new_struct_param_symbol, param_name);
} }
@ -249,6 +246,7 @@ void CanonicalizeEntryPointIO::Run(CloneContext& ctx,
&ctx, member->Declaration()->decorations(), &ctx, member->Declaration()->decorations(),
[](const ast::Decoration* deco) { [](const ast::Decoration* deco) {
return !deco->IsAnyOf<ast::BuiltinDecoration, return !deco->IsAnyOf<ast::BuiltinDecoration,
ast::InterpolateDecoration,
ast::LocationDecoration>(); ast::LocationDecoration>();
}); });
auto symbol = ctx.Clone(member->Declaration()->symbol()); auto symbol = ctx.Clone(member->Declaration()->symbol());

View File

@ -608,21 +608,103 @@ fn frag_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
EXPECT_EQ(expect, str(got)); 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) { TEST_F(CanonicalizeEntryPointIOTest, Struct_LayoutDecorations) {
auto* src = R"( auto* src = R"(
[[block]] [[block]]
struct FragmentInput { struct FragmentInput {
[[size(16), location(1)]] value : f32; [[size(16), location(1)]] value : f32;
[[builtin(position)]] [[align(32)]] coord : vec4<f32>; [[builtin(position)]] [[align(32)]] coord : vec4<f32>;
[[location(0), interpolate(linear, sample)]] [[align(128)]] loc0 : f32;
}; };
struct FragmentOutput { struct FragmentOutput {
[[size(16), location(1)]] value : f32; [[size(16), location(1), interpolate(flat)]] value : f32;
}; };
[[stage(fragment)]] [[stage(fragment)]]
fn frag_main(inputs : FragmentInput) -> FragmentOutput { 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 @@ struct FragmentInput {
value : f32; value : f32;
[[align(32)]] [[align(32)]]
coord : vec4<f32>; coord : vec4<f32>;
[[align(128)]]
loc0 : f32;
}; };
struct FragmentOutput { struct FragmentOutput {
@ -641,6 +725,8 @@ struct FragmentOutput {
}; };
struct tint_symbol_1 { struct tint_symbol_1 {
[[location(0), interpolate(linear, sample)]]
loc0 : f32;
[[location(1)]] [[location(1)]]
value : f32; value : f32;
[[builtin(position)]] [[builtin(position)]]
@ -648,14 +734,14 @@ struct tint_symbol_1 {
}; };
struct tint_symbol_2 { struct tint_symbol_2 {
[[location(1)]] [[location(1), interpolate(flat)]]
value : f32; value : f32;
}; };
[[stage(fragment)]] [[stage(fragment)]]
fn frag_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 { fn frag_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
let inputs : FragmentInput = FragmentInput(tint_symbol.value, tint_symbol.coord); let inputs : FragmentInput = FragmentInput(tint_symbol.value, tint_symbol.coord, tint_symbol.loc0);
let tint_symbol_3 : FragmentOutput = FragmentOutput((inputs.coord.x * inputs.value)); let tint_symbol_3 : FragmentOutput = FragmentOutput(((inputs.coord.x * inputs.value) + inputs.loc0));
return tint_symbol_2(tint_symbol_3.value); return tint_symbol_2(tint_symbol_3.value);
} }
)"; )";

View File

@ -144,7 +144,8 @@ void Spirv::HandleEntryPointIOTypes(CloneContext& ctx) const {
ast::DecorationList new_decorations = RemoveDecorations( ast::DecorationList new_decorations = RemoveDecorations(
&ctx, member->decorations(), [](const ast::Decoration* deco) { &ctx, member->decorations(), [](const ast::Decoration* deco) {
return deco return deco
->IsAnyOf<ast::BuiltinDecoration, ast::LocationDecoration>(); ->IsAnyOf<ast::BuiltinDecoration, ast::InterpolateDecoration,
ast::LocationDecoration>();
}); });
new_struct_members.push_back( new_struct_members.push_back(
ctx.dst->Member(ctx.Clone(member->symbol()), ctx.dst->Member(ctx.Clone(member->symbol()),
@ -313,6 +314,7 @@ Symbol Spirv::HoistToInputVariables(
ast::DecorationList new_decorations = ast::DecorationList new_decorations =
RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) { RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) {
return !deco->IsAnyOf<ast::BuiltinDecoration, return !deco->IsAnyOf<ast::BuiltinDecoration,
ast::InterpolateDecoration,
ast::LocationDecoration>(); ast::LocationDecoration>();
}); });
new_decorations.push_back( new_decorations.push_back(
@ -370,6 +372,7 @@ void Spirv::HoistToOutputVariables(CloneContext& ctx,
ast::DecorationList new_decorations = ast::DecorationList new_decorations =
RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) { RemoveDecorations(&ctx, decorations, [](const ast::Decoration* deco) {
return !deco->IsAnyOf<ast::BuiltinDecoration, return !deco->IsAnyOf<ast::BuiltinDecoration,
ast::InterpolateDecoration,
ast::LocationDecoration>(); ast::LocationDecoration>();
}); });
new_decorations.push_back( new_decorations.push_back(

View File

@ -394,21 +394,100 @@ fn frag_main() {
EXPECT_EQ(expect, str(got)); 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) { TEST_F(SpirvTest, HandleEntryPointIOTypes_StructLayoutDecorations) {
auto* src = R"( auto* src = R"(
[[block]] [[block]]
struct FragmentInput { struct FragmentInput {
[[size(16), location(1)]] value : f32; [[size(16), location(1)]] value : f32;
[[builtin(position)]] [[align(32)]] coord : vec4<f32>; [[builtin(position)]] [[align(32)]] coord : vec4<f32>;
[[location(0), interpolate(linear, sample)]] [[align(128)]] loc0 : f32;
}; };
struct FragmentOutput { struct FragmentOutput {
[[size(16), location(1)]] value : f32; [[size(16), location(1), interpolate(flat)]] value : f32;
}; };
[[stage(fragment)]] [[stage(fragment)]]
fn frag_main(inputs : FragmentInput) -> FragmentOutput { 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 @@ struct FragmentInput {
value : f32; value : f32;
[[align(32)]] [[align(32)]]
coord : vec4<f32>; coord : vec4<f32>;
[[align(128)]]
loc0 : f32;
}; };
struct FragmentOutput { struct FragmentOutput {
@ -430,16 +511,18 @@ struct FragmentOutput {
[[builtin(position), internal(disable_validation__ignore_storage_class)]] var<in> tint_symbol_1 : vec4<f32>; [[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) { [[location(1), interpolate(flat), internal(disable_validation__ignore_storage_class)]] var<out> tint_symbol_5 : f32;
tint_symbol_4 = tint_symbol_3.value;
fn tint_symbol_6(tint_symbol_4 : FragmentOutput) {
tint_symbol_5 = tint_symbol_4.value;
} }
[[stage(fragment)]] [[stage(fragment)]]
fn frag_main() { fn frag_main() {
let tint_symbol_2 : FragmentInput = FragmentInput(tint_symbol, tint_symbol_1); let tint_symbol_3 : FragmentInput = FragmentInput(tint_symbol, tint_symbol_1, tint_symbol_2);
tint_symbol_5(FragmentOutput((tint_symbol_2.coord.x * tint_symbol_2.value))); tint_symbol_6(FragmentOutput(((tint_symbol_3.coord.x * tint_symbol_3.value) + tint_symbol_3.loc0)));
return; return;
} }
)"; )";