Halide 19.0.0
Halide compiler and libraries
Loading...
Searching...
No Matches
vulkan_resources.h
Go to the documentation of this file.
1#ifndef HALIDE_RUNTIME_VULKAN_RESOURCES_H
2#define HALIDE_RUNTIME_VULKAN_RESOURCES_H
3
4#include "vulkan_internal.h"
5#include "vulkan_memory.h"
6
7// --------------------------------------------------------------------------
8
9namespace Halide {
10namespace Runtime {
11namespace Internal {
12namespace Vulkan {
13
14// Defines the specialization constants used for dynamically overiding the dispatch size
16 uint32_t constant_id[3] = {0}; // zero if unused
17};
18
19// Data used to override specialization constants for dynamic dispatching
26
27// Specialization constant binding information
33
34// Shared memory allocation variable information
36 uint32_t constant_id = 0; // specialization constant to override allocation array size (or zero if unused)
39 const char *variable_name = nullptr;
40};
41
42// Entry point metadata for shader modules
58
59// Compilation cache for compiled shader modules
61 VkShaderModule shader_module = {0};
62 VkDescriptorSetLayout *descriptor_set_layouts = nullptr;
63 VkPipelineLayout pipeline_layout = {0};
66};
67
69
70// --------------------------------------------------------------------------
71
72namespace { // internalize
73
74// --------------------------------------------------------------------------
75
76int vk_create_command_pool(void *user_context, VulkanMemoryAllocator *allocator, uint32_t queue_index, VkCommandPool *command_pool) {
77#ifdef DEBUG_RUNTIME
78 debug(user_context)
79 << " vk_create_command_pool (user_context: " << user_context << ", "
80 << "allocator: " << (void *)allocator << ", "
81 << "queue_index: " << queue_index << ")\n";
82#endif
83
84 if (allocator == nullptr) {
85 error(user_context) << "Vulkan: Failed to create command pool ... invalid allocator pointer!\n";
87 }
88
89 VkCommandPoolCreateInfo command_pool_info =
90 {
92 nullptr, // pointer to struct extending this
93 VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // flags. Assume transient short-lived single-use command buffers
94 queue_index // queue family index corresponding to the compute command queue
95 };
96
97 VkResult result = vkCreateCommandPool(allocator->current_device(), &command_pool_info, allocator->callbacks(), command_pool);
98 if (result != VK_SUCCESS) {
99 error(user_context) << "Vulkan: Failed to create command pool!\n";
101 }
103}
104
105int vk_destroy_command_pool(void *user_context, VulkanMemoryAllocator *allocator, VkCommandPool command_pool) {
106#ifdef DEBUG_RUNTIME
107 debug(user_context)
108 << " vk_destroy_command_pool (user_context: " << user_context << ", "
109 << "allocator: " << (void *)allocator << ", "
110 << "command_pool: " << (void *)command_pool << ")\n";
111#endif
112 if (allocator == nullptr) {
113 error(user_context) << "Vulkan: Failed to destroy command pool ... invalid allocator pointer!\n";
115 }
116 if (command_pool == VkInvalidCommandPool) {
117 debug(user_context) << "Vulkan: Command pool already destroyed.\n";
119 }
121 vkDestroyCommandPool(allocator->current_device(), command_pool, allocator->callbacks());
123}
124
125// --
126
127int vk_create_command_buffer(void *user_context, VulkanMemoryAllocator *allocator, VkCommandPool command_pool, VkCommandBuffer *command_buffer) {
128#ifdef DEBUG_RUNTIME
129 debug(user_context)
130 << " vk_create_command_buffer (user_context: " << user_context << ", "
131 << "allocator: " << (void *)allocator << ", "
132 << "command_pool: " << (void *)command_pool << ")\n";
133#endif
134 if (allocator == nullptr) {
135 error(user_context) << "Vulkan: Failed to create command buffer ... invalid allocator pointer!\n";
137 }
138
139 VkCommandBufferAllocateInfo command_buffer_info =
140 {
142 nullptr, // pointer to struct extending this
143 command_pool, // command pool for allocation
144 VK_COMMAND_BUFFER_LEVEL_PRIMARY, // command buffer level
145 1 // number to allocate
146 };
147
148 VkResult result = vkAllocateCommandBuffers(allocator->current_device(), &command_buffer_info, command_buffer);
149 if (result != VK_SUCCESS) {
150 error(user_context) << "Vulkan: Failed to allocate command buffers!\n";
152 }
154}
155
156int vk_destroy_command_buffer(void *user_context, VulkanMemoryAllocator *allocator, VkCommandPool command_pool, VkCommandBuffer command_buffer) {
157#ifdef DEBUG_RUNTIME
158 debug(user_context)
159 << " vk_destroy_command_buffer (user_context: " << user_context << ", "
160 << "allocator: " << (void *)allocator << ", "
161 << "command_pool: " << (void *)command_pool << ", "
162 << "command_buffer: " << (void *)command_buffer << ")\n";
163#endif
164 if (allocator == nullptr) {
165 error(user_context) << "Vulkan: Failed to destroy command buffer ... invalid allocator pointer!\n";
167 }
168
169 vkFreeCommandBuffers(allocator->current_device(), command_pool, 1, &command_buffer);
171}
172
173int vk_fill_command_buffer_with_dispatch_call(void *user_context,
174 VkDevice device,
175 VkCommandBuffer command_buffer,
176 VkPipeline compute_pipeline,
177 VkPipelineLayout pipeline_layout,
178 VkDescriptorSet descriptor_set,
179 uint32_t descriptor_set_index,
180 int blocksX, int blocksY, int blocksZ) {
181
182#ifdef DEBUG_RUNTIME
183 debug(user_context)
184 << " vk_fill_command_buffer_with_dispatch_call (user_context: " << user_context << ", "
185 << "device: " << (void *)device << ", "
186 << "command_buffer: " << (void *)command_buffer << ", "
187 << "pipeline_layout: " << (void *)pipeline_layout << ", "
188 << "descriptor_set: " << (void *)descriptor_set << ", "
189 << "descriptor_set_index: " << descriptor_set_index << ", "
190 << "blocks: " << blocksX << ", " << blocksY << ", " << blocksZ << ")\n";
191#endif
192
193 VkCommandBufferBeginInfo command_buffer_begin_info = {
195 nullptr, // pointer to struct extending this
197 nullptr // pointer to parent command buffer
198 };
199
200 VkResult result = vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info);
201 if (result != VK_SUCCESS) {
202 error(user_context) << "vkBeginCommandBuffer returned " << vk_get_error_name(result) << "\n";
204 }
205
206 vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, compute_pipeline);
207 vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout,
208 descriptor_set_index, 1, &descriptor_set, 0, nullptr);
209 vkCmdDispatch(command_buffer, blocksX, blocksY, blocksZ);
210
211 result = vkEndCommandBuffer(command_buffer);
212 if (result != VK_SUCCESS) {
213 error(user_context) << "vkEndCommandBuffer returned " << vk_get_error_name(result) << "\n";
215 }
216
218}
219
220int vk_submit_command_buffer(void *user_context, VkQueue queue, VkCommandBuffer command_buffer) {
221#ifdef DEBUG_RUNTIME
222 debug(user_context)
223 << " vk_submit_command_buffer (user_context: " << user_context << ", "
224 << "queue: " << (void *)queue << ", "
225 << "command_buffer: " << (void *)command_buffer << ")\n";
226#endif
227
228 VkSubmitInfo submit_info =
229 {
230 VK_STRUCTURE_TYPE_SUBMIT_INFO, // struct type
231 nullptr, // pointer to struct extending this
232 0, // wait semaphore count
233 nullptr, // semaphores
234 nullptr, // pipeline stages where semaphore waits occur
235 1, // how many command buffers to execute
236 &command_buffer, // the command buffers
237 0, // number of semaphores to signal
238 nullptr // the semaphores to signal
239 };
240
241 VkResult result = vkQueueSubmit(queue, 1, &submit_info, 0);
242 if (result != VK_SUCCESS) {
243 error(user_context) << "Vulkan: vkQueueSubmit returned " << vk_get_error_name(result) << "\n";
245 }
247}
248
249// --
250
251bool vk_needs_scalar_uniform_buffer(void *user_context,
252 size_t arg_sizes[],
253 void *args[],
254 int8_t arg_is_buffer[]) {
255 int i = 0;
256 while (arg_sizes[i] > 0) {
257 if (!arg_is_buffer[i]) {
258 return true;
259 }
260 i++;
261 }
262 return false;
263}
264
265uint32_t vk_count_bindings_for_descriptor_set(void *user_context,
266 size_t arg_sizes[],
267 void *args[],
268 int8_t arg_is_buffer[]) {
269
270 // first binding is for passing scalar parameters in a buffer (if necessary)
271 uint32_t bindings_count = vk_needs_scalar_uniform_buffer(user_context, arg_sizes, args, arg_is_buffer);
272
273 int i = 0;
274 while (arg_sizes[i] > 0) {
275 if (arg_is_buffer[i]) {
276 bindings_count++;
277 }
278 i++;
279 }
280 return bindings_count;
281}
282
283// --
284
285int vk_create_descriptor_pool(void *user_context,
286 VulkanMemoryAllocator *allocator,
287 uint32_t uniform_buffer_count,
288 uint32_t storage_buffer_count,
289 VkDescriptorPool *descriptor_pool) {
290#ifdef DEBUG_RUNTIME
291 debug(user_context)
292 << " vk_create_descriptor_pool (user_context: " << user_context << ", "
293 << "allocator: " << (void *)allocator << ", "
294 << "uniform_buffer_count: " << (uint32_t)uniform_buffer_count << ", "
295 << "storage_buffer_count: " << (uint32_t)storage_buffer_count << ")\n";
296#endif
297 if (allocator == nullptr) {
298 error(user_context) << "Vulkan: Failed to create descriptor pool ... invalid allocator pointer!\n";
300 }
301
302 BlockStorage::Config pool_config;
303 pool_config.entry_size = sizeof(VkDescriptorPoolSize);
304 pool_config.minimum_capacity = (uniform_buffer_count ? 1 : 0) + (storage_buffer_count ? 1 : 0);
305 BlockStorage pool_sizes(user_context, pool_config);
306
307 // First binding is reserved for passing scalar parameters as a uniform buffer
308 if (uniform_buffer_count > 0) {
309 VkDescriptorPoolSize uniform_buffer_size = {
310 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // descriptor type
311 uniform_buffer_count // all kernel args are packed into uniform buffers
312 };
313 pool_sizes.append(user_context, &uniform_buffer_size);
314 }
315
316 if (storage_buffer_count > 0) {
317 VkDescriptorPoolSize storage_buffer_size = {
318 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, // descriptor type
319 storage_buffer_count // all halide buffers are passed as storage buffers
320 };
321 pool_sizes.append(user_context, &storage_buffer_size);
322 }
323
324 VkDescriptorPoolCreateInfo descriptor_pool_info = {
326 nullptr, // point to struct extending this
327 0, // flags
328 1, // this pool will only be used for creating one descriptor set!
329 (uint32_t)pool_sizes.size(), // pool size count
330 (const VkDescriptorPoolSize *)pool_sizes.data() // ptr to descriptr pool sizes
331 };
332
333 VkResult result = vkCreateDescriptorPool(allocator->current_device(), &descriptor_pool_info, allocator->callbacks(), descriptor_pool);
334 if (result != VK_SUCCESS) {
335 error(user_context) << "Vulkan: Failed to create descriptor pool! vkCreateDescriptorPool returned " << vk_get_error_name(result) << "\n";
337 }
339}
340
341int vk_destroy_descriptor_pool(void *user_context,
342 VulkanMemoryAllocator *allocator,
343 VkDescriptorPool descriptor_pool) {
344#ifdef DEBUG_RUNTIME
345 debug(user_context)
346 << " vk_destroy_descriptor_pool (user_context: " << user_context << ", "
347 << "allocator: " << (void *)allocator << ", "
348 << "descriptor_pool: " << (void *)descriptor_pool << ")\n";
349#endif
350 if (allocator == nullptr) {
351 error(user_context) << "Vulkan: Failed to destroy descriptor pool ... invalid allocator pointer!\n";
353 }
354 vkDestroyDescriptorPool(allocator->current_device(), descriptor_pool, allocator->callbacks());
356}
357
358// --
359
360int vk_create_descriptor_set_layout(void *user_context,
361 VulkanMemoryAllocator *allocator,
362 uint32_t uniform_buffer_count,
363 uint32_t storage_buffer_count,
364 VkDescriptorSetLayout *layout) {
365
366#ifdef DEBUG_RUNTIME
367 debug(user_context)
368 << " vk_create_descriptor_set_layout (user_context: " << user_context << ", "
369 << "allocator: " << (void *)allocator << ", "
370 << "uniform_buffer_count: " << uniform_buffer_count << ", "
371 << "storage_buffer_count: " << storage_buffer_count << ", "
372 << "layout: " << (void *)layout << ")\n";
373#endif
374 if (allocator == nullptr) {
375 error(user_context) << "Vulkan: Failed to create descriptor set layout ... invalid allocator pointer!\n";
377 }
378
379 BlockStorage::Config layout_config;
380 layout_config.entry_size = sizeof(VkDescriptorSetLayoutBinding);
381 layout_config.minimum_capacity = uniform_buffer_count + storage_buffer_count;
382 BlockStorage layout_bindings(user_context, layout_config);
383
384 // add all uniform buffers first
385 for (uint32_t n = 0; n < uniform_buffer_count; ++n) {
386 VkDescriptorSetLayoutBinding uniform_buffer_layout = {
387 (uint32_t)layout_bindings.size(), // binding index
388 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // descriptor type
389 1, // descriptor count
390 VK_SHADER_STAGE_COMPUTE_BIT, // stage flags
391 nullptr // immutable samplers
392 };
393
394#ifdef DEBUG_RUNTIME
395 debug(user_context)
396 << " [" << (uint32_t)layout_bindings.size() << "] : UNIFORM_BUFFER\n";
397#endif
398
399 layout_bindings.append(user_context, &uniform_buffer_layout);
400 }
401
402 // Add all other storage buffers
403 for (uint32_t n = 0; n < storage_buffer_count; ++n) {
404
405 // halide buffers will be passed as STORAGE_BUFFERS
406 VkDescriptorSetLayoutBinding storage_buffer_layout = {
407 (uint32_t)layout_bindings.size(), // binding index
408 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, // descriptor type
409 1, // descriptor count
410 VK_SHADER_STAGE_COMPUTE_BIT, // stage flags
411 nullptr // immutable samplers
412 };
413#ifdef DEBUG_RUNTIME
414 debug(user_context)
415 << " [" << (uint32_t)layout_bindings.size() << "] : STORAGE_BUFFER\n";
416#endif
417
418 layout_bindings.append(user_context, &storage_buffer_layout);
419 }
420
421 // Create the LayoutInfo struct
422 VkDescriptorSetLayoutCreateInfo layout_info = {
424 nullptr, // pointer to a struct extending this info
425 0, // flags
426 (uint32_t)layout_bindings.size(), // binding count
427 (VkDescriptorSetLayoutBinding *)layout_bindings.data() // pointer to layout bindings array
428 };
429
430 // Create the descriptor set layout
431 VkResult result = vkCreateDescriptorSetLayout(allocator->current_device(), &layout_info, allocator->callbacks(), layout);
432 if (result != VK_SUCCESS) {
433 error(user_context) << "vkCreateDescriptorSetLayout returned " << vk_get_error_name(result) << "\n";
435 }
436
438}
439
440int vk_destroy_descriptor_set_layout(void *user_context,
441 VulkanMemoryAllocator *allocator,
442 VkDescriptorSetLayout descriptor_set_layout) {
443
444#ifdef DEBUG_RUNTIME
445 debug(user_context)
446 << " vk_destroy_descriptor_set_layout (user_context: " << user_context << ", "
447 << "allocator: " << (void *)allocator << ", "
448 << "layout: " << (void *)descriptor_set_layout << ")\n";
449#endif
450 if (allocator == nullptr) {
451 error(user_context) << "Vulkan: Failed to destroy descriptor set layout ... invalid allocator pointer!\n";
453 }
454 vkDestroyDescriptorSetLayout(allocator->current_device(), descriptor_set_layout, allocator->callbacks());
456}
457
458// --
459
460int vk_create_descriptor_set(void *user_context,
461 VulkanMemoryAllocator *allocator,
462 VkDescriptorSetLayout descriptor_set_layout,
463 VkDescriptorPool descriptor_pool,
464 VkDescriptorSet *descriptor_set) {
465#ifdef DEBUG_RUNTIME
466 debug(user_context)
467 << " vk_create_descriptor_set (user_context: " << user_context << ", "
468 << "allocator: " << (void *)allocator << ", "
469 << "descriptor_set_layout: " << (void *)descriptor_set_layout << ", "
470 << "descriptor_pool: " << (void *)descriptor_pool << ")\n";
471#endif
472 if (allocator == nullptr) {
473 error(user_context) << "Vulkan: Failed to create descriptor set ... invalid allocator pointer!\n";
475 }
476
477 VkDescriptorSetAllocateInfo descriptor_set_info =
478 {
480 nullptr, // pointer to struct extending this
481 descriptor_pool, // pool from which to allocate sets
482 1, // number of descriptor sets
483 &descriptor_set_layout // pointer to array of descriptor set layouts
484 };
485
486 VkResult result = vkAllocateDescriptorSets(allocator->current_device(), &descriptor_set_info, descriptor_set);
487 if (result != VK_SUCCESS) {
488 error(user_context) << "Vulkan: vkAllocateDescriptorSets returned " << vk_get_error_name(result) << "\n";
490 }
491
493}
494
495int vk_update_descriptor_set(void *user_context,
496 VulkanMemoryAllocator *allocator,
497 VkBuffer *scalar_args_buffer,
498 size_t uniform_buffer_count,
499 size_t storage_buffer_count,
500 size_t arg_sizes[],
501 void *args[],
502 int8_t arg_is_buffer[],
503 VkDescriptorSet descriptor_set) {
504#ifdef DEBUG_RUNTIME
505 debug(user_context)
506 << " vk_update_descriptor_set (user_context: " << user_context << ", "
507 << "allocator: " << (void *)allocator << ", "
508 << "scalar_args_buffer: " << (void *)scalar_args_buffer << ", "
509 << "uniform_buffer_count: " << (uint32_t)uniform_buffer_count << ", "
510 << "storage_buffer_count: " << (uint32_t)storage_buffer_count << ", "
511 << "descriptor_set: " << (void *)descriptor_set << ")\n";
512#endif
513 if (allocator == nullptr) {
514 error(user_context) << "Vulkan: Failed to create descriptor set ... invalid allocator pointer!\n";
516 }
517
518 BlockStorage::Config dbi_config;
519 dbi_config.minimum_capacity = storage_buffer_count + uniform_buffer_count;
520 dbi_config.entry_size = sizeof(VkDescriptorBufferInfo);
521 BlockStorage descriptor_buffer_info(user_context, dbi_config);
522
523 BlockStorage::Config wds_config;
524 wds_config.minimum_capacity = storage_buffer_count + uniform_buffer_count;
525 wds_config.entry_size = sizeof(VkWriteDescriptorSet);
526 BlockStorage write_descriptor_set(user_context, wds_config);
527
528 // First binding will be the scalar args buffer (if needed) passed as a UNIFORM BUFFER
529 VkDescriptorBufferInfo *scalar_args_entry = nullptr;
530 if (scalar_args_buffer != nullptr) {
531 VkDescriptorBufferInfo scalar_args_descriptor_buffer_info = {
532 *scalar_args_buffer, // the buffer
533 0, // offset
534 VK_WHOLE_SIZE // range
535 };
536 descriptor_buffer_info.append(user_context, &scalar_args_descriptor_buffer_info);
537 scalar_args_entry = (VkDescriptorBufferInfo *)descriptor_buffer_info.back();
538
539#ifdef DEBUG_RUNTIME
540 debug(user_context) << " [" << (uint32_t)write_descriptor_set.size() << "] UNIFORM_BUFFER : "
541 << "buffer=" << (void *)scalar_args_buffer << " "
542 << "offset=" << (uint32_t)(0) << " "
543 << "size=VK_WHOLE_SIZE\n";
544#endif
545 VkWriteDescriptorSet uniform_buffer_write_descriptor_set = {
547 nullptr, // pointer to struct extending this
548 descriptor_set, // descriptor set to update
549 0, // binding slot
550 0, // array elem
551 1, // num to update
552 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // descriptor type
553 nullptr, // for images
554 scalar_args_entry, // info for buffer
555 nullptr // for texel buffers
556 };
557 write_descriptor_set.append(user_context, &uniform_buffer_write_descriptor_set);
558 }
559
560 // Add all the other device buffers as STORAGE BUFFERs
561 for (size_t i = 0; arg_sizes[i] > 0; i++) {
562 if (arg_is_buffer[i]) {
563
564 // get the allocated region for the buffer
565 MemoryRegion *device_region = reinterpret_cast<MemoryRegion *>(((halide_buffer_t *)args[i])->device);
566 MemoryRegion *owner = allocator->owner_of(user_context, device_region);
567
568 // retrieve the buffer from the region
569 VkBuffer *device_buffer = reinterpret_cast<VkBuffer *>(owner->handle);
570 if (device_buffer == nullptr) {
571 error(user_context) << "Vulkan: Failed to retrieve buffer for device memory!\n";
573 }
574
575 VkDeviceSize range_offset = device_region->range.head_offset;
576 VkDeviceSize range_size = device_region->size - device_region->range.head_offset - device_region->range.tail_offset;
577 halide_abort_if_false(user_context, (device_region->size - device_region->range.head_offset - device_region->range.tail_offset) > 0);
578 VkDescriptorBufferInfo device_buffer_info = {
579 *device_buffer, // the buffer
580 range_offset, // range offset
581 range_size // range size
582 };
583 descriptor_buffer_info.append(user_context, &device_buffer_info);
584 VkDescriptorBufferInfo *device_buffer_entry = (VkDescriptorBufferInfo *)descriptor_buffer_info.back();
585
586#ifdef DEBUG_RUNTIME
587 debug(user_context) << " [" << (uint32_t)write_descriptor_set.size() << "] STORAGE_BUFFER : "
588 << "region=" << (void *)device_region << " "
589 << "buffer=" << (void *)device_buffer << " "
590 << "offset=" << (uint32_t)(range_offset) << " "
591 << "size=" << (uint32_t)(range_size) << "\n";
592#endif
593
594 VkWriteDescriptorSet storage_buffer_write_descriptor_set = {
596 nullptr, // pointer to struct extending this
597 descriptor_set, // descriptor set to update
598 (uint32_t)write_descriptor_set.size(), // binding slot
599 0, // array elem
600 1, // num to update
601 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, // descriptor type
602 nullptr, // for images
603 device_buffer_entry, // info for buffer
604 nullptr // for texel buffers
605 };
606 write_descriptor_set.append(user_context, &storage_buffer_write_descriptor_set);
607 }
608 }
609
610 // issue the update call to populate the descriptor set
611 vkUpdateDescriptorSets(allocator->current_device(), (uint32_t)write_descriptor_set.size(), (const VkWriteDescriptorSet *)write_descriptor_set.data(), 0, nullptr);
613}
614
615// --
616
617size_t vk_estimate_scalar_uniform_buffer_size(void *user_context,
618 size_t arg_sizes[],
619 void *args[],
620 int8_t arg_is_buffer[]) {
621 int i = 0;
622 int scalar_uniform_buffer_size = 0;
623 while (arg_sizes[i] > 0) {
624 if (!arg_is_buffer[i]) {
625 scalar_uniform_buffer_size += arg_sizes[i];
626 }
627 i++;
628 }
629 return scalar_uniform_buffer_size;
630}
631
632MemoryRegion *vk_create_scalar_uniform_buffer(void *user_context,
633 VulkanMemoryAllocator *allocator,
634 size_t scalar_buffer_size) {
635
636#ifdef DEBUG_RUNTIME
637 debug(user_context)
638 << " vk_create_scalar_uniform_buffer (user_context: " << user_context << ", "
639 << "allocator: " << (void *)allocator << ", "
640 << "scalar_buffer_size: " << (uint32_t)scalar_buffer_size << ")\n";
641#endif
642
643 if (allocator == nullptr) {
644 error(user_context) << "Vulkan: Failed to create scalar uniform buffer ... invalid allocator pointer!\n";
645 return nullptr;
646 }
647
648 MemoryRequest request = {0};
649 request.size = scalar_buffer_size;
653
654 // allocate a new region
655 MemoryRegion *region = allocator->reserve(user_context, request);
656 if ((region == nullptr) || (region->handle == nullptr)) {
657 error(user_context) << "Vulkan: Failed to create scalar uniform buffer ... unable to allocate device memory!\n";
658 return nullptr;
659 }
660
661 // return the allocated region for the uniform buffer
662 return region;
663}
664
665int vk_update_scalar_uniform_buffer(void *user_context,
666 VulkanMemoryAllocator *allocator,
667 MemoryRegion *region,
668 size_t arg_sizes[],
669 void *args[],
670 int8_t arg_is_buffer[]) {
671
672#ifdef DEBUG_RUNTIME
673 debug(user_context)
674 << " vk_update_scalar_uniform_buffer (user_context: " << user_context << ", "
675 << "region: " << (void *)region << ")\n";
676#endif
677
678 if (allocator == nullptr) {
679 error(user_context) << "Vulkan: Failed to update scalar uniform buffer ... invalid allocator pointer!\n";
681 }
682
683 if ((region == nullptr) || (region->handle == nullptr)) {
684 error(user_context) << "Vulkan: Failed to update scalar uniform buffer ... invalid memory region!\n";
686 }
687
688 // map the region to a host ptr
689 uint8_t *host_ptr = (uint8_t *)allocator->map(user_context, region);
690 if (host_ptr == nullptr) {
691 error(user_context) << "Vulkan: Failed to update scalar uniform buffer ... unable to map host pointer to device memory!\n";
693 }
694
695 // copy to the (host-visible/coherent) scalar uniform buffer
696 size_t arg_offset = 0;
697 for (size_t i = 0; arg_sizes[i] > 0; i++) {
698 if (!arg_is_buffer[i]) {
699 memcpy(host_ptr + arg_offset, args[i], arg_sizes[i]);
700 arg_offset += arg_sizes[i];
701 }
702 }
703
704 // unmap the pointer to the buffer for the region
705 allocator->unmap(user_context, region);
707}
708
709int vk_destroy_scalar_uniform_buffer(void *user_context, VulkanMemoryAllocator *allocator,
710 MemoryRegion *scalar_args_region) {
711
712#ifdef DEBUG_RUNTIME
713 debug(user_context)
714 << " vk_destroy_scalar_uniform_buffer (user_context: " << user_context << ", "
715 << "allocator: " << (void *)allocator << ", "
716 << "scalar_args_region: " << (void *)scalar_args_region << ")\n";
717#endif
718 if (allocator == nullptr) {
719 error(user_context) << "Vulkan: Failed to destroy scalar uniform buffer ... invalid allocator pointer!\n";
721 }
722
723 if (!scalar_args_region) {
725 }
726
727 int error_code = halide_error_code_success;
728 if (halide_can_reuse_device_allocations(user_context)) {
729 error_code = allocator->release(user_context, scalar_args_region);
730 } else {
731 error_code = allocator->reclaim(user_context, scalar_args_region);
732 }
733 return error_code;
734}
735
736// --
737
738int vk_create_pipeline_layout(void *user_context,
739 VulkanMemoryAllocator *allocator,
740 uint32_t descriptor_set_count,
741 VkDescriptorSetLayout *descriptor_set_layouts,
742 VkPipelineLayout *pipeline_layout) {
743
744#ifdef DEBUG_RUNTIME
745 debug(user_context)
746 << " vk_create_pipeline_layout (user_context: " << user_context << ", "
747 << "allocator: " << (void *)allocator << ", "
748 << "descriptor_set_count: " << descriptor_set_count << ", "
749 << "descriptor_set_layouts: " << (void *)descriptor_set_layouts << ", "
750 << "pipeline_layout: " << (void *)pipeline_layout << ")\n";
751#endif
752 if (allocator == nullptr) {
753 error(user_context) << "Vulkan: Failed to create pipeline layout ... invalid allocator pointer!\n";
755 }
756
758 uint64_t max_bound_descriptor_sets = allocator->current_physical_device_limits().maxBoundDescriptorSets;
759 if (descriptor_set_count > max_bound_descriptor_sets) {
760 error(user_context) << "Vulkan: Number of descriptor sets for pipeline layout exceeds the number that can be bound by device!\n"
761 << " requested: " << descriptor_set_count << ","
762 << " available: " << max_bound_descriptor_sets << "\n";
764 }
765 }
766
767 VkPipelineLayoutCreateInfo pipeline_layout_info = {
769 nullptr, // pointer to a structure extending this
770 0, // flags
771 descriptor_set_count, // number of descriptor sets
772 descriptor_set_layouts, // pointer to the descriptor sets
773 0, // number of push constant ranges
774 nullptr // pointer to push constant range structs
775 };
776
777 VkResult result = vkCreatePipelineLayout(allocator->current_device(), &pipeline_layout_info, allocator->callbacks(), pipeline_layout);
778 if (result != VK_SUCCESS) {
779 error(user_context) << "Vulkan: vkCreatePipelineLayout returned " << vk_get_error_name(result) << "\n";
781 }
783}
784
785int vk_destroy_pipeline_layout(void *user_context,
786 VulkanMemoryAllocator *allocator,
787 VkPipelineLayout pipeline_layout) {
788
789#ifdef DEBUG_RUNTIME
790 debug(user_context)
791 << " vk_destroy_pipeline_layout (user_context: " << user_context << ", "
792 << "allocator: " << (void *)allocator << ", "
793 << "pipeline_layout: " << (void *)pipeline_layout << ")\n";
794#endif
795
796 if (allocator == nullptr) {
797 error(user_context) << "Vulkan: Failed to destroy pipeline layout ... invalid allocator pointer!\n";
799 }
800
801 vkDestroyPipelineLayout(allocator->current_device(), pipeline_layout, allocator->callbacks());
803}
804
805// --
806
807int vk_create_compute_pipeline(void *user_context,
808 VulkanMemoryAllocator *allocator,
809 const char *pipeline_name,
810 VkShaderModule shader_module,
811 VkPipelineLayout pipeline_layout,
812 VkSpecializationInfo *specialization_info,
813 VkPipeline *compute_pipeline) {
814
815#ifdef DEBUG_RUNTIME
816 debug(user_context)
817 << " vk_create_compute_pipeline (user_context: " << user_context << ", "
818 << "allocator: " << (void *)allocator << ", "
819 << "shader_module: " << (void *)shader_module << ", "
820 << "pipeline_layout: " << (void *)pipeline_layout << ")\n";
821#endif
822 if (allocator == nullptr) {
823 error(user_context) << "Vulkan: Failed to create compute pipeline ... invalid allocator pointer!\n";
825 }
826
827 VkComputePipelineCreateInfo compute_pipeline_info =
828 {
830 nullptr, // pointer to a structure extending this
831 0, // flags
832 // VkPipelineShaderStageCreatInfo
833 {
835 nullptr, // pointer to a structure extending this
836 0, // flags
837 VK_SHADER_STAGE_COMPUTE_BIT, // compute stage shader
838 shader_module, // shader module
839 pipeline_name, // entry point name
840 specialization_info, // pointer to VkSpecializationInfo struct
841 },
842 pipeline_layout, // pipeline layout
843 0, // base pipeline handle for derived pipeline
844 0 // base pipeline index for derived pipeline
845 };
846
847 VkResult result = vkCreateComputePipelines(allocator->current_device(), 0, 1, &compute_pipeline_info, allocator->callbacks(), compute_pipeline);
848 if (result != VK_SUCCESS) {
849 error(user_context) << "Vulkan: Failed to create compute pipeline! vkCreateComputePipelines returned " << vk_get_error_name(result) << "\n";
851 }
852
854}
855
856int vk_setup_compute_pipeline(void *user_context,
857 VulkanMemoryAllocator *allocator,
858 VulkanShaderBinding *shader_bindings,
859 VulkanDispatchData *dispatch_data,
860 VkShaderModule shader_module,
861 VkPipelineLayout pipeline_layout,
862 VkPipeline *compute_pipeline) {
863
864#ifdef DEBUG_RUNTIME
865 debug(user_context)
866 << " vk_setup_compute_pipeline (user_context: " << user_context << ", "
867 << "entry_point_name: '" << shader_bindings->entry_point_name << "', "
868 << "allocator: " << (void *)allocator << ", "
869 << "shader_bindings: " << (void *)shader_bindings << ", "
870 << "dispatch_data: " << (void *)dispatch_data << ", "
871 << "shader_module: " << (void *)shader_module << ", "
872 << "pipeline_layout: " << (void *)pipeline_layout << ")\n";
873#endif
874
875 if (allocator == nullptr) {
876 error(user_context) << "Vulkan: Failed to setup compute pipeline ... invalid allocator pointer!\n";
878 }
879
880 if (shader_bindings == nullptr) {
881 error(user_context) << "Vulkan: Failed to setup compute pipeline ... invalid shader bindings!\n";
883 }
884
885 if (shader_bindings == nullptr) {
886 error(user_context) << "Vulkan: Failed to setup compute pipeline ... invalid dispatch data!\n";
888 }
889
890 VkResult result = VK_SUCCESS;
891 const char *entry_point_name = shader_bindings->entry_point_name;
892 if (entry_point_name == nullptr) {
893 error(user_context) << "Vulkan: Failed to setup compute pipeline ... missing entry point name!\n";
895 }
896
897 uint32_t dispatch_constant_index = 0;
898 uint32_t dispatch_constant_ids[4] = {0, 0, 0, 0};
899 uint32_t dispatch_constant_values[4] = {0, 0, 0, 0};
900
901 // locate the mapping for overriding any dynamic shared memory allocation sizes
902 if (shader_bindings->shared_memory_allocations_count && dispatch_data->shared_mem_bytes) {
903
904 uint32_t shared_mem_constant_id = 0;
905 uint32_t static_shared_mem_bytes = 0;
906 uint32_t shared_mem_type_size = 0;
907
908 for (uint32_t sm = 0; sm < shader_bindings->shared_memory_allocations_count; sm++) {
909 VulkanSharedMemoryAllocation *allocation = &(shader_bindings->shared_memory_allocations[sm]);
910 if (allocation->constant_id == 0) {
911 // static fixed-size allocation
912 static_shared_mem_bytes += allocation->type_size * allocation->array_size;
913 } else {
914 // dynamic allocation
915 if (shared_mem_constant_id > 0) {
916 error(user_context) << "Vulkan: Multiple dynamic shared memory allocations found! Only one is suported!!\n";
918 break;
919 }
920 shared_mem_constant_id = allocation->constant_id;
921 shared_mem_type_size = allocation->type_size;
922 }
923 }
924 uint32_t shared_mem_bytes_avail = (dispatch_data->shared_mem_bytes - static_shared_mem_bytes);
925#ifdef DEBUG_RUNTIME
926 debug(user_context) << " pipeline uses " << static_shared_mem_bytes << " bytes of static shared memory\n";
927 debug(user_context) << " dispatch requests " << dispatch_data->shared_mem_bytes << " bytes of shared memory\n";
928 debug(user_context) << " dynamic shared memory " << shared_mem_bytes_avail << " bytes available\n";
929#endif
930 // setup the dynamic array size
931 if ((shared_mem_constant_id > 0) && (shared_mem_bytes_avail > 0)) {
932 uint32_t dynamic_array_size = (uint32_t)shared_mem_bytes_avail / shared_mem_type_size;
933#ifdef DEBUG_RUNTIME
934 debug(user_context) << " setting shared memory to " << (uint32_t)dynamic_array_size << " elements "
935 << "(or " << (uint32_t)shared_mem_bytes_avail << " bytes)\n";
936#endif
937 // save the shared mem specialization constant in the first slot
938 dispatch_constant_ids[dispatch_constant_index] = shared_mem_constant_id;
939 dispatch_constant_values[dispatch_constant_index] = dynamic_array_size;
940 dispatch_constant_index++;
941 }
942
943 // verify the device can actually support the necessary amount of shared memory requested
945 uint64_t device_shared_mem_size = allocator->current_physical_device_limits().maxComputeSharedMemorySize;
946 if (static_shared_mem_bytes > device_shared_mem_size) {
947 error(user_context) << "Vulkan: Amount of static shared memory used exceeds device limit!\n"
948 << " requested: " << static_shared_mem_bytes << " bytes,"
949 << " available: " << device_shared_mem_size << " bytes\n";
951 }
952 if (dispatch_data->shared_mem_bytes > device_shared_mem_size) {
953 error(user_context) << "Vulkan: Amount of dynamic shared memory used exceeds device limit!\n"
954 << " requested: " << dispatch_data->shared_mem_bytes << " bytes,"
955 << " available: " << device_shared_mem_size << " bytes\n";
957 }
958 }
959 }
960
961 // locate the mapping for overriding any dynamic workgroup local sizes
962 if (shader_bindings->dispatch_data.local_size_binding.constant_id[0] != 0) {
963 for (uint32_t dim = 0; dim < 3; dim++) {
964 dispatch_constant_ids[dispatch_constant_index] = shader_bindings->dispatch_data.local_size_binding.constant_id[dim];
965 dispatch_constant_values[dispatch_constant_index] = dispatch_data->local_size[dim];
966 dispatch_constant_index++;
967 }
968 }
969
970 // verify the specialization constants actually exist
971 for (uint32_t dc = 0; dc < dispatch_constant_index; dc++) {
972 const uint32_t invalid_index = uint32_t(-1);
973 uint32_t found_index = invalid_index;
974 for (uint32_t sc = 0; sc < shader_bindings->specialization_constants_count; sc++) {
975 if (shader_bindings->specialization_constants[sc].constant_id == dispatch_constant_ids[dc]) {
976#ifdef DEBUG_RUNTIME
977 debug(user_context) << " binding specialization constant [" << dispatch_constant_ids[dc] << "] "
978 << "'" << shader_bindings->specialization_constants[sc].constant_name << "' "
979 << " => " << dispatch_constant_values[dc] << "\n";
980#endif
981 found_index = sc;
982 break;
983 }
984 }
985 if (found_index == invalid_index) {
986 error(user_context) << "Vulkan: Failed to locate dispatch constant index for shader binding!\n";
988 }
989 }
990
991 // don't even attempt to create the pipeline layout if we encountered errors in the shader binding
992 if (result != VK_SUCCESS) {
993 error(user_context) << "Vulkan: Failed to decode shader bindings! " << vk_get_error_name(result) << "\n";
995 }
996
997 // Prepare specialization mapping for all dispatch constants
998 uint32_t dispatch_constant_count = 0;
999 VkSpecializationMapEntry specialization_map_entries[4];
1000 memset(specialization_map_entries, 0, 4 * sizeof(VkSpecializationMapEntry));
1001 for (uint32_t dc = 0; dc < dispatch_constant_index && dc < 4; dc++) {
1002 specialization_map_entries[dc].constantID = dispatch_constant_ids[dc];
1003 specialization_map_entries[dc].size = sizeof(uint32_t);
1004 specialization_map_entries[dc].offset = dc * sizeof(uint32_t);
1005 dispatch_constant_count++;
1006 }
1007
1008 if (dispatch_constant_count > 0) {
1009
1010 // Prepare specialization info block for the shader stage
1011 VkSpecializationInfo specialization_info{};
1012 specialization_info.dataSize = dispatch_constant_count * sizeof(uint32_t);
1013 specialization_info.mapEntryCount = dispatch_constant_count;
1014 specialization_info.pMapEntries = specialization_map_entries;
1015 specialization_info.pData = dispatch_constant_values;
1016
1017 // Recreate the pipeline with the requested shared memory allocation
1018 if (shader_bindings->compute_pipeline) {
1019 int error_code = vk_destroy_compute_pipeline(user_context, allocator, shader_bindings->compute_pipeline);
1020 if (error_code != halide_error_code_success) {
1021 error(user_context) << "Vulkan: Failed to destroy compute pipeline!\n";
1023 }
1024 shader_bindings->compute_pipeline = {0};
1025 }
1026
1027 int error_code = vk_create_compute_pipeline(user_context, allocator, entry_point_name, shader_module, pipeline_layout, &specialization_info, &(shader_bindings->compute_pipeline));
1028 if (error_code != halide_error_code_success) {
1029 error(user_context) << "Vulkan: Failed to create compute pipeline!\n";
1030 return error_code;
1031 }
1032
1033 } else {
1034
1035 // Construct and re-use the fixed pipeline
1036 if (shader_bindings->compute_pipeline == 0) {
1037 int error_code = vk_create_compute_pipeline(user_context, allocator, entry_point_name, shader_module, pipeline_layout, nullptr, &(shader_bindings->compute_pipeline));
1038 if (error_code != halide_error_code_success) {
1039 error(user_context) << "Vulkan: Failed to create compute pipeline!\n";
1040 return error_code;
1041 }
1042 }
1043 }
1044
1046}
1047
1048int vk_destroy_compute_pipeline(void *user_context,
1049 VulkanMemoryAllocator *allocator,
1050 VkPipeline compute_pipeline) {
1051#ifdef DEBUG_RUNTIME
1052 debug(user_context)
1053 << " vk_destroy_compute_pipeline (user_context: " << user_context << ", "
1054 << "allocator: " << (void *)allocator << ", "
1055 << "device: " << (void *)allocator->current_device() << ", "
1056 << "compute_pipeline: " << (void *)compute_pipeline << ")\n";
1057#endif
1058 if (allocator == nullptr) {
1059 error(user_context) << "Vulkan: Failed to destroy compute pipeline ... invalid allocator pointer!\n";
1061 }
1062
1063 vkDestroyPipeline(allocator->current_device(), compute_pipeline, allocator->callbacks());
1065}
1066
1067// --------------------------------------------------------------------------
1068
1069VulkanShaderBinding *vk_decode_shader_bindings(void *user_context, VulkanMemoryAllocator *allocator, const uint32_t *module_ptr, uint32_t module_size) {
1070#ifdef DEBUG_RUNTIME
1071 debug(user_context)
1072 << " vk_decode_shader_bindings (user_context: " << user_context << ", "
1073 << "allocator: " << (void *)allocator << ", "
1074 << "module_ptr: " << (void *)module_ptr << ", "
1075 << "module_size: " << module_size << ")\n";
1076
1077 uint64_t t_before = halide_current_time_ns(user_context);
1078#endif
1079
1080 if (allocator == nullptr) {
1081 error(user_context) << "Vulkan: Failed to decode shader bindings ... invalid allocator pointer!\n";
1082 return nullptr;
1083 }
1084
1085 if ((module_ptr == nullptr) || (module_size < (2 * sizeof(uint32_t)))) {
1086 error(user_context) << "Vulkan: Failed to decode shader bindings ... invalid module buffer!\n";
1087 return nullptr;
1088 }
1089
1090 // Decode the sidecar for the module that lists the descriptor sets
1091 // corresponding to each entry point contained in the module.
1092 //
1093 // Construct a shader binding for each entry point that defines all
1094 // the buffers, constants, shared memory, and workgroup sizes
1095 // that are required for execution.
1096 //
1097 // Like the SPIR-V code module, each entry is one word (1x uint32_t).
1098 // Variable length sections are prefixed with their length (ie number of entries).
1099 //
1100 // [0] Header word count (total length of header)
1101 // [1] Number of descriptor sets
1102 // ... For each descriptor set ...
1103 // ... [0] Length of entry point name (padded to nearest word size)
1104 // ....... [*] Entry point string data (padded with null chars)
1105 // ... [1] Number of uniform buffers for this descriptor set
1106 // ... [2] Number of storage buffers for this descriptor set
1107 // ... [3] Number of specialization constants for this descriptor set
1108 // ....... For each specialization constant ...
1109 // ....... [0] Length of constant name string (padded to nearest word size)
1110 // ........... [*] Constant name string data (padded with null chars)
1111 // ....... [1] Constant id (as used in VkSpecializationMapEntry for binding)
1112 // ....... [2] Size of data type (in bytes)
1113 // ... [4] Number of shared memory allocations for this descriptor set
1114 // ....... For each allocation ...
1115 // ....... [0] Length of variable name string (padded to nearest word size)
1116 // ........... [*] Variable name string data (padded with null chars)
1117 // ....... [1] Constant id to use for overriding array size (zero if it is not bound to a specialization constant)
1118 // ....... [2] Size of data type (in bytes)
1119 // ....... [3] Size of array (ie element count)
1120 // ... [4] Dynamic workgroup dimensions bound to specialization constants
1121 // ....... [0] Constant id to use for local_size_x (zero if it was statically declared and not bound to a specialization constant)
1122 // ....... [1] Constant id to use for local_size_y
1123 // ....... [2] Constant id ot use for local_size_z
1124 //
1125 // NOTE: See CodeGen_Vulkan_Dev::SPIRV_Emitter::encode_header() for the encoding
1126 //
1127 // Both vk_decode_shader_bindings() and vk_compile_shader_module() will
1128 // need to be updated if the header encoding ever changes!
1129 //
1130 uint32_t module_entries = module_size / sizeof(uint32_t);
1131 uint32_t idx = 1; // skip past the header_word_count
1132 uint32_t shader_count = module_ptr[idx++];
1133 if (shader_count < 1) {
1134 error(user_context) << "Vulkan: Failed to decode shader bindings ... no descriptors found!\n";
1135 return nullptr; // no descriptors
1136 }
1137
1138 // allocate an array of shader bindings (one for each entry point in the module)
1139 VkSystemAllocationScope alloc_scope = VkSystemAllocationScope::VK_SYSTEM_ALLOCATION_SCOPE_OBJECT;
1140 size_t shader_bindings_size = shader_count * sizeof(VulkanShaderBinding);
1141 VulkanShaderBinding *shader_bindings = (VulkanShaderBinding *)vk_host_malloc(user_context, shader_bindings_size, 0, alloc_scope, allocator->callbacks());
1142 if (shader_bindings == nullptr) {
1143 error(user_context) << "Vulkan: Failed to allocate shader_bindings! Out of memory!\n";
1144 return nullptr;
1145 }
1146 memset(shader_bindings, 0, shader_bindings_size);
1147
1148 // decode and fill in the shader binding for each entry point
1149 for (uint32_t n = 0; (n < shader_count) && (idx < module_entries); n++) {
1150 halide_debug_assert(user_context, (idx + 8) < module_entries); // should be at least 8 entries
1151
1152 // [0] Length of entry point name (padded to nearest word size)
1153 uint32_t entry_point_name_length = module_ptr[idx++];
1154
1155 // [*] Entry point string data (padded with null chars)
1156 const char *entry_point_name = (const char *)(module_ptr + idx); // NOTE: module owns string data
1157 idx += entry_point_name_length; // skip past string data
1158
1159 // [1] Number of uniform buffers for this descriptor set
1160 uint32_t uniform_buffer_count = module_ptr[idx++];
1161
1162 // [2] Number of storage buffers for this descriptor set
1163 uint32_t storage_buffer_count = module_ptr[idx++];
1164
1165 // [3] Number of specialization constants for this descriptor set
1166 uint32_t specialization_constants_count = module_ptr[idx++];
1167
1168 // Decode all specialization constants
1169 VulkanSpecializationConstant *specialization_constants = nullptr;
1170 if (specialization_constants_count > 0) {
1171
1172 // Allocate an array to store the decoded specialization constant data
1173 size_t specialization_constants_size = specialization_constants_count * sizeof(VulkanSpecializationConstant);
1174 specialization_constants = (VulkanSpecializationConstant *)vk_host_malloc(user_context, specialization_constants_size, 0, alloc_scope, allocator->callbacks());
1175 if (specialization_constants == nullptr) {
1176 error(user_context) << "Vulkan: Failed to allocate specialization_constants! Out of memory!\n";
1177 return nullptr;
1178 }
1179 memset(specialization_constants, 0, specialization_constants_size);
1180
1181 // For each specialization constant ...
1182 for (uint32_t sc = 0; sc < specialization_constants_count; sc++) {
1183 halide_debug_assert(user_context, (idx + 4) < module_entries); // should be at least 4 entries
1184
1185 // [0] Length of constant name string (padded to nearest word size)
1186 uint32_t constant_name_length = module_ptr[idx++];
1187
1188 // [*] Constant name string data (padded with null chars)
1189 const char *constant_name = (const char *)(module_ptr + idx);
1190 specialization_constants[sc].constant_name = constant_name; // NOTE: module owns string data
1191 idx += constant_name_length; // skip past string data
1192
1193 // [1] Constant id (as used in VkSpecializationMapEntry for binding)
1194 specialization_constants[sc].constant_id = module_ptr[idx++];
1195
1196 // [2] Size of data type (in bytes)
1197 specialization_constants[sc].type_size = module_ptr[idx++];
1198 }
1199 }
1200
1201 // [4] Number of shared memory allocations for this descriptor set
1202 uint32_t shared_memory_allocations_count = module_ptr[idx++]; // [3]
1203
1204 // Decode all shared memory allocations ...
1205 VulkanSharedMemoryAllocation *shared_memory_allocations = nullptr;
1206 if (shared_memory_allocations_count > 0) {
1207
1208 // Allocate an array to store the decoded shared memory allocation data
1209 size_t shared_memory_allocations_size = shared_memory_allocations_count * sizeof(VulkanSharedMemoryAllocation);
1210 shared_memory_allocations = (VulkanSharedMemoryAllocation *)vk_host_malloc(user_context, shared_memory_allocations_size, 0, alloc_scope, allocator->callbacks());
1211 if (shared_memory_allocations == nullptr) {
1212 error(user_context) << "Vulkan: Failed to allocate shared_memory_allocations! Out of memory!\n";
1213 return nullptr;
1214 }
1215 memset(shared_memory_allocations, 0, shared_memory_allocations_size);
1216
1217 // For each shared memory allocation ...
1218 for (uint32_t sm = 0; sm < shared_memory_allocations_count && (idx < module_entries); sm++) {
1219 halide_debug_assert(user_context, (idx + 4) < module_entries); // should be at least 4 entries
1220
1221 // [0] Length of variable name string (padded to nearest word size)
1222 uint32_t variable_name_length = module_ptr[idx++];
1223
1224 // [*] Variable name string data (padded with null chars)
1225 const char *variable_name = (const char *)(module_ptr + idx);
1226 shared_memory_allocations[sm].variable_name = variable_name; // NOTE: module owns string data
1227 idx += variable_name_length; // skip past string data
1228
1229 // [1] Constant id to use for overriding array size
1230 shared_memory_allocations[sm].constant_id = module_ptr[idx++];
1231
1232 // [2] Size of data type (in bytes)
1233 shared_memory_allocations[sm].type_size = module_ptr[idx++];
1234
1235 // [3] Size of array (ie element count)
1236 shared_memory_allocations[sm].array_size = module_ptr[idx++];
1237 }
1238 }
1239
1240 // [4] Dynamic workgroup dimensions bound to specialization constants
1241 halide_debug_assert(user_context, (idx + 3) < module_entries); // should be at least 3 entries
1242 for (uint32_t dim = 0; dim < 3 && (idx < module_entries); dim++) {
1243 shader_bindings[n].dispatch_data.local_size_binding.constant_id[dim] = module_ptr[idx++];
1244 }
1245
1246#ifdef DEBUG_RUNTIME
1247
1248 debug(user_context) << " [" << n << "] '" << (const char *)entry_point_name << "'\n";
1249
1250 debug(user_context) << " uniform_buffer_count=" << uniform_buffer_count << "\n"
1251 << " storage_buffer_count=" << storage_buffer_count << "\n";
1252
1253 debug(user_context) << " specialization_constants_count=" << specialization_constants_count << "\n";
1254 for (uint32_t sc = 0; sc < specialization_constants_count; sc++) {
1255 debug(user_context) << " [" << sc << "] "
1256 << "constant_name='" << (const char *)specialization_constants[sc].constant_name << "' "
1257 << "constant_id=" << specialization_constants[sc].constant_id << " "
1258 << "type_size=" << specialization_constants[sc].type_size << "\n";
1259 }
1260
1261 debug(user_context) << " shared_memory_allocations_count=" << shared_memory_allocations_count << "\n";
1262 for (uint32_t sm = 0; sm < shared_memory_allocations_count; sm++) {
1263 debug(user_context) << " [" << sm << "] "
1264 << "variable_name='" << (const char *)shared_memory_allocations[sm].variable_name << "' "
1265 << "constant_id=" << shared_memory_allocations[sm].constant_id << " "
1266 << "type_size=" << shared_memory_allocations[sm].type_size << " "
1267 << "array_size=" << shared_memory_allocations[sm].array_size << "\n";
1268 }
1269 debug(user_context) << " local_size_binding=[";
1270 for (uint32_t dim = 0; dim < 3 && (idx < module_entries); dim++) {
1271 debug(user_context) << shader_bindings[n].dispatch_data.local_size_binding.constant_id[dim] << " ";
1272 }
1273 debug(user_context) << "]\n";
1274#endif
1275 shader_bindings[n].entry_point_name = entry_point_name; // NOTE: module owns string data
1276 shader_bindings[n].uniform_buffer_count = uniform_buffer_count;
1277 shader_bindings[n].storage_buffer_count = storage_buffer_count;
1278 shader_bindings[n].specialization_constants_count = specialization_constants_count;
1279 shader_bindings[n].specialization_constants = specialization_constants;
1280 shader_bindings[n].shared_memory_allocations_count = shared_memory_allocations_count;
1281 shader_bindings[n].shared_memory_allocations = shared_memory_allocations;
1282 }
1283
1284#ifdef DEBUG_RUNTIME
1285 uint64_t t_after = halide_current_time_ns(user_context);
1286 debug(user_context) << " Time: " << (t_after - t_before) / 1.0e6 << " ms\n";
1287#endif
1288
1289 return shader_bindings;
1290}
1291
1292int vk_validate_shader_for_device(void *user_context, VulkanMemoryAllocator *allocator,
1293 const VulkanShaderBinding *shader_bindings, uint32_t shader_count) {
1294#ifdef DEBUG_RUNTIME
1295 debug(user_context)
1296 << " vk_validate_shader_for_device (user_context: " << user_context << ", "
1297 << "allocator: " << (void *)allocator << ", "
1298 << "shader_bindings: " << (void *)shader_bindings << ", "
1299 << "shader_count: " << shader_count << ")\n";
1300#endif
1301
1302 // validate that the shared memory used is less than the available amount on device
1303 if (shader_bindings->shared_memory_allocations_count) {
1304
1305 uint32_t static_shared_mem_bytes = 0;
1306
1307 for (uint32_t sm = 0; sm < shader_bindings->shared_memory_allocations_count; sm++) {
1308 VulkanSharedMemoryAllocation *allocation = &(shader_bindings->shared_memory_allocations[sm]);
1309 if (allocation->constant_id == 0) {
1310 // static fixed-size allocation
1311 static_shared_mem_bytes += allocation->type_size * allocation->array_size;
1312 } else {
1313 // dynamic allocation (can't determine this until runtime)
1314 }
1315 }
1316
1317 // verify the device can actually support the necessary amount of shared memory requested
1319 uint64_t device_shared_mem_size = allocator->current_physical_device_limits().maxComputeSharedMemorySize;
1320 if (static_shared_mem_bytes > device_shared_mem_size) {
1321 error(user_context) << "Vulkan: Amount of static shared memory used exceeds device limit!\n"
1322 << " requested: " << static_shared_mem_bytes << " bytes,"
1323 << " available: " << device_shared_mem_size << " bytes\n";
1325 }
1326 }
1327 }
1328
1329 // validate the number of descriptor sets used is within the amount supported by the device
1332 if (shader_count > max_descriptors) {
1333 error(user_context) << "Vulkan: Number of required descriptor sets exceeds the amount available for device!\n"
1334 << " requested: " << shader_count << ","
1335 << " available: " << max_descriptors << "\n";
1337 }
1338 }
1340}
1341
1342VulkanCompilationCacheEntry *vk_compile_shader_module(void *user_context, VulkanMemoryAllocator *allocator,
1343 const char *ptr, int size) {
1344#ifdef DEBUG_RUNTIME
1345 debug(user_context)
1346 << " vk_compile_shader_module (user_context: " << user_context << ", "
1347 << "allocator: " << (void *)allocator << ", "
1348 << "device: " << (void *)allocator->current_device() << ", "
1349 << "module: " << (void *)ptr << ", "
1350 << "size: " << size << ")\n";
1351
1352 uint64_t t_before = halide_current_time_ns(user_context);
1353#endif
1354
1355 if (allocator == nullptr) {
1356 error(user_context) << "Vulkan: Failed to compile shader modules ... invalid allocator pointer!\n";
1357 return nullptr;
1358 }
1359
1360 if ((ptr == nullptr) || (size <= 0)) {
1361 error(user_context) << "Vulkan: Failed to compile shader modules ... invalid program source buffer!\n";
1362 return nullptr;
1363 }
1364
1365 const uint32_t *module_ptr = (const uint32_t *)ptr;
1366 const uint32_t module_size = (const uint32_t)size;
1367
1368 halide_debug_assert(user_context, module_ptr != nullptr);
1369 halide_debug_assert(user_context, module_size >= (2 * sizeof(uint32_t)));
1370
1371 uint32_t header_word_count = module_ptr[0];
1372 uint32_t shader_count = module_ptr[1];
1373 uint32_t header_size = header_word_count * sizeof(uint32_t);
1374
1375 // skip past the preamble header to the start of the SPIR-V binary
1376 const uint32_t *binary_ptr = (module_ptr + header_word_count);
1377 size_t binary_size = (size - header_size);
1378
1379#ifdef DEBUG_RUNTIME
1380 debug(user_context) << "Vulkan: Decoding module ("
1381 << "module_ptr: " << (void *)module_ptr << ", "
1382 << "header_word_count: " << header_word_count << ", "
1383 << "header_size: " << header_size << ", "
1384 << "binar_ptr: " << (void *)binary_ptr << ", "
1385 << "binary_size: " << (uint32_t)binary_size << ")\n";
1386#endif
1387
1388 VkShaderModuleCreateInfo shader_info = {
1390 nullptr, // pointer to structure extending this
1391 0, // flags (curently unused)
1392 (size_t)binary_size, // code size in bytes
1393 (const uint32_t *)binary_ptr // source
1394 };
1395
1396 VkSystemAllocationScope alloc_scope = VkSystemAllocationScope::VK_SYSTEM_ALLOCATION_SCOPE_OBJECT;
1397 VulkanCompilationCacheEntry *cache_entry = (VulkanCompilationCacheEntry *)vk_host_malloc(user_context, sizeof(VulkanCompilationCacheEntry), 0, alloc_scope, allocator->callbacks());
1398 if (cache_entry == nullptr) {
1399 error(user_context) << "Vulkan: Failed to allocate compilation cache entry! Out of memory!\n";
1400 return nullptr;
1401 }
1402 memset(cache_entry, 0, sizeof(VulkanCompilationCacheEntry));
1403
1404 // decode the entry point data and extract the shader bindings
1405 VulkanShaderBinding *decoded_bindings = vk_decode_shader_bindings(user_context, allocator, module_ptr, module_size);
1406 if (decoded_bindings == nullptr) {
1407 error(user_context) << "Vulkan: Failed to decode shader bindings!\n";
1408 return nullptr;
1409 }
1410
1411 // validate that the compiled shader can be executed by the device with the requested resources
1412 int valid_status = vk_validate_shader_for_device(user_context, allocator, decoded_bindings, shader_count);
1413 if (valid_status != halide_error_code_success) {
1414 vk_host_free(user_context, cache_entry->shader_bindings, allocator->callbacks());
1415 vk_host_free(user_context, cache_entry, allocator->callbacks());
1416 return nullptr;
1417 }
1418
1419 // save the shader bindings in the cache entry
1420 cache_entry->shader_bindings = decoded_bindings;
1421 cache_entry->shader_count = shader_count;
1422
1423 VkResult result = vkCreateShaderModule(allocator->current_device(), &shader_info, allocator->callbacks(), &cache_entry->shader_module);
1424 if ((result != VK_SUCCESS)) {
1425 error(user_context) << "Vulkan: vkCreateShaderModule Failed! Error returned: " << vk_get_error_name(result) << "\n";
1426 vk_host_free(user_context, cache_entry->shader_bindings, allocator->callbacks());
1427 vk_host_free(user_context, cache_entry, allocator->callbacks());
1428 return nullptr;
1429 }
1430
1431 // allocate an array for storing the descriptor set layouts
1432 if (cache_entry->shader_count) {
1433 cache_entry->descriptor_set_layouts = (VkDescriptorSetLayout *)vk_host_malloc(user_context, cache_entry->shader_count * sizeof(VkDescriptorSetLayout), 0, alloc_scope, allocator->callbacks());
1434 if (cache_entry->descriptor_set_layouts == nullptr) {
1435 error(user_context) << "Vulkan: Failed to allocate descriptor set layouts for cache entry! Out of memory!\n";
1436 return nullptr;
1437 }
1438 memset(cache_entry->descriptor_set_layouts, 0, cache_entry->shader_count * sizeof(VkDescriptorSetLayout));
1439 }
1440
1441#ifdef DEBUG_RUNTIME
1442 uint64_t t_after = halide_current_time_ns(user_context);
1443 debug(user_context) << " Time: " << (t_after - t_before) / 1.0e6 << " ms\n";
1444#endif
1445
1446 return cache_entry;
1447}
1448
1449int vk_destroy_shader_modules(void *user_context, VulkanMemoryAllocator *allocator) {
1450
1451#ifdef DEBUG_RUNTIME
1452 debug(user_context)
1453 << " vk_destroy_shader_modules (user_context: " << user_context << ", "
1454 << "allocator: " << (void *)allocator << ", "
1455 << "device: " << (void *)allocator->current_device() << ")\n";
1456
1457 uint64_t t_before = halide_current_time_ns(user_context);
1458#endif
1459
1460 if (allocator == nullptr) {
1461 error(user_context) << "Vulkan: Failed to destroy shader modules ... invalid allocator pointer!\n";
1463 }
1464
1465 // Functor to match compilation cache destruction call with scoped params
1466 struct DestroyShaderModule {
1467 void *user_context = nullptr;
1468 VulkanMemoryAllocator *allocator = nullptr;
1469
1470 DestroyShaderModule(void *ctx, VulkanMemoryAllocator *allocator)
1471 : user_context(ctx), allocator(allocator) {
1472 }
1473
1474 void operator()(VulkanCompilationCacheEntry *cache_entry) {
1475 if (cache_entry != nullptr) {
1476 if (cache_entry->descriptor_set_layouts) {
1477 for (uint32_t n = 0; n < cache_entry->shader_count; n++) {
1478 debug(user_context) << " destroying descriptor set layout [" << n << "] " << cache_entry->shader_bindings[n].entry_point_name << "\n";
1479 vk_destroy_descriptor_set_layout(user_context, allocator, cache_entry->descriptor_set_layouts[n]);
1480 cache_entry->descriptor_set_layouts[n] = {0};
1481 }
1482 vk_host_free(user_context, cache_entry->descriptor_set_layouts, allocator->callbacks());
1483 cache_entry->descriptor_set_layouts = nullptr;
1484 }
1485 if (cache_entry->pipeline_layout) {
1486 debug(user_context) << " destroying pipeline layout " << (void *)cache_entry->pipeline_layout << "\n";
1487 vk_destroy_pipeline_layout(user_context, allocator, cache_entry->pipeline_layout);
1488 cache_entry->pipeline_layout = {0};
1489 }
1490 if (cache_entry->shader_bindings) {
1491 for (uint32_t n = 0; n < cache_entry->shader_count; n++) {
1492 if (cache_entry->shader_bindings[n].args_region) {
1493 vk_destroy_scalar_uniform_buffer(user_context, allocator, cache_entry->shader_bindings[n].args_region);
1494 cache_entry->shader_bindings[n].args_region = nullptr;
1495 }
1496 if (cache_entry->shader_bindings[n].descriptor_pool) {
1497 vk_destroy_descriptor_pool(user_context, allocator, cache_entry->shader_bindings[n].descriptor_pool);
1498 cache_entry->shader_bindings[n].descriptor_pool = {0};
1499 }
1500 if (cache_entry->shader_bindings[n].specialization_constants) {
1501 vk_host_free(user_context, cache_entry->shader_bindings[n].specialization_constants, allocator->callbacks());
1502 cache_entry->shader_bindings[n].specialization_constants = nullptr;
1503 }
1504 if (cache_entry->shader_bindings[n].shared_memory_allocations) {
1505 vk_host_free(user_context, cache_entry->shader_bindings[n].shared_memory_allocations, allocator->callbacks());
1506 cache_entry->shader_bindings[n].shared_memory_allocations = nullptr;
1507 }
1508 if (cache_entry->shader_bindings[n].compute_pipeline) {
1509 vk_destroy_compute_pipeline(user_context, allocator, cache_entry->shader_bindings[n].compute_pipeline);
1510 cache_entry->shader_bindings[n].compute_pipeline = {0};
1511 }
1512 }
1513
1514 vk_host_free(user_context, cache_entry->shader_bindings, allocator->callbacks());
1515 cache_entry->shader_bindings = nullptr;
1516 }
1517 if (cache_entry->shader_module) {
1518 debug(user_context) << " . destroying shader module " << (void *)cache_entry->shader_module << "\n";
1519 vkDestroyShaderModule(allocator->current_device(), cache_entry->shader_module, allocator->callbacks());
1520 cache_entry->shader_module = {0};
1521 }
1522 cache_entry->shader_count = 0;
1523 vk_host_free(user_context, cache_entry, allocator->callbacks());
1524 cache_entry = nullptr;
1525 }
1526 }
1527 };
1528
1529 DestroyShaderModule module_destructor(user_context, allocator);
1530 compilation_cache.delete_context(user_context, allocator->current_device(), module_destructor);
1531
1532#ifdef DEBUG_RUNTIME
1533 uint64_t t_after = halide_current_time_ns(user_context);
1534 debug(user_context) << " Time: " << (t_after - t_before) / 1.0e6 << " ms\n";
1535#endif
1537}
1538
1539// --------------------------------------------------------------------------
1540
1541int vk_do_multidimensional_copy(void *user_context, VkCommandBuffer command_buffer,
1542 const device_copy &c, uint64_t src_offset, uint64_t dst_offset,
1543 int d, bool from_host, bool to_host) {
1544 if (d == 0) {
1545
1546 if ((!from_host && to_host) ||
1547 (from_host && !to_host) ||
1548 (!from_host && !to_host)) {
1549
1550 VkBufferCopy buffer_copy = {
1551 c.src_begin + src_offset, // srcOffset
1552 dst_offset, // dstOffset
1553 c.chunk_size // size
1554 };
1555
1556 VkBuffer *src_buffer = reinterpret_cast<VkBuffer *>(c.src);
1557 VkBuffer *dst_buffer = reinterpret_cast<VkBuffer *>(c.dst);
1558 if (!src_buffer || !dst_buffer) {
1559 error(user_context) << "Vulkan: Failed to retrieve buffer for device memory!\n";
1561 }
1562
1563 vkCmdCopyBuffer(command_buffer, *src_buffer, *dst_buffer, 1, &buffer_copy);
1564
1565 } else if ((c.dst + dst_offset) != (c.src + src_offset)) {
1566 // Could reach here if a user called directly into the
1567 // Vulkan API for a device->host copy on a source buffer
1568 // with device_dirty = false.
1569 memcpy((void *)(c.dst + dst_offset), (void *)(c.src + src_offset), c.chunk_size);
1570 }
1571 } else {
1572 // TODO: deal with negative strides. Currently the code in
1573 // device_buffer_utils.h does not do so either.
1574 uint64_t src_off = 0, dst_off = 0;
1575 for (uint64_t i = 0; i < c.extent[d - 1]; i++) {
1576 int err = vk_do_multidimensional_copy(user_context, command_buffer, c,
1577 src_offset + src_off,
1578 dst_offset + dst_off,
1579 d - 1, from_host, to_host);
1580 dst_off += c.dst_stride_bytes[d - 1];
1581 src_off += c.src_stride_bytes[d - 1];
1582 if (err) {
1583 return err;
1584 }
1585 }
1586 }
1588}
1589
1590int vk_device_crop_from_offset(void *user_context,
1591 const struct halide_buffer_t *src,
1592 int64_t offset,
1593 struct halide_buffer_t *dst) {
1594
1595 VulkanContext ctx(user_context);
1596 if (ctx.error != halide_error_code_success) {
1597 error(user_context) << "Vulkan: Failed to acquire context!\n";
1598 return ctx.error;
1599 }
1600
1601#ifdef DEBUG_RUNTIME
1602 uint64_t t_before = halide_current_time_ns(user_context);
1603#endif
1604
1605 if (offset < 0) {
1606 error(user_context) << "Vulkan: Invalid offset for device crop!\n";
1608 }
1609
1610 // get the allocated region for the device
1611 MemoryRegion *device_region = reinterpret_cast<MemoryRegion *>(src->device);
1612 if (device_region == nullptr) {
1613 error(user_context) << "Vulkan: Failed to crop region! Invalide device region!\n";
1615 }
1616
1617 // create the croppeg region from the allocated region
1618 MemoryRegion *cropped_region = ctx.allocator->create_crop(user_context, device_region, (uint64_t)offset);
1619 if ((cropped_region == nullptr) || (cropped_region->handle == nullptr)) {
1620 error(user_context) << "Vulkan: Failed to crop region! Unable to create memory region!\n";
1622 }
1623
1624 // update the destination to the cropped region
1625 dst->device = (uint64_t)cropped_region;
1627
1628#ifdef DEBUG_RUNTIME
1629 uint64_t t_after = halide_current_time_ns(user_context);
1630 debug(user_context) << " Time: " << (t_after - t_before) / 1.0e6 << " ms\n";
1631#endif
1632
1634}
1635
1636// --------------------------------------------------------------------------
1637
1638} // namespace
1639} // namespace Vulkan
1640} // namespace Internal
1641} // namespace Runtime
1642} // namespace Halide
1643
1644#endif // HALIDE_RUNTIME_VULKAN_RESOURCES_H
bool halide_can_reuse_device_allocations(void *user_context)
Determines whether on device_free the memory is returned immediately to the device API,...
@ halide_error_code_incompatible_device_interface
An operation on a buffer required an allocation on a particular device interface, but a device alloca...
@ 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_device_crop_failed
Cropping/slicing a buffer failed for some other reason.
@ halide_error_code_success
There was no error.
void append(void *user_context, const void *entry_ptr)
Vulkan Memory Allocator class interface for managing large memory requests stored as contiguous block...
int reclaim(void *user_context, MemoryRegion *region)
MemoryRegion * reserve(void *user_context, const MemoryRequest &request)
int release(void *user_context, MemoryRegion *region)
int unmap(void *user_context, MemoryRegion *region)
MemoryRegion * create_crop(void *user_context, MemoryRegion *region, uint64_t offset)
MemoryRegion * owner_of(void *user_context, MemoryRegion *region)
VkPhysicalDeviceLimits current_physical_device_limits() const
const VkAllocationCallbacks * callbacks() const
void * map(void *user_context, MemoryRegion *region)
VKAPI_ATTR void VKAPI_CALL vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ)
@ VK_COMMAND_BUFFER_LEVEL_PRIMARY
VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator)
@ VK_SHADER_STAGE_COMPUTE_BIT
VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers)
VkSystemAllocationScope
VKAPI_ATTR void VKAPI_CALL vkCmdBindPipeline(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline)
struct VkDescriptorSetLayoutBinding VkDescriptorSetLayoutBinding
VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool)
VKAPI_ATTR VkResult VKAPI_CALL vkAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets)
uint64_t VkDeviceSize
Definition mini_vulkan.h:71
VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout)
@ VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
@ VK_PIPELINE_BIND_POINT_COMPUTE
VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy *pRegions)
VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags)
VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator)
@ VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT
VKAPI_ATTR VkResult VKAPI_CALL vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCommandPool *pCommandPool)
VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator)
VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines)
VKAPI_ATTR VkResult VKAPI_CALL vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence)
VKAPI_ATTR void VKAPI_CALL vkCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets, uint32_t dynamicOffsetCount, const uint32_t *pDynamicOffsets)
#define VK_WHOLE_SIZE
VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, VkCommandBuffer *pCommandBuffers)
VkResult
@ VK_SUCCESS
@ VK_ERROR_INITIALIZATION_FAILED
@ VK_ERROR_TOO_MANY_OBJECTS
@ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
@ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
struct VkDescriptorPoolSize VkDescriptorPoolSize
VKAPI_ATTR void VKAPI_CALL vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator)
VKAPI_ATTR VkResult VKAPI_CALL vkCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule)
struct VkDescriptorBufferInfo VkDescriptorBufferInfo
VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies)
@ VK_COMMAND_POOL_CREATE_TRANSIENT_BIT
VKAPI_ATTR VkResult VKAPI_CALL vkEndCommandBuffer(VkCommandBuffer commandBuffer)
struct VkWriteDescriptorSet VkWriteDescriptorSet
VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator)
VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator)
VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout)
@ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO
@ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO
@ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO
@ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO
@ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET
@ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
@ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO
@ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO
@ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO
@ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO
@ VK_STRUCTURE_TYPE_SUBMIT_INFO
@ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO
VKAPI_ATTR VkResult VKAPI_CALL vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo)
WEAK Halide::Internal::GPUCompilationCache< VkDevice, VulkanCompilationCacheEntry * > compilation_cache
This file defines the class FunctionDAG, which is our representation of a Halide pipeline,...
@ Internal
Not visible externally, similar to 'static' linkage in C.
unsigned __INT64_TYPE__ uint64_t
signed __INT64_TYPE__ int64_t
#define halide_debug_assert(user_context, cond)
halide_debug_assert() is like halide_assert(), but only expands into a check when DEBUG_RUNTIME is de...
unsigned __INT8_TYPE__ uint8_t
void * memcpy(void *s1, const void *s2, size_t n)
__SIZE_TYPE__ size_t
void * memset(void *s, int val, size_t n)
unsigned __INT32_TYPE__ uint32_t
#define halide_abort_if_false(user_context, cond)
WEAK int64_t halide_current_time_ns(void *user_context)
signed __INT8_TYPE__ int8_t
#define WEAK
VkDescriptorSetLayout * descriptor_set_layouts
uint32_t shader_count
VulkanShaderBinding * shader_bindings
VkPipelineLayout pipeline_layout
VkShaderModule shader_module
uint32_t maxPerStageDescriptorStorageBuffers
uint32_t maxComputeSharedMemorySize
const VkSpecializationMapEntry * pMapEntries
uint32_t offset
size_t size
uint32_t constantID
The raw representation of an image passed around by generated Halide code.
uint64_t device
A device-handle for e.g.
const struct halide_device_interface_t * device_interface
The interface used to interpret the above handle.