From b18f3719ed6cde7336f2c78b220049eabb9205a7 Mon Sep 17 00:00:00 2001 From: Draklaw Date: Fri, 4 Mar 2022 23:03:42 +0100 Subject: [PATCH] CommandPool & CommandBuffer wrappers. --- CMakeLists.txt | 4 ++- src/VulkanTutorial.cpp | 52 ++++++++--------------------- src/VulkanTutorial.h | 14 ++++---- src/vk/CommandBuffer.cpp | 70 +++++++++++++++++++++++++++++++++++++++ src/vk/CommandBuffer.h | 71 ++++++++++++++++++++++++++++++++++++++++ src/vk/CommandPool.cpp | 67 +++++++++++++++++++++++++++++++++++++ src/vk/CommandPool.h | 61 ++++++++++++++++++++++++++++++++++ src/vk/Context.cpp | 40 +++++++--------------- src/vk/Context.h | 3 +- 9 files changed, 307 insertions(+), 75 deletions(-) create mode 100644 src/vk/CommandBuffer.cpp create mode 100644 src/vk/CommandBuffer.h create mode 100644 src/vk/CommandPool.cpp create mode 100644 src/vk/CommandPool.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b7f36f2..ca77826 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,14 +37,16 @@ add_executable(vk_expe src/core/Logger.cpp src/vk/Context.cpp + src/vk/CommandPool.cpp + src/vk/CommandBuffer.cpp src/vk/Fence.cpp src/vk/Semaphore.cpp src/vk/Framebuffer.cpp src/vk/ShaderModule.cpp src/vk/Pipeline.cpp - src/vk/Swapchain.cpp src/vk/Memory.cpp src/vk/Buffer.cpp + src/vk/Swapchain.cpp src/vk/RenderPass.cpp src/main.cpp diff --git a/src/VulkanTutorial.cpp b/src/VulkanTutorial.cpp index a8d6185..223e6ef 100644 --- a/src/VulkanTutorial.cpp +++ b/src/VulkanTutorial.cpp @@ -184,7 +184,7 @@ void VulkanTutorial::shutdown() { destroy_swapchain_objects(); - m_context.destroy_command_pool(m_command_pool); + m_command_pool.destroy(); m_index_buffer.destroy(); m_vertex_buffer.destroy(); m_context.destroy_descriptor_set_layout(m_descriptor_set_layout); @@ -260,13 +260,16 @@ void VulkanTutorial::draw_frame() { VkPipelineStageFlags stages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, }; + VkCommandBuffer command_buffers[] = { + m_command_buffers[image_index], + }; VkSubmitInfo submit_info { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .waitSemaphoreCount = 1, .pWaitSemaphores = wait_semaphores, .pWaitDstStageMask = stages, .commandBufferCount = 1, - .pCommandBuffers = &m_command_buffers[image_index], + .pCommandBuffers = command_buffers, .signalSemaphoreCount = 1, .pSignalSemaphores = done_semaphores, }; @@ -304,12 +307,6 @@ void VulkanTutorial::destroy_swapchain_objects() { if(m_command_pool == VK_NULL_HANDLE) return; - vkFreeCommandBuffers( - m_context.device(), - m_command_pool, - uint32_t(m_command_buffers.size()), - m_command_buffers.data() - ); m_command_buffers.clear(); for(auto& buffer: m_uniform_buffers) @@ -561,22 +558,13 @@ void VulkanTutorial::create_framebuffers() { } void VulkanTutorial::create_command_pool() { - if(m_command_pool != VK_NULL_HANDLE) + if(!m_command_pool.is_null()) return; - VkCommandPoolCreateInfo pool_info { - .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .flags = 0, - .queueFamilyIndex = m_context.queue_family(GRAPHIC_QUEUE), - }; - - if(vkCreateCommandPool( - m_context.device(), - &pool_info, - nullptr, - &m_command_pool - ) != VK_SUCCESS) - throw std::runtime_error("failed to create command pool"); + m_command_pool = vk::CommandPool( + m_context, + m_context.queue_family(GRAPHIC_QUEUE) + ); } void VulkanTutorial::create_vertex_buffer() { @@ -704,23 +692,9 @@ void VulkanTutorial::create_descriptor_sets() { } void VulkanTutorial::create_command_buffers() { - m_command_buffers.resize(m_framebuffers.size()); - - VkCommandBufferAllocateInfo allocate_info { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = m_command_pool, - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = uint32_t(m_command_buffers.size()), - }; - - if(vkAllocateCommandBuffers( - m_context.device(), - &allocate_info, - m_command_buffers.data() - ) != VK_SUCCESS) - throw std::runtime_error("failed to allocate command buffers"); - - for(size_t index = 0; index < m_command_buffers.size(); index += 1) { + m_command_buffers.clear(); + for(size_t index = 0; index < m_framebuffers.size(); index += 1) { + m_command_buffers.emplace_back(m_context, m_command_pool); VkCommandBuffer command_buffer = m_command_buffers[index]; VkCommandBufferBeginInfo begin_info { diff --git a/src/VulkanTutorial.h b/src/VulkanTutorial.h index 8783982..b0bd2bd 100644 --- a/src/VulkanTutorial.h +++ b/src/VulkanTutorial.h @@ -1,12 +1,14 @@ // Copyright 2022 Simon Boyé #pragma once +#include +#include +#include #include -#include #include -#include -#include -#include +#include +#include +#include #include #include @@ -78,7 +80,7 @@ private: VkPipelineLayout m_pipeline_layout = VK_NULL_HANDLE; vk::Pipeline m_pipeline; std::vector m_framebuffers; - VkCommandPool m_command_pool = VK_NULL_HANDLE; + vk::CommandPool m_command_pool; vk::Buffer m_vertex_buffer; vk::Buffer m_index_buffer; std::vector m_uniform_buffers; @@ -86,7 +88,7 @@ private: vk::MemoryBlock m_uniform_buffer_memory; VkDescriptorPool m_descriptor_pool = VK_NULL_HANDLE; std::vector m_descriptor_sets; - std::vector m_command_buffers; + std::vector m_command_buffers; std::vector m_render_done; Vector3 m_camera_position = Vector3(0.0f, 0.0f, -3.0f); diff --git a/src/vk/CommandBuffer.cpp b/src/vk/CommandBuffer.cpp new file mode 100644 index 0000000..76e6325 --- /dev/null +++ b/src/vk/CommandBuffer.cpp @@ -0,0 +1,70 @@ +// Copyright 2022 Simon Boyé + +#include +#include + +#include + + +namespace vk { + + +CommandBuffer::CommandBuffer() noexcept { +} + +CommandBuffer::CommandBuffer(Context& context, VkCommandPool command_pool, VkCommandBufferLevel level) + : m_context(&context) + , m_command_pool(command_pool) +{ + assert(m_context); + assert(m_command_pool != VK_NULL_HANDLE); + + VkCommandBufferAllocateInfo allocate_info { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = m_command_pool, + .level = level, + .commandBufferCount = 1, + }; + if(vkAllocateCommandBuffers( + context.device(), + &allocate_info, + &m_command_buffer + ) != VK_SUCCESS) + throw std::runtime_error("failed to allocate command pool"); +} + +CommandBuffer::CommandBuffer(CommandBuffer&& other) noexcept +{ + swap(*this, other); +} + +CommandBuffer::~CommandBuffer() noexcept { + if(!is_null()) + destroy(); +} + + +CommandBuffer& CommandBuffer::operator=(CommandBuffer&& other) noexcept { + swap(*this, other); + if(other) + other.destroy(); + return *this; +} + + +void CommandBuffer::destroy() noexcept { + assert(!is_null()); + assert(m_context); + + vkFreeCommandBuffers( + m_context->device(), + m_command_pool, + 1, + &m_command_buffer + ); + + m_command_buffer = nullptr; +} + + +} diff --git a/src/vk/CommandBuffer.h b/src/vk/CommandBuffer.h new file mode 100644 index 0000000..678342f --- /dev/null +++ b/src/vk/CommandBuffer.h @@ -0,0 +1,71 @@ +// Copyright 2022 Simon Boyé +#pragma once + +#include + +#include + + +namespace vk { + + +class CommandBuffer { +public: + CommandBuffer() noexcept; + CommandBuffer(Context& context, VkCommandPool command_pool, VkCommandBufferLevel level=VK_COMMAND_BUFFER_LEVEL_PRIMARY); + CommandBuffer(const CommandBuffer&) = delete; + CommandBuffer(CommandBuffer&& other) noexcept; + ~CommandBuffer() noexcept; + + CommandBuffer& operator=(const CommandBuffer&) = delete; + CommandBuffer& operator=(CommandBuffer&& other) noexcept; + + explicit inline operator bool() const noexcept { + return !is_null(); + } + + inline bool is_null() const noexcept { + return m_command_buffer == VK_NULL_HANDLE; + } + + inline const Context* context() const noexcept { + return m_context; + } + + inline Context* context() noexcept { + return m_context; + } + + inline const VkCommandPool command_pool() const noexcept { + return m_command_pool; + } + + inline VkCommandPool command_pool() noexcept { + return m_command_pool; + } + + inline operator VkCommandBuffer() noexcept { + return m_command_buffer; + } + + inline VkCommandBuffer command_buffer() noexcept { + return m_command_buffer; + } + + friend inline void swap(CommandBuffer& command_buffer_0, CommandBuffer& command_buffer_1) noexcept { + using std::swap; + swap(command_buffer_0.m_context, command_buffer_1.m_context); + swap(command_buffer_0.m_command_pool, command_buffer_1.m_command_pool); + swap(command_buffer_0.m_command_buffer, command_buffer_1.m_command_buffer); + } + + void destroy() noexcept; + +private: + Context* m_context = nullptr; + VkCommandPool m_command_pool = VK_NULL_HANDLE; + VkCommandBuffer m_command_buffer = VK_NULL_HANDLE; +}; + + +} diff --git a/src/vk/CommandPool.cpp b/src/vk/CommandPool.cpp new file mode 100644 index 0000000..7ee30ea --- /dev/null +++ b/src/vk/CommandPool.cpp @@ -0,0 +1,67 @@ +// Copyright 2022 Simon Boyé + +#include +#include + +#include + + +namespace vk { + + +CommandPool::CommandPool() noexcept { +} + +CommandPool::CommandPool(Context& context, uint32_t queue_family, VkCommandPoolCreateFlags flags) + : m_context(&context) +{ + assert(m_context); + + VkCommandPoolCreateInfo create_info { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .flags = flags, + .queueFamilyIndex = queue_family, + }; + if(vkCreateCommandPool( + context.device(), + &create_info, + nullptr, + &m_command_pool + ) != VK_SUCCESS) + throw std::runtime_error("failed to create command pool"); +} + +CommandPool::CommandPool(CommandPool&& other) noexcept +{ + swap(*this, other); +} + +CommandPool::~CommandPool() noexcept { + if(!is_null()) + destroy(); +} + + +CommandPool& CommandPool::operator=(CommandPool&& other) noexcept { + swap(*this, other); + if(other) + other.destroy(); + return *this; +} + + +void CommandPool::destroy() noexcept { + assert(!is_null()); + assert(m_context); + + vkDestroyCommandPool( + m_context->device(), + m_command_pool, + nullptr + ); + + m_command_pool = nullptr; +} + + +} diff --git a/src/vk/CommandPool.h b/src/vk/CommandPool.h new file mode 100644 index 0000000..7038d14 --- /dev/null +++ b/src/vk/CommandPool.h @@ -0,0 +1,61 @@ +// Copyright 2022 Simon Boyé +#pragma once + +#include + +#include + + +namespace vk { + + +class CommandPool { +public: + CommandPool() noexcept; + CommandPool(Context& context, uint32_t queue_family, VkCommandPoolCreateFlags flags=0); + CommandPool(const CommandPool&) = delete; + CommandPool(CommandPool&& other) noexcept; + ~CommandPool() noexcept; + + CommandPool& operator=(const CommandPool&) = delete; + CommandPool& operator=(CommandPool&& other) noexcept; + + explicit inline operator bool() const noexcept { + return !is_null(); + } + + inline bool is_null() const noexcept { + return m_command_pool == VK_NULL_HANDLE; + } + + inline const Context* context() const noexcept { + return m_context; + } + + inline Context* context() noexcept { + return m_context; + } + + inline operator VkCommandPool() noexcept { + return m_command_pool; + } + + inline VkCommandPool command_pool() noexcept { + return m_command_pool; + } + + friend inline void swap(CommandPool& command_pool_0, CommandPool& command_pool_1) noexcept { + using std::swap; + swap(command_pool_0.m_context, command_pool_1.m_context); + swap(command_pool_0.m_command_pool, command_pool_1.m_command_pool); + } + + void destroy() noexcept; + +private: + Context* m_context = nullptr; + VkCommandPool m_command_pool = VK_NULL_HANDLE; +}; + + +} diff --git a/src/vk/Context.cpp b/src/vk/Context.cpp index ee2142a..db4e1a0 100644 --- a/src/vk/Context.cpp +++ b/src/vk/Context.cpp @@ -1,6 +1,7 @@ // Copyright 2022 Simon Boyé #include #include +#include #include #include @@ -141,7 +142,7 @@ void Context::shutdown() { m_allocator.reset(); m_transfer_fence.destroy(); - destroy_command_pool(m_transfer_command_pool); + m_transfer_command_pool.destroy(); destroy_device(m_device); destroy_surface(m_surface); @@ -282,18 +283,7 @@ VkShaderModule Context::create_shader_module_from_file(const char* path) { } void Context::copy_buffer(VkBuffer dst, VkBuffer src, uint32_t dst_queue_family, VkDeviceSize size) { - VkCommandBufferAllocateInfo alloc_info { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = m_transfer_command_pool, - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = 1, - }; - - VkCommandBuffer command_buffer; - vkAllocateCommandBuffers(m_device, &alloc_info, &command_buffer); - auto const command_buffer_guard = make_guard([this, command_buffer]() { - vkFreeCommandBuffers(m_device, m_transfer_command_pool, 1, &command_buffer); - }); + CommandBuffer command_buffer(*this, m_transfer_command_pool); VkCommandBufferBeginInfo begin_info { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, @@ -332,10 +322,13 @@ void Context::copy_buffer(VkBuffer dst, VkBuffer src, uint32_t dst_queue_family, m_transfer_fence.reset(); + VkCommandBuffer command_buffers[] = { + command_buffer + }; VkSubmitInfo submit_info { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .commandBufferCount = 1, - .pCommandBuffers = &command_buffer, + .pCommandBuffers = command_buffers, }; vkQueueSubmit( queue(m_transfer_queue_index), @@ -776,20 +769,11 @@ void Context::create_device(const ContextSettings& settings) { } void Context::create_internal_objects() { - VkCommandPoolCreateInfo pool_info { - .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .flags = 0, - .queueFamilyIndex = queue_family(m_transfer_queue_index), - }; - if(vkCreateCommandPool( - m_device, - &pool_info, - nullptr, - &m_transfer_command_pool - ) != VK_SUCCESS) { - throw std::runtime_error("failed to create command pool"); - } - + m_transfer_command_pool = CommandPool( + *this, + queue_family(m_transfer_queue_index), + VK_COMMAND_POOL_CREATE_TRANSIENT_BIT + ); m_transfer_fence = Fence(*this); } diff --git a/src/vk/Context.h b/src/vk/Context.h index 82b7c7e..2fe4110 100644 --- a/src/vk/Context.h +++ b/src/vk/Context.h @@ -2,6 +2,7 @@ #pragma once #include +#include #include #include @@ -194,7 +195,7 @@ private: VkPresentModeKHR m_present_mode; uint32_t m_transfer_queue_index = UINT32_MAX; - VkCommandPool m_transfer_command_pool = VK_NULL_HANDLE; + CommandPool m_transfer_command_pool; Fence m_transfer_fence; std::vector m_context_destruction_callbacks;