Commit e56fd224 by Jamie Madill Committed by Commit Bot

Vulkan: Fix BufferHelper leaks in DynamicBuffer.

We were leaking BufferHelper pointers in a couple cases. Fix these systematically by using a unique_ptr template. This leak was detected running ANGLE with LSAN enabled. Bug: angleproject:5377 Change-Id: I30ab235105cf74fae2cfc62a22dde534e2d07e81 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2567641Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Jamie Madill <jmadill@chromium.org>
parent 0be3f296
...@@ -652,6 +652,24 @@ bool CanCopyWithTransferForCopyImage(RendererVk *renderer, ...@@ -652,6 +652,24 @@ bool CanCopyWithTransferForCopyImage(RendererVk *renderer,
return isFormatCompatible && return isFormatCompatible &&
CanCopyWithTransfer(renderer, srcFormat, srcTilingMode, destFormat, destTilingMode); CanCopyWithTransfer(renderer, srcFormat, srcTilingMode, destFormat, destTilingMode);
} }
void ReleaseBufferListToRenderer(RendererVk *renderer, BufferHelperPointerVector *buffers)
{
for (std::unique_ptr<BufferHelper> &toFree : *buffers)
{
toFree->release(renderer);
}
buffers->clear();
}
void DestroyBufferList(RendererVk *renderer, BufferHelperPointerVector *buffers)
{
for (std::unique_ptr<BufferHelper> &toDestroy : *buffers)
{
toDestroy->destroy(renderer);
}
buffers->clear();
}
} // anonymous namespace } // anonymous namespace
// This is an arbitrary max. We can change this later if necessary. // This is an arbitrary max. We can change this later if necessary.
...@@ -1598,7 +1616,6 @@ DynamicBuffer::DynamicBuffer() ...@@ -1598,7 +1616,6 @@ DynamicBuffer::DynamicBuffer()
: mUsage(0), : mUsage(0),
mHostVisible(false), mHostVisible(false),
mInitialSize(0), mInitialSize(0),
mBuffer(nullptr),
mNextAllocationOffset(0), mNextAllocationOffset(0),
mLastFlushOrInvalidateOffset(0), mLastFlushOrInvalidateOffset(0),
mSize(0), mSize(0),
...@@ -1610,16 +1627,14 @@ DynamicBuffer::DynamicBuffer(DynamicBuffer &&other) ...@@ -1610,16 +1627,14 @@ DynamicBuffer::DynamicBuffer(DynamicBuffer &&other)
: mUsage(other.mUsage), : mUsage(other.mUsage),
mHostVisible(other.mHostVisible), mHostVisible(other.mHostVisible),
mInitialSize(other.mInitialSize), mInitialSize(other.mInitialSize),
mBuffer(other.mBuffer), mBuffer(std::move(other.mBuffer)),
mNextAllocationOffset(other.mNextAllocationOffset), mNextAllocationOffset(other.mNextAllocationOffset),
mLastFlushOrInvalidateOffset(other.mLastFlushOrInvalidateOffset), mLastFlushOrInvalidateOffset(other.mLastFlushOrInvalidateOffset),
mSize(other.mSize), mSize(other.mSize),
mAlignment(other.mAlignment), mAlignment(other.mAlignment),
mMemoryPropertyFlags(other.mMemoryPropertyFlags), mMemoryPropertyFlags(other.mMemoryPropertyFlags),
mInFlightBuffers(std::move(other.mInFlightBuffers)) mInFlightBuffers(std::move(other.mInFlightBuffers))
{ {}
other.mBuffer = nullptr;
}
void DynamicBuffer::init(RendererVk *renderer, void DynamicBuffer::init(RendererVk *renderer,
VkBufferUsageFlags usage, VkBufferUsageFlags usage,
...@@ -1663,11 +1678,14 @@ void DynamicBuffer::initWithFlags(RendererVk *renderer, ...@@ -1663,11 +1678,14 @@ void DynamicBuffer::initWithFlags(RendererVk *renderer,
DynamicBuffer::~DynamicBuffer() DynamicBuffer::~DynamicBuffer()
{ {
ASSERT(mBuffer == nullptr); ASSERT(mBuffer == nullptr);
ASSERT(mInFlightBuffers.empty());
ASSERT(mBufferFreeList.empty());
} }
angle::Result DynamicBuffer::allocateNewBuffer(ContextVk *contextVk) angle::Result DynamicBuffer::allocateNewBuffer(ContextVk *contextVk)
{ {
std::unique_ptr<BufferHelper> buffer = std::make_unique<BufferHelper>(); ASSERT(!mBuffer);
mBuffer = std::make_unique<BufferHelper>();
VkBufferCreateInfo createInfo = {}; VkBufferCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
...@@ -1678,12 +1696,7 @@ angle::Result DynamicBuffer::allocateNewBuffer(ContextVk *contextVk) ...@@ -1678,12 +1696,7 @@ angle::Result DynamicBuffer::allocateNewBuffer(ContextVk *contextVk)
createInfo.queueFamilyIndexCount = 0; createInfo.queueFamilyIndexCount = 0;
createInfo.pQueueFamilyIndices = nullptr; createInfo.pQueueFamilyIndices = nullptr;
ANGLE_TRY(buffer->init(contextVk, createInfo, mMemoryPropertyFlags)); return mBuffer->init(contextVk, createInfo, mMemoryPropertyFlags);
ASSERT(!mBuffer);
mBuffer = buffer.release();
return angle::Result::Continue;
} }
bool DynamicBuffer::allocateFromCurrentBuffer(size_t sizeInBytes, bool DynamicBuffer::allocateFromCurrentBuffer(size_t sizeInBytes,
...@@ -1734,8 +1747,8 @@ angle::Result DynamicBuffer::allocateWithAlignment(ContextVk *contextVk, ...@@ -1734,8 +1747,8 @@ angle::Result DynamicBuffer::allocateWithAlignment(ContextVk *contextVk,
ANGLE_TRY(flush(contextVk)); ANGLE_TRY(flush(contextVk));
mBuffer->unmap(contextVk->getRenderer()); mBuffer->unmap(contextVk->getRenderer());
mInFlightBuffers.push_back(mBuffer); mInFlightBuffers.push_back(std::move(mBuffer));
mBuffer = nullptr; ASSERT(!mBuffer);
} }
if (sizeToAllocate > mSize) if (sizeToAllocate > mSize)
...@@ -1743,7 +1756,7 @@ angle::Result DynamicBuffer::allocateWithAlignment(ContextVk *contextVk, ...@@ -1743,7 +1756,7 @@ angle::Result DynamicBuffer::allocateWithAlignment(ContextVk *contextVk,
mSize = std::max(mInitialSize, sizeToAllocate); mSize = std::max(mInitialSize, sizeToAllocate);
// Clear the free list since the free buffers are now too small. // Clear the free list since the free buffers are now too small.
for (BufferHelper *toFree : mBufferFreeList) for (std::unique_ptr<BufferHelper> &toFree : mBufferFreeList)
{ {
toFree->release(contextVk->getRenderer()); toFree->release(contextVk->getRenderer());
} }
...@@ -1759,7 +1772,7 @@ angle::Result DynamicBuffer::allocateWithAlignment(ContextVk *contextVk, ...@@ -1759,7 +1772,7 @@ angle::Result DynamicBuffer::allocateWithAlignment(ContextVk *contextVk,
} }
else else
{ {
mBuffer = mBufferFreeList.front(); mBuffer = std::move(mBufferFreeList.front());
mBufferFreeList.erase(mBufferFreeList.begin()); mBufferFreeList.erase(mBufferFreeList.begin());
} }
...@@ -1827,47 +1840,24 @@ angle::Result DynamicBuffer::invalidate(ContextVk *contextVk) ...@@ -1827,47 +1840,24 @@ angle::Result DynamicBuffer::invalidate(ContextVk *contextVk)
return angle::Result::Continue; return angle::Result::Continue;
} }
void DynamicBuffer::releaseBufferListToRenderer(RendererVk *renderer,
std::vector<BufferHelper *> *buffers)
{
for (BufferHelper *toFree : *buffers)
{
toFree->release(renderer);
delete toFree;
}
buffers->clear();
}
void DynamicBuffer::destroyBufferList(RendererVk *renderer, std::vector<BufferHelper *> *buffers)
{
for (BufferHelper *toFree : *buffers)
{
toFree->destroy(renderer);
delete toFree;
}
buffers->clear();
}
void DynamicBuffer::release(RendererVk *renderer) void DynamicBuffer::release(RendererVk *renderer)
{ {
reset(); reset();
releaseBufferListToRenderer(renderer, &mInFlightBuffers); ReleaseBufferListToRenderer(renderer, &mInFlightBuffers);
releaseBufferListToRenderer(renderer, &mBufferFreeList); ReleaseBufferListToRenderer(renderer, &mBufferFreeList);
if (mBuffer) if (mBuffer)
{ {
mBuffer->release(renderer); mBuffer->release(renderer);
SafeDelete(mBuffer); mBuffer.reset(nullptr);
} }
} }
void DynamicBuffer::releaseInFlightBuffersToResourceUseList(ContextVk *contextVk) void DynamicBuffer::releaseInFlightBuffersToResourceUseList(ContextVk *contextVk)
{ {
ResourceUseList *resourceUseList = &contextVk->getResourceUseList(); ResourceUseList *resourceUseList = &contextVk->getResourceUseList();
for (BufferHelper *bufferHelper : mInFlightBuffers) for (std::unique_ptr<BufferHelper> &bufferHelper : mInFlightBuffers)
{ {
bufferHelper->retain(resourceUseList); bufferHelper->retain(resourceUseList);
...@@ -1878,7 +1868,7 @@ void DynamicBuffer::releaseInFlightBuffersToResourceUseList(ContextVk *contextVk ...@@ -1878,7 +1868,7 @@ void DynamicBuffer::releaseInFlightBuffersToResourceUseList(ContextVk *contextVk
} }
else else
{ {
mBufferFreeList.push_back(bufferHelper); mBufferFreeList.push_back(std::move(bufferHelper));
} }
} }
mInFlightBuffers.clear(); mInFlightBuffers.clear();
...@@ -1886,7 +1876,7 @@ void DynamicBuffer::releaseInFlightBuffersToResourceUseList(ContextVk *contextVk ...@@ -1886,7 +1876,7 @@ void DynamicBuffer::releaseInFlightBuffersToResourceUseList(ContextVk *contextVk
void DynamicBuffer::releaseInFlightBuffers(ContextVk *contextVk) void DynamicBuffer::releaseInFlightBuffers(ContextVk *contextVk)
{ {
for (BufferHelper *toRelease : mInFlightBuffers) for (std::unique_ptr<BufferHelper> &toRelease : mInFlightBuffers)
{ {
// If the dynamic buffer was resized we cannot reuse the retained buffer. // If the dynamic buffer was resized we cannot reuse the retained buffer.
if (toRelease->getSize() < mSize) if (toRelease->getSize() < mSize)
...@@ -1895,7 +1885,7 @@ void DynamicBuffer::releaseInFlightBuffers(ContextVk *contextVk) ...@@ -1895,7 +1885,7 @@ void DynamicBuffer::releaseInFlightBuffers(ContextVk *contextVk)
} }
else else
{ {
mBufferFreeList.push_back(toRelease); mBufferFreeList.push_back(std::move(toRelease));
} }
} }
...@@ -1906,15 +1896,14 @@ void DynamicBuffer::destroy(RendererVk *renderer) ...@@ -1906,15 +1896,14 @@ void DynamicBuffer::destroy(RendererVk *renderer)
{ {
reset(); reset();
destroyBufferList(renderer, &mInFlightBuffers); DestroyBufferList(renderer, &mInFlightBuffers);
destroyBufferList(renderer, &mBufferFreeList); DestroyBufferList(renderer, &mBufferFreeList);
if (mBuffer) if (mBuffer)
{ {
mBuffer->unmap(renderer); mBuffer->unmap(renderer);
mBuffer->destroy(renderer); mBuffer->destroy(renderer);
delete mBuffer; mBuffer.reset(nullptr);
mBuffer = nullptr;
} }
} }
......
...@@ -59,6 +59,8 @@ struct TextureUnit final ...@@ -59,6 +59,8 @@ struct TextureUnit final
// currently active VkBuffer we keep it until it is no longer in use. We then mark it available // currently active VkBuffer we keep it until it is no longer in use. We then mark it available
// for future allocations in a free list. // for future allocations in a free list.
class BufferHelper; class BufferHelper;
using BufferHelperPointerVector = std::vector<std::unique_ptr<BufferHelper>>;
class DynamicBuffer : angle::NonCopyable class DynamicBuffer : angle::NonCopyable
{ {
public: public:
...@@ -127,7 +129,7 @@ class DynamicBuffer : angle::NonCopyable ...@@ -127,7 +129,7 @@ class DynamicBuffer : angle::NonCopyable
// This frees resources immediately. // This frees resources immediately.
void destroy(RendererVk *renderer); void destroy(RendererVk *renderer);
BufferHelper *getCurrentBuffer() const { return mBuffer; } BufferHelper *getCurrentBuffer() const { return mBuffer.get(); }
// **Accumulate** an alignment requirement. A dynamic buffer is used as the staging buffer for // **Accumulate** an alignment requirement. A dynamic buffer is used as the staging buffer for
// image uploads, which can contain updates to unrelated mips, possibly with different formats. // image uploads, which can contain updates to unrelated mips, possibly with different formats.
...@@ -147,21 +149,19 @@ class DynamicBuffer : angle::NonCopyable ...@@ -147,21 +149,19 @@ class DynamicBuffer : angle::NonCopyable
private: private:
void reset(); void reset();
angle::Result allocateNewBuffer(ContextVk *contextVk); angle::Result allocateNewBuffer(ContextVk *contextVk);
void releaseBufferListToRenderer(RendererVk *renderer, std::vector<BufferHelper *> *buffers);
void destroyBufferList(RendererVk *renderer, std::vector<BufferHelper *> *buffers);
VkBufferUsageFlags mUsage; VkBufferUsageFlags mUsage;
bool mHostVisible; bool mHostVisible;
size_t mInitialSize; size_t mInitialSize;
BufferHelper *mBuffer; std::unique_ptr<BufferHelper> mBuffer;
uint32_t mNextAllocationOffset; uint32_t mNextAllocationOffset;
uint32_t mLastFlushOrInvalidateOffset; uint32_t mLastFlushOrInvalidateOffset;
size_t mSize; size_t mSize;
size_t mAlignment; size_t mAlignment;
VkMemoryPropertyFlags mMemoryPropertyFlags; VkMemoryPropertyFlags mMemoryPropertyFlags;
std::vector<BufferHelper *> mInFlightBuffers; BufferHelperPointerVector mInFlightBuffers;
std::vector<BufferHelper *> mBufferFreeList; BufferHelperPointerVector mBufferFreeList;
}; };
// Based off of the DynamicBuffer class, DynamicShadowBuffer provides // Based off of the DynamicBuffer class, DynamicShadowBuffer provides
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment