Output more details when pipeline layout mismatches shader declaration

This patch makes Dawn provide more detailed error messages when the
pipeline layout is not compatible with shader module, which is helpful
to debug such errors in WebGPU applications.

BUG=dawn:456

Change-Id: Ib5a870d8e66645481434c4d3dc6fdc1a585aac36
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/22881
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
Jiawei Shao 2020-06-09 17:06:04 +00:00 committed by Commit Bot service account
parent 182af0a4c2
commit b6c8855e3a
4 changed files with 51 additions and 21 deletions

View File

@ -33,8 +33,8 @@ namespace dawn_native {
if (descriptor->module->GetExecutionModel() != stage) {
return DAWN_VALIDATION_ERROR("Setting module with wrong stages");
}
if (layout != nullptr && !descriptor->module->IsCompatibleWithPipelineLayout(layout)) {
return DAWN_VALIDATION_ERROR("Stage not compatible with layout");
if (layout != nullptr) {
DAWN_TRY(descriptor->module->ValidateCompatibilityWithPipelineLayout(layout));
}
return {};
}

View File

@ -221,7 +221,9 @@ namespace dawn_native {
}
for (uint32_t moduleIndex = 0; moduleIndex < count; ++moduleIndex) {
ASSERT(modules[moduleIndex]->IsCompatibleWithPipelineLayout(pipelineLayout));
ASSERT(modules[moduleIndex]
->ValidateCompatibilityWithPipelineLayout(pipelineLayout)
.IsSuccess());
}
return pipelineLayout;

View File

@ -292,6 +292,12 @@ namespace dawn_native {
return wgpu::TextureFormat::Undefined;
}
}
std::string GetShaderDeclarationString(size_t group, uint32_t binding) {
std::ostringstream ostream;
ostream << "the shader module declaration at set " << group << " binding " << binding;
return ostream.str();
}
} // anonymous namespace
MaybeError ValidateSpirv(DeviceBase*, const uint32_t* code, uint32_t codeSize) {
@ -864,25 +870,28 @@ namespace dawn_native {
return mExecutionModel;
}
bool ShaderModuleBase::IsCompatibleWithPipelineLayout(const PipelineLayoutBase* layout) const {
MaybeError ShaderModuleBase::ValidateCompatibilityWithPipelineLayout(
const PipelineLayoutBase* layout) const {
ASSERT(!IsError());
for (uint32_t group : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
if (!IsCompatibleWithBindGroupLayout(group, layout->GetBindGroupLayout(group))) {
return false;
}
DAWN_TRY(
ValidateCompatibilityWithBindGroupLayout(group, layout->GetBindGroupLayout(group)));
}
for (uint32_t group : IterateBitSet(~layout->GetBindGroupLayoutsMask())) {
if (mBindingInfo[group].size() > 0) {
return false;
std::ostringstream ostream;
ostream << "No bind group layout entry matches the declaration set " << group
<< " in the shader module";
return DAWN_VALIDATION_ERROR(ostream.str());
}
}
return true;
return {};
}
bool ShaderModuleBase::IsCompatibleWithBindGroupLayout(
MaybeError ShaderModuleBase::ValidateCompatibilityWithBindGroupLayout(
size_t group,
const BindGroupLayoutBase* layout) const {
ASSERT(!IsError());
@ -897,7 +906,8 @@ namespace dawn_native {
const auto& bindingIt = bindingMap.find(bindingNumber);
if (bindingIt == bindingMap.end()) {
return false;
return DAWN_VALIDATION_ERROR("Missing bind group layout entry for " +
GetShaderDeclarationString(group, bindingNumber));
}
BindingIndex bindingIndex(bindingIt->second);
@ -922,22 +932,32 @@ namespace dawn_native {
moduleInfo.type == wgpu::BindingType::Sampler);
if (!validBindingConversion) {
return false;
return DAWN_VALIDATION_ERROR(
"The binding type of the bind group layout entry conflicts " +
GetShaderDeclarationString(group, bindingNumber));
}
}
if ((bindingInfo.visibility & StageBit(mExecutionModel)) == 0) {
return false;
return DAWN_VALIDATION_ERROR("The bind group layout entry for " +
GetShaderDeclarationString(group, bindingNumber) +
" is not visible for the shader stage");
}
switch (bindingInfo.type) {
case wgpu::BindingType::SampledTexture: {
if (bindingInfo.textureComponentType != moduleInfo.textureComponentType) {
return false;
return DAWN_VALIDATION_ERROR(
"The textureComponentType of the bind group layout entry is different "
"from " +
GetShaderDeclarationString(group, bindingNumber));
}
if (bindingInfo.viewDimension != moduleInfo.viewDimension) {
return false;
return DAWN_VALIDATION_ERROR(
"The viewDimension of the bind group layout entry is different "
"from " +
GetShaderDeclarationString(group, bindingNumber));
}
break;
}
@ -947,10 +967,16 @@ namespace dawn_native {
ASSERT(bindingInfo.storageTextureFormat != wgpu::TextureFormat::Undefined);
ASSERT(moduleInfo.storageTextureFormat != wgpu::TextureFormat::Undefined);
if (bindingInfo.storageTextureFormat != moduleInfo.storageTextureFormat) {
return false;
return DAWN_VALIDATION_ERROR(
"The storageTextureFormat of the bind group layout entry is different "
"from " +
GetShaderDeclarationString(group, bindingNumber));
}
if (bindingInfo.viewDimension != moduleInfo.viewDimension) {
return false;
return DAWN_VALIDATION_ERROR(
"The viewDimension of the bind group layout entry is different "
"from " +
GetShaderDeclarationString(group, bindingNumber));
}
break;
}
@ -965,11 +991,11 @@ namespace dawn_native {
case wgpu::BindingType::StorageTexture:
default:
UNREACHABLE();
return false;
return DAWN_VALIDATION_ERROR("Unsupported binding type");
}
}
return true;
return {};
}
size_t ShaderModuleBase::HashFunc::operator()(const ShaderModuleBase* module) const {

View File

@ -75,7 +75,7 @@ namespace dawn_native {
using FragmentOutputBaseTypes = std::array<Format::Type, kMaxColorAttachments>;
const FragmentOutputBaseTypes& GetFragmentOutputBaseTypes() const;
bool IsCompatibleWithPipelineLayout(const PipelineLayoutBase* layout) const;
MaybeError ValidateCompatibilityWithPipelineLayout(const PipelineLayoutBase* layout) const;
// Functors necessary for the unordered_set<ShaderModuleBase*>-based cache.
struct HashFunc {
@ -98,7 +98,9 @@ namespace dawn_native {
private:
ShaderModuleBase(DeviceBase* device, ObjectBase::ErrorTag tag);
bool IsCompatibleWithBindGroupLayout(size_t group, const BindGroupLayoutBase* layout) const;
MaybeError ValidateCompatibilityWithBindGroupLayout(
size_t group,
const BindGroupLayoutBase* layout) const;
// Different implementations reflection into the shader depending on
// whether using spvc, or directly accessing spirv-cross.