Adds destruction handling for Textures when device is destroyed.

Bug: dawn:628
Change-Id: Iaaa62507592e12a724673a0226783c0425b04f35
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/67601
Commit-Queue: Loko Kung <lokokung@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Loko Kung 2021-11-10 22:25:03 +00:00 committed by Dawn LUCI CQ
parent 75c978f9b9
commit 6b6262dde0
17 changed files with 296 additions and 26 deletions

View File

@ -269,7 +269,7 @@ namespace dawn_native {
// TODO(dawn/628) Add types into the array as they are implemented. // TODO(dawn/628) Add types into the array as they are implemented.
// clang-format off // clang-format off
static constexpr std::array<ObjectType, 10> kObjectTypeDependencyOrder = { static constexpr std::array<ObjectType, 13> kObjectTypeDependencyOrder = {
ObjectType::RenderPipeline, ObjectType::RenderPipeline,
ObjectType::ComputePipeline, ObjectType::ComputePipeline,
ObjectType::PipelineLayout, ObjectType::PipelineLayout,
@ -277,6 +277,9 @@ namespace dawn_native {
ObjectType::BindGroup, ObjectType::BindGroup,
ObjectType::BindGroupLayout, ObjectType::BindGroupLayout,
ObjectType::ShaderModule, ObjectType::ShaderModule,
ObjectType::ExternalTexture,
ObjectType::TextureView,
ObjectType::Texture,
ObjectType::QuerySet, ObjectType::QuerySet,
ObjectType::Sampler, ObjectType::Sampler,
ObjectType::Buffer, ObjectType::Buffer,

View File

@ -91,6 +91,12 @@ namespace dawn_native {
const ExternalTextureDescriptor* descriptor) const ExternalTextureDescriptor* descriptor)
: ApiObjectBase(device, kLabelNotImplemented), mState(ExternalTextureState::Alive) { : ApiObjectBase(device, kLabelNotImplemented), mState(ExternalTextureState::Alive) {
textureViews[0] = descriptor->plane0; textureViews[0] = descriptor->plane0;
TrackInDevice();
}
ExternalTextureBase::ExternalTextureBase(DeviceBase* device)
: ApiObjectBase(device, kLabelNotImplemented), mState(ExternalTextureState::Alive) {
TrackInDevice();
} }
ExternalTextureBase::ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag) ExternalTextureBase::ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag)
@ -113,8 +119,12 @@ namespace dawn_native {
if (GetDevice()->ConsumedError(GetDevice()->ValidateObject(this))) { if (GetDevice()->ConsumedError(GetDevice()->ValidateObject(this))) {
return; return;
} }
DestroyApiObject();
}
bool ExternalTextureBase::DestroyApiObject() {
mState = ExternalTextureState::Destroyed; mState = ExternalTextureState::Destroyed;
ASSERT(!IsError()); return ApiObjectBase::DestroyApiObject();
} }
// static // static

View File

