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