Browse Source

Vk: implement a DescriptorSetLayout.

Together with DescriptorBindingFlags, because it affects the design in a
rather specific way and it wouldn't make sense to postpone this and
forget all again until it becomes needed.
pull/504/head
Vladimír Vondruš 5 years ago
parent
commit
391e680721
  1. 50
      doc/snippets/MagnumVk.cpp
  2. 17
      doc/vulkan-mapping.dox
  3. 2
      doc/vulkan-support.dox
  4. 20
      src/Magnum/Vk/BufferCreateInfo.h
  5. 3
      src/Magnum/Vk/CMakeLists.txt
  6. 216
      src/Magnum/Vk/DescriptorSetLayout.cpp
  7. 176
      src/Magnum/Vk/DescriptorSetLayout.h
  8. 480
      src/Magnum/Vk/DescriptorSetLayoutCreateInfo.h
  9. 44
      src/Magnum/Vk/DeviceFeatures.h
  10. 3
      src/Magnum/Vk/Image.h
  11. 7
      src/Magnum/Vk/ImageCreateInfo.h
  12. 4
      src/Magnum/Vk/Test/CMakeLists.txt
  13. 320
      src/Magnum/Vk/Test/DescriptorSetLayoutTest.cpp
  14. 104
      src/Magnum/Vk/Test/DescriptorSetLayoutVkTest.cpp
  15. 3
      src/Magnum/Vk/Vk.h

50
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/DescriptorSetLayoutCreateInfo.h"
#include "Magnum/Vk/DeviceCreateInfo.h"
#include "Magnum/Vk/DeviceFeatures.h"
#include "Magnum/Vk/DeviceProperties.h"
@ -312,6 +313,55 @@ fence.wait();
/* [CommandBuffer-usage-submit] */
}
{
Vk::Device device{NoCreate};
/* The include should be a no-op here since it was already included above */
/* [DescriptorSetLayout-creation] */
#include <Magnum/Vk/DescriptorSetLayoutCreateInfo.h>
DOXYGEN_IGNORE()
Vk::DescriptorSetLayout layout{device, Vk::DescriptorSetLayoutCreateInfo{
{{0, Vk::DescriptorType::UniformBuffer}},
{{1, Vk::DescriptorType::CombinedImageSampler, 1,
Vk::ShaderStage::Fragment}}
}};
/* [DescriptorSetLayout-creation] */
}
{
Vk::Device device{NoCreate};
/* [DescriptorSetLayout-creation-immutable-samplers] */
Vk::Sampler sampler{DOXYGEN_IGNORE(NoCreate)};
Vk::DescriptorSetLayout layout{device, Vk::DescriptorSetLayoutCreateInfo{
{{0, Vk::DescriptorType::UniformBuffer}},
{{1, Vk::DescriptorType::CombinedImageSampler, {sampler},
Vk::ShaderStage::Fragment}}
}};
/* [DescriptorSetLayout-creation-immutable-samplers] */
}
{
Vk::Instance instance{NoCreate};
/* [DescriptorSetLayout-creation-binding-flags] */
Vk::Device device{instance, Vk::DeviceCreateInfo{DOXYGEN_IGNORE(Vk::pickDevice(instance))}
DOXYGEN_IGNORE()
.setEnabledFeatures(
Vk::DeviceFeature::DescriptorBindingUniformBufferUpdateAfterBind|
DOXYGEN_IGNORE(Vk::DeviceFeatures{})
)
};
Vk::DescriptorSetLayout layout{device, Vk::DescriptorSetLayoutCreateInfo{
{{0, Vk::DescriptorType::UniformBuffer, 1,
~Vk::ShaderStages{},
Vk::DescriptorSetLayoutBinding::Flag::UpdateAfterBind}},
DOXYGEN_IGNORE()
}};
/* [DescriptorSetLayout-creation-binding-flags] */
}
{
Vk::Instance instance;
/* The include should be a no-op here since it was already included above */

17
doc/vulkan-mapping.dox

@ -60,7 +60,7 @@ Vulkan handle | Matching API
@type_vk{DebugUtilsMessengerEXT} @m_class{m-label m-flat m-warning} **EXT** | |
@type_vk{DescriptorPool} | |
@type_vk{DescriptorSet} | |
@type_vk{DescriptorSetLayout} | |
@type_vk{DescriptorSetLayout} | @ref DescriptorSetLayout
@type_vk{DescriptorUpdateTemplate} @m_class{m-label m-flat m-success} **KHR, 1.1** | |
@type_vk{Device} | @ref Device
@type_vk{DeviceMemory} | @ref Memory
@ -191,7 +191,7 @@ Vulkan function | Matching API
@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{CreateDescriptorSetLayout}, \n @fn_vk{DestroyDescriptorSetLayout} | |
@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
@fn_vk{CreateEvent}, \n @fn_vk{DestroyEvent} | |
@ -466,10 +466,9 @@ Vulkan structure | Matching API
@type_vk{DescriptorPoolCreateInfo} | |
@type_vk{DescriptorPoolSize} | |
@type_vk{DescriptorSetAllocateInfo} | |
@type_vk{DescriptorSetLayoutBinding} | |
@type_vk{DescriptorSetLayoutBindingFlagsCreateInfo} | |
@type_vk{DescriptorSetLayoutCreateInfo} | |
@type_vk{DescriptorSetLayoutBindingFlagsCreateInfo} @m_class{m-label m-flat m-success} **EXT, 1.2** | |
@type_vk{DescriptorSetLayoutBinding} | @ref DescriptorSetLayoutBinding
@type_vk{DescriptorSetLayoutBindingFlagsCreateInfo} @m_class{m-label m-flqat m-success} **EXT, 1.2** | @ref DescriptorSetLayoutCreateInfo
@type_vk{DescriptorSetLayoutCreateInfo} | @ref DescriptorSetLayoutCreateInfo
@type_vk{DescriptorSetLayoutSupport} @m_class{m-label m-flat m-success} **KHR, 1.1** | |
@type_vk{DescriptorSetVariableDescriptorCountAllocateInfo} @m_class{m-label m-flat m-success} **EXT, 1.2** | |
@type_vk{DescriptorSetVariableDescriptorCountLayoutSupport} @m_class{m-label m-flat m-success} **EXT, 1.2** | |
@ -826,11 +825,11 @@ Vulkan enum | Matching API
@type_vk{DebugReportObjectTypeEXT} @m_class{m-label m-danger} **deprecated** @m_class{m-label m-flat m-warning} **EXT** | |
@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** | |
@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{DescriptorSetLayoutCreateFlagBits}, \n @type_vk{DescriptorSetLayoutCreateFlags} | |
@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} | |
@type_vk{DescriptorType} | @ref DescriptorType
@type_vk{DeviceQueueCreateFlagBits}, \n @type_vk{DeviceQueueCreateFlags} | |
@type_vk{DriverId} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref DeviceDriver
@type_vk{DynamicState} | @ref DynamicRasterizationState

2
doc/vulkan-support.dox

@ -90,7 +90,7 @@ Extension | Status
@vk_extension{KHR,create_renderpass2} | done
@vk_extension{EXT,sampler_filter_minmax} | |
@vk_extension{KHR,image_format_list} | |
@vk_extension{EXT,descriptor_indexing} | |
@vk_extension{EXT,descriptor_indexing} | done except properties and variable descriptor count allocation
@vk_extension{EXT,shader_viewport_index_layer} | |
@vk_extension{KHR,draw_indirect_count} | |
@vk_extension{KHR,shader_subgroup_extended_types} | |

20
src/Magnum/Vk/BufferCreateInfo.h

