From 04912aa83674a836cd8faab856246c8a4ceb8553 Mon Sep 17 00:00:00 2001 From: Loko Kung Date: Thu, 28 Apr 2022 21:55:33 +0000 Subject: [PATCH] Add multiple device testing capability in DawnTest. - Factors out device creation code to helper. - Updates callbacks and test infra to support different devices and use mock callbacks. - Updates some tests that were using outdated device lost callbacks and multiple devices. Change-Id: I4210280420b8dadbc6355d27995ccf0cd864108c Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/87480 Reviewed-by: Austin Eng Commit-Queue: Loko Kung Kokoro: Kokoro --- src/dawn/tests/DawnTest.cpp | 177 +++++++++--------- src/dawn/tests/DawnTest.h | 46 +++-- .../end2end/CreatePipelineAsyncTests.cpp | 6 +- src/dawn/tests/end2end/DestroyTests.cpp | 10 +- src/dawn/tests/end2end/DeviceLostTests.cpp | 120 +++++------- src/dawn/tests/end2end/SwapChainTests.cpp | 2 +- .../end2end/SwapChainValidationTests.cpp | 18 +- 7 files changed, 171 insertions(+), 208 deletions(-) diff --git a/src/dawn/tests/DawnTest.cpp b/src/dawn/tests/DawnTest.cpp index cfc1b38f24..668bd9b2d9 100644 --- a/src/dawn/tests/DawnTest.cpp +++ b/src/dawn/tests/DawnTest.cpp @@ -30,6 +30,7 @@ #include "dawn/common/Platform.h" #include "dawn/common/SystemUtils.h" #include "dawn/dawn_proc.h" +#include "dawn/native/Device.h" #include "dawn/native/Instance.h" #include "dawn/native/dawn_platform.h" #include "dawn/utils/ComboRenderPipelineDescriptor.h" @@ -903,31 +904,9 @@ bool DawnTestBase::SupportsFeatures(const std::vector& featur return true; } -void DawnTestBase::SetUp() { - { - // Find the adapter that exactly matches our adapter properties. - const auto& adapters = gTestEnv->GetInstance()->GetAdapters(); - const auto& it = std::find_if( - adapters.begin(), adapters.end(), [&](const dawn::native::Adapter& adapter) { - wgpu::AdapterProperties properties; - adapter.GetProperties(&properties); - - return (mParam.adapterProperties.selected && - properties.deviceID == mParam.adapterProperties.deviceID && - properties.vendorID == mParam.adapterProperties.vendorID && - properties.adapterType == mParam.adapterProperties.adapterType && - properties.backendType == mParam.adapterProperties.backendType && - strcmp(properties.name, mParam.adapterProperties.adapterName.c_str()) == 0); - }); - ASSERT(it != adapters.end()); - mBackendAdapter = *it; - } - - // Setup the per-test platform. Tests can provide one by overloading CreateTestPlatform. This is - // NOT a thread-safe operation and is allowed here for testing only. - mTestPlatform = CreateTestPlatform(); - dawn::native::FromAPI(gTestEnv->GetInstance()->Get()) - ->SetPlatformForTesting(mTestPlatform.get()); +std::pair DawnTestBase::CreateDeviceImpl(std::string isolationKey) { + // TODO(dawn:1399) Always flush wire before creating to avoid reuse of the same handle. + FlushWire(); // Create the device from the adapter for (const char* forceEnabledWorkaround : mParam.forceEnabledWorkarounds) { @@ -975,30 +954,16 @@ void DawnTestBase::SetUp() { togglesDesc.forceDisabledToggles = forceDisabledToggles.data(); togglesDesc.forceDisabledTogglesCount = forceDisabledToggles.size(); - std::tie(device, backendDevice) = - mWireHelper->RegisterDevice(mBackendAdapter.CreateDevice(&deviceDescriptor)); - ASSERT_NE(nullptr, backendDevice); - - std::string traceName = - std::string(::testing::UnitTest::GetInstance()->current_test_info()->test_suite_name()) + - "_" + ::testing::UnitTest::GetInstance()->current_test_info()->name(); - mWireHelper->BeginWireTrace(traceName.c_str()); - - queue = device.GetQueue(); - - device.SetUncapturedErrorCallback(OnDeviceError, this); - device.SetDeviceLostCallback(OnDeviceLost, this); -#if defined(DAWN_ENABLE_BACKEND_DESKTOP_GL) - if (IsOpenGL()) { - glfwMakeContextCurrent(gTestEnv->GetOpenGLWindow()); - } -#endif // defined(DAWN_ENABLE_BACKEND_DESKTOP_GL) -#if defined(DAWN_ENABLE_BACKEND_OPENGLES) - if (IsOpenGLES()) { - glfwMakeContextCurrent(gTestEnv->GetOpenGLESWindow()); - } -#endif // defined(DAWN_ENABLE_BACKEND_OPENGLES) + wgpu::DawnCacheDeviceDescriptor cacheDesc = {}; + togglesDesc.nextInChain = &cacheDesc; + cacheDesc.isolationKey = isolationKey.c_str(); + auto devices = mWireHelper->RegisterDevice(mBackendAdapter.CreateDevice(&deviceDescriptor)); + wgpu::Device device = devices.first; + device.SetUncapturedErrorCallback(mDeviceErrorCallback.Callback(), + mDeviceErrorCallback.MakeUserdata(device.Get())); + device.SetDeviceLostCallback(mDeviceLostCallback.Callback(), + mDeviceLostCallback.MakeUserdata(device.Get())); device.SetLoggingCallback( [](WGPULoggingType type, char const* message, void*) { switch (type) { @@ -1017,6 +982,60 @@ void DawnTestBase::SetUp() { } }, nullptr); + return devices; +} + +wgpu::Device DawnTestBase::CreateDevice(std::string isolationKey) { + return CreateDeviceImpl(isolationKey).first; +} + +void DawnTestBase::SetUp() { + { + // Find the adapter that exactly matches our adapter properties. + const auto& adapters = gTestEnv->GetInstance()->GetAdapters(); + const auto& it = std::find_if( + adapters.begin(), adapters.end(), [&](const dawn::native::Adapter& adapter) { + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + + return (mParam.adapterProperties.selected && + properties.deviceID == mParam.adapterProperties.deviceID && + properties.vendorID == mParam.adapterProperties.vendorID && + properties.adapterType == mParam.adapterProperties.adapterType && + properties.backendType == mParam.adapterProperties.backendType && + strcmp(properties.name, mParam.adapterProperties.adapterName.c_str()) == 0); + }); + ASSERT(it != adapters.end()); + mBackendAdapter = *it; + } + + // Setup the per-test platform. Tests can provide one by overloading CreateTestPlatform. This is + // NOT a thread-safe operation and is allowed here for testing only. + mTestPlatform = CreateTestPlatform(); + dawn::native::FromAPI(gTestEnv->GetInstance()->Get()) + ->SetPlatformForTesting(mTestPlatform.get()); + + std::string traceName = + std::string(::testing::UnitTest::GetInstance()->current_test_info()->test_suite_name()) + + "_" + ::testing::UnitTest::GetInstance()->current_test_info()->name(); + mWireHelper->BeginWireTrace(traceName.c_str()); + + // Create the device from the adapter + std::tie(device, backendDevice) = CreateDeviceImpl(); + ASSERT_NE(nullptr, backendDevice); + + queue = device.GetQueue(); + +#if defined(DAWN_ENABLE_BACKEND_DESKTOP_GL) + if (IsOpenGL()) { + glfwMakeContextCurrent(gTestEnv->GetOpenGLWindow()); + } +#endif // defined(DAWN_ENABLE_BACKEND_DESKTOP_GL) +#if defined(DAWN_ENABLE_BACKEND_OPENGLES) + if (IsOpenGLES()) { + glfwMakeContextCurrent(gTestEnv->GetOpenGLESWindow()); + } +#endif // defined(DAWN_ENABLE_BACKEND_OPENGLES) } void DawnTestBase::TearDown() { @@ -1033,50 +1052,36 @@ void DawnTestBase::TearDown() { EXPECT_EQ(mLastWarningCount, dawn::native::GetDeprecationWarningCountForTesting(device.Get())); } - - // The device will be destroyed soon after, so we want to set the expectation. - ExpectDeviceDestruction(); } -void DawnTestBase::StartExpectDeviceError(testing::Matcher errorMatcher) { - mExpectError = true; - mError = false; - mErrorMatcher = errorMatcher; -} - -bool DawnTestBase::EndExpectDeviceError() { - mExpectError = false; - mErrorMatcher = testing::_; - return mError; -} - -void DawnTestBase::ExpectDeviceDestruction() { - mExpectDestruction = true; -} - -// static -void DawnTestBase::OnDeviceError(WGPUErrorType type, const char* message, void* userdata) { - ASSERT(type != WGPUErrorType_NoError); - DawnTestBase* self = static_cast(userdata); - - ASSERT_TRUE(self->mExpectError) << "Got unexpected device error: " << message; - ASSERT_FALSE(self->mError) << "Got two errors in expect block"; - if (self->mExpectError) { - ASSERT_THAT(message, self->mErrorMatcher); +void DawnTestBase::DestroyDevice(wgpu::Device device) { + wgpu::Device resolvedDevice; + if (device != nullptr) { + resolvedDevice = device; + } else { + resolvedDevice = this->device; } - self->mError = true; + EXPECT_CALL(mDeviceLostCallback, + Call(WGPUDeviceLostReason_Destroyed, testing::_, resolvedDevice.Get())) + .Times(1); + resolvedDevice.Destroy(); + FlushWire(); + testing::Mock::VerifyAndClearExpectations(&mDeviceLostCallback); } -void DawnTestBase::OnDeviceLost(WGPUDeviceLostReason reason, const char* message, void* userdata) { - DawnTestBase* self = static_cast(userdata); - if (self->mExpectDestruction) { - EXPECT_EQ(reason, WGPUDeviceLostReason_Destroyed); - return; +void DawnTestBase::LoseDeviceForTesting(wgpu::Device device) { + wgpu::Device resolvedDevice; + if (device != nullptr) { + resolvedDevice = device; + } else { + resolvedDevice = this->device; } - // Using ADD_FAILURE + ASSERT instead of FAIL to prevent the current test from continuing with a - // corrupt state. - ADD_FAILURE() << "Device lost during test: " << message; - ASSERT(false); + EXPECT_CALL(mDeviceLostCallback, + Call(WGPUDeviceLostReason_Undefined, testing::_, resolvedDevice.Get())) + .Times(1); + resolvedDevice.LoseForTesting(); + FlushWire(); + testing::Mock::VerifyAndClearExpectations(&mDeviceLostCallback); } std::ostringstream& DawnTestBase::AddBufferExpectation(const char* file, diff --git a/src/dawn/tests/DawnTest.h b/src/dawn/tests/DawnTest.h index f171c68ef2..d389b592eb 100644 --- a/src/dawn/tests/DawnTest.h +++ b/src/dawn/tests/DawnTest.h @@ -27,6 +27,7 @@ #include "dawn/dawn_proc_table.h" #include "dawn/native/DawnNative.h" #include "dawn/platform/DawnPlatform.h" +#include "dawn/tests/MockCallback.h" #include "dawn/tests/ParamGenerator.h" #include "dawn/tests/ToggleParser.h" #include "dawn/utils/ScopedAutoreleasePool.h" @@ -100,16 +101,22 @@ #define EXPECT_TEXTURE_FLOAT16_EQ(...) \ AddTextureExpectation(__FILE__, __LINE__, __VA_ARGS__) -#define ASSERT_DEVICE_ERROR_MSG(statement, matcher) \ - StartExpectDeviceError(matcher); \ - statement; \ - FlushWire(); \ - if (!EndExpectDeviceError()) { \ - FAIL() << "Expected device error in:\n " << #statement; \ - } \ - do { \ +#define ASSERT_DEVICE_ERROR_MSG_ON(device, statement, matcher) \ + FlushWire(); \ + EXPECT_CALL(mDeviceErrorCallback, \ + Call(testing::Ne(WGPUErrorType_NoError), matcher, device.Get())); \ + statement; \ + FlushWire(); \ + testing::Mock::VerifyAndClearExpectations(&mDeviceErrorCallback); \ + do { \ } while (0) +#define ASSERT_DEVICE_ERROR_MSG(statement, matcher) \ + ASSERT_DEVICE_ERROR_MSG_ON(this->device, statement, matcher) + +#define ASSERT_DEVICE_ERROR_ON(device, statement) \ + ASSERT_DEVICE_ERROR_MSG_ON(device, statement, testing::_) + #define ASSERT_DEVICE_ERROR(statement) ASSERT_DEVICE_ERROR_MSG(statement, testing::_) struct RGBA8 { @@ -311,10 +318,8 @@ class DawnTestBase { bool HasToggleEnabled(const char* workaround) const; - void StartExpectDeviceError(testing::Matcher errorMatcher = testing::_); - bool EndExpectDeviceError(); - - void ExpectDeviceDestruction(); + void DestroyDevice(wgpu::Device device = nullptr); + void LoseDeviceForTesting(wgpu::Device device = nullptr); bool HasVendorIdFilter() const; uint32_t GetVendorIdFilter() const; @@ -348,6 +353,11 @@ class DawnTestBase { size_t mLastWarningCount = 0; + // Mock callbacks tracking errors and destruction. Device lost is a nice mock since tests that + // do not care about device destruction can ignore the callback entirely. + testing::MockCallback mDeviceErrorCallback; + testing::NiceMock> mDeviceLostCallback; + // Helper methods to implement the EXPECT_ macros std::ostringstream& AddBufferExpectation(const char* file, int line, @@ -512,6 +522,9 @@ class DawnTestBase { bool SupportsFeatures(const std::vector& features); + // Exposed device creation helper for tests to use when needing more than 1 device. + wgpu::Device CreateDevice(std::string isolationKey = ""); + // Called in SetUp() to get the features required to be enabled in the tests. The tests must // check if the required features are supported by the adapter in this function and guarantee // the returned features are all supported by the adapter. The tests may provide different @@ -532,13 +545,8 @@ class DawnTestBase { AdapterTestParam mParam; std::unique_ptr mWireHelper; - // Tracking for validation errors - static void OnDeviceError(WGPUErrorType type, const char* message, void* userdata); - static void OnDeviceLost(WGPUDeviceLostReason reason, const char* message, void* userdata); - bool mExpectError = false; - bool mError = false; - testing::Matcher mErrorMatcher; - bool mExpectDestruction = false; + // Internal device creation function for default device creation with some optional overrides. + std::pair CreateDeviceImpl(std::string isolationKey = ""); std::ostringstream& AddTextureExpectationImpl(const char* file, int line, diff --git a/src/dawn/tests/end2end/CreatePipelineAsyncTests.cpp b/src/dawn/tests/end2end/CreatePipelineAsyncTests.cpp index f7e4c29ecf..60bce944f8 100644 --- a/src/dawn/tests/end2end/CreatePipelineAsyncTests.cpp +++ b/src/dawn/tests/end2end/CreatePipelineAsyncTests.cpp @@ -440,8 +440,7 @@ TEST_P(CreatePipelineAsyncTest, DestroyDeviceBeforeCallbackOfCreateComputePipeli task->message = message; }, &task); - ExpectDeviceDestruction(); - device.Destroy(); + DestroyDevice(); } // Verify there is no error when the device is destroyed before the callback of @@ -474,8 +473,7 @@ TEST_P(CreatePipelineAsyncTest, DestroyDeviceBeforeCallbackOfCreateRenderPipelin task->message = message; }, &task); - ExpectDeviceDestruction(); - device.Destroy(); + DestroyDevice(); } // Verify the code path of CreateComputePipelineAsync() to directly return the compute pipeline diff --git a/src/dawn/tests/end2end/DestroyTests.cpp b/src/dawn/tests/end2end/DestroyTests.cpp index 9bd66e7ddb..89450cfafd 100644 --- a/src/dawn/tests/end2end/DestroyTests.cpp +++ b/src/dawn/tests/end2end/DestroyTests.cpp @@ -173,10 +173,7 @@ TEST_P(DestroyTest, DestroyDeviceBeforeSubmit) { DAWN_TEST_UNSUPPORTED_IF(UsesWire()); wgpu::CommandBuffer commands = CreateTriangleCommandBuffer(); - // Tests normally don't expect a device lost error, but since we are destroying the device, we - // actually do, so we need to override the default device lost callback. - ExpectDeviceDestruction(); - device.Destroy(); + DestroyDevice(); ASSERT_DEVICE_ERROR_MSG(queue.Submit(1, &commands), HasSubstr("[Device] is lost.")); } @@ -190,10 +187,7 @@ TEST_P(DestroyTest, DestroyDeviceLingeringBGL) { device, {{0, wgpu::ShaderStage::Fragment, wgpu::SamplerBindingType::Filtering}}); utils::MakeBindGroup(device, layout, {{0, device.CreateSampler()}}); - // Tests normally don't expect a device lost error, but since we are destroying the device, we - // actually do, so we need to override the default device lost callback. - ExpectDeviceDestruction(); - device.Destroy(); + DestroyDevice(); } DAWN_INSTANTIATE_TEST(DestroyTest, diff --git a/src/dawn/tests/end2end/DeviceLostTests.cpp b/src/dawn/tests/end2end/DeviceLostTests.cpp index 853807d403..7dfff521ff 100644 --- a/src/dawn/tests/end2end/DeviceLostTests.cpp +++ b/src/dawn/tests/end2end/DeviceLostTests.cpp @@ -26,20 +26,6 @@ using testing::_; using testing::Exactly; using testing::MockCallback; -class MockDeviceLostCallback { - public: - MOCK_METHOD(void, Call, (WGPUDeviceLostReason reason, const char* message, void* userdata)); -}; - -static std::unique_ptr mockDeviceLostCallback; -static void ToMockDeviceLostCallback(WGPUDeviceLostReason reason, - const char* message, - void* userdata) { - mockDeviceLostCallback->Call(reason, message, userdata); - DawnTestBase* self = static_cast(userdata); - self->StartExpectDeviceError(); -} - class MockQueueWorkDoneCallback { public: MOCK_METHOD(void, Call, (WGPUQueueWorkDoneStatus status, void* userdata)); @@ -57,26 +43,14 @@ class DeviceLostTest : public DawnTest { void SetUp() override { DawnTest::SetUp(); DAWN_TEST_UNSUPPORTED_IF(UsesWire()); - mockDeviceLostCallback = std::make_unique(); mockQueueWorkDoneCallback = std::make_unique(); - // SetDeviceLostCallback will trigger the callback task manager and clean all deferred - // callback tasks, so it should be called at the beginning of each test to prevent - // unexpectedly triggering callback tasks created during test - device.SetDeviceLostCallback(ToMockDeviceLostCallback, this); } void TearDown() override { - mockDeviceLostCallback = nullptr; mockQueueWorkDoneCallback = nullptr; DawnTest::TearDown(); } - void LoseForTesting() { - EXPECT_CALL(*mockDeviceLostCallback, Call(WGPUDeviceLostReason_Undefined, _, this)) - .Times(1); - device.LoseForTesting(); - } - static void MapFailCallback(WGPUBufferMapAsyncStatus status, void* userdata) { EXPECT_EQ(WGPUBufferMapAsyncStatus_DeviceLost, status); EXPECT_EQ(&fakeUserData, userdata); @@ -85,7 +59,7 @@ class DeviceLostTest : public DawnTest { // Test that DeviceLostCallback is invoked when LostForTestimg is called TEST_P(DeviceLostTest, DeviceLostCallbackIsCalled) { - LoseForTesting(); + LoseDeviceForTesting(); } // Test that submit fails when device is lost @@ -94,13 +68,13 @@ TEST_P(DeviceLostTest, SubmitFails) { wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); commands = encoder.Finish(); - LoseForTesting(); + LoseDeviceForTesting(); ASSERT_DEVICE_ERROR(queue.Submit(0, &commands)); } // Test that CreateBindGroupLayout fails when device is lost TEST_P(DeviceLostTest, CreateBindGroupLayoutFails) { - LoseForTesting(); + LoseDeviceForTesting(); wgpu::BindGroupLayoutEntry entry; entry.binding = 0; @@ -129,13 +103,13 @@ TEST_P(DeviceLostTest, GetBindGroupLayoutFails) { wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&descriptor); - LoseForTesting(); + LoseDeviceForTesting(); ASSERT_DEVICE_ERROR(pipeline.GetBindGroupLayout(0).Get()); } // Test that CreateBindGroup fails when device is lost TEST_P(DeviceLostTest, CreateBindGroupFails) { - LoseForTesting(); + LoseDeviceForTesting(); wgpu::BindGroupEntry entry; entry.binding = 0; @@ -154,7 +128,7 @@ TEST_P(DeviceLostTest, CreateBindGroupFails) { // Test that CreatePipelineLayout fails when device is lost TEST_P(DeviceLostTest, CreatePipelineLayoutFails) { - LoseForTesting(); + LoseDeviceForTesting(); wgpu::PipelineLayoutDescriptor descriptor; descriptor.bindGroupLayoutCount = 0; @@ -164,7 +138,7 @@ TEST_P(DeviceLostTest, CreatePipelineLayoutFails) { // Tests that CreateRenderBundleEncoder fails when device is lost TEST_P(DeviceLostTest, CreateRenderBundleEncoderFails) { - LoseForTesting(); + LoseDeviceForTesting(); wgpu::RenderBundleEncoderDescriptor descriptor; descriptor.colorFormatsCount = 0; @@ -174,7 +148,7 @@ TEST_P(DeviceLostTest, CreateRenderBundleEncoderFails) { // Tests that CreateComputePipeline fails when device is lost TEST_P(DeviceLostTest, CreateComputePipelineFails) { - LoseForTesting(); + LoseDeviceForTesting(); wgpu::ComputePipelineDescriptor descriptor = {}; descriptor.layout = nullptr; @@ -184,7 +158,7 @@ TEST_P(DeviceLostTest, CreateComputePipelineFails) { // Tests that CreateRenderPipeline fails when device is lost TEST_P(DeviceLostTest, CreateRenderPipelineFails) { - LoseForTesting(); + LoseDeviceForTesting(); utils::ComboRenderPipelineDescriptor descriptor; ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor)); @@ -192,14 +166,14 @@ TEST_P(DeviceLostTest, CreateRenderPipelineFails) { // Tests that CreateSampler fails when device is lost TEST_P(DeviceLostTest, CreateSamplerFails) { - LoseForTesting(); + LoseDeviceForTesting(); ASSERT_DEVICE_ERROR(device.CreateSampler()); } // Tests that CreateShaderModule fails when device is lost TEST_P(DeviceLostTest, CreateShaderModuleFails) { - LoseForTesting(); + LoseDeviceForTesting(); ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, R"( @stage(fragment) @@ -210,7 +184,7 @@ TEST_P(DeviceLostTest, CreateShaderModuleFails) { // Tests that CreateSwapChain fails when device is lost TEST_P(DeviceLostTest, CreateSwapChainFails) { - LoseForTesting(); + LoseDeviceForTesting(); wgpu::SwapChainDescriptor descriptor = {}; ASSERT_DEVICE_ERROR(device.CreateSwapChain(nullptr, &descriptor)); @@ -218,7 +192,7 @@ TEST_P(DeviceLostTest, CreateSwapChainFails) { // Tests that CreateTexture fails when device is lost TEST_P(DeviceLostTest, CreateTextureFails) { - LoseForTesting(); + LoseDeviceForTesting(); wgpu::TextureDescriptor descriptor; descriptor.size.width = 4; @@ -233,7 +207,7 @@ TEST_P(DeviceLostTest, CreateTextureFails) { // Test that CreateBuffer fails when device is lost TEST_P(DeviceLostTest, CreateBufferFails) { - LoseForTesting(); + LoseDeviceForTesting(); wgpu::BufferDescriptor bufferDescriptor; bufferDescriptor.size = sizeof(float); @@ -248,7 +222,7 @@ TEST_P(DeviceLostTest, BufferMapAsyncFailsForWriting) { bufferDescriptor.usage = wgpu::BufferUsage::MapWrite; wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor); - LoseForTesting(); + LoseDeviceForTesting(); ASSERT_DEVICE_ERROR(buffer.MapAsync(wgpu::MapMode::Write, 0, 4, MapFailCallback, const_cast(&fakeUserData))); } @@ -263,7 +237,7 @@ TEST_P(DeviceLostTest, BufferMapAsyncBeforeLossFailsForWriting) { buffer.MapAsync(wgpu::MapMode::Write, 0, 4, MapFailCallback, const_cast(&fakeUserData)); - LoseForTesting(); + LoseDeviceForTesting(); } // Test that buffer.Unmap fails after device is lost @@ -274,7 +248,7 @@ TEST_P(DeviceLostTest, BufferUnmapFails) { bufferDescriptor.mappedAtCreation = true; wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor); - LoseForTesting(); + LoseDeviceForTesting(); ASSERT_DEVICE_ERROR(buffer.Unmap()); } @@ -285,7 +259,7 @@ TEST_P(DeviceLostTest, CreateBufferMappedAtCreationFails) { bufferDescriptor.usage = wgpu::BufferUsage::MapWrite; bufferDescriptor.mappedAtCreation = true; - LoseForTesting(); + LoseDeviceForTesting(); ASSERT_DEVICE_ERROR(device.CreateBuffer(&bufferDescriptor)); } @@ -297,7 +271,7 @@ TEST_P(DeviceLostTest, BufferMapAsyncFailsForReading) { wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor); - LoseForTesting(); + LoseDeviceForTesting(); ASSERT_DEVICE_ERROR(buffer.MapAsync(wgpu::MapMode::Read, 0, 4, MapFailCallback, const_cast(&fakeUserData))); } @@ -313,7 +287,7 @@ TEST_P(DeviceLostTest, BufferMapAsyncBeforeLossFailsForReading) { buffer.MapAsync(wgpu::MapMode::Read, 0, 4, MapFailCallback, const_cast(&fakeUserData)); - LoseForTesting(); + LoseDeviceForTesting(); } // Test that WriteBuffer fails after device is lost @@ -324,14 +298,14 @@ TEST_P(DeviceLostTest, WriteBufferFails) { wgpu::Buffer buffer = device.CreateBuffer(&bufferDescriptor); - LoseForTesting(); + LoseDeviceForTesting(); float data = 12.0f; ASSERT_DEVICE_ERROR(queue.WriteBuffer(buffer, 0, &data, sizeof(data))); } // Test it's possible to GetMappedRange on a buffer created mapped after device loss TEST_P(DeviceLostTest, GetMappedRange_CreateBufferMappedAtCreationAfterLoss) { - LoseForTesting(); + LoseDeviceForTesting(); wgpu::BufferDescriptor desc; desc.size = 4; @@ -351,7 +325,7 @@ TEST_P(DeviceLostTest, GetMappedRange_CreateBufferMappedAtCreationBeforeLoss) { wgpu::Buffer buffer = device.CreateBuffer(&desc); void* rangeBeforeLoss = buffer.GetMappedRange(); - LoseForTesting(); + LoseDeviceForTesting(); ASSERT_NE(buffer.GetMappedRange(), nullptr); ASSERT_EQ(buffer.GetMappedRange(), rangeBeforeLoss); @@ -368,7 +342,7 @@ TEST_P(DeviceLostTest, GetMappedRange_MapAsyncReading) { queue.Submit(0, nullptr); const void* rangeBeforeLoss = buffer.GetConstMappedRange(); - LoseForTesting(); + LoseDeviceForTesting(); ASSERT_NE(buffer.GetConstMappedRange(), nullptr); ASSERT_EQ(buffer.GetConstMappedRange(), rangeBeforeLoss); @@ -385,7 +359,7 @@ TEST_P(DeviceLostTest, GetMappedRange_MapAsyncWriting) { queue.Submit(0, nullptr); const void* rangeBeforeLoss = buffer.GetConstMappedRange(); - LoseForTesting(); + LoseDeviceForTesting(); ASSERT_NE(buffer.GetConstMappedRange(), nullptr); ASSERT_EQ(buffer.GetConstMappedRange(), rangeBeforeLoss); @@ -399,13 +373,13 @@ TEST_P(DeviceLostTest, CommandEncoderFinishFails) { wgpu::CommandBuffer commands; wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); - LoseForTesting(); + LoseDeviceForTesting(); ASSERT_DEVICE_ERROR(encoder.Finish()); } // Test that QueueOnSubmittedWorkDone fails after device is lost. TEST_P(DeviceLostTest, QueueOnSubmittedWorkDoneFails) { - LoseForTesting(); + LoseDeviceForTesting(); // callback should have device lost status EXPECT_CALL(*mockQueueWorkDoneCallback, Call(WGPUQueueWorkDoneStatus_DeviceLost, nullptr)) @@ -420,33 +394,29 @@ TEST_P(DeviceLostTest, QueueOnSubmittedWorkDoneBeforeLossFails) { .Times(1); queue.OnSubmittedWorkDone(0, ToMockQueueWorkDone, nullptr); - LoseForTesting(); + LoseDeviceForTesting(); } // Test that LostForTesting can only be called on one time -TEST_P(DeviceLostTest, LoseForTestingOnce) { - // First LoseForTesting call should occur normally. The callback is already set in SetUp. - EXPECT_CALL(*mockDeviceLostCallback, Call(WGPUDeviceLostReason_Undefined, _, this)).Times(1); - device.LoseForTesting(); +TEST_P(DeviceLostTest, LoseDeviceForTestingOnce) { + // First LoseDeviceForTesting call should occur normally. The callback is already set in SetUp. + LoseDeviceForTesting(); - // Second LoseForTesting call should result in no callbacks. The LoseForTesting will return - // without doing anything when it sees that device has already been lost. - device.SetDeviceLostCallback(ToMockDeviceLostCallback, this); - EXPECT_CALL(*mockDeviceLostCallback, Call(_, _, this)).Times(0); + // Second LoseDeviceForTesting call should result in no callbacks. Note we also reset the + // callback first since by default the device clears the callback after the device is lost. + device.SetDeviceLostCallback(mDeviceLostCallback.Callback(), + mDeviceLostCallback.MakeUserdata(device.Get())); + EXPECT_CALL(mDeviceLostCallback, Call(WGPUDeviceLostReason_Undefined, testing::_, device.Get())) + .Times(0); device.LoseForTesting(); + FlushWire(); + testing::Mock::VerifyAndClearExpectations(&mDeviceLostCallback); } 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 mockErrorCallback; - device.SetUncapturedErrorCallback(mockErrorCallback.Callback(), - mockErrorCallback.MakeUserdata(nullptr)); - EXPECT_CALL(mockErrorCallback, Call(_, _, _)).Times(Exactly(0)); - device.LoseForTesting(); + // Since the device has a default error callback set that fails if it is called, we just need + // to lose the device and verify no failures. + LoseDeviceForTesting(); } // Test that WGPUCreatePipelineAsyncStatus_DeviceLost can be correctly returned when device is lost @@ -466,7 +436,7 @@ TEST_P(DeviceLostTest, DeviceLostBeforeCreatePipelineAsyncCallback) { }; device.CreateComputePipelineAsync(&descriptor, callback, nullptr); - LoseForTesting(); + LoseDeviceForTesting(); } // This is a regression test for crbug.com/1212385 where Dawn didn't clean up all @@ -493,7 +463,7 @@ TEST_P(DeviceLostTest, FreeBindGroupAfterDeviceLossWithPendingCommands) { queue.Submit(0, nullptr); queue.Submit(0, nullptr); - LoseForTesting(); + LoseDeviceForTesting(); // Releasing the bing group places the bind group layout into a queue in the Vulkan backend // for recycling of descriptor sets. So, after these release calls there is still one last @@ -513,7 +483,7 @@ TEST_P(DeviceLostTest, SetLabelAfterDeviceLoss) { descriptor.size = 4; descriptor.usage = wgpu::BufferUsage::Uniform; wgpu::Buffer buffer = device.CreateBuffer(&descriptor); - LoseForTesting(); + LoseDeviceForTesting(); buffer.SetLabel(label.c_str()); } diff --git a/src/dawn/tests/end2end/SwapChainTests.cpp b/src/dawn/tests/end2end/SwapChainTests.cpp index 321854936b..c55330d7a2 100644 --- a/src/dawn/tests/end2end/SwapChainTests.cpp +++ b/src/dawn/tests/end2end/SwapChainTests.cpp @@ -222,7 +222,7 @@ TEST_P(SwapChainTests, SwitchingDevice) { // See https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2256 DAWN_SUPPRESS_TEST_IF(IsVulkan() && IsBackendValidationEnabled()); - wgpu::Device device2 = wgpu::Device::Acquire(GetAdapter().CreateDevice()); + wgpu::Device device2 = CreateDevice(); for (int i = 0; i < 3; i++) { wgpu::Device deviceToUse; diff --git a/src/dawn/tests/end2end/SwapChainValidationTests.cpp b/src/dawn/tests/end2end/SwapChainValidationTests.cpp index 3af4c889fc..0da72108cc 100644 --- a/src/dawn/tests/end2end/SwapChainValidationTests.cpp +++ b/src/dawn/tests/end2end/SwapChainValidationTests.cpp @@ -319,38 +319,26 @@ TEST_P(SwapChainValidationTests, SwapChainIsInvalidAfterSurfaceDestruction_After ASSERT_DEVICE_ERROR(replacedSwapChain.Present()); } -// Test that after Device is Lost, all swap chain operations fail -static void ToMockDeviceLostCallback(WGPUDeviceLostReason reason, - const char* message, - void* userdata) { - DawnTest* self = static_cast(userdata); - self->StartExpectDeviceError(); -} - // Test that new swap chain present fails after device is lost TEST_P(SwapChainValidationTests, NewSwapChainPresentFailsAfterDeviceLost) { - device.SetDeviceLostCallback(ToMockDeviceLostCallback, this); wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &goodDescriptor); wgpu::TextureView view = swapchain.GetCurrentTextureView(); - device.LoseForTesting(); + LoseDeviceForTesting(); ASSERT_DEVICE_ERROR(swapchain.Present()); } // Test that new swap chain get current texture view fails after device is lost TEST_P(SwapChainValidationTests, NewSwapChainGetCurrentTextureViewFailsAfterDevLost) { - device.SetDeviceLostCallback(ToMockDeviceLostCallback, this); wgpu::SwapChain swapchain = device.CreateSwapChain(surface, &goodDescriptor); - device.LoseForTesting(); + LoseDeviceForTesting(); ASSERT_DEVICE_ERROR(swapchain.GetCurrentTextureView()); } // Test that creation of a new swapchain fails after device is lost TEST_P(SwapChainValidationTests, CreateNewSwapChainFailsAfterDevLost) { - device.SetDeviceLostCallback(ToMockDeviceLostCallback, this); - device.LoseForTesting(); - + LoseDeviceForTesting(); ASSERT_DEVICE_ERROR(device.CreateSwapChain(surface, &goodDescriptor)); }