Browse Source

Vk: implement a RenderPass wrapper.

Quite a big chunk of work, further expanded due to how
VK_KHR_create_renderpass2 is designed -- basically, due to the
tightly-packed nested structures that got replaced with their "version
2", we can no longer just extract the previous structure for backwards
compatibility, but instead have to deep-copy everything to a newly
allocated memory.

Thanks to the the new ArrayTuple structure and a few design iterations I
managed to kick the backwards-compatiblity code into just a single
allocation, while still keeping it possible for the "version 2" code
path to be fully allocation-free (if one passes a completely filled
VkRenderPassCreateInfo2 structure there).
pull/491/head
Vladimír Vondruš 5 years ago
parent
commit
c32f75ddf3
  1. 52
      doc/snippets/MagnumVk.cpp
  2. 12
      doc/vulkan-mapping.dox
  3. 2
      doc/vulkan-support.dox
  4. 4
      src/Magnum/Vk/CMakeLists.txt
  5. 9
      src/Magnum/Vk/Implementation/DeviceState.cpp
  6. 9
      src/Magnum/Vk/Implementation/DeviceState.h
  7. 785
      src/Magnum/Vk/RenderPass.cpp
  8. 1147
      src/Magnum/Vk/RenderPass.h
  9. 2
      src/Magnum/Vk/Test/CMakeLists.txt
  10. 976
      src/Magnum/Vk/Test/RenderPassTest.cpp
  11. 134
      src/Magnum/Vk/Test/RenderPassVkTest.cpp
  12. 1
      src/Magnum/Vk/Vk.h

52
doc/snippets/MagnumVk.cpp

