Don't call the uncaptured error callback after the device is lost
Bug: dawn:2459
Change-Id: I7d633e26d29b8c391be0c0376570707352a71553
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/176801
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Austin Eng <enga@chromium.org>
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index 27c74ac..89a55c9 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -581,7 +581,7 @@
void DeviceBase::HandleError(std::unique_ptr<ErrorData> error,
InternalErrorType additionalAllowedErrors,
- WGPUDeviceLostReason lost_reason) {
+ WGPUDeviceLostReason lostReason) {
AppendDebugLayerMessages(error.get());
InternalErrorType type = error->GetType();
@@ -634,13 +634,13 @@
const std::string messageStr = error->GetFormattedMessage();
if (type == InternalErrorType::DeviceLost) {
- // The device was lost, schedule the application callback's executation.
+ // The device was lost, schedule the application callback's execution.
// Note: we don't invoke the callbacks directly here because it could cause re-entrances ->
// possible deadlock.
if (mDeviceLostCallback != nullptr) {
- mCallbackTaskManager->AddCallbackTask([callback = mDeviceLostCallback, lost_reason,
+ mCallbackTaskManager->AddCallbackTask([callback = mDeviceLostCallback, lostReason,
messageStr, userdata = mDeviceLostUserdata] {
- callback(lost_reason, messageStr.c_str(), userdata);
+ callback(lostReason, messageStr.c_str(), userdata);
});
mDeviceLostCallback = nullptr;
}
@@ -658,9 +658,13 @@
// if it isn't handled. DeviceLost is not handled here because it should be
// handled by the lost callback.
bool captured = mErrorScopeStack->HandleError(ToWGPUErrorType(type), messageStr);
- if (!captured && mUncapturedErrorCallback != nullptr) {
- mUncapturedErrorCallback(static_cast<WGPUErrorType>(ToWGPUErrorType(type)),
- messageStr.c_str(), mUncapturedErrorUserdata);
+ if (!captured) {
+ // Only call the uncaptured error callback if the device is alive. After the
+ // device is lost, the uncaptured error callback should cease firing.
+ if (mUncapturedErrorCallback != nullptr && mState == State::Alive) {
+ mUncapturedErrorCallback(static_cast<WGPUErrorType>(ToWGPUErrorType(type)),
+ messageStr.c_str(), mUncapturedErrorUserdata);
+ }
}
}
}
diff --git a/src/dawn/tests/end2end/D3DResourceWrappingTests.cpp b/src/dawn/tests/end2end/D3DResourceWrappingTests.cpp
index c3ef050..b45a1d9 100644
--- a/src/dawn/tests/end2end/D3DResourceWrappingTests.cpp
+++ b/src/dawn/tests/end2end/D3DResourceWrappingTests.cpp
@@ -1051,8 +1051,8 @@
DestroyDevice();
- ASSERT_DEVICE_ERROR(WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture,
- &d3d11Texture, &externalImage));
+ WrapSharedHandle(&baseDawnDescriptor, &baseD3dDescriptor, &texture, &d3d11Texture,
+ &externalImage);
EXPECT_EQ(externalImage, nullptr);
EXPECT_EQ(texture, nullptr);
diff --git a/src/dawn/tests/end2end/DestroyTests.cpp b/src/dawn/tests/end2end/DestroyTests.cpp
index 050ddf1..4c79683 100644
--- a/src/dawn/tests/end2end/DestroyTests.cpp
+++ b/src/dawn/tests/end2end/DestroyTests.cpp
@@ -191,14 +191,14 @@
device.SetLabel(label.c_str());
}
-// Device destroy before buffer submit will result in error.
+// Test device destroy before submit.
TEST_P(DestroyTest, DestroyDeviceBeforeSubmit) {
// TODO(crbug.com/dawn/628) Add more comprehensive tests with destroy and backends.
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
wgpu::CommandBuffer commands = CreateTriangleCommandBuffer();
DestroyDevice();
- ASSERT_DEVICE_ERROR_MSG(queue.Submit(1, &commands), HasSubstr("[Device] is lost."));
+ queue.Submit(1, &commands);
}
// Regression test for crbug.com/1276928 where a lingering BGL reference in Vulkan with at least one
@@ -220,7 +220,7 @@
DestroyDevice();
wgpu::Queue queue = device.GetQueue();
- ASSERT_DEVICE_ERROR(queue.OnSubmittedWorkDone(
+ queue.OnSubmittedWorkDone(
[](WGPUQueueWorkDoneStatus status, void* userdata) {
// TODO(crbug.com/dawn/2021): Wire and native differ slightly for now. Unify once we
// decide on the correct result. In theory maybe we want to pretend that things succeed
@@ -232,7 +232,7 @@
EXPECT_EQ(status, WGPUQueueWorkDoneStatus_DeviceLost);
}
},
- this));
+ this);
}
DAWN_INSTANTIATE_TEST(DestroyTest,
diff --git a/src/dawn/tests/end2end/DeviceLostTests.cpp b/src/dawn/tests/end2end/DeviceLostTests.cpp
index db93da0..5c8ebad 100644
--- a/src/dawn/tests/end2end/DeviceLostTests.cpp
+++ b/src/dawn/tests/end2end/DeviceLostTests.cpp
@@ -63,6 +63,7 @@
}
void TearDown() override {
+ instance.ProcessEvents(); // Flush all callbacks.
mockQueueWorkDoneCallback = nullptr;
DawnTest::TearDown();
}
@@ -89,6 +90,11 @@
WaitABit();
}
}
+
+ template <typename T>
+ void ExpectObjectIsError(const T& object) {
+ EXPECT_TRUE(dawn::native::CheckIsErrorForTesting(object.Get()));
+ }
};
// Test that DeviceLostCallback is invoked when LostForTestimg is called
@@ -96,14 +102,14 @@
LoseDeviceForTesting();
}
-// Test that submit fails when device is lost
-TEST_P(DeviceLostTest, SubmitFails) {
+// Test that submit fails after the device is lost
+TEST_P(DeviceLostTest, SubmitAfterDeviceLost) {
wgpu::CommandBuffer commands;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
commands = encoder.Finish();
LoseDeviceForTesting();
- ASSERT_DEVICE_ERROR(queue.Submit(0, &commands));
+ queue.Submit(0, &commands);
}
// Test that CreateBindGroupLayout fails when device is lost
@@ -117,7 +123,7 @@
wgpu::BindGroupLayoutDescriptor descriptor;
descriptor.entryCount = 1;
descriptor.entries = &entry;
- ASSERT_DEVICE_ERROR(device.CreateBindGroupLayout(&descriptor));
+ ExpectObjectIsError(device.CreateBindGroupLayout(&descriptor));
}
// Test that GetBindGroupLayout fails when device is lost
@@ -137,7 +143,7 @@
wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&descriptor);
LoseDeviceForTesting();
- ASSERT_DEVICE_ERROR(pipeline.GetBindGroupLayout(0).Get());
+ ExpectObjectIsError(pipeline.GetBindGroupLayout(0));
}
// Test that CreateBindGroup fails when device is lost
@@ -156,7 +162,7 @@
descriptor.layout = nullptr;
descriptor.entryCount = 1;
descriptor.entries = &entry;
- ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
+ ExpectObjectIsError(device.CreateBindGroup(&descriptor));
}
// Test that CreatePipelineLayout fails when device is lost
@@ -166,7 +172,7 @@
wgpu::PipelineLayoutDescriptor descriptor;
descriptor.bindGroupLayoutCount = 0;
descriptor.bindGroupLayouts = nullptr;
- ASSERT_DEVICE_ERROR(device.CreatePipelineLayout(&descriptor));
+ ExpectObjectIsError(device.CreatePipelineLayout(&descriptor));
}
// Tests that CreateRenderBundleEncoder fails when device is lost
@@ -176,7 +182,7 @@
wgpu::RenderBundleEncoderDescriptor descriptor;
descriptor.colorFormatCount = 0;
descriptor.colorFormats = nullptr;
- ASSERT_DEVICE_ERROR(device.CreateRenderBundleEncoder(&descriptor));
+ ExpectObjectIsError(device.CreateRenderBundleEncoder(&descriptor));
}
// Tests that CreateComputePipeline fails when device is lost
@@ -186,7 +192,7 @@
wgpu::ComputePipelineDescriptor descriptor = {};
descriptor.layout = nullptr;
descriptor.compute.module = nullptr;
- ASSERT_DEVICE_ERROR(device.CreateComputePipeline(&descriptor));
+ ExpectObjectIsError(device.CreateComputePipeline(&descriptor));
}
// Tests that CreateRenderPipeline fails when device is lost
@@ -194,21 +200,21 @@
LoseDeviceForTesting();
utils::ComboRenderPipelineDescriptor descriptor;
- ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
+ ExpectObjectIsError(device.CreateRenderPipeline(&descriptor));
}
// Tests that CreateSampler fails when device is lost
TEST_P(DeviceLostTest, CreateSamplerFails) {
LoseDeviceForTesting();
- ASSERT_DEVICE_ERROR(device.CreateSampler());
+ ExpectObjectIsError(device.CreateSampler());
}
// Tests that CreateShaderModule fails when device is lost
TEST_P(DeviceLostTest, CreateShaderModuleFails) {
LoseDeviceForTesting();
- ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, R"(
+ ExpectObjectIsError(utils::CreateShaderModule(device, R"(
@fragment
fn main(@location(0) color : vec4f) -> @location(0) vec4f {
return color;
@@ -231,7 +237,7 @@
descriptor.dimension = wgpu::TextureDimension::e2D;
descriptor.usage = wgpu::TextureUsage::RenderAttachment;
- ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
+ ExpectObjectIsError(device.CreateTexture(&descriptor));
}
// Test that CreateBuffer fails when device is lost
@@ -241,7 +247,7 @@
wgpu::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = sizeof(float);
bufferDescriptor.usage = wgpu::BufferUsage::CopySrc;
- ASSERT_DEVICE_ERROR(device.CreateBuffer(&bufferDescriptor));
+ ExpectObjectIsError(device.CreateBuffer(&bufferDescriptor));
}
// Test that buffer.MapAsync for writing fails after device is lost
@@ -252,8 +258,7 @@
wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor);
LoseDeviceForTesting();
- ASSERT_DEVICE_ERROR(buffer.MapAsync(wgpu::MapMode::Write, 0, 4, MapFailCallback,
- const_cast<int*>(&fakeUserData)));
+ buffer.MapAsync(wgpu::MapMode::Write, 0, 4, MapFailCallback, const_cast<int*>(&fakeUserData));
}
// Test that BufferMapAsync for writing calls back with device lost status when device lost after
@@ -269,8 +274,8 @@
LoseDeviceForTesting();
}
-// Test that buffer.Unmap fails after device is lost
-TEST_P(DeviceLostTest, BufferUnmapFails) {
+// Test that buffer.Unmap after device is lost
+TEST_P(DeviceLostTest, BufferUnmapAfterDeviceLost) {
wgpu::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = sizeof(float);
bufferDescriptor.usage = wgpu::BufferUsage::MapWrite;
@@ -278,7 +283,7 @@
wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor);
LoseDeviceForTesting();
- ASSERT_DEVICE_ERROR(buffer.Unmap());
+ buffer.Unmap();
}
// Test that mappedAtCreation fails after device is lost
@@ -289,7 +294,7 @@
bufferDescriptor.mappedAtCreation = true;
LoseDeviceForTesting();
- ASSERT_DEVICE_ERROR(device.CreateBuffer(&bufferDescriptor));
+ ExpectObjectIsError(device.CreateBuffer(&bufferDescriptor));
}
// Test that BufferMapAsync for reading fails after device is lost
@@ -301,8 +306,7 @@
wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor);
LoseDeviceForTesting();
- ASSERT_DEVICE_ERROR(buffer.MapAsync(wgpu::MapMode::Read, 0, 4, MapFailCallback,
- const_cast<int*>(&fakeUserData)));
+ buffer.MapAsync(wgpu::MapMode::Read, 0, 4, MapFailCallback, const_cast<int*>(&fakeUserData));
}
// Test that BufferMapAsync for reading calls back with device lost status when device lost after
@@ -319,8 +323,8 @@
LoseDeviceForTesting();
}
-// Test that WriteBuffer fails after device is lost
-TEST_P(DeviceLostTest, WriteBufferFails) {
+// Test that WriteBuffer after device is lost
+TEST_P(DeviceLostTest, WriteBufferAfterDeviceLost) {
wgpu::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = sizeof(float);
bufferDescriptor.usage = wgpu::BufferUsage::MapRead | wgpu::BufferUsage::CopyDst;
@@ -329,7 +333,7 @@
LoseDeviceForTesting();
float data = 12.0f;
- ASSERT_DEVICE_ERROR(queue.WriteBuffer(buffer, 0, &data, sizeof(data)));
+ queue.WriteBuffer(buffer, 0, &data, sizeof(data));
}
// Test it's possible to GetMappedRange on a buffer created mapped after device loss
@@ -340,7 +344,8 @@
desc.size = 4;
desc.usage = wgpu::BufferUsage::CopySrc;
desc.mappedAtCreation = true;
- ASSERT_DEVICE_ERROR(wgpu::Buffer buffer = device.CreateBuffer(&desc));
+ wgpu::Buffer buffer = device.CreateBuffer(&desc);
+ ExpectObjectIsError(buffer);
ASSERT_NE(buffer.GetMappedRange(), nullptr);
}
@@ -403,17 +408,17 @@
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
LoseDeviceForTesting();
- ASSERT_DEVICE_ERROR(encoder.Finish());
+ ExpectObjectIsError(encoder.Finish());
}
-// Test that QueueOnSubmittedWorkDone fails after device is lost.
-TEST_P(DeviceLostTest, QueueOnSubmittedWorkDoneFails) {
+// Test that QueueOnSubmittedWorkDone after device is lost.
+TEST_P(DeviceLostTest, QueueOnSubmittedWorkDoneAfterDeviceLost) {
LoseDeviceForTesting();
// callback should have device lost status
EXPECT_CALL(*mockQueueWorkDoneCallback, Call(WGPUQueueWorkDoneStatus_DeviceLost, nullptr))
.Times(1);
- ASSERT_DEVICE_ERROR(queue.OnSubmittedWorkDone(ToMockQueueWorkDone, nullptr));
+ queue.OnSubmittedWorkDone(ToMockQueueWorkDone, nullptr);
}
// Test that QueueOnSubmittedWorkDone when the device is lost after calling OnSubmittedWorkDone
diff --git a/src/dawn/tests/end2end/EventTests.cpp b/src/dawn/tests/end2end/EventTests.cpp
index e1a6371..f05939c 100644
--- a/src/dawn/tests/end2end/EventTests.cpp
+++ b/src/dawn/tests/end2end/EventTests.cpp
@@ -360,14 +360,8 @@
TEST_P(EventCompletionTests, WorkDoneAfterDeviceLoss) {
TrivialSubmit();
LoseTestDevice();
- // Tracking and waiting need to be done together w.r.t the device error assertion because error
- // assertion in DawnTest.h currently calls ProcessEvents which will cause the work done event to
- // trigger before the TestWaitAll call.
- auto TestF = [&]() {
- TrackForTest(OnSubmittedWorkDone(WGPUQueueWorkDoneStatus_Success));
- TestWaitAll();
- };
- ASSERT_DEVICE_ERROR_ON(testDevice, TestF());
+ TrackForTest(OnSubmittedWorkDone(WGPUQueueWorkDoneStatus_Success));
+ TestWaitAll();
}
// WorkDone event twice after submitting some trivial work.
diff --git a/src/dawn/tests/end2end/SwapChainValidationTests.cpp b/src/dawn/tests/end2end/SwapChainValidationTests.cpp
index 6f0e6c5..a902e25 100644
--- a/src/dawn/tests/end2end/SwapChainValidationTests.cpp
+++ b/src/dawn/tests/end2end/SwapChainValidationTests.cpp
@@ -387,13 +387,13 @@
ASSERT_DEVICE_ERROR(replacedSwapChain.Present());
}
-// Test that new swap chain present fails after device is lost
-TEST_P(SwapChainValidationTests, SwapChainPresentFailsAfterDeviceLost) {
+// Test that new swap chain present after device is lost
+TEST_P(SwapChainValidationTests, SwapChainPresentAfterDeviceLost) {
wgpu::SwapChain swapchain = CreateSwapChain(surface, &goodDescriptor);
swapchain.GetCurrentTexture();
LoseDeviceForTesting();
- ASSERT_DEVICE_ERROR(swapchain.Present());
+ swapchain.Present();
}
// Test that new swap chain get current texture fails after device is lost
@@ -401,13 +401,14 @@
wgpu::SwapChain swapchain = CreateSwapChain(surface, &goodDescriptor);
LoseDeviceForTesting();
- ASSERT_DEVICE_ERROR(swapchain.GetCurrentTexture());
+ EXPECT_TRUE(dawn::native::CheckIsErrorForTesting(swapchain.GetCurrentTexture().Get()));
}
// Test that creation of a new swapchain fails after device is lost
TEST_P(SwapChainValidationTests, CreateSwapChainFailsAfterDevLost) {
LoseDeviceForTesting();
- ASSERT_DEVICE_ERROR(CreateSwapChain(surface, &goodDescriptor));
+ EXPECT_TRUE(
+ dawn::native::CheckIsErrorForTesting(CreateSwapChain(surface, &goodDescriptor).Get()));
}
DAWN_INSTANTIATE_TEST(SwapChainValidationTests, MetalBackend(), NullBackend());
diff --git a/src/dawn/tests/unittests/validation/CommandBufferValidationTests.cpp b/src/dawn/tests/unittests/validation/CommandBufferValidationTests.cpp
index 72324a5..093876f 100644
--- a/src/dawn/tests/unittests/validation/CommandBufferValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/CommandBufferValidationTests.cpp
@@ -429,21 +429,19 @@
// encoding.
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
pass.End();
- ASSERT_DEVICE_ERROR(encoder.Finish(), HasSubstr("Destroyed encoder cannot be finished."));
+ encoder.Finish();
}
// Device destroyed after encoding.
{
ExpectDeviceDestruction();
device.Destroy();
- ASSERT_DEVICE_ERROR(wgpu::CommandEncoder encoder = device.CreateCommandEncoder(),
- HasSubstr("[Device] is lost"));
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
// The encoder should not accessing any device info if device is destroyed when try
// encoding.
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&placeholderRenderPass);
pass.End();
- ASSERT_DEVICE_ERROR(encoder.Finish(),
- HasSubstr("[Invalid CommandEncoder (unlabeled)] is invalid."));
+ encoder.Finish();
}
}
diff --git a/src/dawn/tests/white_box/SharedBufferMemoryTests.cpp b/src/dawn/tests/white_box/SharedBufferMemoryTests.cpp
index 635f17d..f3ae18f 100644
--- a/src/dawn/tests/white_box/SharedBufferMemoryTests.cpp
+++ b/src/dawn/tests/white_box/SharedBufferMemoryTests.cpp
@@ -64,9 +64,7 @@
device.Destroy();
wgpu::SharedBufferMemoryDescriptor desc;
- ASSERT_DEVICE_ERROR_MSG(
- wgpu::SharedBufferMemory memory = device.ImportSharedBufferMemory(&desc),
- HasSubstr("lost"));
+ wgpu::SharedBufferMemory memory = device.ImportSharedBufferMemory(&desc);
}
// Test that SharedBufferMemory::IsDeviceLost() returns the expected value before and
diff --git a/src/dawn/tests/white_box/SharedTextureMemoryTests.cpp b/src/dawn/tests/white_box/SharedTextureMemoryTests.cpp
index cc9e1c7..db95ffe 100644
--- a/src/dawn/tests/white_box/SharedTextureMemoryTests.cpp
+++ b/src/dawn/tests/white_box/SharedTextureMemoryTests.cpp
@@ -735,14 +735,29 @@
EXPECT_EQ(exportInfo.type, wgpu::SharedFenceType::Undefined);
}
-// Test that it is an error to import a shared texture memory when the device is destroyed
+// Test importing a shared texture memory when the device is destroyed
TEST_P(SharedTextureMemoryTests, ImportSharedTextureMemoryDeviceDestroyed) {
device.Destroy();
- wgpu::SharedTextureMemoryDescriptor desc;
- ASSERT_DEVICE_ERROR_MSG(
- wgpu::SharedTextureMemory memory = device.ImportSharedTextureMemory(&desc),
- HasSubstr("lost"));
+ wgpu::SharedTextureMemory memory;
+ if (GetParam().mBackend->Name().rfind("OpaqueFD", 0) == 0) {
+ // The OpaqueFD backend for `CreateSharedTextureMemory` uses several
+ // Vulkan device internals before and after the actual call to
+ // ImportSharedTextureMemory. We can't easily make it import with
+ // a destroyed device, so create the SharedTextureMemory with
+ // an invalid descriptor instead. This still tests that an uncaptured
+ // error is not generated on the import call when the device is lost.
+ wgpu::SharedTextureMemoryDescriptor desc;
+ memory = device.ImportSharedTextureMemory(&desc);
+ } else {
+ memory = GetParam().mBackend->CreateSharedTextureMemory(device);
+ }
+
+ wgpu::SharedTextureMemoryBeginAccessDescriptor beginDesc = {};
+ beginDesc.concurrentRead = false;
+ beginDesc.initialized = true;
+ // That the begin access does not succeed since the device is destroyed.
+ EXPECT_FALSE(memory.BeginAccess(memory.CreateTexture(), &beginDesc));
}
// Test that SharedTextureMemory::IsDeviceLost() returns the expected value before and
@@ -765,13 +780,61 @@
EXPECT_TRUE(memory.IsDeviceLost());
}
-// Test that it is an error to import a shared fence when the device is destroyed
+// Test importing a shared fence when the device is destroyed
TEST_P(SharedTextureMemoryTests, ImportSharedFenceDeviceDestroyed) {
+ // Create a shared texture memory and texture
+ wgpu::SharedTextureMemory memory = GetParam().mBackend->CreateSharedTextureMemory(device);
+ wgpu::Texture texture = memory.CreateTexture();
+
+ // Begin access to use the texture
+ wgpu::SharedTextureMemoryBeginAccessDescriptor beginDesc = {};
+ beginDesc.concurrentRead = false;
+ beginDesc.initialized = true;
+ auto backendBeginState = GetParam().mBackend->ChainInitialBeginState(&beginDesc);
+ EXPECT_TRUE(memory.BeginAccess(texture, &beginDesc));
+
+ // Use the texture so there is a fence to export on end access.
+ wgpu::SharedTextureMemoryProperties properties;
+ memory.GetProperties(&properties);
+ if (properties.usage & wgpu::TextureUsage::RenderAttachment) {
+ UseInRenderPass(device, texture);
+ } else if (properties.format != wgpu::TextureFormat::R8BG8Biplanar420Unorm &&
+ properties.format != wgpu::TextureFormat::R10X6BG10X6Biplanar420Unorm &&
+ properties.format != wgpu::TextureFormat::R8BG8A8Triplanar420Unorm) {
+ if (properties.usage & wgpu::TextureUsage::CopySrc) {
+ UseInCopy(device, texture);
+ } else if (properties.usage & wgpu::TextureUsage::CopyDst) {
+ wgpu::Extent3D writeSize = {1, 1, 1};
+ wgpu::ImageCopyTexture dest = {};
+ dest.texture = texture;
+ wgpu::TextureDataLayout dataLayout = {};
+ uint64_t data[2];
+ device.GetQueue().WriteTexture(&dest, &data, sizeof(data), &dataLayout, &writeSize);
+ }
+ }
+
+ // End access to export a fence.
+ wgpu::SharedTextureMemoryEndAccessState endState = {};
+ auto backendEndState = GetParam().mBackend->ChainEndState(&endState);
+ EXPECT_TRUE(memory.EndAccess(texture, &endState));
+
+ // Destroy the device.
device.Destroy();
- wgpu::SharedFenceDescriptor desc;
- ASSERT_DEVICE_ERROR_MSG(wgpu::SharedFence fence = device.ImportSharedFence(&desc),
- HasSubstr("lost"));
+ // Import the shared fence to the destroyed device.
+ std::vector<wgpu::SharedFence> sharedFences(endState.fenceCount);
+ for (size_t i = 0; i < endState.fenceCount; ++i) {
+ sharedFences[i] = GetParam().mBackend->ImportFenceTo(device, endState.fences[i]);
+ }
+ beginDesc.fenceCount = endState.fenceCount;
+ beginDesc.fences = sharedFences.data();
+ beginDesc.signaledValues = endState.signaledValues;
+ beginDesc.concurrentRead = false;
+ beginDesc.initialized = endState.initialized;
+ backendBeginState = GetParam().mBackend->ChainBeginState(&beginDesc, endState);
+
+ // Begin access should fail.
+ EXPECT_FALSE(memory.BeginAccess(texture, &beginDesc));
}
// Test calling GetProperties with an error memory. The properties are filled with 0/None/Undefined.