xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/MemoryTracking.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2023 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // MemoryTracking.h:
7 //    Defines the classes used for memory tracking in ANGLE.
8 //
9 
10 #ifndef LIBANGLE_RENDERER_VULKAN_MEMORYTRACKING_H_
11 #define LIBANGLE_RENDERER_VULKAN_MEMORYTRACKING_H_
12 
13 #include <array>
14 #include <atomic>
15 
16 #include "common/SimpleMutex.h"
17 #include "common/angleutils.h"
18 #include "common/backtrace_utils.h"
19 #include "common/hash_containers.h"
20 #include "common/vulkan/vk_headers.h"
21 
22 namespace rx
23 {
24 namespace vk
25 {
26 class Renderer;
27 
28 // Used to designate memory allocation type for tracking purposes.
29 enum class MemoryAllocationType
30 {
31     Unspecified                              = 0,
32     ImageExternal                            = 1,
33     OffscreenSurfaceAttachmentImage          = 2,
34     SwapchainMSAAImage                       = 3,
35     SwapchainDepthStencilImage               = 4,
36     StagingImage                             = 5,
37     ImplicitMultisampledRenderToTextureImage = 6,
38     TextureImage                             = 7,
39     FontImage                                = 8,
40     RenderBufferStorageImage                 = 9,
41     Buffer                                   = 10,
42     BufferExternal                           = 11,
43 
44     InvalidEnum = 12,
45     EnumCount   = InvalidEnum,
46 };
47 
48 constexpr const char *kMemoryAllocationTypeMessage[] = {
49     "Unspecified",
50     "ImageExternal",
51     "OffscreenSurfaceAttachmentImage",
52     "SwapchainMSAAImage",
53     "SwapchainDepthStencilImage",
54     "StagingImage",
55     "ImplicitMultisampledRenderToTextureImage",
56     "TextureImage",
57     "FontImage",
58     "RenderBufferStorageImage",
59     "Buffer",
60     "BufferExternal",
61     "Invalid",
62 };
63 constexpr const uint32_t kMemoryAllocationTypeCount =
64     static_cast<uint32_t>(MemoryAllocationType::EnumCount);
65 
66 // Used to select the severity for memory allocation logs.
67 enum class MemoryLogSeverity
68 {
69     INFO,
70     WARN,
71 };
72 
73 // Used to store memory allocation information for tracking purposes.
74 struct MemoryAllocationInfo
75 {
76     MemoryAllocationInfo() = default;
77     uint64_t id;
78     MemoryAllocationType allocType;
79     uint32_t memoryHeapIndex;
80     void *handle;
81     VkDeviceSize size;
82 };
83 
84 class MemoryAllocInfoMapKey
85 {
86   public:
MemoryAllocInfoMapKey()87     MemoryAllocInfoMapKey() : handle(nullptr) {}
MemoryAllocInfoMapKey(void * handle)88     MemoryAllocInfoMapKey(void *handle) : handle(handle) {}
89 
90     bool operator==(const MemoryAllocInfoMapKey &rhs) const
91     {
92         return reinterpret_cast<uint64_t>(handle) == reinterpret_cast<uint64_t>(rhs.handle);
93     }
94 
95     size_t hash() const;
96 
97   private:
98     void *handle;
99 };
100 
101 // Process GPU memory reports
102 class MemoryReport final : angle::NonCopyable
103 {
104   public:
105     MemoryReport();
106     void processCallback(const VkDeviceMemoryReportCallbackDataEXT &callbackData, bool logCallback);
107     void logMemoryReportStats() const;
108 
109   private:
110     struct MemorySizes
111     {
112         VkDeviceSize allocatedMemory;
113         VkDeviceSize allocatedMemoryMax;
114         VkDeviceSize importedMemory;
115         VkDeviceSize importedMemoryMax;
116     };
117     mutable angle::SimpleMutex mMemoryReportMutex;
118     VkDeviceSize mCurrentTotalAllocatedMemory;
119     VkDeviceSize mMaxTotalAllocatedMemory;
120     angle::HashMap<VkObjectType, MemorySizes> mSizesPerType;
121     VkDeviceSize mCurrentTotalImportedMemory;
122     VkDeviceSize mMaxTotalImportedMemory;
123     angle::HashMap<uint64_t, int> mUniqueIDCounts;
124 };
125 }  // namespace vk
126 }  // namespace rx
127 
128 // Introduce std::hash for MemoryAllocInfoMapKey.
129 namespace std
130 {
131 template <>
132 struct hash<rx::vk::MemoryAllocInfoMapKey>
133 {
134     size_t operator()(const rx::vk::MemoryAllocInfoMapKey &key) const { return key.hash(); }
135 };
136 }  // namespace std
137 
138 namespace rx
139 {
140 
141 // Memory tracker for allocations and deallocations, which is used in vk::Renderer.
142 class MemoryAllocationTracker : angle::NonCopyable
143 {
144   public:
145     MemoryAllocationTracker(vk::Renderer *renderer);
146     void initMemoryTrackers();
147     void onDeviceInit();
148     void onDestroy();
149 
150     // Memory statistics are logged when handling a context error.
151     void logMemoryStatsOnError();
152 
153     // Collect information regarding memory allocations and deallocations.
154     void onMemoryAllocImpl(vk::MemoryAllocationType allocType,
155                            VkDeviceSize size,
156                            uint32_t memoryTypeIndex,
157                            void *handle);
158     void onMemoryDeallocImpl(vk::MemoryAllocationType allocType,
159                              VkDeviceSize size,
160                              uint32_t memoryTypeIndex,
161                              void *handle);
162 
163     // Memory allocation statistics functions.
164     VkDeviceSize getActiveMemoryAllocationsSize(uint32_t allocTypeIndex) const;
165     VkDeviceSize getActiveHeapMemoryAllocationsSize(uint32_t allocTypeIndex,
166                                                     uint32_t heapIndex) const;
167 
168     uint64_t getActiveMemoryAllocationsCount(uint32_t allocTypeIndex) const;
169     uint64_t getActiveHeapMemoryAllocationsCount(uint32_t allocTypeIndex, uint32_t heapIndex) const;
170 
171     // Compare the expected flags with the flags of the allocated memory.
172     void compareExpectedFlagsWithAllocatedFlags(VkMemoryPropertyFlags requiredFlags,
173                                                 VkMemoryPropertyFlags preferredFlags,
174                                                 VkMemoryPropertyFlags allocatedFlags,
175                                                 void *handle);
176 
177     // Pending memory allocation information is used for logging in case of an unsuccessful
178     // allocation. It is cleared in onMemoryAlloc().
179     VkDeviceSize getPendingMemoryAllocationSize() const;
180     vk::MemoryAllocationType getPendingMemoryAllocationType() const;
181     uint32_t getPendingMemoryTypeIndex() const;
182 
183     void resetPendingMemoryAlloc();
184     void setPendingMemoryAlloc(vk::MemoryAllocationType allocType,
185                                VkDeviceSize size,
186                                uint32_t memoryTypeIndex);
187 
188   private:
189     // Pointer to parent renderer object.
190     vk::Renderer *const mRenderer;
191 
192     // For tracking the overall memory allocation sizes and counts per memory allocation type.
193     std::array<std::atomic<VkDeviceSize>, vk::kMemoryAllocationTypeCount>
194         mActiveMemoryAllocationsSize;
195     std::array<std::atomic<uint64_t>, vk::kMemoryAllocationTypeCount> mActiveMemoryAllocationsCount;
196 
197     // Memory allocation data per memory heap.
198     using PerHeapMemoryAllocationSizeArray =
199         std::array<std::atomic<VkDeviceSize>, VK_MAX_MEMORY_HEAPS>;
200     using PerHeapMemoryAllocationCountArray =
201         std::array<std::atomic<uint64_t>, VK_MAX_MEMORY_HEAPS>;
202 
203     std::array<PerHeapMemoryAllocationSizeArray, vk::kMemoryAllocationTypeCount>
204         mActivePerHeapMemoryAllocationsSize;
205     std::array<PerHeapMemoryAllocationCountArray, vk::kMemoryAllocationTypeCount>
206         mActivePerHeapMemoryAllocationsCount;
207 
208     // Pending memory allocation information is used for logging in case of an allocation error.
209     // It includes the size and type of the last attempted allocation, which are cleared after
210     // the allocation is successful.
211     std::atomic<VkDeviceSize> mPendingMemoryAllocationSize;
212     std::atomic<vk::MemoryAllocationType> mPendingMemoryAllocationType;
213     std::atomic<uint32_t> mPendingMemoryTypeIndex;
214 
215     // Mutex is used to update the data when debug layers are enabled.
216     angle::SimpleMutex mMemoryAllocationMutex;
217 
218     // Additional information regarding memory allocation with debug layers enabled, including
219     // allocation ID and a record of all active allocations.
220     uint64_t mMemoryAllocationID;
221     using MemoryAllocInfoMap = angle::HashMap<vk::MemoryAllocInfoMapKey, vk::MemoryAllocationInfo>;
222     std::unordered_map<angle::BacktraceInfo, MemoryAllocInfoMap> mMemoryAllocationRecord;
223 };
224 }  // namespace rx
225 
226 #endif  // LIBANGLE_RENDERER_VULKAN_MEMORYTRACKING_H_
227