@ -64,16 +64,28 @@ enum class BufferUsage: UnsignedInt {
*/
TransferDestination = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
/** Suitable for creating a uniform texel buffer view */
/**
* Suitable for creating a uniform texel buffer view.
* @see @ref DescriptorType::UniformTexelBuffer
*/
UniformTexelBuffer = VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT,
/** Suitable for creating a storage texel buffer view */
/**
* Suitable for creating a storage texel buffer view.
* @see @ref DescriptorType::StorageTexelBuffer
*/
StorageTexelBuffer = VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT,
/** Suitable for a uniform buffer */
/**
* Suitable for a uniform buffer.
* @see @ref DescriptorType::UniformBuffer
*/
UniformBuffer = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
/** Suitable for a storage buffer */
/**
* Suitable for a storage buffer.
* @see @ref DescriptorType::StorageBuffer
*/
StorageBuffer = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
/**

3
src/Magnum/Vk/CMakeLists.txt

@ -29,6 +29,7 @@ find_package(Vulkan REQUIRED)
set(MagnumVk_SRCS
CommandBuffer.cpp
CommandPool.cpp
DescriptorSetLayout.cpp
Extensions.cpp
Fence.cpp
Framebuffer.cpp
@ -72,6 +73,8 @@ set(MagnumVk_HEADERS
CommandPool.h
CommandPoolCreateInfo.h
ComputePipelineCreateInfo.h
DescriptorSetLayout.h
DescriptorSetLayoutCreateInfo.h
Device.h
DeviceCreateInfo.h
DeviceFeatures.h

216
src/Magnum/Vk/DescriptorSetLayout.cpp

@ -0,0 +1,216 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
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 "DescriptorSetLayout.h"
#include "DescriptorSetLayoutCreateInfo.h"
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/AnyReference.h>
#include <Corrade/Utility/Algorithms.h>
#include "Magnum/Vk/Assert.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/Result.h"
namespace Magnum { namespace Vk {
DescriptorSetLayoutBinding::DescriptorSetLayoutBinding(const UnsignedInt binding, const DescriptorType descriptorType, const UnsignedInt descriptorCount, const ShaderStages stages, Flags flags): _binding{}, _flags{VkDescriptorBindingFlags(flags)} {
_binding.binding = binding;
_binding.descriptorType = VkDescriptorType(descriptorType);
_binding.descriptorCount = descriptorCount;
_binding.stageFlags = VkShaderStageFlags(stages);
}
DescriptorSetLayoutBinding::DescriptorSetLayoutBinding(const UnsignedInt binding, const DescriptorType descriptorType, const Containers::ArrayView<const VkSampler> immutableSamplers, const ShaderStages stages, Flags flags): _binding{}, _flags{VkDescriptorBindingFlags(flags)} {
Containers::ArrayView<VkSampler> immutableSamplersCopy;
_data = Containers::ArrayTuple{
{Containers::NoInit, immutableSamplers.size(), immutableSamplersCopy}
};
Utility::copy(immutableSamplers, immutableSamplersCopy);
_binding.binding = binding;
_binding.descriptorType = VkDescriptorType(descriptorType);
_binding.descriptorCount = immutableSamplers.size();
_binding.pImmutableSamplers = immutableSamplersCopy;
_binding.stageFlags = VkShaderStageFlags(stages);
}
DescriptorSetLayoutBinding::DescriptorSetLayoutBinding(const UnsignedInt binding, const DescriptorType descriptorType, const std::initializer_list<VkSampler> immutableSamplers, const ShaderStages stages, Flags flags): DescriptorSetLayoutBinding{binding, descriptorType, Containers::arrayView(immutableSamplers), stages, flags} {}
DescriptorSetLayoutBinding::DescriptorSetLayoutBinding(NoInitT) noexcept {}
DescriptorSetLayoutBinding::DescriptorSetLayoutBinding(const VkDescriptorSetLayoutBinding& binding, const VkDescriptorBindingFlags flags):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_binding(binding),
_flags{flags} {}
DescriptorSetLayoutBinding::DescriptorSetLayoutBinding(DescriptorSetLayoutBinding&& other) noexcept:
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_binding(other._binding),
_data{std::move(other._data)},
_flags{other._flags}
{
/* 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._binding.pImmutableSamplers = nullptr;
}
DescriptorSetLayoutBinding::~DescriptorSetLayoutBinding() = default;
DescriptorSetLayoutBinding& DescriptorSetLayoutBinding::operator=(DescriptorSetLayoutBinding&& other) noexcept {
using std::swap;
swap(other._binding, _binding);
swap(other._data, _data);
swap(other._flags, _flags);
return *this;
}
DescriptorSetLayoutCreateInfo::DescriptorSetLayoutCreateInfo(const Containers::ArrayView<const Containers::AnyReference<const DescriptorSetLayoutBinding>> bindings, const Flags flags): _info{} {
/* Check the total count of immutable samplers to allocate them all in a
contiguous memory location. Also check if we have any binding flags. If
yes, we have to create an additional array and put a structure into the
pNext chain. */
std::size_t immutableSamplerCount = 0;
bool hasBindingFlags = false;
for(const DescriptorSetLayoutBinding& b: bindings) {
if(b->pImmutableSamplers) immutableSamplerCount += b->descriptorCount;
if(b.flags()) hasBindingFlags = true;
}
/* Allocate a single block of memory for everything. (I'm still amazed at
how simple this is and yet how useful.) */
Containers::ArrayView<VkDescriptorSetLayoutBinding> bindingsCopy;
Containers::ArrayView<VkDescriptorBindingFlags> bindingFlagsCopy;
Containers::ArrayView<VkDescriptorSetLayoutBindingFlagsCreateInfo> bindingsCreateInfoView;
Containers::ArrayView<VkSampler> immutableSamplersCopy;
_data = Containers::ArrayTuple{
{Containers::NoInit, bindings.size(), bindingsCopy},
{Containers::NoInit, hasBindingFlags ? bindings.size() : 0, bindingFlagsCopy},
{Containers::ValueInit, hasBindingFlags ? 1u : 0u, bindingsCreateInfoView},
{Containers::NoInit, immutableSamplerCount, immutableSamplersCopy}
};
/* Copy the binding and then for each manually copy and reroute the
immutable samplers, if any; copy the flags as well if there are any */
std::size_t immutableSamplerOffset = 0;
for(std::size_t i = 0; i != bindings.size(); ++i) {
const DescriptorSetLayoutBinding& b = bindings[i];
bindingsCopy[i] = b;
if(b->pImmutableSamplers) {
Utility::copy(
{b->pImmutableSamplers, b->descriptorCount},
immutableSamplersCopy.slice(immutableSamplerOffset, immutableSamplerOffset + b->descriptorCount));
bindingsCopy[i].pImmutableSamplers = immutableSamplersCopy + immutableSamplerOffset;
immutableSamplerOffset += b->descriptorCount;
}
if(hasBindingFlags) bindingFlagsCopy[i] = b.flags();
}
CORRADE_INTERNAL_ASSERT(immutableSamplerOffset == immutableSamplerCount);
_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
_info.flags = VkDescriptorSetLayoutCreateFlags(flags);
_info.bindingCount = bindings.size();
_info.pBindings = bindingsCopy;
if(hasBindingFlags) {
bindingsCreateInfoView[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO;
bindingsCreateInfoView[0].bindingCount = bindings.size();
bindingsCreateInfoView[0].pBindingFlags = bindingFlagsCopy;
_info.pNext = bindingsCreateInfoView;
}
}
DescriptorSetLayoutCreateInfo::DescriptorSetLayoutCreateInfo(const std::initializer_list<Containers::AnyReference<const DescriptorSetLayoutBinding>> bindings, const Flags flags): DescriptorSetLayoutCreateInfo{Containers::arrayView(bindings), flags} {}
DescriptorSetLayoutCreateInfo::DescriptorSetLayoutCreateInfo(NoInitT) noexcept {}
DescriptorSetLayoutCreateInfo::DescriptorSetLayoutCreateInfo(const VkDescriptorSetLayoutCreateInfo& info):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(info) {}
DescriptorSetLayoutCreateInfo::DescriptorSetLayoutCreateInfo(DescriptorSetLayoutCreateInfo&& 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.bindingCount = 0;
other._info.pBindings = nullptr;
}
DescriptorSetLayoutCreateInfo::~DescriptorSetLayoutCreateInfo() = default;
DescriptorSetLayoutCreateInfo& DescriptorSetLayoutCreateInfo::operator=(DescriptorSetLayoutCreateInfo&& other) noexcept {
using std::swap;
swap(other._info, _info);
swap(other._data, _data);
return *this;
}
DescriptorSetLayout DescriptorSetLayout::wrap(Device& device, const VkDescriptorSetLayout handle, const HandleFlags flags) {
DescriptorSetLayout out{NoCreate};
out._device = &device;
out._handle = handle;
out._flags = flags;
return out;
}
DescriptorSetLayout::DescriptorSetLayout(Device& device, const DescriptorSetLayoutCreateInfo& info): _device{&device}, _flags{HandleFlag::DestroyOnDestruction} {
MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(device->CreateDescriptorSetLayout(device, info, nullptr, &_handle));
}
DescriptorSetLayout::DescriptorSetLayout(NoCreateT): _device{}, _handle{} {}
DescriptorSetLayout::DescriptorSetLayout(DescriptorSetLayout&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags} {
other._handle = {};
}
DescriptorSetLayout::~DescriptorSetLayout() {
if(_handle && (_flags & HandleFlag::DestroyOnDestruction))
(**_device).DestroyDescriptorSetLayout(*_device, _handle, nullptr);
}
DescriptorSetLayout& DescriptorSetLayout::operator=(DescriptorSetLayout&& other) noexcept {
using std::swap;
swap(other._device, _device);
swap(other._handle, _handle);
swap(other._flags, _flags);
return *this;
}
VkDescriptorSetLayout DescriptorSetLayout::release() {
const VkDescriptorSetLayout handle = _handle;
_handle = {};
return handle;
}
}}