@ -42,10 +42,15 @@ namespace dawn_native {
static ExternalTextureBase* MakeError(DeviceBase* device); static ExternalTextureBase* MakeError(DeviceBase* device);
bool DestroyApiObject() override;
ObjectType GetType() const override; ObjectType GetType() const override;
void APIDestroy(); void APIDestroy();
protected:
// Constructor used only for mocking and testing.
ExternalTextureBase(DeviceBase* device);
private: private:
enum class ExternalTextureState { Alive, Destroyed }; enum class ExternalTextureState { Alive, Destroyed };
ExternalTextureBase(DeviceBase* device, const ExternalTextureDescriptor* descriptor); ExternalTextureBase(DeviceBase* device, const ExternalTextureDescriptor* descriptor);

View File

@ -469,14 +469,30 @@ namespace dawn_native {
if (internalUsageDesc != nullptr) { if (internalUsageDesc != nullptr) {
mInternalUsage |= internalUsageDesc->internalUsage; mInternalUsage |= internalUsageDesc->internalUsage;
} }
TrackInDevice();
} }
static Format kUnusedFormat; static Format kUnusedFormat;
TextureBase::TextureBase(DeviceBase* device, TextureState state)
: ApiObjectBase(device, kLabelNotImplemented), mFormat(kUnusedFormat), mState(state) {
TrackInDevice();
}
TextureBase::TextureBase(DeviceBase* device, ObjectBase::ErrorTag tag) TextureBase::TextureBase(DeviceBase* device, ObjectBase::ErrorTag tag)
: ApiObjectBase(device, tag), mFormat(kUnusedFormat) { : ApiObjectBase(device, tag), mFormat(kUnusedFormat) {
} }
bool TextureBase::DestroyApiObject() {
// We need to run the destroy operations prior to setting the state to destroyed so that
// the state is both consistent, and implementations of the destroy that may check the
// state do not skip operations unintentionally. (Example in Vulkan backend, the destroy
// implementation will not be ran if we are already in the Destroyed state.)
bool wasDestroyed = ApiObjectBase::DestroyApiObject();
mState = TextureState::Destroyed;
return wasDestroyed;
}
// static // static
TextureBase* TextureBase::MakeError(DeviceBase* device) { TextureBase* TextureBase::MakeError(DeviceBase* device) {
return new TextureBase(device, ObjectBase::kError); return new TextureBase(device, ObjectBase::kError);
@ -670,15 +686,7 @@ namespace dawn_native {
return; return;
} }
ASSERT(!IsError()); ASSERT(!IsError());
DestroyInternal(); DestroyApiObject();
}
void TextureBase::DestroyImpl() {
}
void TextureBase::DestroyInternal() {
DestroyImpl();
mState = TextureState::Destroyed;
} }
MaybeError TextureBase::ValidateDestroy() const { MaybeError TextureBase::ValidateDestroy() const {
@ -696,6 +704,14 @@ namespace dawn_native {
mRange({ConvertViewAspect(mFormat, descriptor->aspect), mRange({ConvertViewAspect(mFormat, descriptor->aspect),
{descriptor->baseArrayLayer, descriptor->arrayLayerCount}, {descriptor->baseArrayLayer, descriptor->arrayLayerCount},
{descriptor->baseMipLevel, descriptor->mipLevelCount}}) { {descriptor->baseMipLevel, descriptor->mipLevelCount}}) {
TrackInDevice();
}
TextureViewBase::TextureViewBase(TextureBase* texture)
: ApiObjectBase(texture->GetDevice(), kLabelNotImplemented),
mTexture(texture),
mFormat(kUnusedFormat) {
TrackInDevice();
} }
TextureViewBase::TextureViewBase(DeviceBase* device, ObjectBase::ErrorTag tag) TextureViewBase::TextureViewBase(DeviceBase* device, ObjectBase::ErrorTag tag)

View File

@ -51,6 +51,7 @@ namespace dawn_native {
static TextureBase* MakeError(DeviceBase* device); static TextureBase* MakeError(DeviceBase* device);
bool DestroyApiObject() override;
ObjectType GetType() const override; ObjectType GetType() const override;
wgpu::TextureDimension GetDimension() const; wgpu::TextureDimension GetDimension() const;
@ -96,11 +97,11 @@ namespace dawn_native {
void APIDestroy(); void APIDestroy();
protected: protected:
void DestroyInternal(); // Constructor used only for mocking and testing.
TextureBase(DeviceBase* device, TextureState state);
private: private:
TextureBase(DeviceBase* device, ObjectBase::ErrorTag tag); TextureBase(DeviceBase* device, ObjectBase::ErrorTag tag);
virtual void DestroyImpl();
MaybeError ValidateDestroy() const; MaybeError ValidateDestroy() const;
wgpu::TextureDimension mDimension; wgpu::TextureDimension mDimension;
@ -136,6 +137,10 @@ namespace dawn_native {
uint32_t GetLayerCount() const; uint32_t GetLayerCount() const;
const SubresourceRange& GetSubresourceRange() const; const SubresourceRange& GetSubresourceRange() const;
protected:
// Constructor used only for mocking and testing.
TextureViewBase(TextureBase* texture);
private: private:
TextureViewBase(DeviceBase* device, ObjectBase::ErrorTag tag); TextureViewBase(DeviceBase* device, ObjectBase::ErrorTag tag);

View File

@ -647,10 +647,9 @@ namespace dawn_native { namespace d3d12 {
} }
Texture::~Texture() { Texture::~Texture() {
DestroyInternal();
} }
void Texture::DestroyImpl() { void Texture::DestroyApiObjectImpl() {
Device* device = ToBackend(GetDevice()); Device* device = ToBackend(GetDevice());
// In PIX's D3D12-only mode, there is no way to determine frame boundaries // In PIX's D3D12-only mode, there is no way to determine frame boundaries

View File

@ -105,7 +105,7 @@ namespace dawn_native { namespace d3d12 {
// Dawn API // Dawn API
void SetLabelImpl() override; void SetLabelImpl() override;
void DestroyImpl() override; void DestroyApiObjectImpl() override;
MaybeError ClearTexture(CommandRecordingContext* commandContext, MaybeError ClearTexture(CommandRecordingContext* commandContext,
const SubresourceRange& range, const SubresourceRange& range,

View File

@ -66,7 +66,7 @@ namespace dawn_native { namespace metal {
void InitializeAsWrapping(const TextureDescriptor* descriptor, void InitializeAsWrapping(const TextureDescriptor* descriptor,
NSPRef<id<MTLTexture>> wrapped); NSPRef<id<MTLTexture>> wrapped);
void DestroyImpl() override; void DestroyApiObjectImpl() override;
MaybeError ClearTexture(CommandRecordingContext* commandContext, MaybeError ClearTexture(CommandRecordingContext* commandContext,
const SubresourceRange& range, const SubresourceRange& range,

View File

@ -493,10 +493,9 @@ namespace dawn_native { namespace metal {
} }
Texture::~Texture() { Texture::~Texture() {
DestroyInternal();
} }
void Texture::DestroyImpl() { void Texture::DestroyApiObjectImpl() {
mMtlTexture = nullptr; mMtlTexture = nullptr;
} }

View File

@ -188,10 +188,9 @@ namespace dawn_native { namespace opengl {
} }
Texture::~Texture() { Texture::~Texture() {
DestroyInternal();
} }
void Texture::DestroyImpl() { void Texture::DestroyApiObjectImpl() {
if (GetTextureState() == TextureState::OwnedInternal) { if (GetTextureState() == TextureState::OwnedInternal) {
ToBackend(GetDevice())->gl.DeleteTextures(1, &mHandle); ToBackend(GetDevice())->gl.DeleteTextures(1, &mHandle);
mHandle = 0; mHandle = 0;
@ -559,6 +558,9 @@ namespace dawn_native { namespace opengl {
} }
TextureView::~TextureView() { TextureView::~TextureView() {
}
void TextureView::DestroyApiObjectImpl() {
if (mOwnsHandle) { if (mOwnsHandle) {
ToBackend(GetDevice())->gl.DeleteTextures(1, &mHandle); ToBackend(GetDevice())->gl.DeleteTextures(1, &mHandle);
} }

View File

@ -41,7 +41,7 @@ namespace dawn_native { namespace opengl {
private: private:
~Texture() override; ~Texture() override;
void DestroyImpl() override; void DestroyApiObjectImpl() override;
MaybeError ClearTexture(const SubresourceRange& range, TextureBase::ClearValue clearValue); MaybeError ClearTexture(const SubresourceRange& range, TextureBase::ClearValue clearValue);
GLuint mHandle; GLuint mHandle;
@ -57,6 +57,7 @@ namespace dawn_native { namespace opengl {
private: private:
~TextureView() override; ~TextureView() override;
void DestroyApiObjectImpl() override;
GLuint mHandle; GLuint mHandle;
GLenum mTarget; GLenum mTarget;

View File

@ -792,12 +792,11 @@ namespace dawn_native { namespace vulkan {
mSignalSemaphore = VK_NULL_HANDLE; mSignalSemaphore = VK_NULL_HANDLE;
// Destroy the texture so it can't be used again // Destroy the texture so it can't be used again
DestroyInternal(); DestroyApiObject();
return {}; return {};
} }
Texture::~Texture() { Texture::~Texture() {
DestroyInternal();
} }
void Texture::SetLabelHelper(const char* prefix) { void Texture::SetLabelHelper(const char* prefix) {
@ -809,7 +808,7 @@ namespace dawn_native { namespace vulkan {
SetLabelHelper("Dawn_InternalTexture"); SetLabelHelper("Dawn_InternalTexture");
} }
void Texture::DestroyImpl() { void Texture::DestroyApiObjectImpl() {
if (GetTextureState() == TextureState::OwnedInternal) { if (GetTextureState() == TextureState::OwnedInternal) {
Device* device = ToBackend(GetDevice()); Device* device = ToBackend(GetDevice());
@ -1300,6 +1299,9 @@ namespace dawn_native { namespace vulkan {
} }
TextureView::~TextureView() { TextureView::~TextureView() {
}
void TextureView::DestroyApiObjectImpl() {
Device* device = ToBackend(GetTexture()->GetDevice()); Device* device = ToBackend(GetTexture()->GetDevice());
if (mHandle != VK_NULL_HANDLE) { if (mHandle != VK_NULL_HANDLE) {

View File

@ -107,7 +107,7 @@ namespace dawn_native { namespace vulkan {
external_memory::Service* externalMemoryService); external_memory::Service* externalMemoryService);
void InitializeForSwapChain(VkImage nativeImage); void InitializeForSwapChain(VkImage nativeImage);
void DestroyImpl() override; void DestroyApiObjectImpl() override;
MaybeError ClearTexture(CommandRecordingContext* recordingContext, MaybeError ClearTexture(CommandRecordingContext* recordingContext,
const SubresourceRange& range, const SubresourceRange& range,
TextureBase::ClearValue); TextureBase::ClearValue);
@ -176,6 +176,7 @@ namespace dawn_native { namespace vulkan {
private: private:
~TextureView() override; ~TextureView() override;
void DestroyApiObjectImpl() override;
using TextureViewBase::TextureViewBase; using TextureViewBase::TextureViewBase;
MaybeError Initialize(const TextureViewDescriptor* descriptor); MaybeError Initialize(const TextureViewDescriptor* descriptor);

View File

@ -146,6 +146,7 @@ source_set("dawn_native_mocks_sources") {
"unittests/native/mocks/BindGroupMock.h", "unittests/native/mocks/BindGroupMock.h",
"unittests/native/mocks/ComputePipelineMock.h", "unittests/native/mocks/ComputePipelineMock.h",
"unittests/native/mocks/DeviceMock.h", "unittests/native/mocks/DeviceMock.h",
"unittests/native/mocks/ExternalTextureMock.h",
"unittests/native/mocks/PipelineLayoutMock.h", "unittests/native/mocks/PipelineLayoutMock.h",
"unittests/native/mocks/QuerySetMock.h", "unittests/native/mocks/QuerySetMock.h",
"unittests/native/mocks/RenderPipelineMock.h", "unittests/native/mocks/RenderPipelineMock.h",
@ -153,6 +154,7 @@ source_set("dawn_native_mocks_sources") {
"unittests/native/mocks/ShaderModuleMock.cpp", "unittests/native/mocks/ShaderModuleMock.cpp",
"unittests/native/mocks/ShaderModuleMock.h", "unittests/native/mocks/ShaderModuleMock.h",
"unittests/native/mocks/SwapChainMock.h", "unittests/native/mocks/SwapChainMock.h",
"unittests/native/mocks/TextureMock.h",
] ]
} }

View File

@ -20,12 +20,14 @@
#include "mocks/BufferMock.h" #include "mocks/BufferMock.h"
#include "mocks/ComputePipelineMock.h" #include "mocks/ComputePipelineMock.h"
#include "mocks/DeviceMock.h" #include "mocks/DeviceMock.h"
#include "mocks/ExternalTextureMock.h"
#include "mocks/PipelineLayoutMock.h" #include "mocks/PipelineLayoutMock.h"
#include "mocks/QuerySetMock.h" #include "mocks/QuerySetMock.h"
#include "mocks/RenderPipelineMock.h" #include "mocks/RenderPipelineMock.h"
#include "mocks/SamplerMock.h" #include "mocks/SamplerMock.h"
#include "mocks/ShaderModuleMock.h" #include "mocks/ShaderModuleMock.h"
#include "mocks/SwapChainMock.h" #include "mocks/SwapChainMock.h"
#include "mocks/TextureMock.h"
#include "tests/DawnNativeTest.h" #include "tests/DawnNativeTest.h"
#include "utils/ComboRenderPipelineDescriptor.h" #include "utils/ComboRenderPipelineDescriptor.h"
@ -44,6 +46,16 @@ namespace dawn_native { namespace {
mDevice.SetToggle(Toggle::SkipValidation, true); mDevice.SetToggle(Toggle::SkipValidation, true);
} }
Ref<TextureMock> GetTexture() {
if (mTexture != nullptr) {
return mTexture;
}
mTexture =
AcquireRef(new TextureMock(&mDevice, TextureBase::TextureState::OwnedInternal));
EXPECT_CALL(*mTexture.Get(), DestroyApiObjectImpl).Times(1);
return mTexture;
}
Ref<PipelineLayoutMock> GetPipelineLayout() { Ref<PipelineLayoutMock> GetPipelineLayout() {
if (mPipelineLayout != nullptr) { if (mPipelineLayout != nullptr) {
return mPipelineLayout; return mPipelineLayout;
@ -85,6 +97,7 @@ namespace dawn_native { namespace {
// The following lazy-initialized objects are used to facilitate creation of dependent // The following lazy-initialized objects are used to facilitate creation of dependent
// objects under test. // objects under test.
Ref<TextureMock> mTexture;
Ref<PipelineLayoutMock> mPipelineLayout; Ref<PipelineLayoutMock> mPipelineLayout;
Ref<ShaderModuleMock> mVsModule; Ref<ShaderModuleMock> mVsModule;
Ref<ShaderModuleMock> mCsModule; Ref<ShaderModuleMock> mCsModule;
@ -237,6 +250,24 @@ namespace dawn_native { namespace {
} }
} }
TEST_F(DestroyObjectTests, ExternalTextureExplicit) {
ExternalTextureMock externalTextureMock(&mDevice);
EXPECT_CALL(externalTextureMock, DestroyApiObjectImpl).Times(1);
EXPECT_TRUE(externalTextureMock.IsAlive());
externalTextureMock.DestroyApiObject();
EXPECT_FALSE(externalTextureMock.IsAlive());
}
// We can use an actual ExternalTexture object to test the implicit case.
TEST_F(DestroyObjectTests, ExternalTextureImplicit) {
ExternalTextureDescriptor desc = {};
Ref<ExternalTextureBase> externalTexture;
DAWN_ASSERT_AND_ASSIGN(externalTexture, mDevice.CreateExternalTexture(&desc));
EXPECT_TRUE(externalTexture->IsAlive());
}
TEST_F(DestroyObjectTests, PipelineLayoutExplicit) { TEST_F(DestroyObjectTests, PipelineLayoutExplicit) {
PipelineLayoutMock pipelineLayoutMock(&mDevice); PipelineLayoutMock pipelineLayoutMock(&mDevice);
EXPECT_CALL(pipelineLayoutMock, DestroyApiObjectImpl).Times(1); EXPECT_CALL(pipelineLayoutMock, DestroyApiObjectImpl).Times(1);
@ -409,6 +440,84 @@ namespace dawn_native { namespace {
} }
} }
TEST_F(DestroyObjectTests, TextureExplicit) {
{
TextureMock textureMock(&mDevice, TextureBase::TextureState::OwnedInternal);
EXPECT_CALL(textureMock, DestroyApiObjectImpl).Times(1);
EXPECT_TRUE(textureMock.IsAlive());
textureMock.DestroyApiObject();
EXPECT_FALSE(textureMock.IsAlive());
}
{
TextureMock textureMock(&mDevice, TextureBase::TextureState::OwnedExternal);
EXPECT_CALL(textureMock, DestroyApiObjectImpl).Times(1);
EXPECT_TRUE(textureMock.IsAlive());
textureMock.DestroyApiObject();
EXPECT_FALSE(textureMock.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_F(DestroyObjectTests, TextureImplicit) {
{
TextureMock* textureMock =
new TextureMock(&mDevice, TextureBase::TextureState::OwnedInternal);
EXPECT_CALL(*textureMock, DestroyApiObjectImpl).Times(1);
{
TextureDescriptor desc = {};
Ref<TextureBase> texture;
EXPECT_CALL(mDevice, CreateTextureImpl)
.WillOnce(Return(ByMove(AcquireRef(textureMock))));
DAWN_ASSERT_AND_ASSIGN(texture, mDevice.CreateTexture(&desc));
EXPECT_TRUE(texture->IsAlive());
}
}
{
TextureMock* textureMock =
new TextureMock(&mDevice, TextureBase::TextureState::OwnedExternal);
EXPECT_CALL(*textureMock, DestroyApiObjectImpl).Times(1);
{
TextureDescriptor desc = {};
Ref<TextureBase> texture;
EXPECT_CALL(mDevice, CreateTextureImpl)
.WillOnce(Return(ByMove(AcquireRef(textureMock))));
DAWN_ASSERT_AND_ASSIGN(texture, mDevice.CreateTexture(&desc));
EXPECT_TRUE(texture->IsAlive());
}
}
}
TEST_F(DestroyObjectTests, TextureViewExplicit) {
TextureViewMock textureViewMock(GetTexture().Get());
EXPECT_CALL(textureViewMock, DestroyApiObjectImpl).Times(1);
EXPECT_TRUE(textureViewMock.IsAlive());
textureViewMock.DestroyApiObject();
EXPECT_FALSE(textureViewMock.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_F(DestroyObjectTests, TextureViewImplicit) {
TextureViewMock* textureViewMock = new TextureViewMock(GetTexture().Get());
EXPECT_CALL(*textureViewMock, DestroyApiObjectImpl).Times(1);
{
TextureViewDescriptor desc = {};
Ref<TextureViewBase> textureView;
EXPECT_CALL(mDevice, CreateTextureViewImpl)
.WillOnce(Return(ByMove(AcquireRef(textureViewMock))));
DAWN_ASSERT_AND_ASSIGN(textureView,
mDevice.CreateTextureView(GetTexture().Get(), &desc));
EXPECT_TRUE(textureView->IsAlive());
}
}
// Destroying the objects on the mDevice should result in all created objects being destroyed in // Destroying the objects on the mDevice should result in all created objects being destroyed in
// order. // order.
TEST_F(DestroyObjectTests, DestroyObjects) { TEST_F(DestroyObjectTests, DestroyObjects) {
@ -422,6 +531,9 @@ namespace dawn_native { namespace {
SamplerMock* samplerMock = new SamplerMock(&mDevice); SamplerMock* samplerMock = new SamplerMock(&mDevice);
ShaderModuleMock* shaderModuleMock = new ShaderModuleMock(&mDevice); ShaderModuleMock* shaderModuleMock = new ShaderModuleMock(&mDevice);
SwapChainMock* swapChainMock = new SwapChainMock(&mDevice); SwapChainMock* swapChainMock = new SwapChainMock(&mDevice);
TextureMock* textureMock =
new TextureMock(&mDevice, TextureBase::TextureState::OwnedInternal);
TextureViewMock* textureViewMock = new TextureViewMock(GetTexture().Get());
{ {
InSequence seq; InSequence seq;
EXPECT_CALL(*renderPipelineMock, DestroyApiObjectImpl).Times(1); EXPECT_CALL(*renderPipelineMock, DestroyApiObjectImpl).Times(1);
@ -431,6 +543,8 @@ namespace dawn_native { namespace {
EXPECT_CALL(*bindGroupMock, DestroyApiObjectImpl).Times(1); EXPECT_CALL(*bindGroupMock, DestroyApiObjectImpl).Times(1);
EXPECT_CALL(*bindGroupLayoutMock, DestroyApiObjectImpl).Times(1); EXPECT_CALL(*bindGroupLayoutMock, DestroyApiObjectImpl).Times(1);
EXPECT_CALL(*shaderModuleMock, DestroyApiObjectImpl).Times(1); EXPECT_CALL(*shaderModuleMock, DestroyApiObjectImpl).Times(1);
EXPECT_CALL(*textureViewMock, DestroyApiObjectImpl).Times(1);
EXPECT_CALL(*textureMock, DestroyApiObjectImpl).Times(1);
EXPECT_CALL(*querySetMock, DestroyApiObjectImpl).Times(1); EXPECT_CALL(*querySetMock, DestroyApiObjectImpl).Times(1);
EXPECT_CALL(*samplerMock, DestroyApiObjectImpl).Times(1); EXPECT_CALL(*samplerMock, DestroyApiObjectImpl).Times(1);
EXPECT_CALL(*bufferMock, DestroyApiObjectImpl).Times(1); EXPECT_CALL(*bufferMock, DestroyApiObjectImpl).Times(1);
@ -484,6 +598,13 @@ namespace dawn_native { namespace {
EXPECT_TRUE(computePipeline->IsCachedReference()); EXPECT_TRUE(computePipeline->IsCachedReference());
} }
Ref<ExternalTextureBase> externalTexture;
{
ExternalTextureDescriptor desc = {};
DAWN_ASSERT_AND_ASSIGN(externalTexture, mDevice.CreateExternalTexture(&desc));
EXPECT_TRUE(externalTexture->IsAlive());
}
Ref<PipelineLayoutBase> pipelineLayout; Ref<PipelineLayoutBase> pipelineLayout;
{ {
PipelineLayoutDescriptor desc = {}; PipelineLayoutDescriptor desc = {};
@ -560,17 +681,39 @@ namespace dawn_native { namespace {
EXPECT_TRUE(swapChain->IsAlive()); EXPECT_TRUE(swapChain->IsAlive());
} }
Ref<TextureBase> texture;
{
TextureDescriptor desc = {};
EXPECT_CALL(mDevice, CreateTextureImpl)
.WillOnce(Return(ByMove(AcquireRef(textureMock))));
DAWN_ASSERT_AND_ASSIGN(texture, mDevice.CreateTexture(&desc));
EXPECT_TRUE(texture->IsAlive());
}
Ref<TextureViewBase> textureView;
{
TextureViewDescriptor desc = {};
EXPECT_CALL(mDevice, CreateTextureViewImpl)
.WillOnce(Return(ByMove(AcquireRef(textureViewMock))));
DAWN_ASSERT_AND_ASSIGN(textureView,
mDevice.CreateTextureView(GetTexture().Get(), &desc));
EXPECT_TRUE(textureView->IsAlive());
}
mDevice.DestroyObjects(); mDevice.DestroyObjects();
EXPECT_FALSE(bindGroup->IsAlive()); EXPECT_FALSE(bindGroup->IsAlive());
EXPECT_FALSE(bindGroupLayout->IsAlive()); EXPECT_FALSE(bindGroupLayout->IsAlive());
EXPECT_FALSE(buffer->IsAlive()); EXPECT_FALSE(buffer->IsAlive());
EXPECT_FALSE(computePipeline->IsAlive()); EXPECT_FALSE(computePipeline->IsAlive());
EXPECT_FALSE(externalTexture->IsAlive());
EXPECT_FALSE(pipelineLayout->IsAlive()); EXPECT_FALSE(pipelineLayout->IsAlive());
EXPECT_FALSE(querySet->IsAlive()); EXPECT_FALSE(querySet->IsAlive());
EXPECT_FALSE(renderPipeline->IsAlive()); EXPECT_FALSE(renderPipeline->IsAlive());
EXPECT_FALSE(sampler->IsAlive()); EXPECT_FALSE(sampler->IsAlive());
EXPECT_FALSE(shaderModule->IsAlive()); EXPECT_FALSE(shaderModule->IsAlive());
EXPECT_FALSE(swapChain->IsAlive()); EXPECT_FALSE(swapChain->IsAlive());
EXPECT_FALSE(texture->IsAlive());
EXPECT_FALSE(textureView->IsAlive());
} }
}} // namespace dawn_native:: }} // namespace dawn_native::

View File

@ -0,0 +1,36 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef TESTS_UNITTESTS_NATIVE_MOCKS_EXTERNALTEXTURE_MOCK_H_
#define TESTS_UNITTESTS_NATIVE_MOCKS_EXTERNALTEXTURE_MOCK_H_
#include "dawn_native/Device.h"
#include "dawn_native/ExternalTexture.h"
#include <gmock/gmock.h>
namespace dawn_native {
class ExternalTextureMock : public ExternalTextureBase {
public:
ExternalTextureMock(DeviceBase* device) : ExternalTextureBase(device) {
}
~ExternalTextureMock() override = default;
MOCK_METHOD(void, DestroyApiObjectImpl, (), (override));
};
} // namespace dawn_native
#endif // TESTS_UNITTESTS_NATIVE_MOCKS_EXTERNALTEXTURE_MOCK_H_

View File

@ -0,0 +1,46 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef TESTS_UNITTESTS_NATIVE_MOCKS_TEXTURE_MOCK_H_
#define TESTS_UNITTESTS_NATIVE_MOCKS_TEXTURE_MOCK_H_
#include "dawn_native/Device.h"
#include "dawn_native/Texture.h"
#include <gmock/gmock.h>
namespace dawn_native {
class TextureMock : public TextureBase {
public:
TextureMock(DeviceBase* device, TextureBase::TextureState state)
: TextureBase(device, state) {
}
~TextureMock() override = default;
MOCK_METHOD(void, DestroyApiObjectImpl, (), (override));
};
class TextureViewMock : public TextureViewBase {
public:
TextureViewMock(TextureBase* texture) : TextureViewBase(texture) {
}
~TextureViewMock() override = default;
MOCK_METHOD(void, DestroyApiObjectImpl, (), (override));
};
} // namespace dawn_native
#endif // TESTS_UNITTESTS_NATIVE_MOCKS_TEXTURE_MOCK_H_