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