176
src/Magnum/Vk/DescriptorSetLayout.h

@ -0,0 +1,176 @@
#ifndef Magnum_Vk_DescriptorSetLayout_h
#define Magnum_Vk_DescriptorSetLayout_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
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::DescriptorSetLayout
* @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 set layout
@m_since_latest
Wraps a @type_vk_keyword{DescriptorSetLayout}. A descriptor set layout lists
descriptors (such as uniform buffers or samplers) used by shaders in a
@ref Pipeline.
@section Vk-DescriptorSetLayout-creation Descriptor set layout creation
The @ref DescriptorSetLayoutCreateInfo class takes one or more
@ref DescriptorSetLayoutBinding entries, where each specifies the binding
number, descriptor type, descriptor count in case of descriptor arrays and
which shader stages are designed to access the binding. In the following
example one uniform buffer binding @cpp 0 @ce is accessible by any stages and
one combined image/sampler binding @cpp 1 @ce is accessed only by
@link ShaderStage::Fragment @endlink:
@snippet MagnumVk.cpp DescriptorSetLayout-creation
<b></b>
@m_class{m-note m-info}
@par
Note that in C++11 you have to use double brackets (@cpp {{ }} @ce) to
initialize the @ref DescriptorSetLayoutBinding entries, as shown above.
With C++14 and newer it should work with just a single pair of brackets.
@subsection Vk-DescriptorSetLayout-creation-immutable-samplers Immutable samplers
For @ref DescriptorType::Sampler and @ref DescriptorType::CombinedImageSampler
it's possible to specify a list of immutable @ref Sampler "Samplers" in place
of the descriptor count argument. The descriptor count is then implicitly taken
from size of the array. The above snippet with immutable samplers would look
like this:
@snippet MagnumVk.cpp DescriptorSetLayout-creation-immutable-samplers
@subsection Vk-DescriptorSetLayout-creation-binding-flags Descriptor binding flags
With Vulkan 1.2 or @vk_extension{EXT,descriptor_indexing} it's possible to
specify additional flags per binding. All of them require a certain
@ref DeviceFeature to be supported and enabled, see particular
@ref DescriptorSetLayoutBinding::Flag for more information:
@snippet MagnumVk.cpp DescriptorSetLayout-creation-binding-flags
*/
class MAGNUM_VK_EXPORT DescriptorSetLayout {
public:
/**
* @brief Wrap existing Vulkan handle
* @param device Vulkan device the descriptor set layout is
* created on
* @param handle The @type_vk{DescriptorSetLayout} handle
* @param flags Handle flags
*
* The @p handle is expected to be originating from @p device. Unlike
* a descriptor set layout created using a constructor, the Vulkan
* descriptor set layout is by default not deleted on destruction, use
* @p flags for different behavior.
* @see @ref release()
*/
static DescriptorSetLayout wrap(Device& device, VkDescriptorSetLayout handle, HandleFlags flags = {});
/**
* @brief Constructor
* @param device Vulkan device to create the descriptor set layout
* on
* @param info Descriptor set layout creation info
*
* @see @fn_vk_keyword{CreateDescriptorSetLayout}
*/
explicit DescriptorSetLayout(Device& device, const DescriptorSetLayoutCreateInfo& info);
/**
* @brief Construct without creating the descriptor set layout
*
* 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 DescriptorSetLayout(NoCreateT);
/** @brief Copying is not allowed */
DescriptorSetLayout(const DescriptorSetLayout&) = delete;
/** @brief Move constructor */
DescriptorSetLayout(DescriptorSetLayout&& other) noexcept;
/**
* @brief Destructor
*
* Destroys associated @type_vk{DescriptorSetLayout} handle, unless the
* instance was created using @ref wrap() without
* @ref HandleFlag::DestroyOnDestruction specified.
* @see @fn_vk_keyword{DestroyDescriptorSetLayout}, @ref release()
*/
~DescriptorSetLayout();
/** @brief Copying is not allowed */
DescriptorSetLayout& operator=(const DescriptorSetLayout&) = delete;
/** @brief Move assignment */
DescriptorSetLayout& operator=(DescriptorSetLayout&& other) noexcept;
/** @brief Underlying @type_vk{DescriptorSetLayout} handle */
VkDescriptorSetLayout handle() { return _handle; }
/** @overload */
operator VkDescriptorSetLayout() { return _handle; }
/** @brief Handle flags */
HandleFlags handleFlags() const { return _flags; }
/**
* @brief Release the underlying Vulkan descriptor set layout
*
* Releases ownership of the Vulkan descriptor set layout and returns
* its handle so @fn_vk{DestroyDescriptorSetLayout} is not called on
* destruction. The internal state is then equivalent to moved-from
* state.
* @see @ref wrap()
*/
VkDescriptorSetLayout release();
private:
/* Can't be a reference because of the NoCreate constructor */
Device* _device;
VkDescriptorSetLayout _handle;
HandleFlags _flags;
};
}}
#endif

480
src/Magnum/Vk/DescriptorSetLayoutCreateInfo.h

