Moves DestroyApiObject call into ApiObjectBase::DeleteThis
- Moving the call into DeleteThis should make it so that derived classes don't need to explicitly implement a destructor that calls DestroyApiObject. Bug: dawn:628 Change-Id: I145f42e7e4c144cc0d2d7c7f609744399d514fe1 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/66840 Commit-Queue: Loko Kung <lokokung@google.com> Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
parent
74635bc6e9
commit
bf9b3cc5a9
|
@ -200,7 +200,11 @@ namespace dawn_native {
|
||||||
mCaches = std::make_unique<DeviceBase::Caches>();
|
mCaches = std::make_unique<DeviceBase::Caches>();
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceBase::~DeviceBase() = default;
|
DeviceBase::~DeviceBase() {
|
||||||
|
// We need to explicitly release the Queue before we complete the destructor so that the
|
||||||
|
// Queue does not get destroyed after the Device.
|
||||||
|
mQueue = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
MaybeError DeviceBase::Initialize(QueueBase* defaultQueue) {
|
MaybeError DeviceBase::Initialize(QueueBase* defaultQueue) {
|
||||||
mQueue = AcquireRef(defaultQueue);
|
mQueue = AcquireRef(defaultQueue);
|
||||||
|
|
|
@ -70,15 +70,22 @@ namespace dawn_native {
|
||||||
return IsInList();
|
return IsInList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApiObjectBase::DeleteThis() {
|
||||||
|
DestroyApiObject();
|
||||||
|
RefCounted::DeleteThis();
|
||||||
|
}
|
||||||
|
|
||||||
void ApiObjectBase::TrackInDevice() {
|
void ApiObjectBase::TrackInDevice() {
|
||||||
ASSERT(GetDevice() != nullptr);
|
ASSERT(GetDevice() != nullptr);
|
||||||
GetDevice()->TrackObject(this);
|
GetDevice()->TrackObject(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ApiObjectBase::DestroyApiObject() {
|
bool ApiObjectBase::DestroyApiObject() {
|
||||||
const std::lock_guard<std::mutex> lock(*GetDevice()->GetObjectListMutex(GetType()));
|
{
|
||||||
if (!RemoveFromList()) {
|
const std::lock_guard<std::mutex> lock(*GetDevice()->GetObjectListMutex(GetType()));
|
||||||
return false;
|
if (!RemoveFromList()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DestroyApiObjectImpl();
|
DestroyApiObjectImpl();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -71,6 +71,17 @@ namespace dawn_native {
|
||||||
void APISetLabel(const char* label);
|
void APISetLabel(const char* label);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// Overriding of the RefCounted's DeleteThis function ensures that instances of objects
|
||||||
|
// always call their derived class implementation of DestroyApiObject prior to the derived
|
||||||
|
// class being destroyed. This guarantees that when ApiObjects' reference counts drop to 0,
|
||||||
|
// then the underlying backend's Destroy calls are executed. We cannot naively put the call
|
||||||
|
// to DestroyApiObject in the destructor of this class because it calls DestroyApiObjectImpl
|
||||||
|
// which is a virtual function often implemented in the Derived class which would already
|
||||||
|
// have been destroyed by the time ApiObject's destructor is called by C++'s destruction
|
||||||
|
// order. Note that some classes like BindGroup may override the DeleteThis function again,
|
||||||
|
// and they should ensure that their overriding versions call this underlying version
|
||||||
|
// somewhere.
|
||||||
|
void DeleteThis() override;
|
||||||
void TrackInDevice();
|
void TrackInDevice();
|
||||||
virtual void DestroyApiObjectImpl();
|
virtual void DestroyApiObjectImpl();
|
||||||
|
|
||||||
|
|
|
@ -131,10 +131,6 @@ namespace dawn_native { namespace d3d12 {
|
||||||
device->GetSamplerStagingDescriptorAllocator(GetSamplerDescriptorCount());
|
device->GetSamplerStagingDescriptorAllocator(GetSamplerDescriptorCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
BindGroupLayout::~BindGroupLayout() {
|
|
||||||
DestroyApiObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultOrError<Ref<BindGroup>> BindGroupLayout::AllocateBindGroup(
|
ResultOrError<Ref<BindGroup>> BindGroupLayout::AllocateBindGroup(
|
||||||
Device* device,
|
Device* device,
|
||||||
const BindGroupDescriptor* descriptor) {
|
const BindGroupDescriptor* descriptor) {
|
||||||
|
|
|
@ -64,7 +64,7 @@ namespace dawn_native { namespace d3d12 {
|
||||||
BindGroupLayout(Device* device,
|
BindGroupLayout(Device* device,
|
||||||
const BindGroupLayoutDescriptor* descriptor,
|
const BindGroupLayoutDescriptor* descriptor,
|
||||||
PipelineCompatibilityToken pipelineCompatibilityToken);
|
PipelineCompatibilityToken pipelineCompatibilityToken);
|
||||||
~BindGroupLayout() override;
|
~BindGroupLayout() override = default;
|
||||||
|
|
||||||
// Contains the offset into the descriptor heap for the given resource view. Samplers and
|
// Contains the offset into the descriptor heap for the given resource view. Samplers and
|
||||||
// non-samplers are stored in separate descriptor heaps, so the offsets should be unique
|
// non-samplers are stored in separate descriptor heaps, so the offsets should be unique
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace dawn_native { namespace metal {
|
||||||
BindGroupLayout(DeviceBase* device,
|
BindGroupLayout(DeviceBase* device,
|
||||||
const BindGroupLayoutDescriptor* descriptor,
|
const BindGroupLayoutDescriptor* descriptor,
|
||||||
PipelineCompatibilityToken pipelineCompatibilityToken);
|
PipelineCompatibilityToken pipelineCompatibilityToken);
|
||||||
~BindGroupLayout() override;
|
~BindGroupLayout() override = default;
|
||||||
|
|
||||||
SlabAllocator<BindGroup> mBindGroupAllocator;
|
SlabAllocator<BindGroup> mBindGroupAllocator;
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,10 +33,6 @@ namespace dawn_native { namespace metal {
|
||||||
mBindGroupAllocator(MakeFrontendBindGroupAllocator<BindGroup>(4096)) {
|
mBindGroupAllocator(MakeFrontendBindGroupAllocator<BindGroup>(4096)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
BindGroupLayout::~BindGroupLayout() {
|
|
||||||
DestroyApiObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<BindGroup> BindGroupLayout::AllocateBindGroup(Device* device,
|
Ref<BindGroup> BindGroupLayout::AllocateBindGroup(Device* device,
|
||||||
const BindGroupDescriptor* descriptor) {
|
const BindGroupDescriptor* descriptor) {
|
||||||
return AcquireRef(mBindGroupAllocator.Allocate(device, descriptor));
|
return AcquireRef(mBindGroupAllocator.Allocate(device, descriptor));
|
||||||
|
|
|
@ -271,10 +271,6 @@ namespace dawn_native { namespace null {
|
||||||
: BindGroupLayoutBase(device, descriptor, pipelineCompatibilityToken) {
|
: BindGroupLayoutBase(device, descriptor, pipelineCompatibilityToken) {
|
||||||
}
|
}
|
||||||
|
|
||||||
BindGroupLayout::~BindGroupLayout() {
|
|
||||||
DestroyApiObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buffer
|
// Buffer
|
||||||
|
|
||||||
Buffer::Buffer(Device* device, const BufferDescriptor* descriptor)
|
Buffer::Buffer(Device* device, const BufferDescriptor* descriptor)
|
||||||
|
|
|
@ -207,7 +207,7 @@ namespace dawn_native { namespace null {
|
||||||
PipelineCompatibilityToken pipelineCompatibilityToken);
|
PipelineCompatibilityToken pipelineCompatibilityToken);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~BindGroupLayout() override;
|
~BindGroupLayout() override = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Buffer final : public BufferBase {
|
class Buffer final : public BufferBase {
|
||||||
|
|
|
@ -25,10 +25,6 @@ namespace dawn_native { namespace opengl {
|
||||||
mBindGroupAllocator(MakeFrontendBindGroupAllocator<BindGroup>(4096)) {
|
mBindGroupAllocator(MakeFrontendBindGroupAllocator<BindGroup>(4096)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
BindGroupLayout::~BindGroupLayout() {
|
|
||||||
DestroyApiObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<BindGroup> BindGroupLayout::AllocateBindGroup(Device* device,
|
Ref<BindGroup> BindGroupLayout::AllocateBindGroup(Device* device,
|
||||||
const BindGroupDescriptor* descriptor) {
|
const BindGroupDescriptor* descriptor) {
|
||||||
return AcquireRef(mBindGroupAllocator.Allocate(device, descriptor));
|
return AcquireRef(mBindGroupAllocator.Allocate(device, descriptor));
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace dawn_native { namespace opengl {
|
||||||
void DeallocateBindGroup(BindGroup* bindGroup);
|
void DeallocateBindGroup(BindGroup* bindGroup);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
~BindGroupLayout() override;
|
~BindGroupLayout() override = default;
|
||||||
SlabAllocator<BindGroup> mBindGroupAllocator;
|
SlabAllocator<BindGroup> mBindGroupAllocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,6 @@ namespace dawn_native { namespace vulkan {
|
||||||
device->fn.DestroyDescriptorSetLayout(device->GetVkDevice(), mHandle, nullptr);
|
device->fn.DestroyDescriptorSetLayout(device->GetVkDevice(), mHandle, nullptr);
|
||||||
mHandle = VK_NULL_HANDLE;
|
mHandle = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
DestroyApiObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorSetLayout BindGroupLayout::GetHandle() const {
|
VkDescriptorSetLayout BindGroupLayout::GetHandle() const {
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace dawn_native { namespace {
|
||||||
using ::testing::InSequence;
|
using ::testing::InSequence;
|
||||||
using ::testing::Return;
|
using ::testing::Return;
|
||||||
|
|
||||||
TEST(DestroyObjectTests, BindGroupLayout) {
|
TEST(DestroyObjectTests, BindGroupLayoutExplicit) {
|
||||||
// Skipping validation on descriptors as coverage for validation is already present.
|
// Skipping validation on descriptors as coverage for validation is already present.
|
||||||
DeviceMock device;
|
DeviceMock device;
|
||||||
device.SetToggle(Toggle::SkipValidation, true);
|
device.SetToggle(Toggle::SkipValidation, true);
|
||||||
|
@ -46,6 +46,28 @@ namespace dawn_native { namespace {
|
||||||
EXPECT_FALSE(bindGroupLayout->IsAlive());
|
EXPECT_FALSE(bindGroupLayout->IsAlive());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the reference count on API objects reach 0, they should delete themselves. Note that GTest
|
||||||
|
// will also complain if there is a memory leak.
|
||||||
|
TEST(DestroyObjectTests, BindGroupLayoutImplicit) {
|
||||||
|
// Skipping validation on descriptors as coverage for validation is already present.
|
||||||
|
DeviceMock device;
|
||||||
|
device.SetToggle(Toggle::SkipValidation, true);
|
||||||
|
|
||||||
|
BindGroupLayoutMock* bindGroupLayoutMock = new BindGroupLayoutMock(&device);
|
||||||
|
EXPECT_CALL(*bindGroupLayoutMock, DestroyApiObjectImpl).Times(1);
|
||||||
|
|
||||||
|
{
|
||||||
|
BindGroupLayoutDescriptor desc = {};
|
||||||
|
Ref<BindGroupLayoutBase> bindGroupLayout;
|
||||||
|
EXPECT_CALL(device, CreateBindGroupLayoutImpl)
|
||||||
|
.WillOnce(Return(ByMove(AcquireRef(bindGroupLayoutMock))));
|
||||||
|
DAWN_ASSERT_AND_ASSIGN(bindGroupLayout, device.CreateBindGroupLayout(&desc));
|
||||||
|
|
||||||
|
EXPECT_TRUE(bindGroupLayout->IsAlive());
|
||||||
|
EXPECT_TRUE(bindGroupLayout->IsCachedReference());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Destroying the objects on the device should result in all created objects being destroyed in
|
// Destroying the objects on the device should result in all created objects being destroyed in
|
||||||
// order.
|
// order.
|
||||||
TEST(DestroyObjectTests, DestroyObjects) {
|
TEST(DestroyObjectTests, DestroyObjects) {
|
||||||
|
|
|
@ -26,9 +26,7 @@ namespace dawn_native {
|
||||||
public:
|
public:
|
||||||
BindGroupLayoutMock(DeviceBase* device) : BindGroupLayoutBase(device) {
|
BindGroupLayoutMock(DeviceBase* device) : BindGroupLayoutBase(device) {
|
||||||
}
|
}
|
||||||
~BindGroupLayoutMock() override {
|
~BindGroupLayoutMock() override = default;
|
||||||
DestroyApiObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
MOCK_METHOD(void, DestroyApiObjectImpl, (), (override));
|
MOCK_METHOD(void, DestroyApiObjectImpl, (), (override));
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue