| 579 | } |
| 580 | |
| 581 | std::unique_ptr<argument_buffer> vulkan_function::create_argument_buffer_internal(const device_queue& cqueue, |
| 582 | const function_entry& kern_entry, |
| 583 | const toolchain::arg_info& arg floor_unused, |
| 584 | const uint32_t& user_arg_index, |
| 585 | const uint32_t& ll_arg_index, |
| 586 | const MEMORY_FLAG& add_mem_flags, |
| 587 | const bool zero_init) const { |
| 588 | const auto& vk_dev = (const vulkan_device&)cqueue.get_device(); |
| 589 | const auto& vk_ctx = (const vulkan_context&)*vk_dev.context; |
| 590 | const auto& vulkan_entry = (const vulkan_function_entry&)kern_entry; |
| 591 | |
| 592 | // check if info exists |
| 593 | const auto& arg_info = vulkan_entry.info->args[ll_arg_index].argument_buffer_info; |
| 594 | if (!arg_info) { |
| 595 | log_error("no argument buffer info for arg at index #$", user_arg_index); |
| 596 | return {}; |
| 597 | } |
| 598 | |
| 599 | const auto arg_buf_name = vulkan_entry.info->name + ".arg_buffer@" + std::to_string(user_arg_index); |
| 600 | |
| 601 | // argument buffers are implemented as individual descriptor sets inside the parent function/program, stored in descriptor buffers |
| 602 | // -> grab the descriptor set layout from the parent function that has already created this + allocate a descriptor buffer |
| 603 | if (vulkan_entry.argument_buffers.empty()) { |
| 604 | log_error("no argument buffer info in function entry (in $)", vulkan_entry.info->name); |
| 605 | return {}; |
| 606 | } |
| 607 | |
| 608 | // find the argument buffer info index |
| 609 | uint32_t arg_buf_idx = 0; |
| 610 | for (uint32_t i = 0, count = uint32_t(vulkan_entry.info->args.size()); i < std::min(ll_arg_index, count); ++i) { |
| 611 | if (i == ll_arg_index) { |
| 612 | break; |
| 613 | } |
| 614 | if (has_flag<ARG_FLAG::ARGUMENT_BUFFER>(vulkan_entry.info->args[i].flags)) { |
| 615 | ++arg_buf_idx; |
| 616 | } |
| 617 | } |
| 618 | if (arg_buf_idx >= vulkan_entry.argument_buffers.size()) { |
| 619 | log_error("argument buffer info index is out-of-bounds for function entry (arg #$ in $)", |
| 620 | user_arg_index, vulkan_entry.info->name); |
| 621 | return {}; |
| 622 | } |
| 623 | const auto& arg_buf_info = vulkan_entry.argument_buffers[arg_buf_idx]; |
| 624 | |
| 625 | // the argument buffer size is device/driver dependent (can't be statically known) |
| 626 | // -> query required buffer size + ensure good alignment |
| 627 | const auto arg_buffer_size = const_math::round_next_multiple(arg_buf_info.layout.layout_size, uint64_t(256)); |
| 628 | |
| 629 | // query offset for each binding/argument |
| 630 | std::vector<VkDeviceSize> argument_offsets; |
| 631 | argument_offsets.reserve(arg_buf_info.layout.bindings.size()); |
| 632 | for (const auto& binding : arg_buf_info.layout.bindings) { |
| 633 | VkDeviceSize offset = 0; |
| 634 | vkGetDescriptorSetLayoutBindingOffsetEXT(vk_dev.device, arg_buf_info.layout.desc_set_layout, binding.binding, &offset); |
| 635 | argument_offsets.emplace_back(offset); |
| 636 | } |
| 637 | |
| 638 | // alloc with Vulkan flags: need host-visible/host-coherent and descriptor buffer usage flags |
nothing calls this directly
no test coverage detected