@@ -143,6 +143,109 @@ extern "C" int halide_webgpu_release_context(void *user_context) {
143143}
144144
145145#define HAS_MULTIPLE_CONTEXTS true
146+ #elif defined(TEST_VULKAN)
147+
148+ #include " HalideRuntimeVulkan.h"
149+
150+ struct gpu_context {
151+ halide_vulkan_memory_allocator *allocator = nullptr ;
152+ VkInstance instance = nullptr ;
153+ VkDevice device = nullptr ;
154+ VkPhysicalDevice physical_device = nullptr ;
155+ VkQueue queue = nullptr ;
156+ uint32_t queue_family_index = 0 ;
157+ VkDebugUtilsMessengerEXT messenger = nullptr ;
158+ halide_vulkan_acquire_context_t previous_acquire = nullptr ;
159+ halide_vulkan_release_context_t previous_release = nullptr ;
160+ int acquires = 0 ;
161+ int releases = 0 ;
162+ } vulkan_context;
163+
164+ extern " C" int custom_vulkan_acquire_context (void *user_context,
165+ halide_vulkan_memory_allocator **allocator,
166+ VkInstance *instance,
167+ VkDevice *device,
168+ VkPhysicalDevice *physical_device,
169+ VkQueue *queue,
170+ uint32_t *queue_family_index,
171+ VkDebugUtilsMessengerEXT *messenger,
172+ bool create) {
173+ if (vulkan_context.allocator == nullptr || vulkan_context.instance == nullptr ) {
174+ return halide_error_code_device_interface_no_device;
175+ }
176+ *allocator = vulkan_context.allocator ;
177+ *instance = vulkan_context.instance ;
178+ *device = vulkan_context.device ;
179+ *physical_device = vulkan_context.physical_device ;
180+ *queue = vulkan_context.queue ;
181+ *queue_family_index = vulkan_context.queue_family_index ;
182+ *messenger = vulkan_context.messenger ;
183+ vulkan_context.acquires ++;
184+ return halide_error_code_success;
185+ }
186+
187+ extern " C" int custom_vulkan_release_context (void *user_context,
188+ VkInstance instance,
189+ VkDevice device,
190+ VkQueue queue,
191+ VkDebugUtilsMessengerEXT messenger) {
192+ vulkan_context.releases ++;
193+ return halide_error_code_success;
194+ }
195+
196+ bool init_context () {
197+ halide_vulkan_memory_allocator *default_allocator = nullptr ;
198+ // Use Halide's built-in Vulkan setup to get real handles, then exercise the
199+ // same callback and allocator path an embedder would use for its own context.
200+ int result = halide_vulkan_acquire_context (nullptr ,
201+ &default_allocator,
202+ &vulkan_context.instance ,
203+ &vulkan_context.device ,
204+ &vulkan_context.physical_device ,
205+ &vulkan_context.queue ,
206+ &vulkan_context.queue_family_index ,
207+ &vulkan_context.messenger ,
208+ true );
209+ if (result != halide_error_code_success) {
210+ printf (" [SKIP] Failed to create Vulkan context: %d\n " , result);
211+ return false ;
212+ }
213+ halide_vulkan_release_context (nullptr , vulkan_context.instance , vulkan_context.device ,
214+ vulkan_context.queue , vulkan_context.messenger );
215+
216+ result = halide_vulkan_acquire_memory_allocator (nullptr ,
217+ &vulkan_context.allocator ,
218+ vulkan_context.instance ,
219+ vulkan_context.device ,
220+ vulkan_context.physical_device );
221+ if (result != halide_error_code_success) {
222+ printf (" Failed to create external Vulkan allocator: %d\n " , result);
223+ return false ;
224+ }
225+
226+ vulkan_context.previous_acquire = halide_set_vulkan_acquire_context (custom_vulkan_acquire_context);
227+ vulkan_context.previous_release = halide_set_vulkan_release_context (custom_vulkan_release_context);
228+ return true ;
229+ }
230+
231+ void destroy_context () {
232+ int result = halide_vulkan_release_memory_allocator (nullptr ,
233+ vulkan_context.allocator ,
234+ vulkan_context.instance ,
235+ vulkan_context.device ,
236+ vulkan_context.physical_device );
237+ if (result != halide_error_code_success) {
238+ printf (" Failed to release external Vulkan allocator: %d\n " , result);
239+ }
240+ assert (vulkan_context.acquires == vulkan_context.releases );
241+ vulkan_context.allocator = nullptr ;
242+
243+ halide_set_vulkan_acquire_context (vulkan_context.previous_acquire );
244+ halide_set_vulkan_release_context (vulkan_context.previous_release );
245+ halide_device_release (nullptr , halide_vulkan_device_interface ());
246+
247+ vulkan_context = gpu_context{};
248+ }
146249#else
147250// Just use the default implementation of acquire/release.
148251bool init_context () {
@@ -194,10 +297,14 @@ bool run_test() {
194297 output.device_free ();
195298
196299 if (interface != nullptr ) {
300+ #if defined(TEST_VULKAN)
301+ destroy_context ();
302+ #else
197303 halide_device_release (nullptr , interface);
198304
199305 // Free the context we created.
200306 destroy_context ();
307+ #endif
201308 } else {
202309 printf (" Device interface is nullptr.\n " );
203310 }
@@ -207,17 +314,13 @@ bool run_test() {
207314}
208315
209316int main (int argc, char **argv) {
210- #if defined(TEST_VULKAN)
211- printf (" [SKIP] Vulkan doesn't implement a custom context for this test.\n " );
212- #else
213317 if (!run_test ()) {
214318 return 1 ;
215319 }
216320
217321 if (!run_test ()) {
218322 return 1 ;
219323 }
220- #endif
221324 return 0 ;
222325}
223326
0 commit comments