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:
parent
ebaa4b4f3d
commit
05cc833ae8
|
@ -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,18 +1028,30 @@ 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 Type* param_type = nullptr;
|
||||||
|
const Type* store_type = nullptr;
|
||||||
|
ast::DecorationList out_decos;
|
||||||
|
if (var_id == builtin_position_info.per_vertex_var_id) {
|
||||||
|
// The SPIR-V gl_PerVertex variable has already been remapped to
|
||||||
|
// a gl_Position variable.
|
||||||
|
// Substitute the type.
|
||||||
|
param_type = ty_.Vector(ty_.F32(), 4);
|
||||||
|
out_decos.emplace_back(
|
||||||
|
create<ast::BuiltinDecoration>(source, ast::Builtin::kPosition));
|
||||||
|
} else {
|
||||||
const auto* var = def_use_mgr_->GetDef(var_id);
|
const auto* var = def_use_mgr_->GetDef(var_id);
|
||||||
TINT_ASSERT(var != nullptr);
|
TINT_ASSERT(var != nullptr);
|
||||||
TINT_ASSERT(var->opcode() == SpvOpVariable);
|
TINT_ASSERT(var->opcode() == SpvOpVariable);
|
||||||
const auto* store_type = GetVariableStoreType(*var);
|
store_type = GetVariableStoreType(*var);
|
||||||
const auto* forced_store_type = store_type;
|
param_type = store_type;
|
||||||
ast::DecorationList out_decos;
|
if (!parser_impl_.ConvertDecorationsForVariable(var_id, ¶m_type,
|
||||||
if (!parser_impl_.ConvertDecorationsForVariable(
|
&out_decos)) {
|
||||||
var_id, &forced_store_type, &out_decos)) {
|
|
||||||
// This occurs, and is not an error, for the PointSize builtin.
|
// This occurs, and is not an error, for the PointSize builtin.
|
||||||
if (!success()) {
|
if (!success()) {
|
||||||
// But exit early if an error was logged.
|
// But exit early if an error was logged.
|
||||||
|
@ -1045,6 +1059,7 @@ bool FunctionEmitter::EmitEntryPointAsWrapper() {
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(dneto): flatten structs and arrays to vectors or scalars.
|
// TODO(dneto): flatten structs and arrays to vectors or scalars.
|
||||||
// The Per-vertex structure is already flattened.
|
// The Per-vertex structure is already flattened.
|
||||||
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue