Hash :
58d7ace2
Author :
Date :
2022-11-22T16:08:07
Vulkan: Add memory allocation log support in debug
* Added a memory tracker to the renderer object to keep track of the
memory allocations and deallocations in more detail.
* This feature is used for debugging only.
* To enable it, set angle_enable_memory_alloc_logging=true in GN args
(added in renderer/vulkan/BUILD).
* It is related to ANGLE_ENABLE_MEMORY_ALLOC_LOGGING in the code.
* The tracker are updated in the memory allocation tracking functions
if the feature is enabled. (The counter is always updated, even if
the feature is disabled.)
* At the end of a RendererVk object, it checks for and logs any
remaining allocated memory from MemoryAllocationType members.
* The data is stored in the map object "mMemoryAllocationTracker".
The key used for it is currently of type angle::BacktraceInfo.
* If angle_enable_unwind_backtrace_support is disabled, or not on
Android, the key is an empty object.
* MemoryAllocInfoMapKey is used as a key to access the allocation
information.
Bug: b/242641395
Change-Id: If701a4bdea2f8738a830ee47e0c7c5cdacf95b87
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4050103
Reviewed-by: Charlie Lao <cclao@google.com>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Amirali Abdolrashidi <abdolrashidi@google.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
//
// Copyright 2022 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Suballocation.cpp:
// Implements class methods for BufferBlock and Suballocation and other related classes
//
// #include "libANGLE/renderer/vulkan/vk_utils.h"
#include "libANGLE/renderer/vulkan/Suballocation.h"
#include "libANGLE/Context.h"
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.h"
namespace rx
{
namespace vk
{
// BufferBlock implementation.
BufferBlock::BufferBlock()
: mMemoryPropertyFlags(0),
mSize(0),
mAllocatedBufferSize(0),
mMemoryAllocationType(MemoryAllocationType::InvalidEnum),
mMappedMemory(nullptr)
{}
BufferBlock::BufferBlock(BufferBlock &&other)
: mVirtualBlock(std::move(other.mVirtualBlock)),
mBuffer(std::move(other.mBuffer)),
mDeviceMemory(std::move(other.mDeviceMemory)),
mMemoryPropertyFlags(other.mMemoryPropertyFlags),
mSize(other.mSize),
mAllocatedBufferSize(other.mAllocatedBufferSize),
mMemoryAllocationType(other.mMemoryAllocationType),
mMappedMemory(other.mMappedMemory),
mSerial(other.mSerial),
mCountRemainsEmpty(0)
{}
BufferBlock &BufferBlock::operator=(BufferBlock &&other)
{
std::swap(mVirtualBlock, other.mVirtualBlock);
std::swap(mBuffer, other.mBuffer);
std::swap(mDeviceMemory, other.mDeviceMemory);
std::swap(mMemoryPropertyFlags, other.mMemoryPropertyFlags);
std::swap(mSize, other.mSize);
std::swap(mAllocatedBufferSize, other.mAllocatedBufferSize);
std::swap(mMemoryAllocationType, other.mMemoryAllocationType);
std::swap(mMappedMemory, other.mMappedMemory);
std::swap(mSerial, other.mSerial);
std::swap(mCountRemainsEmpty, other.mCountRemainsEmpty);
return *this;
}
BufferBlock::~BufferBlock()
{
ASSERT(!mVirtualBlock.valid());
ASSERT(!mBuffer.valid());
ASSERT(!mDeviceMemory.valid());
ASSERT(mDescriptorSetCacheManager.empty());
}
void BufferBlock::destroy(RendererVk *renderer)
{
VkDevice device = renderer->getDevice();
mDescriptorSetCacheManager.destroyKeys(renderer);
if (mMappedMemory)
{
unmap(device);
}
renderer->onMemoryDealloc(mMemoryAllocationType, mAllocatedBufferSize,
mDeviceMemory.getHandle());
mVirtualBlock.destroy(device);
mBuffer.destroy(device);
mDeviceMemory.destroy(device);
}
angle::Result BufferBlock::init(Context *context,
Buffer &buffer,
vma::VirtualBlockCreateFlags flags,
DeviceMemory &deviceMemory,
VkMemoryPropertyFlags memoryPropertyFlags,
VkDeviceSize size)
{
RendererVk *renderer = context->getRenderer();
ASSERT(!mVirtualBlock.valid());
ASSERT(!mBuffer.valid());
ASSERT(!mDeviceMemory.valid());
ANGLE_VK_TRY(context, mVirtualBlock.init(renderer->getDevice(), flags, size));
mBuffer = std::move(buffer);
mDeviceMemory = std::move(deviceMemory);
mMemoryPropertyFlags = memoryPropertyFlags;
mSize = size;
mAllocatedBufferSize = size;
mMemoryAllocationType = MemoryAllocationType::Buffer;
mMappedMemory = nullptr;
mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
return angle::Result::Continue;
}
void BufferBlock::initWithoutVirtualBlock(Context *context,
Buffer &buffer,
MemoryAllocationType memoryAllocationType,
DeviceMemory &deviceMemory,
VkMemoryPropertyFlags memoryPropertyFlags,
VkDeviceSize size,
VkDeviceSize allocatedBufferSize)
{
RendererVk *renderer = context->getRenderer();
ASSERT(!mVirtualBlock.valid());
ASSERT(!mBuffer.valid());
ASSERT(!mDeviceMemory.valid());
mBuffer = std::move(buffer);
mDeviceMemory = std::move(deviceMemory);
mMemoryPropertyFlags = memoryPropertyFlags;
mSize = size;
mAllocatedBufferSize = allocatedBufferSize;
mMemoryAllocationType = memoryAllocationType;
mMappedMemory = nullptr;
mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
}
VkResult BufferBlock::map(const VkDevice device)
{
ASSERT(mMappedMemory == nullptr);
return mDeviceMemory.map(device, 0, mSize, 0, &mMappedMemory);
}
void BufferBlock::unmap(const VkDevice device)
{
mDeviceMemory.unmap(device);
mMappedMemory = nullptr;
}
VkResult BufferBlock::allocate(VkDeviceSize size,
VkDeviceSize alignment,
VmaVirtualAllocation *allocationOut,
VkDeviceSize *offsetOut)
{
std::unique_lock<std::mutex> lock(mVirtualBlockMutex);
mCountRemainsEmpty = 0;
return mVirtualBlock.allocate(size, alignment, allocationOut, offsetOut);
}
void BufferBlock::free(VmaVirtualAllocation allocation, VkDeviceSize offset)
{
std::unique_lock<std::mutex> lock(mVirtualBlockMutex);
mVirtualBlock.free(allocation, offset);
}
int32_t BufferBlock::getAndIncrementEmptyCounter()
{
return ++mCountRemainsEmpty;
}
void BufferBlock::calculateStats(vma::StatInfo *pStatInfo) const
{
std::unique_lock<std::mutex> lock(mVirtualBlockMutex);
mVirtualBlock.calculateStats(pStatInfo);
}
// BufferSuballocation implementation.
VkResult BufferSuballocation::map(Context *context)
{
return mBufferBlock->map(context->getDevice());
}
// SharedBufferSuballocationGarbage implementation.
bool SharedBufferSuballocationGarbage::destroyIfComplete(RendererVk *renderer)
{
if (renderer->hasUnfinishedUse(mLifetime))
{
return false;
}
mBuffer.destroy(renderer->getDevice());
mSuballocation.destroy(renderer);
return true;
}
bool SharedBufferSuballocationGarbage::hasUnsubmittedUse(RendererVk *renderer) const
{
return renderer->hasUnsubmittedUse(mLifetime);
}
} // namespace vk
} // namespace rx