From c656c5529800d47695a2a4ea371443e6e59208c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 12 Mar 2021 16:57:41 +0100 Subject: [PATCH] Vk: ability to list descriptor set layouts in PipelineLayoutCreateInfo. --- doc/snippets/MagnumVk.cpp | 20 ++++++++- src/Magnum/Vk/DescriptorSetLayout.h | 6 +++ src/Magnum/Vk/PipelineLayout.cpp | 43 ++++++++++++++++++- src/Magnum/Vk/PipelineLayout.h | 18 +++++++- src/Magnum/Vk/PipelineLayoutCreateInfo.h | 36 +++++++++++++++- src/Magnum/Vk/Test/PipelineLayoutTest.cpp | 47 ++++++++++++++++++++- src/Magnum/Vk/Test/PipelineLayoutVkTest.cpp | 30 +++++++++++-- 7 files changed, 191 insertions(+), 9 deletions(-) diff --git a/doc/snippets/MagnumVk.cpp b/doc/snippets/MagnumVk.cpp index 30bbdc89f..8d90b1047 100644 --- a/doc/snippets/MagnumVk.cpp +++ b/doc/snippets/MagnumVk.cpp @@ -55,7 +55,7 @@ #include "Magnum/Vk/MemoryAllocateInfo.h" #include "Magnum/Vk/Mesh.h" #include "Magnum/Vk/Pipeline.h" -#include "Magnum/Vk/PipelineLayout.h" +#include "Magnum/Vk/PipelineLayoutCreateInfo.h" #include "Magnum/Vk/PixelFormat.h" #include "Magnum/Vk/Queue.h" #include "Magnum/Vk/RasterizationPipelineCreateInfo.h" @@ -1021,6 +1021,24 @@ cmd.bindPipeline(pipeline); /* [Pipeline-usage] */ } +{ +Vk::Device device{NoCreate}; +/* The include should be a no-op here since it was already included above */ +/* [PipelineLayout-creation] */ +#include + +DOXYGEN_IGNORE() + +Vk::DescriptorSetLayout layout1{DOXYGEN_IGNORE(NoCreate)}; +Vk::DescriptorSetLayout layout2{DOXYGEN_IGNORE(NoCreate)}; +DOXYGEN_IGNORE() + +Vk::PipelineLayout{device, Vk::PipelineLayoutCreateInfo{ + layout1, layout2, DOXYGEN_IGNORE(layout1) +}}; +/* [PipelineLayout-creation] */ +} + { Vk::Device device{NoCreate}; /* The include should be a no-op here since it was already included above */ diff --git a/src/Magnum/Vk/DescriptorSetLayout.h b/src/Magnum/Vk/DescriptorSetLayout.h index 1e4c4167b..6d42d54a9 100644 --- a/src/Magnum/Vk/DescriptorSetLayout.h +++ b/src/Magnum/Vk/DescriptorSetLayout.h @@ -85,6 +85,12 @@ specify additional flags per binding. All of them require a certain @ref DescriptorSetLayoutBinding::Flag for more information: @snippet MagnumVk.cpp DescriptorSetLayout-creation-binding-flags + +@section Vk-DescriptorSetLayout-usage Descriptor set layout usage + +A descriptor set layout is used in a @ref PipelineLayout creation and +subsequently for descriptor set allocation from a descriptor pool. See the +corresponding class documentation for more information. */ class MAGNUM_VK_EXPORT DescriptorSetLayout { public: diff --git a/src/Magnum/Vk/PipelineLayout.cpp b/src/Magnum/Vk/PipelineLayout.cpp index 7c51015e1..a4e5bcd9c 100644 --- a/src/Magnum/Vk/PipelineLayout.cpp +++ b/src/Magnum/Vk/PipelineLayout.cpp @@ -26,16 +26,32 @@ #include "PipelineLayout.h" #include "PipelineLayoutCreateInfo.h" +#include +#include + #include "Magnum/Vk/Assert.h" #include "Magnum/Vk/Device.h" #include "Magnum/Vk/Result.h" namespace Magnum { namespace Vk { -PipelineLayoutCreateInfo::PipelineLayoutCreateInfo(): _info{} { +PipelineLayoutCreateInfo::PipelineLayoutCreateInfo(const Containers::ArrayView descriptorSetLayouts): _info{} { + /* Make a copy of the descriptor set layout list */ + Containers::ArrayView descriptorSetLayoutsCopy; + _data = Containers::ArrayTuple{ + {Containers::NoInit, descriptorSetLayouts.size(), descriptorSetLayoutsCopy} + }; + Utility::copy(descriptorSetLayouts, descriptorSetLayoutsCopy); + _info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + _info.setLayoutCount = descriptorSetLayoutsCopy.size(); + _info.pSetLayouts = descriptorSetLayoutsCopy; } +PipelineLayoutCreateInfo::PipelineLayoutCreateInfo(): PipelineLayoutCreateInfo{Containers::ArrayView{}} {} + +PipelineLayoutCreateInfo::PipelineLayoutCreateInfo(const std::initializer_list descriptorSetLayouts): PipelineLayoutCreateInfo{Containers::arrayView(descriptorSetLayouts)} {} + PipelineLayoutCreateInfo::PipelineLayoutCreateInfo(NoInitT) noexcept {} PipelineLayoutCreateInfo::PipelineLayoutCreateInfo(const VkPipelineLayoutCreateInfo& info): @@ -43,6 +59,31 @@ PipelineLayoutCreateInfo::PipelineLayoutCreateInfo(const VkPipelineLayoutCreateI member instead of doing a copy */ _info(info) {} +PipelineLayoutCreateInfo::PipelineLayoutCreateInfo(PipelineLayoutCreateInfo&& other) noexcept: + /* Can't use {} with GCC 4.8 here because it tries to initialize the first + member instead of doing a copy */ + _info(other._info), + _data{std::move(other._data)} +{ + /* Ensure the previous instance doesn't reference state that's now ours */ + /** @todo this is now more like a destructible move, do it more selectively + and clear only what's really ours and not external? */ + other._info.pNext = nullptr; + other._info.setLayoutCount = 0; + other._info.pSetLayouts = nullptr; + other._info.pushConstantRangeCount = 0; + other._info.pPushConstantRanges = nullptr; +} + +PipelineLayoutCreateInfo::~PipelineLayoutCreateInfo() = default; + +PipelineLayoutCreateInfo& PipelineLayoutCreateInfo::operator=(PipelineLayoutCreateInfo&& other) noexcept { + using std::swap; + swap(other._info, _info); + swap(other._data, _data); + return *this; +} + PipelineLayout PipelineLayout::wrap(Device& device, const VkPipelineLayout handle, const HandleFlags flags) { PipelineLayout out{NoCreate}; out._device = &device; diff --git a/src/Magnum/Vk/PipelineLayout.h b/src/Magnum/Vk/PipelineLayout.h index 2feec7f3d..828cc8a86 100644 --- a/src/Magnum/Vk/PipelineLayout.h +++ b/src/Magnum/Vk/PipelineLayout.h @@ -43,7 +43,23 @@ namespace Magnum { namespace Vk { @brief Pipeline layout @m_since_latest -Wraps a @type_vk_keyword{PipelineLayout}. Used in a @ref Pipeline. +Wraps a @type_vk_keyword{PipelineLayout}. Specifies what descriptor set layouts +and push constants are used in a @ref Pipeline. + +@section Vk-PipelineLayout-creation Pipeline layout creation + +Except for the rare case when your shader doesn't have any bindings, in which +case a default-constructed @ref PipelineLayoutCreateInfo would be enough, +you'll want to list @ref DescriptorSetLayout instances for all descriptor sets +needed by shaders in the pipeline: + +@snippet MagnumVk.cpp PipelineLayout-creation + +@section Vk-PipelineLayout-usage Pipeline layout usage + +Once created, the pipeline layout instance is used for @ref Pipeline creation +and for descriptor set binding. See the corresponding class documentation for +more information. */ class MAGNUM_VK_EXPORT PipelineLayout { public: diff --git a/src/Magnum/Vk/PipelineLayoutCreateInfo.h b/src/Magnum/Vk/PipelineLayoutCreateInfo.h index f6067d0a3..d259d453e 100644 --- a/src/Magnum/Vk/PipelineLayoutCreateInfo.h +++ b/src/Magnum/Vk/PipelineLayoutCreateInfo.h @@ -30,6 +30,8 @@ * @m_since_latest */ +#include + #include "Magnum/Tags.h" #include "Magnum/Vk/Vk.h" #include "Magnum/Vk/Vulkan.h" @@ -41,19 +43,34 @@ namespace Magnum { namespace Vk { @brief Pipeline layout creation info @m_since_latest -Wraps a @type_vk_keyword{PipelineLayoutCreateInfo}. +Wraps a @type_vk_keyword{PipelineLayoutCreateInfo}. See +@ref Vk-PipelineLayout-creation "Pipeline layout creation" for usage +information. */ class MAGNUM_VK_EXPORT PipelineLayoutCreateInfo { public: + /* VkPipelineLayoutCreateFlagBits is currently empty, so no reason + to expose */ + /** * @brief Constructor + * @param descriptorSetLayouts Descriptor set layouts used in this + * pipeline layout * * The following @type_vk{PipelineLayoutCreateInfo} fields are * pre-filled in addition to `sType`, everything else is zero-filled: * - * - (none) + * - `setLayoutCount` and `pSetLayouts` to a copy of + * @p descriptorSetLayouts */ + #ifdef DOXYGEN_GENERATING_OUTPUT + explicit PipelineLayoutCreateInfo(Containers::ArrayView descriptorSetLayouts = {}); + #else /* so we don't need to include ArrayView */ + explicit PipelineLayoutCreateInfo(Containers::ArrayView descriptorSetLayouts); explicit PipelineLayoutCreateInfo(); + #endif + /** @overload */ + explicit PipelineLayoutCreateInfo(std::initializer_list descriptorSetLayouts); /** * @brief Construct without initializing the contents @@ -72,6 +89,20 @@ class MAGNUM_VK_EXPORT PipelineLayoutCreateInfo { */ explicit PipelineLayoutCreateInfo(const VkPipelineLayoutCreateInfo& info); + /** @brief Copying is not allowed */ + PipelineLayoutCreateInfo(const PipelineLayoutCreateInfo&) = delete; + + /** @brief Move constructor */ + PipelineLayoutCreateInfo(PipelineLayoutCreateInfo&& other) noexcept; + + ~PipelineLayoutCreateInfo(); + + /** @brief Copying is not allowed */ + PipelineLayoutCreateInfo& operator=(const PipelineLayoutCreateInfo&) = delete; + + /** @brief Move assignment */ + PipelineLayoutCreateInfo& operator=(PipelineLayoutCreateInfo&& other) noexcept; + /** @brief Underlying @type_vk{PipelineLayoutCreateInfo} structure */ VkPipelineLayoutCreateInfo& operator*() { return _info; } /** @overload */ @@ -85,6 +116,7 @@ class MAGNUM_VK_EXPORT PipelineLayoutCreateInfo { private: VkPipelineLayoutCreateInfo _info; + Containers::ArrayTuple _data; }; }} diff --git a/src/Magnum/Vk/Test/PipelineLayoutTest.cpp b/src/Magnum/Vk/Test/PipelineLayoutTest.cpp index 10f19d631..62344f245 100644 --- a/src/Magnum/Vk/Test/PipelineLayoutTest.cpp +++ b/src/Magnum/Vk/Test/PipelineLayoutTest.cpp @@ -24,6 +24,7 @@ */ #include +#include #include #include "Magnum/Vk/PipelineLayoutCreateInfo.h" @@ -34,8 +35,11 @@ struct PipelineLayoutTest: TestSuite::Tester { explicit PipelineLayoutTest(); void createInfoConstruct(); + void createInfoConstructDescriptorSetLayouts(); void createInfoConstructNoInit(); void createInfoConstructFromVk(); + void createInfoConstructCopy(); + void createInfoConstructMove(); void constructNoCreate(); void constructCopy(); @@ -43,8 +47,11 @@ struct PipelineLayoutTest: TestSuite::Tester { PipelineLayoutTest::PipelineLayoutTest() { addTests({&PipelineLayoutTest::createInfoConstruct, + &PipelineLayoutTest::createInfoConstructDescriptorSetLayouts, &PipelineLayoutTest::createInfoConstructNoInit, &PipelineLayoutTest::createInfoConstructFromVk, + &PipelineLayoutTest::createInfoConstructCopy, + &PipelineLayoutTest::createInfoConstructMove, &PipelineLayoutTest::constructNoCreate, &PipelineLayoutTest::constructCopy}); @@ -52,8 +59,20 @@ PipelineLayoutTest::PipelineLayoutTest() { void PipelineLayoutTest::createInfoConstruct() { PipelineLayoutCreateInfo info; - /** @todo expand once there's actually something */ CORRADE_COMPARE(info->flags, 0); + CORRADE_COMPARE(info->setLayoutCount, 0); +} + +void PipelineLayoutTest::createInfoConstructDescriptorSetLayouts() { + VkDescriptorSetLayout layouts[]{reinterpret_cast(0xdead), reinterpret_cast(0xbeef)}; + + PipelineLayoutCreateInfo info{layouts}; + CORRADE_COMPARE(info->setLayoutCount, 2); + CORRADE_VERIFY(info->pSetLayouts); + /* The contents should be copied */ + CORRADE_VERIFY(info->pSetLayouts != layouts); + CORRADE_COMPARE(info->pSetLayouts[0], reinterpret_cast(0xdead)); + CORRADE_COMPARE(info->pSetLayouts[1], reinterpret_cast(0xbeef)); } void PipelineLayoutTest::createInfoConstructNoInit() { @@ -76,6 +95,32 @@ void PipelineLayoutTest::createInfoConstructFromVk() { CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2); } +void PipelineLayoutTest::createInfoConstructCopy() { + CORRADE_VERIFY(!std::is_copy_constructible{}); + CORRADE_VERIFY(!std::is_copy_assignable{}); +} + +void PipelineLayoutTest::createInfoConstructMove() { + PipelineLayoutCreateInfo a{reinterpret_cast(0xdead), reinterpret_cast(0xbeef)}; + CORRADE_COMPARE(a->setLayoutCount, 2); + CORRADE_VERIFY(a->pSetLayouts); + + PipelineLayoutCreateInfo b = std::move(a); + CORRADE_COMPARE(a->setLayoutCount, 0); + CORRADE_VERIFY(!a->pSetLayouts); + CORRADE_COMPARE(b->setLayoutCount, 2); + CORRADE_VERIFY(b->pSetLayouts); + CORRADE_COMPARE(b->pSetLayouts[1], reinterpret_cast(0xbeef)); + + PipelineLayoutCreateInfo c; + c = std::move(b); + CORRADE_COMPARE(b->setLayoutCount, 0); + CORRADE_VERIFY(!b->pSetLayouts); + CORRADE_COMPARE(c->setLayoutCount, 2); + CORRADE_VERIFY(c->pSetLayouts); + CORRADE_COMPARE(c->pSetLayouts[1], reinterpret_cast(0xbeef)); +} + void PipelineLayoutTest::constructNoCreate() { { PipelineLayout layout{NoCreate}; diff --git a/src/Magnum/Vk/Test/PipelineLayoutVkTest.cpp b/src/Magnum/Vk/Test/PipelineLayoutVkTest.cpp index 0c5b92a79..e9869929f 100644 --- a/src/Magnum/Vk/Test/PipelineLayoutVkTest.cpp +++ b/src/Magnum/Vk/Test/PipelineLayoutVkTest.cpp @@ -25,6 +25,7 @@ #include +#include "Magnum/Vk/DescriptorSetLayoutCreateInfo.h" #include "Magnum/Vk/PipelineLayoutCreateInfo.h" #include "Magnum/Vk/Result.h" #include "Magnum/Vk/VulkanTester.h" @@ -34,21 +35,24 @@ namespace Magnum { namespace Vk { namespace Test { namespace { struct PipelineLayoutVkTest: VulkanTester { explicit PipelineLayoutVkTest(); - void construct(); + void constructEmpty(); + void constructWithDescriptorSetLayout(); void constructMove(); void wrap(); }; PipelineLayoutVkTest::PipelineLayoutVkTest() { - addTests({&PipelineLayoutVkTest::construct, + addTests({&PipelineLayoutVkTest::constructEmpty, + &PipelineLayoutVkTest::constructWithDescriptorSetLayout, &PipelineLayoutVkTest::constructMove, &PipelineLayoutVkTest::wrap}); } -void PipelineLayoutVkTest::construct() { +void PipelineLayoutVkTest::constructEmpty() { { + /* Rare, but should still work */ PipelineLayout layout{device(), PipelineLayoutCreateInfo{}}; CORRADE_VERIFY(layout.handle()); CORRADE_COMPARE(layout.handleFlags(), HandleFlag::DestroyOnDestruction); @@ -58,6 +62,26 @@ void PipelineLayoutVkTest::construct() { CORRADE_VERIFY(true); } +void PipelineLayoutVkTest::constructWithDescriptorSetLayout() { + { + DescriptorSetLayout descriptorSetLayout1{device(), DescriptorSetLayoutCreateInfo{ + {{15, DescriptorType::UniformBuffer}} + }}; + DescriptorSetLayout descriptorSetLayout2{device(), DescriptorSetLayoutCreateInfo{ + {{1, DescriptorType::CombinedImageSampler}} + }}; + + PipelineLayout layout{device(), PipelineLayoutCreateInfo{ + descriptorSetLayout1, descriptorSetLayout2 + }}; + CORRADE_VERIFY(layout.handle()); + CORRADE_COMPARE(layout.handleFlags(), HandleFlag::DestroyOnDestruction); + } + + /* Shouldn't crash or anything */ + CORRADE_VERIFY(true); +} + void PipelineLayoutVkTest::constructMove() { PipelineLayout a{device(), PipelineLayoutCreateInfo{}}; VkPipelineLayout handle = a.handle();