1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "gpu_memory_allocator_vk.h"
17 
18 #include <cinttypes>
19 #include <vulkan/vulkan_core.h>
20 
21 // Including the external library header <vk_mem_alloc.h> causes a warning. Disabling it.
22 #ifdef _MSC_VER
23 #pragma warning(push)
24 #pragma warning(disable : 4701)
25 #elif defined(__clang__)
26 #pragma clang diagnostic push
27 #pragma clang diagnostic ignored "-Wignored-qualifiers"
28 #pragma clang diagnostic ignored "-Wswitch"
29 #elif defined(__GNUC__)
30 #pragma GCC diagnostic push
31 #pragma GCC diagnostic ignored "-Wignored-qualifiers"
32 #pragma GCC diagnostic ignored "-Wswitch"
33 #endif
34 // vma_mem_alloc.h will use VMA_NULLABLE and VMA_NOT_NULL as clang nullability attribtues but does a
35 // poor job at using them everywhere. Thus it causes lots of clang compiler warnings. We just
36 // disable them here by defining them to be nothing.
37 #ifdef VMA_NULLABLE
38 #undef VMA_NULLABLE
39 #define VMA_NULLABLE
40 #endif
41 #ifdef VMA_NOT_NULL
42 #undef VMA_NOT_NULL
43 #define VMA_NOT_NULL
44 #endif
45 #define VMA_IMPLEMENTATION
46 #ifdef __OHOS_PLATFORM__
47 #include "../../../../../../../third_party/skia/third_party/vulkanmemoryallocator/include/vk_mem_alloc.h"
48 #else
49 #include <VulkanMemoryAllocator/src/vk_mem_alloc.h>
50 #endif
51 #ifdef _MSC_VER
52 #pragma warning(pop)
53 #elif defined(__clang__)
54 #pragma clang diagnostic pop
55 #elif defined(__GNUC__)
56 #pragma GCC diagnostic pop
57 #endif
58 
59 #include <base/containers/vector.h>
60 #include <base/util/formats.h>
61 
62 #if (RENDER_PERF_ENABLED == 1)
63 #include <core/implementation_uids.h>
64 #include <core/perf/intf_performance_data_manager.h>
65 #endif
66 
67 #include <render/device/gpu_resource_desc.h>
68 #include <render/namespace.h>
69 
70 #include "util/log.h"
71 #include "vulkan/validate_vk.h"
72 
73 using namespace BASE_NS;
74 
75 template<>
hash(const RENDER_NS::GpuBufferDesc & desc)76 uint64_t BASE_NS::hash(const RENDER_NS::GpuBufferDesc& desc)
77 {
78     const uint64_t importantEngineCreationFlags =
79         (desc.engineCreationFlags &
80             RENDER_NS::EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_SINGLE_SHOT_STAGING) |
81         (desc.engineCreationFlags &
82             RENDER_NS::EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER);
83 
84     uint64_t seed = importantEngineCreationFlags;
85     HashCombine(seed, static_cast<uint64_t>(desc.usageFlags), static_cast<uint64_t>(desc.memoryPropertyFlags));
86     return seed;
87 }
88 
89 template<>
hash(const RENDER_NS::GpuImageDesc & desc)90 uint64_t BASE_NS::hash(const RENDER_NS::GpuImageDesc& desc)
91 {
92     const uint64_t importantImageUsageFlags =
93         (desc.usageFlags & RENDER_NS::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) |
94         (desc.usageFlags & RENDER_NS::CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
95 
96     uint64_t seed = importantImageUsageFlags;
97     HashCombine(seed, static_cast<uint64_t>(desc.imageType), static_cast<uint64_t>(desc.memoryPropertyFlags));
98     return seed;
99 }
100 
101 RENDER_BEGIN_NAMESPACE()
102 namespace {
103 #if (RENDER_PERF_ENABLED == 1)
LogStats(VmaAllocator aAllocator)104 void LogStats(VmaAllocator aAllocator)
105 {
106     if (auto* inst = CORE_NS::GetInstance<CORE_NS::IPerformanceDataManagerFactory>(CORE_NS::UID_PERFORMANCE_FACTORY);
107         inst) {
108         CORE_NS::IPerformanceDataManager* pdm = inst->Get("Memory");
109 
110         VmaBudget budgets[VK_MAX_MEMORY_HEAPS] {};
111         vmaGetHeapBudgets(aAllocator, budgets);
112         VmaStatistics stats {};
113         for (const VmaBudget& budget : budgets) {
114             stats.blockBytes += budget.statistics.blockBytes;
115             stats.allocationBytes += budget.statistics.allocationBytes;
116         }
117         pdm->UpdateData("VMA Memory", "AllGraphicsMemory", int64_t(stats.blockBytes));
118         pdm->UpdateData("VMA Memory", "GraphicsMemoryInUse", int64_t(stats.allocationBytes));
119         pdm->UpdateData("VMA Memory", "GraphicsMemoryNotInUse", int64_t(stats.blockBytes - stats.allocationBytes));
120     }
121 }
122 #endif
123 
GetVmaVulkanFunctions(VkInstance instance,VkDevice device)124 VmaVulkanFunctions GetVmaVulkanFunctions(VkInstance instance, VkDevice device)
125 {
126     VmaVulkanFunctions funs {};
127 #ifdef USE_NEW_VMA
128     funs.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
129     funs.vkGetDeviceProcAddr = vkGetDeviceProcAddr;
130 #endif
131     funs.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties;
132     funs.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties;
133     funs.vkAllocateMemory = vkAllocateMemory;
134     funs.vkFreeMemory = vkFreeMemory;
135     funs.vkMapMemory = vkMapMemory;
136     funs.vkUnmapMemory = vkUnmapMemory;
137     funs.vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges;
138     funs.vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges;
139     funs.vkBindBufferMemory = vkBindBufferMemory;
140     funs.vkBindImageMemory = vkBindImageMemory;
141     funs.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements;
142     funs.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements;
143     funs.vkCreateBuffer = vkCreateBuffer;
144     funs.vkDestroyBuffer = vkDestroyBuffer;
145     funs.vkCreateImage = vkCreateImage;
146     funs.vkDestroyImage = vkDestroyImage;
147     funs.vkCmdCopyBuffer = vkCmdCopyBuffer;
148 #if VK_VERSION_1_1
149     // NOTE: on some platforms Vulkan library has only the entrypoints for 1.0. To avoid variation just fetch the
150     // function always.
151     funs.vkGetBufferMemoryRequirements2KHR =
152         (PFN_vkGetBufferMemoryRequirements2)vkGetDeviceProcAddr(device, "vkGetBufferMemoryRequirements2");
153     funs.vkGetImageMemoryRequirements2KHR =
154         (PFN_vkGetImageMemoryRequirements2)vkGetDeviceProcAddr(device, "vkGetImageMemoryRequirements2");
155     funs.vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2)(void*)vkGetDeviceProcAddr(device, "vkBindBufferMemory2");
156     funs.vkBindImageMemory2KHR = (PFN_vkBindImageMemory2)(void*)vkGetDeviceProcAddr(device, "vkBindImageMemory2");
157     funs.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetInstanceProcAddr(
158         instance, "vkGetPhysicalDeviceMemoryProperties2");
159 #else
160     // VK_KHR_get_memory_requirements2
161     funs.vkGetBufferMemoryRequirements2KHR =
162         (PFN_vkGetBufferMemoryRequirements2KHR)vkGetDeviceProcAddr(device, "vkGetBufferMemoryRequirements2KHR");
163     funs.vkGetImageMemoryRequirements2KHR =
164         (PFN_vkGetImageMemoryRequirements2KHR)vkGetDeviceProcAddr(device, "vkGetImageMemoryRequirements2KHR");
165     // VK_KHR_bind_memory2
166     funs.vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2KHR)vkGetDeviceProcAddr(device, "vkBindBufferMemory2KHR");
167     funs.vkBindImageMemory2KHR = (PFN_vkBindImageMemory2KHR)vkGetDeviceProcAddr(device, "vkBindImageMemory2KHR");
168     // VK_KHR_get_physical_device_properties2
169     funs.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2KHR)vkGetInstanceProcAddr(
170         instance, "vkGetPhysicalDeviceMemoryProperties2KHR");
171 #endif
172     return funs;
173 }
174 } // namespace
175 
PlatformGpuMemoryAllocator(VkInstance instance,VkPhysicalDevice physicalDevice,VkDevice device,const GpuMemoryAllocatorCreateInfo & createInfo)176 PlatformGpuMemoryAllocator::PlatformGpuMemoryAllocator(VkInstance instance, VkPhysicalDevice physicalDevice,
177     VkDevice device, const GpuMemoryAllocatorCreateInfo& createInfo)
178 {
179     {
180         // 0 -> 1.0
181         uint32_t vulkanApiVersion = 0;
182         // synchronized by the engine
183         VmaAllocatorCreateFlags vmaCreateFlags =
184             VmaAllocatorCreateFlagBits::VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
185 #if (RENDER_VULKAN_RT_ENABLED == 1)
186         vmaCreateFlags |= VmaAllocatorCreateFlagBits::VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
187         vulkanApiVersion = VK_API_VERSION_1_2;
188 #endif
189         VmaVulkanFunctions funs = GetVmaVulkanFunctions(instance, device);
190         VmaAllocatorCreateInfo allocatorInfo = {};
191         allocatorInfo.vulkanApiVersion = vulkanApiVersion;
192         allocatorInfo.flags = vmaCreateFlags;
193         allocatorInfo.preferredLargeHeapBlockSize = createInfo.preferredLargeHeapBlockSize;
194         allocatorInfo.instance = instance;
195         allocatorInfo.physicalDevice = physicalDevice;
196         allocatorInfo.device = device;
197         allocatorInfo.pVulkanFunctions = &funs;
198         vmaCreateAllocator(&allocatorInfo, &allocator_);
199     }
200 
201     // custom pools
202     for (const auto& ref : createInfo.customPools) {
203         PLUGIN_ASSERT(ref.resourceType == MemoryAllocatorResourceType::GPU_BUFFER ||
204                       ref.resourceType == MemoryAllocatorResourceType::GPU_IMAGE);
205 
206         if (ref.resourceType == MemoryAllocatorResourceType::GPU_BUFFER) {
207             CreatePoolForBuffers(ref);
208         } else if (ref.resourceType == MemoryAllocatorResourceType::GPU_IMAGE) {
209             CreatePoolForImages(ref);
210         }
211     }
212 }
213 
~PlatformGpuMemoryAllocator()214 PlatformGpuMemoryAllocator::~PlatformGpuMemoryAllocator()
215 {
216 #if (RENDER_PERF_ENABLED == 1)
217     PLUGIN_ASSERT(memoryDebugStruct_.buffer == 0);
218     PLUGIN_ASSERT(memoryDebugStruct_.image == 0);
219 #endif
220 
221     for (auto ref : customGpuBufferPools_) {
222         if (ref != VK_NULL_HANDLE) {
223             vmaDestroyPool(allocator_, // allocator
224                 ref);                  // pool
225         }
226     }
227     for (auto ref : customGpuImagePools_) {
228         if (ref != VK_NULL_HANDLE) {
229             vmaDestroyPool(allocator_, // allocator
230                 ref);                  // pool
231         }
232     }
233 
234     vmaDestroyAllocator(allocator_);
235 }
236 
CreateBuffer(const VkBufferCreateInfo & bufferCreateInfo,const VmaAllocationCreateInfo & allocationCreateInfo,VkBuffer & buffer,VmaAllocation & allocation,VmaAllocationInfo & allocationInfo)237 void PlatformGpuMemoryAllocator::CreateBuffer(const VkBufferCreateInfo& bufferCreateInfo,
238     const VmaAllocationCreateInfo& allocationCreateInfo, VkBuffer& buffer, VmaAllocation& allocation,
239     VmaAllocationInfo& allocationInfo)
240 {
241     VkResult result = vmaCreateBuffer(allocator_, // allocator,
242         &bufferCreateInfo,                        // pBufferCreateInfo
243         &allocationCreateInfo,                    // pAllocationCreateInfo
244         &buffer,                                  // pBuffer
245         &allocation,                              // pAllocation
246         &allocationInfo);                         // pAllocationInfo
247     if (result != VK_SUCCESS) {
248         if ((result == VK_ERROR_OUT_OF_DEVICE_MEMORY) && (allocationCreateInfo.pool != VK_NULL_HANDLE)) {
249             PLUGIN_LOG_D(
250                 "Out of buffer memory with custom memory pool (i.e. block size might be exceeded), bytesize: %" PRIu64
251                 ", falling back to default memory pool",
252                 bufferCreateInfo.size);
253             VmaAllocationCreateInfo fallBackAllocationCreateInfo = allocationCreateInfo;
254             fallBackAllocationCreateInfo.pool = VK_NULL_HANDLE;
255             result = vmaCreateBuffer(
256                 allocator_, &bufferCreateInfo, &fallBackAllocationCreateInfo, &buffer, &allocation, &allocationInfo);
257         }
258         if (result != VK_SUCCESS) {
259             PLUGIN_LOG_E(
260                 "VKResult not VK_SUCCESS in buffer memory allocation(result : %i), (allocation bytesize : %" PRIu64 ")",
261                 (int32_t)result, bufferCreateInfo.size);
262         }
263     }
264 
265 #if (RENDER_PERF_ENABLED == 1)
266     if (allocation) {
267         memoryDebugStruct_.buffer += static_cast<uint64_t>(allocation->GetSize());
268         LogStats(allocator_);
269     }
270 #endif
271 }
272 
DestroyBuffer(VkBuffer buffer,VmaAllocation allocation)273 void PlatformGpuMemoryAllocator::DestroyBuffer(VkBuffer buffer, VmaAllocation allocation)
274 {
275 #if (RENDER_PERF_ENABLED == 1)
276     uint64_t byteSize = 0;
277     if (allocation) {
278         byteSize = static_cast<uint64_t>(allocation->GetSize());
279     }
280 #endif
281 
282     vmaDestroyBuffer(allocator_, // allocator
283         buffer,                  // buffer
284         allocation);             // allocation
285 
286 #if (RENDER_PERF_ENABLED == 1)
287     if (allocation) {
288         memoryDebugStruct_.buffer -= byteSize;
289         LogStats(allocator_);
290     }
291 #endif
292 }
293 
CreateImage(const VkImageCreateInfo & imageCreateInfo,const VmaAllocationCreateInfo & allocationCreateInfo,VkImage & image,VmaAllocation & allocation,VmaAllocationInfo & allocationInfo)294 void PlatformGpuMemoryAllocator::CreateImage(const VkImageCreateInfo& imageCreateInfo,
295     const VmaAllocationCreateInfo& allocationCreateInfo, VkImage& image, VmaAllocation& allocation,
296     VmaAllocationInfo& allocationInfo)
297 {
298     VkResult result = vmaCreateImage(allocator_, // allocator,
299         &imageCreateInfo,                        // pImageCreateInfo
300         &allocationCreateInfo,                   // pAllocationCreateInfo
301         &image,                                  // pImage
302         &allocation,                             // pAllocation
303         &allocationInfo);                        // pAllocationInfo
304     if ((result == VK_ERROR_OUT_OF_DEVICE_MEMORY) && (allocationCreateInfo.pool != VK_NULL_HANDLE)) {
305         PLUGIN_LOG_D("Out of memory for image with custom memory pool (i.e. block size might be exceeded), falling "
306                      "back to default memory pool");
307         VmaAllocationCreateInfo fallBackAllocationCreateInfo = allocationCreateInfo;
308         fallBackAllocationCreateInfo.pool = VK_NULL_HANDLE;
309         result = vmaCreateImage(
310             allocator_, &imageCreateInfo, &fallBackAllocationCreateInfo, &image, &allocation, &allocationInfo);
311     }
312     if (result != VK_SUCCESS) {
313         PLUGIN_LOG_E("VKResult not VK_SUCCESS in image memory allocation(result : %i) (bytesize : %" PRIu64 ")",
314             (int32_t)result, allocationInfo.size);
315     }
316 
317 #if (RENDER_PERF_ENABLED == 1)
318     if (allocation) {
319         memoryDebugStruct_.image += static_cast<uint64_t>(allocation->GetSize());
320         LogStats(allocator_);
321     }
322 #endif
323 }
324 
DestroyImage(VkImage image,VmaAllocation allocation)325 void PlatformGpuMemoryAllocator::DestroyImage(VkImage image, VmaAllocation allocation)
326 {
327 #if (RENDER_PERF_ENABLED == 1)
328     uint64_t byteSize = 0;
329     if (allocation) {
330         byteSize = static_cast<uint64_t>(allocation->GetSize());
331     }
332 #endif
333 
334     vmaDestroyImage(allocator_, // allocator
335         image,                  // image
336         allocation);            // allocation
337 
338 #if (RENDER_PERF_ENABLED == 1)
339     if (allocation) {
340         memoryDebugStruct_.image -= byteSize;
341         LogStats(allocator_);
342     }
343 #endif
344 }
345 
GetMemoryTypeProperties(const uint32_t memoryType)346 uint32_t PlatformGpuMemoryAllocator::GetMemoryTypeProperties(const uint32_t memoryType)
347 {
348     VkMemoryPropertyFlags memPropertyFlags = 0;
349     vmaGetMemoryTypeProperties(allocator_, memoryType, &memPropertyFlags);
350     return static_cast<uint32_t>(memPropertyFlags);
351 }
352 
FlushAllocation(const VmaAllocation & allocation,const VkDeviceSize offset,const VkDeviceSize byteSize)353 void PlatformGpuMemoryAllocator::FlushAllocation(
354     const VmaAllocation& allocation, const VkDeviceSize offset, const VkDeviceSize byteSize)
355 {
356     vmaFlushAllocation(allocator_, allocation, offset, byteSize);
357 }
358 
InvalidateAllocation(const VmaAllocation & allocation,const VkDeviceSize offset,const VkDeviceSize byteSize)359 void PlatformGpuMemoryAllocator::InvalidateAllocation(
360     const VmaAllocation& allocation, const VkDeviceSize offset, const VkDeviceSize byteSize)
361 {
362     vmaInvalidateAllocation(allocator_, allocation, offset, byteSize);
363 }
364 
GetBufferPool(const GpuBufferDesc & desc) const365 VmaPool PlatformGpuMemoryAllocator::GetBufferPool(const GpuBufferDesc& desc) const
366 {
367     VmaPool result = VK_NULL_HANDLE;
368     const uint64_t hash = BASE_NS::hash(desc);
369     if (const auto iter = hashToGpuBufferPoolIndex_.find(hash); iter != hashToGpuBufferPoolIndex_.cend()) {
370         PLUGIN_ASSERT(iter->second < static_cast<uint32_t>(customGpuBufferPools_.size()));
371         result = customGpuBufferPools_[iter->second];
372     }
373     return result;
374 }
375 
GetImagePool(const GpuImageDesc & desc) const376 VmaPool PlatformGpuMemoryAllocator::GetImagePool(const GpuImageDesc& desc) const
377 {
378     VmaPool result = VK_NULL_HANDLE;
379     const uint64_t hash = BASE_NS::hash(desc);
380     if (const auto iter = hashToGpuImagePoolIndex_.find(hash); iter != hashToGpuImagePoolIndex_.cend()) {
381         PLUGIN_ASSERT(iter->second < static_cast<uint32_t>(customGpuImagePools_.size()));
382         result = customGpuImagePools_[iter->second];
383     }
384     return result;
385 }
386 
MapMemory(VmaAllocation allocation)387 void* PlatformGpuMemoryAllocator::MapMemory(VmaAllocation allocation)
388 {
389     void* data { nullptr };
390     VALIDATE_VK_RESULT(vmaMapMemory(allocator_, allocation, &data));
391     return data;
392 }
393 
UnmapMemory(VmaAllocation allocation)394 void PlatformGpuMemoryAllocator::UnmapMemory(VmaAllocation allocation)
395 {
396     vmaUnmapMemory(allocator_, allocation);
397 }
398 
CreatePoolForBuffers(const GpuMemoryAllocatorCustomPool & customPool)399 void PlatformGpuMemoryAllocator::CreatePoolForBuffers(const GpuMemoryAllocatorCustomPool& customPool)
400 {
401     PLUGIN_ASSERT(customPool.resourceType == MemoryAllocatorResourceType::GPU_BUFFER);
402 
403     const auto& buf = customPool.gpuResourceDesc.buffer;
404 
405     VmaAllocationCreateInfo allocationCreateInfo = {};
406     allocationCreateInfo.preferredFlags = (VkMemoryPropertyFlags)buf.memoryPropertyFlags;
407     allocationCreateInfo.requiredFlags = allocationCreateInfo.preferredFlags;
408     if (allocationCreateInfo.preferredFlags ==
409         ((VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) | (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))) {
410         allocationCreateInfo.flags = VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT;
411     }
412 
413     VkBufferCreateInfo bufferCreateInfo = {};
414     bufferCreateInfo.sType = VkStructureType::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
415     bufferCreateInfo.usage = VkBufferUsageFlagBits(buf.usageFlags);
416     bufferCreateInfo.sharingMode = VkSharingMode::VK_SHARING_MODE_EXCLUSIVE;
417     bufferCreateInfo.size = 1024u; // default reference size
418 
419     uint32_t memoryTypeIndex = 0;
420     VALIDATE_VK_RESULT(vmaFindMemoryTypeIndexForBufferInfo(allocator_, // pImageCreateInfo
421         &bufferCreateInfo,                                             // pBufferCreateInfo
422         &allocationCreateInfo,                                         // pAllocationCreateInfo
423         &memoryTypeIndex));                                            // pMemoryTypeIndex
424 
425     VmaPoolCreateInfo poolCreateInfo = {};
426     poolCreateInfo.flags = (customPool.linearAllocationAlgorithm)
427                                ? VmaPoolCreateFlagBits::VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT
428                                : (VkFlags)0;
429     poolCreateInfo.memoryTypeIndex = memoryTypeIndex;
430     poolCreateInfo.blockSize = customPool.blockSize;
431 
432     const uint64_t hash = BASE_NS::hash(buf);
433     const size_t hashCount = hashToGpuBufferPoolIndex_.count(hash);
434 
435     PLUGIN_ASSERT_MSG(hashCount == 0, "similar buffer pool already created");
436     if (hashCount == 0) {
437         VmaPool pool = VK_NULL_HANDLE;
438         VALIDATE_VK_RESULT(vmaCreatePool(allocator_, // allocator
439             &poolCreateInfo,                         // pCreateInfo
440             &pool));                                 // pPool
441 
442         customGpuBufferPools_.push_back(pool);
443         hashToGpuBufferPoolIndex_[hash] = static_cast<uint32_t>(customGpuBufferPools_.size()) - 1;
444 #if (RENDER_PERF_ENABLED == 1)
445         customGpuBufferPoolNames_.push_back(customPool.name);
446 #endif
447     }
448 }
449 
CreatePoolForImages(const GpuMemoryAllocatorCustomPool & customPool)450 void PlatformGpuMemoryAllocator::CreatePoolForImages(const GpuMemoryAllocatorCustomPool& customPool)
451 {
452     PLUGIN_ASSERT(customPool.resourceType == MemoryAllocatorResourceType::GPU_IMAGE);
453 
454     const auto& img = customPool.gpuResourceDesc.image;
455 
456     VmaAllocationCreateInfo allocationCreateInfo = {};
457     allocationCreateInfo.preferredFlags = (VkMemoryPropertyFlags)img.memoryPropertyFlags;
458     allocationCreateInfo.requiredFlags = allocationCreateInfo.preferredFlags;
459 
460     VkImageCreateInfo imageCreateInfo = {};
461     imageCreateInfo.sType = VkStructureType::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
462     imageCreateInfo.usage = VkImageUsageFlagBits(img.usageFlags);
463     imageCreateInfo.imageType = VkImageType(img.imageType);
464     imageCreateInfo.format = VkFormat::VK_FORMAT_R8G8B8A8_UNORM;
465     imageCreateInfo.sharingMode = VkSharingMode::VK_SHARING_MODE_EXCLUSIVE;
466     imageCreateInfo.extent = VkExtent3D { 1024u, 1024u, 1 }; // default reference size
467     imageCreateInfo.arrayLayers = 1;
468     imageCreateInfo.mipLevels = 1;
469     imageCreateInfo.samples = VkSampleCountFlagBits::VK_SAMPLE_COUNT_1_BIT;
470 
471     uint32_t memoryTypeIndex = 0;
472     VALIDATE_VK_RESULT(vmaFindMemoryTypeIndexForImageInfo(allocator_, // pImageCreateInfo
473         &imageCreateInfo,                                             // pImageCreateInfo
474         &allocationCreateInfo,                                        // pAllocationCreateInfo
475         &memoryTypeIndex));                                           // pMemoryTypeIndex
476 
477     VmaPoolCreateInfo poolCreateInfo = {};
478     poolCreateInfo.flags = (customPool.linearAllocationAlgorithm)
479                                ? VmaPoolCreateFlagBits::VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT
480                                : (VkFlags)0;
481     poolCreateInfo.memoryTypeIndex = memoryTypeIndex;
482 
483     const uint64_t hash = BASE_NS::hash(img);
484     const size_t hashCount = hashToGpuImagePoolIndex_.count(hash);
485 
486     PLUGIN_ASSERT_MSG(hashCount == 0, "similar image pool already created");
487     if (hashCount == 0) {
488         VmaPool pool = VK_NULL_HANDLE;
489         VALIDATE_VK_RESULT(vmaCreatePool(allocator_, // allocator
490             &poolCreateInfo,                         // pCreateInfo
491             &pool));                                 // pPool
492 
493         customGpuImagePools_.push_back(pool);
494         hashToGpuImagePoolIndex_[hash] = static_cast<uint32_t>(customGpuImagePools_.size()) - 1;
495 #if (RENDER_PERF_ENABLED == 1)
496         customGpuImagePoolNames_.push_back(customPool.name);
497 #endif
498     }
499 }
500 
501 #if (RENDER_PERF_ENABLED == 1)
GetBufferPoolDebugName(const GpuBufferDesc & desc) const502 string PlatformGpuMemoryAllocator::GetBufferPoolDebugName(const GpuBufferDesc& desc) const
503 {
504     const size_t hash = BASE_NS::hash(desc);
505     if (const auto iter = hashToGpuBufferPoolIndex_.find(hash); iter != hashToGpuBufferPoolIndex_.cend()) {
506         PLUGIN_ASSERT(iter->second < static_cast<uint32_t>(customGpuBufferPools_.size()));
507         return customGpuBufferPoolNames_[iter->second];
508     }
509     return {};
510 }
GetImagePoolDebugName(const GpuImageDesc & desc) const511 string PlatformGpuMemoryAllocator::GetImagePoolDebugName(const GpuImageDesc& desc) const
512 {
513     const size_t hash = BASE_NS::hash(desc);
514     if (const auto iter = hashToGpuImagePoolIndex_.find(hash); iter != hashToGpuImagePoolIndex_.cend()) {
515         PLUGIN_ASSERT(iter->second < static_cast<uint32_t>(customGpuImagePools_.size()));
516         return customGpuImagePoolNames_[iter->second];
517     }
518     return {};
519 }
520 #endif
521 RENDER_END_NAMESPACE()
522