diff --git a/doc/snippets/MagnumVk.cpp b/doc/snippets/MagnumVk.cpp index 11b64b578..a3c8c966e 100644 --- a/doc/snippets/MagnumVk.cpp +++ b/doc/snippets/MagnumVk.cpp @@ -39,6 +39,7 @@ #include "Magnum/Vk/CommandBuffer.h" #include "Magnum/Vk/CommandPoolCreateInfo.h" #include "Magnum/Vk/ComputePipelineCreateInfo.h" +#include "Magnum/Vk/DescriptorPoolCreateInfo.h" #include "Magnum/Vk/DescriptorSetLayoutCreateInfo.h" #include "Magnum/Vk/DescriptorType.h" #include "Magnum/Vk/DeviceCreateInfo.h" @@ -314,6 +315,21 @@ fence.wait(); /* [CommandBuffer-usage-submit] */ } +{ +Vk::Device device{NoCreate}; +/* The include should be a no-op here since it was already included above */ +/* [DescriptorPool-creation] */ +#include + +DOXYGEN_IGNORE() + +Vk::DescriptorPool pool{device, Vk::DescriptorPoolCreateInfo{8, { + {Vk::DescriptorType::UniformBuffer, 24}, + {Vk::DescriptorType::CombinedImageSampler, 16} +}}}; +/* [DescriptorPool-creation] */ +} + { Vk::Device device{NoCreate}; /* The include should be a no-op here since it was already included above */ diff --git a/doc/vulkan-mapping.dox b/doc/vulkan-mapping.dox index 55dde6ffb..0a73aa051 100644 --- a/doc/vulkan-mapping.dox +++ b/doc/vulkan-mapping.dox @@ -58,7 +58,7 @@ Vulkan handle | Matching API @type_vk{DeferredOperationKHR} @m_class{m-label m-flat m-warning} **KHR** | | @type_vk{DebugReportCallbackEXT} @m_class{m-label m-danger} **deprecated** @m_class{m-label m-flat m-warning} **EXT** | | @type_vk{DebugUtilsMessengerEXT} @m_class{m-label m-flat m-warning} **EXT** | | -@type_vk{DescriptorPool} | | +@type_vk{DescriptorPool} | @ref DescriptorPool @type_vk{DescriptorSet} | | @type_vk{DescriptorSetLayout} | @ref DescriptorSetLayout @type_vk{DescriptorUpdateTemplate} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @@ -190,7 +190,7 @@ Vulkan function | Matching API @fn_vk{CreateDebugReportCallbackEXT} @m_class{m-label m-danger} **deprecated** @m_class{m-label m-flat m-warning} **EXT**, \n @fn_vk{DestroyDebugReportCallbackEXT} @m_class{m-label m-danger} **deprecated** @m_class{m-label m-flat m-warning} **EXT** | | @fn_vk{CreateDebugUtilsMessengerEXT} @m_class{m-label m-flat m-warning} **EXT**, \n @fn_vk{DestroyDebugUtilsMessengerEXT} @m_class{m-label m-flat m-warning} **EXT** | | @fn_vk{CreateDeferredOperationKHR} @m_class{m-label m-flat m-warning} **KHR**, \n @fn_vk{DestroyDeferredOperationKHR} @m_class{m-label m-flat m-warning} **KHR** | | -@fn_vk{CreateDescriptorPool}, \n @fn_vk{DestroyDescriptorPool} | | +@fn_vk{CreateDescriptorPool}, \n @fn_vk{DestroyDescriptorPool} | @ref DescriptorPool constructor and destructor @fn_vk{CreateDescriptorSetLayout}, \n @fn_vk{DestroyDescriptorSetLayout} | @ref DescriptorSetLayout constructor and destructor @fn_vk{CreateDescriptorUpdateTemplate} @m_class{m-label m-flat m-success} **KHR, 1.1**, \n @fn_vk{DestroyDescriptorUpdateTemplate} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @fn_vk{CreateDevice}, \n @fn_vk{DestroyDevice} | @ref Device constructor and destructor @@ -463,8 +463,8 @@ Vulkan structure | Matching API @type_vk{DebugUtilsObjectTagInfoEXT} @m_class{m-label m-flat m-warning} **EXT** | | @type_vk{DescriptorBufferInfo} | | @type_vk{DescriptorImageInfo} | | -@type_vk{DescriptorPoolCreateInfo} | | -@type_vk{DescriptorPoolSize} | | +@type_vk{DescriptorPoolCreateInfo} | @ref DescriptorPoolCreateInfo +@type_vk{DescriptorPoolSize} | @ref DescriptorPoolCreateInfo @type_vk{DescriptorSetAllocateInfo} | | @type_vk{DescriptorSetLayoutBinding} | @ref DescriptorSetLayoutBinding @type_vk{DescriptorSetLayoutBindingFlagsCreateInfo} @m_class{m-label m-flqat m-success} **EXT, 1.2** | @ref DescriptorSetLayoutCreateInfo @@ -826,7 +826,7 @@ Vulkan enum | Matching API @type_vk{DebugUtilsMessageSeverityFlagBitsEXT} @m_class{m-label m-flat m-warning} **EXT**, \n @type_vk{DebugUtilsMessageTypeFlagsEXT} @m_class{m-label m-flat m-warning} **EXT** | | @type_vk{DependencyFlagBits}, \n @type_vk{DependencyFlags} | @ref DependencyFlag, \n @ref DependencyFlags @type_vk{DescriptorBindingFlagBits} @m_class{m-label m-flat m-success} **EXT, 1.2**, \n @type_vk{DescriptorBindingFlags} @m_class{m-label m-flat m-success} **EXT, 1.2** | @ref DescriptorSetLayoutBinding::Flag, \n @ref DescriptorSetLayoutBinding::Flags -@type_vk{DescriptorPoolCreateFlagBits}, \n @type_vk{DescriptorPoolCreateFlags} | | +@type_vk{DescriptorPoolCreateFlagBits}, \n @type_vk{DescriptorPoolCreateFlags} | @ref DescriptorPoolCreateInfo::Flag, \n @ref DescriptorPoolCreateInfo::Flags @type_vk{DescriptorSetLayoutCreateFlagBits}, \n @type_vk{DescriptorSetLayoutCreateFlags} | @ref DescriptorSetLayoutCreateInfo::Flag, \n @ref DescriptorSetLayoutCreateInfo::Flags @type_vk{DescriptorUpdateTemplateType} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @type_vk{DescriptorType} | @ref DescriptorType diff --git a/src/Magnum/Vk/CMakeLists.txt b/src/Magnum/Vk/CMakeLists.txt index 95abbc271..f4d189ccb 100644 --- a/src/Magnum/Vk/CMakeLists.txt +++ b/src/Magnum/Vk/CMakeLists.txt @@ -48,6 +48,7 @@ set(MagnumVk_SRCS set(MagnumVk_GracefulAssert_SRCS Buffer.cpp + DescriptorPool.cpp Device.cpp DeviceProperties.cpp DeviceFeatures.cpp @@ -74,6 +75,8 @@ set(MagnumVk_HEADERS CommandPool.h CommandPoolCreateInfo.h ComputePipelineCreateInfo.h + DescriptorPool.h + DescriptorPoolCreateInfo.h DescriptorSetLayout.h DescriptorSetLayoutCreateInfo.h DescriptorType.h diff --git a/src/Magnum/Vk/DescriptorPool.cpp b/src/Magnum/Vk/DescriptorPool.cpp new file mode 100644 index 000000000..d9a1616c1 --- /dev/null +++ b/src/Magnum/Vk/DescriptorPool.cpp @@ -0,0 +1,131 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "DescriptorPool.h" +#include "DescriptorPoolCreateInfo.h" + +#include + +#include "Magnum/Vk/Assert.h" +#include "Magnum/Vk/DescriptorType.h" +#include "Magnum/Vk/Device.h" +#include "Magnum/Vk/Result.h" + +namespace Magnum { namespace Vk { + +DescriptorPoolCreateInfo::DescriptorPoolCreateInfo(const UnsignedInt maxSets, const Containers::ArrayView> poolSizes, const Flags flags): _info{} { + CORRADE_ASSERT(maxSets, + "Vk::DescriptorPoolCreateInfo: there has to be at least one set", ); + CORRADE_ASSERT(poolSizes, + "Vk::DescriptorPoolCreateInfo: there has to be at least one pool", ); + + Containers::ArrayView poolSizesCopy; + _data = Containers::ArrayTuple{ + {Containers::NoInit, poolSizes.size(), poolSizesCopy} + }; + for(std::size_t i = 0; i != poolSizes.size(); ++i) { + CORRADE_ASSERT(poolSizes[i].second, + "Vk::DescriptorPoolCreateInfo: pool" << i << "of" << poolSizes[i].first << "has no descriptors", ); + poolSizesCopy[i].type = VkDescriptorType(poolSizes[i].first); + poolSizesCopy[i].descriptorCount = poolSizes[i].second; + } + + _info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + _info.flags = VkDescriptorPoolCreateFlags(flags); + _info.maxSets = maxSets; + _info.poolSizeCount = poolSizesCopy.size(); + _info.pPoolSizes = poolSizesCopy; +} + +DescriptorPoolCreateInfo::DescriptorPoolCreateInfo(const UnsignedInt maxSets, const std::initializer_list> poolSizes, const Flags flags): DescriptorPoolCreateInfo{maxSets, Containers::arrayView(poolSizes), flags} {} + +DescriptorPoolCreateInfo::DescriptorPoolCreateInfo(NoInitT) noexcept {} + +DescriptorPoolCreateInfo::DescriptorPoolCreateInfo(const VkDescriptorPoolCreateInfo& info): + /* Can't use {} with GCC 4.8 here because it tries to initialize the first + member instead of doing a copy */ + _info(info) {} + +DescriptorPoolCreateInfo::DescriptorPoolCreateInfo(DescriptorPoolCreateInfo&& 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.poolSizeCount = 0; + other._info.pPoolSizes = nullptr; +} + +DescriptorPoolCreateInfo::~DescriptorPoolCreateInfo() = default; + +DescriptorPoolCreateInfo& DescriptorPoolCreateInfo::operator=(DescriptorPoolCreateInfo&& other) noexcept { + using std::swap; + swap(other._info, _info); + swap(other._data, _data); + return *this; +} + +DescriptorPool DescriptorPool::wrap(Device& device, const VkDescriptorPool handle, const HandleFlags flags) { + DescriptorPool out{NoCreate}; + out._device = &device; + out._handle = handle; + out._flags = flags; + return out; +} + +DescriptorPool::DescriptorPool(Device& device, const DescriptorPoolCreateInfo& info): _device{&device}, _flags{HandleFlag::DestroyOnDestruction} { + MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(device->CreateDescriptorPool(device, info, nullptr, &_handle)); +} + +DescriptorPool::DescriptorPool(NoCreateT): _device{}, _handle{} {} + +DescriptorPool::DescriptorPool(DescriptorPool&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags} { + other._handle = {}; +} + +DescriptorPool::~DescriptorPool() { + if(_handle && (_flags & HandleFlag::DestroyOnDestruction)) + (**_device).DestroyDescriptorPool(*_device, _handle, nullptr); +} + +DescriptorPool& DescriptorPool::operator=(DescriptorPool&& other) noexcept { + using std::swap; + swap(other._device, _device); + swap(other._handle, _handle); + swap(other._flags, _flags); + return *this; +} + +VkDescriptorPool DescriptorPool::release() { + const VkDescriptorPool handle = _handle; + _handle = {}; + return handle; +} + +}} diff --git a/src/Magnum/Vk/DescriptorPool.h b/src/Magnum/Vk/DescriptorPool.h new file mode 100644 index 000000000..7976b435e --- /dev/null +++ b/src/Magnum/Vk/DescriptorPool.h @@ -0,0 +1,144 @@ +#ifndef Magnum_Vk_DescriptorPool_h +#define Magnum_Vk_DescriptorPool_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class @ref Magnum::Vk::DescriptorPool + * @m_since_latest + */ + +#include "Magnum/Tags.h" +#include "Magnum/Vk/Handle.h" +#include "Magnum/Vk/visibility.h" +#include "Magnum/Vk/Vk.h" +#include "Magnum/Vk/Vulkan.h" + +namespace Magnum { namespace Vk { + +/** +@brief Descriptor pool +@m_since_latest + +Wraps @type_vk_keyword{DescriptorPool}, which is used for allocating descriptor +sets. + +@section Vk-DescriptorPool-creation Descriptor pool creation + +The @ref DescriptorPoolCreateInfo class takes a maximum number of descriptor +sets that can be allocated from a pool and then a list of total available +descriptor counts for desired @ref DescriptorType "DescriptorTypes". The +following snippet creates a pool allowing to allocate at most 8 descriptor sets +with 24 sampler bindings and 16 uniform bindings: + +@snippet MagnumVk.cpp DescriptorPool-creation +*/ +class MAGNUM_VK_EXPORT DescriptorPool { + public: + /** + * @brief Wrap existing Vulkan handle + * @param device Vulkan device the descriptor pool is + * created on + * @param handle The @type_vk{DescriptorPool} handle + * @param flags Handle flags + * + * The @p handle is expected to be originating from @p device. Unlike + * a descriptor pool created using a constructor, the Vulkan descriptor + * pool is by default not deleted on destruction, use @p flags for + * different behavior. + * @see @ref release() + */ + static DescriptorPool wrap(Device& device, VkDescriptorPool handle, HandleFlags flags = {}); + + /** + * @brief Constructor + * @param device Vulkan device to create the descriptor pool on + * @param info Descriptor pool creation info + * + * @see @fn_vk_keyword{CreateDescriptorPool} + */ + explicit DescriptorPool(Device& device, const DescriptorPoolCreateInfo& info); + + /** + * @brief Construct without creating the fence + * + * The constructed instance is equivalent to moved-from state. Useful + * in cases where you will overwrite the instance later anyway. Move + * another object over it to make it useful. + */ + explicit DescriptorPool(NoCreateT); + + /** @brief Copying is not allowed */ + DescriptorPool(const DescriptorPool&) = delete; + + /** @brief Move constructor */ + DescriptorPool(DescriptorPool&& other) noexcept; + + /** + * @brief Destructor + * + * Destroys associated @type_vk{DescriptorPool} handle, unless the + * instance was created using @ref wrap() without + * @ref HandleFlag::DestroyOnDestruction specified. + * @see @fn_vk_keyword{DestroyDescriptorPool}, @ref release() + */ + ~DescriptorPool(); + + /** @brief Copying is not allowed */ + DescriptorPool& operator=(const DescriptorPool&) = delete; + + /** @brief Move assignment */ + DescriptorPool& operator=(DescriptorPool&& other) noexcept; + + /** @brief Underlying @type_vk{DescriptorPool} handle */ + VkDescriptorPool handle() { return _handle; } + /** @overload */ + operator VkDescriptorPool() { return _handle; } + + /** @brief Handle flags */ + HandleFlags handleFlags() const { return _flags; } + + /** + * @brief Release the underlying Vulkan descriptor pool + * + * Releases ownership of the Vulkan descriptor pool and returns its + * handle so @fn_vk{DestroyDescriptorPool} is not called on + * destruction. The internal state is then equivalent to moved-from + * state. + * @see @ref wrap() + */ + VkDescriptorPool release(); + + private: + /* Can't be a reference because of the NoCreate constructor */ + Device* _device; + + VkDescriptorPool _handle; + HandleFlags _flags; +}; + +}} + +#endif diff --git a/src/Magnum/Vk/DescriptorPoolCreateInfo.h b/src/Magnum/Vk/DescriptorPoolCreateInfo.h new file mode 100644 index 000000000..3d84c3934 --- /dev/null +++ b/src/Magnum/Vk/DescriptorPoolCreateInfo.h @@ -0,0 +1,183 @@ +#ifndef Magnum_Vk_DescriptorPoolCreateInfo_h +#define Magnum_Vk_DescriptorPoolCreateInfo_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class @ref Magnum::Vk::DescriptorPoolCreateInfo + * @m_since_latest + */ + +#include +#include +#include + +#include "Magnum/Magnum.h" +#include "Magnum/Tags.h" +#include "Magnum/Vk/visibility.h" +#include "Magnum/Vk/Vk.h" +#include "Magnum/Vk/Vulkan.h" + +namespace Magnum { namespace Vk { + +/** +@brief Descriptor pool creation info +@m_since_latest + +Wraps a @type_vk_keyword{DescriptorPoolCreateInfo} and the nested +@type_vk_keyword{DescriptorPoolSize} structures. See +@ref Vk-DescriptorPool-creation "Descriptor pool creation" for usage +information. +*/ +class MAGNUM_VK_EXPORT DescriptorPoolCreateInfo { + public: + /** + * @brief Descriptor pool creation flag + * + * Wraps @type_vk_keyword{DescriptorPoolCreateFlagBits}. + * @see @ref Flags, @ref DescriptorPoolCreateInfo() + * @m_enum_values_as_keywords + */ + enum class Flag: UnsignedInt { + /** + * Allow individual descriptor sets to be freed instead of just the + * whole pool. + * @todoc reference relevant functions once they exist + * + * @m_class{m-note m-success} + * + * @par + * Not using this flag may help the driver to use simpler + * per-pool allocators instead of per-set. Without this flag + * set, descriptor pool fragmentation can't occur. + */ + FreeDescriptorSet = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + + /** + * Descriptor sets allocated from this pool can use bindings with + * the @ref DescriptorSetLayoutBinding::Flag::UpdateAfterBind set. + * @requires_vk_feature @ref DeviceFeature::DescriptorBindingSampledImageUpdateAfterBind + * if used on a @ref DescriptorType::CombinedImageSampler / + * @relativeref{DescriptorType,SampledImage} + * @requires_vk_feature @ref DeviceFeature::DescriptorBindingStorageImageUpdateAfterBind + * if used on a @ref DescriptorType::StorageImage + * @requires_vk_feature @ref DeviceFeature::DescriptorBindingUniformTexelBufferUpdateAfterBind + * if used on a @ref DescriptorType::UniformTexelBuffer + * @requires_vk_feature @ref DeviceFeature::DescriptorBindingStorageTexelBufferUpdateAfterBind + * if used on a @ref DescriptorType::StorageTexelBuffer + * @requires_vk_feature @ref DeviceFeature::DescriptorBindingUniformBufferUpdateAfterBind + * if used on a @ref DescriptorType::UniformBuffer / + * @relativeref{DescriptorType,UniformBufferDynamic} + * @requires_vk_feature @ref DeviceFeature::DescriptorBindingStorageBufferUpdateAfterBind + * if used on a @ref DescriptorType::StorageBuffer / + * @relativeref{DescriptorType,StorageBufferDynamic} + */ + UpdateAfterBind = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT + }; + + /** + * @brief DescriptorPool creation flags + * + * Type-safe wrapper for @type_vk_keyword{DescriptorPoolCreateFlags}. + * @see @ref DescriptorPoolCreateInfo() + */ + typedef Containers::EnumSet Flags; + + /** + * @brief Constructor + * @param maxSets Maximum count of descriptor sets that can be + * allocated from this pool. Has to be at least one. + * @param poolSizes Pool sizes for each descriptor type. There has + * to be at least one, and pool sizes can't be zero. + * @param flags DescriptorPool creation flags + * + * The following @type_vk{DescriptorPoolCreateInfo} fields are + * pre-filled in addition to `sType`, everything else is zero-filled: + * + * - `flags` + * - `maxSets` + * - `poolSizeCount` and `pPoolSizes` to @p poolSizes converted to + * a list of @type_vk{DescriptorPoolSize} structures + */ + explicit DescriptorPoolCreateInfo(UnsignedInt maxSets, Containers::ArrayView> poolSizes, Flags flags = {}); + /** @overload */ + explicit DescriptorPoolCreateInfo(UnsignedInt maxSets, std::initializer_list> poolSizes, 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 DescriptorPoolCreateInfo(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 DescriptorPoolCreateInfo(const VkDescriptorPoolCreateInfo& info); + + /** @brief Copying is not allowed */ + DescriptorPoolCreateInfo(const DescriptorPoolCreateInfo&) = delete; + + /** @brief Move constructor */ + DescriptorPoolCreateInfo(DescriptorPoolCreateInfo&& other) noexcept; + + ~DescriptorPoolCreateInfo(); + + /** @brief Copying is not allowed */ + DescriptorPoolCreateInfo& operator=(const DescriptorPoolCreateInfo&) = delete; + + /** @brief Move assignment */ + DescriptorPoolCreateInfo& operator=(DescriptorPoolCreateInfo&& other) noexcept; + + /** @brief Underlying @type_vk{DescriptorPoolCreateInfo} structure */ + VkDescriptorPoolCreateInfo& operator*() { return _info; } + /** @overload */ + const VkDescriptorPoolCreateInfo& operator*() const { return _info; } + /** @overload */ + VkDescriptorPoolCreateInfo* operator->() { return &_info; } + /** @overload */ + const VkDescriptorPoolCreateInfo* operator->() const { return &_info; } + /** @overload */ + operator const VkDescriptorPoolCreateInfo*() const { return &_info; } + + private: + VkDescriptorPoolCreateInfo _info; + Containers::ArrayTuple _data; +}; + +CORRADE_ENUMSET_OPERATORS(DescriptorPoolCreateInfo::Flags) + +}} + +/* Make the definition complete -- it doesn't make sense to have a CreateInfo + without the corresponding object anyway. */ +#include "Magnum/Vk/DescriptorPool.h" + +#endif diff --git a/src/Magnum/Vk/DescriptorSetLayout.h b/src/Magnum/Vk/DescriptorSetLayout.h index 6d42d54a9..d537e6e5a 100644 --- a/src/Magnum/Vk/DescriptorSetLayout.h +++ b/src/Magnum/Vk/DescriptorSetLayout.h @@ -89,7 +89,7 @@ specify additional flags per binding. All of them require a certain @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 +subsequently for descriptor set allocation from a @ref DescriptorPool. See the corresponding class documentation for more information. */ class MAGNUM_VK_EXPORT DescriptorSetLayout { diff --git a/src/Magnum/Vk/DescriptorSetLayoutCreateInfo.h b/src/Magnum/Vk/DescriptorSetLayoutCreateInfo.h index a7cd9ec9b..7165e7a64 100644 --- a/src/Magnum/Vk/DescriptorSetLayoutCreateInfo.h +++ b/src/Magnum/Vk/DescriptorSetLayoutCreateInfo.h @@ -74,6 +74,11 @@ class MAGNUM_VK_EXPORT DescriptorSetLayoutBinding { * submission will use the most recently set descriptors for * the binding and the updates do not invalidate the command * buffer. + * + * Descriptor set layouts using this flag can be only allocated + * from a @ref DescriptorPool that has + * @ref DescriptorPoolCreateInfo::Flag::UpdateAfterBind set as + * well. * @requires_vk_feature @ref DeviceFeature::DescriptorBindingSampledImageUpdateAfterBind * if used on a @ref DescriptorType::CombinedImageSampler / * @relativeref{DescriptorType,SampledImage} @@ -114,6 +119,10 @@ class MAGNUM_VK_EXPORT DescriptorSetLayoutBinding { * This descriptor binding has a variable size that will be * specified when a descriptor set is allocated using this layout, * and the @p descriptorCount value is treated as an upper bound. + * + * Allowed only on the last binding number in the layout, not + * allowed on a @ref DescriptorType::UniformBufferDynamic or + * @ref DescriptorType::StorageBufferDynamic. * @requires_vk_feature @ref DeviceFeature::DescriptorBindingVariableDescriptorCount */ VariableDescriptorCount = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT @@ -135,7 +144,9 @@ class MAGNUM_VK_EXPORT DescriptorSetLayoutBinding { * @param descriptorType Descriptor type * @param descriptorCount Number of descriptors contained in the * binding. If the shader binding is not an array, use @cpp 1 @ce, - * zero is allowed as well. + * zero is allowed as well. For a @ref Flag::VariableDescriptorCount + * this is used as an upper bound and a concrete size is specified + * during descriptor set allocation. * @param stages Shader stages that access the binding. * Use @cpp ~Vk::ShaderStages{} @ce to specify that all stages * may access the binding. diff --git a/src/Magnum/Vk/DescriptorType.h b/src/Magnum/Vk/DescriptorType.h index 494fe641e..13f6f6c03 100644 --- a/src/Magnum/Vk/DescriptorType.h +++ b/src/Magnum/Vk/DescriptorType.h @@ -41,7 +41,7 @@ namespace Magnum { namespace Vk { @m_since_latest Wraps @type_vk_keyword{DescriptorType}. -@see @ref DescriptorSetLayoutBinding +@see @ref DescriptorSetLayoutBinding, @ref DescriptorPoolCreateInfo @m_enum_values_as_keywords */ enum class DescriptorType: Int { diff --git a/src/Magnum/Vk/Test/CMakeLists.txt b/src/Magnum/Vk/Test/CMakeLists.txt index 5c40346b3..8279445a6 100644 --- a/src/Magnum/Vk/Test/CMakeLists.txt +++ b/src/Magnum/Vk/Test/CMakeLists.txt @@ -27,6 +27,7 @@ corrade_add_test(VkBufferTest BufferTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkCommandBufferTest CommandBufferTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkCommandPoolTest CommandPoolTest.cpp LIBRARIES MagnumVk) +corrade_add_test(VkDescriptorPoolTest DescriptorPoolTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkDescriptorSetLayoutTest DescriptorSetLayoutTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkDescriptorTypeTest DescriptorTypeTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkDeviceTest DeviceTest.cpp LIBRARIES MagnumVk) @@ -131,6 +132,7 @@ set_target_properties( VkBufferTest VkCommandBufferTest VkCommandPoolTest + VkDescriptorPoolTest VkDescriptorSetLayoutTest VkDescriptorTypeTest VkDeviceTest @@ -196,6 +198,7 @@ if(BUILD_VK_TESTS) corrade_add_test(VkBufferVkTest BufferVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester) corrade_add_test(VkCommandBufferVkTest CommandBufferVkTest.cpp LIBRARIES MagnumVulkanTester) corrade_add_test(VkCommandPoolVkTest CommandPoolVkTest.cpp LIBRARIES MagnumVulkanTester) + corrade_add_test(VkDescriptorPoolVkTest DescriptorPoolVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester) corrade_add_test(VkDescriptorSetLayoutVkTest DescriptorSetLayoutVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester) corrade_add_test(VkDeviceVkTest DeviceVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester) corrade_add_test(VkDevicePropertiesVkTest DevicePropertiesVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester) @@ -248,6 +251,7 @@ if(BUILD_VK_TESTS) VkBufferVkTest VkCommandBufferVkTest VkCommandPoolVkTest + VkDescriptorPoolVkTest VkDescriptorSetLayoutVkTest VkDeviceVkTest VkDevicePropertiesVkTest diff --git a/src/Magnum/Vk/Test/DescriptorPoolTest.cpp b/src/Magnum/Vk/Test/DescriptorPoolTest.cpp new file mode 100644 index 000000000..150cb2190 --- /dev/null +++ b/src/Magnum/Vk/Test/DescriptorPoolTest.cpp @@ -0,0 +1,183 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include + +#include "Magnum/Vk/DescriptorPoolCreateInfo.h" +#include "Magnum/Vk/DescriptorType.h" + +namespace Magnum { namespace Vk { namespace Test { namespace { + +struct DescriptorPoolTest: TestSuite::Tester { + explicit DescriptorPoolTest(); + + void createInfoConstruct(); + void createInfoConstructNoSets(); + void createInfoConstructNoPools(); + void createInfoConstructEmptyPool(); + void createInfoConstructNoInit(); + void createInfoConstructFromVk(); + void createInfoConstructCopy(); + void createInfoConstructMove(); + + void constructNoCreate(); + void constructCopy(); +}; + +DescriptorPoolTest::DescriptorPoolTest() { + addTests({&DescriptorPoolTest::createInfoConstruct, + &DescriptorPoolTest::createInfoConstructNoSets, + &DescriptorPoolTest::createInfoConstructNoPools, + &DescriptorPoolTest::createInfoConstructEmptyPool, + &DescriptorPoolTest::createInfoConstructNoInit, + &DescriptorPoolTest::createInfoConstructFromVk, + &DescriptorPoolTest::createInfoConstructCopy, + &DescriptorPoolTest::createInfoConstructMove, + + &DescriptorPoolTest::constructNoCreate, + &DescriptorPoolTest::constructCopy}); +} + +void DescriptorPoolTest::createInfoConstruct() { + DescriptorPoolCreateInfo info{5, { + {DescriptorType::CombinedImageSampler, 7}, + {DescriptorType::UniformBuffer, 3} + }, DescriptorPoolCreateInfo::Flag::FreeDescriptorSet|DescriptorPoolCreateInfo::Flag::UpdateAfterBind}; + CORRADE_COMPARE(info->flags, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT|VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT); + CORRADE_COMPARE(info->maxSets, 5); + CORRADE_COMPARE(info->poolSizeCount, 2); + CORRADE_VERIFY(info->pPoolSizes); + CORRADE_COMPARE(info->pPoolSizes[0].type, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + CORRADE_COMPARE(info->pPoolSizes[0].descriptorCount, 7); + CORRADE_COMPARE(info->pPoolSizes[1].type, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + CORRADE_COMPARE(info->pPoolSizes[1].descriptorCount, 3); +} + +void DescriptorPoolTest::createInfoConstructNoSets() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + std::ostringstream out; + Error redirectError{&out}; + DescriptorPoolCreateInfo{0, {}}; + CORRADE_COMPARE(out.str(), "Vk::DescriptorPoolCreateInfo: there has to be at least one set\n"); +} + +void DescriptorPoolTest::createInfoConstructNoPools() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + std::ostringstream out; + Error redirectError{&out}; + DescriptorPoolCreateInfo{5, {}}; + CORRADE_COMPARE(out.str(), "Vk::DescriptorPoolCreateInfo: there has to be at least one pool\n"); +} + +void DescriptorPoolTest::createInfoConstructEmptyPool() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + std::ostringstream out; + Error redirectError{&out}; + DescriptorPoolCreateInfo{5, { + {DescriptorType::InputAttachment, 2}, + {DescriptorType::UniformBuffer, 0}, + }}; + CORRADE_COMPARE(out.str(), "Vk::DescriptorPoolCreateInfo: pool 1 of Vk::DescriptorType::UniformBuffer has no descriptors\n"); +} + +void DescriptorPoolTest::createInfoConstructNoInit() { + DescriptorPoolCreateInfo info{NoInit}; + info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; + new(&info) DescriptorPoolCreateInfo{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 DescriptorPoolTest::createInfoConstructFromVk() { + VkDescriptorPoolCreateInfo vkInfo; + vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; + + DescriptorPoolCreateInfo info{vkInfo}; + CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2); +} + +void DescriptorPoolTest::createInfoConstructCopy() { + CORRADE_VERIFY(!std::is_copy_constructible{}); + CORRADE_VERIFY(!std::is_copy_assignable{}); +} + +void DescriptorPoolTest::createInfoConstructMove() { + DescriptorPoolCreateInfo a{5, { + {DescriptorType::CombinedImageSampler, 7}, + {DescriptorType::UniformBuffer, 3} + }}; + CORRADE_COMPARE(a->poolSizeCount, 2); + CORRADE_VERIFY(a->pPoolSizes); + + DescriptorPoolCreateInfo b = std::move(a); + CORRADE_COMPARE(a->poolSizeCount, 0); + CORRADE_VERIFY(!a->pPoolSizes); + CORRADE_COMPARE(b->poolSizeCount, 2); + CORRADE_VERIFY(b->pPoolSizes); + CORRADE_COMPARE(b->pPoolSizes[1].type, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + + DescriptorPoolCreateInfo c{VkDescriptorPoolCreateInfo{}}; + c = std::move(b); + CORRADE_COMPARE(b->poolSizeCount, 0); + CORRADE_VERIFY(!b->pPoolSizes); + CORRADE_COMPARE(c->poolSizeCount, 2); + CORRADE_VERIFY(c->pPoolSizes); + CORRADE_COMPARE(c->pPoolSizes[1].type, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); +} + +void DescriptorPoolTest::constructNoCreate() { + { + DescriptorPool pool{NoCreate}; + CORRADE_VERIFY(!pool.handle()); + } + + /* Implicit construction is not allowed */ + CORRADE_VERIFY(!std::is_convertible::value); +} + +void DescriptorPoolTest::constructCopy() { + CORRADE_VERIFY(!std::is_copy_constructible{}); + CORRADE_VERIFY(!std::is_copy_assignable{}); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Vk::Test::DescriptorPoolTest) diff --git a/src/Magnum/Vk/Test/DescriptorPoolVkTest.cpp b/src/Magnum/Vk/Test/DescriptorPoolVkTest.cpp new file mode 100644 index 000000000..66a58ba5b --- /dev/null +++ b/src/Magnum/Vk/Test/DescriptorPoolVkTest.cpp @@ -0,0 +1,103 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Magnum/Vk/DescriptorPoolCreateInfo.h" +#include "Magnum/Vk/DescriptorType.h" +#include "Magnum/Vk/Result.h" +#include "Magnum/Vk/VulkanTester.h" + +namespace Magnum { namespace Vk { namespace Test { namespace { + +struct DescriptorPoolVkTest: VulkanTester { + explicit DescriptorPoolVkTest(); + + void construct(); + void constructMove(); + + void wrap(); +}; + +DescriptorPoolVkTest::DescriptorPoolVkTest() { + addTests({&DescriptorPoolVkTest::construct, + &DescriptorPoolVkTest::constructMove, + + &DescriptorPoolVkTest::wrap}); +} + +void DescriptorPoolVkTest::construct() { + { + DescriptorPool pool{device(), DescriptorPoolCreateInfo{5, { + {DescriptorType::UniformBuffer, 2} + }}}; + CORRADE_VERIFY(pool.handle()); + CORRADE_COMPARE(pool.handleFlags(), HandleFlag::DestroyOnDestruction); + } + + /* Shouldn't crash or anything */ + CORRADE_VERIFY(true); +} + +void DescriptorPoolVkTest::constructMove() { + DescriptorPool a{device(), DescriptorPoolCreateInfo{5, { + {DescriptorType::UniformBuffer, 2} + }}}; + VkDescriptorPool handle = a.handle(); + + DescriptorPool b = std::move(a); + CORRADE_VERIFY(!a.handle()); + CORRADE_COMPARE(b.handle(), handle); + CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction); + + DescriptorPool c{NoCreate}; + c = std::move(b); + CORRADE_VERIFY(!b.handle()); + CORRADE_COMPARE(b.handleFlags(), HandleFlags{}); + CORRADE_COMPARE(c.handle(), handle); + CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction); + + CORRADE_VERIFY(std::is_nothrow_move_constructible::value); + CORRADE_VERIFY(std::is_nothrow_move_assignable::value); +} + +void DescriptorPoolVkTest::wrap() { + VkDescriptorPool pool{}; + CORRADE_COMPARE(Result(device()->CreateDescriptorPool(device(), + DescriptorPoolCreateInfo{5, { + {DescriptorType::UniformBuffer, 2} + }}, + nullptr, &pool)), Result::Success); + + auto wrapped = DescriptorPool::wrap(device(), pool, HandleFlag::DestroyOnDestruction); + CORRADE_COMPARE(wrapped.handle(), pool); + + /* Release the handle again, destroy by hand */ + CORRADE_COMPARE(wrapped.release(), pool); + CORRADE_VERIFY(!wrapped.handle()); + device()->DestroyDescriptorPool(device(), pool, nullptr); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Vk::Test::DescriptorPoolVkTest) diff --git a/src/Magnum/Vk/Vk.h b/src/Magnum/Vk/Vk.h index 33b453d64..723772562 100644 --- a/src/Magnum/Vk/Vk.h +++ b/src/Magnum/Vk/Vk.h @@ -57,6 +57,8 @@ class CopyImageToBufferInfo; /* Not forward-declaring CopyBufferToImageInfo1D etc right now, I see no need */ enum class DependencyFlag: UnsignedInt; typedef Containers::EnumSet DependencyFlags; +class DescriptorPool; +class DescriptorPoolCreateInfo; class DescriptorSetLayout; class DescriptorSetLayoutCreateInfo; enum class DescriptorType: Int;