diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp index a0afaf52b9..84a9c3a500 100644 --- a/src/dawn/native/Device.cpp +++ b/src/dawn/native/Device.cpp @@ -308,6 +308,10 @@ void DeviceBase::WillDropLastExternalRef() { // out all remaining refs. Destroy(); + // Drop te device's reference to the queue. Because the application dropped the last external + // references, they can no longer get the queue from APIGetQueue(). + mQueue = nullptr; + // Reset callbacks since after this, since after dropping the last external reference, the // application may have freed any device-scope memory needed to run the callback. mUncapturedErrorCallback = [](WGPUErrorType, char const* message, void*) { @@ -454,11 +458,12 @@ void DeviceBase::Destroy() { // implementations of DestroyImpl checks that we are disconnected before doing work. mState = State::Disconnected; + // Note: mQueue is not released here since the application may still get it after calling + // Destroy() via APIGetQueue. mDynamicUploader = nullptr; mEmptyBindGroupLayout = nullptr; mInternalPipelineStore = nullptr; mExternalTexturePlaceholderView = nullptr; - mQueue = nullptr; AssumeCommandsComplete(); diff --git a/src/dawn/tests/end2end/DestroyTests.cpp b/src/dawn/tests/end2end/DestroyTests.cpp index 89450cfafd..7b46a23532 100644 --- a/src/dawn/tests/end2end/DestroyTests.cpp +++ b/src/dawn/tests/end2end/DestroyTests.cpp @@ -190,6 +190,20 @@ TEST_P(DestroyTest, DestroyDeviceLingeringBGL) { DestroyDevice(); } +// Regression test for crbug.com/1327865 where the device set the queue to null +// inside Destroy() such that it could no longer return it to a call to GetQueue(). +TEST_P(DestroyTest, GetQueueAfterDeviceDestroy) { + DestroyDevice(); + + wgpu::Queue queue = device.GetQueue(); + ASSERT_DEVICE_ERROR(queue.OnSubmittedWorkDone( + 0u, + [](WGPUQueueWorkDoneStatus status, void* userdata) { + EXPECT_EQ(status, WGPUQueueWorkDoneStatus_DeviceLost); + }, + nullptr)); +} + DAWN_INSTANTIATE_TEST(DestroyTest, D3D12Backend(), MetalBackend(),