spirv-reader: builtin in/out keep their signedness as private vars

Update the plan for pipeline I/O.

Bug: tint:508
Change-Id: I263d954403134a78106b3372ec9df3d9d868ef1d
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/54462
Auto-Submit: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: James Price <jrprice@google.com>
This commit is contained in:
David Neto 2021-06-11 20:45:06 +00:00 committed by Tint LUCI CQ
parent 27067f5c1e
commit ba403cdf8f
3 changed files with 167 additions and 4 deletions

View File

@ -36,19 +36,22 @@ inputs and outputs, and two functions:
is the same as the original SPIR-V entry point. is the same as the original SPIR-V entry point.
- Original input variables are mapped to pseudo-in Private variables - Original input variables are mapped to pseudo-in Private variables
with the same store types, but no other attributes or properties copied. with the same store types, but no other attributes or properties copied.
In Vulkan, Input variables don't have initalizers.
- Original output variables are mapped to pseudo-out Private variables - Original output variables are mapped to pseudo-out Private variables
with the same store types, but no other attributes or properties are copied. with the same store types and optional initializer, but no other attributes
or properties are copied.
- A wrapper entry point function whose arguments correspond in type, location - A wrapper entry point function whose arguments correspond in type, location
and builtin attributes the original input variables, and whose return type is and builtin attributes the original input variables, and whose return type is
a structure containing members correspond in type, location, and builtin a structure containing members correspond in type, location, and builtin
attributes to the original output variables. attributes to the original output variables.
The body of the wrapper function the following phases: The body of the wrapper function the following phases:
- Copy formal parameter values into pseudo-in variables. - Copy formal parameter values into pseudo-in variables.
- Use stores to initialize pseudo-out variables: - Insert a bitcast if the WGSL builtin variable has different signedness
- If the original variable had an initializer, store that value. from the SPIR-V declared type.
- Otherwise, store a zero value for the store type.
- Execute the inner function. - Execute the inner function.
- Copy pseudo-out variables into the return structure. - Copy pseudo-out variables into the return structure.
- Insert a bitcast if the WGSL builtin variable has different signedness
from the SPIR-V declared type.
- Return the return structure. - Return the return structure.
- Replace uses of the the original input/output variables to the pseudo-in and - Replace uses of the the original input/output variables to the pseudo-in and

View File

@ -957,6 +957,8 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
continue; continue;
} }
// In Vulkan SPIR-V, Input variables must not have an initializer.
const auto var_name = namer_.GetName(var_id); const auto var_name = namer_.GetName(var_id);
const auto var_sym = builder_.Symbols().Register(var_name); const auto var_sym = builder_.Symbols().Register(var_name);
const auto param_name = namer_.MakeDerivedName(var_name + "_param"); const auto param_name = namer_.MakeDerivedName(var_name + "_param");

View File

@ -80,6 +80,7 @@ std::string CommonTypes() {
%float_1p5 = OpConstant %float 1.5 %float_1p5 = OpConstant %float 1.5
%uint_1 = OpConstant %uint 1 %uint_1 = OpConstant %uint 1
%int_m1 = OpConstant %int -1 %int_m1 = OpConstant %int -1
%int_14 = OpConstant %int 14
%uint_2 = OpConstant %uint 2 %uint_2 = OpConstant %uint 2
%v2bool = OpTypeVector %bool 2 %v2bool = OpTypeVector %bool 2
@ -4018,6 +4019,157 @@ TEST_F(SpvModuleScopeVarParserTest, OutputVarsConvertedToPrivate) {
EXPECT_THAT(got, HasSubstr(expected)) << got; EXPECT_THAT(got, HasSubstr(expected)) << got;
} }
TEST_F(SpvModuleScopeVarParserTest,
OutputVarsConvertedToPrivate_WithInitializer) {
const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
%ptr_out_uint = OpTypePointer Output %uint
%1 = OpVariable %ptr_out_uint Output %uint_1
)" + MainBody();
auto p = parser(test::Assemble(assembly));
// TODO(crbug.com/tint/508): Remove this when everything is converted
// to HLSL style pipeline IO.
p->SetHLSLStylePipelineIO();
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
EXPECT_TRUE(p->error().empty());
const auto got = p->program().to_str();
const std::string expected =
R"(Variable{
x_1
private
undefined
__u32
{
ScalarConstructor[not set]{1u}
}
}
)";
EXPECT_THAT(got, HasSubstr(expected)) << got;
}
TEST_F(SpvModuleScopeVarParserTest,
Builtin_Output_Initializer_SameSignednessAsWGSL) {
// Only outputs can have initializers.
// WGSL sample_mask store type is u32.
const auto assembly = Preamble() + FragMain() + R"(
OpDecorate %1 BuiltIn SampleMask
)" + CommonTypes() + R"(
%ptr_ty = OpTypePointer Output %uint
%1 = OpVariable %ptr_ty Output %uint_1
)" + MainBody();
auto p = parser(test::Assemble(assembly));
// TODO(crbug.com/tint/508): Remove this when everything is converted
// to HLSL style pipeline IO.
p->SetHLSLStylePipelineIO();
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
EXPECT_TRUE(p->error().empty());
const auto got = p->program().to_str();
const std::string expected =
R"(Variable{
x_1
private
undefined
__u32
{
ScalarConstructor[not set]{1u}
}
}
)";
EXPECT_THAT(got, HasSubstr(expected)) << got;
}
TEST_F(SpvModuleScopeVarParserTest,
Builtin_Output_Initializer_OppositeSignednessAsWGSL) {
// Only outputs can have initializers.
// WGSL sample_mask store type is u32. Use i32 in SPIR-V
const auto assembly = Preamble() + FragMain() + R"(
OpDecorate %1 BuiltIn SampleMask
)" + CommonTypes() + R"(
%ptr_ty = OpTypePointer Output %int
%1 = OpVariable %ptr_ty Output %int_14
)" + MainBody();
auto p = parser(test::Assemble(assembly));
// TODO(crbug.com/tint/508): Remove this when everything is converted
// to HLSL style pipeline IO.
p->SetHLSLStylePipelineIO();
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
EXPECT_TRUE(p->error().empty());
const auto got = p->program().to_str();
const std::string expected =
R"(Variable{
x_1
private
undefined
__i32
{
ScalarConstructor[not set]{14}
}
}
)";
EXPECT_THAT(got, HasSubstr(expected)) << got;
}
TEST_F(SpvModuleScopeVarParserTest, Builtin_Input_SameSignednessAsWGSL) {
// WGSL vertex_index store type is u32.
const auto assembly = Preamble() + FragMain() + R"(
OpDecorate %1 BuiltIn VertexIndex
)" + CommonTypes() + R"(
%ptr_ty = OpTypePointer Input %uint
%1 = OpVariable %ptr_ty Input
)" + MainBody();
auto p = parser(test::Assemble(assembly));
// TODO(crbug.com/tint/508): Remove this when everything is converted
// to HLSL style pipeline IO.
p->SetHLSLStylePipelineIO();
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
EXPECT_TRUE(p->error().empty());
const auto got = p->program().to_str();
const std::string expected =
R"(Variable{
x_1
private
undefined
__u32
}
)";
EXPECT_THAT(got, HasSubstr(expected)) << got;
}
TEST_F(SpvModuleScopeVarParserTest, Builtin_Input_OppositeSignednessAsWGSL) {
// WGSL vertex_index store type is u32. Use i32 in SPIR-V.
const auto assembly = Preamble() + FragMain() + R"(
OpDecorate %1 BuiltIn VertexIndex
)" + CommonTypes() + R"(
%ptr_ty = OpTypePointer Input %int
%1 = OpVariable %ptr_ty Input
)" + MainBody();
auto p = parser(test::Assemble(assembly));
// TODO(crbug.com/tint/508): Remove this when everything is converted
// to HLSL style pipeline IO.
p->SetHLSLStylePipelineIO();
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
EXPECT_TRUE(p->error().empty());
const auto got = p->program().to_str();
const std::string expected =
R"(Variable{
x_1
private
undefined
__i32
}
)";
EXPECT_THAT(got, HasSubstr(expected)) << got;
}
TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_IOLocations) { TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_IOLocations) {
const auto assembly = CommonCapabilities() + R"( const auto assembly = CommonCapabilities() + R"(
OpEntryPoint Vertex %main "main" %1 %2 %3 %4 OpEntryPoint Vertex %main "main" %1 %2 %3 %4
@ -4136,6 +4288,12 @@ TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_IOLocations) {
EXPECT_THAT(got, HasSubstr(expected)) << got; EXPECT_THAT(got, HasSubstr(expected)) << got;
} }
// TODO(dneto): pipeline IO: convert signedness on builtin inputs in the wrapper
// body
// TODO(dneto): pipeline IO: convert signedness on builtin outputs in the
// wrapper body
// TODO(dneto): pipeline IO: flatten structures, and distribute locations
// TODO(dneto): Test passing pointer to SampleMask as function parameter, // TODO(dneto): Test passing pointer to SampleMask as function parameter,
// both input case and output case. // both input case and output case.