Make ConsumedError require handling the returned bool.

This change makes it harder to misuse ConsumedError which can cause
device loss. When it is a known error, instead use HandleError to
bypass the "unlikely" if clause.

Bug: dawn:1336
Change-Id: I3052db343fe4080b257f1c2f9535f743a0e78526
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/120384
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Loko Kung <lokokung@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Loko Kung 2023-03-02 01:24:03 +00:00 committed by Dawn LUCI CQ
parent e11208e9ce
commit d81aca7106
8 changed files with 59 additions and 52 deletions

View File

@ -506,9 +506,7 @@ void BufferBase::APIUnmap() {
if (GetDevice()->ConsumedError(ValidateUnmap(), "calling %s.Unmap().", this)) { if (GetDevice()->ConsumedError(ValidateUnmap(), "calling %s.Unmap().", this)) {
return; return;
} }
if (GetDevice()->ConsumedError(Unmap(), "calling %s.Unmap().", this)) { DAWN_UNUSED(GetDevice()->ConsumedError(Unmap(), "calling %s.Unmap().", this));
return;
}
} }
MaybeError BufferBase::Unmap() { MaybeError BufferBase::Unmap() {

View File

@ -151,7 +151,7 @@ ObjectType ComputePassEncoder::GetType() const {
void ComputePassEncoder::APIEnd() { void ComputePassEncoder::APIEnd() {
if (mEnded && IsValidationEnabled()) { if (mEnded && IsValidationEnabled()) {
GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("%s was already ended.", this)); GetDevice()->HandleError(DAWN_VALIDATION_ERROR("%s was already ended.", this));
return; return;
} }

View File

@ -469,6 +469,7 @@ void DeviceBase::APIDestroy() {
void DeviceBase::HandleError(std::unique_ptr<ErrorData> error, void DeviceBase::HandleError(std::unique_ptr<ErrorData> error,
InternalErrorType additionalAllowedErrors, InternalErrorType additionalAllowedErrors,
WGPUDeviceLostReason lost_reason) { WGPUDeviceLostReason lost_reason) {
AppendDebugLayerMessages(error.get());
InternalErrorType allowedErrors = InternalErrorType allowedErrors =
InternalErrorType::Validation | InternalErrorType::DeviceLost | additionalAllowedErrors; InternalErrorType::Validation | InternalErrorType::DeviceLost | additionalAllowedErrors;
InternalErrorType type = error->GetType(); InternalErrorType type = error->GetType();
@ -545,7 +546,6 @@ void DeviceBase::HandleError(std::unique_ptr<ErrorData> error,
void DeviceBase::ConsumeError(std::unique_ptr<ErrorData> error, void DeviceBase::ConsumeError(std::unique_ptr<ErrorData> error,
InternalErrorType additionalAllowedErrors) { InternalErrorType additionalAllowedErrors) {
ASSERT(error != nullptr); ASSERT(error != nullptr);
AppendDebugLayerMessages(error.get());
HandleError(std::move(error), additionalAllowedErrors); HandleError(std::move(error), additionalAllowedErrors);
} }
@ -1203,21 +1203,24 @@ BufferBase* DeviceBase::APICreateErrorBuffer(const BufferDescriptor* desc) {
// The validation errors on BufferDescriptor should be prior to any OOM errors when // The validation errors on BufferDescriptor should be prior to any OOM errors when
// MapppedAtCreation == false. // MapppedAtCreation == false.
MaybeError maybeError = ValidateBufferDescriptor(this, &fakeDescriptor); MaybeError maybeError = ValidateBufferDescriptor(this, &fakeDescriptor);
if (maybeError.IsError()) {
ConsumedError(maybeError.AcquireError(), InternalErrorType::OutOfMemory,
"calling %s.CreateBuffer(%s).", this, desc);
} else {
const DawnBufferDescriptorErrorInfoFromWireClient* clientErrorInfo = nullptr;
FindInChain(desc->nextInChain, &clientErrorInfo);
if (clientErrorInfo != nullptr && clientErrorInfo->outOfMemory) {
ConsumedError(DAWN_OUT_OF_MEMORY_ERROR("Failed to allocate memory for buffer mapping"),
InternalErrorType::OutOfMemory);
}
}
// Set the size of the error buffer to 0 as this function is called only when an OOM happens at // Set the size of the error buffer to 0 as this function is called only when an OOM happens at
// the client side. // the client side.
fakeDescriptor.size = 0; fakeDescriptor.size = 0;
if (maybeError.IsError()) {
std::unique_ptr<ErrorData> error = maybeError.AcquireError();
error->AppendContext("calling %s.CreateBuffer(%s).", this, desc);
HandleError(std::move(error), InternalErrorType::OutOfMemory);
} else {
const DawnBufferDescriptorErrorInfoFromWireClient* clientErrorInfo = nullptr;
FindInChain(desc->nextInChain, &clientErrorInfo);
if (clientErrorInfo != nullptr && clientErrorInfo->outOfMemory) {
HandleError(DAWN_OUT_OF_MEMORY_ERROR("Failed to allocate memory for buffer mapping"),
InternalErrorType::OutOfMemory);
}
}
return BufferBase::MakeError(this, &fakeDescriptor); return BufferBase::MakeError(this, &fakeDescriptor);
} }
@ -1401,7 +1404,7 @@ void DeviceBase::APIInjectError(wgpu::ErrorType type, const char* message) {
} }
void DeviceBase::APIValidateTextureDescriptor(const TextureDescriptor* desc) { void DeviceBase::APIValidateTextureDescriptor(const TextureDescriptor* desc) {
ConsumedError(ValidateTextureDescriptor(this, desc)); DAWN_UNUSED(ConsumedError(ValidateTextureDescriptor(this, desc)));
} }
QueueBase* DeviceBase::GetQueue() const { QueueBase* DeviceBase::GetQueue() const {

View File

@ -76,7 +76,11 @@ class DeviceBase : public RefCountedWithExternalCount {
InternalErrorType additionalAllowedErrors = InternalErrorType::None, InternalErrorType additionalAllowedErrors = InternalErrorType::None,
WGPUDeviceLostReason lost_reason = WGPUDeviceLostReason_Undefined); WGPUDeviceLostReason lost_reason = WGPUDeviceLostReason_Undefined);
bool ConsumedError(MaybeError maybeError, // Variants of ConsumedError must use the returned boolean to handle failure cases since an
// error may cause a device loss and further execution may be undefined. This is especially
// true for the ResultOrError variants.
[[nodiscard]] bool ConsumedError(
MaybeError maybeError,
InternalErrorType additionalAllowedErrors = InternalErrorType::None) { InternalErrorType additionalAllowedErrors = InternalErrorType::None) {
if (DAWN_UNLIKELY(maybeError.IsError())) { if (DAWN_UNLIKELY(maybeError.IsError())) {
ConsumeError(maybeError.AcquireError(), additionalAllowedErrors); ConsumeError(maybeError.AcquireError(), additionalAllowedErrors);
@ -86,7 +90,8 @@ class DeviceBase : public RefCountedWithExternalCount {
} }
template <typename T> template <typename T>
bool ConsumedError(ResultOrError<T> resultOrError, [[nodiscard]] bool ConsumedError(
ResultOrError<T> resultOrError,
T* result, T* result,
InternalErrorType additionalAllowedErrors = InternalErrorType::None) { InternalErrorType additionalAllowedErrors = InternalErrorType::None) {
if (DAWN_UNLIKELY(resultOrError.IsError())) { if (DAWN_UNLIKELY(resultOrError.IsError())) {
@ -98,7 +103,7 @@ class DeviceBase : public RefCountedWithExternalCount {
} }
template <typename... Args> template <typename... Args>
bool ConsumedError(MaybeError maybeError, [[nodiscard]] bool ConsumedError(MaybeError maybeError,
InternalErrorType additionalAllowedErrors, InternalErrorType additionalAllowedErrors,
const char* formatStr, const char* formatStr,
const Args&... args) { const Args&... args) {
@ -114,13 +119,14 @@ class DeviceBase : public RefCountedWithExternalCount {
} }
template <typename... Args> template <typename... Args>
bool ConsumedError(MaybeError maybeError, const char* formatStr, Args&&... args) { [[nodiscard]] bool ConsumedError(MaybeError maybeError,
return ConsumedError(std::move(maybeError), InternalErrorType::None, formatStr, const char* formatStr,
std::forward<Args>(args)...); const Args&... args) {
return ConsumedError(std::move(maybeError), InternalErrorType::None, formatStr, args...);
} }
template <typename T, typename... Args> template <typename T, typename... Args>
bool ConsumedError(ResultOrError<T> resultOrError, [[nodiscard]] bool ConsumedError(ResultOrError<T> resultOrError,
T* result, T* result,
InternalErrorType additionalAllowedErrors, InternalErrorType additionalAllowedErrors,
const char* formatStr, const char* formatStr,
@ -138,12 +144,12 @@ class DeviceBase : public RefCountedWithExternalCount {
} }
template <typename T, typename... Args> template <typename T, typename... Args>
bool ConsumedError(ResultOrError<T> resultOrError, [[nodiscard]] bool ConsumedError(ResultOrError<T> resultOrError,
T* result, T* result,
const char* formatStr, const char* formatStr,
Args&&... args) { const Args&... args) {
return ConsumedError(std::move(resultOrError), result, InternalErrorType::None, formatStr, return ConsumedError(std::move(resultOrError), result, InternalErrorType::None, formatStr,
std::forward<Args>(args)...); args...);
} }
MaybeError ValidateObject(const ApiObjectBase* object) const; MaybeError ValidateObject(const ApiObjectBase* object) const;

View File

@ -281,7 +281,7 @@ void QueueBase::APIWriteBuffer(BufferBase* buffer,
uint64_t bufferOffset, uint64_t bufferOffset,
const void* data, const void* data,
size_t size) { size_t size) {
GetDevice()->ConsumedError(WriteBuffer(buffer, bufferOffset, data, size)); DAWN_UNUSED(GetDevice()->ConsumedError(WriteBuffer(buffer, bufferOffset, data, size)));
} }
MaybeError QueueBase::WriteBuffer(BufferBase* buffer, MaybeError QueueBase::WriteBuffer(BufferBase* buffer,
@ -322,8 +322,8 @@ void QueueBase::APIWriteTexture(const ImageCopyTexture* destination,
size_t dataSize, size_t dataSize,
const TextureDataLayout* dataLayout, const TextureDataLayout* dataLayout,
const Extent3D* writeSize) { const Extent3D* writeSize) {
GetDevice()->ConsumedError( DAWN_UNUSED(GetDevice()->ConsumedError(
WriteTextureInternal(destination, data, dataSize, *dataLayout, writeSize)); WriteTextureInternal(destination, data, dataSize, *dataLayout, writeSize)));
} }
MaybeError QueueBase::WriteTextureInternal(const ImageCopyTexture* destination, MaybeError QueueBase::WriteTextureInternal(const ImageCopyTexture* destination,
@ -389,16 +389,16 @@ void QueueBase::APICopyTextureForBrowser(const ImageCopyTexture* source,
const ImageCopyTexture* destination, const ImageCopyTexture* destination,
const Extent3D* copySize, const Extent3D* copySize,
const CopyTextureForBrowserOptions* options) { const CopyTextureForBrowserOptions* options) {
GetDevice()->ConsumedError( DAWN_UNUSED(GetDevice()->ConsumedError(
CopyTextureForBrowserInternal(source, destination, copySize, options)); CopyTextureForBrowserInternal(source, destination, copySize, options)));
} }
void QueueBase::APICopyExternalTextureForBrowser(const ImageCopyExternalTexture* source, void QueueBase::APICopyExternalTextureForBrowser(const ImageCopyExternalTexture* source,
const ImageCopyTexture* destination, const ImageCopyTexture* destination,
const Extent3D* copySize, const Extent3D* copySize,
const CopyTextureForBrowserOptions* options) { const CopyTextureForBrowserOptions* options) {
GetDevice()->ConsumedError( DAWN_UNUSED(GetDevice()->ConsumedError(
CopyExternalTextureForBrowserInternal(source, destination, copySize, options)); CopyExternalTextureForBrowserInternal(source, destination, copySize, options)));
} }
MaybeError QueueBase::CopyTextureForBrowserInternal(const ImageCopyTexture* source, MaybeError QueueBase::CopyTextureForBrowserInternal(const ImageCopyTexture* source,

View File

@ -137,7 +137,7 @@ void RenderPassEncoder::TrackQueryAvailability(QuerySetBase* querySet, uint32_t
void RenderPassEncoder::APIEnd() { void RenderPassEncoder::APIEnd() {
if (mEnded && IsValidationEnabled()) { if (mEnded && IsValidationEnabled()) {
GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("%s was already ended.", this)); GetDevice()->HandleError(DAWN_VALIDATION_ERROR("%s was already ended.", this));
return; return;
} }

View File

@ -35,16 +35,16 @@ class ErrorSwapChain final : public SwapChainBase {
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("%s is an error swapchain.", this)); GetDevice()->HandleError(DAWN_VALIDATION_ERROR("%s is an error swapchain.", this));
} }
TextureViewBase* APIGetCurrentTextureView() override { TextureViewBase* APIGetCurrentTextureView() override {
GetDevice()->ConsumedError(DAWN_VALIDATION_ERROR("%s is an error swapchain.", this)); GetDevice()->HandleError(DAWN_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("%s is an error swapchain.", this)); GetDevice()->HandleError(DAWN_VALIDATION_ERROR("%s is an error swapchain.", this));
} }
}; };
@ -300,7 +300,7 @@ void NewSwapChainBase::APIConfigure(wgpu::TextureFormat format,
wgpu::TextureUsage allowedUsage, wgpu::TextureUsage allowedUsage,
uint32_t width, uint32_t width,
uint32_t height) { uint32_t height) {
GetDevice()->ConsumedError( GetDevice()->HandleError(
DAWN_VALIDATION_ERROR("Configure is invalid for surface-based swapchains.")); DAWN_VALIDATION_ERROR("Configure is invalid for surface-based swapchains."));
} }

View File

@ -226,6 +226,6 @@ TEST_F(DeviceTickValidationTest, DestroyDeviceBeforeInternalTick) {
ExpectDeviceDestruction(); ExpectDeviceDestruction();
device.Destroy(); device.Destroy();
dawn::native::DeviceBase* nativeDevice = dawn::native::FromAPI(device.Get()); dawn::native::DeviceBase* nativeDevice = dawn::native::FromAPI(device.Get());
ASSERT_DEVICE_ERROR(nativeDevice->ConsumedError(nativeDevice->Tick()), ASSERT_DEVICE_ERROR(EXPECT_TRUE(nativeDevice->ConsumedError(nativeDevice->Tick())),
HasSubstr("[Device] is lost.")); HasSubstr("[Device] is lost."));
} }