Halide 17.0.0
Halide compiler and libraries
Loading...
Searching...
No Matches
vulkan_memory.h
Go to the documentation of this file.
1#ifndef HALIDE_RUNTIME_VULKAN_MEMORY_H
2#define HALIDE_RUNTIME_VULKAN_MEMORY_H
3
6#include "vulkan_internal.h"
7
8// Uncomment to enable verbose memory allocation debugging
9// #define HL_VK_DEBUG_MEM 1
10
11namespace Halide {
12namespace Runtime {
13namespace Internal {
14namespace Vulkan {
15
16// --------------------------------------------------------------------------
17
18// Enable external client to override Vulkan allocation callbacks (if they so desire)
20WEAK const VkAllocationCallbacks *custom_allocation_callbacks = nullptr; // nullptr => use Vulkan runtime implementation
21
22// --------------------------------------------------------------------------
23
24// Runtime configuration parameters to adjust the behaviour of the block allocator
26 size_t maximum_pool_size = 0; //< Maximum number of bytes to allocate for the entire pool (including all blocks). Specified in bytes. Zero means no constraint
27 size_t minimum_block_size = 32 * 1024 * 1024; //< Default block size is 32MB
28 size_t maximum_block_size = 0; //< Specified in bytes. Zero means no constraint
29 size_t maximum_block_count = 0; //< Maximum number of blocks to allocate. Zero means no constraint
30 size_t nearest_multiple = 32; //< Always round up the requested region sizes to the given integer value. Zero means no constraint
31};
33
34// --------------------------------------------------------------------------
35
36/** Vulkan Memory Allocator class interface for managing large
37 * memory requests stored as contiguous blocks of memory, which
38 * are then sub-allocated into smaller regions of
39 * memory to avoid the excessive cost of vkAllocate and the limited
40 * number of available allocation calls through the API.
41 */
43public:
44 // disable copy constructors and assignment
47
48 // disable non-factory constrction
51
52 // Factory methods for creation / destruction
53 static VulkanMemoryAllocator *create(void *user_context, const VulkanMemoryConfig &config,
56 const VkAllocationCallbacks *alloc_callbacks = nullptr);
57
58 static int destroy(void *user_context, VulkanMemoryAllocator *allocator);
59
60 // Public interface methods
61 MemoryRegion *reserve(void *user_context, MemoryRequest &request);
62 int release(void *user_context, MemoryRegion *region); //< unmark and cache the region for reuse
63 int reclaim(void *user_context, MemoryRegion *region); //< free the region and consolidate
64 int retain(void *user_context, MemoryRegion *region); //< retain the region and increase its use count
65 bool collect(void *user_context); //< returns true if any blocks were removed
66 int release(void *user_context);
67 int destroy(void *user_context);
68
69 void *map(void *user_context, MemoryRegion *region);
70 int unmap(void *user_context, MemoryRegion *region);
71 MemoryRegion *create_crop(void *user_context, MemoryRegion *region, uint64_t offset);
72 int destroy_crop(void *user_context, MemoryRegion *region);
73 MemoryRegion *owner_of(void *user_context, MemoryRegion *region);
74
76 return this->device;
77 }
79 return this->physical_device;
80 }
82 return this->alloc_callbacks;
83 }
84
85 static const VulkanMemoryConfig &default_config();
86
87 static int allocate_block(void *instance_ptr, MemoryBlock *block);
88 static int deallocate_block(void *instance_ptr, MemoryBlock *block);
89
90 static int allocate_region(void *instance_ptr, MemoryRegion *region);
91 static int deallocate_region(void *instance_ptr, MemoryRegion *region);
92
93 size_t bytes_allocated_for_blocks() const;
94 size_t blocks_allocated() const;
95
96 size_t bytes_allocated_for_regions() const;
97 size_t regions_allocated() const;
98
99private:
100 static constexpr uint32_t invalid_usage_flags = uint32_t(-1);
101 static constexpr uint32_t invalid_memory_type = uint32_t(VK_MAX_MEMORY_TYPES);
102
103 // Initializes a new instance
104 int initialize(void *user_context, const VulkanMemoryConfig &config,
107 const VkAllocationCallbacks *alloc_callbacks = nullptr);
108
109 uint32_t select_memory_usage(void *user_context, MemoryProperties properties) const;
110
111 uint32_t select_memory_type(void *user_context,
112 VkPhysicalDevice physical_device,
113 MemoryProperties properties,
115
116 size_t block_byte_count = 0;
117 size_t block_count = 0;
118 size_t region_byte_count = 0;
119 size_t region_count = 0;
120 void *owner_context = nullptr;
121 VulkanMemoryConfig config;
122 VkDevice device = nullptr;
123 VkPhysicalDevice physical_device = nullptr;
124 VkPhysicalDeviceLimits physical_device_limits = {};
125 const VkAllocationCallbacks *alloc_callbacks = nullptr;
126 BlockAllocator *block_allocator = nullptr;
127};
128
132 const VkAllocationCallbacks *alloc_callbacks) {
133
134 if (system_allocator.allocate == nullptr) {
135 error(user_context) << "VulkanBlockAllocator: Unable to create instance! Missing system allocator interface!\n";
136 return nullptr;
137 }
138
139 VulkanMemoryAllocator *result = reinterpret_cast<VulkanMemoryAllocator *>(
140 system_allocator.allocate(user_context, sizeof(VulkanMemoryAllocator)));
141
142 if (result == nullptr) {
143 error(user_context) << "VulkanMemoryAllocator: Failed to create instance! Out of memory!\n";
144 return nullptr; // caller must handle error case for out-of-memory
145 }
146
147 result->initialize(user_context, cfg, dev, phys_dev, system_allocator, alloc_callbacks);
148 return result;
149}
150
151int VulkanMemoryAllocator::destroy(void *user_context, VulkanMemoryAllocator *instance) {
152 if (instance == nullptr) {
153 error(user_context) << "VulkanBlockAllocator: Unable to destroy instance! Invalide instance pointer!\n";
155 }
156 const BlockAllocator::MemoryAllocators &allocators = instance->block_allocator->current_allocators();
157 instance->destroy(user_context);
158 BlockAllocator::destroy(user_context, instance->block_allocator);
159 if (allocators.system.deallocate == nullptr) {
160 error(user_context) << "VulkanBlockAllocator: Unable to destroy instance! Missing system allocator interface!\n";
162 }
163 allocators.system.deallocate(user_context, instance);
165}
166
167int VulkanMemoryAllocator::initialize(void *user_context,
170 const VkAllocationCallbacks *callbacks) {
171
172 owner_context = user_context;
173 config = cfg;
174 device = dev;
175 physical_device = phys_dev;
176 alloc_callbacks = callbacks;
177 region_count = 0;
178 region_byte_count = 0;
179 block_count = 0;
180 block_byte_count = 0;
182 allocators.system = system_allocator;
186 block_allocator_config.maximum_pool_size = cfg.maximum_pool_size;
187 block_allocator_config.maximum_block_count = cfg.maximum_block_count;
188 block_allocator_config.maximum_block_size = cfg.maximum_block_size;
189 block_allocator_config.minimum_block_size = cfg.minimum_block_size;
190 block_allocator_config.nearest_multiple = cfg.nearest_multiple;
191 block_allocator = BlockAllocator::create(user_context, block_allocator_config, allocators);
192 if (block_allocator == nullptr) {
193 error(user_context) << "VulkanMemoryAllocator: Failed to create BlockAllocator! Out of memory?!\n";
195 }
196
197 // get the physical device properties to determine limits and allocation requirements
199 memset(&physical_device_limits, 0, sizeof(VkPhysicalDeviceLimits));
201 memcpy(&physical_device_limits, &(physical_device_properties.limits), sizeof(VkPhysicalDeviceLimits));
203}
204
206#if defined(HL_VK_DEBUG_MEM)
207 debug(nullptr) << "VulkanMemoryAllocator: Reserving memory ("
208 << "user_context=" << user_context << " "
209 << "block_allocator=" << (void *)(block_allocator) << " "
210 << "request_size=" << (uint32_t)(request.size) << " "
211 << "device=" << (void *)(device) << " "
212 << "physical_device=" << (void *)(physical_device) << ") ...\n";
213#endif
214
215 if ((device == nullptr) || (physical_device == nullptr)) {
216 error(user_context) << "VulkanMemoryAllocator: Unable to reserve memory! Invalid device handle!\n";
217 return nullptr;
218 }
219
220 if (block_allocator == nullptr) {
221 error(user_context) << "VulkanMemoryAllocator: Unable to reserve memory! Invalid block allocator!\n";
222 return nullptr;
223 }
224
225 return block_allocator->reserve(this, request);
226}
227
228void *VulkanMemoryAllocator::map(void *user_context, MemoryRegion *region) {
229#if defined(HL_VK_DEBUG_MEM)
230 debug(nullptr) << "VulkanMemoryAllocator: Mapping region ("
231 << "user_context=" << user_context << " "
232 << "device=" << (void *)(device) << " "
233 << "physical_device=" << (void *)(physical_device) << " "
234 << "region=" << (void *)(region) << " "
235 << "region_size=" << (uint32_t)region->size << " "
236 << "region_offset=" << (uint32_t)region->offset << " "
237 << "crop_offset=" << (uint32_t)region->range.head_offset << ") ...\n";
238#endif
239 if ((device == nullptr) || (physical_device == nullptr)) {
240 error(user_context) << "VulkanMemoryAllocator: Unable to map memory! Invalid device handle!\n";
241 return nullptr;
242 }
243
244 if (block_allocator == nullptr) {
245 error(user_context) << "VulkanMemoryAllocator: Unable to map memory! Invalid block allocator!\n";
246 return nullptr;
247 }
248
249 MemoryRegion *owner = owner_of(user_context, region);
251 if (region_allocator == nullptr) {
252 error(user_context) << "VulkanMemoryAllocator: Unable to map region! Invalid region allocator handle!\n";
253 return nullptr; // NOTE: caller must handle nullptr
254 }
255
256 BlockResource *block_resource = region_allocator->block_resource();
257 if (block_resource == nullptr) {
258 error(user_context) << "VulkanMemoryAllocator: Unable to map region! Invalid block resource handle!\n";
259 return nullptr; // NOTE: caller must handle nullptr
260 }
261
262 VkDeviceMemory *device_memory = reinterpret_cast<VkDeviceMemory *>(block_resource->memory.handle);
263 if (device_memory == nullptr) {
264 error(user_context) << "VulkanMemoryAllocator: Unable to map region! Invalid device memory handle!\n";
265 return nullptr; // NOTE: caller must handle nullptr
266 }
267
268 void *mapped_ptr = nullptr;
270 VkDeviceSize memory_size = region->size - region->range.tail_offset - region->range.head_offset;
271 if (((double)region->size - (double)region->range.tail_offset - (double)region->range.head_offset) <= 0.0) {
272 error(user_context) << "VulkanMemoryAllocator: Unable to map region! Invalid memory range !\n";
273 return nullptr;
274 }
275 debug(nullptr) << "VulkanMemoryAllocator: MapMemory ("
276 << "user_context=" << user_context << "\n"
277 << " region_size=" << (uint32_t)region->size << "\n"
278 << " region_offset=" << (uint32_t)region->offset << "\n"
279 << " region_range.head_offset=" << (uint32_t)region->range.head_offset << "\n"
280 << " region_range.tail_offset=" << (uint32_t)region->range.tail_offset << "\n"
281 << " memory_offset=" << (uint32_t)memory_offset << "\n"
282 << " memory_size=" << (uint32_t)memory_size << ") ...\n";
283
284 VkResult result = vkMapMemory(device, *device_memory, memory_offset, memory_size, 0, (void **)(&mapped_ptr));
285 if (result != VK_SUCCESS) {
286 error(user_context) << "VulkanMemoryAllocator: Mapping region failed! vkMapMemory returned error code: " << vk_get_error_name(result) << "\n";
287 return nullptr;
288 }
289
290 return mapped_ptr;
291}
292
293int VulkanMemoryAllocator::unmap(void *user_context, MemoryRegion *region) {
294#if defined(HL_VK_DEBUG_MEM)
295 debug(nullptr) << "VulkanMemoryAllocator: Unmapping region ("
296 << "user_context=" << user_context << " "
297 << "device=" << (void *)(device) << " "
298 << "physical_device=" << (void *)(physical_device) << " "
299 << "region=" << (void *)(region) << " "
300 << "region_size=" << (uint32_t)region->size << " "
301 << "region_offset=" << (uint32_t)region->offset << " "
302 << "crop_offset=" << (uint32_t)region->range.head_offset << ") ...\n";
303#endif
304 if ((device == nullptr) || (physical_device == nullptr)) {
305 error(user_context) << "VulkanMemoryAllocator: Unable to unmap region! Invalid device handle!\n";
307 }
308
309 MemoryRegion *owner = owner_of(user_context, region);
311 if (region_allocator == nullptr) {
312 error(user_context) << "VulkanMemoryAllocator: Unable to unmap region! Invalid region allocator handle!\n";
314 }
315
316 BlockResource *block_resource = region_allocator->block_resource();
317 if (block_resource == nullptr) {
318 error(user_context) << "VulkanMemoryAllocator: Unable to unmap region! Invalid block resource handle!\n";
320 }
321
322 VkDeviceMemory *device_memory = reinterpret_cast<VkDeviceMemory *>(block_resource->memory.handle);
323 if (device_memory == nullptr) {
324 error(user_context) << "VulkanMemoryAllocator: Unable to unmap region! Invalid device memory handle!\n";
326 }
327
330}
331
333#if defined(HL_VK_DEBUG_MEM)
334 debug(nullptr) << "VulkanMemoryAllocator: Cropping region ("
335 << "user_context=" << user_context << " "
336 << "device=" << (void *)(device) << " "
337 << "physical_device=" << (void *)(physical_device) << " "
338 << "region=" << (void *)(region) << " "
339 << "region_size=" << (uint32_t)region->size << " "
340 << "region_offset=" << (uint32_t)region->offset << " "
341 << "crop_offset=" << (int64_t)offset << ") ...\n";
342#endif
343 if ((device == nullptr) || (physical_device == nullptr)) {
344 error(user_context) << "VulkanMemoryAllocator: Unable to crop region! Invalid device handle!\n";
345 return nullptr;
346 }
347
348 MemoryRegion *owner = owner_of(user_context, region);
350 if (region_allocator == nullptr) {
351 error(user_context) << "VulkanMemoryAllocator: Unable to unmap region! Invalid region allocator handle!\n";
352 return nullptr; // NOTE: caller must handle nullptr
353 }
354
355 // increment usage count
356 int error_code = region_allocator->retain(this, owner);
357 if (error_code != halide_error_code_success) {
358 error(user_context) << "VulkanMemoryAllocator: Unable to crop region! Failed to retain memory region!\n";
359 return nullptr; // NOTE: caller must handle nullptr
360 }
361
362 // create a new region to return, and copy all the other region's properties
363 const BlockAllocator::MemoryAllocators &allocators = block_allocator->current_allocators();
364 if (allocators.system.allocate == nullptr) {
365 error(user_context) << "VulkanMemoryAllocator: Unable to create crop! Missing system allocator interface!\n";
366 return nullptr;
367 }
368
369 MemoryRegion *memory_region = reinterpret_cast<MemoryRegion *>(
370 allocators.system.allocate(user_context, sizeof(MemoryRegion)));
371
372 if (memory_region == nullptr) {
373 error(user_context) << "VulkanMemoryAllocator: Failed to allocate memory region! Out of memory!\n";
374 return nullptr;
375 }
377
378 // point the handle to the owner of the allocated region, and update the head offset
379 memory_region->is_owner = false;
380 memory_region->handle = (void *)owner;
381 memory_region->range.head_offset = owner->range.head_offset + offset;
382 return memory_region;
383}
384
385int VulkanMemoryAllocator::destroy_crop(void *user_context, MemoryRegion *region) {
386 if (region == nullptr) {
387 error(user_context) << "VulkanMemoryAllocator: Failed to destroy crop! Invalid memory region!\n";
389 }
390
391 MemoryRegion *owner = owner_of(user_context, region);
393 if (region_allocator == nullptr) {
394 error(user_context) << "VulkanMemoryAllocator: Unable to destroy crop region! Invalid region allocator handle!\n";
396 }
397
398 // decrement usage count
399 int error_code = region_allocator->release(this, owner);
400 if (error_code != halide_error_code_success) {
401 error(user_context) << "VulkanBlockAllocator: Unable to destroy crop region! Region allocator failed to release memory region!\n";
402 return error_code;
403 }
404
405 // discard the copied region struct
406 const BlockAllocator::MemoryAllocators &allocators = block_allocator->current_allocators();
407 if (allocators.system.deallocate == nullptr) {
408 error(user_context) << "VulkanBlockAllocator: Unable to destroy crop region! Missing system allocator interface!\n";
410 }
411 allocators.system.deallocate(user_context, region);
413}
414
416 if (region->is_owner) {
417 return region;
418 } else {
419 // If this is a cropped region, use the handle to retrieve the owner of the allocation
420 return reinterpret_cast<MemoryRegion *>(region->handle);
421 }
422}
423
424int VulkanMemoryAllocator::release(void *user_context, MemoryRegion *region) {
425#if defined(HL_VK_DEBUG_MEM)
426 debug(nullptr) << "VulkanMemoryAllocator: Releasing region ("
427 << "user_context=" << user_context << " "
428 << "region=" << (void *)(region) << " "
429 << "size=" << (uint32_t)region->size << " "
430 << "offset=" << (uint32_t)region->offset << ") ...\n";
431#endif
432 if ((device == nullptr) || (physical_device == nullptr)) {
433 error(user_context) << "VulkanMemoryAllocator: Unable to release region! Invalid device handle!\n";
435 }
436 if (block_allocator == nullptr) {
437 error(user_context) << "VulkanMemoryAllocator: Unable to release region! Invalid block allocator!\n";
439 }
440 return block_allocator->release(this, region);
441}
442
443int VulkanMemoryAllocator::reclaim(void *user_context, MemoryRegion *region) {
444#if defined(HL_VK_DEBUG_MEM)
445 debug(nullptr) << "VulkanMemoryAllocator: Reclaiming region ("
446 << "user_context=" << user_context << " "
447 << "region=" << (void *)(region) << " "
448 << "size=" << (uint32_t)region->size << " "
449 << "offset=" << (uint32_t)region->offset << ") ...\n";
450#endif
451 if ((device == nullptr) || (physical_device == nullptr)) {
452 error(user_context) << "VulkanMemoryAllocator: Unable to reclaim region! Invalid device handle!\n";
454 }
455 if (block_allocator == nullptr) {
456 error(user_context) << "VulkanMemoryAllocator: Unable to reclaim region! Invalid block allocator!\n";
458 }
459 return block_allocator->reclaim(this, region);
460}
461
462int VulkanMemoryAllocator::retain(void *user_context, MemoryRegion *region) {
463#if defined(HL_VK_DEBUG_MEM)
464 debug(nullptr) << "VulkanMemoryAllocator: Retaining region ("
465 << "user_context=" << user_context << " "
466 << "region=" << (void *)(region) << " "
467 << "size=" << (uint32_t)region->size << " "
468 << "offset=" << (uint32_t)region->offset << ") ...\n";
469#endif
470 if ((device == nullptr) || (physical_device == nullptr)) {
471 error(user_context) << "VulkanMemoryAllocator: Unable to retain region! Invalid device handle!\n";
473 }
474 if (block_allocator == nullptr) {
475 error(user_context) << "VulkanMemoryAllocator: Unable to retain region! Invalid block allocator!\n";
477 }
478 return block_allocator->retain(this, region);
479}
480
481bool VulkanMemoryAllocator::collect(void *user_context) {
482#if defined(HL_VK_DEBUG_MEM)
483 debug(nullptr) << "VulkanMemoryAllocator: Collecting unused memory ("
484 << "user_context=" << user_context << ") ... \n";
485#endif
486 if ((device == nullptr) || (physical_device == nullptr) || (block_allocator == nullptr)) {
487 return false;
488 }
489 return block_allocator->collect(this);
490}
491
492int VulkanMemoryAllocator::release(void *user_context) {
493#if defined(HL_VK_DEBUG_MEM)
494 debug(nullptr) << "VulkanMemoryAllocator: Releasing block allocator ("
495 << "user_context=" << user_context << ") ... \n";
496#endif
497 if ((device == nullptr) || (physical_device == nullptr)) {
498 error(user_context) << "VulkanMemoryAllocator: Unable to release allocator! Invalid device handle!\n";
500 }
501 if (block_allocator == nullptr) {
502 error(user_context) << "VulkanMemoryAllocator: Unable to release allocator! Invalid block allocator!\n";
504 }
505
506 return block_allocator->release(this);
507}
508
509int VulkanMemoryAllocator::destroy(void *user_context) {
510#if defined(HL_VK_DEBUG_MEM)
511 debug(nullptr) << "VulkanMemoryAllocator: Destroying allocator ("
512 << "user_context=" << user_context << ") ... \n";
513#endif
514 if (block_allocator != nullptr) {
515 block_allocator->destroy(this);
516 }
517 region_count = 0;
518 region_byte_count = 0;
519 block_count = 0;
520 block_byte_count = 0;
522}
523
524const VulkanMemoryConfig &
526 static VulkanMemoryConfig result;
527 return result;
528}
529
530// --
531
533 VulkanMemoryAllocator *instance = reinterpret_cast<VulkanMemoryAllocator *>(instance_ptr);
534 if (instance == nullptr) {
536 }
537
538 void *user_context = instance->owner_context;
539 if ((instance->device == nullptr) || (instance->physical_device == nullptr)) {
540 error(user_context) << "VulkanBlockAllocator: Unable to deallocate block! Invalid device handle!\n";
542 }
543
544 if (block == nullptr) {
545 error(user_context) << "VulkanBlockAllocator: Unable to deallocate block! Invalid pointer!\n";
547 }
548
549#if defined(HL_VK_DEBUG_MEM)
550 debug(nullptr) << "VulkanMemoryAllocator: Allocating block ("
551 << "user_context=" << user_context << " "
552 << "block=" << (void *)(block) << " "
553 << "size=" << (uint64_t)block->size << ", "
554 << "dedicated=" << (block->dedicated ? "true" : "false") << " "
555 << "usage=" << halide_memory_usage_name(block->properties.usage) << " "
556 << "caching=" << halide_memory_caching_name(block->properties.caching) << " "
557 << "visibility=" << halide_memory_visibility_name(block->properties.visibility) << ")\n";
558#endif
559
560 // Find an appropriate memory type given the flags
561 uint32_t memory_type = instance->select_memory_type(user_context, instance->physical_device, block->properties, 0);
562 if (memory_type == invalid_memory_type) {
563 error(user_context) << "VulkanMemoryAllocator: Unable to find appropriate memory type for device!\n";
565 }
566
567 // Allocate memory
570 nullptr, // struct extending this
571 block->size, // size of allocation in bytes
572 memory_type // memory type index from physical device
573 };
574
576 if (device_memory == nullptr) {
577 debug(nullptr) << "VulkanBlockAllocator: Unable to allocate block! Failed to allocate device memory handle!\n";
579 }
580
581 VkResult result = vkAllocateMemory(instance->device, &alloc_info, instance->alloc_callbacks, device_memory);
582 if (result != VK_SUCCESS) {
583 debug(nullptr) << "VulkanMemoryAllocator: Allocation failed! vkAllocateMemory returned: " << vk_get_error_name(result) << "\n";
585 }
586#ifdef DEBUG_RUNTIME
587 debug(nullptr) << "vkAllocateMemory: Allocated memory for device region (" << (uint64_t)block->size << " bytes) ...\n";
588#endif
589
590 uint32_t usage_flags = instance->select_memory_usage(user_context, block->properties);
591
594 nullptr, // struct extending this
595 0, // create flags
596 sizeof(uint32_t), // buffer size (in bytes)
597 usage_flags, // buffer usage flags
598 VK_SHARING_MODE_EXCLUSIVE, // sharing mode
599 0, nullptr};
600
601 // Create a buffer to determine alignment requirements
602 VkBuffer buffer = {0};
603 result = vkCreateBuffer(instance->device, &create_info, instance->alloc_callbacks, &buffer);
604 if (result != VK_SUCCESS) {
605 debug(nullptr) << "VulkanMemoryAllocator: Failed to create buffer!\n\t"
606 << "vkCreateBuffer returned: " << vk_get_error_name(result) << "\n";
608 }
609
611 vkGetBufferMemoryRequirements(instance->device, buffer, &memory_requirements);
612 vkDestroyBuffer(instance->device, buffer, instance->alloc_callbacks);
613
614#if defined(HL_VK_DEBUG_MEM)
615 debug(nullptr) << "VulkanMemoryAllocator: Block allocated ("
616 << "size=" << (uint32_t)block->size << ", "
617 << "alignment=" << (uint32_t)memory_requirements.alignment << ", "
618 << "uniform_buffer_offset_alignment=" << (uint32_t)instance->physical_device_limits.minUniformBufferOffsetAlignment << ", "
619 << "storage_buffer_offset_alignment=" << (uint32_t)instance->physical_device_limits.minStorageBufferOffsetAlignment << ", "
620 << "dedicated=" << (block->dedicated ? "true" : "false") << ")\n";
621#endif
622
623 // Enforce any alignment constrainst reported by the device limits for each usage type
625 block->properties.alignment = instance->physical_device_limits.minStorageBufferOffsetAlignment;
627 block->properties.alignment = instance->physical_device_limits.minUniformBufferOffsetAlignment;
628 }
629 // Some drivers appear to report a buffer alignment constraint (regardless of usage) that can be larger than either of the above
630 if (memory_requirements.alignment > block->properties.alignment) {
631 block->properties.alignment = memory_requirements.alignment;
632 }
633 block->handle = (void *)device_memory;
634 instance->block_byte_count += block->size;
635 instance->block_count++;
637}
638
640 VulkanMemoryAllocator *instance = reinterpret_cast<VulkanMemoryAllocator *>(instance_ptr);
641 if (instance == nullptr) {
643 }
644
645 void *user_context = instance->owner_context;
646#if defined(HL_VK_DEBUG_MEM)
647 debug(nullptr) << "VulkanMemoryAllocator: Deallocating block ("
648 << "user_context=" << user_context << " "
649 << "block=" << (void *)(block) << ") ... \n";
650#endif
651
652 if ((instance->device == nullptr) || (instance->physical_device == nullptr)) {
653 error(user_context) << "VulkanBlockAllocator: Unable to deallocate block! Invalid device handle!\n";
655 }
656
657 if (block == nullptr) {
658 error(user_context) << "VulkanBlockAllocator: Unable to deallocate block! Invalid pointer!\n";
660 }
661
662#if defined(HL_VK_DEBUG_MEM)
663 debug(nullptr) << "VulkanBlockAllocator: deallocating block ("
664 << "size=" << (uint32_t)block->size << ", "
665 << "dedicated=" << (block->dedicated ? "true" : "false") << " "
666 << "usage=" << halide_memory_usage_name(block->properties.usage) << " "
667 << "caching=" << halide_memory_caching_name(block->properties.caching) << " "
668 << "visibility=" << halide_memory_visibility_name(block->properties.visibility) << ")\n";
669#endif
670
671 if (block->handle == nullptr) {
672 error(user_context) << "VulkanBlockAllocator: Unable to deallocate block! Invalid handle!\n";
674 }
675
676 VkDeviceMemory *device_memory = reinterpret_cast<VkDeviceMemory *>(block->handle);
677 if (device_memory == nullptr) {
678 error(user_context) << "VulkanBlockAllocator: Unable to deallocate block! Invalid device memory handle!\n";
680 }
681
682 vkFreeMemory(instance->device, *device_memory, instance->alloc_callbacks);
683#ifdef DEBUG_RUNTIME
684 debug(nullptr) << "vkFreeMemory: Deallocated memory for device region (" << (uint64_t)block->size << " bytes) ...\n";
685#endif
686
687 if (instance->block_count > 0) {
688 instance->block_count--;
689 } else {
690 error(nullptr) << "VulkanRegionAllocator: Block counter invalid ... reseting to zero!\n";
691 instance->block_count = 0;
692 }
693
694 if (int64_t(instance->block_byte_count) - int64_t(block->size) >= 0) {
695 instance->block_byte_count -= block->size;
696 } else {
697 error(nullptr) << "VulkanRegionAllocator: Block byte counter invalid ... reseting to zero!\n";
698 instance->block_byte_count = 0;
699 }
700
701 block->handle = nullptr;
702 vk_host_free(nullptr, device_memory, instance->alloc_callbacks);
703 device_memory = nullptr;
705}
706
708 return block_count;
709}
710
712 return block_byte_count;
713}
714
715uint32_t VulkanMemoryAllocator::select_memory_type(void *user_context,
716 VkPhysicalDevice physical_device,
717 MemoryProperties properties,
718 uint32_t required_flags) const {
719
720 uint32_t want_flags = 0; //< preferred memory flags for requested access type
721 uint32_t need_flags = 0; //< must have in order to enable requested access
722 switch (properties.visibility) {
725 break;
728 break;
732 break;
735 break;
738 default:
739 error(nullptr) << "VulkanMemoryAllocator: Unable to convert type! Invalid memory visibility request!\n\t"
740 << "visibility=" << halide_memory_visibility_name(properties.visibility) << "\n";
741 return invalid_memory_type;
742 };
743
744 switch (properties.caching) {
748 }
749 break;
753 }
754 break;
758 }
759 break;
762 break;
764 default:
765 error(user_context) << "VulkanMemoryAllocator: Unable to convert type! Invalid memory caching request!\n\t"
766 << "caching=" << halide_memory_caching_name(properties.caching) << "\n";
767 return invalid_memory_type;
768 };
769
772
773 uint32_t result = invalid_memory_type;
774 for (uint32_t i = 0; i < device_memory_properties.memoryTypeCount; ++i) {
775
776 // if required flags are given, see if the memory type matches the requirement
777 if (required_flags) {
778 if (((required_flags >> i) & 1) == 0) {
779 continue;
780 }
781 }
782
783 const VkMemoryPropertyFlags properties = device_memory_properties.memoryTypes[i].propertyFlags;
784 if (need_flags) {
785 if ((properties & need_flags) != need_flags) {
786 continue;
787 }
788 }
789
790 if (want_flags) {
791 if ((properties & want_flags) != want_flags) {
792 continue;
793 }
794 }
795
796 result = i;
797 break;
798 }
799
800 if (result == invalid_memory_type) {
801 error(user_context) << "VulkanBlockAllocator: Failed to find appropriate memory type for given properties:\n\t"
802 << "usage=" << halide_memory_usage_name(properties.usage) << " "
803 << "caching=" << halide_memory_caching_name(properties.caching) << " "
804 << "visibility=" << halide_memory_visibility_name(properties.visibility) << "\n";
805 return invalid_memory_type;
806 }
807
808 return result;
809}
810
811// --
812
814
815 VulkanMemoryAllocator *instance = reinterpret_cast<VulkanMemoryAllocator *>(instance_ptr);
816 if (instance == nullptr) {
818 }
819
820 void *user_context = instance->owner_context;
821#if defined(HL_VK_DEBUG_MEM)
822 debug(nullptr) << "VulkanMemoryAllocator: Allocating region ("
823 << "user_context=" << user_context << " "
824 << "region=" << (void *)(region) << ") ... \n";
825#endif
826
827 if ((instance->device == nullptr) || (instance->physical_device == nullptr)) {
828 error(user_context) << "VulkanRegionAllocator: Unable to allocate region! Invalid device handle!\n";
830 }
831
832 if (region == nullptr) {
833 error(user_context) << "VulkanRegionAllocator: Unable to allocate region! Invalid pointer!\n";
835 }
836
837#if defined(HL_VK_DEBUG_MEM)
838 debug(nullptr) << "VulkanRegionAllocator: Allocating region ("
839 << "size=" << (uint32_t)region->size << ", "
840 << "offset=" << (uint32_t)region->offset << ", "
841 << "dedicated=" << (region->dedicated ? "true" : "false") << " "
842 << "usage=" << halide_memory_usage_name(region->properties.usage) << " "
843 << "caching=" << halide_memory_caching_name(region->properties.caching) << " "
844 << "visibility=" << halide_memory_visibility_name(region->properties.visibility) << ")\n";
845#endif
846
847 uint32_t usage_flags = instance->select_memory_usage(user_context, region->properties);
848
851 nullptr, // struct extending this
852 0, // create flags
853 region->size, // buffer size (in bytes)
854 usage_flags, // buffer usage flags
855 VK_SHARING_MODE_EXCLUSIVE, // sharing mode
856 0, nullptr};
857
858 VkBuffer *buffer = (VkBuffer *)vk_host_malloc(nullptr, sizeof(VkBuffer), 0, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT, instance->alloc_callbacks);
859 if (buffer == nullptr) {
860 error(user_context) << "VulkanRegionAllocator: Unable to allocate region! Failed to allocate buffer handle!\n";
862 }
863
864 VkResult result = vkCreateBuffer(instance->device, &create_info, instance->alloc_callbacks, buffer);
865 if (result != VK_SUCCESS) {
866 error(user_context) << "VulkanRegionAllocator: Failed to create buffer!\n\t"
867 << "vkCreateBuffer returned: " << vk_get_error_name(result) << "\n";
869 }
870#ifdef DEBUG_RUNTIME
871 debug(nullptr) << "vkCreateBuffer: Created buffer for device region (" << (uint64_t)region->size << " bytes) ...\n";
872#endif
873
875 if (region_allocator == nullptr) {
876 error(user_context) << "VulkanBlockAllocator: Unable to allocate region! Invalid region allocator!\n";
878 }
879
880 BlockResource *block_resource = region_allocator->block_resource();
881 if (block_resource == nullptr) {
882 error(user_context) << "VulkanBlockAllocator: Unable to allocate region! Invalid block resource handle!\n";
884 }
885
886 VkDeviceMemory *device_memory = reinterpret_cast<VkDeviceMemory *>(block_resource->memory.handle);
887 if (device_memory == nullptr) {
888 error(user_context) << "VulkanBlockAllocator: Unable to allocate region! Invalid device memory handle!\n";
890 }
891
892 // Finally, bind buffer to the device memory
893 result = vkBindBufferMemory(instance->device, *buffer, *device_memory, region->offset);
894 if (result != VK_SUCCESS) {
895 error(user_context) << "VulkanRegionAllocator: Failed to bind buffer!\n\t"
896 << "vkBindBufferMemory returned: " << vk_get_error_name(result) << "\n";
898 }
899
900 region->handle = (void *)buffer;
901 region->is_owner = true;
902 instance->region_byte_count += region->size;
903 instance->region_count++;
905}
906
908 VulkanMemoryAllocator *instance = reinterpret_cast<VulkanMemoryAllocator *>(instance_ptr);
909 if (instance == nullptr) {
911 }
912
913 void *user_context = instance->owner_context;
914#if defined(HL_VK_DEBUG_MEM)
915 debug(nullptr) << "VulkanMemoryAllocator: Deallocating region ("
916 << "user_context=" << user_context << " "
917 << "region=" << (void *)(region) << ") ... \n";
918#endif
919
920 if ((instance->device == nullptr) || (instance->physical_device == nullptr)) {
921 error(user_context) << "VulkanRegionAllocator: Unable to deallocate region! Invalid device handle!\n";
923 }
924
925 if (region == nullptr) {
926 error(user_context) << "VulkanRegionAllocator: Unable to deallocate region! Invalid pointer!\n";
928 }
929
930#if defined(HL_VK_DEBUG_MEM)
931 debug(nullptr) << "VulkanRegionAllocator: Deallocating region ("
932 << "size=" << (uint32_t)region->size << ", "
933 << "offset=" << (uint32_t)region->offset << ", "
934 << "dedicated=" << (region->dedicated ? "true" : "false") << " "
935 << "usage=" << halide_memory_usage_name(region->properties.usage) << " "
936 << "caching=" << halide_memory_caching_name(region->properties.caching) << " "
937 << "visibility=" << halide_memory_visibility_name(region->properties.visibility) << ")\n";
938#endif
939
940 if (region->handle == nullptr) {
941 error(user_context) << "VulkanRegionAllocator: Unable to deallocate region! Invalid handle!\n";
943 }
944
945 VkBuffer *buffer = reinterpret_cast<VkBuffer *>(region->handle);
946 if (buffer == nullptr) {
947 error(user_context) << "VulkanRegionAllocator: Unable to deallocate region! Invalid buffer handle!\n";
949 }
950
951 vkDestroyBuffer(instance->device, *buffer, instance->alloc_callbacks);
952#ifdef DEBUG_RUNTIME
953 debug(nullptr) << "vkDestroyBuffer: Destroyed buffer for device region (" << (uint64_t)region->size << " bytes) ...\n";
954#endif
955 region->handle = nullptr;
956 if (instance->region_count > 0) {
957 instance->region_count--;
958 } else {
959 error(nullptr) << "VulkanRegionAllocator: Region counter invalid ... reseting to zero!\n";
960 instance->region_count = 0;
962 }
963
964 if (int64_t(instance->region_byte_count) - int64_t(region->size) >= 0) {
965 instance->region_byte_count -= region->size;
966 } else {
967 error(nullptr) << "VulkanRegionAllocator: Region byte counter invalid ... reseting to zero!\n";
968 instance->region_byte_count = 0;
970 }
971 vk_host_free(nullptr, buffer, instance->alloc_callbacks);
972 buffer = nullptr;
974}
975
977 return region_count;
978}
979
981 return region_byte_count;
982}
983
984uint32_t VulkanMemoryAllocator::select_memory_usage(void *user_context, MemoryProperties properties) const {
985 uint32_t result = 0;
986 switch (properties.usage) {
989 break;
993 break;
996 break;
999 break;
1002 break;
1005 default:
1006 error(user_context) << "VulkanRegionAllocator: Unable to convert type! Invalid memory usage request!\n\t"
1007 << "usage=" << halide_memory_usage_name(properties.usage) << "\n";
1008 return invalid_usage_flags;
1009 };
1010
1011 if (result == invalid_usage_flags) {
1012 error(user_context) << "VulkanRegionAllocator: Failed to find appropriate memory usage for given properties:\n\t"
1013 << "usage=" << halide_memory_usage_name(properties.usage) << " "
1014 << "caching=" << halide_memory_caching_name(properties.caching) << " "
1015 << "visibility=" << halide_memory_visibility_name(properties.visibility) << "\n";
1016 return invalid_usage_flags;
1017 }
1018
1019 return result;
1020}
1021
1022// --------------------------------------------------------------------------
1023
1024namespace {
1025
1026// --------------------------------------------------------------------------
1027// Halide System allocator for host allocations
1028void *vk_system_malloc(void *user_context, size_t size) {
1029 return malloc(size);
1030}
1031
1032void vk_system_free(void *user_context, void *ptr) {
1033 free(ptr);
1034}
1035
1036// Vulkan host-side allocation
1037void *vk_host_malloc(void *user_context, size_t size, size_t alignment, VkSystemAllocationScope scope, const VkAllocationCallbacks *callbacks) {
1038 if (callbacks) {
1039 return callbacks->pfnAllocation(user_context, size, alignment, scope);
1040 } else {
1041 return vk_system_malloc(user_context, size);
1042 }
1043}
1044
1045void vk_host_free(void *user_context, void *ptr, const VkAllocationCallbacks *callbacks) {
1046 if (callbacks) {
1047 return callbacks->pfnFree(user_context, ptr);
1048 } else {
1049 return vk_system_free(user_context, ptr);
1050 }
1051}
1052
1053VulkanMemoryAllocator *vk_create_memory_allocator(void *user_context,
1054 VkDevice device,
1055 VkPhysicalDevice physical_device,
1056 const VkAllocationCallbacks *alloc_callbacks) {
1057
1059 VulkanMemoryConfig config = memory_allocator_config;
1060
1061 // Parse the allocation config string (if specified).
1062 //
1063 // `HL_VK_ALLOC_CONFIG=N:N:N` will tell Halide to configure the Vulkan memory
1064 // allocator use the given constraints specified as three integer values
1065 // separated by a `:` or `;`. These values correspond to `minimum_block_size`,
1066 // `maximum_block_size` and `maximum_block_count`.
1067 //
1068 const char *alloc_config = vk_get_alloc_config_internal(user_context);
1071 alloc_config_values.parse(user_context, alloc_config, HL_VK_ENV_DELIM);
1072 if (alloc_config_values.size() > 0) {
1073 config.maximum_pool_size = atoi(alloc_config_values[0]) * 1024 * 1024;
1074 print(user_context) << "Vulkan: Configuring allocator with " << (uint32_t)config.maximum_pool_size << " for maximum pool size (in bytes)\n";
1075 }
1076 if (alloc_config_values.size() > 1) {
1077 config.minimum_block_size = atoi(alloc_config_values[1]) * 1024 * 1024;
1078 print(user_context) << "Vulkan: Configuring allocator with " << (uint32_t)config.minimum_block_size << " for minimum block size (in bytes)\n";
1079 }
1080 if (alloc_config_values.size() > 2) {
1081 config.maximum_block_size = atoi(alloc_config_values[2]) * 1024 * 1024;
1082 print(user_context) << "Vulkan: Configuring allocator with " << (uint32_t)config.maximum_block_size << " for maximum block size (in bytes)\n";
1083 }
1084 if (alloc_config_values.size() > 3) {
1085 config.maximum_block_count = atoi(alloc_config_values[3]);
1086 print(user_context) << "Vulkan: Configuring allocator with " << (uint32_t)config.maximum_block_count << " for maximum block count\n";
1087 }
1088 if (alloc_config_values.size() > 4) {
1089 config.nearest_multiple = atoi(alloc_config_values[4]);
1090 print(user_context) << "Vulkan: Configuring allocator with " << (uint32_t)config.nearest_multiple << " for nearest multiple\n";
1091 }
1092 }
1093
1094 return VulkanMemoryAllocator::create(user_context,
1095 config, device, physical_device,
1096 system_allocator, alloc_callbacks);
1097}
1098
1099int vk_destroy_memory_allocator(void *user_context, VulkanMemoryAllocator *allocator) {
1100 if (allocator != nullptr) {
1101 VulkanMemoryAllocator::destroy(user_context, allocator);
1102 allocator = nullptr;
1103 }
1105}
1106
1107// --------------------------------------------------------------------------
1108
1109int vk_clear_device_buffer(void *user_context,
1110 VulkanMemoryAllocator *allocator,
1111 VkCommandPool command_pool,
1114
1115#ifdef DEBUG_RUNTIME
1116 debug(user_context)
1117 << " vk_clear_device_buffer (user_context: " << user_context << ", "
1118 << "allocator: " << (void *)allocator << ", "
1119 << "command_pool: " << (void *)command_pool << ", "
1120 << "command_queue: " << (void *)command_queue << ", "
1121 << "device_buffer: " << (void *)device_buffer << ")\n";
1122#endif
1123
1124 // create a command buffer
1126 int error_code = vk_create_command_buffer(user_context, allocator, command_pool, &command_buffer);
1127 if (error_code != halide_error_code_success) {
1128 error(user_context) << "Vulkan: Failed to create command buffer!\n";
1129 return error_code;
1130 }
1131
1132 // begin the command buffer
1134 {
1136 nullptr, // pointer to struct extending this
1138 nullptr // pointer to parent command buffer
1139 };
1140
1142 if (result != VK_SUCCESS) {
1143 error(user_context) << "Vulkan: vkBeginCommandBuffer returned " << vk_get_error_name(result) << "\n";
1145 }
1146
1147 // fill buffer with zero values up to the size of the buffer
1149
1150 // end the command buffer
1152 if (result != VK_SUCCESS) {
1153 error(user_context) << "Vulkan: vkEndCommandBuffer returned " << vk_get_error_name(result) << "\n";
1155 }
1156
1157 // submit the command buffer
1159 {
1160 VK_STRUCTURE_TYPE_SUBMIT_INFO, // struct type
1161 nullptr, // pointer to struct extending this
1162 0, // wait semaphore count
1163 nullptr, // semaphores
1164 nullptr, // pipeline stages where semaphore waits occur
1165 1, // how many command buffers to execute
1166 &command_buffer, // the command buffers
1167 0, // number of semaphores to signal
1168 nullptr // the semaphores to signal
1169 };
1170
1171 result = vkQueueSubmit(command_queue, 1, &submit_info, 0);
1172 if (result != VK_SUCCESS) {
1173 error(user_context) << "Vulkan: vkQueueSubmit returned " << vk_get_error_name(result) << "\n";
1175 }
1176
1177 // wait for memset to finish
1179 if (result != VK_SUCCESS) {
1180 error(user_context) << "Vulkan: vkQueueWaitIdle returned " << vk_get_error_name(result) << "\n";
1182 }
1183
1184 error_code = vk_destroy_command_buffer(user_context, allocator, command_pool, command_buffer);
1185 if (error_code != halide_error_code_success) {
1186 error(user_context) << "Vulkan: Failed to destroy command buffer!\n";
1187 return error_code;
1188 }
1189
1191}
1192
1193// --------------------------------------------------------------------------
1194
1195} // namespace
1196} // namespace Vulkan
1197} // namespace Internal
1198} // namespace Runtime
1199} // namespace Halide
1200
1201// --------------------------------------------------------------------------
1202
1203extern "C" {
1204
1205// --------------------------------------------------------------------------
1206
1208 using namespace Halide::Runtime::Internal::Vulkan;
1209 ScopedSpinLock lock(&custom_allocation_callbacks_lock);
1210 custom_allocation_callbacks = callbacks;
1211}
1212
1214 using namespace Halide::Runtime::Internal::Vulkan;
1215 ScopedSpinLock lock(&custom_allocation_callbacks_lock);
1216 return custom_allocation_callbacks;
1217}
1218
1219// --------------------------------------------------------------------------
1220
1221} // extern "C"
1222
1223#endif // HALIDE_RUNTIME_VULKAN_MEMORY_H
@ 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...
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)
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()
VulkanMemoryAllocator(const VulkanMemoryAllocator &)=delete
int release(void *user_context, MemoryRegion *region)
static int allocate_block(void *instance_ptr, MemoryBlock *block)
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)
MemoryRegion * create_crop(void *user_context, MemoryRegion *region, uint64_t offset)
int destroy_crop(void *user_context, MemoryRegion *region)
static int allocate_region(void *instance_ptr, MemoryRegion *region)
MemoryRegion * owner_of(void *user_context, MemoryRegion *region)
MemoryRegion * reserve(void *user_context, MemoryRequest &request)
const VkAllocationCallbacks * callbacks() const
static int deallocate_block(void *instance_ptr, MemoryBlock *block)
void * map(void *user_context, MemoryRegion *region)
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)
VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset)
VkFlags VkMemoryPropertyFlags
VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data)
VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory)
#define VK_MAX_MEMORY_TYPES
@ VK_SHARING_MODE_EXCLUSIVE
@ VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
@ VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
@ VK_MEMORY_PROPERTY_HOST_CACHED_BIT
@ VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
VKAPI_ATTR void VKAPI_CALL vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements)
VkSystemAllocationScope
@ VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
VKAPI_ATTR VkResult VKAPI_CALL vkQueueWaitIdle(VkQueue queue)
uint64_t VkDeviceSize
Definition mini_vulkan.h:71
VKAPI_ATTR void VKAPI_CALL vkFreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator)
@ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties)
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties)
VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer)
VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence)
VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **ppData)
#define VK_WHOLE_SIZE
@ VK_BUFFER_USAGE_TRANSFER_DST_BIT
@ VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT
@ VK_BUFFER_USAGE_STORAGE_BUFFER_BIT
@ VK_BUFFER_USAGE_TRANSFER_SRC_BIT
VkResult
@ VK_SUCCESS
VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(VkDevice device, VkDeviceMemory memory)
VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(VkCommandBuffer commandBuffer)
VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator)
@ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
@ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
@ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
@ VK_STRUCTURE_TYPE_SUBMIT_INFO
VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo)
WEAK VulkanMemoryConfig memory_allocator_config
WEAK const VkAllocationCallbacks * custom_allocation_callbacks
WEAK ScopedSpinLock::AtomicFlag custom_allocation_callbacks_lock
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 cast(Expr a)
Cast an expression to the halide type corresponding to the C++ type T.
Definition IROperator.h:364
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
int atoi(const char *)
void * malloc(size_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
#define WEAK
void free(void *)
static bool is_empty(const char *str)
PFN_vkAllocationFunction pfnAllocation
PFN_vkFreeFunction pfnFree
VkDeviceSize minStorageBufferOffsetAlignment
VkDeviceSize minUniformBufferOffsetAlignment
#define HL_VK_ENV_DELIM
WEAK void halide_vulkan_set_allocation_callbacks(const VkAllocationCallbacks *callbacks)
WEAK const VkAllocationCallbacks * halide_vulkan_get_allocation_callbacks(void *user_context)