Add support for using Tint Inspector

Adds in a toggle to control using Tint or SPIRV Cross for reflection.
The current implementation only gets name and stage information via Tint,
backfilling the rest from SPIRV Cross.
Future CLs will fill in the rest of the entry point metadata.

Bug: dawn:578
Change-Id: Iee16b9dbb9a17d4aaa68e5e52e4aa91ee0a62624
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/33500
Commit-Queue: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Ryan Harrison 2020-12-01 14:53:07 +00:00 committed by Commit Bot service account
parent a92f0d2b61
commit c3830d436c
4 changed files with 152 additions and 17 deletions

View File

@ -120,7 +120,21 @@ namespace dawn_native {
return tint::transform::InputStepMode::kInstance; return tint::transform::InputStepMode::kInstance;
} }
} }
#endif
SingleShaderStage PipelineStateToShaderStage(tint::ast::PipelineStage stage) {
switch (stage) {
case tint::ast::PipelineStage::kVertex:
return SingleShaderStage::Vertex;
case tint::ast::PipelineStage::kFragment:
return SingleShaderStage::Fragment;
case tint::ast::PipelineStage::kCompute:
return SingleShaderStage::Compute;
default:
UNREACHABLE();
}
}
#endif // DAWN_ENABLE_WGSL
MaybeError ValidateSpirv(const uint32_t* code, uint32_t codeSize) { MaybeError ValidateSpirv(const uint32_t* code, uint32_t codeSize) {
spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1); spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1);
@ -727,6 +741,126 @@ namespace dawn_native {
return {std::move(metadata)}; return {std::move(metadata)};
} }
// Currently only partially populated the reflection data, needs to be
// completed using PopulateMetadataUsingSPIRVCross. In the future, once
// this function is complete, ReflectShaderUsingSPIRVCross and
// PopulateMetadataUsingSPIRVCross will be removed.
ResultOrError<EntryPointMetadataTable> ReflectShaderUsingTint(DeviceBase* device,
std::vector<uint32_t> spirv) {
#ifdef DAWN_ENABLE_WGSL
EntryPointMetadataTable result;
std::ostringstream errorStream;
errorStream << "Tint Reflection failure:" << std::endl;
tint::Context context;
tint::reader::spirv::Parser parser(&context, spirv);
if (!parser.Parse()) {
errorStream << "Parser: " << parser.error() << std::endl;
return DAWN_VALIDATION_ERROR(errorStream.str().c_str());
}
tint::ast::Module module = parser.module();
if (!module.IsValid()) {
errorStream << "Invalid module generated..." << std::endl;
return DAWN_VALIDATION_ERROR(errorStream.str().c_str());
}
tint::TypeDeterminer typeDeterminer(&context, &module);
if (!typeDeterminer.Determine()) {
errorStream << "Type Determination: " << typeDeterminer.error();
return DAWN_VALIDATION_ERROR(errorStream.str().c_str());
}
tint::Validator validator;
if (!validator.Validate(&module)) {
errorStream << "Validation: " << validator.error() << std::endl;
return DAWN_VALIDATION_ERROR(errorStream.str().c_str());
}
tint::inspector::Inspector inspector(&context, module);
auto entryPoints = inspector.GetEntryPoints();
if (inspector.has_error()) {
errorStream << "Inspector: " << inspector.error() << std::endl;
return DAWN_VALIDATION_ERROR(errorStream.str().c_str());
}
for (auto& entryPoint : entryPoints) {
ASSERT(result.count(entryPoint.name) == 0);
auto metadata = std::make_unique<EntryPointMetadata>();
metadata->stage = PipelineStateToShaderStage(entryPoint.stage);
result[entryPoint.name] = std::move(metadata);
}
return std::move(result);
#else
return DAWN_VALIDATION_ERROR("Using Tint is not enabled in this build.");
#endif // DAWN_ENABLE_WGSL
}
// Uses SPIRV-Cross, which is planned for removal, but until
// ReflectShaderUsingTint is completed, will be kept as a
// fallback/source of truth.
ResultOrError<EntryPointMetadataTable> ReflectShaderUsingSPIRVCross(
DeviceBase* device,
std::vector<uint32_t> spirv) {
EntryPointMetadataTable result;
spirv_cross::Compiler compiler(spirv);
for (const spirv_cross::EntryPoint& entryPoint :
compiler.get_entry_points_and_stages()) {
ASSERT(result.count(entryPoint.name) == 0);
SingleShaderStage stage = ExecutionModelToShaderStage(entryPoint.execution_model);
compiler.set_entry_point(entryPoint.name, entryPoint.execution_model);
std::unique_ptr<EntryPointMetadata> metadata;
DAWN_TRY_ASSIGN(metadata,
ExtractSpirvInfo(device, compiler, entryPoint.name, stage));
result[entryPoint.name] = std::move(metadata);
}
return std::move(result);
}
// Temporary utility method that allows for polyfilling like behaviour,
// specifically data missing from the Tint implementation is filled in
// using the SPIRV-Cross implementation. Once the Tint implementation is
// completed, this function will be removed.
MaybeError PopulateMetadataUsingSPIRVCross(DeviceBase* device,
std::vector<uint32_t> spirv,
EntryPointMetadataTable* tintTable) {
EntryPointMetadataTable crossTable;
DAWN_TRY_ASSIGN(crossTable, ReflectShaderUsingSPIRVCross(device, spirv));
if (tintTable->size() != crossTable.size()) {
return DAWN_VALIDATION_ERROR(
"Tint and SPIRV-Cross returned different number of entry points");
}
for (auto& crossMember : crossTable) {
auto& name = crossMember.first;
auto& crossEntry = crossMember.second;
auto tintMember = tintTable->find(name);
if (tintMember == tintTable->end()) {
return DAWN_VALIDATION_ERROR(
"Tint and SPIRV-Cross returned different entry point names");
}
auto& tintEntry = tintMember->second;
if (tintEntry->stage != crossEntry->stage) {
return DAWN_VALIDATION_ERROR(
"Tint and SPIRV-Cross returned different stages for entry point");
}
// TODO(rharrison): Use the Inspector to get this data.
tintEntry->bindings = crossEntry->bindings;
tintEntry->usedVertexAttributes = crossEntry->usedVertexAttributes;
tintEntry->fragmentOutputFormatBaseTypes =
crossEntry->fragmentOutputFormatBaseTypes;
tintEntry->fragmentOutputsWritten = crossEntry->fragmentOutputsWritten;
tintEntry->localWorkgroupSize = crossEntry->localWorkgroupSize;
}
return {};
}
} // anonymous namespace } // anonymous namespace
MaybeError ValidateShaderModuleDescriptor(DeviceBase* device, MaybeError ValidateShaderModuleDescriptor(DeviceBase* device,
@ -894,7 +1028,7 @@ namespace dawn_native {
#ifdef DAWN_ENABLE_WGSL #ifdef DAWN_ENABLE_WGSL
DAWN_TRY_ASSIGN(spirv, ConvertWGSLToSPIRV(mWgsl.c_str())); DAWN_TRY_ASSIGN(spirv, ConvertWGSLToSPIRV(mWgsl.c_str()));
#else #else
return DAWN_VALIDATION_ERROR("WGSL not supported (yet)"); return DAWN_VALIDATION_ERROR("Using Tint is not enabled in this build.");
#endif // DAWN_ENABLE_WGSL #endif // DAWN_ENABLE_WGSL
} else { } else {
spirv = mOriginalSpirv; spirv = mOriginalSpirv;
@ -905,21 +1039,15 @@ namespace dawn_native {
} }
mSpirv = std::move(spirv); mSpirv = std::move(spirv);
if (GetDevice()->IsToggleEnabled(Toggle::UseTintInspector)) {
spirv_cross::Compiler compiler(mSpirv); EntryPointMetadataTable table;
for (const spirv_cross::EntryPoint& entryPoint : compiler.get_entry_points_and_stages()) { DAWN_TRY_ASSIGN(table, ReflectShaderUsingTint(GetDevice(), mSpirv));
ASSERT(mEntryPoints.count(entryPoint.name) == 0); DAWN_TRY(PopulateMetadataUsingSPIRVCross(GetDevice(), mSpirv, &table));
mEntryPoints = std::move(table);
SingleShaderStage stage = ExecutionModelToShaderStage(entryPoint.execution_model); } else {
compiler.set_entry_point(entryPoint.name, entryPoint.execution_model); DAWN_TRY_ASSIGN(mEntryPoints, ReflectShaderUsingSPIRVCross(GetDevice(), mSpirv));
std::unique_ptr<EntryPointMetadata> metadata;
DAWN_TRY_ASSIGN(metadata,
ExtractSpirvInfo(GetDevice(), compiler, entryPoint.name, stage));
mEntryPoints[entryPoint.name] = std::move(metadata);
} }
return {}; return {};
} }
} // namespace dawn_native } // namespace dawn_native

