Skip to content

Commit 8272670

Browse files
cesaremercurioCesare Mercurio
authored andcommitted
Vulkan: export allocator for custom contexts
Add documented hooks that let an override of halide_vulkan_acquire_context return its own VkInstance/device yet still bootstrap Halide's allocator. The weak runtime now exposes halide_vulkan_export_memory_allocator/halide_vulkan_memory_allocator_release plus a vk_release_memory_allocator helper that only tears down Halide-owned caches. VulkanContext will lazily allocate+export Halide's allocator when an override returns nullptr. Example integration and validation lives at 9041848.
1 parent 1877f41 commit 8272670

File tree

4 files changed

+101
-1
lines changed

4 files changed

+101
-1
lines changed

src/runtime/HalideRuntimeVulkan.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,23 @@ extern int halide_vulkan_release_context(void *user_context,
105105
VkDevice device,
106106
VkQueue queue,
107107
VkDebugUtilsMessengerEXT messenger);
108+
109+
// - halide_vulkan_export_memory_allocator
110+
// exports the internally allocated memory allocator in case the user wants to just set
111+
// up their own context but use Halide's memory allocator. Must have overridden halide_vulkan_acquire_context
112+
// and halide_vulkan_release_context. Must override also halide_vulkan_export_memory_allocator and guard access
113+
// with the same locking used by the custom acquire/release implementations. This allows the allocator to be
114+
// saved for future halide_vulkan_acquire_context calls that Halide will automatically issue to retrieve
115+
// the custom context.
116+
extern int halide_vulkan_export_memory_allocator(void *user_context,
117+
struct halide_vulkan_memory_allocator *allocator);
118+
// - halide_vulkan_memory_allocator_release
119+
// releases the internally allocated memory allocator, important for proper memory cleanup. Must have overridden halide_vulkan_acquire_context
120+
// and halide_vulkan_release_context, and must coordinate with the same locking as the custom implementations.
121+
extern int halide_vulkan_memory_allocator_release(void *user_context,
122+
struct halide_vulkan_memory_allocator *allocator,
123+
VkInstance instance,
124+
VkDebugUtilsMessengerEXT messenger);
108125
// --
109126

110127
// Override the default allocation callbacks (default uses Vulkan runtime implementation)

src/runtime/vulkan.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,17 @@ WEAK bool halide_vulkan_is_initialized() {
8686
return is_initialized;
8787
}
8888