@ -0,0 +1,480 @@
#ifndef Magnum_Vk_DescriptorSetLayoutCreateInfo_h
#define Magnum_Vk_DescriptorSetLayoutCreateInfo_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
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::DescriptorSetLayoutCreateInfo, @ref Magnum::Vk::DescriptorSetLayoutBinding, enum @ref Magnum::Vk::DescriptorType
* @m_since_latest
*/
/* While I'm not commonly including the Reference headers, the constructor of
DescriptorSetLayoutCreateInfo needs this type and so users would be forced
to include it every time they include this header. Or forget to do so and
wonder why the code is not compiling, which especially when combined with
the fact that one has to wrap the DescriptorSetLayoutBinding instances in
double {{}}'s might be a bit too much to handle. */
#include <Corrade/Containers/AnyReference.h>
#include <Corrade/Containers/ArrayTuple.h>
#include <Corrade/Containers/EnumSet.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 type
@m_since_latest
Wraps @type_vk_keyword{DescriptorType}.
@see @ref DescriptorSetLayoutBinding
@m_enum_values_as_keywords
*/
enum class DescriptorType: Int {
/**
* @ref Sampler.
*
* @see @ref DescriptorType::CombinedImageSampler
*/
Sampler = VK_DESCRIPTOR_TYPE_SAMPLER,
/**
* @ref Sampler combined with an @ref Image.
*
* @m_class{m-note m-success}
*
* @par
* On some implementations it may be more efficient to sample from an
* a combined image sampler than a separate
* @ref DescriptorType::Sampler and @ref DescriptorType::SampledImage.
*
* The image is expected to have been created with @ref ImageUsage::Sampled
* and be in either @ref ImageLayout::General or
* @ref ImageLayout::ShaderReadOnly.
*/
CombinedImageSampler = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
/**
* Sampled @ref Image.
*
* The image is expected to have been created with @ref ImageUsage::Sampled
* and be in either @ref ImageLayout::General or
* @ref ImageLayout::ShaderReadOnly.
* @see @ref DescriptorType::CombinedImageSampler
*/
SampledImage = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
/**
* Storage @ref Image.
*
* The image is expected to have been created with @ref ImageUsage::Storage
* and be in @ref ImageLayout::General.
*/
StorageImage = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
/**
* Uniform texel buffer view.
*
* The buffer is expected to have been created with
* @ref BufferUsage::UniformTexelBuffer.
*/
UniformTexelBuffer = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
/**
* Storage texel buffer view.
*
* The buffer is expected to have been created with
* @ref BufferUsage::StorageTexelBuffer.
*/
StorageTexelBuffer = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
/**
* Uniform @ref Buffer.
*
* The buffer is expected to have been created with
* @ref BufferUsage::UniformBuffer.
*/
UniformBuffer = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
/**
* Storage @ref Buffer.
*
* The buffer is expected to have been created with
* @ref BufferUsage::StorageBuffer.
*/
StorageBuffer = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
/**
* Uniform @ref Buffer with a dynamic offset.
*
* The buffer is expected to have been created with
* @ref BufferUsage::UniformBuffer.
*/
UniformBufferDynamic = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
/**
* Storage @ref Buffer with a dynamic offset.
*
* The buffer is expected to have been created with
* @ref BufferUsage::StorageBuffer.
*/
StorageBufferDynamic = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
/**
* Input @ref Image attachment.
*
* The image is expected to have been created with
* @ref ImageUsage::InputAttachment and be in @ref ImageLayout::General.
*/
InputAttachment = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
/**
* Acceleration structure.
*
* @requires_vk_feature @ref DeviceFeature::AccelerationStructure
*/
AccelerationStructure = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR
};
/**
@brief Descriptor set layout binding
@m_since_latest
Wraps a @type_vk_keyword{DescriptorSetLayoutBinding} together with
associated @type_vk_keyword{DescriptorBindingFlags}. See
@ref Vk-DescriptorSetLayout-creation "Descriptor set layout creation"
for usage information.
*/
class MAGNUM_VK_EXPORT DescriptorSetLayoutBinding {
public:
/**
* @brief Descriptor set layout binding flag
*
* Wraps @type_vk_keyword{DescriptorBindingFlagBits}.
* @see @ref Flags, @ref DescriptorSetLayoutBinding()
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing}
* @m_enum_values_as_keywords
*/
enum class Flag: UnsignedInt {
/**
* If descriptors in this binding are updated between
* binding them in a command buffer and a @ref Queue::submit(), the
* submission will use the most recently set descriptors for
* the binding and the updates do not invalidate the command
* buffer.
* @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_BINDING_UPDATE_AFTER_BIND_BIT,
/**
* Descriptors not used by the command buffer can be updated
* after binding them in a command buffer and while the command
* buffer is pending execution. If set together with
* @ref Flag::PartiallyBound, any descriptors that are not
* dynamically used can be updated, if alone then only descriptors
* statically not used can be updated.
* @requires_vk_feature @ref DeviceFeature::DescriptorBindingUpdateUnusedWhilePending
*/
UpdateUnusedWhilePending = VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT,
/**
* Descriptors in the binding that are not dynamically used don't
* need to contain valid descriptors when consumed.
* @requires_vk_feature @ref DeviceFeature::DescriptorBindingPartiallyBound
*/
PartiallyBound = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT,
/**
* 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.
* @requires_vk_feature @ref DeviceFeature::DescriptorBindingVariableDescriptorCount
*/
VariableDescriptorCount = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT
};
/**
* @brief Descriptor set layout creation flags
*
* Type-safe wrapper for @type_vk_keyword{DescriptorBindingFlags}.
* @see @ref DescriptorSetLayoutBinding()
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing}
*/
typedef Containers::EnumSet<Flag> Flags;
/**
* @brief Constructor
* @param binding Binding corresponding to a particular
* binding in a shader
* @param descriptorType Descriptor type
* @param descriptorCount Number of descriptors contained in the
* binding. Has to be at least @cpp 1 @ce. If the shader binding
* is not an array, use @cpp 1 @ce.
* @param stages Shader stages that access the binding.
* Use @cpp ~Vk::ShaderStages{} @ce to specify that all stages
* may access the binding.
* @param flags Flags
*
* The following @type_vk{DescriptorSetLayoutBinding} fields are
* pre-filled, everything else is zero-filled:
*
* - `binding`
* - `descriptorType`
* - `descriptorCount`
* - `stageFlags` to @p stages
*
* If @p flags are non-empty, a @type_vk{DescriptorBindingFlags} field
* is saved and then subsequently available through @ref flags().
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing} if
* @p flags are non-empty
*/
/*implicit*/ DescriptorSetLayoutBinding(UnsignedInt binding, DescriptorType descriptorType, UnsignedInt descriptorCount = 1, ShaderStages stages = ~ShaderStages{}, Flags flags = {});
/**
* @brief Construct with immutable samplers
* @param binding Binding corresponding to a particular
* binding in a shader
* @param descriptorType Descriptor type. Should be either
* @ref DescriptorType::Sampler or
* @ref DescriptorType::CombinedImageSampler.
* @param immutableSamplers Immutable samplers
* @param stages Shader stages that access the binding.
* Use @cpp ~Vk::ShaderStages{} @ce to specify that all stages
* may access the binding.
* @param flags Flags
*
* The following @type_vk{DescriptorSetLayoutBinding} fields are
* pre-filled, everything else is zero-filled:
*
* - `binding`
* - `descriptorType`
* - `descriptorCount` to @cpp immutableSamplers.size() @ce
* - `pImmutableSamplers` to a copy of @p immutableSamplers
* - `stageFlags` to @p stages
*
* If @p flags are non-empty, a @type_vk{DescriptorBindingFlags} field
* is saved and then subsequently available through @ref flags().
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing} if
* @p flags are non-empty
*/
/*implicit*/ DescriptorSetLayoutBinding(UnsignedInt binding, DescriptorType descriptorType, Containers::ArrayView<const VkSampler> immutableSamplers, ShaderStages stages = ~ShaderStages{}, Flags flags = {});
/** @overload */
/*implicit*/ DescriptorSetLayoutBinding(UnsignedInt binding, DescriptorType descriptorType, std::initializer_list<VkSampler> immutableSamplers, ShaderStages stages = ~ShaderStages{}, Flags flags = {});
/**
* @brief Construct without initializing the contents
*
* Note that the structure has to be fully initialized afterwards in
* order to be usable.
*/
explicit DescriptorSetLayoutBinding(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 DescriptorSetLayoutBinding(const VkDescriptorSetLayoutBinding& info, VkDescriptorBindingFlags flags = {});
/** @brief Copying is not allowed */
DescriptorSetLayoutBinding(const DescriptorSetLayoutBinding&) = delete;
/** @brief Move constructor */
DescriptorSetLayoutBinding(DescriptorSetLayoutBinding&& other) noexcept;
~DescriptorSetLayoutBinding();
/** @brief Copying is not allowed */
DescriptorSetLayoutBinding& operator=(const DescriptorSetLayoutBinding&) = delete;
/** @brief Move assignment */
DescriptorSetLayoutBinding& operator=(DescriptorSetLayoutBinding&& other) noexcept;
/** @brief Underlying @type_vk{DescriptorSetLayoutBinding} structure */
VkDescriptorSetLayoutBinding& operator*() { return _binding; }
/** @overload */
const VkDescriptorSetLayoutBinding& operator*() const { return _binding; }
/** @overload */
VkDescriptorSetLayoutBinding* operator->() { return &_binding; }
/** @overload */
const VkDescriptorSetLayoutBinding* operator->() const { return &_binding; }
/** @overload */
operator const VkDescriptorSetLayoutBinding*() const { return &_binding; }
/**
* @overload
*
* The class is implicitly convertible to a reference in addition to
* a pointer because the type is commonly used in arrays as well, which
* would be annoying to do with a pointer conversion.
*/
operator const VkDescriptorSetLayoutBinding&() const { return _binding; }
/** @brief Underlying @type_vk{DescriptorBindingFlags} enum set */
VkDescriptorBindingFlags& flags() { return _flags; }
/** @overload */
VkDescriptorBindingFlags flags() const { return _flags; }
private:
VkDescriptorSetLayoutBinding _binding;
Containers::ArrayTuple _data;
VkDescriptorBindingFlags _flags;
};
CORRADE_ENUMSET_OPERATORS(DescriptorSetLayoutBinding::Flags)
/**
@brief Descriptor set layout creation info
@m_since_latest
Wraps a @type_vk_keyword{DescriptorSetLayoutCreateInfo} together with
@type_vk_keyword{DescriptorSetLayoutBindingFlagsCreateInfo}. See
@ref Vk-DescriptorSetLayout-creation "Descriptor set layout creation"
for usage information.
*/
class MAGNUM_VK_EXPORT DescriptorSetLayoutCreateInfo {
public:
/**
* @brief Descriptor set layout creation flag
*
* Wraps @type_vk_keyword{DescriptorSetLayoutCreateFlagBits}.
* @see @ref Flags, @ref DescriptorSetLayoutCreateInfo()
* @m_enum_values_as_keywords
*/
enum class Flag: UnsignedInt {
/** @todo all the flags from extensions and 1.2 */
};
/**
* @brief Descriptor set layout creation flags
*
* Type-safe wrapper for @type_vk_keyword{DescriptorSetLayoutCreateFlags}.
* @see @ref DescriptorSetLayoutCreateInfo()
*/
typedef Containers::EnumSet<Flag> Flags;
/**
* @brief Constructor
* @param bindings Descriptor set layout bindings. At least one
* binding has to be present.
* @param flags Descriptor set layout creation flags
*
* The following @type_vk{DescriptorSetLayoutCreateInfo} fields are
* pre-filled in addition to `sType`, everything else is zero-filled:
*
* - `flags`
* - `bindingCount` to @cpp bindings.size() @ce
* - `pBindings` to a copy of @p bindings
*
* If any of the @p bindings has @ref DescriptorSetLayoutBinding::flags()
* non-empty, a @type_vk{DescriptorSetLayoutBindingFlagsCreateInfo}
* structure is referenced from the `pNext` chain of
* @type_vk{DescriptorSetLayoutCreateInfo}, with the following fields
* set in addition to `sType`, everything else zero-filled:
*
* - `bindingCount` to @cpp binding.size() @ce
* - `pBindingFlags` to a list of all
* @ref DescriptorSetLayoutBinding::flags() from @p bindings
*/
explicit DescriptorSetLayoutCreateInfo(Containers::ArrayView<const Containers::AnyReference<const DescriptorSetLayoutBinding>> bindings, Flags flags = {});
/** @overload */
explicit DescriptorSetLayoutCreateInfo(std::initializer_list<Containers::AnyReference<const DescriptorSetLayoutBinding>> bindings, 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 DescriptorSetLayoutCreateInfo(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 DescriptorSetLayoutCreateInfo(const VkDescriptorSetLayoutCreateInfo& info);
/** @brief Copying is not allowed */
DescriptorSetLayoutCreateInfo(const DescriptorSetLayoutCreateInfo&) = delete;
/** @brief Move constructor */
DescriptorSetLayoutCreateInfo(DescriptorSetLayoutCreateInfo&& other) noexcept;
~DescriptorSetLayoutCreateInfo();
/** @brief Copying is not allowed */
DescriptorSetLayoutCreateInfo& operator=(const DescriptorSetLayoutCreateInfo&) = delete;
/** @brief Move assignment */
DescriptorSetLayoutCreateInfo& operator=(DescriptorSetLayoutCreateInfo&& other) noexcept;
/** @brief Underlying @type_vk{DescriptorSetLayoutCreateInfo} structure */
VkDescriptorSetLayoutCreateInfo& operator*() { return _info; }
/** @overload */
const VkDescriptorSetLayoutCreateInfo& operator*() const { return _info; }
/** @overload */
VkDescriptorSetLayoutCreateInfo* operator->() { return &_info; }
/** @overload */
const VkDescriptorSetLayoutCreateInfo* operator->() const { return &_info; }
/** @overload */
operator const VkDescriptorSetLayoutCreateInfo*() const { return &_info; }
private:
VkDescriptorSetLayoutCreateInfo _info;
Containers::ArrayTuple _data;
};
CORRADE_ENUMSET_OPERATORS(DescriptorSetLayoutCreateInfo::Flags)
}}
/* Make the definition complete -- it doesn't make sense to have a CreateInfo
without the corresponding object anyway. */
#include "Magnum/Vk/DescriptorSetLayout.h"
#endif

44
src/Magnum/Vk/DeviceFeatures.h

@ -876,81 +876,95 @@ enum class DeviceFeature: UnsignedShort {
ShaderStorageTexelBufferArrayNonUniformIndexing,
/**
* Whether uniform buffer descriptors can be updated after a set is bound.
* Whether @ref DescriptorType::UniformBuffer /
* @relativeref{DescriptorType,UniformBufferDynamic} can be updated after a
* set is bound.
* @see @ref DeviceFeature::DescriptorBindingAccelerationStructureUpdateAfterBind,
* @relativeref{DeviceFeature,DescriptorBindingSampledImageUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageImageUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingUniformTexelBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageTexelBufferUpdateAfterBind}
* @relativeref{DeviceFeature,DescriptorBindingStorageTexelBufferUpdateAfterBind},
* @ref DescriptorSetLayoutBinding::Flag::UpdateAfterBind
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing}
*/
DescriptorBindingUniformBufferUpdateAfterBind,
/**
* Whether sampled image descriptors can be updated after a set is bound.
* Whether @ref DescriptorType::CombinedImageSampler /
* @relativeref{DescriptorType,SampledImage} can be updated after a set is
* bound.
* @see @ref DeviceFeature::DescriptorBindingAccelerationStructureUpdateAfterBind,
* @relativeref{DeviceFeature,DescriptorBindingUniformBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageImageUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingUniformTexelBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageTexelBufferUpdateAfterBind}
* @relativeref{DeviceFeature,DescriptorBindingStorageTexelBufferUpdateAfterBind},
* @ref DescriptorSetLayoutBinding::Flag::UpdateAfterBind
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing}
*/
DescriptorBindingSampledImageUpdateAfterBind,
/**
* Whether storage image descriptors can be updated after a set is bound.
* Whether @ref DescriptorType::StorageImage can be updated after a set is
* bound.
* @see @ref DeviceFeature::DescriptorBindingAccelerationStructureUpdateAfterBind,
* @relativeref{DeviceFeature,DescriptorBindingUniformBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingSampledImageUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingUniformTexelBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageTexelBufferUpdateAfterBind}
* @relativeref{DeviceFeature,DescriptorBindingStorageTexelBufferUpdateAfterBind},
* @ref DescriptorSetLayoutBinding::Flag::UpdateAfterBind
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing}
*/
DescriptorBindingStorageImageUpdateAfterBind,
/**
* Whether storage buffer descriptors can be updated after a set is bound.
* Whether @ref DescriptorType::StorageBuffer /
* @relativeref{DescriptorType,StorageBufferDynamic} can be updated after a
* set is bound.
* @see @ref DeviceFeature::DescriptorBindingAccelerationStructureUpdateAfterBind,
* @relativeref{DeviceFeature,DescriptorBindingUniformBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingSampledImageUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageImageUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingUniformTexelBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageTexelBufferUpdateAfterBind}
* @relativeref{DeviceFeature,DescriptorBindingStorageTexelBufferUpdateAfterBind},
* @ref DescriptorSetLayoutBinding::Flag::UpdateAfterBind
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing}
*/
DescriptorBindingStorageBufferUpdateAfterBind,
/**
* Whether uniform texel buffer descriptors can be updated after a set is
* bound.
* Whether @ref DescriptorType::UniformTexelBuffer can be updated after a
* set is bound.
* @see @ref DeviceFeature::DescriptorBindingAccelerationStructureUpdateAfterBind,
* @relativeref{DeviceFeature,DescriptorBindingUniformBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingSampledImageUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageImageUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageTexelBufferUpdateAfterBind}
* @relativeref{DeviceFeature,DescriptorBindingStorageTexelBufferUpdateAfterBind},
* @ref DescriptorSetLayoutBinding::Flag::UpdateAfterBind
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing}
*/
DescriptorBindingUniformTexelBufferUpdateAfterBind,
/**
* Whether storage texel buffer descriptors can be updated after a set is
* bound.
* Whether @ref DescriptorType::StorageTexelBuffer can be updated after a
* set is bound.
* @see @ref DeviceFeature::DescriptorBindingAccelerationStructureUpdateAfterBind,
* @relativeref{DeviceFeature,DescriptorBindingUniformBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingSampledImageUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageImageUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingStorageBufferUpdateAfterBind},
* @relativeref{DeviceFeature,DescriptorBindingUniformTexelBufferUpdateAfterBind}
* @relativeref{DeviceFeature,DescriptorBindingUniformTexelBufferUpdateAfterBind},
* @ref DescriptorSetLayoutBinding::Flag::UpdateAfterBind
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing}
*/
DescriptorBindingStorageTexelBufferUpdateAfterBind,
/**
* Whether descriptors can be updated while the set is in use.
* @see @ref DescriptorSetLayoutBinding::Flag::UpdateUnusedWhilePending
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing}
*/
DescriptorBindingUpdateUnusedWhilePending,
@ -958,6 +972,7 @@ enum class DeviceFeature: UnsignedShort {
/**
* Whether a descriptor set binding in which some descriptors are not valid
* can be statically used.
* @see @ref DescriptorSetLayoutBinding::Flag::PartiallyBound
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing}
*/
DescriptorBindingPartiallyBound,
@ -965,6 +980,7 @@ enum class DeviceFeature: UnsignedShort {
/**
* Whether descriptor sets with a variably-sized last binding are
* supported.
* @see @ref DescriptorSetLayoutBinding::Flag::VariableDescriptorCount
* @requires_vk12 Extension @vk_extension{EXT,descriptor_indexing}
*/
DescriptorBindingVariableDescriptorCount,

3
src/Magnum/Vk/Image.h

@ -133,6 +133,9 @@ enum class ImageLayout: Int {
*
* Only valid for images created with @ref ImageUsage::Sampled or
* @ref ImageUsage::InputAttachment.
* @see @ref DescriptorType::CombinedImageSampler,
* @ref DescriptorType::SampledImage,
* @ref DescriptorType::InputAttachment
*/
ShaderReadOnly = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,

7
src/Magnum/Vk/ImageCreateInfo.h

@ -82,7 +82,8 @@ enum class ImageUsage: UnsignedInt {
*
* Not all pixel formats support sampling, see @ref PixelFormat for more
* information.
* @see @ref ImageLayout::ShaderReadOnly
* @see @ref ImageLayout::ShaderReadOnly,
* @ref DescriptorType::SampledImage
*/
Sampled = VK_IMAGE_USAGE_SAMPLED_BIT,
@ -92,7 +93,8 @@ enum class ImageUsage: UnsignedInt {
* Not all pixel formats support shader storage, with some requiring the
* @ref DeviceFeature::ShaderStorageImageExtendedFormats feature. See
* @ref PixelFormat for more information.
* @see @ref ImageLayout::General
* @see @ref ImageLayout::General,
* @ref DescriptorType::StorageImage
*/
Storage = VK_IMAGE_USAGE_STORAGE_BIT,
@ -125,6 +127,7 @@ enum class ImageUsage: UnsignedInt {
* Input attachment in a shader or framebuffer
*
* @see @ref ImageLayout::ShaderReadOnly,
* @ref DescriptorType::InputAttachment,
* @ref SubpassDescription::setInputAttachments()
*/
InputAttachment = VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT

4
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(VkDescriptorSetLayoutTest DescriptorSetLayoutTest.cpp LIBRARIES MagnumVk)
corrade_add_test(VkDeviceTest DeviceTest.cpp LIBRARIES MagnumVk)
corrade_add_test(VkDevicePropertiesTest DevicePropertiesTest.cpp LIBRARIES MagnumVk)
corrade_add_test(VkDeviceFeaturesTest DeviceFeaturesTest.cpp LIBRARIES MagnumVk)
@ -129,6 +130,7 @@ set_target_properties(
VkBufferTest
VkCommandBufferTest
VkCommandPoolTest
VkDescriptorSetLayoutTest
VkDeviceTest
VkDeviceFeaturesTest
VkDevicePropertiesTest
@ -192,6 +194,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(VkDescriptorSetLayoutVkTest DescriptorSetLayoutVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkDeviceVkTest DeviceVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester)
corrade_add_test(VkDevicePropertiesVkTest DevicePropertiesVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester)
corrade_add_test(VkExtensionPropertiesVkTest ExtensionPropertiesVkTest.cpp LIBRARIES MagnumVkTestLib)
@ -243,6 +246,7 @@ if(BUILD_VK_TESTS)
VkBufferVkTest
VkCommandBufferVkTest
VkCommandPoolVkTest
VkDescriptorSetLayoutVkTest
VkDeviceVkTest
VkDevicePropertiesVkTest
VkExtensionPropertiesVkTest

320
src/Magnum/Vk/Test/DescriptorSetLayoutTest.cpp

@ -0,0 +1,320 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
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 <new>
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Vk/DescriptorSetLayoutCreateInfo.h"
#include "Magnum/Vk/Shader.h"
namespace Magnum { namespace Vk { namespace Test { namespace {
struct DescriptorSetLayoutTest: TestSuite::Tester {
explicit DescriptorSetLayoutTest();
void bindingConstruct();
void bindingConstructCountStages();
void bindingConstructFlags();
void bindingConstructImmutableSamplers();
void bindingConstructNoInit();
void bindingConstructFromVk();
void bindingConstructCopy();
void bindingConstructMove();
void createInfoConstruct();
void createInfoConstructBindingFlags();
void createInfoConstructBindingImmutableSamplers();
void createInfoConstructNoInit();
void createInfoConstructFromVk();
void createInfoConstructCopy();
void createInfoConstructMove();
void constructNoCreate();
void constructCopy();
};
DescriptorSetLayoutTest::DescriptorSetLayoutTest() {
addTests({&DescriptorSetLayoutTest::bindingConstruct,
&DescriptorSetLayoutTest::bindingConstructCountStages,
&DescriptorSetLayoutTest::bindingConstructFlags,
&DescriptorSetLayoutTest::bindingConstructImmutableSamplers,
&DescriptorSetLayoutTest::bindingConstructNoInit,
&DescriptorSetLayoutTest::bindingConstructFromVk,
&DescriptorSetLayoutTest::bindingConstructCopy,
&DescriptorSetLayoutTest::bindingConstructMove,
&DescriptorSetLayoutTest::createInfoConstruct,
&DescriptorSetLayoutTest::createInfoConstructBindingFlags,
&DescriptorSetLayoutTest::createInfoConstructBindingImmutableSamplers,
&DescriptorSetLayoutTest::createInfoConstructNoInit,
&DescriptorSetLayoutTest::createInfoConstructFromVk,
&DescriptorSetLayoutTest::createInfoConstructCopy,
&DescriptorSetLayoutTest::createInfoConstructMove,
&DescriptorSetLayoutTest::constructNoCreate,
&DescriptorSetLayoutTest::constructCopy});
}
void DescriptorSetLayoutTest::bindingConstruct() {
DescriptorSetLayoutBinding binding{15, DescriptorType::SampledImage};
CORRADE_COMPARE(binding->binding, 15);
CORRADE_COMPARE(binding->descriptorType, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
CORRADE_COMPARE(binding->descriptorCount, 1);
CORRADE_VERIFY(!binding->pImmutableSamplers);
CORRADE_COMPARE(binding->stageFlags, VK_SHADER_STAGE_ALL);
CORRADE_COMPARE(binding.flags(), 0);
}
void DescriptorSetLayoutTest::bindingConstructCountStages() {
DescriptorSetLayoutBinding binding{15, DescriptorType::SampledImage, 5, ShaderStage::Fragment|ShaderStage::RayMiss};
CORRADE_COMPARE(binding->binding, 15);
CORRADE_COMPARE(binding->descriptorType, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
CORRADE_COMPARE(binding->descriptorCount, 5);
CORRADE_VERIFY(!binding->pImmutableSamplers);
CORRADE_COMPARE(binding->stageFlags, VK_SHADER_STAGE_FRAGMENT_BIT|VK_SHADER_STAGE_MISS_BIT_KHR);
CORRADE_COMPARE(binding.flags(), 0);
}
void DescriptorSetLayoutTest::bindingConstructFlags() {
DescriptorSetLayoutBinding binding{15, DescriptorType::SampledImage, 2, ShaderStage::Fragment, DescriptorSetLayoutBinding::Flag::UpdateAfterBind|DescriptorSetLayoutBinding::Flag::PartiallyBound};
CORRADE_COMPARE(binding->binding, 15);
CORRADE_COMPARE(binding->descriptorType, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
CORRADE_COMPARE(binding->descriptorCount, 2);
CORRADE_VERIFY(!binding->pImmutableSamplers);
CORRADE_COMPARE(binding->stageFlags, VK_SHADER_STAGE_FRAGMENT_BIT);
CORRADE_COMPARE(binding.flags(), VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT|VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT);
}
void DescriptorSetLayoutTest::bindingConstructImmutableSamplers() {
DescriptorSetLayoutBinding binding{15, DescriptorType::SampledImage, {reinterpret_cast<VkSampler>(0xdead), reinterpret_cast<VkSampler>(0xbeef), reinterpret_cast<VkSampler>(0xcafe)}, ShaderStage::Fragment, DescriptorSetLayoutBinding::Flag::UpdateAfterBind};
CORRADE_COMPARE(binding->binding, 15);
CORRADE_COMPARE(binding->descriptorType, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
CORRADE_COMPARE(binding->descriptorCount, 3);
CORRADE_VERIFY(binding->pImmutableSamplers);
CORRADE_COMPARE(binding->pImmutableSamplers[0], reinterpret_cast<VkSampler>(0xdead));
CORRADE_COMPARE(binding->pImmutableSamplers[1], reinterpret_cast<VkSampler>(0xbeef));
CORRADE_COMPARE(binding->pImmutableSamplers[2], reinterpret_cast<VkSampler>(0xcafe));
CORRADE_COMPARE(binding->stageFlags, VK_SHADER_STAGE_FRAGMENT_BIT);
CORRADE_COMPARE(binding.flags(), VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT);
}
void DescriptorSetLayoutTest::bindingConstructNoInit() {
VkSampler a;
DescriptorSetLayoutBinding info{NoInit};
info->pImmutableSamplers = &a;
new(&info) DescriptorSetLayoutBinding{NoInit};
CORRADE_COMPARE(info->pImmutableSamplers, &a);
CORRADE_VERIFY(std::is_nothrow_constructible<DescriptorSetLayoutBinding, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, DescriptorSetLayoutBinding>::value);
}
void DescriptorSetLayoutTest::bindingConstructFromVk() {
VkSampler a;
VkDescriptorSetLayoutBinding vkInfo;
vkInfo.pImmutableSamplers = &a;
DescriptorSetLayoutBinding info{vkInfo};
CORRADE_COMPARE(info->pImmutableSamplers, &a);
}
void DescriptorSetLayoutTest::bindingConstructCopy() {
CORRADE_VERIFY(!std::is_copy_constructible<DescriptorSetLayoutBinding>{});
CORRADE_VERIFY(!std::is_copy_assignable<DescriptorSetLayoutBinding>{});
}
void DescriptorSetLayoutTest::bindingConstructMove() {
DescriptorSetLayoutBinding a{15, DescriptorType::SampledImage, {reinterpret_cast<VkSampler>(0xdead), reinterpret_cast<VkSampler>(0xbeef), reinterpret_cast<VkSampler>(0xcafe)}, ShaderStage::Fragment, DescriptorSetLayoutBinding::Flag::UpdateAfterBind};
CORRADE_COMPARE(a->descriptorCount, 3);
CORRADE_VERIFY(a->pImmutableSamplers);
CORRADE_COMPARE(a->pImmutableSamplers[1], reinterpret_cast<VkSampler>(0xbeef));
DescriptorSetLayoutBinding b = std::move(a);
CORRADE_VERIFY(!a->pImmutableSamplers);
CORRADE_COMPARE(b->descriptorCount, 3);
CORRADE_VERIFY(b->pImmutableSamplers);
CORRADE_COMPARE(b->pImmutableSamplers[1], reinterpret_cast<VkSampler>(0xbeef));
CORRADE_COMPARE(b.flags(), VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT);
DescriptorSetLayoutBinding c{3, {}};
c = std::move(b);
CORRADE_VERIFY(!b->pImmutableSamplers);
CORRADE_COMPARE(c->descriptorCount, 3);
CORRADE_VERIFY(c->pImmutableSamplers);
CORRADE_COMPARE(c->pImmutableSamplers[1], reinterpret_cast<VkSampler>(0xbeef));
CORRADE_COMPARE(c.flags(), VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT);
}
void DescriptorSetLayoutTest::createInfoConstruct() {
DescriptorSetLayoutCreateInfo info{{
/* I hope the {{ will no longer be needed with C++14? */
{{7, DescriptorType::UniformBuffer}},
{{12, DescriptorType::CombinedImageSampler}}
}, DescriptorSetLayoutCreateInfo::Flag(VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT)};
CORRADE_COMPARE(info->bindingCount, 2);
CORRADE_VERIFY(info->pBindings);
CORRADE_COMPARE(info->pBindings[0].binding, 7);
CORRADE_COMPARE(info->pBindings[0].descriptorType, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
CORRADE_COMPARE(info->pBindings[0].descriptorCount, 1);
CORRADE_COMPARE(info->pBindings[1].binding, 12);
CORRADE_COMPARE(info->pBindings[1].descriptorType, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
CORRADE_COMPARE(info->pBindings[1].descriptorCount, 1);
CORRADE_COMPARE(info->flags, VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT);
CORRADE_VERIFY(!info->pNext);
}
void DescriptorSetLayoutTest::createInfoConstructBindingFlags() {
DescriptorSetLayoutCreateInfo info{{
{{7, DescriptorType::UniformBuffer}},
{{12, DescriptorType::CombinedImageSampler, 1, ~ShaderStages{}, DescriptorSetLayoutBinding::Flag::PartiallyBound}}
}};
CORRADE_COMPARE(info->bindingCount, 2);
CORRADE_VERIFY(info->pBindings);
CORRADE_COMPARE(info->pBindings[0].binding, 7);
CORRADE_COMPARE(info->pBindings[0].descriptorType, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
CORRADE_COMPARE(info->pBindings[0].descriptorCount, 1);
CORRADE_COMPARE(info->pBindings[1].binding, 12);
CORRADE_COMPARE(info->pBindings[1].descriptorType, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
CORRADE_COMPARE(info->pBindings[1].descriptorCount, 1);
CORRADE_VERIFY(info->pNext);
const auto& flags = *static_cast<const VkDescriptorSetLayoutBindingFlagsCreateInfo*>(info->pNext);
CORRADE_COMPARE(flags.bindingCount, 2);
CORRADE_VERIFY(flags.pBindingFlags);
CORRADE_COMPARE(flags.pBindingFlags[0], 0);
CORRADE_COMPARE(flags.pBindingFlags[1], VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT);
}
void DescriptorSetLayoutTest::createInfoConstructBindingImmutableSamplers() {
DescriptorSetLayoutBinding binding{3, DescriptorType::Sampler, {reinterpret_cast<VkSampler>(0xdead), reinterpret_cast<VkSampler>(0xbeef)}};
DescriptorSetLayoutCreateInfo info{{
{{7, DescriptorType::UniformBuffer}},
binding,
{{12, DescriptorType::CombinedImageSampler, {reinterpret_cast<VkSampler>(0xcafe)}}},
}};
CORRADE_COMPARE(info->bindingCount, 3);
CORRADE_VERIFY(info->pBindings);
CORRADE_COMPARE(info->pBindings[0].binding, 7);
CORRADE_COMPARE(info->pBindings[0].descriptorType, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
CORRADE_COMPARE(info->pBindings[0].descriptorCount, 1);
CORRADE_VERIFY(!info->pBindings[0].pImmutableSamplers);
CORRADE_COMPARE(info->pBindings[1].binding, 3);
CORRADE_COMPARE(info->pBindings[1].descriptorType, VK_DESCRIPTOR_TYPE_SAMPLER);
CORRADE_COMPARE(info->pBindings[1].descriptorCount, 2);
CORRADE_VERIFY(info->pBindings[1].pImmutableSamplers);
/* The samplers should get copied, not referenced */
CORRADE_VERIFY(info->pBindings[1].pImmutableSamplers != binding->pImmutableSamplers);
CORRADE_COMPARE(info->pBindings[1].pImmutableSamplers[0], reinterpret_cast<VkSampler>(0xdead));
CORRADE_COMPARE(info->pBindings[1].pImmutableSamplers[1], reinterpret_cast<VkSampler>(0xbeef));
CORRADE_COMPARE(info->pBindings[2].binding, 12);
CORRADE_COMPARE(info->pBindings[2].descriptorType, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
CORRADE_COMPARE(info->pBindings[2].descriptorCount, 1);
CORRADE_VERIFY(info->pBindings[2].pImmutableSamplers);
CORRADE_COMPARE(info->pBindings[2].pImmutableSamplers[0], reinterpret_cast<VkSampler>(0xcafe));
CORRADE_VERIFY(!info->pNext);
}
void DescriptorSetLayoutTest::createInfoConstructNoInit() {
DescriptorSetLayoutCreateInfo info{NoInit};
info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&info) DescriptorSetLayoutCreateInfo{NoInit};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY(std::is_nothrow_constructible<DescriptorSetLayoutCreateInfo, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, DescriptorSetLayoutCreateInfo>::value);
}
void DescriptorSetLayoutTest::createInfoConstructFromVk() {
VkDescriptorSetLayoutCreateInfo vkInfo;
vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
DescriptorSetLayoutCreateInfo info{vkInfo};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
}
void DescriptorSetLayoutTest::createInfoConstructCopy() {
CORRADE_VERIFY(!std::is_copy_constructible<DescriptorSetLayoutCreateInfo>{});
CORRADE_VERIFY(!std::is_copy_assignable<DescriptorSetLayoutCreateInfo>{});
}
void DescriptorSetLayoutTest::createInfoConstructMove() {
DescriptorSetLayoutCreateInfo a{{
{{7, DescriptorType::UniformBuffer}},
{{12, DescriptorType::CombinedImageSampler, 1, ~ShaderStages{}, DescriptorSetLayoutBinding::Flag::PartiallyBound}}
}};
CORRADE_COMPARE(a->bindingCount, 2);
CORRADE_VERIFY(a->pBindings);
CORRADE_VERIFY(a->pNext);
DescriptorSetLayoutCreateInfo b = std::move(a);
CORRADE_COMPARE(a->bindingCount, 0);
CORRADE_VERIFY(!a->pBindings);
CORRADE_VERIFY(!a->pNext);
CORRADE_VERIFY(b->pBindings);
CORRADE_VERIFY(b->pNext);
CORRADE_COMPARE(b->pBindings[1].binding, 12);
CORRADE_VERIFY(static_cast<const VkDescriptorSetLayoutBindingFlagsCreateInfo*>(b->pNext)->pBindingFlags);
CORRADE_COMPARE(static_cast<const VkDescriptorSetLayoutBindingFlagsCreateInfo*>(b->pNext)->pBindingFlags[1], VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT);
DescriptorSetLayoutCreateInfo c{VkDescriptorSetLayoutCreateInfo{}};
c = std::move(b);
CORRADE_COMPARE(b->bindingCount, 0);
CORRADE_VERIFY(!b->pBindings);
CORRADE_VERIFY(!b->pNext);
CORRADE_VERIFY(c->pBindings);
CORRADE_VERIFY(c->pNext);
CORRADE_COMPARE(c->pBindings[1].binding, 12);
CORRADE_VERIFY(static_cast<const VkDescriptorSetLayoutBindingFlagsCreateInfo*>(c->pNext)->pBindingFlags);
CORRADE_COMPARE(static_cast<const VkDescriptorSetLayoutBindingFlagsCreateInfo*>(c->pNext)->pBindingFlags[1], VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT);
}
void DescriptorSetLayoutTest::constructNoCreate() {
{
DescriptorSetLayout fence{NoCreate};
CORRADE_VERIFY(!fence.handle());
}
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoCreateT, DescriptorSetLayout>::value);
}
void DescriptorSetLayoutTest::constructCopy() {
CORRADE_VERIFY(!std::is_copy_constructible<DescriptorSetLayout>{});
CORRADE_VERIFY(!std::is_copy_assignable<DescriptorSetLayout>{});
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::DescriptorSetLayoutTest)

104
src/Magnum/Vk/Test/DescriptorSetLayoutVkTest.cpp

@ -0,0 +1,104 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
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 <Corrade/Containers/Reference.h>
#include "Magnum/Vk/DescriptorSetLayoutCreateInfo.h"
#include "Magnum/Vk/Result.h"
#include "Magnum/Vk/VulkanTester.h"
namespace Magnum { namespace Vk { namespace Test { namespace {
struct DescriptorSetLayoutVkTest: VulkanTester {
explicit DescriptorSetLayoutVkTest();
void construct();
void constructMove();
void wrap();
};
DescriptorSetLayoutVkTest::DescriptorSetLayoutVkTest() {
addTests({&DescriptorSetLayoutVkTest::construct,
&DescriptorSetLayoutVkTest::constructMove,
&DescriptorSetLayoutVkTest::wrap});
}
void DescriptorSetLayoutVkTest::construct() {
{
DescriptorSetLayout layout{device(), DescriptorSetLayoutCreateInfo{
{{15, DescriptorType::UniformBuffer}}
}};
CORRADE_VERIFY(layout.handle());
CORRADE_COMPARE(layout.handleFlags(), HandleFlag::DestroyOnDestruction);
}
/* Shouldn't crash or anything */
CORRADE_VERIFY(true);
}
void DescriptorSetLayoutVkTest::constructMove() {
DescriptorSetLayout a{device(), DescriptorSetLayoutCreateInfo{
{{15, DescriptorType::UniformBuffer}}
}};
VkDescriptorSetLayout handle = a.handle();
DescriptorSetLayout b = std::move(a);
CORRADE_VERIFY(!a.handle());
CORRADE_COMPARE(b.handle(), handle);
CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction);
DescriptorSetLayout 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<DescriptorSetLayout>::value);
CORRADE_VERIFY(std::is_nothrow_move_assignable<DescriptorSetLayout>::value);
}
void DescriptorSetLayoutVkTest::wrap() {
VkDescriptorSetLayout layout{};
CORRADE_COMPARE(Result(device()->CreateDescriptorSetLayout(device(),
DescriptorSetLayoutCreateInfo{
{{15, DescriptorType::UniformBuffer}}
},
nullptr, &layout)), Result::Success);
auto wrapped = DescriptorSetLayout::wrap(device(), layout, HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(wrapped.handle(), layout);
/* Release the handle again, destroy by hand */
CORRADE_COMPARE(wrapped.release(), layout);
CORRADE_VERIFY(!wrapped.handle());
device()->DestroyDescriptorSetLayout(device(), layout, nullptr);
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::DescriptorSetLayoutVkTest)

3
src/Magnum/Vk/Vk.h

@ -57,6 +57,9 @@ class CopyImageToBufferInfo;
/* Not forward-declaring CopyBufferToImageInfo1D etc right now, I see no need */
enum class DependencyFlag: UnsignedInt;
typedef Containers::EnumSet<DependencyFlag> DependencyFlags;
class DescriptorSetLayout;
class DescriptorSetLayoutCreateInfo;
enum class DescriptorType: Int;
class Device;
class DeviceCreateInfo;
enum class DeviceFeature: UnsignedShort;

Loading…
Cancel
Save