mirror of https://github.com/mosra/magnum.git
Browse Source
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
12 changed files with 3124 additions and 9 deletions
@ -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); |
||||
} |
||||
|
||||
}} |
||||
@ -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) |
||||
@ -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) |
||||
Loading…
Reference in new issue