View File

@ -39,6 +39,10 @@ namespace dawn_native {
struct EntryPointMetadata; struct EntryPointMetadata;
// A map from name to EntryPointMetadata.
using EntryPointMetadataTable =
std::unordered_map<std::string, std::unique_ptr<EntryPointMetadata>>;
MaybeError ValidateShaderModuleDescriptor(DeviceBase* device, MaybeError ValidateShaderModuleDescriptor(DeviceBase* device,
const ShaderModuleDescriptor* descriptor); const ShaderModuleDescriptor* descriptor);
MaybeError ValidateCompatibilityWithPipelineLayout(DeviceBase* device, MaybeError ValidateCompatibilityWithPipelineLayout(DeviceBase* device,
@ -130,8 +134,7 @@ namespace dawn_native {
std::vector<uint32_t> mSpirv; std::vector<uint32_t> mSpirv;
std::string mWgsl; std::string mWgsl;
// A map from [name, stage] to EntryPointMetadata. EntryPointMetadataTable mEntryPoints;
std::unordered_map<std::string, std::unique_ptr<EntryPointMetadata>> mEntryPoints;
}; };
} // namespace dawn_native } // namespace dawn_native

View File

@ -144,6 +144,9 @@ namespace dawn_native {
{Toggle::UseTintGenerator, {Toggle::UseTintGenerator,
{"use_tint_generator", "Use Tint instead of SPRIV-cross to generate shaders.", {"use_tint_generator", "Use Tint instead of SPRIV-cross to generate shaders.",
"https://crbug.com/dawn/548"}}, "https://crbug.com/dawn/548"}},
{Toggle::UseTintInspector,
{"use_tint_inspector", "Use Tint instead of SPRIV-cross for shader reflection.",
"https://crbug.com/dawn/578"}},
// Dummy comment to separate the }} so it is clearer what to copy-paste to add a toggle. // Dummy comment to separate the }} so it is clearer what to copy-paste to add a toggle.
}}; }};

View File

@ -45,6 +45,7 @@ namespace dawn_native {
MetalEnableVertexPulling, MetalEnableVertexPulling,
DisallowUnsafeAPIs, DisallowUnsafeAPIs,
UseTintGenerator, UseTintGenerator,
UseTintInspector,
EnumCount, EnumCount,
InvalidEnum = EnumCount, InvalidEnum = EnumCount,