Halide  19.0.0
Halide compiler and libraries
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 
9 namespace Halide {
10 namespace Runtime {
11 namespace Internal {
12 namespace 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
21  uint32_t global_size[3] = {0}; // aka blocks
22  uint32_t local_size[3] = {0}; // aka threads
25 };
26 
27 // Specialization constant binding information
31  const char *constant_name = nullptr;
32 };
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
44  const char *entry_point_name = nullptr;
46  VkDescriptorPool descriptor_pool = {0};
47  VkDescriptorSet descriptor_set = {0};
48  VkPipeline compute_pipeline = {0};
57 };
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 
72 namespace { // internalize
73 
74 // --------------------------------------------------------------------------
75 
76 int 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 
105 int 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 
127 int 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 
156 int 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 
173 int 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 
220 int 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 
251 bool 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 
265 uint32_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 
285 int 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 
341 int 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 
360 int 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 
440 int 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 
460 int 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 
495 int 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 
617 size_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 
632 MemoryRegion *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 
665 int 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 
709 int 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 
738 int 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 
785 int 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 
807 int 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 
856 int 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";
917  result = VK_ERROR_TOO_MANY_OBJECTS;
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 
1048 int 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 
1069 VulkanShaderBinding *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)
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 
1292 int 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 
1342 VulkanCompilationCacheEntry *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 
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 
1449 int 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 
1541 int 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 
1590 int 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;
1626  dst->device_interface = src->device_interface;
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...
Definition: vulkan_memory.h:42
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)
const VkAllocationCallbacks * callbacks() const
Definition: vulkan_memory.h:85
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
Definition: vulkan_memory.h:82
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
Definition: mini_vulkan.h:975
VKAPI_ATTR void VKAPI_CALL vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator)
@ VK_SHADER_STAGE_COMPUTE_BIT
Definition: mini_vulkan.h:1261
VKAPI_ATTR void VKAPI_CALL vkFreeCommandBuffers(VkDevice device, VkCommandPool commandPool, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers)
VkSystemAllocationScope
Definition: mini_vulkan.h:365
@ VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
Definition: mini_vulkan.h:367
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
Definition: mini_vulkan.h:1372
@ VK_PIPELINE_BIND_POINT_COMPUTE
Definition: mini_vulkan.h:967
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
Definition: mini_vulkan.h:1366
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
Definition: mini_vulkan.h:117
VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, VkCommandBuffer *pCommandBuffers)
VkResult
Definition: mini_vulkan.h:138
@ VK_SUCCESS
Definition: mini_vulkan.h:139
@ VK_ERROR_INITIALIZATION_FAILED
Definition: mini_vulkan.h:147
@ VK_ERROR_TOO_MANY_OBJECTS
Definition: mini_vulkan.h:154
@ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
Definition: mini_vulkan.h:935
@ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
Definition: mini_vulkan.h:936
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
Definition: mini_vulkan.h:1359
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
Definition: mini_vulkan.h:202
@ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO
Definition: mini_vulkan.h:203
@ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO
Definition: mini_vulkan.h:205
@ VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO
Definition: mini_vulkan.h:213
@ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET
Definition: mini_vulkan.h:208
@ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
Definition: mini_vulkan.h:215
@ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO
Definition: mini_vulkan.h:207
@ VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO
Definition: mini_vulkan.h:189
@ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO
Definition: mini_vulkan.h:191
@ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO
Definition: mini_vulkan.h:206
@ VK_STRUCTURE_TYPE_SUBMIT_INFO
Definition: mini_vulkan.h:177
@ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO
Definition: mini_vulkan.h:212
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 * memset(void *s, int val, size_t n)
__SIZE_TYPE__ size_t
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
void * memcpy(void *s1, const void *s2, size_t n)
VkDescriptorSetLayout * descriptor_set_layouts
uint32_t shader_count
VulkanShaderBinding * shader_bindings
VkPipelineLayout pipeline_layout
VkShaderModule shader_module
VulkanSharedMemoryAllocation * shared_memory_allocations
uint32_t maxPerStageDescriptorStorageBuffers
Definition: mini_vulkan.h:1553
uint32_t maxBoundDescriptorSets
Definition: mini_vulkan.h:1550
uint32_t maxComputeSharedMemorySize
Definition: mini_vulkan.h:1588
const VkSpecializationMapEntry * pMapEntries
Definition: mini_vulkan.h:1957
const void * pData
Definition: mini_vulkan.h:1959
Definition: mini_vulkan.h:1949
uint32_t offset
Definition: mini_vulkan.h:1951
size_t size
Definition: mini_vulkan.h:1952
uint32_t constantID
Definition: mini_vulkan.h:1950
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.