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