From 7ee30c55e33944e011eddde14b43aa15d86720bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 30 Dec 2020 18:31:47 +0100 Subject: [PATCH] Vk: command buffer begin and end. --- doc/vulkan-mapping.dox | 4 +- src/Magnum/Vk/CommandBuffer.cpp | 21 ++++ src/Magnum/Vk/CommandBuffer.h | 119 ++++++++++++++++++++- src/Magnum/Vk/Test/CommandBufferTest.cpp | 35 +++++- src/Magnum/Vk/Test/CommandBufferVkTest.cpp | 20 +++- src/Magnum/Vk/Vk.h | 1 + 6 files changed, 195 insertions(+), 5 deletions(-) diff --git a/doc/vulkan-mapping.dox b/doc/vulkan-mapping.dox index 803c00736..f0eca200a 100644 --- a/doc/vulkan-mapping.dox +++ b/doc/vulkan-mapping.dox @@ -62,7 +62,7 @@ Vulkan function | Matching API Vulkan function | Matching API --------------------------------------- | ------------ -@fn_vk{BeginCommandBuffer}, \n \fn_vk{EndCommandBuffer} | | +@fn_vk{BeginCommandBuffer}, \n \fn_vk{EndCommandBuffer} | @ref CommandBuffer::begin(), \n @ref CommandBuffer::end() @fn_vk{BindBufferMemory}, \n @fn_vk{BindBufferMemory2} @m_class{m-label m-flat m-success} **KHR, 1.1** | @ref Buffer::bindMemory() @fn_vk{BindImageMemory}, \n @fn_vk{BindImageMemory2} @m_class{m-label m-flat m-success} **KHR, 1.1** | @ref Image::bindMemory() @fn_vk{BuildAccelerationStructuresKHR} @m_class{m-label m-flat m-warning} **KHR** | | @@ -385,7 +385,7 @@ Vulkan structure | Matching API @type_vk{ClearValue} | | @type_vk{ClearRect} | convertible from/to @ref Range3Di using @ref Magnum/Vk/Integration.h @type_vk{CommandBufferAllocateInfo} | not exposed, internal to @ref CommandPool::allocate() -@type_vk{CommandBufferBeginInfo} | | +@type_vk{CommandBufferBeginInfo} | @ref CommandBufferBeginInfo @type_vk{CommandBufferInheritanceInfo} | | @type_vk{CommandPoolCreateInfo} | @ref CommandPoolCreateInfo @type_vk{ComponentMapping} | | diff --git a/src/Magnum/Vk/CommandBuffer.cpp b/src/Magnum/Vk/CommandBuffer.cpp index ffd92628e..e5261e783 100644 --- a/src/Magnum/Vk/CommandBuffer.cpp +++ b/src/Magnum/Vk/CommandBuffer.cpp @@ -64,6 +64,27 @@ void CommandBuffer::reset(const CommandBufferResetFlags flags) { MAGNUM_VK_INTERNAL_ASSERT_SUCCESS((**_device).ResetCommandBuffer(_handle, VkCommandBufferResetFlags(flags))); } +CommandBufferBeginInfo::CommandBufferBeginInfo(const Flags flags): _info{} { + _info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + _info.flags = VkCommandBufferUsageFlags(flags); +} + +CommandBufferBeginInfo::CommandBufferBeginInfo(NoInitT) noexcept {} + +CommandBufferBeginInfo::CommandBufferBeginInfo(const VkCommandBufferBeginInfo& info): + /* Can't use {} with GCC 4.8 here because it tries to initialize the first + member instead of doing a copy */ + _info(info) {} + +CommandBuffer& CommandBuffer::begin(const CommandBufferBeginInfo& info) { + MAGNUM_VK_INTERNAL_ASSERT_SUCCESS((**_device).BeginCommandBuffer(_handle, info)); + return *this; +} + +void CommandBuffer::end() { + MAGNUM_VK_INTERNAL_ASSERT_SUCCESS((**_device).EndCommandBuffer(_handle)); +} + VkCommandBuffer CommandBuffer::release() { const VkCommandBuffer handle = _handle; _handle = nullptr; diff --git a/src/Magnum/Vk/CommandBuffer.h b/src/Magnum/Vk/CommandBuffer.h index 723f06da6..26a178c4a 100644 --- a/src/Magnum/Vk/CommandBuffer.h +++ b/src/Magnum/Vk/CommandBuffer.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class @ref Magnum::Vk::CommandBuffer, enum @ref Magnum::Vk::CommandPoolResetFlag, enum set @ref Magnum::Vk::CommandPoolResetFlags + * @brief Class @ref Magnum::Vk::CommandBuffer, @ref Magnum::Vk::CommandBufferBeginInfo, enum @ref Magnum::Vk::CommandPoolResetFlag, enum set @ref Magnum::Vk::CommandPoolResetFlags * @m_since_latest */ @@ -40,6 +40,106 @@ namespace Magnum { namespace Vk { +/** +@brief Command buffer begin info +@m_since_latest + +Wraps a @type_vk_keyword{CommandBufferBeginInfo}. +@see @ref CommandBuffer::begin() +*/ +class MAGNUM_VK_EXPORT CommandBufferBeginInfo { + public: + /** + * @brief Command buffer begin flag + * + * Wraps @type_vk_keyword{CommandBufferBeginFlagBits}. + * @see @ref Flags, @ref CommandBufferBeginInfo(Flags) + */ + enum class Flag: UnsignedInt { + /** + * Each recording will be submitted only once and the command + * buffer will be reset and recorded again between each submission. + * + * @m_class{m-note m-success} + * + * @par + * Setting this flag on single-use command buffers might help + * drivers pick a better tradeoff between CPU time spent + * optimizing the commands and GPU time spent executing them. + */ + OneTimeSubmit = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, + + /** + * Specifies that a @ref CommandBufferLevel::Secondary buffer is + * entirely inside a render pass. Ignored for + * @ref CommandBufferLevel::Primary command buffers (the default). + */ + RenderPassContinue = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, + + /** + * A command buffer can be resubmitted to a queue while it is in + * the pending state, and recorded into multiple primary command + * buffers. + */ + SimultaneousUse = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT + }; + + /** + * @brief Command buffer begin flags + * + * Type-safe wrapper for @type_vk_keyword{CommandBufferBeginFlags}. + * @see @ref CommandBufferBeginInfo(Flags) + */ + typedef Containers::EnumSet Flags; + + /** + * @brief Constructor + * @param flags Command buffer begin flags + * + * The following @type_vk{CommandBufferBeginInfo} fields are pre-filled + * in addition to `sType`, everything else is zero-filled: + * + * - `flags` + */ + /* cmd.begin(CommandBufferBeginInfo::Flag::OneTimeSubmit) doesn't work + anyway (would need an extra conversion from Flag to Flags), so no + point in making this implicit. */ + explicit CommandBufferBeginInfo(Flags flags = {}); + + /** + * @brief Construct without initializing the contents + * + * Note that not even the `sType` field is set --- the structure has to + * be fully initialized afterwards in order to be usable. + */ + explicit CommandBufferBeginInfo(NoInitT) noexcept; + + /** + * @brief Construct from existing data + * + * Copies the existing values verbatim, pointers are kept unchanged + * without taking over the ownership. Modifying the newly created + * instance will not modify the original data nor the pointed-to data. + */ + explicit CommandBufferBeginInfo(const VkCommandBufferBeginInfo& info); + + /** @brief Underlying @type_vk{CommandBufferBeginInfo} structure */ + VkCommandBufferBeginInfo& operator*() { return _info; } + /** @overload */ + const VkCommandBufferBeginInfo& operator*() const { return _info; } + /** @overload */ + VkCommandBufferBeginInfo* operator->() { return &_info; } + /** @overload */ + const VkCommandBufferBeginInfo* operator->() const { return &_info; } + /** @overload */ + operator const VkCommandBufferBeginInfo*() const { return &_info; } + + private: + VkCommandBufferBeginInfo _info; +}; + +CORRADE_ENUMSET_OPERATORS(CommandBufferBeginInfo::Flags) + /** @brief Command buffer reset flag @m_since_latest @@ -150,6 +250,23 @@ class MAGNUM_VK_EXPORT CommandBuffer { */ VkCommandBuffer release(); + /** + * @brief Begin command buffer recording + * @return Reference to self (for method chaining) + * + * @see @fn_vk_keyword{BeginCommandBuffer} + */ + CommandBuffer& begin(const CommandBufferBeginInfo& info = CommandBufferBeginInfo{}); + + /** + * @brief End command buffer recording + * + * As this function is expected to be called last, it doesn't return a + * reference to self for method chaining. + * @see @fn_vk_keyword{EndCommandBuffer} + */ + void end(); + private: friend CommandPool; diff --git a/src/Magnum/Vk/Test/CommandBufferTest.cpp b/src/Magnum/Vk/Test/CommandBufferTest.cpp index e95a5bdd5..d754f76ff 100644 --- a/src/Magnum/Vk/Test/CommandBufferTest.cpp +++ b/src/Magnum/Vk/Test/CommandBufferTest.cpp @@ -33,15 +33,48 @@ namespace Magnum { namespace Vk { namespace Test { namespace { struct CommandBufferTest: TestSuite::Tester { explicit CommandBufferTest(); + void beginInfoConstruct(); + void beginInfoConstructNoInit(); + void beginInfoConstructFromVk(); + void constructNoCreate(); void constructCopy(); }; CommandBufferTest::CommandBufferTest() { - addTests({&CommandBufferTest::constructNoCreate, + addTests({&CommandBufferTest::beginInfoConstruct, + &CommandBufferTest::beginInfoConstructNoInit, + &CommandBufferTest::beginInfoConstructFromVk, + + &CommandBufferTest::constructNoCreate, &CommandBufferTest::constructCopy}); } +void CommandBufferTest::beginInfoConstruct() { + CommandBufferBeginInfo info{CommandBufferBeginInfo::Flag::OneTimeSubmit}; + CORRADE_COMPARE(info->flags, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); +} + +void CommandBufferTest::beginInfoConstructNoInit() { + CommandBufferBeginInfo info{NoInit}; + info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; + new(&info) CommandBufferBeginInfo{NoInit}; + CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2); + + CORRADE_VERIFY((std::is_nothrow_constructible::value)); + + /* Implicit construction is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); +} + +void CommandBufferTest::beginInfoConstructFromVk() { + VkCommandBufferBeginInfo vkInfo; + vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; + + CommandBufferBeginInfo info{vkInfo}; + CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2); +} + void CommandBufferTest::constructNoCreate() { { CommandBuffer buffer{NoCreate}; diff --git a/src/Magnum/Vk/Test/CommandBufferVkTest.cpp b/src/Magnum/Vk/Test/CommandBufferVkTest.cpp index 3c50fdcc0..75930e7d4 100644 --- a/src/Magnum/Vk/Test/CommandBufferVkTest.cpp +++ b/src/Magnum/Vk/Test/CommandBufferVkTest.cpp @@ -40,6 +40,8 @@ struct CommandBufferVkTest: VulkanTester { void wrap(); void reset(); + + void beginEnd(); }; CommandBufferVkTest::CommandBufferVkTest() { @@ -47,7 +49,9 @@ CommandBufferVkTest::CommandBufferVkTest() { &CommandBufferVkTest::constructMove, &CommandBufferVkTest::wrap, - &CommandBufferVkTest::reset}); + &CommandBufferVkTest::reset, + + &CommandBufferVkTest::beginEnd}); } void CommandBufferVkTest::construct() { @@ -122,6 +126,20 @@ void CommandBufferVkTest::reset() { CORRADE_VERIFY(true); } +void CommandBufferVkTest::beginEnd() { + CommandPool pool{device(), CommandPoolCreateInfo{ + device().properties().pickQueueFamily(QueueFlag::Graphics)}}; + + pool.allocate() + .begin(CommandBufferBeginInfo{ + CommandBufferBeginInfo::Flag::OneTimeSubmit + }) + .end(); + + /* Does not do anything visible, so just test that it didn't blow up */ + CORRADE_VERIFY(true); +} + }}}} CORRADE_TEST_MAIN(Magnum::Vk::Test::CommandBufferVkTest) diff --git a/src/Magnum/Vk/Vk.h b/src/Magnum/Vk/Vk.h index f70ca07c5..670c598ea 100644 --- a/src/Magnum/Vk/Vk.h +++ b/src/Magnum/Vk/Vk.h @@ -39,6 +39,7 @@ namespace Magnum { namespace Vk { class Buffer; class BufferCreateInfo; class CommandBuffer; +/* CommandBufferBeginInfo is useful only in combination with CommandBuffer */ class CommandPool; class CommandPoolCreateInfo; class Device;