89+
WEAK int halide_vulkan_export_memory_allocator(void *user_context, halide_vulkan_memory_allocator *allocator) {
90+
halide_mutex_lock(&thread_lock);
91+
halide_error_code_t status = halide_error_code_success;
92+
if (allocator == nullptr) {
93+
error(user_context) << "Vulkan: Memory allocator is null!\n";
94+
status = halide_error_code_buffer_argument_is_null;
95+
}
96+
halide_mutex_unlock(&thread_lock);
97+
return status;
98+
}
99+
89100
WEAK int halide_vulkan_device_free(void *user_context, halide_buffer_t *halide_buffer) {
90101
debug(user_context)
91102
<< "halide_vulkan_device_free (user_context: " << user_context
@@ -258,6 +269,21 @@ WEAK int halide_vulkan_device_release(void *user_context) {
258269
return destroy_status;
259270
}
260271

272+
WEAK int halide_vulkan_memory_allocator_release(void *user_context,
273+
struct halide_vulkan_memory_allocator *allocator,
274+
VkInstance instance,
275+
VkDebugUtilsMessengerEXT messenger) {
276+
debug(user_context) << "halide_vulkan_memory_allocator_release (user_context: " << user_context << ")\n";
277+
// Destroy the context if we created it
278+
if (allocator == nullptr) {
279+
error(user_context) << "Vulkan: Memory allocator is null!\n";
280+
return halide_error_code_buffer_argument_is_null;
281+
}
282+
283+
return vk_release_memory_allocator(user_context, (VulkanMemoryAllocator *)allocator,
284+
instance, messenger);
285+
}
286+
261287
WEAK int halide_vulkan_device_malloc(void *user_context, halide_buffer_t *buf) {
262288
debug(user_context)
263289
<< "halide_vulkan_device_malloc (user_context: " << user_context

src/runtime/vulkan_context.h

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,43 @@ class VulkanContext {
5858
error = halide_error_code_device_interface_no_device;
5959
halide_error_no_device_interface(user_context);
6060
}
61+
// If user overrode halide_vulkan_acquire_context and returned nullptr for allocator,
62+
// create Halide's allocator for the provided device. User must override `halide_vulkan_export_memory_allocator`
63+
// and make sure to propagate it back at the next call of `halide_vulkan_acquire_context` as he overrides it.
64+
if (allocator == nullptr &&
65+
instance != VK_NULL_HANDLE &&
66+
device != VK_NULL_HANDLE &&
67+
physical_device != VK_NULL_HANDLE) {
68+
#ifdef DEBUG_RUNTIME
69+
// Initialize clock for debug timing - normally done in halide_vulkan_acquire_context
70+
halide_start_clock(user_context);
71+
#endif
72+
// make sure halide vulkan is loaded BEFORE creating allocator
73+
debug(user_context) << "VulkanContext: Loading Vulkan function pointers for context override...\n";
74+
75+
vk_load_vulkan_loader_functions(user_context);
76+
if (vkGetInstanceProcAddr == nullptr) {
77+
debug(user_context) << "VulkanContext: Failed to load vkGetInstanceProcAddr from loader!\n";
78+
} else {
79+
debug(user_context) << "VulkanContext: vkGetInstanceProcAddr loaded successfully: " << (void *)vkGetInstanceProcAddr << "\n";
80+
vk_load_vulkan_instance_functions(user_context, instance);
81+
vk_load_vulkan_device_functions(user_context, device);
82+
}
83+
84+
allocator = vk_create_memory_allocator(user_context, device, physical_device,
85+
halide_vulkan_get_allocation_callbacks(user_context));
86+
if (allocator == nullptr) {
87+
error = halide_error_code_out_of_memory;
88+
debug(user_context) << "Vulkan: Failed to create memory allocator for device!\n";
89+
return;
90+
}
91+
int result = halide_vulkan_export_memory_allocator(user_context, reinterpret_cast<halide_vulkan_memory_allocator *>(allocator));
92+
if (result != halide_error_code_success) {
93+
error = static_cast<halide_error_code_t>(result);
94+
debug(user_context) << "Vulkan: Failed to export memory allocator for device!\n";
95+
return;
96+
}
97+
}
6198
halide_debug_assert(user_context, allocator != nullptr);
6299
halide_debug_assert(user_context, instance != VK_NULL_HANDLE);
63100
halide_debug_assert(user_context, device != VK_NULL_HANDLE);
@@ -546,8 +583,8 @@ int vk_destroy_context(void *user_context, VulkanMemoryAllocator *allocator,
546583

547584
if (allocator != nullptr) {
548585
vk_destroy_shader_modules(user_context, allocator);
549-
vk_destroy_memory_allocator(user_context, allocator);
550586
vk_destroy_debug_utils_messenger(user_context, instance, allocator, messenger);
587+
vk_destroy_memory_allocator(user_context, allocator);
551588
}
552589

553590
const VkAllocationCallbacks *alloc_callbacks = halide_vulkan_get_allocation_callbacks(user_context);
@@ -560,6 +597,20 @@ int vk_destroy_context(void *user_context, VulkanMemoryAllocator *allocator,
560597
return halide_error_code_success;
561598
}
562599

600+
// Clean up only Halide's internal resources for external context (leaves device/instance alone)
601+
int vk_release_memory_allocator(void *user_context, VulkanMemoryAllocator *allocator,
602+
VkInstance instance, VkDebugUtilsMessengerEXT messenger) {
603+
debug(user_context) << "vk_release_memory_allocator (user_context: " << user_context << ")\n";
604+
// Clean up only Halide's internal resources, not the device/instance we don't own
605+
if (allocator != nullptr) {
606+
vk_destroy_shader_modules(user_context, allocator);
607+
vk_destroy_debug_utils_messenger(user_context, instance, allocator, messenger);
608+
vk_destroy_memory_allocator(user_context, allocator);
609+
}
610+
611+
return halide_error_code_success;
612+
}
613+
563614
// --------------------------------------------------------------------------
564615

565616
VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_utils_messenger_callback(

src/runtime/vulkan_internal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ int vk_destroy_context(
6666
VkPhysicalDevice physical_device,
6767
VkQueue queue);
6868

69+
int vk_release_memory_allocator(
70+
void *user_context,
71+
VulkanMemoryAllocator *allocator,
72+
VkInstance instance,
73+
VkDebugUtilsMessengerEXT messenger);
74+
6975
int vk_find_compute_capability(void *user_context, int *major, int *minor);
7076

7177
int vk_create_instance(void *user_context, const StringTable &requested_layers, VkInstance *instance, const VkAllocationCallbacks *alloc_callbacks);

0 commit comments

Comments
 (0)