Fill CompilationInfo with Tint diagnostic messages

The previous CL had no way of communicating disagnostic messages from
Tint to the ShaderModule in the event that it failed to validate. This
change ensures that messages generated during validation aren't dropped
on the floor and can be queried from the failed modules CompilationInfo.

BUG: dawn:746
Change-Id: Ic2551654ca30baab0fb5124a148eb4fcdf4b0f22
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/46960
Commit-Queue: Brandon Jones <bajones@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
Brandon Jones 2021-04-08 04:25:11 +00:00 committed by Commit Bot service account
parent c243f67d58
commit 47b6b680e1
7 changed files with 102 additions and 55 deletions

View File

@ -57,7 +57,11 @@ namespace dawn_native {
// Cannot add messages after GetCompilationInfo has been called.
ASSERT(mCompilationInfo.messages == nullptr);
mMessageStrings.push_back(diagnostic.message);
if (diagnostic.code) {
mMessageStrings.push_back(std::string(diagnostic.code) + ": " + diagnostic.message);
} else {
mMessageStrings.push_back(diagnostic.message);
}
mMessages.push_back({nullptr, tintSeverityToMessageType(diagnostic.severity),
diagnostic.source.range.begin.line,
diagnostic.source.range.begin.column});

View File

@ -22,6 +22,7 @@
#include "dawn_native/Buffer.h"
#include "dawn_native/CommandBuffer.h"
#include "dawn_native/CommandEncoder.h"
#include "dawn_native/CompilationMessages.h"
#include "dawn_native/ComputePipeline.h"
#include "dawn_native/CreatePipelineAsyncTracker.h"
#include "dawn_native/DynamicUploader.h"
@ -599,6 +600,8 @@ namespace dawn_native {
ResultOrError<Ref<ShaderModuleBase>> DeviceBase::GetOrCreateShaderModule(
const ShaderModuleDescriptor* descriptor,
ShaderModuleParseResult* parseResult) {
ASSERT(parseResult != nullptr);
ShaderModuleBase blueprint(this, descriptor);
const size_t blueprintHash = blueprint.ComputeContentHash();
@ -609,18 +612,15 @@ namespace dawn_native {
if (iter != mCaches->shaderModules.end()) {
result = *iter;
} else {
if (parseResult == nullptr) {
if (!parseResult->HasParsedShader()) {
// We skip the parse on creation if validation isn't enabled which let's us quickly
// lookup in the cache without validating and parsing. We need the parsed module
// now, so call validate. Most of |ValidateShaderModuleDescriptor| is parsing, but
// we can consider splitting it if additional validation is added.
ASSERT(!IsValidationEnabled());
ShaderModuleParseResult localParseResult =
ValidateShaderModuleDescriptor(this, descriptor).AcquireSuccess();
DAWN_TRY_ASSIGN(result, CreateShaderModuleImpl(descriptor, &localParseResult));
} else {
DAWN_TRY_ASSIGN(result, CreateShaderModuleImpl(descriptor, parseResult));
DAWN_TRY(ValidateShaderModuleDescriptor(this, descriptor, parseResult));
}
DAWN_TRY_ASSIGN(result, CreateShaderModuleImpl(descriptor, parseResult));
result->SetIsCachedReference();
result->SetContentHash(blueprintHash);
mCaches->shaderModules.insert(result.Get());
@ -888,8 +888,9 @@ namespace dawn_native {
}
ShaderModuleBase* DeviceBase::APICreateShaderModule(const ShaderModuleDescriptor* descriptor) {
Ref<ShaderModuleBase> result;
if (ConsumedError(CreateShaderModuleInternal(descriptor), &result)) {
return ShaderModuleBase::MakeError(this);
ShaderModuleParseResult parseResult = {};
if (ConsumedError(CreateShaderModuleInternal(descriptor, &parseResult), &result)) {
return ShaderModuleBase::MakeError(this, std::move(parseResult.compilationMessages));
}
return result.Detach();
}
@ -1242,17 +1243,15 @@ namespace dawn_native {
}
ResultOrError<Ref<ShaderModuleBase>> DeviceBase::CreateShaderModuleInternal(
const ShaderModuleDescriptor* descriptor) {
const ShaderModuleDescriptor* descriptor,
ShaderModuleParseResult* parseResult) {
DAWN_TRY(ValidateIsAlive());
ShaderModuleParseResult parseResult = {};
ShaderModuleParseResult* parseResultPtr = nullptr;
if (IsValidationEnabled()) {
DAWN_TRY_ASSIGN(parseResult, ValidateShaderModuleDescriptor(this, descriptor));
parseResultPtr = &parseResult;
DAWN_TRY(ValidateShaderModuleDescriptor(this, descriptor, parseResult));
}
return GetOrCreateShaderModule(descriptor, parseResultPtr);
return GetOrCreateShaderModule(descriptor, parseResult);
}
ResultOrError<Ref<SwapChainBase>> DeviceBase::CreateSwapChainInternal(

View File

@ -38,6 +38,7 @@ namespace dawn_native {
class DynamicUploader;
class ErrorScopeStack;
class ExternalTextureBase;
class OwnedCompilationMessages;
class PersistentCache;
class StagingBufferBase;
struct InternalPipelineStore;
@ -321,7 +322,8 @@ namespace dawn_native {
const RenderPipelineDescriptor2* descriptor);
ResultOrError<Ref<SamplerBase>> CreateSamplerInternal(const SamplerDescriptor* descriptor);
ResultOrError<Ref<ShaderModuleBase>> CreateShaderModuleInternal(
const ShaderModuleDescriptor* descriptor);
const ShaderModuleDescriptor* descriptor,
ShaderModuleParseResult* parseResult);
ResultOrError<Ref<SwapChainBase>> CreateSwapChainInternal(
Surface* surface,
const SwapChainDescriptor* descriptor);

View File

@ -390,11 +390,15 @@ namespace dawn_native {
return {};
}
ResultOrError<tint::Program> ParseWGSL(const tint::Source::File* file) {
ResultOrError<tint::Program> ParseWGSL(const tint::Source::File* file,
OwnedCompilationMessages* outMessages) {
std::ostringstream errorStream;
errorStream << "Tint WGSL reader failure:" << std::endl;
tint::Program program = tint::reader::wgsl::Parse(file);
if (outMessages != nullptr) {
outMessages->AddMessages(program.Diagnostics());
}
if (!program.IsValid()) {
auto err = program.Diagnostics().str();
errorStream << "Parser: " << err << std::endl
@ -406,11 +410,15 @@ namespace dawn_native {
return std::move(program);
}
ResultOrError<tint::Program> ParseSPIRV(const std::vector<uint32_t>& spirv) {
ResultOrError<tint::Program> ParseSPIRV(const std::vector<uint32_t>& spirv,
OwnedCompilationMessages* outMessages) {
std::ostringstream errorStream;
errorStream << "Tint SPIRV reader failure:" << std::endl;
tint::Program program = tint::reader::spirv::Parse(spirv);
if (outMessages != nullptr) {
outMessages->AddMessages(program.Diagnostics());
}
if (!program.IsValid()) {
auto err = program.Diagnostics().str();
errorStream << "Parser: " << err << std::endl;
@ -420,12 +428,17 @@ namespace dawn_native {
return std::move(program);
}
MaybeError ValidateModule(const tint::Program* program) {
MaybeError ValidateModule(const tint::Program* program,
OwnedCompilationMessages* outMessages) {
std::ostringstream errorStream;
errorStream << "Tint program validation" << std::endl;
tint::Validator validator;
if (!validator.Validate(program)) {
bool isValid = validator.Validate(program);
if (outMessages != nullptr) {
outMessages->AddMessages(validator.diagnostics());
}
if (!isValid) {
auto err = validator.diagnostics().str();
errorStream << "Validation: " << err << std::endl;
return DAWN_VALIDATION_ERROR(errorStream.str().c_str());
@ -1039,7 +1052,9 @@ namespace dawn_native {
}
} // anonymous namespace
ShaderModuleParseResult::ShaderModuleParseResult() = default;
ShaderModuleParseResult::ShaderModuleParseResult()
: compilationMessages(new OwnedCompilationMessages()) {
}
ShaderModuleParseResult::~ShaderModuleParseResult() = default;
ShaderModuleParseResult::ShaderModuleParseResult(ShaderModuleParseResult&& rhs) = default;
@ -1047,9 +1062,15 @@ namespace dawn_native {
ShaderModuleParseResult& ShaderModuleParseResult::operator=(ShaderModuleParseResult&& rhs) =
default;
ResultOrError<ShaderModuleParseResult> ValidateShaderModuleDescriptor(
DeviceBase* device,
const ShaderModuleDescriptor* descriptor) {
bool ShaderModuleParseResult::HasParsedShader() const {
return tintProgram != nullptr || spirv.size() > 0;
}
MaybeError ValidateShaderModuleDescriptor(DeviceBase* device,
const ShaderModuleDescriptor* descriptor,
ShaderModuleParseResult* parseResult) {
ASSERT(parseResult != nullptr);
const ChainedStruct* chainedDescriptor = descriptor->nextInChain;
if (chainedDescriptor == nullptr) {
return DAWN_VALIDATION_ERROR("Shader module descriptor missing chained descriptor");
@ -1060,9 +1081,10 @@ namespace dawn_native {
"Shader module descriptor chained nextInChain must be nullptr");
}
OwnedCompilationMessages* outMessages = parseResult->compilationMessages.get();
ScopedTintICEHandler scopedICEHandler(device);
ShaderModuleParseResult parseResult = {};
switch (chainedDescriptor->sType) {
case wgpu::SType::ShaderModuleSPIRVDescriptor: {
const auto* spirvDesc =
@ -1070,16 +1092,16 @@ namespace dawn_native {
std::vector<uint32_t> spirv(spirvDesc->code, spirvDesc->code + spirvDesc->codeSize);
if (device->IsToggleEnabled(Toggle::UseTintGenerator)) {
tint::Program program;
DAWN_TRY_ASSIGN(program, ParseSPIRV(spirv));
DAWN_TRY_ASSIGN(program, ParseSPIRV(spirv, outMessages));
if (device->IsValidationEnabled()) {
DAWN_TRY(ValidateModule(&program));
DAWN_TRY(ValidateModule(&program, outMessages));
}
parseResult.tintProgram = std::make_unique<tint::Program>(std::move(program));
parseResult->tintProgram = std::make_unique<tint::Program>(std::move(program));
} else {
if (device->IsValidationEnabled()) {
DAWN_TRY(ValidateSpirv(spirv.data(), spirv.size()));
}
parseResult.spirv = std::move(spirv);
parseResult->spirv = std::move(spirv);
}
break;
}
@ -1091,29 +1113,30 @@ namespace dawn_native {
tint::Source::File file("", wgslDesc->source);
tint::Program program;
DAWN_TRY_ASSIGN(program, ParseWGSL(&file));
DAWN_TRY_ASSIGN(program, ParseWGSL(&file, outMessages));
if (device->IsToggleEnabled(Toggle::UseTintGenerator)) {
if (device->IsValidationEnabled()) {
DAWN_TRY(ValidateModule(&program));
DAWN_TRY(ValidateModule(&program, outMessages));
}
parseResult.tintProgram = std::make_unique<tint::Program>(std::move(program));
parseResult->tintProgram = std::make_unique<tint::Program>(std::move(program));
} else {
tint::transform::Manager transformManager;
transformManager.append(
std::make_unique<tint::transform::EmitVertexPointSize>());
transformManager.append(std::make_unique<tint::transform::Spirv>());
DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, &program));
DAWN_TRY_ASSIGN(program,
RunTransforms(&transformManager, &program, outMessages));
if (device->IsValidationEnabled()) {
DAWN_TRY(ValidateModule(&program));
DAWN_TRY(ValidateModule(&program, outMessages));
}
std::vector<uint32_t> spirv;
DAWN_TRY_ASSIGN(spirv, ModuleToSPIRV(&program));
DAWN_TRY(ValidateSpirv(spirv.data(), spirv.size()));
parseResult.spirv = std::move(spirv);
parseResult->spirv = std::move(spirv);
}
break;
}
@ -1121,7 +1144,7 @@ namespace dawn_native {
return DAWN_VALIDATION_ERROR("Unsupported sType");
}
return std::move(parseResult);
return {};
}
RequiredBufferSizes ComputeRequiredBufferSizesForLayout(const EntryPointMetadata& entryPoint,
@ -1136,8 +1159,12 @@ namespace dawn_native {
}
ResultOrError<tint::Program> RunTransforms(tint::transform::Transform* transform,
const tint::Program* program) {
const tint::Program* program,
OwnedCompilationMessages* outMessages) {
tint::transform::Transform::Output output = transform->Run(program);
if (outMessages != nullptr) {
outMessages->AddMessages(output.program.Diagnostics());
}
if (!output.program.IsValid()) {
std::string err = "Tint program failure: " + output.program.Diagnostics().str();
return DAWN_VALIDATION_ERROR(err.c_str());
@ -1196,9 +1223,7 @@ namespace dawn_native {
// ShaderModuleBase
ShaderModuleBase::ShaderModuleBase(DeviceBase* device, const ShaderModuleDescriptor* descriptor)
: CachedObject(device),
mType(Type::Undefined),
mCompilationMessages(std::make_unique<OwnedCompilationMessages>()) {
: CachedObject(device), mType(Type::Undefined) {
ASSERT(descriptor->nextInChain != nullptr);
switch (descriptor->nextInChain->sType) {
case wgpu::SType::ShaderModuleSPIRVDescriptor: {
@ -1220,10 +1245,13 @@ namespace dawn_native {
}
}
ShaderModuleBase::ShaderModuleBase(DeviceBase* device, ObjectBase::ErrorTag tag)
ShaderModuleBase::ShaderModuleBase(
DeviceBase* device,
ObjectBase::ErrorTag tag,
std::unique_ptr<OwnedCompilationMessages> compilationMessages)
: CachedObject(device, tag),
mType(Type::Undefined),
mCompilationMessages(std::make_unique<OwnedCompilationMessages>()) {
mCompilationMessages(std::move(compilationMessages)) {
}
ShaderModuleBase::~ShaderModuleBase() {
@ -1233,8 +1261,10 @@ namespace dawn_native {
}
// static
ShaderModuleBase* ShaderModuleBase::MakeError(DeviceBase* device) {
return new ShaderModuleBase(device, ObjectBase::kError);
ShaderModuleBase* ShaderModuleBase::MakeError(
DeviceBase* device,
std::unique_ptr<OwnedCompilationMessages> compilationMessages) {
return new ShaderModuleBase(device, ObjectBase::kError, std::move(compilationMessages));
}
bool ShaderModuleBase::HasEntryPoint(const std::string& entryPoint) const {
@ -1286,7 +1316,7 @@ namespace dawn_native {
const std::string& entryPoint,
BindGroupIndex pullingBufferBindingSet) const {
tint::Program program;
DAWN_TRY_ASSIGN(program, ParseSPIRV(spirv));
DAWN_TRY_ASSIGN(program, ParseSPIRV(spirv, nullptr));
return GeneratePullingSpirv(&program, vertexState, entryPoint, pullingBufferBindingSet);
}
@ -1308,8 +1338,11 @@ namespace dawn_native {
transformManager.append(std::make_unique<tint::transform::BoundArrayAccessors>());
}
// A nullptr is passed in for the CompilationMessages here since this method is called
// during RenderPipeline creation, by which point the shader module's CompilationInfo may
// have already been queried.
tint::Program program;
DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, programIn));
DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, programIn, nullptr));
tint::writer::spirv::Generator generator(&program);
if (!generator.Generate()) {
@ -1325,6 +1358,7 @@ namespace dawn_native {
MaybeError ShaderModuleBase::InitializeBase(ShaderModuleParseResult* parseResult) {
mTintProgram = std::move(parseResult->tintProgram);
mSpirv = std::move(parseResult->spirv);
mCompilationMessages = std::move(parseResult->compilationMessages);
if (GetDevice()->IsToggleEnabled(Toggle::UseTintGenerator)) {
DAWN_TRY_ASSIGN(mEntryPoints, ReflectShaderUsingTint(GetDevice(), mTintProgram.get()));

View File

@ -19,6 +19,7 @@
#include "common/ityp_array.h"
#include "dawn_native/BindingInfo.h"
#include "dawn_native/CachedObject.h"
#include "dawn_native/CompilationMessages.h"
#include "dawn_native/Error.h"
#include "dawn_native/Format.h"
#include "dawn_native/Forward.h"
@ -48,7 +49,6 @@ namespace spirv_cross {
namespace dawn_native {
class OwnedCompilationMessages;
struct EntryPointMetadata;
// A map from name to EntryPointMetadata.
@ -61,13 +61,16 @@ namespace dawn_native {
ShaderModuleParseResult(ShaderModuleParseResult&& rhs);
ShaderModuleParseResult& operator=(ShaderModuleParseResult&& rhs);
bool HasParsedShader() const;
std::unique_ptr<tint::Program> tintProgram;
std::vector<uint32_t> spirv;
std::unique_ptr<OwnedCompilationMessages> compilationMessages;
};
ResultOrError<ShaderModuleParseResult> ValidateShaderModuleDescriptor(
DeviceBase* device,
const ShaderModuleDescriptor* descriptor);
MaybeError ValidateShaderModuleDescriptor(DeviceBase* device,
const ShaderModuleDescriptor* descriptor,
ShaderModuleParseResult* parseResult);
MaybeError ValidateCompatibilityWithPipelineLayout(DeviceBase* device,
const EntryPointMetadata& entryPoint,
const PipelineLayoutBase* layout);
@ -75,7 +78,8 @@ namespace dawn_native {
RequiredBufferSizes ComputeRequiredBufferSizesForLayout(const EntryPointMetadata& entryPoint,
const PipelineLayoutBase* layout);
ResultOrError<tint::Program> RunTransforms(tint::transform::Transform* transform,
const tint::Program* program);
const tint::Program* program,
OwnedCompilationMessages* messages);
std::unique_ptr<tint::transform::VertexPulling> MakeVertexPullingTransform(
const VertexState& vertexState,
@ -125,7 +129,9 @@ namespace dawn_native {
ShaderModuleBase(DeviceBase* device, const ShaderModuleDescriptor* descriptor);
~ShaderModuleBase() override;
static ShaderModuleBase* MakeError(DeviceBase* device);
static ShaderModuleBase* MakeError(
DeviceBase* device,
std::unique_ptr<OwnedCompilationMessages> compilationMessages);
// Return true iff the program has an entrypoint called `entryPoint`.
bool HasEntryPoint(const std::string& entryPoint) const;
@ -169,7 +175,9 @@ namespace dawn_native {
const std::vector<uint32_t>& spirv);
private:
ShaderModuleBase(DeviceBase* device, ObjectBase::ErrorTag tag);
ShaderModuleBase(DeviceBase* device,
ObjectBase::ErrorTag tag,
std::unique_ptr<OwnedCompilationMessages> compilationMessages);
// The original data in the descriptor for caching.
enum class Type { Undefined, Spirv, Wgsl };

View File

@ -59,7 +59,8 @@ namespace dawn_native { namespace vulkan {
tint::Program program;
DAWN_TRY_ASSIGN(program,
RunTransforms(&transformManager, parseResult->tintProgram.get()));
RunTransforms(&transformManager, parseResult->tintProgram.get(),
CompilationMessages()));
tint::writer::spirv::Generator generator(&program);
if (!generator.Generate()) {

View File

@ -14,7 +14,6 @@
#include "common/Constants.h"
#include "dawn_native/CompilationMessages.h"
#include "dawn_native/ShaderModule.h"
#include "tests/unittests/validation/ValidationTest.h"