Improve validation messages for surface/swap chain

Updates validation messages with more contextual information in:
 - ChainUtils.h
 - Device.cpp
 - SpirvValidation.cpp
 - Surface.cpp
 - SwapChain.cpp

Bug: dawn:563
Change-Id: I486512791caaf1acf4607539aa5ad11daf1ab9be
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/67140
Commit-Queue: Brandon Jones <bajones@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Brandon Jones 2021-10-21 19:25:04 +00:00 committed by Dawn LUCI CQ
parent 853c61d0a6
commit 7dc906a4c9
5 changed files with 73 additions and 86 deletions

View File

@ -36,9 +36,8 @@ namespace dawn_native {
template <typename T> template <typename T>
MaybeError ValidateSingleSTypeInner(const ChainedStruct* chain, T sType) { MaybeError ValidateSingleSTypeInner(const ChainedStruct* chain, T sType) {
if (chain->sType != sType) { DAWN_INVALID_IF(chain->sType != sType,
return DAWN_VALIDATION_ERROR("Unsupported sType"); "Unsupported sType (%s). Expected (%s)", chain->sType, sType);
}
return {}; return {};
} }
@ -57,9 +56,8 @@ namespace dawn_native {
if (chain == nullptr) { if (chain == nullptr) {
return {}; return {};
} }
if (chain->nextInChain != nullptr) { DAWN_INVALID_IF(chain->nextInChain != nullptr,
return DAWN_VALIDATION_ERROR("Chain can only contain a single chained struct"); "Chain can only contain a single chained struct.");
}
return ValidateSingleSTypeInner(chain, sType); return ValidateSingleSTypeInner(chain, sType);
} }
@ -70,9 +68,8 @@ namespace dawn_native {
if (chain == nullptr) { if (chain == nullptr) {
return {}; return {};
} }
if (chain->nextInChain != nullptr) { DAWN_INVALID_IF(chain->nextInChain != nullptr,
return DAWN_VALIDATION_ERROR("Chain can only contain a single chained struct"); "Chain can only contain a single chained struct.");
}
return ValidateSingleSTypeInner(chain, sType, sTypes...); return ValidateSingleSTypeInner(chain, sType, sTypes...);
} }

View File

@ -1444,7 +1444,8 @@ namespace dawn_native {
const SwapChainDescriptor* descriptor) { const SwapChainDescriptor* descriptor) {
DAWN_TRY(ValidateIsAlive()); DAWN_TRY(ValidateIsAlive());
if (IsValidationEnabled()) { if (IsValidationEnabled()) {
DAWN_TRY(ValidateSwapChainDescriptor(this, surface, descriptor)); DAWN_TRY_CONTEXT(ValidateSwapChainDescriptor(this, surface, descriptor),
"validating %s", descriptor);
} }
// TODO(dawn:269): Remove this code path once implementation-based swapchains are removed. // TODO(dawn:269): Remove this code path once implementation-based swapchains are removed.

View File

@ -65,10 +65,8 @@ namespace dawn_native {
device->EmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str()); device->EmitLog(WGPULoggingType_Info, dumpedMsg.str().c_str());
} }
if (!valid) { DAWN_INVALID_IF(!valid,
return DAWN_VALIDATION_ERROR( "Produced invalid SPIRV. Please file a bug at https://crbug.com/tint.");
"Produced invalid SPIRV. Please file a bug at https://crbug.com/tint.");
}
return {}; return {};
} }

View File