@ -42,6 +42,7 @@
#include "Magnum/Vk/Image.h" #include "Magnum/Vk/Image.h"
#include "Magnum/Vk/LayerProperties.h" #include "Magnum/Vk/LayerProperties.h"
#include "Magnum/Vk/Queue.h" #include "Magnum/Vk/Queue.h"
#include "Magnum/Vk/RenderPass.h"
#include "Magnum/Vk/Shader.h" #include "Magnum/Vk/Shader.h"
#include "MagnumExternal/Vulkan/flextVkGlobal.h" #include "MagnumExternal/Vulkan/flextVkGlobal.h"
@ -416,6 +417,57 @@ indices.bindMemory(memory, indicesOffset);
/* [Memory-mapping] */ /* [Memory-mapping] */
} }
{
Vk::Device device{DOXYGEN_IGNORE(NoCreate)};
/* [RenderPass-usage] */
Vk::RenderPass renderPass{device, Vk::RenderPassCreateInfo{}
.setAttachments({
VK_FORMAT_R8G8B8A8_SRGB,
VK_FORMAT_D24_UNORM_S8_UINT
})
.addSubpass(Vk::SubpassDescription{}
.setColorAttachments({0})
.setDepthStencilAttachment(1)
)
};
/* [RenderPass-usage] */
}
{
Vk::Device device{DOXYGEN_IGNORE(NoCreate)};
/* [RenderPass-usage-load-store] */
Vk::RenderPass renderPass{device, Vk::RenderPassCreateInfo{}
.setAttachments({
{VK_FORMAT_R8G8B8A8_SRGB, Vk::AttachmentLoadOperation::Clear, {}},
{VK_FORMAT_D24_UNORM_S8_UINT, Vk::AttachmentLoadOperation::Clear, {}},
})
DOXYGEN_IGNORE()
};
/* [RenderPass-usage-load-store] */
}
{
Vk::Device device{DOXYGEN_IGNORE(NoCreate)};
/* [RenderPass-usage-layout] */
Vk::RenderPass renderPass{device, Vk::RenderPassCreateInfo{}
.setAttachments({
{VK_FORMAT_R8G8B8A8_SRGB,
Vk::AttachmentLoadOperation::Clear, {},
Vk::ImageLayout::ColorAttachment,
Vk::ImageLayout::ColorAttachment},
{VK_FORMAT_D24_UNORM_S8_UINT,
Vk::AttachmentLoadOperation::Clear, {},
Vk::ImageLayout::DepthStencilAttachment,
Vk::ImageLayout::DepthStencilAttachment},
})
.addSubpass(Vk::SubpassDescription{}
.setColorAttachments({{0, Vk::ImageLayout::ColorAttachment}})
.setDepthStencilAttachment({1, Vk::ImageLayout::ColorAttachment})
)
};
/* [RenderPass-usage-layout] */
}
{ {
Vk::Device device{DOXYGEN_IGNORE(NoCreate)}; Vk::Device device{DOXYGEN_IGNORE(NoCreate)};
/* [Shader-usage] */ /* [Shader-usage] */

12
doc/vulkan-mapping.dox

@ -142,7 +142,7 @@ Vulkan function | Matching API
@fn_vk{CreatePipelineCache}, \n @fn_vk{DestroyPipelineCache} | | @fn_vk{CreatePipelineCache}, \n @fn_vk{DestroyPipelineCache} | |
@fn_vk{CreatePipelineLayout}, \n @fn_vk{DestroyPipelineLayout} | | @fn_vk{CreatePipelineLayout}, \n @fn_vk{DestroyPipelineLayout} | |
@fn_vk{CreateQueryPool}, \n @fn_vk{DestroyQueryPool} | | @fn_vk{CreateQueryPool}, \n @fn_vk{DestroyQueryPool} | |
@fn_vk{CreateRenderPass}, \n @fn_vk{CreateRenderPass2} @m_class{m-label m-flat m-success} **KHR, 1.2**, \n @fn_vk{DestroyRenderPass} | | @fn_vk{CreateRenderPass}, \n @fn_vk{CreateRenderPass2} @m_class{m-label m-flat m-success} **KHR, 1.2**, \n @fn_vk{DestroyRenderPass} | @ref RenderPass constructor and destructor
@fn_vk{CreateSampler}, \n @fn_vk{DestroySampler} | | @fn_vk{CreateSampler}, \n @fn_vk{DestroySampler} | |
@fn_vk{CreateSamplerYcbcrConversion} @m_class{m-label m-flat m-success} **KHR, 1.1** , \n @fn_vk{DestroySamplerYcbcrConversion} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @fn_vk{CreateSamplerYcbcrConversion} @m_class{m-label m-flat m-success} **KHR, 1.1** , \n @fn_vk{DestroySamplerYcbcrConversion} @m_class{m-label m-flat m-success} **KHR, 1.1** | |
@fn_vk{CreateSemaphore}, \n @fn_vk{DestroySemaphore} | | @fn_vk{CreateSemaphore}, \n @fn_vk{DestroySemaphore} | |
@ -305,9 +305,9 @@ Vulkan structure | Matching API
--------------------------------------- | ------------ --------------------------------------- | ------------
@type_vk{AllocationCallbacks} | intentionally @ref vulkan-wrapping-host-allocation "not exposed" @type_vk{AllocationCallbacks} | intentionally @ref vulkan-wrapping-host-allocation "not exposed"
@type_vk{ApplicationInfo} | @ref InstanceCreateInfo @type_vk{ApplicationInfo} | @ref InstanceCreateInfo
@type_vk{AttachmentDescription}, \n @type_vk{AttachmentDescription2} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{AttachmentDescription}, \n @type_vk{AttachmentDescription2} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref AttachmentDescription
@type_vk{AttachmentDescriptionStencilLayout} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{AttachmentDescriptionStencilLayout} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{AttachmentReference}, \n @type_vk{AttachmentReference2} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{AttachmentReference}, \n @type_vk{AttachmentReference2} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref AttachmentReference
@type_vk{AttachmentReferenceStencilLayout} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{AttachmentReferenceStencilLayout} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@subsection vulkan-mapping-structures-b B @subsection vulkan-mapping-structures-b B
@ -584,7 +584,7 @@ Vulkan structure | Matching API
@type_vk{Rect2D} | convertible from/to @ref Range2Di using @ref Magnum/Vk/Integration.h @type_vk{Rect2D} | convertible from/to @ref Range2Di using @ref Magnum/Vk/Integration.h
@type_vk{RenderPassBeginInfo} | | @type_vk{RenderPassBeginInfo} | |
@type_vk{RenderPassAttachmentBeginInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{RenderPassAttachmentBeginInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{RenderPassCreateInfo}, \n @type_vk{RenderPassCreateInfo2} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{RenderPassCreateInfo}, \n @type_vk{RenderPassCreateInfo2} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref RenderPassCreateInfo
@type_vk{RenderPassMultiviewCreateInfo} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @type_vk{RenderPassMultiviewCreateInfo} @m_class{m-label m-flat m-success} **KHR, 1.1** | |
@type_vk{RenderPassInputAttachmentAspectCreateInfo} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @type_vk{RenderPassInputAttachmentAspectCreateInfo} @m_class{m-label m-flat m-success} **KHR, 1.1** | |
@ -617,8 +617,8 @@ Vulkan structure | Matching API
@type_vk{SubmitInfo} | | @type_vk{SubmitInfo} | |
@type_vk{SubpassBeginInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{SubpassBeginInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{SubpassEndInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{SubpassEndInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{SubpassDependency}, \n @type_vk{SubpassDependency2} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{SubpassDependency}, \n @type_vk{SubpassDependency2} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref SubpassDependency
@type_vk{SubpassDescription}, \n @type_vk{SubpassDescription2} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{SubpassDescription}, \n @type_vk{SubpassDescription2} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref SubpassDescription
@type_vk{SubpassDescriptionDepthStencilResolve} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @type_vk{SubpassDescriptionDepthStencilResolve} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{SubresourceLayout} | | @type_vk{SubresourceLayout} | |

2
doc/vulkan-support.dox

@ -87,7 +87,7 @@ Extension | Status
@vk_extension{KHR,sampler_mirror_clamp_to_edge} | @ref Vk::vkSamplerAddressMode() only @vk_extension{KHR,sampler_mirror_clamp_to_edge} | @ref Vk::vkSamplerAddressMode() only
@vk_extension{KHR,shader_float16_int8} | | @vk_extension{KHR,shader_float16_int8} | |
@vk_extension{KHR,imageless_framebuffer} | | @vk_extension{KHR,imageless_framebuffer} | |
@vk_extension{KHR,create_renderpass2} | | @vk_extension{KHR,create_renderpass2} | only render pass creation
@vk_extension{EXT,sampler_filter_minmax} | | @vk_extension{EXT,sampler_filter_minmax} | |
@vk_extension{KHR,image_format_list} | | @vk_extension{KHR,image_format_list} | |
@vk_extension{EXT,descriptor_indexing} | | @vk_extension{EXT,descriptor_indexing} | |

4
src/Magnum/Vk/CMakeLists.txt

@ -48,7 +48,8 @@ set(MagnumVk_GracefulAssert_SRCS
ExtensionProperties.cpp ExtensionProperties.cpp
Image.cpp Image.cpp
LayerProperties.cpp LayerProperties.cpp
Memory.cpp) Memory.cpp
RenderPass.cpp)
set(MagnumVk_HEADERS set(MagnumVk_HEADERS
Assert.h Assert.h
@ -67,6 +68,7 @@ set(MagnumVk_HEADERS
LayerProperties.h LayerProperties.h
Memory.h Memory.h
Queue.h Queue.h
RenderPass.h
Result.h Result.h
Shader.h Shader.h
TypeTraits.h TypeTraits.h

9
src/Magnum/Vk/Implementation/DeviceState.cpp

@ -29,6 +29,7 @@
#include "Magnum/Vk/Device.h" #include "Magnum/Vk/Device.h"
#include "Magnum/Vk/Extensions.h" #include "Magnum/Vk/Extensions.h"
#include "Magnum/Vk/Image.h" #include "Magnum/Vk/Image.h"
#include "Magnum/Vk/RenderPass.h"
#include "Magnum/Vk/Version.h" #include "Magnum/Vk/Version.h"
namespace Magnum { namespace Vk { namespace Implementation { namespace Magnum { namespace Vk { namespace Implementation {
@ -61,6 +62,14 @@ DeviceState::DeviceState(Device& device) {
bindImageMemoryImplementation = &Image::bindMemoryImplementationDefault; bindImageMemoryImplementation = &Image::bindMemoryImplementationDefault;
bindBufferMemoryImplementation = &Buffer::bindMemoryImplementationDefault; bindBufferMemoryImplementation = &Buffer::bindMemoryImplementationDefault;
} }
if(device.isVersionSupported(Version::Vk12)) {
createRenderPassImplementation = &RenderPass::createImplementation12;
} else if(device.isExtensionEnabled<Extensions::KHR::create_renderpass2>()) {
createRenderPassImplementation = &RenderPass::createImplementationKHR;
} else {
createRenderPassImplementation = &RenderPass::createImplementationDefault;
}
} }
}}} }}}

9
src/Magnum/Vk/Implementation/DeviceState.h

@ -28,7 +28,13 @@
#include "Magnum/Vk/Vk.h" #include "Magnum/Vk/Vk.h"
#include "Magnum/Vk/Vulkan.h" #include "Magnum/Vk/Vulkan.h"
namespace Magnum { namespace Vk { namespace Implementation { namespace Magnum { namespace Vk {
/* Declared here instead of in Vk.h because it makes no sense to store it
anywhere */
class RenderPassCreateInfo;
namespace Implementation {
struct DeviceState { struct DeviceState {
explicit DeviceState(Device& instance); explicit DeviceState(Device& instance);
@ -39,6 +45,7 @@ struct DeviceState {
void(*getImageMemoryRequirementsImplementation)(Device&, const VkImageMemoryRequirementsInfo2&, VkMemoryRequirements2&); void(*getImageMemoryRequirementsImplementation)(Device&, const VkImageMemoryRequirementsInfo2&, VkMemoryRequirements2&);
VkResult(*bindBufferMemoryImplementation)(Device&, UnsignedInt, const VkBindBufferMemoryInfo*); VkResult(*bindBufferMemoryImplementation)(Device&, UnsignedInt, const VkBindBufferMemoryInfo*);
VkResult(*bindImageMemoryImplementation)(Device&, UnsignedInt, const VkBindImageMemoryInfo*); VkResult(*bindImageMemoryImplementation)(Device&, UnsignedInt, const VkBindImageMemoryInfo*);
VkResult(*createRenderPassImplementation)(Device&, const RenderPassCreateInfo&, const VkAllocationCallbacks*, VkRenderPass*);
}; };
}}} }}}

785
src/Magnum/Vk/RenderPass.cpp

@ -0,0 +1,785 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020 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 "RenderPass.h"
#include <Corrade/Containers/ArrayTuple.h>
#include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Utility/Algorithms.h>
#include "Magnum/Vk/Assert.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/Handle.h"
#include "Magnum/Vk/Image.h"
#include "Magnum/Vk/Implementation/DeviceState.h"
namespace Magnum { namespace Vk {
AttachmentDescription::AttachmentDescription(const VkFormat format, const AttachmentLoadOperation loadOperation, const AttachmentStoreOperation storeOperation, const ImageLayout initialLayout, const ImageLayout finalLayout, const Int samples, const Flags flags): _description{} {
_description.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
_description.flags = VkAttachmentDescriptionFlags(flags);
_description.format = format;
_description.samples = VkSampleCountFlagBits(samples);
_description.loadOp = VkAttachmentLoadOp(loadOperation);
_description.storeOp = VkAttachmentStoreOp(storeOperation);
_description.initialLayout = VkImageLayout(initialLayout);
_description.finalLayout = VkImageLayout(finalLayout);
}
AttachmentDescription::AttachmentDescription(const VkFormat format, const AttachmentLoadOperation loadOperation, const AttachmentStoreOperation storeOperation, const Int samples, const Flags flags): AttachmentDescription{format, loadOperation, storeOperation, ImageLayout::General, ImageLayout::General, samples, flags} {}
AttachmentDescription::AttachmentDescription(const VkFormat format, const std::pair<AttachmentLoadOperation, AttachmentLoadOperation> depthStencilLoadOperation, const std::pair<AttachmentStoreOperation, AttachmentStoreOperation> depthStencilStoreOperation, const ImageLayout initialLayout, const ImageLayout finalLayout, const Int samples, const Flags flags): _description{} {
_description.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
_description.flags = VkAttachmentDescriptionFlags(flags);
_description.format = format;
_description.samples = VkSampleCountFlagBits(samples);
_description.loadOp = VkAttachmentLoadOp(depthStencilLoadOperation.first);
_description.storeOp = VkAttachmentStoreOp(depthStencilStoreOperation.first);
_description.stencilLoadOp = VkAttachmentLoadOp(depthStencilLoadOperation.second);
_description.stencilStoreOp = VkAttachmentStoreOp(depthStencilStoreOperation.second);
_description.initialLayout = VkImageLayout(initialLayout);
_description.finalLayout = VkImageLayout(finalLayout);
}
AttachmentDescription::AttachmentDescription(const VkFormat format, const std::pair<AttachmentLoadOperation, AttachmentLoadOperation> depthStencilLoadOperation, const std::pair<AttachmentStoreOperation, AttachmentStoreOperation> depthStencilStoreOperation, const Int samples, const Flags flags): AttachmentDescription{format, depthStencilLoadOperation, depthStencilStoreOperation, ImageLayout::General, ImageLayout::General, samples, flags} {}
AttachmentDescription::AttachmentDescription(NoInitT) noexcept {}
AttachmentDescription::AttachmentDescription(const VkAttachmentDescription2& description):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_description(description) {}
AttachmentDescription::AttachmentDescription(const VkAttachmentDescription& description): _description{
VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2,
nullptr,
description.flags,
description.format,
description.samples,
description.loadOp,
description.storeOp,
description.stencilLoadOp,
description.stencilStoreOp,
description.initialLayout,
description.finalLayout
} {}
namespace {
/* Used by RenderPassCreateInfo::vkRenderPassCreateInfo() as well */
VkAttachmentDescription vkAttachmentDescription(const VkAttachmentDescription2& description) {
return {
description.flags,
description.format,
description.samples,
description.loadOp,
description.storeOp,
description.stencilLoadOp,
description.stencilStoreOp,
description.initialLayout,
description.finalLayout
};
}
}
VkAttachmentDescription AttachmentDescription::vkAttachmentDescription() const {
return Vk::vkAttachmentDescription(_description);
}
AttachmentReference::AttachmentReference(const UnsignedInt attachment, const ImageLayout layout): _reference{} {
_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
_reference.attachment = attachment;
_reference.layout = VkImageLayout(layout);
}
AttachmentReference::AttachmentReference(): _reference{} {
_reference.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
_reference.attachment = VK_ATTACHMENT_UNUSED;
_reference.layout = VK_IMAGE_LAYOUT_UNDEFINED;
}
AttachmentReference::AttachmentReference(NoInitT) noexcept {}
AttachmentReference::AttachmentReference(const VkAttachmentReference2& reference):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_reference(reference) {}
AttachmentReference::AttachmentReference(const VkAttachmentReference& reference): _reference{
VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
nullptr,
reference.attachment,
reference.layout,
0
} {}
namespace {
/* Used in SubpassDescription::vkSubpassDescription() as well */
VkAttachmentReference vkAttachmentReference(const VkAttachmentReference2& reference) {
return {
reference.attachment,
reference.layout
};
}
}
VkAttachmentReference AttachmentReference::vkAttachmentReference() const {
return Vk::vkAttachmentReference(_reference);
}
struct SubpassDescription::State {
Containers::ArrayTuple inputAttachments, colorAttachments;
AttachmentReference depthStencilAttachment;
Containers::Array<UnsignedInt> preserveAttachments;
};
SubpassDescription::SubpassDescription(const Flags flags): _description{} {
_description.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2;
_description.flags = VkSubpassDescriptionFlags(flags);
_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
}
SubpassDescription::SubpassDescription(NoInitT) noexcept {}
SubpassDescription::SubpassDescription(const VkSubpassDescription2& description):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_description(description) {}
SubpassDescription::SubpassDescription(const VkSubpassDescription& description): _description{
VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2,
nullptr,
description.flags,
description.pipelineBindPoint,
0,
/* Input, color, resolve and depth/stencil attachment references set
below */
0, nullptr,
0, nullptr, nullptr,
nullptr,
description.preserveAttachmentCount,
description.pPreserveAttachments
}, _state{Containers::InPlaceInit} {
/* Convert all attachment references to the "version 2" format */
setInputAttachmentsInternal<VkAttachmentReference>({description.pInputAttachments, description.inputAttachmentCount});
setColorAttachmentsInternal<VkAttachmentReference>({description.pColorAttachments, description.colorAttachmentCount}, {description.pResolveAttachments, description.pResolveAttachments ? description.colorAttachmentCount : 0});
if(description.pDepthStencilAttachment)
setDepthStencilAttachment(AttachmentReference{*description.pDepthStencilAttachment});
}
SubpassDescription::~SubpassDescription() = default;
SubpassDescription::SubpassDescription(SubpassDescription&& other) noexcept:
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_description(other._description),
_state{std::move(other._state)}
{
/* 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._description.pNext = nullptr;
other._description.inputAttachmentCount = 0;
other._description.pInputAttachments = nullptr;
other._description.colorAttachmentCount = 0;
other._description.pColorAttachments = nullptr;
other._description.pResolveAttachments = nullptr;
other._description.pDepthStencilAttachment = nullptr;
other._description.preserveAttachmentCount = 0;
other._description.pPreserveAttachments = nullptr;
}
SubpassDescription& SubpassDescription::operator=(SubpassDescription&& other) noexcept {
using std::swap;
swap(other._description, _description);
swap(other._state, _state);
return *this;
}
template<class T> void SubpassDescription::setInputAttachmentsInternal(Containers::ArrayView<const T> attachments) {
if(!_state) _state.emplace();
Containers::ArrayView<AttachmentReference> wrappers;
Containers::ArrayView<VkAttachmentReference2> vkAttachments2;
_state->inputAttachments = Containers::ArrayTuple{
{NoInit, attachments.size(), wrappers},
{NoInit, attachments.size(), vkAttachments2}
};
for(std::size_t i = 0; i != attachments.size(); ++i) {
new(wrappers + i) AttachmentReference{attachments[i]};
/* Can't use {} with GCC 4.8 here because it tries to initialize the
first member instead of doing a copy */
new(vkAttachments2 + i) VkAttachmentReference2(wrappers[i]);
}
_description.inputAttachmentCount = attachments.size();
_description.pInputAttachments = vkAttachments2;
}
SubpassDescription& SubpassDescription::setInputAttachments(Containers::ArrayView<const AttachmentReference> attachments) & {
setInputAttachmentsInternal(attachments);
return *this;
}
SubpassDescription&& SubpassDescription::setInputAttachments(Containers::ArrayView<const AttachmentReference> attachments) && {
return std::move(setInputAttachments(attachments));
}
SubpassDescription& SubpassDescription::setInputAttachments(std::initializer_list<AttachmentReference> attachments) & {
return setInputAttachments(Containers::arrayView(attachments));
}
SubpassDescription&& SubpassDescription::setInputAttachments(std::initializer_list<AttachmentReference> attachments) && {
return std::move(setInputAttachments(attachments));
}
template<class T> void SubpassDescription::setColorAttachmentsInternal(Containers::ArrayView<const T> attachments, Containers::ArrayView<const T> resolveAttachments) {
if(!_state) _state.emplace();
CORRADE_ASSERT(!resolveAttachments.size() || resolveAttachments.size() == attachments.size(),
"Vk::SubpassDescription::setColorAttachments(): resolve attachments expected to be either empty or have a size of" << attachments.size() << "but got" << resolveAttachments.size(), );
Containers::ArrayView<AttachmentReference> wrappers,
resolveWrappers;
Containers::ArrayView<VkAttachmentReference2> vkAttachments2,
vkResolveAttachments2;
Containers::ArrayView<VkAttachmentReference> vkAttachments,
vkResolveAttachments;
_state->colorAttachments = Containers::ArrayTuple{
{NoInit, attachments.size(), wrappers},
{NoInit, resolveAttachments.size(), resolveWrappers},
{NoInit, attachments.size(), vkAttachments2},
{NoInit, resolveAttachments.size(), vkResolveAttachments2},
{NoInit, attachments.size(), vkAttachments},
{NoInit, resolveAttachments.size(), vkResolveAttachments}
};
for(std::size_t i = 0; i != attachments.size(); ++i) {
new(wrappers + i) AttachmentReference{attachments[i]};
/* Can't use {} with GCC 4.8 here because it tries to initialize the
first member instead of doing a copy */
new(vkAttachments2 + i) VkAttachmentReference2(*wrappers[i]);
new(vkAttachments + i) VkAttachmentReference{
vkAttachments2[i].attachment,
vkAttachments2[i].layout
};
}
if(!resolveAttachments.empty()) for(std::size_t i = 0; i != attachments.size(); ++i) {
new(resolveWrappers + i) AttachmentReference{resolveAttachments[i]};
/* Can't use {} with GCC 4.8 here because it tries to initialize the
first member instead of doing a copy */
new(vkResolveAttachments2 + i) VkAttachmentReference2(*resolveWrappers[i]);
new(vkResolveAttachments + i) VkAttachmentReference{
vkResolveAttachments2[i].attachment,
vkResolveAttachments2[i].layout
};
}
_description.colorAttachmentCount = attachments.size();
_description.pColorAttachments = vkAttachments2;
_description.pResolveAttachments = resolveAttachments.empty() ?
nullptr : vkResolveAttachments2;
}
SubpassDescription& SubpassDescription::setColorAttachments(Containers::ArrayView<const AttachmentReference> attachments, Containers::ArrayView<const AttachmentReference> resolveAttachments) & {
setColorAttachmentsInternal(attachments, resolveAttachments);
return *this;
}
SubpassDescription&& SubpassDescription::setColorAttachments(Containers::ArrayView<const AttachmentReference> attachments, Containers::ArrayView<const AttachmentReference> resolveAttachments) && {
return std::move(setColorAttachments(attachments, resolveAttachments));
}
SubpassDescription& SubpassDescription::setColorAttachments(Containers::ArrayView<const AttachmentReference> attachments) & {
return setColorAttachments(attachments, {});
}
SubpassDescription&& SubpassDescription::setColorAttachments(Containers::ArrayView<const AttachmentReference> attachments) && {
return std::move(setColorAttachments(attachments));
}
SubpassDescription& SubpassDescription::setColorAttachments(std::initializer_list<AttachmentReference> attachments, std::initializer_list<AttachmentReference> resolveAttachments) & {
return setColorAttachments(Containers::arrayView(attachments), Containers::arrayView(resolveAttachments));
}
SubpassDescription&& SubpassDescription::setColorAttachments(std::initializer_list<AttachmentReference> attachments, std::initializer_list<AttachmentReference> resolveAttachments) && {
return std::move(setColorAttachments(attachments, resolveAttachments));
}
SubpassDescription& SubpassDescription::setDepthStencilAttachment(AttachmentReference attachment) & {
if(!_state) _state.emplace();
_state->depthStencilAttachment = attachment;
_description.pDepthStencilAttachment = _state->depthStencilAttachment;
return *this;
}
SubpassDescription&& SubpassDescription::setDepthStencilAttachment(AttachmentReference attachment) && {
return std::move(setDepthStencilAttachment(attachment));
}
SubpassDescription& SubpassDescription::setPreserveAttachments(Containers::Array<UnsignedInt>&& attachments) & {
if(!_state) _state.emplace();
_state->preserveAttachments = std::move(attachments);
_description.preserveAttachmentCount = _state->preserveAttachments.size();
_description.pPreserveAttachments = _state->preserveAttachments;
return *this;
}
SubpassDescription&& SubpassDescription::setPreserveAttachments(Containers::Array<UnsignedInt>&& attachments) && {
return std::move(setPreserveAttachments(std::move(attachments)));
}
SubpassDescription& SubpassDescription::setPreserveAttachments(Containers::ArrayView<const UnsignedInt> attachments) & {
Containers::Array<UnsignedInt> copy{NoInit, attachments.size()};
Utility::copy(attachments, copy);
return setPreserveAttachments(std::move(copy));
}
SubpassDescription&& SubpassDescription::setPreserveAttachments(Containers::ArrayView<const UnsignedInt> attachments) && {
return std::move(setPreserveAttachments(attachments));
}
SubpassDescription& SubpassDescription::setPreserveAttachments(std::initializer_list<UnsignedInt> attachments) & {
return setPreserveAttachments(Containers::arrayView(attachments));
}
SubpassDescription&& SubpassDescription::setPreserveAttachments(std::initializer_list<UnsignedInt> attachments) && {
return std::move(setPreserveAttachments(attachments));
}
namespace {
std::size_t vkSubpassDescriptionExtrasSize(const VkSubpassDescription2& description) {
return sizeof(VkAttachmentReference)*(description.inputAttachmentCount +
description.colorAttachmentCount*(description.pResolveAttachments ? 2 : 1) +
(description.pDepthStencilAttachment ? 1 : 0));
}
std::pair<VkSubpassDescription, std::size_t> vkSubpassDescriptionExtrasInto(const VkSubpassDescription2& description, char* const out) {
/* Not using an array view nor arrayCast() because the output is not
guaranteed to be divisible by the structure size and we have nothing
else to do with the size either */
const auto attachmentReferences = reinterpret_cast<VkAttachmentReference*>(out);
/* Copy what can be copied, the pointers will be filled below from the
running offset */
VkSubpassDescription description1{
description.flags,
description.pipelineBindPoint,
description.inputAttachmentCount, nullptr,
description.colorAttachmentCount, nullptr, nullptr,
nullptr,
description.preserveAttachmentCount,
description.pPreserveAttachments
};
/* Save convverted attachment references to offsets inside the out view,
update the pointers in the description structure for everything that has
attachments */
std::size_t offset = 0;
if(description.inputAttachmentCount)
description1.pInputAttachments = attachmentReferences + offset;
for(std::size_t i = 0; i != description.inputAttachmentCount; ++i)
attachmentReferences[offset++] = vkAttachmentReference(description.pInputAttachments[i]);
if(description.colorAttachmentCount)
description1.pColorAttachments = attachmentReferences + offset;
for(std::size_t i = 0; i != description.colorAttachmentCount; ++i)
attachmentReferences[offset++] = vkAttachmentReference(description.pColorAttachments[i]);
if(description.pResolveAttachments) {
description1.pResolveAttachments = attachmentReferences + offset;
for(std::size_t i = 0; i != description.colorAttachmentCount; ++i)
attachmentReferences[offset++] = vkAttachmentReference(description.pResolveAttachments[i]);
}
if(description.pDepthStencilAttachment) {
description1.pDepthStencilAttachment = attachmentReferences + offset;
attachmentReferences[offset++] = vkAttachmentReference(*description.pDepthStencilAttachment);
}
return {description1, offset*sizeof(VkAttachmentReference)};
}
}
Containers::Array<VkSubpassDescription> SubpassDescription::vkSubpassDescription() const {
/* Allocate an array to fit VkSubpassDescription together with all
converted VkAttachmentReference instances it needs. Expect the default
deleter is used so we don't need to wrap some other below. */
const std::size_t extrasSize = vkSubpassDescriptionExtrasSize(_description);
Containers::Array<char> storage{Containers::NoInit, sizeof(VkSubpassDescription) + extrasSize};
CORRADE_INTERNAL_ASSERT(!storage.deleter());
/* Fill it with data and return, faking a size of 1 and with a custom
deleter that correctly deletes as a char array again */
std::pair<VkSubpassDescription, std::size_t> out = vkSubpassDescriptionExtrasInto(_description, storage.suffix(sizeof(VkSubpassDescription)));
CORRADE_INTERNAL_ASSERT(out.second == extrasSize);
*reinterpret_cast<VkSubpassDescription*>(storage.data()) = out.first;
return Containers::Array<VkSubpassDescription>{
reinterpret_cast<VkSubpassDescription*>(storage.release()), 1,
[](VkSubpassDescription* data, std::size_t) {
delete[] reinterpret_cast<char*>(data);
}
};
}
SubpassDependency::SubpassDependency(NoInitT) noexcept {}
SubpassDependency::SubpassDependency(const VkSubpassDependency2& dependency):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_dependency(dependency) {}
SubpassDependency::SubpassDependency(const VkSubpassDependency& dependency): _dependency{
VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2,
nullptr,
dependency.srcSubpass,
dependency.dstSubpass,
dependency.srcStageMask,
dependency.dstStageMask,
dependency.srcAccessMask,
dependency.dstAccessMask,
dependency.dependencyFlags,
0
} {}
namespace {
/* Used by RenderPassCreateInfo::vkRenderPassCreateInfo() as well */
VkSubpassDependency vkSubpassDependency(const VkSubpassDependency2& dependency) {
return {
dependency.srcSubpass,
dependency.dstSubpass,
dependency.srcStageMask,
dependency.dstStageMask,
dependency.srcAccessMask,
dependency.dstAccessMask,
dependency.dependencyFlags
};
}
}
VkSubpassDependency SubpassDependency::vkSubpassDependency() const {
return Vk::vkSubpassDependency(_dependency);
}
struct RenderPassCreateInfo::State {
Containers::ArrayTuple attachments;
Containers::Array<SubpassDescription> subpasses;
Containers::Array<VkSubpassDescription2> vkSubpasses2;
Containers::ArrayTuple dependencies;
};
RenderPassCreateInfo::RenderPassCreateInfo(const Flags flags): _info{} {
_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2;
_info.flags = VkRenderPassCreateFlags(flags);
}
RenderPassCreateInfo::RenderPassCreateInfo(NoInitT) noexcept {}
RenderPassCreateInfo::RenderPassCreateInfo(const VkRenderPassCreateInfo2& info):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(info) {}
RenderPassCreateInfo::RenderPassCreateInfo(const VkRenderPassCreateInfo& info): _info{
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2,
info.pNext, /* See note in constructor */
info.flags,
/* Attachment descriptions, subpass descriptions and subpass dependencies
are set below */
0, nullptr,
0, nullptr,
0, nullptr,
/* View masks aren't present in the "version 1" structure */
0, nullptr
} {
/* Create attachment descriptions in the "version 2" format */
setAttachmentsInternal<VkAttachmentDescription>({info.pAttachments, info.attachmentCount});
/* Add subpass descriptions in the "version 1" format. Since this has to
be done one-by-one to allow moves of SubpassDescription, no special
internal API is needed. */
for(std::size_t i = 0; i != info.subpassCount; ++i)
addSubpass(SubpassDescription{info.pSubpasses[i]});
/* Create subpass dependencies in the "version 2" format */
setDependenciesInternal<VkSubpassDependency>({info.pDependencies, info.dependencyCount});
}
RenderPassCreateInfo::RenderPassCreateInfo(RenderPassCreateInfo&& 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),
_state{std::move(other._state)}
{
/* 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.attachmentCount = 0;
other._info.pAttachments = nullptr;
other._info.subpassCount = 0;
other._info.pSubpasses = nullptr;
other._info.dependencyCount = 0;
other._info.pDependencies = nullptr;
other._info.correlatedViewMaskCount = 0;
other._info.pCorrelatedViewMasks = nullptr;
}
RenderPassCreateInfo::~RenderPassCreateInfo() = default;
RenderPassCreateInfo& RenderPassCreateInfo::operator=(RenderPassCreateInfo&& other) noexcept {
using std::swap;
swap(other._info, _info);
swap(other._state, _state);
return *this;
}
template<class T> void RenderPassCreateInfo::setAttachmentsInternal(Containers::ArrayView<const T> attachments) {
if(!_state) _state.emplace();
Containers::ArrayView<AttachmentDescription> wrappers;
Containers::ArrayView<VkAttachmentDescription2> vkAttachments2;
_state->attachments = Containers::ArrayTuple{
{NoInit, attachments.size(), wrappers},
{NoInit, attachments.size(), vkAttachments2}
};
for(std::size_t i = 0; i != attachments.size(); ++i) {
new(wrappers + i) AttachmentDescription{attachments[i]};
/* Can't use {} with GCC 4.8 here because it tries to initialize the
first member instead of doing a copy */
new(vkAttachments2 + i) VkAttachmentDescription2(wrappers[i]);
}
_info.attachmentCount = attachments.size();
_info.pAttachments = vkAttachments2;
}
RenderPassCreateInfo& RenderPassCreateInfo::setAttachments(Containers::ArrayView<const AttachmentDescription> attachments) {
setAttachmentsInternal(attachments);
return *this;
}
RenderPassCreateInfo& RenderPassCreateInfo::setAttachments(std::initializer_list<AttachmentDescription> attachments) {
return setAttachments(Containers::arrayView(attachments));
}
RenderPassCreateInfo& RenderPassCreateInfo::addSubpass(SubpassDescription&& subpass) {
if(!_state) _state.emplace();
/* Unfortunately here we can't use an ArrayTuple as it can't grow, and
accepting an array view / initializer list would mean a deep copy, which
is even less acceptable. So two separate allocations it is. */
arrayAppend(_state->subpasses, std::move(subpass));
/* Can't use {} with GCC 4.8 here because it tries to initialize the
first member instead of doing a copy */
arrayAppend(_state->vkSubpasses2, VkSubpassDescription2(_state->subpasses.back()));
/* The arrays might have been reallocated, reconnect the info structure
pointers */
_info.subpassCount = _state->vkSubpasses2.size();
_info.pSubpasses = _state->vkSubpasses2;
return *this;
}
template<class T> void RenderPassCreateInfo::setDependenciesInternal(Containers::ArrayView<const T> dependencies) {
if(!_state) _state.emplace();
Containers::ArrayView<SubpassDependency> wrappers;
Containers::ArrayView<VkSubpassDependency2> vkDependencies2;
_state->dependencies = Containers::ArrayTuple{
{NoInit, dependencies.size(), wrappers},
{NoInit, dependencies.size(), vkDependencies2}
};
for(std::size_t i = 0; i != dependencies.size(); ++i) {
new(wrappers + i) SubpassDependency{dependencies[i]};
/* Can't use {} with GCC 4.8 here because it tries to initialize the
first member instead of doing a copy */
new(vkDependencies2 + i) VkSubpassDependency2(wrappers[i]);
}
_info.dependencyCount = dependencies.size();
_info.pDependencies = vkDependencies2;
}
RenderPassCreateInfo& RenderPassCreateInfo::setDependencies(Containers::ArrayView<const SubpassDependency> dependencies) {
setDependenciesInternal(dependencies);
return *this;
}
RenderPassCreateInfo& RenderPassCreateInfo::setDependencies(std::initializer_list<SubpassDependency> dependencies) {
return setDependencies(Containers::arrayView(dependencies));
}
Containers::Array<VkRenderPassCreateInfo> RenderPassCreateInfo::vkRenderPassCreateInfo() const {
/* Check that all the structs we copy into the contiguous array have the
expected alignment requirements. Subpass descriptions have the largest
(on 64bit) due to the internal pointers, so they'll go first. */
static_assert(
alignof(VkSubpassDescription) == sizeof(void*) &&
alignof(VkAttachmentDescription) == 4 &&
alignof(VkAttachmentReference) == 4 &&
alignof(VkSubpassDependency) == 4,
"unexpected alignment of VkRenderPassCreateInfo substructures");
/* Calculate size of all "extras" */
const std::size_t structuresSize =
sizeof(VkSubpassDescription)*_info.subpassCount +
sizeof(VkAttachmentDescription)*_info.attachmentCount +
sizeof(VkSubpassDependency)*_info.dependencyCount;
std::size_t extrasSize = 0;
for(std::size_t i = 0; i != _info.subpassCount; ++i)
extrasSize += vkSubpassDescriptionExtrasSize(_info.pSubpasses[i]);
/* Allocate an array to fit VkRenderPassCreateInfo together with all extras
it needs. Expect the default deleter is used so we don't need to wrap
some other below. */
Containers::Array<char> storage{Containers::NoInit, sizeof(VkRenderPassCreateInfo) + structuresSize + extrasSize};
CORRADE_INTERNAL_ASSERT(!storage.deleter());
/* Copy what can be copied for the output info struct. The pointers will be
filled below from the running offset and the struct will be put into the
storage array at the very end. */
VkRenderPassCreateInfo info1{
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
/* Right now (Vulkan 1:2.163) the set of allowed pNext structures in
"version 2" is a *subset* of what's allowed in "version 1", so
simply reusing them should be fine. */
_info.pNext,
_info.flags,
_info.attachmentCount, nullptr,
_info.subpassCount, nullptr,
_info.dependencyCount, nullptr
};
/* Fill in the dynamically-sized subpass description structs with the
higher alignment requirements first, put the "extras" at the end */
std::size_t offset = sizeof(VkRenderPassCreateInfo);
std::size_t extrasOffset = sizeof(VkRenderPassCreateInfo) + structuresSize;
info1.pSubpasses = reinterpret_cast<VkSubpassDescription*>(storage + offset);
for(std::size_t i = 0; i != _info.subpassCount; ++i) {
std::pair<VkSubpassDescription, std::size_t> out = vkSubpassDescriptionExtrasInto(_info.pSubpasses[i], storage + extrasOffset);
*reinterpret_cast<VkSubpassDescription*>(storage + offset) = out.first;
offset += sizeof(VkSubpassDescription);
extrasOffset += out.second;
}
CORRADE_INTERNAL_ASSERT(extrasOffset == storage.size());
/* Attachment descriptions */
info1.pAttachments = reinterpret_cast<VkAttachmentDescription*>(storage + offset);
for(std::size_t i = 0; i != _info.attachmentCount; ++i) {
*reinterpret_cast<VkAttachmentDescription*>(storage + offset) = vkAttachmentDescription(_info.pAttachments[i]);
offset += sizeof(VkAttachmentDescription);
}
/* Subpass dependencies */
info1.pDependencies = reinterpret_cast<VkSubpassDependency*>(storage + offset);
for(std::size_t i = 0; i != _info.dependencyCount; ++i) {
*reinterpret_cast<VkSubpassDependency*>(storage + offset) = vkSubpassDependency(_info.pDependencies[i]);
offset += sizeof(VkSubpassDependency);
}
CORRADE_INTERNAL_ASSERT(offset == sizeof(VkRenderPassCreateInfo) + structuresSize);
*reinterpret_cast<VkRenderPassCreateInfo*>(storage.data()) = info1;
return Containers::Array<VkRenderPassCreateInfo>{
reinterpret_cast<VkRenderPassCreateInfo*>(storage.release()), 1,
[](VkRenderPassCreateInfo* data, std::size_t) {
delete[] reinterpret_cast<char*>(data);
}
};
}
RenderPass RenderPass::wrap(Device& device, const VkRenderPass handle, const HandleFlags flags) {
RenderPass out{NoCreate};
out._device = &device;
out._handle = handle;
out._flags = flags;
return out;
}
RenderPass::RenderPass(Device& device, const RenderPassCreateInfo& info):
_device{&device},
#ifdef CORRADE_GRACEFUL_ASSERT
_handle{}, /* Otherwise the destructor dies if we hit the subpass assert */
#endif
_flags{HandleFlag::DestroyOnDestruction}
{
CORRADE_ASSERT(info->subpassCount,
"Vk::RenderPass: needs to be created with at least one subpass", );
MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(_device->state().createRenderPassImplementation(*_device, info, nullptr, &_handle));
}
RenderPass::RenderPass(NoCreateT): _device{}, _handle{} {}
RenderPass::RenderPass(RenderPass&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags} {
other._handle = {};
}
RenderPass::~RenderPass() {
if(_handle && (_flags & HandleFlag::DestroyOnDestruction))
(**_device).DestroyRenderPass(*_device, _handle, nullptr);
}
RenderPass& RenderPass::operator=(RenderPass&& other) noexcept {
using std::swap;
swap(other._device, _device);
swap(other._handle, _handle);
swap(other._flags, _flags);
return *this;
}
VkRenderPass RenderPass::release() {
const VkRenderPass handle = _handle;
_handle = {};
return handle;
}
VkResult RenderPass::createImplementationDefault(Device& device, const RenderPassCreateInfo& info, const VkAllocationCallbacks* const callbacks, VkRenderPass* const handle) {
return device->CreateRenderPass(device, info.vkRenderPassCreateInfo(), callbacks, handle);
}
VkResult RenderPass::createImplementationKHR(Device& device, const RenderPassCreateInfo& info, const VkAllocationCallbacks* const callbacks, VkRenderPass* const handle) {
return device->CreateRenderPass2KHR(device, info, callbacks, handle);
}
VkResult RenderPass::createImplementation12(Device& device, const RenderPassCreateInfo& info, const VkAllocationCallbacks* const callbacks, VkRenderPass* const handle) {
return device->CreateRenderPass2(device, info, callbacks, handle);
}
}}

1147
src/Magnum/Vk/RenderPass.h

File diff suppressed because it is too large Load Diff

2
src/Magnum/Vk/Test/CMakeLists.txt

@ -39,6 +39,7 @@ corrade_add_test(VkIntegrationTest IntegrationTest.cpp LIBRARIES MagnumVk)
corrade_add_test(VkLayerPropertiesTest LayerPropertiesTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkLayerPropertiesTest LayerPropertiesTest.cpp LIBRARIES MagnumVk)
corrade_add_test(VkMemoryTest MemoryTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkMemoryTest MemoryTest.cpp LIBRARIES MagnumVkTestLib)
corrade_add_test(VkResultTest ResultTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkResultTest ResultTest.cpp LIBRARIES MagnumVk)
corrade_add_test(VkRenderPassTest RenderPassTest.cpp LIBRARIES MagnumVkTestLib)
corrade_add_test(VkShaderTest ShaderTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkShaderTest ShaderTest.cpp LIBRARIES MagnumVk)
add_library(VkAssertTestObjects OBJECT AssertTest.cpp) add_library(VkAssertTestObjects OBJECT AssertTest.cpp)
@ -115,6 +116,7 @@ if(BUILD_VK_TESTS)
corrade_add_test(VkImageVkTest ImageVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester) corrade_add_test(VkImageVkTest ImageVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkInstanceVkTest InstanceVkTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkInstanceVkTest InstanceVkTest.cpp LIBRARIES MagnumVk)
corrade_add_test(VkMemoryVkTest MemoryVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester) corrade_add_test(VkMemoryVkTest MemoryVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkRenderPassVkTest RenderPassVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester)
corrade_add_test(VkShaderVkTest ShaderVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester) corrade_add_test(VkShaderVkTest ShaderVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
target_include_directories(VkShaderVkTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(VkShaderVkTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
corrade_add_test(VkVersionVkTest VersionVkTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkVersionVkTest VersionVkTest.cpp LIBRARIES MagnumVk)

976
src/Magnum/Vk/Test/RenderPassTest.cpp

@ -0,0 +1,976 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020 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 <sstream>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Vk/Image.h"
#include "Magnum/Vk/RenderPass.h"
namespace Magnum { namespace Vk { namespace Test { namespace {
struct RenderPassTest: TestSuite::Tester {
explicit RenderPassTest();
/* While *ConstructFromVk() tests that going from VkFromThing -> Vk::Thing
-> VkToThing doesn't result in information loss, the *ConvertToVk()
tests additionally check that all calls both on our APIs and by editing
the contained structure are correctly propagated to the resulting
structures. */
void attachmentDescriptionConstruct();
void attachmentDescriptionConstructImplicitLayout();
void attachmentDescriptionConstructDepthStencil();
void attachmentDescriptionConstructDepthStencilImplicitLayout();
void attachmentDescriptionConstructImplicitLoadStoreLayout();
void attachmentDescriptionConstructNoInit();
template<class From, class To> void attachmentDescriptionConstructFromVk();
template<class T> void attachmentDescriptionConvertToVk();
void attachmentReferenceConstruct();
void attachmentReferenceConstructUnused();
void attachmentReferenceConstructNoInit();
template<class From, class To> void attachmentReferenceConstructFromVk();
template<class T> void attachmentReferenceConvertToVk();
void subpassDescriptionConstruct();
void subpassDescriptionConstructNoInit();
void subpassDescriptionConstructInputAttachments();
void subpassDescriptionConstructColorAttachments();
void subpassDescriptionConstructColorResolveAttachments();
void subpassDescriptionConstructColorResolveAttachmentsWrongCount();
void subpassDescriptionConstructDepthStencilAttachment();
void subpassDescriptionConstructPreserveAttachments();
void subpassDescriptionConstructEmptyAttachmentLists();
template<class From, class To> void subpassDescriptionConstructFromVk();
void subpassDescriptionConstructCopy();
void subpassDescriptionConstructMove();
template<class T> void subpassDescriptionConvertToVk();
template<class T> void subpassDescriptionConvertToVkNoAttachments();
template<class T> void subpassDescriptionConvertToVkNoResolveAttachments();
void subpassDescriptionRvalue();
void subpassDependencyConstructNoInit();
template<class From, class To> void subpassDependencyConstructFromVk();
template<class T> void subpassDependencyConvertToVk();
void createInfoConstruct();
void createInfoConstructNoInit();
void createInfoConstructAttachments();
void createInfoConstructSubpasses();
void createInfoConstructDependencies();
template<class From, class To> void createInfoConstructFromVk();
void createInfoConstructCopy();
void createInfoConstructMove();
template<class T> void createInfoConvertToVk();
void constructNoCreate();
void constructCopy();
};
RenderPassTest::RenderPassTest() {
addTests({&RenderPassTest::attachmentDescriptionConstruct,
&RenderPassTest::attachmentDescriptionConstructImplicitLayout,
&RenderPassTest::attachmentDescriptionConstructDepthStencil,
&RenderPassTest::attachmentDescriptionConstructDepthStencilImplicitLayout,
&RenderPassTest::attachmentDescriptionConstructImplicitLoadStoreLayout,
&RenderPassTest::attachmentDescriptionConstructNoInit,
&RenderPassTest::attachmentDescriptionConstructFromVk<VkAttachmentDescription2, VkAttachmentDescription2>,
&RenderPassTest::attachmentDescriptionConstructFromVk<VkAttachmentDescription, VkAttachmentDescription2>,
&RenderPassTest::attachmentDescriptionConstructFromVk<VkAttachmentDescription2, VkAttachmentDescription>,
&RenderPassTest::attachmentDescriptionConstructFromVk<VkAttachmentDescription, VkAttachmentDescription>,
&RenderPassTest::attachmentDescriptionConvertToVk<VkAttachmentDescription2>,
&RenderPassTest::attachmentDescriptionConvertToVk<VkAttachmentDescription>,
&RenderPassTest::attachmentReferenceConstruct,
&RenderPassTest::attachmentReferenceConstructUnused,
&RenderPassTest::attachmentReferenceConstructNoInit,
&RenderPassTest::attachmentReferenceConstructFromVk<VkAttachmentReference2, VkAttachmentReference2>,
&RenderPassTest::attachmentReferenceConstructFromVk<VkAttachmentReference, VkAttachmentReference2>,
&RenderPassTest::attachmentReferenceConstructFromVk<VkAttachmentReference2, VkAttachmentReference>,
&RenderPassTest::attachmentReferenceConstructFromVk<VkAttachmentReference, VkAttachmentReference>,
&RenderPassTest::attachmentReferenceConvertToVk<VkAttachmentReference2>,
&RenderPassTest::attachmentReferenceConvertToVk<VkAttachmentReference>,
&RenderPassTest::subpassDescriptionConstruct,
&RenderPassTest::subpassDescriptionConstructNoInit,
&RenderPassTest::subpassDescriptionConstructInputAttachments,
&RenderPassTest::subpassDescriptionConstructColorAttachments,
&RenderPassTest::subpassDescriptionConstructColorResolveAttachments,
&RenderPassTest::subpassDescriptionConstructColorResolveAttachmentsWrongCount,
&RenderPassTest::subpassDescriptionConstructDepthStencilAttachment,
&RenderPassTest::subpassDescriptionConstructPreserveAttachments,
&RenderPassTest::subpassDescriptionConstructEmptyAttachmentLists,
&RenderPassTest::subpassDescriptionConstructFromVk<VkSubpassDescription2, VkSubpassDescription2>,
&RenderPassTest::subpassDescriptionConstructFromVk<VkSubpassDescription, VkSubpassDescription2>,
&RenderPassTest::subpassDescriptionConstructFromVk<VkSubpassDescription2, VkSubpassDescription>,
&RenderPassTest::subpassDescriptionConstructFromVk<VkSubpassDescription, VkSubpassDescription>,
&RenderPassTest::subpassDescriptionConstructCopy,
&RenderPassTest::subpassDescriptionConstructMove,
&RenderPassTest::subpassDescriptionConvertToVk<VkSubpassDescription2>,
&RenderPassTest::subpassDescriptionConvertToVk<VkSubpassDescription>,
&RenderPassTest::subpassDescriptionConvertToVkNoAttachments<VkSubpassDescription2>,
&RenderPassTest::subpassDescriptionConvertToVkNoAttachments<VkSubpassDescription>,
&RenderPassTest::subpassDescriptionConvertToVkNoResolveAttachments<VkSubpassDescription2>,
&RenderPassTest::subpassDescriptionConvertToVkNoResolveAttachments<VkSubpassDescription>,
&RenderPassTest::subpassDescriptionRvalue,
&RenderPassTest::subpassDependencyConstructNoInit,
&RenderPassTest::subpassDependencyConstructFromVk<VkSubpassDependency2, VkSubpassDependency2>,
&RenderPassTest::subpassDependencyConstructFromVk<VkSubpassDependency, VkSubpassDependency2>,
&RenderPassTest::subpassDependencyConstructFromVk<VkSubpassDependency2, VkSubpassDependency>,
&RenderPassTest::subpassDependencyConstructFromVk<VkSubpassDependency, VkSubpassDependency>,
&RenderPassTest::subpassDependencyConvertToVk<VkSubpassDependency2>,
&RenderPassTest::subpassDependencyConvertToVk<VkSubpassDependency>,
&RenderPassTest::createInfoConstruct,
&RenderPassTest::createInfoConstructNoInit,
&RenderPassTest::createInfoConstructAttachments,
&RenderPassTest::createInfoConstructSubpasses,
&RenderPassTest::createInfoConstructDependencies,
&RenderPassTest::createInfoConstructFromVk<VkRenderPassCreateInfo2, VkRenderPassCreateInfo2>,
&RenderPassTest::createInfoConstructFromVk<VkRenderPassCreateInfo, VkRenderPassCreateInfo2>,
&RenderPassTest::createInfoConstructFromVk<VkRenderPassCreateInfo2, VkRenderPassCreateInfo>,
&RenderPassTest::createInfoConstructFromVk<VkRenderPassCreateInfo, VkRenderPassCreateInfo>,
&RenderPassTest::createInfoConstructCopy,
&RenderPassTest::createInfoConstructMove,
&RenderPassTest::createInfoConvertToVk<VkRenderPassCreateInfo2>,
&RenderPassTest::createInfoConvertToVk<VkRenderPassCreateInfo>,
&RenderPassTest::constructNoCreate,
&RenderPassTest::constructCopy});
}
template<class> struct Traits;
#define _c(type) \
template<> struct Traits<Vk ## type> { \
static const char* name() { return #type; } \
static Vk ## type convert(const type& instance) { \
return instance.vk ## type (); \
} \
}; \
template<> struct Traits<Vk ## type ## 2> { \
static const char* name() { return #type "2"; } \
static Vk ## type ## 2 convert(const type& instance) { \
return instance; \
} \
};
#define _ca(type) \
template<> struct Traits<Vk ## type> { \
static const char* name() { return #type; } \
static Containers::Array<Vk ## type> convert(const type& instance) { \
return instance.vk ## type (); \
} \
}; \
template<> struct Traits<Vk ## type ## 2> { \
static const char* name() { return #type "2"; } \
/* So we have the same interface in both cases */ \
static Containers::Array<Vk ## type ## 2> convert(const type& instance) { \
return {Containers::InPlaceInit, {*instance}}; \
} \
};
_c(AttachmentDescription)
_c(AttachmentReference)
_ca(SubpassDescription)
_c(SubpassDependency)
_ca(RenderPassCreateInfo)
#undef _c
#undef _ca
void RenderPassTest::attachmentDescriptionConstruct() {
AttachmentDescription description{VK_FORMAT_R8G8B8A8_SNORM,
AttachmentLoadOperation::Clear, AttachmentStoreOperation::DontCare,
ImageLayout::ColorAttachment, ImageLayout::TransferDestination,
4, AttachmentDescription::Flag::MayAlias};
CORRADE_COMPARE(description->flags, VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT);
CORRADE_COMPARE(description->format, VK_FORMAT_R8G8B8A8_SNORM);
CORRADE_COMPARE(description->samples, VK_SAMPLE_COUNT_4_BIT);
CORRADE_COMPARE(description->loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
CORRADE_COMPARE(description->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD);
CORRADE_COMPARE(description->storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
CORRADE_COMPARE(description->stencilStoreOp, VK_ATTACHMENT_STORE_OP_STORE);
CORRADE_COMPARE(description->initialLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
CORRADE_COMPARE(description->finalLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
}
void RenderPassTest::attachmentDescriptionConstructImplicitLayout() {
AttachmentDescription description{VK_FORMAT_R8G8B8A8_SNORM,
AttachmentLoadOperation::Clear, AttachmentStoreOperation::DontCare,
4, AttachmentDescription::Flag::MayAlias};
CORRADE_COMPARE(description->flags, VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT);
CORRADE_COMPARE(description->format, VK_FORMAT_R8G8B8A8_SNORM);
CORRADE_COMPARE(description->samples, VK_SAMPLE_COUNT_4_BIT);
CORRADE_COMPARE(description->loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
CORRADE_COMPARE(description->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD);
CORRADE_COMPARE(description->storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
CORRADE_COMPARE(description->stencilStoreOp, VK_ATTACHMENT_STORE_OP_STORE);
CORRADE_COMPARE(description->initialLayout, VK_IMAGE_LAYOUT_GENERAL);
CORRADE_COMPARE(description->finalLayout, VK_IMAGE_LAYOUT_GENERAL);
}
void RenderPassTest::attachmentDescriptionConstructDepthStencil() {
AttachmentDescription description{VK_FORMAT_R8G8B8A8_SNORM,
{AttachmentLoadOperation::Clear, AttachmentLoadOperation::DontCare},
{AttachmentStoreOperation::Store, AttachmentStoreOperation::DontCare},
ImageLayout::DepthStencilAttachment, ImageLayout::ShaderReadOnly,
4, AttachmentDescription::Flag::MayAlias};
CORRADE_COMPARE(description->flags, VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT);
CORRADE_COMPARE(description->format, VK_FORMAT_R8G8B8A8_SNORM);
CORRADE_COMPARE(description->samples, VK_SAMPLE_COUNT_4_BIT);
CORRADE_COMPARE(description->loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
CORRADE_COMPARE(description->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
CORRADE_COMPARE(description->storeOp, VK_ATTACHMENT_STORE_OP_STORE);
CORRADE_COMPARE(description->stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
CORRADE_COMPARE(description->initialLayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
CORRADE_COMPARE(description->finalLayout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
void RenderPassTest::attachmentDescriptionConstructDepthStencilImplicitLayout() {
AttachmentDescription description{VK_FORMAT_R8G8B8A8_SNORM,
{AttachmentLoadOperation::Clear, AttachmentLoadOperation::DontCare},
{AttachmentStoreOperation::Store, AttachmentStoreOperation::DontCare},
4, AttachmentDescription::Flag::MayAlias};
CORRADE_COMPARE(description->flags, VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT);
CORRADE_COMPARE(description->format, VK_FORMAT_R8G8B8A8_SNORM);
CORRADE_COMPARE(description->samples, VK_SAMPLE_COUNT_4_BIT);
CORRADE_COMPARE(description->loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
CORRADE_COMPARE(description->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
CORRADE_COMPARE(description->storeOp, VK_ATTACHMENT_STORE_OP_STORE);
CORRADE_COMPARE(description->stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
CORRADE_COMPARE(description->initialLayout, VK_IMAGE_LAYOUT_GENERAL);
CORRADE_COMPARE(description->finalLayout, VK_IMAGE_LAYOUT_GENERAL);
}
void RenderPassTest::attachmentDescriptionConstructImplicitLoadStoreLayout() {
AttachmentDescription description{VK_FORMAT_R8G8B8A8_SNORM,
4, AttachmentDescription::Flag::MayAlias};
CORRADE_COMPARE(description->flags, VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT);
CORRADE_COMPARE(description->format, VK_FORMAT_R8G8B8A8_SNORM);
CORRADE_COMPARE(description->samples, VK_SAMPLE_COUNT_4_BIT);
CORRADE_COMPARE(description->loadOp, VK_ATTACHMENT_LOAD_OP_LOAD);
CORRADE_COMPARE(description->stencilLoadOp, VK_ATTACHMENT_LOAD_OP_LOAD);
CORRADE_COMPARE(description->storeOp, VK_ATTACHMENT_STORE_OP_STORE);
CORRADE_COMPARE(description->stencilStoreOp, VK_ATTACHMENT_STORE_OP_STORE);
CORRADE_COMPARE(description->initialLayout, VK_IMAGE_LAYOUT_GENERAL);
CORRADE_COMPARE(description->finalLayout, VK_IMAGE_LAYOUT_GENERAL);
}
void RenderPassTest::attachmentDescriptionConstructNoInit() {
AttachmentDescription description{NoInit};
description->sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
new(&description) AttachmentDescription{NoInit};
CORRADE_COMPARE(description->sType, VK_STRUCTURE_TYPE_APPLICATION_INFO);
CORRADE_VERIFY((std::is_nothrow_constructible<AttachmentDescription, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, AttachmentDescription>::value));
}
template<class From, class To> void RenderPassTest::attachmentDescriptionConstructFromVk() {
setTestCaseTemplateName({Traits<From>::name(), Traits<To>::name()});
From from{};
from.flags = VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT;
from.format = VK_FORMAT_R8G8B8A8_SNORM;
from.samples = VK_SAMPLE_COUNT_32_BIT;
from.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
from.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
from.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
from.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
from.initialLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL;
from.finalLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
AttachmentDescription description{from};
To to = Traits<To>::convert(description);
CORRADE_COMPARE(to.flags, VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT);
CORRADE_COMPARE(to.format, VK_FORMAT_R8G8B8A8_SNORM);
CORRADE_COMPARE(to.samples, VK_SAMPLE_COUNT_32_BIT);
CORRADE_COMPARE(to.loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
CORRADE_COMPARE(to.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
CORRADE_COMPARE(to.storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
CORRADE_COMPARE(to.stencilStoreOp, VK_ATTACHMENT_STORE_OP_STORE);
CORRADE_COMPARE(to.initialLayout, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL);
CORRADE_COMPARE(to.finalLayout, VK_IMAGE_LAYOUT_PREINITIALIZED);
}
template<class T> void RenderPassTest::attachmentDescriptionConvertToVk() {
setTestCaseTemplateName(Traits<T>::name());
AttachmentDescription description{VK_FORMAT_R8G8B8A8_SNORM,
{AttachmentLoadOperation::Clear, AttachmentLoadOperation::DontCare}, {AttachmentStoreOperation::Store, AttachmentStoreOperation::DontCare},
ImageLayout::ShaderReadOnly, ImageLayout::TransferDestination,
32, AttachmentDescription::Flag::MayAlias};
T out = Traits<T>::convert(description);
CORRADE_COMPARE(out.flags, VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT);
CORRADE_COMPARE(out.format, VK_FORMAT_R8G8B8A8_SNORM);
CORRADE_COMPARE(out.samples, VK_SAMPLE_COUNT_32_BIT);
CORRADE_COMPARE(out.loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
CORRADE_COMPARE(out.stencilLoadOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
CORRADE_COMPARE(out.storeOp, VK_ATTACHMENT_STORE_OP_STORE);
CORRADE_COMPARE(out.stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
CORRADE_COMPARE(out.initialLayout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
CORRADE_COMPARE(out.finalLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
}
void RenderPassTest::attachmentReferenceConstruct() {
AttachmentReference reference{3, ImageLayout::ColorAttachment};
CORRADE_COMPARE(reference->attachment, 3);
CORRADE_COMPARE(reference->layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
}
void RenderPassTest::attachmentReferenceConstructUnused() {
AttachmentReference reference;
CORRADE_COMPARE(reference->attachment, VK_ATTACHMENT_UNUSED);
CORRADE_COMPARE(reference->layout, VK_IMAGE_LAYOUT_UNDEFINED);
}
void RenderPassTest::attachmentReferenceConstructNoInit() {
AttachmentReference reference{NoInit};
reference->sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
new(&reference) AttachmentReference{NoInit};
CORRADE_COMPARE(reference->sType, VK_STRUCTURE_TYPE_APPLICATION_INFO);
CORRADE_VERIFY((std::is_nothrow_constructible<AttachmentReference, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, AttachmentReference>::value));
}
template<class From, class To> void RenderPassTest::attachmentReferenceConstructFromVk() {
setTestCaseTemplateName({Traits<From>::name(), Traits<To>::name()});
From from{};
from.attachment = 3;
from.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
AttachmentReference reference{from};
To to = Traits<To>::convert(reference);
CORRADE_COMPARE(to.attachment, 3);
CORRADE_COMPARE(to.layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
template<class T> void RenderPassTest::attachmentReferenceConvertToVk() {
setTestCaseTemplateName(Traits<T>::name());
AttachmentReference reference{3, ImageLayout::ShaderReadOnly};
T out = Traits<T>::convert(reference);
CORRADE_COMPARE(out.attachment, 3);
CORRADE_COMPARE(out.layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
}
void RenderPassTest::subpassDescriptionConstruct() {
/** @todo use a real flag once it exists */
SubpassDescription description{SubpassDescription::Flag(VK_INCOMPLETE)};
CORRADE_COMPARE(description->flags, VK_INCOMPLETE);
CORRADE_COMPARE(description->inputAttachmentCount, 0);
CORRADE_VERIFY(!description->pInputAttachments);
CORRADE_COMPARE(description->colorAttachmentCount, 0);
CORRADE_VERIFY(!description->pColorAttachments);
CORRADE_VERIFY(!description->pResolveAttachments);
CORRADE_VERIFY(!description->pDepthStencilAttachment);
CORRADE_COMPARE(description->preserveAttachmentCount, 0);
CORRADE_VERIFY(!description->pPreserveAttachments);
}
void RenderPassTest::subpassDescriptionConstructNoInit() {
SubpassDescription description{NoInit};
description->sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
new(&description) SubpassDescription{NoInit};
CORRADE_COMPARE(description->sType, VK_STRUCTURE_TYPE_APPLICATION_INFO);
CORRADE_VERIFY((std::is_nothrow_constructible<SubpassDescription, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, SubpassDescription>::value));
}
void RenderPassTest::subpassDescriptionConstructInputAttachments() {
SubpassDescription description;
description.setInputAttachments({15, {}, 2});
CORRADE_COMPARE(description->inputAttachmentCount, 3);
CORRADE_VERIFY(description->pInputAttachments);
CORRADE_COMPARE(description->pInputAttachments[0].attachment, 15);
CORRADE_COMPARE(description->pInputAttachments[1].attachment, VK_ATTACHMENT_UNUSED);
CORRADE_COMPARE(description->pInputAttachments[2].attachment, 2);
}
void RenderPassTest::subpassDescriptionConstructColorAttachments() {
SubpassDescription description;
description.setColorAttachments({{}, 23});
CORRADE_COMPARE(description->colorAttachmentCount, 2);
CORRADE_VERIFY(description->pColorAttachments);
CORRADE_VERIFY(!description->pResolveAttachments);
CORRADE_COMPARE(description->pColorAttachments[0].attachment, VK_ATTACHMENT_UNUSED);
CORRADE_COMPARE(description->pColorAttachments[1].attachment, 23);
}
void RenderPassTest::subpassDescriptionConstructColorResolveAttachments() {
SubpassDescription description;
description.setColorAttachments({{}, 23}, {1, 0});
CORRADE_COMPARE(description->colorAttachmentCount, 2);
CORRADE_VERIFY(description->pColorAttachments);
CORRADE_COMPARE(description->pColorAttachments[0].attachment, VK_ATTACHMENT_UNUSED);
CORRADE_COMPARE(description->pColorAttachments[1].attachment, 23);
CORRADE_VERIFY(description->pResolveAttachments);
CORRADE_COMPARE(description->pResolveAttachments[0].attachment, 1);
CORRADE_COMPARE(description->pResolveAttachments[1].attachment, 0);
}
void RenderPassTest::subpassDescriptionConstructColorResolveAttachmentsWrongCount() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
SubpassDescription description;
std::ostringstream out;
Error redirectError{&out};
description.setColorAttachments({0, 1}, {2, 3, 5});
CORRADE_COMPARE(out.str(),
"Vk::SubpassDescription::setColorAttachments(): resolve attachments expected to be either empty or have a size of 2 but got 3\n");
}
void RenderPassTest::subpassDescriptionConstructDepthStencilAttachment() {
SubpassDescription description;
description.setDepthStencilAttachment(11);
CORRADE_VERIFY(description->pDepthStencilAttachment);
CORRADE_COMPARE(description->pDepthStencilAttachment->attachment, 11);
}
void RenderPassTest::subpassDescriptionConstructPreserveAttachments() {
SubpassDescription description;
description.setPreserveAttachments({1, 0, 3, 14});
CORRADE_COMPARE(description->preserveAttachmentCount, 4);
CORRADE_VERIFY(description->pPreserveAttachments);
CORRADE_COMPARE(description->pPreserveAttachments[0], 1);
CORRADE_COMPARE(description->pPreserveAttachments[1], 0);
CORRADE_COMPARE(description->pPreserveAttachments[2], 3);
CORRADE_COMPARE(description->pPreserveAttachments[3], 14);
}
void RenderPassTest::subpassDescriptionConstructEmptyAttachmentLists() {
SubpassDescription description;
description.setColorAttachments({}, {})
.setInputAttachments({})
.setPreserveAttachments({});
CORRADE_COMPARE(description->inputAttachmentCount, 0);
CORRADE_VERIFY(!description->pInputAttachments);
CORRADE_COMPARE(description->colorAttachmentCount, 0);
CORRADE_VERIFY(!description->pColorAttachments);
CORRADE_VERIFY(!description->pResolveAttachments);
CORRADE_COMPARE(description->preserveAttachmentCount, 0);
CORRADE_VERIFY(!description->pPreserveAttachments);
}
template<class From, class To> void RenderPassTest::subpassDescriptionConstructFromVk() {
setTestCaseTemplateName({Traits<From>::name(), Traits<To>::name()});
typedef typename std::remove_const<typename std::remove_pointer<decltype(From{}.pInputAttachments)>::type>::type FromAttachmentReference;
FromAttachmentReference inputAttachments[3]{};
inputAttachments[0].attachment = 24;
inputAttachments[0].layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL;
inputAttachments[1].attachment = 35;
inputAttachments[2].attachment = VK_ATTACHMENT_UNUSED;
FromAttachmentReference colorAttachments[2]{};
colorAttachments[0].attachment = 1;
colorAttachments[1].attachment = 3;
colorAttachments[1].layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
FromAttachmentReference resolveAttachments[2]{};
resolveAttachments[0].attachment = 25;
resolveAttachments[0].layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
resolveAttachments[1].attachment = 12;
FromAttachmentReference depthAttachment{};
depthAttachment.attachment = 5;
depthAttachment.layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL;
UnsignedInt preserveAttachments[4]{0, 15, 23, 17};
From from{};
from.flags = VK_NOT_READY; /* wrong, but to set at least something */
from.pipelineBindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
from.inputAttachmentCount = 3;
from.pInputAttachments = inputAttachments;
from.colorAttachmentCount = 2;
from.pColorAttachments = colorAttachments;
from.pResolveAttachments = resolveAttachments;
from.pDepthStencilAttachment = &depthAttachment;
from.preserveAttachmentCount = 4;
from.pPreserveAttachments = preserveAttachments;
SubpassDescription description{from};
Containers::Array<To> array = Traits<To>::convert(description);
const To& to = array[0];
CORRADE_COMPARE(to.flags, VK_NOT_READY); /* wrong, but to set at least something */
CORRADE_COMPARE(to.pipelineBindPoint, VK_PIPELINE_BIND_POINT_COMPUTE);
CORRADE_COMPARE(to.inputAttachmentCount, 3);
CORRADE_VERIFY(to.pInputAttachments);
CORRADE_COMPARE(to.pInputAttachments[0].attachment, 24);
CORRADE_COMPARE(to.pInputAttachments[0].layout, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL);
CORRADE_COMPARE(to.pInputAttachments[1].attachment, 35);
CORRADE_COMPARE(to.pInputAttachments[2].attachment, VK_ATTACHMENT_UNUSED);
CORRADE_COMPARE(to.colorAttachmentCount, 2);
CORRADE_VERIFY(to.pColorAttachments);
CORRADE_COMPARE(to.pColorAttachments[0].attachment, 1);
CORRADE_COMPARE(to.pColorAttachments[1].attachment, 3);
CORRADE_COMPARE(to.pColorAttachments[1].layout, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL);
CORRADE_VERIFY(to.pResolveAttachments);
CORRADE_COMPARE(to.pResolveAttachments[0].attachment, 25);
CORRADE_COMPARE(to.pResolveAttachments[0].layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
CORRADE_COMPARE(to.pResolveAttachments[1].attachment, 12);
CORRADE_VERIFY(to.pDepthStencilAttachment);
CORRADE_COMPARE(to.pDepthStencilAttachment->attachment, 5);
CORRADE_COMPARE(to.pDepthStencilAttachment->layout, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL);
CORRADE_COMPARE(to.preserveAttachmentCount, 4);
CORRADE_VERIFY(to.pPreserveAttachments);
CORRADE_COMPARE(to.pPreserveAttachments[0], 0);
CORRADE_COMPARE(to.pPreserveAttachments[1], 15);
CORRADE_COMPARE(to.pPreserveAttachments[2], 23);
CORRADE_COMPARE(to.pPreserveAttachments[3], 17);
}
void RenderPassTest::subpassDescriptionConstructCopy() {
CORRADE_VERIFY(!(std::is_copy_constructible<SubpassDescription>{}));
CORRADE_VERIFY(!(std::is_copy_assignable<SubpassDescription>{}));
}
void RenderPassTest::subpassDescriptionConstructMove() {
SubpassDescription a;
a.setInputAttachments({24, 35});
CORRADE_COMPARE(a->inputAttachmentCount, 2);
CORRADE_COMPARE(a->pInputAttachments[1].attachment, 35);
SubpassDescription b{std::move(a)};
CORRADE_COMPARE(a->inputAttachmentCount, 0);
CORRADE_VERIFY(!a->pInputAttachments);
CORRADE_COMPARE(b->inputAttachmentCount, 2);
CORRADE_COMPARE(b->pInputAttachments[1].attachment, 35);
SubpassDescription c;
c = std::move(b);
CORRADE_COMPARE(b->inputAttachmentCount, 0);
CORRADE_VERIFY(!b->pInputAttachments);
CORRADE_COMPARE(c->inputAttachmentCount, 2);
CORRADE_COMPARE(c->pInputAttachments[1].attachment, 35);
CORRADE_VERIFY(std::is_nothrow_move_constructible<SubpassDescription>::value);
CORRADE_VERIFY(std::is_nothrow_move_assignable<SubpassDescription>::value);
}
template<class T> void RenderPassTest::subpassDescriptionConvertToVk() {
setTestCaseTemplateName(Traits<T>::name());
SubpassDescription description{};
description.setInputAttachments({
24, {35, ImageLayout::ShaderReadOnly}, 17
})
.setColorAttachments({1, 3}, {{25, ImageLayout::ColorAttachment}, 12})
.setDepthStencilAttachment({5, ImageLayout::DepthStencilAttachment})
.setPreserveAttachments({0, 15, 23, 17});
Containers::Array<T> array = Traits<T>::convert(description);
const T& to = array[0];
CORRADE_COMPARE(to.inputAttachmentCount, 3);
CORRADE_VERIFY(to.pInputAttachments);
CORRADE_COMPARE(to.pInputAttachments[0].attachment, 24);
CORRADE_COMPARE(to.pInputAttachments[1].attachment, 35);
CORRADE_COMPARE(to.pInputAttachments[1].layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
CORRADE_COMPARE(to.pInputAttachments[2].attachment, 17);
CORRADE_COMPARE(to.colorAttachmentCount, 2);
CORRADE_VERIFY(to.pColorAttachments);
CORRADE_COMPARE(to.pColorAttachments[0].attachment, 1);
CORRADE_COMPARE(to.pColorAttachments[1].attachment, 3);
CORRADE_VERIFY(to.pResolveAttachments);
CORRADE_COMPARE(to.pResolveAttachments[0].attachment, 25);
CORRADE_COMPARE(to.pResolveAttachments[0].layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
CORRADE_COMPARE(to.pResolveAttachments[1].attachment, 12);
CORRADE_VERIFY(to.pDepthStencilAttachment);
CORRADE_COMPARE(to.pDepthStencilAttachment->attachment, 5);
CORRADE_COMPARE(to.pDepthStencilAttachment->layout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
CORRADE_COMPARE(to.preserveAttachmentCount, 4);
CORRADE_VERIFY(to.pPreserveAttachments);
CORRADE_COMPARE(to.pPreserveAttachments[0], 0);
CORRADE_COMPARE(to.pPreserveAttachments[1], 15);
CORRADE_COMPARE(to.pPreserveAttachments[2], 23);
CORRADE_COMPARE(to.pPreserveAttachments[3], 17);
}
template<class T> void RenderPassTest::subpassDescriptionConvertToVkNoAttachments() {
setTestCaseTemplateName(Traits<T>::name());
SubpassDescription description;
Containers::Array<T> array = Traits<T>::convert(description);
const T& to = array[0];
CORRADE_COMPARE(to.inputAttachmentCount, 0);
CORRADE_VERIFY(!to.pInputAttachments);
CORRADE_COMPARE(to.colorAttachmentCount, 0);
CORRADE_VERIFY(!to.pColorAttachments);
CORRADE_VERIFY(!to.pResolveAttachments);
CORRADE_VERIFY(!to.pDepthStencilAttachment);
CORRADE_COMPARE(to.preserveAttachmentCount, 0);
CORRADE_VERIFY(!to.pPreserveAttachments);
}
template<class T> void RenderPassTest::subpassDescriptionConvertToVkNoResolveAttachments() {
setTestCaseTemplateName(Traits<T>::name());
SubpassDescription description{};
description.setColorAttachments({1, 3});
Containers::Array<T> array = Traits<T>::convert(description);
const T& to = array[0];
CORRADE_COMPARE(to.colorAttachmentCount, 2);
CORRADE_VERIFY(to.pColorAttachments);
CORRADE_COMPARE(to.pColorAttachments[0].attachment, 1);
CORRADE_COMPARE(to.pColorAttachments[1].attachment, 3);
CORRADE_VERIFY(!to.pResolveAttachments);
}
void RenderPassTest::subpassDescriptionRvalue() {
SubpassDescription&& description = SubpassDescription{}
.setInputAttachments(Containers::ArrayView<const AttachmentReference>{})
.setInputAttachments(std::initializer_list<AttachmentReference>{})
.setColorAttachments(Containers::ArrayView<const AttachmentReference>{})
.setColorAttachments(std::initializer_list<AttachmentReference>{})
.setColorAttachments(Containers::ArrayView<const AttachmentReference>{}, Containers::ArrayView<const AttachmentReference>{})
.setColorAttachments(std::initializer_list<AttachmentReference>{}, std::initializer_list<AttachmentReference>{})
.setDepthStencilAttachment({})
.setPreserveAttachments(Containers::ArrayView<const UnsignedInt>{})
.setPreserveAttachments(Containers::Array<UnsignedInt>{})
.setPreserveAttachments(std::initializer_list<UnsignedInt>{});
/* Just to test something, main point is that the above compiles, links and
returns a &&. Can't test anything related to the contents because the
destructor gets called at the end of the expression. */
CORRADE_VERIFY(&description);
}
void RenderPassTest::subpassDependencyConstructNoInit() {
SubpassDependency dependency{NoInit};
dependency->sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
new(&dependency) SubpassDependency{NoInit};
CORRADE_COMPARE(dependency->sType, VK_STRUCTURE_TYPE_APPLICATION_INFO);
CORRADE_VERIFY((std::is_nothrow_constructible<SubpassDependency, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, SubpassDependency>::value));
}
template<class From, class To> void RenderPassTest::subpassDependencyConstructFromVk() {
setTestCaseTemplateName({Traits<From>::name(), Traits<To>::name()});
From from{};
from.srcSubpass = 3;
from.dstSubpass = 4;
from.srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
from.dstStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
from.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
from.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
from.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
SubpassDependency dependency{from};
To to = Traits<To>::convert(dependency);
CORRADE_COMPARE(to.srcSubpass, 3);
CORRADE_COMPARE(to.dstSubpass, 4);
CORRADE_COMPARE(to.srcStageMask, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
CORRADE_COMPARE(to.dstStageMask, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT);
CORRADE_COMPARE(to.srcAccessMask, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
CORRADE_COMPARE(to.dstAccessMask, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT);
CORRADE_COMPARE(to.dependencyFlags, VK_DEPENDENCY_BY_REGION_BIT);
}
template<class T> void RenderPassTest::subpassDependencyConvertToVk() {
setTestCaseTemplateName(Traits<T>::name());
CORRADE_SKIP("No SubpassDependency APIs to test.");
}
void RenderPassTest::createInfoConstruct() {
/** @todo use a real flag once it exists */
RenderPassCreateInfo info{RenderPassCreateInfo::Flag(VK_INCOMPLETE)};
CORRADE_COMPARE(info->flags, VK_INCOMPLETE);
CORRADE_COMPARE(info->attachmentCount, 0);
CORRADE_VERIFY(!info->pAttachments);
CORRADE_COMPARE(info->subpassCount, 0);
CORRADE_VERIFY(!info->pSubpasses);
CORRADE_COMPARE(info->dependencyCount, 0);
CORRADE_VERIFY(!info->pDependencies);
}
void RenderPassTest::createInfoConstructNoInit() {
RenderPassCreateInfo info{NoInit};
info->sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
new(&info) RenderPassCreateInfo{NoInit};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_APPLICATION_INFO);
CORRADE_VERIFY((std::is_nothrow_constructible<RenderPassCreateInfo, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, RenderPassCreateInfo>::value));
}
void RenderPassTest::createInfoConstructAttachments() {
RenderPassCreateInfo info;
info.setAttachments({
{VK_FORMAT_R16G16B16A16_SFLOAT, AttachmentLoadOperation::Clear, AttachmentStoreOperation::DontCare},
{VK_FORMAT_R8G8B8_SNORM, 4}
});
CORRADE_COMPARE(info->attachmentCount, 2);
CORRADE_VERIFY(info->pAttachments);
CORRADE_COMPARE(info->pAttachments[0].format, VK_FORMAT_R16G16B16A16_SFLOAT);
CORRADE_COMPARE(info->pAttachments[0].loadOp, VK_ATTACHMENT_LOAD_OP_CLEAR);
CORRADE_COMPARE(info->pAttachments[0].storeOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
CORRADE_COMPARE(info->pAttachments[1].format, VK_FORMAT_R8G8B8_SNORM);
CORRADE_COMPARE(info->pAttachments[1].samples, VK_SAMPLE_COUNT_4_BIT);
}
void RenderPassTest::createInfoConstructSubpasses() {
RenderPassCreateInfo info;
info.addSubpass(SubpassDescription{}
.setColorAttachments({15, 34, 1})
.setPreserveAttachments({22})
);
info.addSubpass(SubpassDescription{}
.setInputAttachments({17, {}})
.setDepthStencilAttachment(1)
);
CORRADE_COMPARE(info->subpassCount, 2);
CORRADE_VERIFY(info->pSubpasses);
CORRADE_COMPARE(info->pSubpasses[0].colorAttachmentCount, 3);
CORRADE_VERIFY(info->pSubpasses[0].pColorAttachments);
CORRADE_COMPARE(info->pSubpasses[0].pColorAttachments[1].attachment, 34);
CORRADE_COMPARE(info->pSubpasses[0].preserveAttachmentCount, 1);
CORRADE_VERIFY(info->pSubpasses[0].pPreserveAttachments);
CORRADE_COMPARE(info->pSubpasses[0].pPreserveAttachments[0], 22);
CORRADE_COMPARE(info->pSubpasses[1].inputAttachmentCount, 2);
CORRADE_VERIFY(info->pSubpasses[1].pInputAttachments);
CORRADE_COMPARE(info->pSubpasses[1].pInputAttachments[1].attachment, VK_ATTACHMENT_UNUSED);
CORRADE_VERIFY(info->pSubpasses[1].pDepthStencilAttachment);
CORRADE_COMPARE(info->pSubpasses[1].pDepthStencilAttachment->attachment, 1);
}
void RenderPassTest::createInfoConstructDependencies() {
RenderPassCreateInfo info;
/** @todo update once we have a real API */
VkSubpassDependency2 a{};
a.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
VkSubpassDependency2 b{};
b.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
info.setDependencies({
SubpassDependency{a},
SubpassDependency{b}
});
CORRADE_COMPARE(info->dependencyCount, 2);
CORRADE_VERIFY(info->pDependencies);
CORRADE_COMPARE(info->pDependencies[0].sType, VK_STRUCTURE_TYPE_APPLICATION_INFO);
CORRADE_COMPARE(info->pDependencies[1].sType, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO);
}
template<class From, class To> void RenderPassTest::createInfoConstructFromVk() {
setTestCaseTemplateName({Traits<From>::name(), Traits<To>::name()});
VkRenderPassInputAttachmentAspectCreateInfo aspectInfo{};
typedef typename std::remove_const<typename std::remove_pointer<decltype(From{}.pAttachments)>::type>::type FromAttachmentDescription;
typedef typename std::remove_const<typename std::remove_pointer<decltype(From{}.pSubpasses)>::type>::type FromSubpassDescription;
typedef typename std::remove_const<typename std::remove_pointer<decltype(From{}.pSubpasses->pColorAttachments)>::type>::type FromAttachmentReference;
typedef typename std::remove_const<typename std::remove_pointer<decltype(From{}.pDependencies)>::type>::type FromSubpassDependency;
FromAttachmentDescription attachments[2]{};
attachments[0].format = VK_FORMAT_A1R5G5B5_UNORM_PACK16;
attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
FromAttachmentReference ref[2]{};
ref[0].attachment = 1;
ref[1].attachment = 15;
ref[1].layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
UnsignedInt fiftyseven = 57;
FromSubpassDescription subpasses[3]{};
subpasses[0].colorAttachmentCount = 2;
subpasses[0].pColorAttachments = ref;
subpasses[1].pDepthStencilAttachment = &ref[1];
subpasses[2].preserveAttachmentCount = 1;
subpasses[2].pPreserveAttachments = &fiftyseven;
FromSubpassDependency dependency{};
dependency.srcAccessMask = VK_ACCESS_INDEX_READ_BIT;
From from{};
from.pNext = &aspectInfo;
from.flags = VK_NOT_READY; /** @todo use a real flag once it exists */
from.attachmentCount = 2;
from.pAttachments = attachments;
from.subpassCount = 3;
from.pSubpasses = subpasses;
from.dependencyCount = 1;
from.pDependencies = &dependency;
RenderPassCreateInfo info{from};
Containers::Array<To> array = Traits<To>::convert(info);
const To& to = array[0];
CORRADE_COMPARE(to.pNext, &aspectInfo);
CORRADE_COMPARE(to.flags, VK_NOT_READY);
CORRADE_COMPARE(to.attachmentCount, 2);
CORRADE_VERIFY(to.pAttachments);
CORRADE_COMPARE(to.pAttachments[0].format, VK_FORMAT_A1R5G5B5_UNORM_PACK16);
CORRADE_COMPARE(to.pAttachments[1].stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
CORRADE_COMPARE(to.subpassCount, 3);
CORRADE_VERIFY(to.pSubpasses);
/* Test also that unset arrays stay 0/nullptr */
CORRADE_COMPARE(to.pSubpasses[0].inputAttachmentCount, 0);
CORRADE_VERIFY(!to.pSubpasses[0].pInputAttachments);
CORRADE_COMPARE(to.pSubpasses[0].colorAttachmentCount, 2);
CORRADE_VERIFY(to.pSubpasses[0].pColorAttachments);
CORRADE_COMPARE(to.pSubpasses[0].pColorAttachments[0].attachment, 1);
CORRADE_COMPARE(to.pSubpasses[0].pColorAttachments[1].attachment, 15);
CORRADE_COMPARE(to.pSubpasses[0].pColorAttachments[1].layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
CORRADE_VERIFY(to.pSubpasses[1].pDepthStencilAttachment);
CORRADE_COMPARE(to.pSubpasses[1].pDepthStencilAttachment->attachment, 15);
CORRADE_COMPARE(to.pSubpasses[1].pDepthStencilAttachment->layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
CORRADE_COMPARE(to.pSubpasses[2].preserveAttachmentCount, 1);
CORRADE_VERIFY(to.pSubpasses[2].pPreserveAttachments);
CORRADE_COMPARE(to.pSubpasses[2].pPreserveAttachments[0], 57);
CORRADE_COMPARE(to.dependencyCount, 1);
CORRADE_VERIFY(to.pDependencies);
CORRADE_COMPARE(to.pDependencies[0].srcAccessMask, VK_ACCESS_INDEX_READ_BIT);
}
void RenderPassTest::createInfoConstructCopy() {
CORRADE_VERIFY(!std::is_copy_constructible<RenderPassCreateInfo>{});
CORRADE_VERIFY(!std::is_copy_assignable<RenderPassCreateInfo>{});
}
void RenderPassTest::createInfoConstructMove() {
RenderPassCreateInfo a;
a.setAttachments({VK_FORMAT_D32_SFLOAT, VK_FORMAT_R8G8B8_SNORM});
CORRADE_COMPARE(a->attachmentCount, 2);
CORRADE_COMPARE(a->pAttachments[1].format, VK_FORMAT_R8G8B8_SNORM);
RenderPassCreateInfo b{std::move(a)};
CORRADE_COMPARE(a->attachmentCount, 0);
CORRADE_VERIFY(!a->pAttachments);
CORRADE_COMPARE(b->attachmentCount, 2);
CORRADE_COMPARE(b->pAttachments[1].format, VK_FORMAT_R8G8B8_SNORM);
RenderPassCreateInfo c;
c = std::move(b);
CORRADE_COMPARE(b->attachmentCount, 0);
CORRADE_VERIFY(!b->pAttachments);
CORRADE_COMPARE(c->attachmentCount, 2);
CORRADE_COMPARE(c->pAttachments[1].format, VK_FORMAT_R8G8B8_SNORM);
CORRADE_VERIFY(std::is_nothrow_move_constructible<RenderPassCreateInfo>::value);
CORRADE_VERIFY(std::is_nothrow_move_assignable<RenderPassCreateInfo>::value);
}
template<class T> void RenderPassTest::createInfoConvertToVk() {
VkSubpassDependency dependency{};
dependency.srcAccessMask = VK_ACCESS_INDEX_READ_BIT;
RenderPassCreateInfo info;
info.setAttachments({
AttachmentDescription{VK_FORMAT_A1R5G5B5_UNORM_PACK16},
AttachmentDescription{{}, {}, {AttachmentStoreOperation::Store, AttachmentStoreOperation::DontCare}}
})
.addSubpass(SubpassDescription{}.setColorAttachments({1, {15, ImageLayout::ShaderReadOnly}}))
.addSubpass(SubpassDescription{}.setDepthStencilAttachment({15, ImageLayout::ShaderReadOnly}))
.addSubpass(SubpassDescription{}.setPreserveAttachments({57}))
.setDependencies({SubpassDependency{dependency}});
Containers::Array<T> array = Traits<T>::convert(info);
const T& to = array[0];
CORRADE_COMPARE(to.attachmentCount, 2);
CORRADE_VERIFY(to.pAttachments);
CORRADE_COMPARE(to.pAttachments[0].format, VK_FORMAT_A1R5G5B5_UNORM_PACK16);
CORRADE_COMPARE(to.pAttachments[1].stencilStoreOp, VK_ATTACHMENT_STORE_OP_DONT_CARE);
CORRADE_COMPARE(to.subpassCount, 3);
CORRADE_VERIFY(to.pSubpasses);
/* Test also that unset arrays stay 0/nullptr */
CORRADE_COMPARE(to.pSubpasses[0].inputAttachmentCount, 0);
CORRADE_VERIFY(!to.pSubpasses[0].pInputAttachments);
CORRADE_COMPARE(to.pSubpasses[0].colorAttachmentCount, 2);
CORRADE_VERIFY(to.pSubpasses[0].pColorAttachments);
CORRADE_COMPARE(to.pSubpasses[0].pColorAttachments[0].attachment, 1);
CORRADE_COMPARE(to.pSubpasses[0].pColorAttachments[1].attachment, 15);
CORRADE_COMPARE(to.pSubpasses[0].pColorAttachments[1].layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
CORRADE_VERIFY(to.pSubpasses[1].pDepthStencilAttachment);
CORRADE_COMPARE(to.pSubpasses[1].pDepthStencilAttachment->attachment, 15);
CORRADE_COMPARE(to.pSubpasses[1].pDepthStencilAttachment->layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
CORRADE_COMPARE(to.pSubpasses[2].preserveAttachmentCount, 1);
CORRADE_VERIFY(to.pSubpasses[2].pPreserveAttachments);
CORRADE_COMPARE(to.pSubpasses[2].pPreserveAttachments[0], 57);
CORRADE_COMPARE(to.dependencyCount, 1);
CORRADE_VERIFY(to.pDependencies);
CORRADE_COMPARE(to.pDependencies[0].srcAccessMask, VK_ACCESS_INDEX_READ_BIT);
}
void RenderPassTest::constructNoCreate() {
{
RenderPass renderPass{NoCreate};
CORRADE_VERIFY(!renderPass.handle());
}
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoCreateT, RenderPass>::value));
}
void RenderPassTest::constructCopy() {
CORRADE_VERIFY(!std::is_copy_constructible<RenderPass>{});
CORRADE_VERIFY(!std::is_copy_assignable<RenderPass>{});
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::RenderPassTest)

134
src/Magnum/Vk/Test/RenderPassVkTest.cpp

@ -0,0 +1,134 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020 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 <sstream>
#include <Corrade/Containers/Array.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Vk/Handle.h"
#include "Magnum/Vk/RenderPass.h"
#include "Magnum/Vk/Result.h"
#include "Magnum/Vk/VulkanTester.h"
namespace Magnum { namespace Vk { namespace Test { namespace {
struct RenderPassVkTest: VulkanTester {
explicit RenderPassVkTest();
void construct();
void constructNoSubpasses();
void constructSubpassNoAttachments();
void constructMove();
void wrap();
};
RenderPassVkTest::RenderPassVkTest() {
addTests({&RenderPassVkTest::construct,
&RenderPassVkTest::constructNoSubpasses,
&RenderPassVkTest::constructSubpassNoAttachments,
&RenderPassVkTest::constructMove,
&RenderPassVkTest::wrap});
}
void RenderPassVkTest::construct() {
{
RenderPass renderPass{device(), RenderPassCreateInfo{}
.setAttachments({VK_FORMAT_R8G8B8A8_SNORM})
.addSubpass(SubpassDescription{}.setColorAttachments({0}))
};
CORRADE_VERIFY(renderPass.handle());
CORRADE_COMPARE(renderPass.handleFlags(), HandleFlag::DestroyOnDestruction);
}
/* Shouldn't crash or anything */
CORRADE_VERIFY(true);
}
void RenderPassVkTest::constructNoSubpasses() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
std::ostringstream out;
Error redirectError{&out};
RenderPass{device(), RenderPassCreateInfo{}};
CORRADE_COMPARE(out.str(), "Vk::RenderPass: needs to be created with at least one subpass\n");
}
void RenderPassVkTest::constructSubpassNoAttachments() {
/* The spec requires at least one subpass, but it doesn't say anything
about attachments, so this should work */
RenderPass renderPass{device(), RenderPassCreateInfo{}
.addSubpass(SubpassDescription{})
};
CORRADE_VERIFY(renderPass.handle());
}
void RenderPassVkTest::constructMove() {
RenderPass a{device(), RenderPassCreateInfo{}
.setAttachments({VK_FORMAT_R8G8B8A8_SNORM})
.addSubpass(SubpassDescription{}.setColorAttachments({0}))
};
VkRenderPass handle = a.handle();
RenderPass b = std::move(a);
CORRADE_VERIFY(!a.handle());
CORRADE_COMPARE(b.handle(), handle);
CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction);
RenderPass 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<RenderPass>::value);
CORRADE_VERIFY(std::is_nothrow_move_assignable<RenderPass>::value);
}
void RenderPassVkTest::wrap() {
VkRenderPass renderPass{};
CORRADE_COMPARE(Result(device()->CreateRenderPass(device(),
RenderPassCreateInfo{}
.setAttachments({VK_FORMAT_R8G8B8A8_SNORM})
.addSubpass(SubpassDescription{}.setColorAttachments({0}))
.vkRenderPassCreateInfo(),
nullptr, &renderPass)), Result::Success);
auto wrapped = RenderPass::wrap(device(), renderPass, HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(wrapped.handle(), renderPass);
/* Release the handle again, destroy by hand */
CORRADE_COMPARE(wrapped.release(), renderPass);
CORRADE_VERIFY(!wrapped.handle());
device()->DestroyRenderPass(device(), renderPass, nullptr);
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::RenderPassVkTest)

1
src/Magnum/Vk/Vk.h

@ -64,6 +64,7 @@ typedef Containers::EnumSet<MemoryHeapFlag> MemoryHeapFlags;
class Queue; class Queue;
enum class QueueFlag: UnsignedInt; enum class QueueFlag: UnsignedInt;
typedef Containers::EnumSet<QueueFlag> QueueFlags; typedef Containers::EnumSet<QueueFlag> QueueFlags;
class RenderPass;
enum class Result: Int; enum class Result: Int;
enum class Version: UnsignedInt; enum class Version: UnsignedInt;
#endif #endif

Loading…
Cancel
Save