Don't forward device lost errors to the uncaptured error callback
This issue was discovered in http://crrev.com/c/2613517 where a device lost error on page teardown was bubbling up to the Renderer's uncaptured error callback. Bug: chromium:1160459 Change-Id: I64b8c7779f4808d5a4b87c131aaf2e041c512bb9 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/36960 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
558599fc9a
commit
8ef94f1684
|
@ -212,10 +212,15 @@ namespace dawn_native {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceBase::HandleError(InternalErrorType type, const char* message) {
|
void DeviceBase::HandleError(InternalErrorType type, const char* message) {
|
||||||
|
if (type == InternalErrorType::DeviceLost) {
|
||||||
|
// A real device lost happened. Set the state to disconnected as the device cannot be
|
||||||
|
// used.
|
||||||
|
mState = State::Disconnected;
|
||||||
|
} else if (type == InternalErrorType::Internal) {
|
||||||
// If we receive an internal error, assume the backend can't recover and proceed with
|
// If we receive an internal error, assume the backend can't recover and proceed with
|
||||||
// device destruction. We first wait for all previous commands to be completed so that
|
// device destruction. We first wait for all previous commands to be completed so that
|
||||||
// backend objects can be freed immediately, before handling the loss.
|
// backend objects can be freed immediately, before handling the loss.
|
||||||
if (type == InternalErrorType::Internal) {
|
|
||||||
// Move away from the Alive state so that the application cannot use this device
|
// Move away from the Alive state so that the application cannot use this device
|
||||||
// anymore.
|
// anymore.
|
||||||
// TODO(cwallez@chromium.org): Do we need atomics for this to become visible to other
|
// TODO(cwallez@chromium.org): Do we need atomics for this to become visible to other
|
||||||
|
@ -240,7 +245,7 @@ namespace dawn_native {
|
||||||
mDeviceLostCallback = nullptr;
|
mDeviceLostCallback = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Still forward device loss and internal errors to the error scopes so they all reject.
|
// Still forward device loss errors to the error scopes so they all reject.
|
||||||
mCurrentErrorScope->HandleError(ToWGPUErrorType(type), message);
|
mCurrentErrorScope->HandleError(ToWGPUErrorType(type), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,7 +327,7 @@ namespace dawn_native {
|
||||||
if (DAWN_LIKELY(mState == State::Alive)) {
|
if (DAWN_LIKELY(mState == State::Alive)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return DAWN_DEVICE_LOST_ERROR("Device is lost");
|
return DAWN_VALIDATION_ERROR("Device is lost");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceBase::LoseForTesting() {
|
void DeviceBase::LoseForTesting() {
|
||||||
|
|
|
@ -26,7 +26,6 @@ namespace dawn_native {
|
||||||
Validation,
|
Validation,
|
||||||
DeviceLost,
|
DeviceLost,
|
||||||
Internal,
|
Internal,
|
||||||
Unimplemented,
|
|
||||||
OutOfMemory
|
OutOfMemory
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -72,11 +71,23 @@ namespace dawn_native {
|
||||||
|
|
||||||
#define DAWN_MAKE_ERROR(TYPE, MESSAGE) \
|
#define DAWN_MAKE_ERROR(TYPE, MESSAGE) \
|
||||||
::dawn_native::ErrorData::Create(TYPE, MESSAGE, __FILE__, __func__, __LINE__)
|
::dawn_native::ErrorData::Create(TYPE, MESSAGE, __FILE__, __func__, __LINE__)
|
||||||
|
|
||||||
#define DAWN_VALIDATION_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::Validation, MESSAGE)
|
#define DAWN_VALIDATION_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::Validation, MESSAGE)
|
||||||
|
|
||||||
|
// DAWN_DEVICE_LOST_ERROR means that there was a real unrecoverable native device lost error.
|
||||||
|
// We can't even do a graceful shutdown because the Device is gone.
|
||||||
#define DAWN_DEVICE_LOST_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::DeviceLost, MESSAGE)
|
#define DAWN_DEVICE_LOST_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::DeviceLost, MESSAGE)
|
||||||
|
|
||||||
|
// DAWN_INTERNAL_ERROR means Dawn hit an unexpected error in the backend and should try to
|
||||||
|
// gracefully shut down.
|
||||||
#define DAWN_INTERNAL_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::Internal, MESSAGE)
|
#define DAWN_INTERNAL_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::Internal, MESSAGE)
|
||||||
|
|
||||||
#define DAWN_UNIMPLEMENTED_ERROR(MESSAGE) \
|
#define DAWN_UNIMPLEMENTED_ERROR(MESSAGE) \
|
||||||
DAWN_MAKE_ERROR(InternalErrorType::Internal, std::string("Unimplemented: ") + MESSAGE)
|
DAWN_MAKE_ERROR(InternalErrorType::Internal, std::string("Unimplemented: ") + MESSAGE)
|
||||||
|
|
||||||
|
// DAWN_OUT_OF_MEMORY_ERROR means we ran out of memory. It may be used as a signal internally in
|
||||||
|
// Dawn to free up unused resources. Or, it may bubble up to the application to signal an allocation
|
||||||
|
// was too large or they should free some existing resources.
|
||||||
#define DAWN_OUT_OF_MEMORY_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::OutOfMemory, MESSAGE)
|
#define DAWN_OUT_OF_MEMORY_ERROR(MESSAGE) DAWN_MAKE_ERROR(InternalErrorType::OutOfMemory, MESSAGE)
|
||||||
|
|
||||||
#define DAWN_CONCAT1(x, y) x##y
|
#define DAWN_CONCAT1(x, y) x##y
|
||||||
|
|
|
@ -87,14 +87,23 @@ namespace dawn_native {
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Unknown and DeviceLost are fatal. All error scopes capture them.
|
// DeviceLost is fatal. All error scopes capture them.
|
||||||
// |consumed| is false because these should bubble to all scopes.
|
// |consumed| is false because these should bubble to all scopes.
|
||||||
case wgpu::ErrorType::Unknown:
|
|
||||||
case wgpu::ErrorType::DeviceLost:
|
case wgpu::ErrorType::DeviceLost:
|
||||||
consumed = false;
|
consumed = false;
|
||||||
|
if (currentScope->mErrorType != wgpu::ErrorType::DeviceLost) {
|
||||||
|
// DeviceLost overrides any other error that is not a DeviceLost.
|
||||||
|
currentScope->mErrorType = type;
|
||||||
|
currentScope->mErrorMessage = message;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case wgpu::ErrorType::Unknown:
|
||||||
|
// Means the scope was destroyed before contained work finished.
|
||||||
|
// This happens when you destroy the device while there's pending work.
|
||||||
|
// That's handled in ErrorScope::UnlinkForShutdownImpl, not here.
|
||||||
case wgpu::ErrorType::NoError:
|
case wgpu::ErrorType::NoError:
|
||||||
|
// Not considered an error, and should never be passed to HandleError.
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -111,8 +120,10 @@ namespace dawn_native {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The root error scope captures all uncaptured errors.
|
// The root error scope captures all uncaptured errors.
|
||||||
|
// Except, it should not capture device lost errors since those go to
|
||||||
|
// the device lost callback.
|
||||||
ASSERT(currentScope->IsRoot());
|
ASSERT(currentScope->IsRoot());
|
||||||
if (currentScope->mCallback) {
|
if (currentScope->mCallback && type != wgpu::ErrorType::DeviceLost) {
|
||||||
currentScope->mCallback(static_cast<WGPUErrorType>(type), message,
|
currentScope->mCallback(static_cast<WGPUErrorType>(type), message,
|
||||||
currentScope->mUserdata);
|
currentScope->mUserdata);
|
||||||
}
|
}
|
||||||
|
|
|
@ -264,6 +264,7 @@ source_set("dawn_end2end_tests_sources") {
|
||||||
|
|
||||||
sources = [
|
sources = [
|
||||||
"DawnTest.h",
|
"DawnTest.h",
|
||||||
|
"MockCallback.h",
|
||||||
"end2end/BasicTests.cpp",
|
"end2end/BasicTests.cpp",
|
||||||
"end2end/BindGroupTests.cpp",
|
"end2end/BindGroupTests.cpp",
|
||||||
"end2end/BufferTests.cpp",
|
"end2end/BufferTests.cpp",
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "tests/DawnTest.h"
|
#include "tests/DawnTest.h"
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
|
#include "tests/MockCallback.h"
|
||||||
#include "utils/ComboRenderPipelineDescriptor.h"
|
#include "utils/ComboRenderPipelineDescriptor.h"
|
||||||
#include "utils/WGPUHelpers.h"
|
#include "utils/WGPUHelpers.h"
|
||||||
|
|
||||||
|
@ -516,6 +517,19 @@ TEST_P(DeviceLostTest, LoseForTestingOnce) {
|
||||||
device.LoseForTesting();
|
device.LoseForTesting();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(DeviceLostTest, DeviceLostDoesntCallUncapturedError) {
|
||||||
|
// Set no callback.
|
||||||
|
device.SetDeviceLostCallback(nullptr, nullptr);
|
||||||
|
|
||||||
|
// Set the uncaptured error callback which should not be called on
|
||||||
|
// device lost.
|
||||||
|
MockCallback<WGPUErrorCallback> mockErrorCallback;
|
||||||
|
device.SetUncapturedErrorCallback(mockErrorCallback.Callback(),
|
||||||
|
mockErrorCallback.MakeUserdata(nullptr));
|
||||||
|
EXPECT_CALL(mockErrorCallback, Call(_, _, _)).Times(Exactly(0));
|
||||||
|
device.LoseForTesting();
|
||||||
|
}
|
||||||
|
|
||||||
DAWN_INSTANTIATE_TEST(DeviceLostTest,
|
DAWN_INSTANTIATE_TEST(DeviceLostTest,
|
||||||
D3D12Backend(),
|
D3D12Backend(),
|
||||||
MetalBackend(),
|
MetalBackend(),
|
||||||
|
|
Loading…
Reference in New Issue