1#ifndef HALIDE_RUNTIME_VULKAN_MEMORY_H
2#define HALIDE_RUNTIME_VULKAN_MEMORY_H
54 VkDevice dev, VkPhysicalDevice phys_dev,
56 const VkAllocationCallbacks *alloc_callbacks =
nullptr);
80 return this->physical_device;
83 return this->physical_device_limits;
86 return this->alloc_callbacks;
108 static constexpr uint32_t invalid_memory_type =
uint32_t(VK_MAX_MEMORY_TYPES);
112 VkDevice dev, VkPhysicalDevice phys_dev,
114 const VkAllocationCallbacks *alloc_callbacks =
nullptr);
122 VkPhysicalDeviceMemoryProperties *memory_properties,
126 bool is_preferred_memory_type_for_flags(
void *
user_context,
127 VkPhysicalDeviceMemoryProperties *memory_properties,
133 VkPhysicalDeviceMemoryProperties *memory_properties,
137 int lookup_requirements(
void *
user_context,
size_t size,
uint32_t usage_flags, VkMemoryRequirements *memory_requirements);
139 size_t block_byte_count = 0;
140 size_t block_count = 0;
141 size_t region_byte_count = 0;
142 size_t region_count = 0;
143 void *owner_context =
nullptr;
145 VkDevice device =
nullptr;
146 VkPhysicalDevice physical_device =
nullptr;
147 VkPhysicalDeviceLimits physical_device_limits = {};
148 const VkAllocationCallbacks *alloc_callbacks =
nullptr;
155 const VkAllocationCallbacks *alloc_callbacks) {
157 if (system_allocator.
allocate ==
nullptr) {
158 error(
user_context) <<
"VulkanBlockAllocator: Unable to create instance! Missing system allocator interface!\n";
165 if (result ==
nullptr) {
166 error(
user_context) <<
"VulkanMemoryAllocator: Failed to create instance! Out of memory!\n";
170 result->initialize(
user_context, cfg, dev, phys_dev, system_allocator, alloc_callbacks);
175 if (instance ==
nullptr) {
176 error(
user_context) <<
"VulkanBlockAllocator: Unable to destroy instance! Invalide instance pointer!\n";
182 error(
user_context) <<
"VulkanBlockAllocator: Unable to destroy instance! Missing system allocator interface!\n";
189int VulkanMemoryAllocator::initialize(
void *
user_context,
192 const VkAllocationCallbacks *callbacks) {
197 physical_device = phys_dev;
200 region_byte_count = 0;
202 block_byte_count = 0;
204 allocators.
system = system_allocator;
214 if (block_allocator ==
nullptr) {
215 error(
user_context) <<
"VulkanMemoryAllocator: Failed to create BlockAllocator! Out of memory?!\n";
220 VkPhysicalDeviceProperties physical_device_properties = {0};
221 memset(&physical_device_limits, 0,
sizeof(VkPhysicalDeviceLimits));
222 vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties);
223 memcpy(&physical_device_limits, &(physical_device_properties.limits),
sizeof(VkPhysicalDeviceLimits));
228#if defined(HL_VK_DEBUG_MEM)
229 debug(
nullptr) <<
"VulkanMemoryAllocator: Reserving memory ("
231 <<
"block_allocator=" << (
void *)(block_allocator) <<
" "
233 <<
"device=" << (
void *)(device) <<
" "
234 <<
"physical_device=" << (
void *)(physical_device) <<
") ...\n";
237 if ((device ==
nullptr) || (physical_device ==
nullptr)) {
238 error(
user_context) <<
"VulkanMemoryAllocator: Unable to reserve memory! Invalid device handle!\n";
242 if (block_allocator ==
nullptr) {
243 error(
user_context) <<
"VulkanMemoryAllocator: Unable to reserve memory! Invalid block allocator!\n";
247 return block_allocator->
reserve(
this, request);
251#if defined(HL_VK_DEBUG_MEM)
252 debug(
nullptr) <<
"VulkanMemoryAllocator: Mapping region ("
254 <<
"device=" << (
void *)(device) <<
" "
255 <<
"physical_device=" << (
void *)(physical_device) <<
" "
256 <<
"region=" << (
void *)(region) <<
" "
261 if ((device ==
nullptr) || (physical_device ==
nullptr)) {
262 error(
user_context) <<
"VulkanMemoryAllocator: Unable to map memory! Invalid device handle!\n";
266 if (block_allocator ==
nullptr) {
267 error(
user_context) <<
"VulkanMemoryAllocator: Unable to map memory! Invalid block allocator!\n";
273 if (region_allocator ==
nullptr) {
274 error(
user_context) <<
"VulkanMemoryAllocator: Unable to map region! Invalid region allocator handle!\n";
279 if (block_resource ==
nullptr) {
280 error(
user_context) <<
"VulkanMemoryAllocator: Unable to map region! Invalid block resource handle!\n";
284 VkDeviceMemory *device_memory =
reinterpret_cast<VkDeviceMemory *
>(block_resource->
memory.
handle);
285 if (device_memory ==
nullptr) {
286 error(
user_context) <<
"VulkanMemoryAllocator: Unable to map region! Invalid device memory handle!\n";
290 void *mapped_ptr =
nullptr;
294 error(
user_context) <<
"VulkanMemoryAllocator: Unable to map region! Invalid memory range !\n";
297#if defined(HL_VK_DEBUG_MEM)
298 debug(
nullptr) <<
"VulkanMemoryAllocator: MapMemory ("
304 <<
" memory_offset=" << (
uint32_t)memory_offset <<
"\n"
305 <<
" memory_size=" << (
uint32_t)memory_size <<
"\n)\n";
307 VkResult result = vkMapMemory(device, *device_memory, memory_offset, memory_size, 0, (
void **)(&mapped_ptr));
308 if (result != VK_SUCCESS) {
309 error(
user_context) <<
"VulkanMemoryAllocator: Mapping region failed! vkMapMemory returned error code: " << vk_get_error_name(result) <<
"\n";
317#if defined(HL_VK_DEBUG_MEM)
318 debug(
nullptr) <<
"VulkanMemoryAllocator: Unmapping region ("
320 <<
"device=" << (
void *)(device) <<
" "
321 <<
"physical_device=" << (
void *)(physical_device) <<
" "
322 <<
"region=" << (
void *)(region) <<
" "
327 if ((device ==
nullptr) || (physical_device ==
nullptr)) {
328 error(
user_context) <<
"VulkanMemoryAllocator: Unable to unmap region! Invalid device handle!\n";
334 if (region_allocator ==
nullptr) {
335 error(
user_context) <<
"VulkanMemoryAllocator: Unable to unmap region! Invalid region allocator handle!\n";
340 if (block_resource ==
nullptr) {
341 error(
user_context) <<
"VulkanMemoryAllocator: Unable to unmap region! Invalid block resource handle!\n";
345 VkDeviceMemory *device_memory =
reinterpret_cast<VkDeviceMemory *
>(block_resource->
memory.
handle);
346 if (device_memory ==
nullptr) {
347 error(
user_context) <<
"VulkanMemoryAllocator: Unable to unmap region! Invalid device memory handle!\n";
351 vkUnmapMemory(device, *device_memory);
356#if defined(HL_VK_DEBUG_MEM)
357 debug(
nullptr) <<
"VulkanMemoryAllocator: Cropping region ("
359 <<
"device=" << (
void *)(device) <<
" "
360 <<
"physical_device=" << (
void *)(physical_device) <<
" "
361 <<
"region=" << (
void *)(region) <<
" "
364 <<
"crop_offset=" << (
int64_t)offset <<
") ...\n";
366 if ((device ==
nullptr) || (physical_device ==
nullptr)) {
367 error(
user_context) <<
"VulkanMemoryAllocator: Unable to crop region! Invalid device handle!\n";
373 if (region_allocator ==
nullptr) {
374 error(
user_context) <<
"VulkanMemoryAllocator: Unable to unmap region! Invalid region allocator handle!\n";
381 error(
user_context) <<
"VulkanMemoryAllocator: Unable to crop region! Failed to retain memory region!\n";
388 error(
user_context) <<
"VulkanMemoryAllocator: Unable to create crop! Missing system allocator interface!\n";
395 if (memory_region ==
nullptr) {
396 error(
user_context) <<
"VulkanMemoryAllocator: Failed to allocate memory region! Out of memory!\n";
403 memory_region->
handle = (
void *)owner;
405 return memory_region;
409 if (region ==
nullptr) {
410 error(
user_context) <<
"VulkanMemoryAllocator: Failed to destroy crop! Invalid memory region!\n";
416 if (region_allocator ==
nullptr) {
417 error(
user_context) <<
"VulkanMemoryAllocator: Unable to destroy crop region! Invalid region allocator handle!\n";
424 error(
user_context) <<
"VulkanBlockAllocator: Unable to destroy crop region! Region allocator failed to release memory region!\n";
431 error(
user_context) <<
"VulkanBlockAllocator: Unable to destroy crop region! Missing system allocator interface!\n";
448#if defined(HL_VK_DEBUG_MEM)
449 debug(
nullptr) <<
"VulkanMemoryAllocator: Releasing region ("
451 <<
"region=" << (
void *)(region) <<
" "
455 if ((device ==
nullptr) || (physical_device ==
nullptr)) {
456 error(
user_context) <<
"VulkanMemoryAllocator: Unable to release region! Invalid device handle!\n";
459 if (block_allocator ==
nullptr) {
460 error(
user_context) <<
"VulkanMemoryAllocator: Unable to release region! Invalid block allocator!\n";
463 return block_allocator->
release(
this, region);
467#if defined(HL_VK_DEBUG_MEM)
468 debug(
nullptr) <<
"VulkanMemoryAllocator: Reclaiming region ("
470 <<
"region=" << (
void *)(region) <<
" "
474 if ((device ==
nullptr) || (physical_device ==
nullptr)) {
475 error(
user_context) <<
"VulkanMemoryAllocator: Unable to reclaim region! Invalid device handle!\n";
478 if (block_allocator ==
nullptr) {
479 error(
user_context) <<
"VulkanMemoryAllocator: Unable to reclaim region! Invalid block allocator!\n";
482 return block_allocator->
reclaim(
this, region);
486#if defined(HL_VK_DEBUG_MEM)
487 debug(
nullptr) <<
"VulkanMemoryAllocator: Retaining region ("
489 <<
"region=" << (
void *)(region) <<
" "
493 if ((device ==
nullptr) || (physical_device ==
nullptr)) {
494 error(
user_context) <<
"VulkanMemoryAllocator: Unable to retain region! Invalid device handle!\n";
497 if (block_allocator ==
nullptr) {
498 error(
user_context) <<
"VulkanMemoryAllocator: Unable to retain region! Invalid block allocator!\n";
501 return block_allocator->
retain(
this, region);
505#if defined(HL_VK_DEBUG_MEM)
506 debug(
nullptr) <<
"VulkanMemoryAllocator: Collecting unused memory ("
509 if ((device ==
nullptr) || (physical_device ==
nullptr) || (block_allocator ==
nullptr)) {
512 return block_allocator->
collect(
this);
516#if defined(HL_VK_DEBUG_MEM)
517 debug(
nullptr) <<
"VulkanMemoryAllocator: Releasing block allocator ("
520 if ((device ==
nullptr) || (physical_device ==
nullptr)) {
521 error(
user_context) <<
"VulkanMemoryAllocator: Unable to release allocator! Invalid device handle!\n";
524 if (block_allocator ==
nullptr) {
525 error(
user_context) <<
"VulkanMemoryAllocator: Unable to release allocator! Invalid block allocator!\n";
529 return block_allocator->
release(
this);
533#if defined(HL_VK_DEBUG_MEM)
534 debug(
nullptr) <<
"VulkanMemoryAllocator: Destroying allocator ("
537 if (block_allocator !=
nullptr) {
539 block_allocator =
nullptr;
542 region_byte_count = 0;
544 block_byte_count = 0;
555int VulkanMemoryAllocator::lookup_requirements(
void *
user_context,
size_t size,
uint32_t usage_flags, VkMemoryRequirements *memory_requirements) {
556#if defined(HL_VK_DEBUG_MEM)
557 debug(
nullptr) <<
"VulkanMemoryAllocator: Looking up requirements ("
559 <<
"size=" << (
uint32_t)block->size <<
", "
560 <<
"usage_flags=" << usage_flags <<
") ... \n";
562 VkBufferCreateInfo create_info = {
563 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
568 VK_SHARING_MODE_EXCLUSIVE,
572 VkBuffer buffer = VK_NULL_HANDLE;
573 VkResult result = vkCreateBuffer(this->device, &create_info, this->alloc_callbacks, &buffer);
574 if (result != VK_SUCCESS) {
575#if defined(HL_VK_DEBUG_MEM)
576 debug(
nullptr) <<
"VulkanMemoryAllocator: Failed to create buffer to find requirements!\n\t"
577 <<
"vkCreateBuffer returned: " << vk_get_error_name(result) <<
"\n";
579 error(
user_context) <<
"VulkanRegionAllocator: Failed to create buffer to gather memory requirements!\n";
583 vkGetBufferMemoryRequirements(this->device, buffer, memory_requirements);
584 vkDestroyBuffer(this->device, buffer, this->alloc_callbacks);
591 if (instance ==
nullptr) {
596#if defined(HL_VK_DEBUG_MEM)
597 debug(
nullptr) <<
"VulkanMemoryAllocator: Conforming block request ("
599 <<
"request=" << (
void *)(request) <<
") ... \n";
602 if ((instance->device ==
nullptr) || (instance->physical_device ==
nullptr)) {
603 error(
user_context) <<
"VulkanRegionAllocator: Unable to conform block request! Invalid device handle!\n";
607 VkMemoryRequirements memory_requirements = {0};
611 error(
user_context) <<
"VulkanRegionAllocator: Failed to conform block request! Unable to lookup requirements!\n";
615#if defined(HL_VK_DEBUG_MEM)
616 debug(
nullptr) <<
"VulkanMemoryAllocator: Block allocated ("
618 <<
"required_alignment=" << (
uint32_t)memory_requirements.alignment <<
", "
619 <<
"required_size=" << (
uint32_t)memory_requirements.size <<
", "
620 <<
"uniform_buffer_offset_alignment=" << (
uint32_t)instance->physical_device_limits.minUniformBufferOffsetAlignment <<
", "
621 <<
"storage_buffer_offset_alignment=" << (
uint32_t)instance->physical_device_limits.minStorageBufferOffsetAlignment <<
", "
622 <<
"dedicated=" << (request->
dedicated ?
"true" :
"false") <<
")\n";
625 request->
size = memory_requirements.size;
632 if (instance ==
nullptr) {
637 if ((instance->device ==
nullptr) || (instance->physical_device ==
nullptr)) {
638 error(
user_context) <<
"VulkanBlockAllocator: Unable to deallocate block! Invalid device handle!\n";
642 if (block ==
nullptr) {
643 error(
user_context) <<
"VulkanBlockAllocator: Unable to deallocate block! Invalid pointer!\n";
647#if defined(HL_VK_DEBUG_MEM)
648 debug(
nullptr) <<
"VulkanMemoryAllocator: Allocating block ("
650 <<
"block=" << (
void *)(block) <<
" "
652 <<
"dedicated=" << (block->
dedicated ?
"true" :
"false") <<
" "
658 VkDeviceMemory *device_memory = (VkDeviceMemory *)vk_host_malloc(
nullptr,
sizeof(VkDeviceMemory), 0, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, instance->alloc_callbacks);
659 if (device_memory ==
nullptr) {
660 error(
user_context) <<
"VulkanBlockAllocator: Unable to allocate block! Failed to allocate device memory handle!\n";
664 VkPhysicalDeviceMemoryProperties memory_properties;
665 vkGetPhysicalDeviceMemoryProperties(instance->physical_device, &memory_properties);
668 uint32_t selected_type = invalid_memory_type;
673 for (
uint32_t type_index = 0; type_index < memory_properties.memoryTypeCount; type_index++) {
674 if (!instance->is_preferred_memory_type_for_flags(
user_context, &memory_properties, type_index, preferred_flags, required_flags)) {
679 VkMemoryAllocateInfo alloc_info = {
680 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
686 VkResult result = vkAllocateMemory(instance->device, &alloc_info, instance->alloc_callbacks, device_memory);
687 if (result == VK_SUCCESS) {
688 selected_type = type_index;
692#if defined(HL_VK_DEBUG_MEM)
693 debug(
user_context) <<
"VulkanMemoryAllocator: Allocation request for preferred flags was not successful (\n"
694 <<
"\tblock=" << (
void *)(block) <<
"\n"
695 <<
"\ttype_index=" << type_index <<
"\n"
697 <<
"\tdedicated=" << (block->
dedicated ?
"true" :
"false") <<
"\n"
705 <<
"vkAllocateMemory returned: "
706 << vk_get_error_name(result) <<
"\n";
711 if (selected_type == invalid_memory_type) {
712 for (
uint32_t type_index = 0; type_index < memory_properties.memoryTypeCount; type_index++) {
713 if (!instance->is_valid_memory_type_for_flags(
user_context, &memory_properties, type_index, required_flags)) {
718 VkMemoryAllocateInfo alloc_info = {
719 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
725 VkResult result = vkAllocateMemory(instance->device, &alloc_info, instance->alloc_callbacks, device_memory);
726 if (result == VK_SUCCESS) {
727 selected_type = type_index;
730#if defined(HL_VK_DEBUG_MEM)
731 debug(
user_context) <<
"VulkanMemoryAllocator: Allocation request for valid flags was not successful (\n"
732 <<
"\tblock=" << (
void *)(block) <<
"\n"
733 <<
"\ttype_index=" << type_index <<
"\n"
735 <<
"\tdedicated=" << (block->
dedicated ?
"true" :
"false") <<
"\n"
743 <<
"vkAllocateMemory returned: "
744 << vk_get_error_name(result) <<
"\n";
749 if (selected_type == invalid_memory_type) {
750 vk_host_free(
nullptr, device_memory, instance->alloc_callbacks);
751 device_memory = VK_NULL_HANDLE;
752 error(
user_context) <<
"VulkanMemoryAllocator: Allocation failed for block (\n"
753 <<
"\tblock=" << (
void *)(block) <<
"\n"
755 <<
"\tdedicated=" << (block->
dedicated ?
"true" :
"false") <<
"\n"
767 debug(
nullptr) <<
"vkAllocateMemory: Allocated memory for device region (" << (
uint64_t)block->
size <<
" bytes) ...\n";
770 block->
handle = (
void *)device_memory;
771 instance->block_byte_count += block->
size;
772 instance->block_count++;
778 if (instance ==
nullptr) {
783#if defined(HL_VK_DEBUG_MEM)
784 debug(
nullptr) <<
"VulkanMemoryAllocator: Deallocating block ("
786 <<
"block=" << (
void *)(block) <<
") ... \n";
789 if ((instance->device ==
nullptr) || (instance->physical_device ==
nullptr)) {
790 error(
user_context) <<
"VulkanBlockAllocator: Unable to deallocate block! Invalid device handle!\n";
794 if (block ==
nullptr) {
795 error(
user_context) <<
"VulkanBlockAllocator: Unable to deallocate block! Invalid pointer!\n";
799#if defined(HL_VK_DEBUG_MEM)
800 debug(
nullptr) <<
"VulkanBlockAllocator: deallocating block ("
802 <<
"dedicated=" << (block->
dedicated ?
"true" :
"false") <<
" "
809 if (block->
handle ==
nullptr) {
813 VkDeviceMemory *device_memory =
reinterpret_cast<VkDeviceMemory *
>(block->
handle);
814 if (device_memory ==
nullptr) {
815 error(
user_context) <<
"VulkanBlockAllocator: Unable to deallocate block! Invalid device memory handle!\n";
819 vkFreeMemory(instance->device, *device_memory, instance->alloc_callbacks);
821 debug(
nullptr) <<
"vkFreeMemory: Deallocated memory for device region (" << (
uint64_t)block->
size <<
" bytes) ...\n";
824 if (instance->block_count > 0) {
825 instance->block_count--;
827 error(
nullptr) <<
"VulkanRegionAllocator: Block counter invalid ... reseting to zero!\n";
828 instance->block_count = 0;
832 instance->block_byte_count -= block->
size;
834 error(
nullptr) <<
"VulkanRegionAllocator: Block byte counter invalid ... reseting to zero!\n";
835 instance->block_byte_count = 0;
839 vk_host_free(
nullptr, device_memory, instance->alloc_callbacks);
840 device_memory =
nullptr;
849 return block_byte_count;
852uint32_t VulkanMemoryAllocator::required_flags_for_memory_properties(
858 required_flags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
861 required_flags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
864 required_flags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
870 error(
user_context) <<
"VulkanMemoryAllocator: Unable to convert type! Invalid memory visibility request!\n\t"
872 return invalid_memory_type;
874 return required_flags;
877uint32_t VulkanMemoryAllocator::preferred_flags_for_memory_properties(
883 preferred_flags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
886 preferred_flags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
893 error(
user_context) <<
"VulkanMemoryAllocator: Unable to convert type! Invalid memory visibility request!\n\t"
895 return invalid_memory_type;
901 if (required_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
902 preferred_flags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
906 if (required_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
907 preferred_flags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
911 if (required_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
912 preferred_flags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
920 error(
user_context) <<
"VulkanMemoryAllocator: Unable to convert type! Invalid memory caching request!\n\t"
922 return invalid_memory_type;
924 return preferred_flags;
927bool VulkanMemoryAllocator::is_valid_memory_type_for_heap(
void *
user_context,
928 VkPhysicalDeviceMemoryProperties *memory_properties,
932 if (memory_type_index < memory_properties->memoryTypeCount) {
933 if (memory_properties->memoryTypes[memory_type_index].heapIndex == heap_index) {
940bool VulkanMemoryAllocator::is_valid_memory_type_for_flags(
void *
user_context,
941 VkPhysicalDeviceMemoryProperties *memory_properties,
945 if (memory_type_index < memory_properties->memoryTypeCount) {
946 const VkMemoryPropertyFlags property_flags = memory_properties->memoryTypes[memory_type_index].propertyFlags;
947 if (required_flags) {
948 if ((property_flags & required_flags) != required_flags) {
957bool VulkanMemoryAllocator::is_preferred_memory_type_for_flags(
void *
user_context,
958 VkPhysicalDeviceMemoryProperties *memory_properties,
963 if (memory_type_index < memory_properties->memoryTypeCount) {
964 const VkMemoryPropertyFlags property_flags = memory_properties->memoryTypes[memory_type_index].propertyFlags;
965 if (required_flags) {
966 if ((property_flags & required_flags) != required_flags) {
971 if (preferred_flags) {
972 if ((property_flags & preferred_flags) != preferred_flags) {
991 VkMemoryRequirements memory_requirements = {0};
995 error(
user_context) <<
"VulkanRegionAllocator: Failed to conform block request! Unable to lookup requirements!\n";
999#if defined(HL_VK_DEBUG_MEM)
1000 debug(
nullptr) <<
"VulkanMemoryAllocator: Buffer requirements ("
1001 <<
"requested_size=" << (
uint32_t)region->size <<
", "
1002 <<
"required_alignment=" << (
uint32_t)memory_requirements.alignment <<
", "
1003 <<
"required_size=" << (
uint32_t)memory_requirements.size <<
")\n";
1007 if (usage_flags & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) {
1008 if ((request->
alignment % this->physical_device_limits.minStorageBufferOffsetAlignment) != 0) {
1009 request->
alignment = this->physical_device_limits.minStorageBufferOffsetAlignment;
1011 }
else if (usage_flags & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) {
1012 if ((request->
alignment % this->physical_device_limits.minUniformBufferOffsetAlignment) != 0) {
1013 request->
alignment = this->physical_device_limits.minUniformBufferOffsetAlignment;
1026#if defined(HL_VK_DEBUG_MEM)
1027 if ((request->
size != actual_size) || (request->
alignment != actual_alignment) || (request->
offset != actual_offset)) {
1028 debug(
nullptr) <<
"VulkanMemoryAllocator: Adjusting request to match requirements (\n"
1032 <<
" required.size = " << (
uint64_t)memory_requirements.size <<
",\n"
1033 <<
" required.alignment = " << (
uint64_t)memory_requirements.alignment <<
"\n)\n";
1036 request->
size = actual_size;
1038 request->
offset = actual_offset;
1046 if (instance ==
nullptr) {
1051#if defined(HL_VK_DEBUG_MEM)
1052 debug(
nullptr) <<
"VulkanMemoryAllocator: Conforming region request ("
1054 <<
"request=" << (
void *)(region) <<
") ... \n";
1057 if ((instance->device ==
nullptr) || (instance->physical_device ==
nullptr)) {
1058 error(
user_context) <<
"VulkanRegionAllocator: Unable to conform region request! Invalid device handle!\n";
1062#if defined(HL_VK_DEBUG_MEM)
1063 debug(
nullptr) <<
"VulkanRegionAllocator: Conforming region request ("
1066 <<
"dedicated=" << (request->
dedicated ?
"true" :
"false") <<
" "
1078 if (instance ==
nullptr) {
1083#if defined(HL_VK_DEBUG_MEM)
1084 debug(
nullptr) <<
"VulkanMemoryAllocator: Allocating region ("
1086 <<
"region=" << (
void *)(region) <<
") ... \n";
1089 if ((instance->device ==
nullptr) || (instance->physical_device ==
nullptr)) {
1090 error(
user_context) <<
"VulkanRegionAllocator: Unable to allocate region! Invalid device handle!\n";
1094 if (region ==
nullptr) {
1095 error(
user_context) <<
"VulkanRegionAllocator: Unable to allocate region! Invalid pointer!\n";
1099#if defined(HL_VK_DEBUG_MEM)
1100 debug(
nullptr) <<
"VulkanRegionAllocator: Allocating region ("
1103 <<
"dedicated=" << (region->
dedicated ?
"true" :
"false") <<
" "
1111 VkBufferCreateInfo create_info = {
1112 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1117 VK_SHARING_MODE_EXCLUSIVE,
1120 VkBuffer *buffer = (VkBuffer *)vk_host_malloc(
nullptr,
sizeof(VkBuffer), 0, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, instance->alloc_callbacks);
1121 if (buffer ==
nullptr) {
1122 error(
user_context) <<
"VulkanRegionAllocator: Unable to allocate region! Failed to allocate buffer handle!\n";
1126 VkResult result = vkCreateBuffer(instance->device, &create_info, instance->alloc_callbacks, buffer);
1127 if (result != VK_SUCCESS) {
1130 result = vkCreateBuffer(instance->device, &create_info, instance->alloc_callbacks, buffer);
1132 if (result != VK_SUCCESS) {
1133 vk_host_free(
nullptr, buffer, instance->alloc_callbacks);
1135 error(
user_context) <<
"VulkanRegionAllocator: Failed to create buffer!\n\t"
1136 <<
"vkCreateBuffer returned: " << vk_get_error_name(result) <<
"\n";
1145 VkMemoryRequirements memory_requirements = {0};
1146 vkGetBufferMemoryRequirements(instance->device, *buffer, &memory_requirements);
1148#if defined(HL_VK_DEBUG_MEM)
1149 debug(
nullptr) <<
"VulkanMemoryAllocator: Buffer requirements ("
1151 <<
"required_alignment=" << (
uint32_t)memory_requirements.alignment <<
", "
1152 <<
"required_size=" << (
uint32_t)memory_requirements.size <<
")\n";
1155 if (memory_requirements.size > region->
size) {
1156 vkDestroyBuffer(instance->device, *buffer, instance->alloc_callbacks);
1158 debug(
nullptr) <<
"VulkanMemoryAllocator: Reallocating buffer to match required size ("
1161 create_info.size = memory_requirements.size;
1162 VkResult result = vkCreateBuffer(instance->device, &create_info, instance->alloc_callbacks, buffer);
1163 if (result != VK_SUCCESS) {
1164 error(
user_context) <<
"VulkanRegionAllocator: Failed to recreate buffer!\n\t"
1165 <<
"vkCreateBuffer returned: " << vk_get_error_name(result) <<
"\n";
1171 debug(
nullptr) <<
"vkCreateBuffer: Created buffer for device region (" << (
uint64_t)region->
size <<
" bytes) ...\n";
1175 if (region_allocator ==
nullptr) {
1176 error(
user_context) <<
"VulkanBlockAllocator: Unable to allocate region! Invalid region allocator!\n";
1181 if (block_resource ==
nullptr) {
1182 error(
user_context) <<
"VulkanBlockAllocator: Unable to allocate region! Invalid block resource handle!\n";
1186 VkDeviceMemory *device_memory =
reinterpret_cast<VkDeviceMemory *
>(block_resource->
memory.
handle);
1187 if (device_memory ==
nullptr) {
1188 error(
user_context) <<
"VulkanBlockAllocator: Unable to allocate region! Invalid device memory handle!\n";
1193 result = vkBindBufferMemory(instance->device, *buffer, *device_memory, region->
offset);
1194 if (result != VK_SUCCESS) {
1195 error(
user_context) <<
"VulkanRegionAllocator: Failed to bind buffer!\n\t"
1196 <<
"vkBindBufferMemory returned: " << vk_get_error_name(result) <<
"\n";
1200 region->
handle = (
void *)buffer;
1202 instance->region_byte_count += region->
size;
1203 instance->region_count++;
1209 if (instance ==
nullptr) {
1214#if defined(HL_VK_DEBUG_MEM)
1215 debug(
nullptr) <<
"VulkanMemoryAllocator: Deallocating region ("
1217 <<
"region=" << (
void *)(region) <<
") ... \n";
1220 if ((instance->device ==
nullptr) || (instance->physical_device ==
nullptr)) {
1221 error(
user_context) <<
"VulkanRegionAllocator: Unable to deallocate region! Invalid device handle!\n";
1225 if (region ==
nullptr) {
1226 error(
user_context) <<
"VulkanRegionAllocator: Unable to deallocate region! Invalid pointer!\n";
1230#if defined(HL_VK_DEBUG_MEM)
1231 debug(
nullptr) <<
"VulkanRegionAllocator: Deallocating region ("
1234 <<
"dedicated=" << (region->
dedicated ?
"true" :
"false") <<
" "
1240 if (region->
handle ==
nullptr) {
1241 error(
user_context) <<
"VulkanRegionAllocator: Unable to deallocate region! Invalid handle!\n";
1245 VkBuffer *buffer =
reinterpret_cast<VkBuffer *
>(region->
handle);
1246 if (buffer ==
nullptr) {
1247 error(
user_context) <<
"VulkanRegionAllocator: Unable to deallocate region! Invalid buffer handle!\n";
1251 vkDestroyBuffer(instance->device, *buffer, instance->alloc_callbacks);
1253 debug(
nullptr) <<
"vkDestroyBuffer: Destroyed buffer for device region (" << (
uint64_t)region->
size <<
" bytes) ...\n";
1256 region->
handle =
nullptr;
1257 if (instance->region_count > 0) {
1258 instance->region_count--;
1260 error(
user_context) <<
"VulkanRegionAllocator: Region counter invalid ... reseting to zero!\n";
1261 instance->region_count = 0;
1266 instance->region_byte_count -= region->
size;
1268 error(
user_context) <<
"VulkanRegionAllocator: Region byte counter invalid ... reseting to zero!\n";
1269 instance->region_byte_count = 0;
1272 vk_host_free(
nullptr, buffer, instance->alloc_callbacks);
1278 return region_count;
1282 return region_byte_count;
1287 switch (properties.
usage) {
1289 result |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
1293 result |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
1296 result |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
1299 result |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
1302 result |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
1307 error(
user_context) <<
"VulkanRegionAllocator: Unable to convert type! Invalid memory usage request!\n\t"
1309 return invalid_usage_flags;
1312 if (result == invalid_usage_flags) {
1313 error(
user_context) <<
"VulkanRegionAllocator: Failed to find appropriate memory usage for given properties:\n\t"
1317 return invalid_usage_flags;
1329void *vk_system_malloc(
void *
user_context,
size_t size) {
1338void *vk_host_malloc(
void *
user_context,
size_t size,
size_t alignment, VkSystemAllocationScope scope,
const VkAllocationCallbacks *callbacks) {
1340 return callbacks->pfnAllocation(
user_context, size, alignment, scope);
1346void vk_host_free(
void *
user_context,
void *ptr,
const VkAllocationCallbacks *callbacks) {
1354VulkanMemoryAllocator *vk_create_memory_allocator(
void *
user_context,
1356 VkPhysicalDevice physical_device,
1357 const VkAllocationCallbacks *alloc_callbacks) {
1373 if (alloc_config_values.
size() > 0) {
1374 config.maximum_pool_size =
atoi(alloc_config_values[0]) * 1024 * 1024;
1375 print(
user_context) <<
"Vulkan: Configuring allocator with " << (
uint32_t)config.maximum_pool_size <<
" for maximum pool size (in bytes)\n";
1377 if (alloc_config_values.
size() > 1) {
1378 config.minimum_block_size =
atoi(alloc_config_values[1]) * 1024 * 1024;
1379 print(
user_context) <<
"Vulkan: Configuring allocator with " << (
uint32_t)config.minimum_block_size <<
" for minimum block size (in bytes)\n";
1381 if (alloc_config_values.
size() > 2) {
1382 config.maximum_block_size =
atoi(alloc_config_values[2]) * 1024 * 1024;
1383 print(
user_context) <<
"Vulkan: Configuring allocator with " << (
uint32_t)config.maximum_block_size <<
" for maximum block size (in bytes)\n";
1385 if (alloc_config_values.
size() > 3) {
1386 config.maximum_block_count =
atoi(alloc_config_values[3]);
1387 print(
user_context) <<
"Vulkan: Configuring allocator with " << (
uint32_t)config.maximum_block_count <<
" for maximum block count\n";
1389 if (alloc_config_values.
size() > 4) {
1390 config.nearest_multiple =
atoi(alloc_config_values[4]);
1391 print(
user_context) <<
"Vulkan: Configuring allocator with " << (
uint32_t)config.nearest_multiple <<
" for nearest multiple\n";
1396 config, device, physical_device,
1397 system_allocator, alloc_callbacks);
1414 VkQueue command_queue,
1415 VkBuffer device_buffer) {
1419 <<
" vk_clear_device_buffer (user_context: " <<
user_context <<
", "
1420 <<
"allocator: " << (
void *)
allocator <<
", "
1422 <<
"command_queue: " << (
void *)command_queue <<
", "
1423 <<
"device_buffer: " << (
void *)device_buffer <<
")\n";
1427 VkCommandBufferBeginInfo command_buffer_begin_info =
1429 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1431 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
1435 VkResult result = vkBeginCommandBuffer(
command_buffer, &command_buffer_begin_info);
1436 if (result != VK_SUCCESS) {
1437 error(
user_context) <<
"Vulkan: vkBeginCommandBuffer returned " << vk_get_error_name(result) <<
"\n";
1442 vkCmdFillBuffer(
command_buffer, device_buffer, 0, VK_WHOLE_SIZE, 0);
1446 if (result != VK_SUCCESS) {
1447 error(
user_context) <<
"Vulkan: vkEndCommandBuffer returned " << vk_get_error_name(result) <<
"\n";
1452 VkSubmitInfo submit_info =
1454 VK_STRUCTURE_TYPE_SUBMIT_INFO,
1465 result = vkQueueSubmit(command_queue, 1, &submit_info, VK_NULL_HANDLE);
1466 if (result != VK_SUCCESS) {
1467 error(
user_context) <<
"Vulkan: vkQueueSubmit returned " << vk_get_error_name(result) <<
"\n";
1472 result = vkQueueWaitIdle(command_queue);
1473 if (result != VK_SUCCESS) {
1474 error(
user_context) <<
"Vulkan: vkQueueWaitIdle returned " << vk_get_error_name(result) <<
"\n";
1498 custom_allocation_callbacks = callbacks;
1504 return custom_allocation_callbacks;
halide_error_code_t
The error codes that may be returned by a Halide pipeline.
@ halide_error_code_internal_error
There is a bug in the Halide compiler.
@ halide_error_code_generic_error
An uncategorized error occurred.
@ halide_error_code_success
There was no error.
@ halide_error_code_device_malloc_failed
The Halide runtime encountered an error while trying to allocate memory on device.
@ halide_error_code_out_of_memory
A call to halide_malloc returned NULL.
Allocator class interface for managing large contiguous blocks of memory, which are then sub-allocate...
bool collect(void *user_context)
MemoryRegion * reserve(void *user_context, const MemoryRequest &request)
int release(void *user_context, MemoryRegion *region)
int retain(void *user_context, MemoryRegion *region)
static void destroy(void *user_context, BlockAllocator *block_allocator)
static BlockAllocator * create(void *user_context, const Config &config, const MemoryAllocators &allocators)
int reclaim(void *user_context, MemoryRegion *region)
const MemoryAllocators & current_allocators() const
Allocator class interface for sub-allocating a contiguous memory block into smaller regions of memory...
static RegionAllocator * find_allocator(void *user_context, MemoryRegion *memory_region)
int retain(void *user_context, MemoryRegion *memory_region)
int release(void *user_context, MemoryRegion *memory_region)
BlockResource * block_resource() const
size_t parse(void *user_context, const char *str, const char *delim)
Vulkan Memory Allocator class interface for managing large memory requests stored as contiguous block...
int reclaim(void *user_context, MemoryRegion *region)
static const VulkanMemoryConfig & default_config()
MemoryRegion * reserve(void *user_context, const MemoryRequest &request)
VulkanMemoryAllocator(const VulkanMemoryAllocator &)=delete
int release(void *user_context, MemoryRegion *region)
static int allocate_block(void *instance_ptr, MemoryBlock *block)
int conform(void *user_context, MemoryRequest *request)
static int deallocate_region(void *instance_ptr, MemoryRegion *region)
VulkanMemoryAllocator & operator=(const VulkanMemoryAllocator &)=delete
static int destroy(void *user_context, VulkanMemoryAllocator *allocator)
int unmap(void *user_context, MemoryRegion *region)
static int conform_region_request(void *instance_ptr, MemoryRequest *request)
~VulkanMemoryAllocator()=delete
MemoryRegion * create_crop(void *user_context, MemoryRegion *region, uint64_t offset)
int destroy_crop(void *user_context, MemoryRegion *region)
size_t regions_allocated() const
size_t blocks_allocated() const
static int allocate_region(void *instance_ptr, MemoryRegion *region)
static int conform_block_request(void *instance_ptr, MemoryRequest *request)
MemoryRegion * owner_of(void *user_context, MemoryRegion *region)
VkDevice current_device() const
VkPhysicalDeviceLimits current_physical_device_limits() const
bool collect(void *user_context)
size_t bytes_allocated_for_blocks() const
const VkAllocationCallbacks * callbacks() const
static int deallocate_block(void *instance_ptr, MemoryBlock *block)
VulkanMemoryAllocator()=delete
void * map(void *user_context, MemoryRegion *region)
VkPhysicalDevice current_physical_device() const
size_t bytes_allocated_for_regions() const
int retain(void *user_context, MemoryRegion *region)
static VulkanMemoryAllocator * create(void *user_context, const VulkanMemoryConfig &config, VkDevice dev, VkPhysicalDevice phys_dev, const SystemMemoryAllocatorFns &system_allocator, const VkAllocationCallbacks *alloc_callbacks=nullptr)
WEAK const char * halide_memory_caching_name(MemoryCaching value)
WEAK const char * halide_memory_usage_name(MemoryUsage value)
WEAK const char * halide_memory_visibility_name(MemoryVisibility value)
WEAK VulkanMemoryConfig memory_allocator_config
WEAK const VkAllocationCallbacks * custom_allocation_callbacks
WEAK ScopedSpinLock::AtomicFlag custom_allocation_callbacks_lock
WEAK char alloc_config[1024]
ALWAYS_INLINE size_t conform_alignment(size_t requested, size_t required)
ALWAYS_INLINE size_t conform_size(size_t offset, size_t size, size_t alignment, size_t nearest_multiple)
ALWAYS_INLINE size_t aligned_offset(size_t offset, size_t alignment)
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
@ Internal
Not visible externally, similar to 'static' linkage in C.
Expr print(const std::vector< Expr > &values)
Create an Expr that prints out its value whenever it is evaluated.
unsigned __INT64_TYPE__ uint64_t
signed __INT64_TYPE__ int64_t
void * memcpy(void *s1, const void *s2, size_t n)
void * memset(void *s, int val, size_t n)
unsigned __INT32_TYPE__ uint32_t
size_t maximum_block_count
size_t minimum_block_size
size_t maximum_block_size
MemoryRegionAllocatorFns region
MemoryBlockAllocatorFns block
SystemMemoryAllocatorFns system
MemoryProperties properties
MemoryVisibility visibility
MemoryProperties properties
MemoryProperties properties
static bool is_empty(const char *str)
DeallocateSystemFn deallocate
AllocateSystemFn allocate
size_t maximum_block_size
size_t minimum_block_size
size_t maximum_block_count
WEAK void halide_vulkan_set_allocation_callbacks(const VkAllocationCallbacks *callbacks)
WEAK const VkAllocationCallbacks * halide_vulkan_get_allocation_callbacks(void *user_context)
VkCommandBuffer command_buffer
VulkanMemoryAllocator * allocator