From 0a295c027d81316cac4442323cb422dbc54a4d92 Mon Sep 17 00:00:00 2001 From: Brandon Jones Date: Wed, 24 Feb 2021 22:09:30 +0000 Subject: [PATCH] Reset Internal D3D12 Device After Test Shutdown Adds dawn_native::ResetDeviceInternal, which allows us to destroy and create a new ID3D12Device. The device should be reset after every test when GPU-based validation is enabled in order to prevent GBV objects from using a significant amount of memory over time. Bug: dawn:623 Change-Id: I654d093d993ab0198c6c240bd0f3f843d2762680 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/41340 Reviewed-by: Austin Eng Reviewed-by: Rafael Cintron Commit-Queue: Brandon Jones --- src/dawn_native/Adapter.cpp | 9 +++++++++ src/dawn_native/Adapter.h | 3 +++ src/dawn_native/DawnNative.cpp | 4 ++++ src/dawn_native/d3d12/AdapterD3D12.cpp | 11 +++++++++++ src/dawn_native/d3d12/AdapterD3D12.h | 2 ++ src/include/dawn_native/DawnNative.h | 3 +++ src/tests/DawnTest.cpp | 5 +++++ src/tests/end2end/DeviceInitializationTests.cpp | 2 +- 8 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/dawn_native/Adapter.cpp b/src/dawn_native/Adapter.cpp index 38f97984d2..3e70831c40 100644 --- a/src/dawn_native/Adapter.cpp +++ b/src/dawn_native/Adapter.cpp @@ -91,4 +91,13 @@ namespace dawn_native { return {}; } + void AdapterBase::ResetInternalDeviceForTesting() { + mInstance->ConsumedError(ResetInternalDeviceForTestingImpl()); + } + + MaybeError AdapterBase::ResetInternalDeviceForTestingImpl() { + return DAWN_INTERNAL_ERROR( + "ResetInternalDeviceForTesting should only be used with the D3D12 backend."); + } + } // namespace dawn_native diff --git a/src/dawn_native/Adapter.h b/src/dawn_native/Adapter.h index db741a873a..118bcdfa67 100644 --- a/src/dawn_native/Adapter.h +++ b/src/dawn_native/Adapter.h @@ -40,6 +40,8 @@ namespace dawn_native { DeviceBase* CreateDevice(const DeviceDescriptor* descriptor = nullptr); + void ResetInternalDeviceForTesting(); + ExtensionsSet GetSupportedExtensions() const; bool SupportsAllRequestedExtensions( const std::vector& requestedExtensions) const; @@ -56,6 +58,7 @@ namespace dawn_native { MaybeError CreateDeviceInternal(DeviceBase** result, const DeviceDescriptor* descriptor); + virtual MaybeError ResetInternalDeviceForTestingImpl(); InstanceBase* mInstance = nullptr; wgpu::BackendType mBackend; }; diff --git a/src/dawn_native/DawnNative.cpp b/src/dawn_native/DawnNative.cpp index b7b46adf3d..c089926a37 100644 --- a/src/dawn_native/DawnNative.cpp +++ b/src/dawn_native/DawnNative.cpp @@ -111,6 +111,10 @@ namespace dawn_native { return reinterpret_cast(mImpl->CreateDevice(deviceDescriptor)); } + void Adapter::ResetInternalDeviceForTesting() { + mImpl->ResetInternalDeviceForTesting(); + } + // AdapterDiscoverOptionsBase AdapterDiscoveryOptionsBase::AdapterDiscoveryOptionsBase(WGPUBackendType type) diff --git a/src/dawn_native/d3d12/AdapterD3D12.cpp b/src/dawn_native/d3d12/AdapterD3D12.cpp index ac7ad9dd2a..775e32da18 100644 --- a/src/dawn_native/d3d12/AdapterD3D12.cpp +++ b/src/dawn_native/d3d12/AdapterD3D12.cpp @@ -216,4 +216,15 @@ namespace dawn_native { namespace d3d12 { return Device::Create(this, descriptor); } + // Resets the backend device and creates a new one. If any D3D12 objects belonging to the + // current ID3D12Device have not been destroyed, a non-zero value will be returned upon Reset() + // and the subequent call to CreateDevice will return a handle the existing device instead of + // creating a new one. + MaybeError Adapter::ResetInternalDeviceForTestingImpl() { + ASSERT(mD3d12Device.Reset() == 0); + DAWN_TRY(Initialize()); + + return {}; + } + }} // namespace dawn_native::d3d12 diff --git a/src/dawn_native/d3d12/AdapterD3D12.h b/src/dawn_native/d3d12/AdapterD3D12.h index e0910bffa5..250a701273 100644 --- a/src/dawn_native/d3d12/AdapterD3D12.h +++ b/src/dawn_native/d3d12/AdapterD3D12.h @@ -38,6 +38,8 @@ namespace dawn_native { namespace d3d12 { private: ResultOrError CreateDeviceImpl(const DeviceDescriptor* descriptor) override; + MaybeError ResetInternalDeviceForTestingImpl() override; + void InitializeSupportedExtensions(); MaybeError InitializeDebugLayerFilters(); void CleanUpDebugLayerFilters(); diff --git a/src/include/dawn_native/DawnNative.h b/src/include/dawn_native/DawnNative.h index 3e8e6c0f23..f161d4ae9f 100644 --- a/src/include/dawn_native/DawnNative.h +++ b/src/include/dawn_native/DawnNative.h @@ -116,6 +116,9 @@ namespace dawn_native { // On an error, nullptr is returned. WGPUDevice CreateDevice(const DeviceDescriptor* deviceDescriptor = nullptr); + // Reset the backend device object for testing purposes. + void ResetInternalDeviceForTesting(); + private: AdapterBase* mImpl = nullptr; }; diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp index 8de73b8a29..7cc9693e26 100644 --- a/src/tests/DawnTest.cpp +++ b/src/tests/DawnTest.cpp @@ -677,6 +677,11 @@ DawnTestBase::~DawnTestBase() { queue = wgpu::Queue(); device = wgpu::Device(); + // D3D12's GPU-based validation will accumulate objects over time if the backend device is not + // destroyed and recreated, so we reset it here. + if (IsD3D12() && IsBackendValidationEnabled()) { + mBackendAdapter.ResetInternalDeviceForTesting(); + } mWireHelper.reset(); } diff --git a/src/tests/end2end/DeviceInitializationTests.cpp b/src/tests/end2end/DeviceInitializationTests.cpp index 11b73d1b3e..31948e6a1b 100644 --- a/src/tests/end2end/DeviceInitializationTests.cpp +++ b/src/tests/end2end/DeviceInitializationTests.cpp @@ -62,7 +62,7 @@ TEST_F(DeviceInitializationTest, DeviceOutlivesInstance) { properties.backendType == desiredProperties.backendType) { // Create the device, destroy the instance, and break out of the loop. dawn_native::DeviceDescriptor deviceDescriptor = {}; - device = wgpu::Device(adapter.CreateDevice(&deviceDescriptor)); + device = wgpu::Device::Acquire(adapter.CreateDevice(&deviceDescriptor)); instance.reset(); break; }