• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 PATH_TO_VMA
47 #include PATH_TO_VMA
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/cpu_perf_scope.h>
65 #include <core/perf/intf_performance_data_manager.h>
66 #endif
67 
68 #include <render/device/gpu_resource_desc.h>
69 #include <render/namespace.h>
70 
71 #include "util/log.h"
72 #include "vulkan/validate_vk.h"
73 
74 using namespace BASE_NS;
75 
76 template<>
hash(const RENDER_NS::GpuBufferDesc & desc)77 uint64_t BASE_NS::hash(const RENDER_NS::GpuBufferDesc& desc)
78 {
79     const uint64_t importantEngineCreationFlags =
80         (desc.engineCreationFlags &
81             RENDER_NS::EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_SINGLE_SHOT_STAGING) |
82         (desc.engineCreationFlags &
83             RENDER_NS::EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_DYNAMIC_RING_BUFFER);
84 
85     uint64_t seed = importantEngineCreationFlags;
86     HashCombine(seed, (uint64_t)desc.usageFlags, (uint64_t)desc.memoryPropertyFlags);
87     return seed;
88 }
89 
90 template<>
hash(const RENDER_NS::GpuImageDesc & desc)91 uint64_t BASE_NS::hash(const RENDER_NS::GpuImageDesc& desc)
92 {
93     const uint64_t importantImageUsageFlags =
94         (desc.usageFlags & RENDER_NS::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) |
95         (desc.usageFlags & RENDER_NS::CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
96 
97     uint64_t seed = importantImageUsageFlags;
98     HashCombine(seed, (uint64_t)desc.imageType, (uint64_t)desc.memoryPropertyFlags);
99     return seed;
100 }
101 
102 RENDER_BEGIN_NAMESPACE()
103 namespace {
104 #if (RENDER_PERF_ENABLED == 1)
105 CORE_PROFILER_SYMBOL(IMAGE_POOL, "image");
106 CORE_PROFILER_SYMBOL(BUFFER_POOL, "buffer");
107 CORE_PROFILER_SYMBOL(MEMORY_MAPPED_POOL, "mapped_memory");
108 
LogStats(VmaAllocator aAllocator)109 void LogStats(VmaAllocator aAllocator)
110 {
111     if (auto* inst = CORE_NS::GetInstance<CORE_NS::IPerformanceDataManagerFactory>(CORE_NS::UID_PERFORMANCE_FACTORY);
112         inst) {
113         CORE_NS::IPerformanceDataManager* pdm = inst->Get("Memory");
114         if (!pdm) {
115             return;
116         }
117 
118         VmaBudget budgets[VK_MAX_MEMORY_HEAPS] {};
119         vmaGetHeapBudgets(aAllocator, budgets);
120         VmaStatistics stats {};
121         for (const VmaBudget& budget : budgets) {
122             stats.blockBytes += budget.statistics.blockBytes;
123             stats.allocationBytes += budget.statistics.allocationBytes;
124         }
125         pdm->UpdateData("VMA Memory", "AllGraphicsMemory", int64_t(stats.blockBytes));
126         pdm->UpdateData("VMA Memory", "GraphicsMemoryInUse", int64_t(stats.allocationBytes));
127         pdm->UpdateData("VMA Memory", "GraphicsMemoryNotInUse", int64_t(stats.blockBytes - stats.allocationBytes));
128     }
129 }
130 #endif
131 
GetVmaVulkanFunctions(VkInstance instance,VkDevice device)132 VmaVulkanFunctions GetVmaVulkanFunctions(VkInstance instance, VkDevice device)
133 {
134     VmaVulkanFunctions funs {};
135 #ifdef USE_NEW_VMA
136     funs.vkGetInstanceProcAddr = vkGetInstanceProcAddr;
137     funs.vkGetDeviceProcAddr = vkGetDeviceProcAddr;
138 #endif
139     funs.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties;
140     funs.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties;
141     funs.vkAllocateMemory = vkAllocateMemory;
142     funs.vkFreeMemory = vkFreeMemory;
143     funs.vkMapMemory = vkMapMemory;
144     funs.vkUnmapMemory = vkUnmapMemory;
145     funs.vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges;
146     funs.vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges;
147     funs.vkBindBufferMemory = vkBindBufferMemory;
148     funs.vkBindImageMemory = vkBindImageMemory;
149     funs.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements;
150     funs.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements;
151     funs.vkCreateBuffer = vkCreateBuffer;
152     funs.vkDestroyBuffer = vkDestroyBuffer;
153     funs.vkCreateImage = vkCreateImage;
154     funs.vkDestroyImage = vkDestroyImage;
155     funs.vkCmdCopyBuffer = vkCmdCopyBuffer;
156 #if VK_VERSION_1_1
157     // NOTE: on some platforms Vulkan library has only the entrypoints for 1.0. To avoid variation just fetch the
158     // function always.
159     funs.vkGetBufferMemoryRequirements2KHR =
160         (PFN_vkGetBufferMemoryRequirements2)vkGetDeviceProcAddr(device, "vkGetBufferMemoryRequirements2");
161     funs.vkGetImageMemoryRequirements2KHR =
162         (PFN_vkGetImageMemoryRequirements2)vkGetDeviceProcAddr(device, "vkGetImageMemoryRequirements2");
163     funs.vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2)(void*)vkGetDeviceProcAddr(device, "vkBindBufferMemory2");
164     funs.vkBindImageMemory2KHR = (PFN_vkBindImageMemory2)(void*)vkGetDeviceProcAddr(device, "vkBindImageMemory2");
165     funs.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2)vkGetInstanceProcAddr(
166         instance, "vkGetPhysicalDeviceMemoryProperties2");
167 #else
168     // VK_KHR_get_memory_requirements2
169     funs.vkGetBufferMemoryRequirements2KHR =
170         (PFN_vkGetBufferMemoryRequirements2KHR)vkGetDeviceProcAddr(device, "vkGetBufferMemoryRequirements2KHR");
171     funs.vkGetImageMemoryRequirements2KHR =
172         (PFN_vkGetImageMemoryRequirements2KHR)vkGetDeviceProcAddr(device, "vkGetImageMemoryRequirements2KHR");
173     // VK_KHR_bind_memory2
174     funs.vkBindBufferMemory2KHR = (PFN_vkBindBufferMemory2KHR)vkGetDeviceProcAddr(device, "vkBindBufferMemory2KHR");
175     funs.vkBindImageMemory2KHR = (PFN_vkBindImageMemory2KHR)vkGetDeviceProcAddr(device, "vkBindImageMemory2KHR");
176     // VK_KHR_get_physical_device_properties2
177     funs.vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2KHR)vkGetInstanceProcAddr(
178         instance, "vkGetPhysicalDeviceMemoryProperties2KHR");
179 #endif
180     return funs;
181 }
182 } // namespace
183 
PlatformGpuMemoryAllocator(VkInstance instance,VkPhysicalDevice physicalDevice,VkDevice device,const GpuMemoryAllocatorCreateInfo & createInfo)184 PlatformGpuMemoryAllocator::PlatformGpuMemoryAllocator(VkInstance instance, VkPhysicalDevice physicalDevice,
185     VkDevice device, const GpuMemoryAllocatorCreateInfo& createInfo)
186 {
187     {
188         // 0 -> 1.0
189         uint32_t vulkanApiVersion = 0;
190         // synchronized by the engine
191         VmaAllocatorCreateFlags vmaCreateFlags =
192             VmaAllocatorCreateFlagBits::VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
193 #if (RENDER_VULKAN_RT_ENABLED == 1)
194         vmaCreateFlags |= VmaAllocatorCreateFlagBits::VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
195         vulkanApiVersion = VK_API_VERSION_1_2;
196 #endif
197         VmaVulkanFunctions funs = GetVmaVulkanFunctions(instance, device);
198         VmaAllocatorCreateInfo allocatorInfo = {};
199         allocatorInfo.vulkanApiVersion = vulkanApiVersion;
200         allocatorInfo.flags = vmaCreateFlags;
201         allocatorInfo.preferredLargeHeapBlockSize = createInfo.preferredLargeHeapBlockSize;
202         allocatorInfo.instance = instance;
203         allocatorInfo.physicalDevice = physicalDevice;
204         allocatorInfo.device = device;
205         allocatorInfo.pVulkanFunctions = &funs;
206         vmaCreateAllocator(&allocatorInfo, &allocator_);
207     }
208 
209     // custom pools
210     for (const auto& ref : createInfo.customPools) {
211         PLUGIN_ASSERT(ref.resourceType == MemoryAllocatorResourceType::GPU_BUFFER ||
212                       ref.resourceType == MemoryAllocatorResourceType::GPU_IMAGE);
213 
214         if (ref.resourceType == MemoryAllocatorResourceType::GPU_BUFFER) {
215             CreatePoolForBuffers(ref);
216         } else if (ref.resourceType == MemoryAllocatorResourceType::GPU_IMAGE) {
217             CreatePoolForImages(ref);
218         }
219     }
220 }
221 
~PlatformGpuMemoryAllocator()222 PlatformGpuMemoryAllocator::~PlatformGpuMemoryAllocator()
223 {
224 #if (RENDER_PERF_ENABLED == 1)
225     PLUGIN_ASSERT(memoryDebugStruct_.buffer == 0);
226     PLUGIN_ASSERT(memoryDebugStruct_.image == 0);
227 #endif
228 
229     for (auto ref : customGpuBufferPools_) {
230         if (ref != VK_NULL_HANDLE) {
231             vmaDestroyPool(allocator_, // allocator
232                 ref);                  // pool
233         }
234     }
235     for (auto ref : customGpuImagePools_) {
236         if (ref != VK_NULL_HANDLE) {
237             vmaDestroyPool(allocator_, // allocator
238                 ref);                  // pool
239         }
240     }
241 
242     vmaDestroyAllocator(allocator_);
243 }
244 
CreateBuffer(const VkBufferCreateInfo & bufferCreateInfo,const VmaAllocationCreateInfo & allocationCreateInfo,VkBuffer & buffer,VmaAllocation & allocation,VmaAllocationInfo & allocationInfo)245 void PlatformGpuMemoryAllocator::CreateBuffer(const VkBufferCreateInfo& bufferCreateInfo,
246     const VmaAllocationCreateInfo& allocationCreateInfo, VkBuffer& buffer, VmaAllocation& allocation,
247     VmaAllocationInfo& allocationInfo)
248 {
249     VkResult result = vmaCreateBuffer(allocator_, // allocator,
250         &bufferCreateInfo,                        // pBufferCreateInfo
251         &allocationCreateInfo,                    // pAllocationCreateInfo
252         &buffer,                                  // pBuffer
253         &allocation,                              // pAllocation
254         &allocationInfo);                         // pAllocationInfo
255     if (result != VK_SUCCESS) {
256         if ((result == VK_ERROR_OUT_OF_DEVICE_MEMORY) && (allocationCreateInfo.pool != VK_NULL_HANDLE)) {
257             PLUGIN_LOG_D(
258                 "Out of buffer memory with custom memory pool (i.e. block size might be exceeded), bytesize: %" PRIu64
259                 ", falling back to default memory pool",
260                 bufferCreateInfo.size);
261             VmaAllocationCreateInfo fallBackAllocationCreateInfo = allocationCreateInfo;
262             fallBackAllocationCreateInfo.pool = VK_NULL_HANDLE;
263             result = vmaCreateBuffer(
264                 allocator_, &bufferCreateInfo, &fallBackAllocationCreateInfo, &buffer, &allocation, &allocationInfo);
265         }
266         if (result != VK_SUCCESS) {
267             PLUGIN_LOG_E(
268                 "VKResult not VK_SUCCESS in buffer memory allocation(result : %i), (allocation bytesize : %" PRIu64 ")",
269                 (int32_t)result, bufferCreateInfo.size);
270         }
271     }
272 
273 #if (RENDER_PERF_ENABLED == 1)
274     if (allocation) {
275         memoryDebugStruct_.buffer += (uint64_t)allocation->GetSize();
276         LogStats(allocator_);
277         CORE_PROFILER_ALLOC_N(buffer, (uint64_t)allocation->GetSize(), BUFFER_POOL);
278     }
279 #endif
280 }
281 
DestroyBuffer(VkBuffer buffer,VmaAllocation allocation)282 void PlatformGpuMemoryAllocator::DestroyBuffer(VkBuffer buffer, VmaAllocation allocation)
283 {
284 #if (RENDER_PERF_ENABLED == 1)
285     uint64_t byteSize = 0;
286     if (allocation) {
287         byteSize = (uint64_t)allocation->GetSize();
288         assert(byteSize > 0);
289     }
290 #endif
291 
292     vmaDestroyBuffer(allocator_, // allocator
293         buffer,                  // buffer
294         allocation);             // allocation
295 
296 #if (RENDER_PERF_ENABLED == 1)
297     if (allocation) {
298         memoryDebugStruct_.buffer -= byteSize;
299         LogStats(allocator_);
300         CORE_PROFILER_FREE_N(buffer, BUFFER_POOL);
301     }
302 #endif
303 }
304 
CreateImage(const VkImageCreateInfo & imageCreateInfo,const VmaAllocationCreateInfo & allocationCreateInfo,VkImage & image,VmaAllocation & allocation,VmaAllocationInfo & allocationInfo)305 void PlatformGpuMemoryAllocator::CreateImage(const VkImageCreateInfo& imageCreateInfo,
306     const VmaAllocationCreateInfo& allocationCreateInfo, VkImage& image, VmaAllocation& allocation,
307     VmaAllocationInfo& allocationInfo)
308 {
309     VkResult result = vmaCreateImage(allocator_, // allocator,
310         &imageCreateInfo,                        // pImageCreateInfo
311         &allocationCreateInfo,                   // pAllocationCreateInfo
312         &image,                                  // pImage
313         &allocation,                             // pAllocation
314         &allocationInfo);                        // pAllocationInfo
315     if ((result == VK_ERROR_OUT_OF_DEVICE_MEMORY) && (allocationCreateInfo.pool != VK_NULL_HANDLE)) {
316         PLUGIN_LOG_D("Out of memory for image with custom memory pool (i.e. block size might be exceeded), falling "
317                      "back to default memory pool");
318         VmaAllocationCreateInfo fallBackAllocationCreateInfo = allocationCreateInfo;
319         fallBackAllocationCreateInfo.pool = VK_NULL_HANDLE;
320         result = vmaCreateImage(
321             allocator_, &imageCreateInfo, &fallBackAllocationCreateInfo, &image, &allocation, &allocationInfo);
322     }
323     if (result != VK_SUCCESS) {
324         PLUGIN_LOG_E("VKResult not VK_SUCCESS in image memory allocation(result : %i) (bytesize : %" PRIu64 ")",
325             (int32_t)result, allocationInfo.size);
326     }
327 
328 #if (RENDER_PERF_ENABLED == 1)
329     if (allocation) {
330         memoryDebugStruct_.image += (uint64_t)allocation->GetSize();
331         LogStats(allocator_);
332         CORE_PROFILER_ALLOC_N(image, (uint64_t)allocation->GetSize(), IMAGE_POOL);
333     }
334 #endif
335 }
336 
DestroyImage(VkImage image,VmaAllocation allocation)337 void PlatformGpuMemoryAllocator::DestroyImage(VkImage image, VmaAllocation allocation)
338 {
339 #if (RENDER_PERF_ENABLED == 1)
340     uint64_t byteSize = 0;
341     if (allocation) {
342         byteSize = (uint64_t)allocation->GetSize();
343         assert(byteSize > 0);
344     }
345 #endif
346 
347     vmaDestroyImage(allocator_, // allocator
348         image,                  // image
349         allocation);            // allocation
350 
351 #if (RENDER_PERF_ENABLED == 1)
352     if (allocation) {
353         memoryDebugStruct_.image -= byteSize;
354         LogStats(allocator_);
355         CORE_PROFILER_FREE_N(image, IMAGE_POOL);
356     }
357 #endif
358 }
359 
GetMemoryTypeProperties(const uint32_t memoryType)360 uint32_t PlatformGpuMemoryAllocator::GetMemoryTypeProperties(const uint32_t memoryType)
361 {
362     VkMemoryPropertyFlags memPropertyFlags = 0;
363     vmaGetMemoryTypeProperties(allocator_, memoryType, &memPropertyFlags);
364     return (uint32_t)memPropertyFlags;
365 }
366 
FlushAllocation(const VmaAllocation & allocation,const VkDeviceSize offset,const VkDeviceSize byteSize)367 void PlatformGpuMemoryAllocator::FlushAllocation(
368     const VmaAllocation& allocation, const VkDeviceSize offset, const VkDeviceSize byteSize)
369 {
370     vmaFlushAllocation(allocator_, allocation, offset, byteSize);
371 }
372 
InvalidateAllocation(const VmaAllocation & allocation,const VkDeviceSize offset,const VkDeviceSize byteSize)373 void PlatformGpuMemoryAllocator::InvalidateAllocation(
374     const VmaAllocation& allocation, const VkDeviceSize offset, const VkDeviceSize byteSize)
375 {
376     vmaInvalidateAllocation(allocator_, allocation, offset, byteSize);
377 }
378 
GetBufferPool(const GpuBufferDesc & desc) const379 VmaPool PlatformGpuMemoryAllocator::GetBufferPool(const GpuBufferDesc& desc) const
380 {
381     VmaPool result = VK_NULL_HANDLE;
382     const uint64_t hash = BASE_NS::hash(desc);
383     if (const auto iter = hashToGpuBufferPoolIndex_.find(hash); iter != hashToGpuBufferPoolIndex_.cend()) {
384         PLUGIN_ASSERT(iter->second < (uint32_t)customGpuBufferPools_.size());
385         result = customGpuBufferPools_[iter->second];
386     }
387     return result;
388 }
389 
GetImagePool(const GpuImageDesc & desc) const390 VmaPool PlatformGpuMemoryAllocator::GetImagePool(const GpuImageDesc& desc) const
391 {
392     VmaPool result = VK_NULL_HANDLE;
393     const uint64_t hash = BASE_NS::hash(desc);
394     if (const auto iter = hashToGpuImagePoolIndex_.find(hash); iter != hashToGpuImagePoolIndex_.cend()) {
395         PLUGIN_ASSERT(iter->second < (uint32_t)customGpuImagePools_.size());
396         result = customGpuImagePools_[iter->second];
397     }
398     return result;
399 }
400 
MapMemory(VmaAllocation allocation)401 void* PlatformGpuMemoryAllocator::MapMemory(VmaAllocation allocation)
402 {
403     void* data { nullptr };
404     VALIDATE_VK_RESULT(vmaMapMemory(allocator_, allocation, &data));
405 #if RENDER_PERF_ENABLED
406     CORE_PROFILER_ALLOC_N(data, (uint64_t)allocation->GetSize(), MEMORY_MAPPED_POOL);
407 #endif
408     return data;
409 }
410 
UnmapMemory(VmaAllocation allocation)411 void PlatformGpuMemoryAllocator::UnmapMemory(VmaAllocation allocation)
412 {
413     vmaUnmapMemory(allocator_, allocation);
414 #if RENDER_PERF_ENABLED
415     CORE_PROFILER_FREE_N(allocation->GetMappedData(), MEMORY_MAPPED_POOL);
416 #endif
417 }
418 
CreatePoolForBuffers(const GpuMemoryAllocatorCustomPool & customPool)419 void PlatformGpuMemoryAllocator::CreatePoolForBuffers(const GpuMemoryAllocatorCustomPool& customPool)
420 {
421     PLUGIN_ASSERT(customPool.resourceType == MemoryAllocatorResourceType::GPU_BUFFER);
422 
423     const auto& buf = customPool.gpuResourceDesc.buffer;
424 
425     VmaAllocationCreateInfo allocationCreateInfo = {};
426     allocationCreateInfo.preferredFlags = (VkMemoryPropertyFlags)buf.memoryPropertyFlags;
427     allocationCreateInfo.requiredFlags = allocationCreateInfo.preferredFlags;
428     if (allocationCreateInfo.preferredFlags ==
429         ((VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) | (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))) {
430         allocationCreateInfo.flags = VmaAllocationCreateFlagBits::VMA_ALLOCATION_CREATE_MAPPED_BIT;
431     }
432 
433     VkBufferCreateInfo bufferCreateInfo = {};
434     bufferCreateInfo.sType = VkStructureType::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
435     bufferCreateInfo.usage = VkBufferUsageFlagBits(buf.usageFlags);
436     bufferCreateInfo.sharingMode = VkSharingMode::VK_SHARING_MODE_EXCLUSIVE;
437     bufferCreateInfo.size = 1024u; // default reference size
438 
439     uint32_t memoryTypeIndex = 0;
440     VALIDATE_VK_RESULT(vmaFindMemoryTypeIndexForBufferInfo(allocator_, // pImageCreateInfo
441         &bufferCreateInfo,                                             // pBufferCreateInfo
442         &allocationCreateInfo,                                         // pAllocationCreateInfo
443         &memoryTypeIndex));                                            // pMemoryTypeIndex
444 
445     VmaPoolCreateInfo poolCreateInfo = {};
446     poolCreateInfo.flags = (customPool.linearAllocationAlgorithm)
447                                ? VmaPoolCreateFlagBits::VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT
448                                : (VkFlags)0;
449     poolCreateInfo.memoryTypeIndex = memoryTypeIndex;
450     poolCreateInfo.blockSize = customPool.blockSize;
451 
452     const uint64_t hash = BASE_NS::hash(buf);
453     const size_t hashCount = hashToGpuBufferPoolIndex_.count(hash);
454 
455     PLUGIN_ASSERT_MSG(hashCount == 0, "similar buffer pool already created");
456     if (hashCount == 0) {
457         VmaPool pool = VK_NULL_HANDLE;
458         VALIDATE_VK_RESULT(vmaCreatePool(allocator_, // allocator
459             &poolCreateInfo,                         // pCreateInfo
460             &pool));                                 // pPool
461 
462         customGpuBufferPools_.push_back(pool);
463         hashToGpuBufferPoolIndex_[hash] = (uint32_t)customGpuBufferPools_.size() - 1;
464 #if (RENDER_PERF_ENABLED == 1)
465         customGpuBufferPoolNames_.push_back(customPool.name);
466 #endif
467     }
468 }
469 
CreatePoolForImages(const GpuMemoryAllocatorCustomPool & customPool)470 void PlatformGpuMemoryAllocator::CreatePoolForImages(const GpuMemoryAllocatorCustomPool& customPool)
471 {
472     PLUGIN_ASSERT(customPool.resourceType == MemoryAllocatorResourceType::GPU_IMAGE);
473 
474     const auto& img = customPool.gpuResourceDesc.image;
475 
476     VmaAllocationCreateInfo allocationCreateInfo = {};
477     allocationCreateInfo.preferredFlags = (VkMemoryPropertyFlags)img.memoryPropertyFlags;
478     allocationCreateInfo.requiredFlags = allocationCreateInfo.preferredFlags;
479 
480     VkImageCreateInfo imageCreateInfo = {};
481     imageCreateInfo.sType = VkStructureType::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
482     imageCreateInfo.usage = VkImageUsageFlagBits(img.usageFlags);
483     imageCreateInfo.imageType = VkImageType(img.imageType);
484     imageCreateInfo.format = VkFormat::VK_FORMAT_R8G8B8A8_UNORM;
485     imageCreateInfo.sharingMode = VkSharingMode::VK_SHARING_MODE_EXCLUSIVE;
486     imageCreateInfo.extent = VkExtent3D { 1024u, 1024u, 1 }; // default reference size
487     imageCreateInfo.arrayLayers = 1;
488     imageCreateInfo.mipLevels = 1;
489     imageCreateInfo.samples = VkSampleCountFlagBits::VK_SAMPLE_COUNT_1_BIT;
490 
491     uint32_t memoryTypeIndex = 0;
492     VALIDATE_VK_RESULT(vmaFindMemoryTypeIndexForImageInfo(allocator_, // pImageCreateInfo
493         &imageCreateInfo,                                             // pImageCreateInfo
494         &allocationCreateInfo,                                        // pAllocationCreateInfo
495         &memoryTypeIndex));                                           // pMemoryTypeIndex
496 
497     VmaPoolCreateInfo poolCreateInfo = {};
498     poolCreateInfo.flags = (customPool.linearAllocationAlgorithm)
499                                ? VmaPoolCreateFlagBits::VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT
500                                : (VkFlags)0;
501     poolCreateInfo.memoryTypeIndex = memoryTypeIndex;
502 
503     const uint64_t hash = BASE_NS::hash(img);
504     const size_t hashCount = hashToGpuImagePoolIndex_.count(hash);
505 
506     PLUGIN_ASSERT_MSG(hashCount == 0, "similar image pool already created");
507     if (hashCount == 0) {
508         VmaPool pool = VK_NULL_HANDLE;
509         VALIDATE_VK_RESULT(vmaCreatePool(allocator_, // allocator
510             &poolCreateInfo,                         // pCreateInfo
511             &pool));                                 // pPool
512 
513         customGpuImagePools_.push_back(pool);
514         hashToGpuImagePoolIndex_[hash] = (uint32_t)customGpuImagePools_.size() - 1;
515 #if (RENDER_PERF_ENABLED == 1)
516         customGpuImagePoolNames_.push_back(customPool.name);
517 #endif
518     }
519 }
520 
521 #if (RENDER_PERF_ENABLED == 1)
GetBufferPoolDebugName(const GpuBufferDesc & desc) const522 string PlatformGpuMemoryAllocator::GetBufferPoolDebugName(const GpuBufferDesc& desc) const
523 {
524     const size_t hash = BASE_NS::hash(desc);
525     if (const auto iter = hashToGpuBufferPoolIndex_.find(hash); iter != hashToGpuBufferPoolIndex_.cend()) {
526         PLUGIN_ASSERT(iter->second < (uint32_t)customGpuBufferPools_.size());
527         return customGpuBufferPoolNames_[iter->second];
528     }
529     return {};
530 }
GetImagePoolDebugName(const GpuImageDesc & desc) const531 string PlatformGpuMemoryAllocator::GetImagePoolDebugName(const GpuImageDesc& desc) const
532 {
533     const size_t hash = BASE_NS::hash(desc);
534     if (const auto iter = hashToGpuImagePoolIndex_.find(hash); iter != hashToGpuImagePoolIndex_.cend()) {
535         PLUGIN_ASSERT(iter->second < (uint32_t)customGpuImagePools_.size());
536         return customGpuImagePoolNames_[iter->second];
537     }
538     return {};
539 }
540 #endif
541 RENDER_END_NAMESPACE()
542