Hash :
6f959e07
Author :
Date :
2023-04-28T16:00:11
Vulkan: Add non-device memory option for VMA image * Updated the required flags for allocateAndBindMemory() to no longer include VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, though still preferred. This allows VMA to allocate from another memory type if the device is out of memory. * Added a debug message to indicate when allocated memory for VMA image does not have all the preferred property flags. * Also added a warning in the case of memory allocation fallback. * Added a perf counter to keep track of image allocation fallbacks from the device memory. * deviceMemoryImageAllocationFallbacks * Added a test to make sure that VMA images can still be allocated from other memory types even if device memory is unavailable. * VulkanImageTest.AllocateVMAImageWhenDeviceOOM Bug: b/280304441 Change-Id: Ic452c18ded25345cdb7e271442372b99aede045e Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4493483 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 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
//
// Copyright 2023 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.
//
// MemoryTracking.h:
// Defines the classes used for memory tracking in ANGLE.
//
#ifndef LIBANGLE_RENDERER_VULKAN_MEMORYTRACKING_H_
#define LIBANGLE_RENDERER_VULKAN_MEMORYTRACKING_H_
#include <array>
#include <atomic>
#include <mutex>
#include "common/angleutils.h"
#include "common/backtrace_utils.h"
#include "common/vulkan/vk_headers.h"
namespace rx
{
class RendererVk;
namespace vk
{
// Used to designate memory allocation type for tracking purposes.
enum class MemoryAllocationType
{
Unspecified = 0,
ImageExternal = 1,
OffscreenSurfaceAttachmentImage = 2,
SwapchainMSAAImage = 3,
SwapchainDepthStencilImage = 4,
StagingImage = 5,
ImplicitMultisampledRenderToTextureImage = 6,
TextureImage = 7,
FontImage = 8,
RenderBufferStorageImage = 9,
Buffer = 10,
BufferExternal = 11,
InvalidEnum = 12,
EnumCount = InvalidEnum,
};
constexpr const char *kMemoryAllocationTypeMessage[] = {
"Unspecified",
"ImageExternal",
"OffscreenSurfaceAttachmentImage",
"SwapchainMSAAImage",
"SwapchainDepthStencilImage",
"StagingImage",
"ImplicitMultisampledRenderToTextureImage",
"TextureImage",
"FontImage",
"RenderBufferStorageImage",
"Buffer",
"BufferExternal",
"Invalid",
};
constexpr const uint32_t kMemoryAllocationTypeCount =
static_cast<uint32_t>(MemoryAllocationType::EnumCount);
// Used to select the severity for memory allocation logs.
enum class MemoryLogSeverity
{
INFO,
WARN,
};
// Used to store memory allocation information for tracking purposes.
struct MemoryAllocationInfo
{
MemoryAllocationInfo() = default;
uint64_t id;
MemoryAllocationType allocType;
uint32_t memoryHeapIndex;
void *handle;
VkDeviceSize size;
};
class MemoryAllocInfoMapKey
{
public:
MemoryAllocInfoMapKey() : handle(nullptr) {}
MemoryAllocInfoMapKey(void *handle) : handle(handle) {}
bool operator==(const MemoryAllocInfoMapKey &rhs) const
{
return reinterpret_cast<uint64_t>(handle) == reinterpret_cast<uint64_t>(rhs.handle);
}
size_t hash() const;
private:
void *handle;
};
// Process GPU memory reports
class MemoryReport final : angle::NonCopyable
{
public:
MemoryReport();
void processCallback(const VkDeviceMemoryReportCallbackDataEXT &callbackData, bool logCallback);
void logMemoryReportStats() const;
private:
struct MemorySizes
{
VkDeviceSize allocatedMemory;
VkDeviceSize allocatedMemoryMax;
VkDeviceSize importedMemory;
VkDeviceSize importedMemoryMax;
};
mutable std::mutex mMemoryReportMutex;
VkDeviceSize mCurrentTotalAllocatedMemory;
VkDeviceSize mMaxTotalAllocatedMemory;
angle::HashMap<VkObjectType, MemorySizes> mSizesPerType;
VkDeviceSize mCurrentTotalImportedMemory;
VkDeviceSize mMaxTotalImportedMemory;
angle::HashMap<uint64_t, int> mUniqueIDCounts;
};
} // namespace vk
// Memory tracker for allocations and deallocations, which is used in RendererVk.
class MemoryAllocationTracker : angle::NonCopyable
{
public:
MemoryAllocationTracker(RendererVk *renderer);
void initMemoryTrackers();
void onDeviceInit();
void onDestroy();
// Memory statistics are logged when handling a context error.
void logMemoryStatsOnError();
// Collect information regarding memory allocations and deallocations.
void onMemoryAllocImpl(vk::MemoryAllocationType allocType,
VkDeviceSize size,
uint32_t memoryTypeIndex,
void *handle);
void onMemoryDeallocImpl(vk::MemoryAllocationType allocType,
VkDeviceSize size,
uint32_t memoryTypeIndex,
void *handle);
// Memory allocation statistics functions.
VkDeviceSize getActiveMemoryAllocationsSize(uint32_t allocTypeIndex) const;
VkDeviceSize getActiveHeapMemoryAllocationsSize(uint32_t allocTypeIndex,
uint32_t heapIndex) const;
uint64_t getActiveMemoryAllocationsCount(uint32_t allocTypeIndex) const;
uint64_t getActiveHeapMemoryAllocationsCount(uint32_t allocTypeIndex, uint32_t heapIndex) const;
// Compare the expected flags with the flags of the allocated memory.
void compareExpectedFlagsWithAllocatedFlags(VkMemoryPropertyFlags requiredFlags,
VkMemoryPropertyFlags preferredFlags,
VkMemoryPropertyFlags allocatedFlags,
void *handle);
// Pending memory allocation information is used for logging in case of an unsuccessful
// allocation. It is cleared in onMemoryAlloc().
VkDeviceSize getPendingMemoryAllocationSize() const;
vk::MemoryAllocationType getPendingMemoryAllocationType() const;
uint32_t getPendingMemoryTypeIndex() const;
void resetPendingMemoryAlloc();
void setPendingMemoryAlloc(vk::MemoryAllocationType allocType,
VkDeviceSize size,
uint32_t memoryTypeIndex);
private:
// Pointer to parent renderer object.
RendererVk *const mRenderer;
// For tracking the overall memory allocation sizes and counts per memory allocation type.
std::array<std::atomic<VkDeviceSize>, vk::kMemoryAllocationTypeCount>
mActiveMemoryAllocationsSize;
std::array<std::atomic<uint64_t>, vk::kMemoryAllocationTypeCount> mActiveMemoryAllocationsCount;
// Memory allocation data per memory heap.
using PerHeapMemoryAllocationSizeArray =
std::array<std::atomic<VkDeviceSize>, VK_MAX_MEMORY_HEAPS>;
using PerHeapMemoryAllocationCountArray =
std::array<std::atomic<uint64_t>, VK_MAX_MEMORY_HEAPS>;
std::array<PerHeapMemoryAllocationSizeArray, vk::kMemoryAllocationTypeCount>
mActivePerHeapMemoryAllocationsSize;
std::array<PerHeapMemoryAllocationCountArray, vk::kMemoryAllocationTypeCount>
mActivePerHeapMemoryAllocationsCount;
// Pending memory allocation information is used for logging in case of an allocation error.
// It includes the size and type of the last attempted allocation, which are cleared after
// the allocation is successful.
std::atomic<VkDeviceSize> mPendingMemoryAllocationSize;
std::atomic<vk::MemoryAllocationType> mPendingMemoryAllocationType;
std::atomic<uint32_t> mPendingMemoryTypeIndex;
// Mutex is used to update the data when debug layers are enabled.
std::mutex mMemoryAllocationMutex;
// Additional information regarding memory allocation with debug layers enabled, including
// allocation ID and a record of all active allocations.
uint64_t mMemoryAllocationID;
using MemoryAllocInfoMap = angle::HashMap<vk::MemoryAllocInfoMapKey, vk::MemoryAllocationInfo>;
std::unordered_map<angle::BacktraceInfo, MemoryAllocInfoMap> mMemoryAllocationRecord;
};
} // namespace rx
// Introduce std::hash for MemoryAllocInfoMapKey.
namespace std
{
template <>
struct hash<rx::vk::MemoryAllocInfoMapKey>
{
size_t operator()(const rx::vk::MemoryAllocInfoMapKey &key) const { return key.hash(); }
};
} // namespace std
#endif // LIBANGLE_RENDERER_VULKAN_MEMORYTRACKING_H_