@ -36,9 +36,9 @@ namespace dawn_native {
MaybeError ValidateSurfaceDescriptor(const InstanceBase* instance, MaybeError ValidateSurfaceDescriptor(const InstanceBase* instance,
const SurfaceDescriptor* descriptor) { const SurfaceDescriptor* descriptor) {
if (descriptor->nextInChain == nullptr) { DAWN_INVALID_IF(descriptor->nextInChain == nullptr,
return DAWN_VALIDATION_ERROR("Surface cannot be created with just the base descriptor"); "Surface cannot be created with %s. nextInChain is not specified.",
} descriptor);
DAWN_TRY(ValidateSingleSType(descriptor->nextInChain, DAWN_TRY(ValidateSingleSType(descriptor->nextInChain,
wgpu::SType::SurfaceDescriptorFromMetalLayer, wgpu::SType::SurfaceDescriptorFromMetalLayer,
@ -52,9 +52,8 @@ namespace dawn_native {
FindInChain(descriptor->nextInChain, &metalDesc); FindInChain(descriptor->nextInChain, &metalDesc);
if (metalDesc) { if (metalDesc) {
// Check that the layer is a CAMetalLayer (or a derived class). // Check that the layer is a CAMetalLayer (or a derived class).
if (!InheritsFromCAMetalLayer(metalDesc->layer)) { DAWN_INVALID_IF(!InheritsFromCAMetalLayer(metalDesc->layer),
return DAWN_VALIDATION_ERROR("layer must be a CAMetalLayer"); "Layer must be a CAMetalLayer");
}
return {}; return {};
} }
#endif // defined(DAWN_ENABLE_BACKEND_METAL) #endif // defined(DAWN_ENABLE_BACKEND_METAL)
@ -64,9 +63,7 @@ namespace dawn_native {
const SurfaceDescriptorFromWindowsHWND* hwndDesc = nullptr; const SurfaceDescriptorFromWindowsHWND* hwndDesc = nullptr;
FindInChain(descriptor->nextInChain, &hwndDesc); FindInChain(descriptor->nextInChain, &hwndDesc);
if (hwndDesc) { if (hwndDesc) {
if (IsWindow(static_cast<HWND>(hwndDesc->hwnd)) == 0) { DAWN_INVALID_IF(IsWindow(static_cast<HWND>(hwndDesc->hwnd)) == 0, "Invalid HWND");
return DAWN_VALIDATION_ERROR("Invalid HWND");
}
return {}; return {};
} }
# endif // defined(DAWN_PLATFORM_WIN32) # endif // defined(DAWN_PLATFORM_WIN32)
@ -75,11 +72,10 @@ namespace dawn_native {
if (coreWindowDesc) { if (coreWindowDesc) {
// Validate the coreWindow by query for ICoreWindow interface // Validate the coreWindow by query for ICoreWindow interface
ComPtr<ABI::Windows::UI::Core::ICoreWindow> coreWindow; ComPtr<ABI::Windows::UI::Core::ICoreWindow> coreWindow;
if (coreWindowDesc->coreWindow == nullptr || DAWN_INVALID_IF(coreWindowDesc->coreWindow == nullptr ||
FAILED(static_cast<IUnknown*>(coreWindowDesc->coreWindow) FAILED(static_cast<IUnknown*>(coreWindowDesc->coreWindow)
->QueryInterface(IID_PPV_ARGS(&coreWindow)))) { ->QueryInterface(IID_PPV_ARGS(&coreWindow))),
return DAWN_VALIDATION_ERROR("Invalid CoreWindow"); "Invalid CoreWindow");
}
return {}; return {};
} }
const SurfaceDescriptorFromWindowsSwapChainPanel* swapChainPanelDesc = nullptr; const SurfaceDescriptorFromWindowsSwapChainPanel* swapChainPanelDesc = nullptr;
@ -87,11 +83,10 @@ namespace dawn_native {
if (swapChainPanelDesc) { if (swapChainPanelDesc) {
// Validate the swapChainPanel by querying for ISwapChainPanel interface // Validate the swapChainPanel by querying for ISwapChainPanel interface
ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> swapChainPanel; ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> swapChainPanel;
if (swapChainPanelDesc->swapChainPanel == nullptr || DAWN_INVALID_IF(swapChainPanelDesc->swapChainPanel == nullptr ||
FAILED(static_cast<IUnknown*>(swapChainPanelDesc->swapChainPanel) FAILED(static_cast<IUnknown*>(swapChainPanelDesc->swapChainPanel)
->QueryInterface(IID_PPV_ARGS(&swapChainPanel)))) { ->QueryInterface(IID_PPV_ARGS(&swapChainPanel))),
return DAWN_VALIDATION_ERROR("Invalid SwapChainPanel"); "Invalid SwapChainPanel");
}
return {}; return {};
} }
#endif // defined(DAWN_PLATFORM_WINDOWS) #endif // defined(DAWN_PLATFORM_WINDOWS)
@ -111,14 +106,13 @@ namespace dawn_native {
xDesc->window, &attributes); xDesc->window, &attributes);
XSetErrorHandler(oldErrorHandler); XSetErrorHandler(oldErrorHandler);
if (status == 0) { DAWN_INVALID_IF(status == 0, "Invalid X Window");
return DAWN_VALIDATION_ERROR("Invalid X Window");
}
return {}; return {};
} }
#endif // defined(DAWN_USE_X11) #endif // defined(DAWN_USE_X11)
return DAWN_VALIDATION_ERROR("Unsupported sType"); return DAWN_FORMAT_VALIDATION_ERROR("Unsupported sType (%s)",
descriptor->nextInChain->sType);
} }
Surface::Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor) Surface::Surface(InstanceBase* instance, const SurfaceDescriptor* descriptor)

View File

@ -36,16 +36,19 @@ namespace dawn_native {
wgpu::TextureUsage allowedUsage, wgpu::TextureUsage allowedUsage,
uint32_t width, uint32_t width,
uint32_t height) override { uint32_t height) override {
GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("error swapchain")); GetDevice()->ConsumedError(
DAWN_FORMAT_VALIDATION_ERROR("%s is an error swapchain.", this));
} }
TextureViewBase* APIGetCurrentTextureView() override { TextureViewBase* APIGetCurrentTextureView() override {
GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("error swapchain")); GetDevice()->ConsumedError(
DAWN_FORMAT_VALIDATION_ERROR("%s is an error swapchain.", this));
return TextureViewBase::MakeError(GetDevice()); return TextureViewBase::MakeError(GetDevice());
} }
void APIPresent() override { void APIPresent() override {
GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("error swapchain")); GetDevice()->ConsumedError(
DAWN_FORMAT_VALIDATION_ERROR("%s is an error swapchain.", this));
} }
}; };
@ -55,45 +58,43 @@ namespace dawn_native {
const Surface* surface, const Surface* surface,
const SwapChainDescriptor* descriptor) { const SwapChainDescriptor* descriptor) {
if (descriptor->implementation != 0) { if (descriptor->implementation != 0) {
if (surface != nullptr) { DAWN_INVALID_IF(surface != nullptr,
return DAWN_VALIDATION_ERROR( "Exactly one of surface or implementation must be set");
"Exactly one of surface or implementation must be set");
}
DawnSwapChainImplementation* impl = DawnSwapChainImplementation* impl =
reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation); reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation);
if (!impl->Init || !impl->Destroy || !impl->Configure || !impl->GetNextTexture || DAWN_INVALID_IF(!impl->Init || !impl->Destroy || !impl->Configure ||
!impl->Present) { !impl->GetNextTexture || !impl->Present,
return DAWN_VALIDATION_ERROR("Implementation is incomplete"); "Implementation is incomplete");
}
} else { } else {
if (surface == nullptr) { DAWN_INVALID_IF(surface == nullptr,
return DAWN_VALIDATION_ERROR( "At least one of surface or implementation must be set");
"At least one of surface or implementation must be set");
}
DAWN_TRY(ValidatePresentMode(descriptor->presentMode)); DAWN_TRY(ValidatePresentMode(descriptor->presentMode));
// TODO(crbug.com/dawn/160): Lift this restriction once // TODO(crbug.com/dawn/160): Lift this restriction once
// wgpu::Instance::GetPreferredSurfaceFormat is implemented. // wgpu::Instance::GetPreferredSurfaceFormat is implemented.
if (descriptor->format != wgpu::TextureFormat::BGRA8Unorm) { DAWN_INVALID_IF(descriptor->format != wgpu::TextureFormat::BGRA8Unorm,
return DAWN_VALIDATION_ERROR("Format must (currently) be BGRA8Unorm"); "Format (%s) is not %s, which is (currently) the only accepted format.",
} descriptor->format, wgpu::TextureFormat::BGRA8Unorm);
if (descriptor->usage != wgpu::TextureUsage::RenderAttachment) { DAWN_INVALID_IF(descriptor->usage != wgpu::TextureUsage::RenderAttachment,
return DAWN_VALIDATION_ERROR("Usage must (currently) be RenderAttachment"); "Usage (%s) is not %s, which is (currently) the only accepted usage.",
} descriptor->usage, wgpu::TextureUsage::RenderAttachment);
if (descriptor->width == 0 || descriptor->height == 0) { DAWN_INVALID_IF(descriptor->width == 0 || descriptor->height == 0,
return DAWN_VALIDATION_ERROR("Swapchain size can't be empty"); "Swap Chain size (width: %u, height: %u) is empty.", descriptor->width,
} descriptor->height);
if (descriptor->width > device->GetLimits().v1.maxTextureDimension2D || DAWN_INVALID_IF(
descriptor->height > device->GetLimits().v1.maxTextureDimension2D) { descriptor->width > device->GetLimits().v1.maxTextureDimension2D ||
return DAWN_VALIDATION_ERROR("Swapchain size too big"); descriptor->height > device->GetLimits().v1.maxTextureDimension2D,
} "Swap Chain size (width: %u, height: %u) is greater than the maximum 2D texture "
"size (width: %u, height: %u).",
descriptor->width, descriptor->height, device->GetLimits().v1.maxTextureDimension2D,
device->GetLimits().v1.maxTextureDimension2D);
} }
return {}; return {};
@ -230,9 +231,9 @@ namespace dawn_native {
DAWN_TRY(ValidateTextureUsage(allowedUsage)); DAWN_TRY(ValidateTextureUsage(allowedUsage));
DAWN_TRY(ValidateTextureFormat(format)); DAWN_TRY(ValidateTextureFormat(format));
if (width == 0 || height == 0) { DAWN_INVALID_IF(width == 0 || height == 0,
return DAWN_VALIDATION_ERROR("Swap chain cannot be configured to zero size"); "Configuration size (width: %u, height: %u) for %s is empty.", width,
} height, this);
return {}; return {};
} }
@ -241,10 +242,9 @@ namespace dawn_native {
DAWN_TRY(GetDevice()->ValidateIsAlive()); DAWN_TRY(GetDevice()->ValidateIsAlive());
DAWN_TRY(GetDevice()->ValidateObject(this)); DAWN_TRY(GetDevice()->ValidateObject(this));
if (mWidth == 0) { // If width is 0, it implies swap chain has never been configured
// If width is 0, it implies swap chain has never been configured DAWN_INVALID_IF(mWidth == 0, "%s was not configured prior to calling GetNextTexture.",
return DAWN_VALIDATION_ERROR("Swap chain needs to be configured before GetNextTexture"); this);
}
return {}; return {};
} }
@ -253,10 +253,10 @@ namespace dawn_native {
DAWN_TRY(GetDevice()->ValidateIsAlive()); DAWN_TRY(GetDevice()->ValidateIsAlive());
DAWN_TRY(GetDevice()->ValidateObject(this)); DAWN_TRY(GetDevice()->ValidateObject(this));
if (mCurrentTextureView == nullptr) { DAWN_INVALID_IF(
return DAWN_VALIDATION_ERROR( mCurrentTextureView == nullptr,
"Cannot call present without a GetCurrentTextureView call for this frame"); "GetCurrentTextureView was not called on %s this frame prior to calling Present.",
} this);
return {}; return {};
} }
@ -302,7 +302,7 @@ namespace dawn_native {
uint32_t width, uint32_t width,
uint32_t height) { uint32_t height) {
GetDevice()->ConsumedError( GetDevice()->ConsumedError(
DAWN_VALIDATION_ERROR("Configure is invalid for surface-based swapchains")); DAWN_FORMAT_VALIDATION_ERROR("Configure is invalid for surface-based swapchains."));
} }
TextureViewBase* NewSwapChainBase::APIGetCurrentTextureView() { TextureViewBase* NewSwapChainBase::APIGetCurrentTextureView() {
@ -386,13 +386,12 @@ namespace dawn_native {
DAWN_TRY(GetDevice()->ValidateIsAlive()); DAWN_TRY(GetDevice()->ValidateIsAlive());
DAWN_TRY(GetDevice()->ValidateObject(this)); DAWN_TRY(GetDevice()->ValidateObject(this));
if (!mAttached) { DAWN_INVALID_IF(!mAttached, "Cannot call Present called on detached %s.", this);
return DAWN_VALIDATION_ERROR("Presenting on detached swapchain");
}
if (mCurrentTextureView == nullptr) { DAWN_INVALID_IF(
return DAWN_VALIDATION_ERROR("Presenting without prior GetCurrentTextureView"); mCurrentTextureView == nullptr,
} "GetCurrentTextureView was not called on %s this frame prior to calling Present.",
this);
return {}; return {};
} }
@ -401,9 +400,7 @@ namespace dawn_native {
DAWN_TRY(GetDevice()->ValidateIsAlive()); DAWN_TRY(GetDevice()->ValidateIsAlive());
DAWN_TRY(GetDevice()->ValidateObject(this)); DAWN_TRY(GetDevice()->ValidateObject(this));
if (!mAttached) { DAWN_INVALID_IF(!mAttached, "Cannot call GetCurrentTextureView on detached %s.", this);
return DAWN_VALIDATION_ERROR("Getting view on detached swapchain");
}
return {}; return {};
} }