Immediately call fence and map callbacks on device loss.

This is more in line with what happens in dawn_wire and Blink's WebGPU
implementation. It also allows fixing the Fence-related DeviceLost tests
to destroy the mock fence callback on destruction, which in turns fixes
a crash on dawn_end2end_tests exit on MSVC x64 debug.

Bug: dawn:602

Change-Id: I277e7fa284a573854ed46576602d5f6819db1357
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/38526
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Auto-Submit: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Corentin Wallez 2021-01-27 15:54:12 +00:00 committed by Commit Bot service account
parent 2df77f4325
commit c1d3a66bd2
8 changed files with 29 additions and 15 deletions

View File

@ -35,7 +35,10 @@ namespace dawn_native {
: buffer(std::move(buffer)), id(id) { : buffer(std::move(buffer)), id(id) {
} }
void Finish() override { void Finish() override {
buffer->OnMapRequestCompleted(id); buffer->OnMapRequestCompleted(id, WGPUBufferMapAsyncStatus_Success);
}
void HandleDeviceLoss() override {
buffer->OnMapRequestCompleted(id, WGPUBufferMapAsyncStatus_DeviceLost);
} }
~MapRequestTask() override = default; ~MapRequestTask() override = default;
@ -537,8 +540,8 @@ namespace dawn_native {
mState = BufferState::Destroyed; mState = BufferState::Destroyed;
} }
void BufferBase::OnMapRequestCompleted(MapRequestID mapID) { void BufferBase::OnMapRequestCompleted(MapRequestID mapID, WGPUBufferMapAsyncStatus status) {
CallMapCallback(mapID, WGPUBufferMapAsyncStatus_Success); CallMapCallback(mapID, status);
} }
bool BufferBase::IsDataInitialized() const { bool BufferBase::IsDataInitialized() const {

View File

@ -53,7 +53,7 @@ namespace dawn_native {
wgpu::BufferUsage GetUsage() const; wgpu::BufferUsage GetUsage() const;
MaybeError MapAtCreation(); MaybeError MapAtCreation();
void OnMapRequestCompleted(MapRequestID mapID); void OnMapRequestCompleted(MapRequestID mapID, WGPUBufferMapAsyncStatus status);
MaybeError ValidateCanUseOnQueueNow() const; MaybeError ValidateCanUseOnQueueNow() const;

View File

@ -240,6 +240,8 @@ namespace dawn_native {
// The device was lost, call the application callback. // The device was lost, call the application callback.
if (type == InternalErrorType::DeviceLost && mDeviceLostCallback != nullptr) { if (type == InternalErrorType::DeviceLost && mDeviceLostCallback != nullptr) {
mDefaultQueue->HandleDeviceLoss();
mDeviceLostCallback(message, mDeviceLostUserdata); mDeviceLostCallback(message, mDeviceLostUserdata);
mDeviceLostCallback = nullptr; mDeviceLostCallback = nullptr;
} }

View File

@ -28,7 +28,10 @@ namespace dawn_native {
: fence(std::move(fence)), value(value) { : fence(std::move(fence)), value(value) {
} }
void Finish() override { void Finish() override {
fence->SetCompletedValue(value); fence->SetCompletedValue(value, WGPUFenceCompletionStatus_Success);
}
void HandleDeviceLoss() override {
fence->SetCompletedValue(value, WGPUFenceCompletionStatus_DeviceLost);
} }
~FenceInFlight() override = default; ~FenceInFlight() override = default;
@ -116,18 +119,14 @@ namespace dawn_native {
mSignalValue = signalValue; mSignalValue = signalValue;
} }
void Fence::SetCompletedValue(FenceAPISerial completedValue) { void Fence::SetCompletedValue(FenceAPISerial completedValue, WGPUFenceCompletionStatus status) {
ASSERT(!IsError()); ASSERT(!IsError());
ASSERT(completedValue <= mSignalValue); ASSERT(completedValue <= mSignalValue);
ASSERT(completedValue > mCompletedValue); ASSERT(completedValue > mCompletedValue);
mCompletedValue = completedValue; mCompletedValue = completedValue;
for (auto& request : mRequests.IterateUpTo(mCompletedValue)) { for (auto& request : mRequests.IterateUpTo(mCompletedValue)) {
if (GetDevice()->IsLost()) { request.completionCallback(status, request.userdata);
request.completionCallback(WGPUFenceCompletionStatus_DeviceLost, request.userdata);
} else {
request.completionCallback(WGPUFenceCompletionStatus_Success, request.userdata);
}
} }
mRequests.ClearUpTo(mCompletedValue); mRequests.ClearUpTo(mCompletedValue);
} }

View File

@ -46,7 +46,7 @@ namespace dawn_native {
friend class QueueBase; friend class QueueBase;
friend struct FenceInFlight; friend struct FenceInFlight;
void SetSignaledValue(FenceAPISerial signalValue); void SetSignaledValue(FenceAPISerial signalValue);
void SetCompletedValue(FenceAPISerial completedValue); void SetCompletedValue(FenceAPISerial completedValue, WGPUFenceCompletionStatus status);
void UpdateFenceOnComplete(Fence* fence, FenceAPISerial value); void UpdateFenceOnComplete(Fence* fence, FenceAPISerial value);
private: private:

View File

@ -192,6 +192,13 @@ namespace dawn_native {
mTasksInFlight.ClearUpTo(finishedSerial); mTasksInFlight.ClearUpTo(finishedSerial);
} }
void QueueBase::HandleDeviceLoss() {
for (auto& task : mTasksInFlight.IterateAll()) {
task->HandleDeviceLoss();
}
mTasksInFlight.Clear();
}
Fence* QueueBase::CreateFence(const FenceDescriptor* descriptor) { Fence* QueueBase::CreateFence(const FenceDescriptor* descriptor) {
if (GetDevice()->ConsumedError(ValidateCreateFence(descriptor))) { if (GetDevice()->ConsumedError(ValidateCreateFence(descriptor))) {
return Fence::MakeError(GetDevice()); return Fence::MakeError(GetDevice());

View File

@ -30,6 +30,7 @@ namespace dawn_native {
struct TaskInFlight { struct TaskInFlight {
virtual ~TaskInFlight(); virtual ~TaskInFlight();
virtual void Finish() = 0; virtual void Finish() = 0;
virtual void HandleDeviceLoss() = 0;
}; };
static QueueBase* MakeError(DeviceBase* device); static QueueBase* MakeError(DeviceBase* device);
@ -52,6 +53,7 @@ namespace dawn_native {
void TrackTask(std::unique_ptr<TaskInFlight> task, ExecutionSerial serial); void TrackTask(std::unique_ptr<TaskInFlight> task, ExecutionSerial serial);
void Tick(ExecutionSerial finishedSerial); void Tick(ExecutionSerial finishedSerial);
void HandleDeviceLoss();
protected: protected:
QueueBase(DeviceBase* device); QueueBase(DeviceBase* device);

View File

@ -65,6 +65,7 @@ class DeviceLostTest : public DawnTest {
void TearDown() override { void TearDown() override {
mockDeviceLostCallback = nullptr; mockDeviceLostCallback = nullptr;
mockFenceOnCompletionCallback = nullptr;
DawnTest::TearDown(); DawnTest::TearDown();
} }
@ -449,8 +450,8 @@ TEST_P(DeviceLostTest, FenceOnCompletionFails) {
ASSERT_DEVICE_ERROR(fence.OnCompletion(2u, ToMockFenceOnCompletionFails, nullptr)); ASSERT_DEVICE_ERROR(fence.OnCompletion(2u, ToMockFenceOnCompletionFails, nullptr));
ASSERT_DEVICE_ERROR(device.Tick()); ASSERT_DEVICE_ERROR(device.Tick());
// completed value should not have changed from initial value // completed value is the last value signaled (all previous GPU operations are as if completed)
EXPECT_EQ(fence.GetCompletedValue(), 0u); EXPECT_EQ(fence.GetCompletedValue(), 2u);
} }
// Test that Fence::OnCompletion callbacks with device lost status when device is lost after calling // Test that Fence::OnCompletion callbacks with device lost status when device is lost after calling
@ -469,7 +470,7 @@ TEST_P(DeviceLostTest, FenceOnCompletionBeforeLossFails) {
SetCallbackAndLoseForTesting(); SetCallbackAndLoseForTesting();
ASSERT_DEVICE_ERROR(device.Tick()); ASSERT_DEVICE_ERROR(device.Tick());
EXPECT_EQ(fence.GetCompletedValue(), 0u); EXPECT_EQ(fence.GetCompletedValue(), 2u);
} }
// Regression test for the Null backend not properly setting the completedSerial when // Regression test for the Null backend not properly setting the completedSerial when