diff --git a/src/dawn/common/LinkedList.h b/src/dawn/common/LinkedList.h index b9503eee18..c196098107 100644 --- a/src/dawn/common/LinkedList.h +++ b/src/dawn/common/LinkedList.h @@ -185,6 +185,9 @@ class LinkedList { // Appends |e| to the end of the linked list. void Append(LinkNode* e) { e->InsertBefore(&root_); } + // Prepends |e| to the front og the linked list. + void Prepend(LinkNode* e) { e->InsertAfter(&root_); } + // Moves all elements (in order) of the list and appends them into |l| leaving the list empty. void MoveInto(LinkedList* l) { if (empty()) { diff --git a/src/dawn/native/BindGroup.cpp b/src/dawn/native/BindGroup.cpp index c5e0afcdfe..8ac9d20144 100644 --- a/src/dawn/native/BindGroup.cpp +++ b/src/dawn/native/BindGroup.cpp @@ -450,11 +450,11 @@ BindGroupBase::BindGroupBase(DeviceBase* device, } } - TrackInDevice(); + GetObjectTrackingList()->Track(this); } BindGroupBase::BindGroupBase(DeviceBase* device) : ApiObjectBase(device, kLabelNotImplemented) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } BindGroupBase::~BindGroupBase() = default; diff --git a/src/dawn/native/BindGroupLayout.cpp b/src/dawn/native/BindGroupLayout.cpp index ae4f071673..d4bd324558 100644 --- a/src/dawn/native/BindGroupLayout.cpp +++ b/src/dawn/native/BindGroupLayout.cpp @@ -481,7 +481,7 @@ BindGroupLayoutBase::BindGroupLayoutBase(DeviceBase* device, const BindGroupLayoutDescriptor* descriptor, PipelineCompatibilityToken pipelineCompatibilityToken) : BindGroupLayoutBase(device, descriptor, pipelineCompatibilityToken, kUntrackedByDevice) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } BindGroupLayoutBase::BindGroupLayoutBase(DeviceBase* device, ObjectBase::ErrorTag tag) @@ -489,7 +489,7 @@ BindGroupLayoutBase::BindGroupLayoutBase(DeviceBase* device, ObjectBase::ErrorTa BindGroupLayoutBase::BindGroupLayoutBase(DeviceBase* device) : ApiObjectBase(device, kLabelNotImplemented) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } BindGroupLayoutBase::~BindGroupLayoutBase() = default; diff --git a/src/dawn/native/Buffer.cpp b/src/dawn/native/Buffer.cpp index 3c0f4e1b40..b7aca54d77 100644 --- a/src/dawn/native/Buffer.cpp +++ b/src/dawn/native/Buffer.cpp @@ -68,7 +68,7 @@ class ErrorBuffer final : public BufferBase { } // Since error buffers in this case may allocate memory, we need to track them // for destruction on the device. - TrackInDevice(); + GetObjectTrackingList()->Track(this); } } @@ -152,7 +152,7 @@ BufferBase::BufferBase(DeviceBase* device, const BufferDescriptor* descriptor) mUsage |= kInternalStorageBuffer; } - TrackInDevice(); + GetObjectTrackingList()->Track(this); } BufferBase::BufferBase(DeviceBase* device, @@ -171,7 +171,7 @@ BufferBase::BufferBase(DeviceBase* device, BufferBase::BufferBase(DeviceBase* device, BufferState state) : ApiObjectBase(device, kLabelNotImplemented), mState(state) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } BufferBase::~BufferBase() { diff --git a/src/dawn/native/CommandBuffer.cpp b/src/dawn/native/CommandBuffer.cpp index ab22dea037..4a5453065b 100644 --- a/src/dawn/native/CommandBuffer.cpp +++ b/src/dawn/native/CommandBuffer.cpp @@ -30,12 +30,12 @@ CommandBufferBase::CommandBufferBase(CommandEncoder* encoder, : ApiObjectBase(encoder->GetDevice(), descriptor->label), mCommands(encoder->AcquireCommands()), mResourceUsages(encoder->AcquireResourceUsages()) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } CommandBufferBase::CommandBufferBase(DeviceBase* device) : ApiObjectBase(device, kLabelNotImplemented) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } CommandBufferBase::CommandBufferBase(DeviceBase* device, ObjectBase::ErrorTag tag) diff --git a/src/dawn/native/CommandEncoder.cpp b/src/dawn/native/CommandEncoder.cpp index 1ac551a0a4..6ffc08d006 100644 --- a/src/dawn/native/CommandEncoder.cpp +++ b/src/dawn/native/CommandEncoder.cpp @@ -718,7 +718,7 @@ CommandEncoder* CommandEncoder::MakeError(DeviceBase* device) { CommandEncoder::CommandEncoder(DeviceBase* device, const CommandEncoderDescriptor* descriptor) : ApiObjectBase(device, descriptor->label), mEncodingContext(device, this) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); const DawnEncoderInternalUsageDescriptor* internalUsageDesc = nullptr; FindInChain(descriptor->nextInChain, &internalUsageDesc); diff --git a/src/dawn/native/ComputePassEncoder.cpp b/src/dawn/native/ComputePassEncoder.cpp index 65d00cbc91..1d3c2b3b7c 100644 --- a/src/dawn/native/ComputePassEncoder.cpp +++ b/src/dawn/native/ComputePassEncoder.cpp @@ -114,7 +114,7 @@ ComputePassEncoder::ComputePassEncoder(DeviceBase* device, EncodingContext* encodingContext) : ProgrammableEncoder(device, descriptor->label, encodingContext), mCommandEncoder(commandEncoder) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } // static diff --git a/src/dawn/native/ComputePipeline.cpp b/src/dawn/native/ComputePipeline.cpp index eca8467798..ef84b2ceed 100644 --- a/src/dawn/native/ComputePipeline.cpp +++ b/src/dawn/native/ComputePipeline.cpp @@ -47,14 +47,14 @@ ComputePipelineBase::ComputePipelineBase(DeviceBase* device, {{SingleShaderStage::Compute, descriptor->compute.module, descriptor->compute.entryPoint, descriptor->compute.constantCount, descriptor->compute.constants}}) { SetContentHash(ComputeContentHash()); - TrackInDevice(); + GetObjectTrackingList()->Track(this); // Initialize the cache key to include the cache type and device information. StreamIn(&mCacheKey, CacheKey::Type::ComputePipeline, device->GetCacheKey()); } ComputePipelineBase::ComputePipelineBase(DeviceBase* device) : PipelineBase(device) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } ComputePipelineBase::ComputePipelineBase(DeviceBase* device, ObjectBase::ErrorTag tag) diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp index 8112f64c5d..9862bf52aa 100644 --- a/src/dawn/native/Device.cpp +++ b/src/dawn/native/Device.cpp @@ -338,7 +338,7 @@ void DeviceBase::DestroyObjects() { // can destroy the frontend cache. // clang-format off - static constexpr std::array kObjectTypeDependencyOrder = { + static constexpr std::array kObjectTypeDependencyOrder = { ObjectType::ComputePassEncoder, ObjectType::RenderPassEncoder, ObjectType::RenderBundleEncoder, @@ -353,26 +353,15 @@ void DeviceBase::DestroyObjects() { ObjectType::BindGroupLayout, ObjectType::ShaderModule, ObjectType::ExternalTexture, - ObjectType::TextureView, - ObjectType::Texture, + ObjectType::Texture, // Note that Textures own the TextureViews. ObjectType::QuerySet, ObjectType::Sampler, ObjectType::Buffer, }; // clang-format on - // We first move all objects out from the tracking list into a separate list so that we can - // avoid locking the same mutex twice. We can then iterate across the separate list to call - // the actual destroy function. - LinkedList objects; for (ObjectType type : kObjectTypeDependencyOrder) { - ApiObjectList& objList = mObjectLists[type]; - const std::lock_guard lock(objList.mutex); - objList.objects.MoveInto(&objects); - } - while (!objects.empty()) { - // The destroy call should also remove the object from the list. - objects.head()->value()->Destroy(); + mObjectLists[type].Destroy(); } } @@ -685,14 +674,8 @@ bool DeviceBase::IsLost() const { return mState != State::Alive; } -void DeviceBase::TrackObject(ApiObjectBase* object) { - ApiObjectList& objectList = mObjectLists[object->GetType()]; - std::lock_guard lock(objectList.mutex); - object->InsertBefore(objectList.objects.head()); -} - -std::mutex* DeviceBase::GetObjectListMutex(ObjectType type) { - return &mObjectLists[type].mutex; +ApiObjectList* DeviceBase::GetObjectTrackingList(ObjectType type) { + return &mObjectLists[type]; } AdapterBase* DeviceBase::GetAdapter() const { diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h index 4fbe874a10..7311fea09c 100644 --- a/src/dawn/native/Device.h +++ b/src/dawn/native/Device.h @@ -333,8 +333,7 @@ class DeviceBase : public RefCountedWithExternalCount { }; State GetState() const; bool IsLost() const; - void TrackObject(ApiObjectBase* object); - std::mutex* GetObjectListMutex(ObjectType type); + ApiObjectList* GetObjectTrackingList(ObjectType type); std::vector GetTogglesUsed() const; WGSLExtensionSet GetWGSLExtensionAllowList() const; @@ -548,12 +547,6 @@ class DeviceBase : public RefCountedWithExternalCount { State mState = State::BeingCreated; - // Encompasses the mutex and the actual list that contains all live objects "owned" by the - // device. - struct ApiObjectList { - std::mutex mutex; - LinkedList objects; - }; PerObjectType mObjectLists; FormatTable mFormatTable; diff --git a/src/dawn/native/ExternalTexture.cpp b/src/dawn/native/ExternalTexture.cpp index 42a511b15b..ab4047093b 100644 --- a/src/dawn/native/ExternalTexture.cpp +++ b/src/dawn/native/ExternalTexture.cpp @@ -115,12 +115,12 @@ ResultOrError> ExternalTextureBase::Create( ExternalTextureBase::ExternalTextureBase(DeviceBase* device, const ExternalTextureDescriptor* descriptor) : ApiObjectBase(device, descriptor->label), mState(ExternalTextureState::Alive) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } ExternalTextureBase::ExternalTextureBase(DeviceBase* device) : ApiObjectBase(device, kLabelNotImplemented), mState(ExternalTextureState::Alive) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } // Error external texture cannot be used in bind group. diff --git a/src/dawn/native/ObjectBase.cpp b/src/dawn/native/ObjectBase.cpp index 763129bf10..6a2f151a16 100644 --- a/src/dawn/native/ObjectBase.cpp +++ b/src/dawn/native/ObjectBase.cpp @@ -37,6 +37,31 @@ DeviceBase* ObjectBase::GetDevice() const { return mDevice.Get(); } +void ApiObjectList::Track(ApiObjectBase* object) { + if (mMarkedDestroyed) { + object->DestroyImpl(); + return; + } + std::lock_guard lock(mMutex); + mObjects.Prepend(object); +} + +bool ApiObjectList::Untrack(ApiObjectBase* object) { + std::lock_guard lock(mMutex); + return object->RemoveFromList(); +} + +void ApiObjectList::Destroy() { + std::lock_guard lock(mMutex); + mMarkedDestroyed = true; + while (!mObjects.empty()) { + auto* head = mObjects.head(); + bool removed = head->RemoveFromList(); + ASSERT(removed); + head->value()->DestroyImpl(); + } +} + ApiObjectBase::ApiObjectBase(DeviceBase* device, const char* label) : ObjectBase(device) { if (label) { mLabel = label; @@ -71,14 +96,18 @@ void ApiObjectBase::DeleteThis() { RefCounted::DeleteThis(); } -void ApiObjectBase::TrackInDevice() { +ApiObjectList* ApiObjectBase::GetObjectTrackingList() { ASSERT(GetDevice() != nullptr); - GetDevice()->TrackObject(this); + return GetDevice()->GetObjectTrackingList(GetType()); } void ApiObjectBase::Destroy() { - const std::lock_guard lock(*GetDevice()->GetObjectListMutex(GetType())); - if (RemoveFromList()) { + if (!IsAlive()) { + return; + } + ApiObjectList* list = GetObjectTrackingList(); + ASSERT(list != nullptr); + if (list->Untrack(this)) { DestroyImpl(); } } diff --git a/src/dawn/native/ObjectBase.h b/src/dawn/native/ObjectBase.h index 5ebaad0b90..c1268bb0c1 100644 --- a/src/dawn/native/ObjectBase.h +++ b/src/dawn/native/ObjectBase.h @@ -15,6 +15,7 @@ #ifndef SRC_DAWN_NATIVE_OBJECTBASE_H_ #define SRC_DAWN_NATIVE_OBJECTBASE_H_ +#include #include #include "dawn/common/LinkedList.h" @@ -23,6 +24,7 @@ namespace dawn::native { +class ApiObjectBase; class DeviceBase; class ErrorMonad : public RefCounted { @@ -48,6 +50,26 @@ class ObjectBase : public ErrorMonad { Ref mDevice; }; +// Generic object list with a mutex for tracking for destruction. +class ApiObjectList { + public: + // Tracks an object if the list is not destroyed. If the list is destroyed, destroys the object. + void Track(ApiObjectBase* object); + + // Returns true iff the object was removed from the list. + bool Untrack(ApiObjectBase* object); + + // Destroys and removes all the objects tracked in the list. + void Destroy(); + + private: + // Boolean used to mark the list so that on subsequent calls to Untrack, we don't need to + // reaquire the lock, and Track on new objects immediately destroys them. + bool mMarkedDestroyed = false; + std::mutex mMutex; + LinkedList mObjects; +}; + class ApiObjectBase : public ObjectBase, public LinkNode { public: struct LabelNotImplementedTag {}; @@ -85,7 +107,11 @@ class ApiObjectBase : public ObjectBase, public LinkNode { // and they should ensure that their overriding versions call this underlying version // somewhere. void DeleteThis() override; - void TrackInDevice(); + + // Returns the list where this object may be tracked for future destruction. This can be + // overrided to create hierarchical object tracking ownership: + // i.e. Device -[tracks]-> Texture -[tracks]-> TextureView. + virtual ApiObjectList* GetObjectTrackingList(); // Sub-classes may override this function multiple times. Whenever overriding this function, // however, users should be sure to call their parent's version in the new override to make @@ -94,6 +120,8 @@ class ApiObjectBase : public ObjectBase, public LinkNode { virtual void DestroyImpl() = 0; private: + friend class ApiObjectList; + virtual void SetLabelImpl(); std::string mLabel; diff --git a/src/dawn/native/PipelineLayout.cpp b/src/dawn/native/PipelineLayout.cpp index c740a71915..887a5198ef 100644 --- a/src/dawn/native/PipelineLayout.cpp +++ b/src/dawn/native/PipelineLayout.cpp @@ -71,12 +71,12 @@ PipelineLayoutBase::PipelineLayoutBase(DeviceBase* device, PipelineLayoutBase::PipelineLayoutBase(DeviceBase* device, const PipelineLayoutDescriptor* descriptor) : PipelineLayoutBase(device, descriptor, kUntrackedByDevice) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } PipelineLayoutBase::PipelineLayoutBase(DeviceBase* device) : ApiObjectBase(device, kLabelNotImplemented) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } PipelineLayoutBase::PipelineLayoutBase(DeviceBase* device, ObjectBase::ErrorTag tag) diff --git a/src/dawn/native/QuerySet.cpp b/src/dawn/native/QuerySet.cpp index ad75bedebc..2776dddb1c 100644 --- a/src/dawn/native/QuerySet.cpp +++ b/src/dawn/native/QuerySet.cpp @@ -107,11 +107,11 @@ QuerySetBase::QuerySetBase(DeviceBase* device, const QuerySetDescriptor* descrip } mQueryAvailability.resize(descriptor->count); - TrackInDevice(); + GetObjectTrackingList()->Track(this); } QuerySetBase::QuerySetBase(DeviceBase* device) : ApiObjectBase(device, kLabelNotImplemented) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } QuerySetBase::QuerySetBase(DeviceBase* device, diff --git a/src/dawn/native/RenderBundle.cpp b/src/dawn/native/RenderBundle.cpp index d2e3d6939c..c200cbe9da 100644 --- a/src/dawn/native/RenderBundle.cpp +++ b/src/dawn/native/RenderBundle.cpp @@ -39,7 +39,7 @@ RenderBundleBase::RenderBundleBase(RenderBundleEncoder* encoder, mStencilReadOnly(stencilReadOnly), mDrawCount(encoder->GetDrawCount()), mResourceUsage(std::move(resourceUsage)) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } void RenderBundleBase::DestroyImpl() { diff --git a/src/dawn/native/RenderBundleEncoder.cpp b/src/dawn/native/RenderBundleEncoder.cpp index 02cc54c134..01e48fc9e9 100644 --- a/src/dawn/native/RenderBundleEncoder.cpp +++ b/src/dawn/native/RenderBundleEncoder.cpp @@ -100,7 +100,7 @@ RenderBundleEncoder::RenderBundleEncoder(DeviceBase* device, descriptor->depthReadOnly, descriptor->stencilReadOnly), mBundleEncodingContext(device, this) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } RenderBundleEncoder::RenderBundleEncoder(DeviceBase* device, ErrorTag errorTag) diff --git a/src/dawn/native/RenderPassEncoder.cpp b/src/dawn/native/RenderPassEncoder.cpp index b066655f37..6965f12ca1 100644 --- a/src/dawn/native/RenderPassEncoder.cpp +++ b/src/dawn/native/RenderPassEncoder.cpp @@ -76,7 +76,7 @@ RenderPassEncoder::RenderPassEncoder(DeviceBase* device, if (maxDrawCountInfo) { mMaxDrawCount = maxDrawCountInfo->maxDrawCount; } - TrackInDevice(); + GetObjectTrackingList()->Track(this); } // static diff --git a/src/dawn/native/RenderPipeline.cpp b/src/dawn/native/RenderPipeline.cpp index 03b90bb69c..553896fc64 100644 --- a/src/dawn/native/RenderPipeline.cpp +++ b/src/dawn/native/RenderPipeline.cpp @@ -616,14 +616,14 @@ RenderPipelineBase::RenderPipelineBase(DeviceBase* device, } SetContentHash(ComputeContentHash()); - TrackInDevice(); + GetObjectTrackingList()->Track(this); // Initialize the cache key to include the cache type and device information. StreamIn(&mCacheKey, CacheKey::Type::RenderPipeline, device->GetCacheKey()); } RenderPipelineBase::RenderPipelineBase(DeviceBase* device) : PipelineBase(device) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } RenderPipelineBase::RenderPipelineBase(DeviceBase* device, ObjectBase::ErrorTag tag) diff --git a/src/dawn/native/Sampler.cpp b/src/dawn/native/Sampler.cpp index 5d8715795d..2205a3b049 100644 --- a/src/dawn/native/Sampler.cpp +++ b/src/dawn/native/Sampler.cpp @@ -86,11 +86,11 @@ SamplerBase::SamplerBase(DeviceBase* device, SamplerBase::SamplerBase(DeviceBase* device, const SamplerDescriptor* descriptor) : SamplerBase(device, descriptor, kUntrackedByDevice) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } SamplerBase::SamplerBase(DeviceBase* device) : ApiObjectBase(device, kLabelNotImplemented) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } SamplerBase::SamplerBase(DeviceBase* device, ObjectBase::ErrorTag tag) diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp index e527634b2e..f244a50501 100644 --- a/src/dawn/native/ShaderModule.cpp +++ b/src/dawn/native/ShaderModule.cpp @@ -1089,12 +1089,12 @@ ShaderModuleBase::ShaderModuleBase(DeviceBase* device, ShaderModuleBase::ShaderModuleBase(DeviceBase* device, const ShaderModuleDescriptor* descriptor) : ShaderModuleBase(device, descriptor, kUntrackedByDevice) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } ShaderModuleBase::ShaderModuleBase(DeviceBase* device) : ApiObjectBase(device, kLabelNotImplemented) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } ShaderModuleBase::ShaderModuleBase(DeviceBase* device, ObjectBase::ErrorTag tag) diff --git a/src/dawn/native/SwapChain.cpp b/src/dawn/native/SwapChain.cpp index 60cd62b532..3e1d3de721 100644 --- a/src/dawn/native/SwapChain.cpp +++ b/src/dawn/native/SwapChain.cpp @@ -117,7 +117,7 @@ TextureDescriptor GetSwapChainBaseTextureDescriptor(NewSwapChainBase* swapChain) // SwapChainBase SwapChainBase::SwapChainBase(DeviceBase* device) : ApiObjectBase(device, kLabelNotImplemented) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } SwapChainBase::SwapChainBase(DeviceBase* device, ObjectBase::ErrorTag tag) diff --git a/src/dawn/native/Texture.cpp b/src/dawn/native/Texture.cpp index 5ddbbc3674..5c525daa54 100644 --- a/src/dawn/native/Texture.cpp +++ b/src/dawn/native/Texture.cpp @@ -552,7 +552,7 @@ TextureBase::TextureBase(DeviceBase* device, if (internalUsageDesc != nullptr) { mInternalUsage |= internalUsageDesc->internalUsage; } - TrackInDevice(); + GetObjectTrackingList()->Track(this); } TextureBase::~TextureBase() = default; @@ -561,7 +561,7 @@ static constexpr Format kUnusedFormat; TextureBase::TextureBase(DeviceBase* device, TextureState state) : ApiObjectBase(device, kLabelNotImplemented), mFormat(kUnusedFormat), mState(state) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } TextureBase::TextureBase(DeviceBase* device, @@ -578,6 +578,9 @@ TextureBase::TextureBase(DeviceBase* device, void TextureBase::DestroyImpl() { mState = TextureState::Destroyed; + + // Destroy all of the views associated with the texture as well. + mTextureViews.Destroy(); } // static @@ -766,6 +769,10 @@ ResultOrError> TextureBase::CreateView( return GetDevice()->CreateTextureView(this, descriptor); } +ApiObjectList* TextureBase::GetViewTrackingList() { + return &mTextureViews; +} + TextureViewBase* TextureBase::APICreateView(const TextureViewDescriptor* descriptor) { DeviceBase* device = GetDevice(); @@ -831,14 +838,14 @@ TextureViewBase::TextureViewBase(TextureBase* texture, const TextureViewDescript mRange({ConvertViewAspect(mFormat, descriptor->aspect), {descriptor->baseArrayLayer, descriptor->arrayLayerCount}, {descriptor->baseMipLevel, descriptor->mipLevelCount}}) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } TextureViewBase::TextureViewBase(TextureBase* texture) : ApiObjectBase(texture->GetDevice(), kLabelNotImplemented), mTexture(texture), mFormat(kUnusedFormat) { - TrackInDevice(); + GetObjectTrackingList()->Track(this); } TextureViewBase::TextureViewBase(DeviceBase* device, ObjectBase::ErrorTag tag) @@ -907,4 +914,9 @@ const SubresourceRange& TextureViewBase::GetSubresourceRange() const { return mRange; } +ApiObjectList* TextureViewBase::GetObjectTrackingList() { + ASSERT(!IsError()); + return mTexture->GetViewTrackingList(); +} + } // namespace dawn::native diff --git a/src/dawn/native/Texture.h b/src/dawn/native/Texture.h index 84faa6914d..8513ad0004 100644 --- a/src/dawn/native/Texture.h +++ b/src/dawn/native/Texture.h @@ -92,6 +92,7 @@ class TextureBase : public ApiObjectBase { ResultOrError> CreateView( const TextureViewDescriptor* descriptor = nullptr); + ApiObjectList* GetViewTrackingList(); // Dawn API TextureViewBase* APICreateView(const TextureViewDescriptor* descriptor = nullptr); @@ -129,6 +130,10 @@ class TextureBase : public ApiObjectBase { TextureState mState; wgpu::TextureFormat mFormatEnumForReflection; + // Textures track texture views created from them so that they can be destroyed when the texture + // is destroyed. + ApiObjectList mTextureViews; + // TODO(crbug.com/dawn/845): Use a more optimized data structure to save space std::vector mIsSubresourceContentInitializedAtIndex; }; @@ -162,6 +167,8 @@ class TextureViewBase : public ApiObjectBase { private: TextureViewBase(DeviceBase* device, ObjectBase::ErrorTag tag); + ApiObjectList* GetObjectTrackingList() override; + Ref mTexture; const Format& mFormat; diff --git a/src/dawn/tests/unittests/LinkedListTests.cpp b/src/dawn/tests/unittests/LinkedListTests.cpp index 8737bab8e0..4867339dff 100644 --- a/src/dawn/tests/unittests/LinkedListTests.cpp +++ b/src/dawn/tests/unittests/LinkedListTests.cpp @@ -117,6 +117,41 @@ TEST(LinkedList, Append) { } } +TEST(LinkedList, Prepend) { + LinkedList list; + ExpectListContents(list, 0, nullptr); + + Node n1(1); + list.Prepend(&n1); + + EXPECT_EQ(&n1, list.head()); + EXPECT_EQ(&n1, list.tail()); + { + const int expected[] = {1}; + ExpectListContents(list, 1, expected); + } + + Node n2(2); + list.Prepend(&n2); + + EXPECT_EQ(&n2, list.head()); + EXPECT_EQ(&n1, list.tail()); + { + const int expected[] = {2, 1}; + ExpectListContents(list, 2, expected); + } + + Node n3(3); + list.Prepend(&n3); + + EXPECT_EQ(&n3, list.head()); + EXPECT_EQ(&n1, list.tail()); + { + const int expected[] = {3, 2, 1}; + ExpectListContents(list, 3, expected); + } +} + TEST(LinkedList, RemoveFromList) { LinkedList list;