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