Skip to content

Commit

Permalink
Added allocateCommandBuffers<N> function, which allocate the command …
Browse files Browse the repository at this point in the history
…buffers of compile time count to avoid std::vector<vk::CommandBuffer> heap allocation.
  • Loading branch information
stripe2933 committed Sep 18, 2024
1 parent 0559656 commit 5251260
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 20 deletions.
2 changes: 2 additions & 0 deletions docs/hello-triangle.md
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,8 @@ int main() {

Command buffer allocation and submission code is gone. `vku::executeSingleCommand` automatically allocates a command buffer from the given command pool, begins before/ends after the given command buffer recording function execution, and submits the command buffer into the given queue.

For optimization, since it knows only a single command buffer have to be allocated (allocation count is known at the compile time), it uses `vku::allocateCommandBuffers<N>` to avoid the heap allocation.

You can optionally pass the `vk::Fence` handle to the last parameter. With fence, it signaled when the submitted command buffer execution finished. Otherwise, *vku* does not handle any synchronization, therefore we should wait for the graphics queue to be idle manually.

### 5.1. Check Your First Triangle with Debuggers
Expand Down
38 changes: 28 additions & 10 deletions interface/commands.cppm
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,32 @@ struct std::hash<VULKAN_HPP_NAMESPACE::Semaphore> {
#endif

namespace vku {
/**
* Allocate command buffers from \p commandPool without heap allocation.
* @tparam N Number of command buffers to allocate.
* @param device Vulkan device. Must be same device from \p commandPool.
* @param commandPool Command pool to allocate command buffers.
* @param level Command buffer level (default: primary).
* @return Array of \p N command buffers.
* @throw vk::Result if failed to allocate command buffers.
*/
export template <std::size_t N>
[[nodiscard]] auto allocateCommandBuffers(
VULKAN_HPP_NAMESPACE::Device device,
VULKAN_HPP_NAMESPACE::CommandPool commandPool,
VULKAN_HPP_NAMESPACE::CommandBufferLevel level = {}
) -> std::array<VULKAN_HPP_NAMESPACE::CommandBuffer, N> {
std::array<VULKAN_HPP_NAMESPACE::CommandBuffer, N> commandBuffers;
const VULKAN_HPP_NAMESPACE::Result result = device.allocateCommandBuffers(
vku::unsafeAddress(VULKAN_HPP_NAMESPACE::CommandBufferAllocateInfo { commandPool, level, N }),
commandBuffers.data());

if (result != VULKAN_HPP_NAMESPACE::Result::eSuccess) {
throw result;
}
return commandBuffers;
}

export template <std::invocable<VULKAN_HPP_NAMESPACE::CommandBuffer> F>
struct ExecutionInfo {
F commandRecorder;
Expand All @@ -75,11 +101,7 @@ namespace vku {
) -> void
requires std::is_void_v<std::invoke_result_t<F, VULKAN_HPP_NAMESPACE::CommandBuffer>>
{
const VULKAN_HPP_NAMESPACE::CommandBuffer commandBuffer = device.allocateCommandBuffers(VULKAN_HPP_NAMESPACE::CommandBufferAllocateInfo {
commandPool,
VULKAN_HPP_NAMESPACE::CommandBufferLevel::ePrimary,
1,
})[0];
const VULKAN_HPP_NAMESPACE::CommandBuffer commandBuffer = allocateCommandBuffers<1>(device, commandPool)[0];
commandBuffer.begin({ VULKAN_HPP_NAMESPACE::CommandBufferUsageFlagBits::eOneTimeSubmit });
std::invoke(FWD(f), commandBuffer);
commandBuffer.end();
Expand All @@ -98,11 +120,7 @@ namespace vku {
F &&f,
VULKAN_HPP_NAMESPACE::Fence fence = {}
) -> std::invoke_result_t<F, VULKAN_HPP_NAMESPACE::CommandBuffer> {
const VULKAN_HPP_NAMESPACE::CommandBuffer commandBuffer = device.allocateCommandBuffers(VULKAN_HPP_NAMESPACE::CommandBufferAllocateInfo {
commandPool,
VULKAN_HPP_NAMESPACE::CommandBufferLevel::ePrimary,
1,
})[0];
const VULKAN_HPP_NAMESPACE::CommandBuffer commandBuffer = allocateCommandBuffers<1>(device, commandPool)[0];
commandBuffer.begin({ VULKAN_HPP_NAMESPACE::CommandBufferUsageFlagBits::eOneTimeSubmit });
auto result = std::invoke(FWD(f), commandBuffer);
commandBuffer.end();
Expand Down
6 changes: 1 addition & 5 deletions test/swapchain-msaa-triangle/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,7 @@ int main(){
vk::CommandPoolCreateFlagBits::eResetCommandBuffer,
gpu.queueFamilies.graphicsPresent
} };
const vk::CommandBuffer commandBuffer = (*gpu.device).allocateCommandBuffers(vk::CommandBufferAllocateInfo {
*graphicsCommandPool,
vk::CommandBufferLevel::ePrimary,
1,
})[0];
const vk::CommandBuffer commandBuffer = vku::allocateCommandBuffers<1>(*gpu.device, *graphicsCommandPool)[0];

// Change all swapchain image layouts to PresentSrcKHR to avoid Undefined format for srcImageLayout of future
// pipeline barriers.
Expand Down
6 changes: 1 addition & 5 deletions test/swapchain-triangle/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,7 @@ int main(){
vk::CommandPoolCreateFlagBits::eResetCommandBuffer,
gpu.queueFamilies.graphicsPresent
} };
const vk::CommandBuffer commandBuffer = (*gpu.device).allocateCommandBuffers(vk::CommandBufferAllocateInfo {
*graphicsCommandPool,
vk::CommandBufferLevel::ePrimary,
1,
})[0];
const vk::CommandBuffer commandBuffer = vku::allocateCommandBuffers<1>(*gpu.device, *graphicsCommandPool)[0];

// Change all swapchain image layouts to PresentSrcKHR to avoid Undefined format for srcImageLayout of future
// pipeline barriers.
Expand Down

0 comments on commit 5251260

Please sign in to comment.