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 <enga@chromium.org>
Reviewed-by: Rafael Cintron <rafael.cintron@microsoft.com>
Commit-Queue: Brandon Jones <brandon1.jones@intel.com>
This commit is contained in:
Brandon Jones 2021-02-24 22:09:30 +00:00 committed by Commit Bot service account
parent d87de3343a
commit 0a295c027d
8 changed files with 38 additions and 1 deletions

View File

@ -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

View File

@ -40,6 +40,8 @@ namespace dawn_native {
DeviceBase* CreateDevice(const DeviceDescriptor* descriptor = nullptr);
void ResetInternalDeviceForTesting();
ExtensionsSet GetSupportedExtensions() const;
bool SupportsAllRequestedExtensions(
const std::vector<const char*>& 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;
};

View File

@ -111,6 +111,10 @@ namespace dawn_native {
return reinterpret_cast<WGPUDevice>(mImpl->CreateDevice(deviceDescriptor));
}
void Adapter::ResetInternalDeviceForTesting() {
mImpl->ResetInternalDeviceForTesting();
}
// AdapterDiscoverOptionsBase
AdapterDiscoveryOptionsBase::AdapterDiscoveryOptionsBase(WGPUBackendType type)

View File

@ -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

View File

@ -38,6 +38,8 @@ namespace dawn_native { namespace d3d12 {
private:
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override;
MaybeError ResetInternalDeviceForTestingImpl() override;
void InitializeSupportedExtensions();
MaybeError InitializeDebugLayerFilters();
void CleanUpDebugLayerFilters();

View File

@ -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;
};

View File

@ -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();
}

View File

@ -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;
}