readers::spirv: Emit entry points
Bug: tint:3 Change-Id: I66b99ad6ecb3f409f9df7bfa9aa6c4da65e3f66b Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/17582 Reviewed-by: dan sinclair <dsinclair@google.com>
This commit is contained in:
parent
14cfcd707d
commit
a14fec951e
|
@ -319,6 +319,7 @@ if(${TINT_BUILD_SPV_READER})
|
||||||
reader/spirv/enum_converter_test.cc
|
reader/spirv/enum_converter_test.cc
|
||||||
reader/spirv/fail_stream_test.cc
|
reader/spirv/fail_stream_test.cc
|
||||||
reader/spirv/namer_test.cc
|
reader/spirv/namer_test.cc
|
||||||
|
reader/spirv/parser_impl_entry_point_test.cc
|
||||||
reader/spirv/parser_impl_import_test.cc
|
reader/spirv/parser_impl_import_test.cc
|
||||||
reader/spirv/parser_impl_user_name_test.cc
|
reader/spirv/parser_impl_user_name_test.cc
|
||||||
reader/spirv/parser_impl_test.cc
|
reader/spirv/parser_impl_test.cc
|
||||||
|
|
|
@ -38,6 +38,7 @@ ParserImpl::ParserImpl(const std::vector<uint32_t>& spv_binary)
|
||||||
spv_binary_(spv_binary),
|
spv_binary_(spv_binary),
|
||||||
fail_stream_(&success_, &errors_),
|
fail_stream_(&success_, &errors_),
|
||||||
namer_(fail_stream_),
|
namer_(fail_stream_),
|
||||||
|
enum_converter_(fail_stream_),
|
||||||
tools_context_(kTargetEnv),
|
tools_context_(kTargetEnv),
|
||||||
tools_(kTargetEnv) {
|
tools_(kTargetEnv) {
|
||||||
// Create a message consumer to propagate error messages from SPIRV-Tools
|
// Create a message consumer to propagate error messages from SPIRV-Tools
|
||||||
|
@ -123,8 +124,20 @@ void ParserImpl::ResetInternalModule() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParserImpl::ParseInternalModule() {
|
bool ParserImpl::ParseInternalModule() {
|
||||||
return RegisterExtendedInstructionImports() && RegisterUserNames();
|
if (!success_) {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
if (!RegisterExtendedInstructionImports()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!RegisterUserNames()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!EmitEntryPoints()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// TODO(dneto): fill in the rest
|
// TODO(dneto): fill in the rest
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParserImpl::RegisterExtendedInstructionImports() {
|
bool ParserImpl::RegisterExtendedInstructionImports() {
|
||||||
|
@ -150,6 +163,16 @@ bool ParserImpl::RegisterExtendedInstructionImports() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParserImpl::RegisterUserNames() {
|
bool ParserImpl::RegisterUserNames() {
|
||||||
|
// Register entry point names. An entry point name is the point of contact
|
||||||
|
// between the API and the shader. It has the highest priority for
|
||||||
|
// preservation, so register it first.
|
||||||
|
for (const spvtools::opt::Instruction& entry_point :
|
||||||
|
module_->entry_points()) {
|
||||||
|
const uint32_t function_id = entry_point.GetSingleWordInOperand(1);
|
||||||
|
const std::string name = entry_point.GetInOperand(2).AsString();
|
||||||
|
namer_.SuggestSanitizedName(function_id, name);
|
||||||
|
}
|
||||||
|
|
||||||
// Register names from OpName and OpMemberName
|
// Register names from OpName and OpMemberName
|
||||||
for (const auto& inst : module_->debugs2()) {
|
for (const auto& inst : module_->debugs2()) {
|
||||||
switch (inst.opcode()) {
|
switch (inst.opcode()) {
|
||||||
|
@ -178,6 +201,20 @@ bool ParserImpl::RegisterUserNames() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ParserImpl::EmitEntryPoints() {
|
||||||
|
for (const spvtools::opt::Instruction& entry_point :
|
||||||
|
module_->entry_points()) {
|
||||||
|
const auto stage = SpvExecutionModel(entry_point.GetSingleWordInOperand(0));
|
||||||
|
const uint32_t function_id = entry_point.GetSingleWordInOperand(1);
|
||||||
|
const std::string name = namer_.GetName(function_id);
|
||||||
|
|
||||||
|
ast_module_.AddEntryPoint(std::make_unique<ast::EntryPoint>(
|
||||||
|
enum_converter_.ToPipelineStage(stage), "", name));
|
||||||
|
}
|
||||||
|
// The enum conversion could have failed, so return the existing status value.
|
||||||
|
return success_;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace spirv
|
} // namespace spirv
|
||||||
} // namespace reader
|
} // namespace reader
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "src/ast/import.h"
|
#include "src/ast/import.h"
|
||||||
#include "src/ast/module.h"
|
#include "src/ast/module.h"
|
||||||
#include "src/reader/reader.h"
|
#include "src/reader/reader.h"
|
||||||
|
#include "src/reader/spirv/enum_converter.h"
|
||||||
#include "src/reader/spirv/fail_stream.h"
|
#include "src/reader/spirv/fail_stream.h"
|
||||||
#include "src/reader/spirv/namer.h"
|
#include "src/reader/spirv/namer.h"
|
||||||
|
|
||||||
|
@ -108,6 +109,9 @@ class ParserImpl : Reader {
|
||||||
/// SPIR-V IDs, and uniqueness of names of fields within any single struct.
|
/// SPIR-V IDs, and uniqueness of names of fields within any single struct.
|
||||||
bool RegisterUserNames();
|
bool RegisterUserNames();
|
||||||
|
|
||||||
|
/// Emit entry point AST nodes.
|
||||||
|
bool EmitEntryPoints();
|
||||||
|
|
||||||
// The SPIR-V binary we're parsing
|
// The SPIR-V binary we're parsing
|
||||||
std::vector<uint32_t> spv_binary_;
|
std::vector<uint32_t> spv_binary_;
|
||||||
|
|
||||||
|
@ -123,6 +127,8 @@ class ParserImpl : Reader {
|
||||||
|
|
||||||
// An object used to store and generate names for SPIR-V objects.
|
// An object used to store and generate names for SPIR-V objects.
|
||||||
Namer namer_;
|
Namer namer_;
|
||||||
|
// An object used to convert SPIR-V enums to Tint enums
|
||||||
|
EnumConverter enum_converter_;
|
||||||
|
|
||||||
// The internal representation of the SPIR-V module and its context.
|
// The internal representation of the SPIR-V module and its context.
|
||||||
spvtools::Context tools_context_;
|
spvtools::Context tools_context_;
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
// Copyright 2020 The Tint Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "src/reader/spirv/parser_impl.h"
|
||||||
|
#include "src/reader/spirv/spirv_tools_helpers_test.h"
|
||||||
|
|
||||||
|
namespace tint {
|
||||||
|
namespace reader {
|
||||||
|
namespace spirv {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ::testing::HasSubstr;
|
||||||
|
|
||||||
|
using SpvParseImport = ::testing::Test;
|
||||||
|
|
||||||
|
std::string MakeEntryPoint(const std::string& stage,
|
||||||
|
const std::string& name,
|
||||||
|
const std::string& id = "42") {
|
||||||
|
return std::string("OpEntryPoint ") + stage + " %" + id + "2 \"" + name +
|
||||||
|
"\"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvParseImport, NoEntryPoint) {
|
||||||
|
ParserImpl p(test::Assemble(""));
|
||||||
|
EXPECT_TRUE(p.BuildAndParseInternalModule());
|
||||||
|
EXPECT_TRUE(p.error().empty());
|
||||||
|
const auto module_ast = p.module().to_str();
|
||||||
|
EXPECT_THAT(module_ast, Not(HasSubstr("EntryPoint")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvParseImport, EntryPointVertex) {
|
||||||
|
ParserImpl p(test::Assemble(MakeEntryPoint("GLCompute", "foobar")));
|
||||||
|
EXPECT_TRUE(p.BuildAndParseInternalModule());
|
||||||
|
EXPECT_TRUE(p.error().empty());
|
||||||
|
const auto module_str = p.module().to_str();
|
||||||
|
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{compute = foobar})"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvParseImport, EntryPointFragment) {
|
||||||
|
ParserImpl p(test::Assemble(MakeEntryPoint("Fragment", "blitz")));
|
||||||
|
EXPECT_TRUE(p.BuildAndParseInternalModule());
|
||||||
|
EXPECT_TRUE(p.error().empty());
|
||||||
|
const auto module_str = p.module().to_str();
|
||||||
|
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{fragment = blitz})"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvParseImport, EntryPointCompute) {
|
||||||
|
ParserImpl p(test::Assemble(MakeEntryPoint("GLCompute", "sort")));
|
||||||
|
EXPECT_TRUE(p.BuildAndParseInternalModule());
|
||||||
|
EXPECT_TRUE(p.error().empty());
|
||||||
|
const auto module_str = p.module().to_str();
|
||||||
|
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{compute = sort})"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvParseImport, EntryPointMultiNameConflict) {
|
||||||
|
ParserImpl p(test::Assemble(MakeEntryPoint("GLCompute", "work", "40") +
|
||||||
|
MakeEntryPoint("Vertex", "work", "50") +
|
||||||
|
MakeEntryPoint("Fragment", "work", "60")));
|
||||||
|
EXPECT_TRUE(p.BuildAndParseInternalModule());
|
||||||
|
EXPECT_TRUE(p.error().empty());
|
||||||
|
const auto module_str = p.module().to_str();
|
||||||
|
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{compute = work})"));
|
||||||
|
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{vertex = work_1})"));
|
||||||
|
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{fragment = work_2})"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvParseImport, EntryPointNameIsSanitized) {
|
||||||
|
ParserImpl p(test::Assemble(MakeEntryPoint("GLCompute", ".1234")));
|
||||||
|
EXPECT_TRUE(p.BuildAndParseInternalModule());
|
||||||
|
EXPECT_TRUE(p.error().empty());
|
||||||
|
const auto module_str = p.module().to_str();
|
||||||
|
EXPECT_THAT(module_str, HasSubstr(R"(EntryPoint{compute = x_1234})"));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace spirv
|
||||||
|
} // namespace reader
|
||||||
|
} // namespace tint
|
Loading…
Reference in New Issue