spirv-reader: pipeline IO: handle position builtin

Bug: tint:508
Change-Id: I9a4dea29bddf0d511fb62f353dda24de72cf85f4
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/54486
Commit-Queue: David Neto <dneto@google.com>
Auto-Submit: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
This commit is contained in:
David Neto 2021-06-15 22:47:17 +00:00 committed by Tint LUCI CQ
parent ebaa4b4f3d
commit 05cc833ae8
3 changed files with 101 additions and 18 deletions

View File

@ -20,6 +20,8 @@
#include "src/ast/assignment_statement.h" #include "src/ast/assignment_statement.h"
#include "src/ast/bitcast_expression.h" #include "src/ast/bitcast_expression.h"
#include "src/ast/break_statement.h" #include "src/ast/break_statement.h"
#include "src/ast/builtin.h"
#include "src/ast/builtin_decoration.h"
#include "src/ast/call_statement.h" #include "src/ast/call_statement.h"
#include "src/ast/continue_statement.h" #include "src/ast/continue_statement.h"
#include "src/ast/discard_statement.h" #include "src/ast/discard_statement.h"
@ -1026,24 +1028,37 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
const auto return_struct_sym = const auto return_struct_sym =
builder_.Symbols().Register(return_struct_name); builder_.Symbols().Register(return_struct_name);
const auto& builtin_position_info = parser_impl_.GetBuiltInPositionInfo();
// Define the structure. // Define the structure.
ast::ExpressionList return_exprs; ast::ExpressionList return_exprs;
std::vector<ast::StructMember*> return_members; std::vector<ast::StructMember*> return_members;
for (uint32_t var_id : ep_info_->outputs) { for (uint32_t var_id : ep_info_->outputs) {
const auto* var = def_use_mgr_->GetDef(var_id); const Type* param_type = nullptr;
TINT_ASSERT(var != nullptr); const Type* store_type = nullptr;
TINT_ASSERT(var->opcode() == SpvOpVariable);
const auto* store_type = GetVariableStoreType(*var);
const auto* forced_store_type = store_type;
ast::DecorationList out_decos; ast::DecorationList out_decos;
if (!parser_impl_.ConvertDecorationsForVariable( if (var_id == builtin_position_info.per_vertex_var_id) {
var_id, &forced_store_type, &out_decos)) { // The SPIR-V gl_PerVertex variable has already been remapped to
// This occurs, and is not an error, for the PointSize builtin. // a gl_Position variable.
if (!success()) { // Substitute the type.
// But exit early if an error was logged. param_type = ty_.Vector(ty_.F32(), 4);
return false; out_decos.emplace_back(
create<ast::BuiltinDecoration>(source, ast::Builtin::kPosition));
} else {
const auto* var = def_use_mgr_->GetDef(var_id);
TINT_ASSERT(var != nullptr);
TINT_ASSERT(var->opcode() == SpvOpVariable);
store_type = GetVariableStoreType(*var);
param_type = store_type;
if (!parser_impl_.ConvertDecorationsForVariable(var_id, &param_type,
&out_decos)) {
// This occurs, and is not an error, for the PointSize builtin.
if (!success()) {
// But exit early if an error was logged.
return false;
}
continue;
} }
continue;
} }
// TODO(dneto): flatten structs and arrays to vectors or scalars. // TODO(dneto): flatten structs and arrays to vectors or scalars.
@ -1057,7 +1072,7 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
// Form the member type. // Form the member type.
// Reuse the var name for the member name. They can't clash. // Reuse the var name for the member name. They can't clash.
ast::StructMember* return_member = create<ast::StructMember>( ast::StructMember* return_member = create<ast::StructMember>(
Source{}, var_sym, forced_store_type->Build(builder_), out_decos); Source{}, var_sym, param_type->Build(builder_), out_decos);
return_members.push_back(return_member); return_members.push_back(return_member);
ast::Expression* return_member_value = ast::Expression* return_member_value =
@ -1070,7 +1085,7 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
if (store_type->As<Array>()->type->IsSignedScalarOrVector()) { if (store_type->As<Array>()->type->IsSignedScalarOrVector()) {
// sample_mask is unsigned in WGSL. Bitcast it. // sample_mask is unsigned in WGSL. Bitcast it.
return_member_value = create<ast::BitcastExpression>( return_member_value = create<ast::BitcastExpression>(
source, forced_store_type->Build(builder_), return_member_value); source, param_type->Build(builder_), return_member_value);
} }
} else { } else {
// No other builtin outputs need signedness conversion. // No other builtin outputs need signedness conversion.

View File

@ -1053,7 +1053,8 @@ const Type* ParserImpl::ConvertType(uint32_t type_id,
if (pointee_type_id == builtin_position_.struct_type_id) { if (pointee_type_id == builtin_position_.struct_type_id) {
builtin_position_.pointer_type_id = type_id; builtin_position_.pointer_type_id = type_id;
builtin_position_.storage_class = storage_class; builtin_position_.storage_class =
hlsl_style_pipeline_io_ ? SpvStorageClassPrivate : storage_class;
return nullptr; return nullptr;
} }
auto* ast_elem_ty = ConvertType(pointee_type_id, PtrAs::Ptr); auto* ast_elem_ty = ConvertType(pointee_type_id, PtrAs::Ptr);
@ -1314,13 +1315,18 @@ bool ParserImpl::EmitModuleScopeVariables() {
// Make sure the variable has a name. // Make sure the variable has a name.
namer_.SuggestSanitizedName(builtin_position_.per_vertex_var_id, namer_.SuggestSanitizedName(builtin_position_.per_vertex_var_id,
"gl_Position"); "gl_Position");
ast::DecorationList decos;
if (!hlsl_style_pipeline_io_) {
// When doing HLSL-style pipeline IO, the decoration goes on the
// parameter, not the variable.
decos.push_back(
create<ast::BuiltinDecoration>(Source{}, ast::Builtin::kPosition));
}
auto* var = MakeVariable( auto* var = MakeVariable(
builtin_position_.per_vertex_var_id, builtin_position_.per_vertex_var_id,
enum_converter_.ToStorageClass(builtin_position_.storage_class), enum_converter_.ToStorageClass(builtin_position_.storage_class),
ConvertType(builtin_position_.position_member_type_id), false, nullptr, ConvertType(builtin_position_.position_member_type_id), false, nullptr,
ast::DecorationList{ std::move(decos));
create<ast::BuiltinDecoration>(Source{}, ast::Builtin::kPosition),
});
builder_.AST().AddGlobalVariable(var); builder_.AST().AddGlobalVariable(var);
} }

View File

@ -4841,6 +4841,68 @@ TEST_F(SpvModuleScopeVarParserTest,
EXPECT_EQ(got, expected) << got; EXPECT_EQ(got, expected) << got;
} }
TEST_F(SpvModuleScopeVarParserTest,
BuiltinPosition_BuiltIn_Position_MapsToVec4) {
// In Vulkan SPIR-V, Position is the first member of gl_PerVertex
const std::string assembly = PerVertexPreamble() + R"(
%main = OpFunction %void None %voidfn
%entry = OpLabel
OpReturn
OpFunctionEnd
)";
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->Parse()) << p->error() << assembly;
EXPECT_TRUE(p->error().empty());
const auto got = p->program().to_str();
const std::string expected = R"(Module{
Struct main_out {
StructMember{[[ BuiltinDecoration{position}
]] gl_Position: __vec_4__f32}
}
Variable{
gl_Position
private
undefined
__vec_4__f32
}
Function main_1 -> __void
()
{
Return{}
}
Function main -> __type_name_main_out
StageDecoration{vertex}
()
{
Call[not set]{
Identifier[not set]{main_1}
(
)
}
Return{
{
TypeConstructor[not set]{
__type_name_main_out
Identifier[not set]{gl_Position}
}
}
}
}
}
)";
EXPECT_EQ(got, expected) << got;
}
// TODO(dneto): pipeline IO: gl_Position, with initializer
// TODO(dneto): pipeline IO: read PointSize
// TODO(dneto): pipeline IO: write PointSize
// TODO(dneto): pipeline IO: flatten structures, and distribute locations // TODO(dneto): pipeline IO: flatten structures, and distribute locations
} // namespace } // namespace