Browse Source

Vk: implement render pass begin / end / next commands.

pull/491/head
Vladimír Vondruš 5 years ago
parent
commit
4a49b3a770
  1. 9
      doc/vulkan-mapping.dox
  2. 2
      doc/vulkan-support.dox
  3. 73
      src/Magnum/Vk/CommandBuffer.cpp
  4. 74
      src/Magnum/Vk/CommandBuffer.h
  5. 10
      src/Magnum/Vk/Implementation/DeviceState.cpp
  6. 9
      src/Magnum/Vk/Implementation/DeviceState.h
  7. 100
      src/Magnum/Vk/RenderPass.cpp
  8. 251
      src/Magnum/Vk/RenderPass.h
  9. 5
      src/Magnum/Vk/RenderPassCreateInfo.h
  10. 162
      src/Magnum/Vk/Test/RenderPassTest.cpp
  11. 65
      src/Magnum/Vk/Test/RenderPassVkTest.cpp
  12. 3
      src/Magnum/Vk/Vk.h

9
doc/vulkan-mapping.dox

@ -75,7 +75,7 @@ Vulkan function | Matching API
--------------------------------------- | ------------
@fn_vk{CmdBeginQuery}, \n @fn_vk{CmdEndQuery} | |
@fn_vk{CmdBeginDebugUtilsLabelEXT} @m_class{m-label m-flat m-warning} **EXT**, \n @fn_vk{CmdEndebugUtilsLabelEXT} @m_class{m-label m-flat m-warning} **EXT** | |
@fn_vk{CmdBeginRenderPass}, \n @fn_vk{CmdBeginRenderPass2} @m_class{m-label m-flat m-success} **KHR, 1.2**, \n @fn_vk{CmdEndRenderpass}, \n @fn_vk{CmdEndRenderpass2} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@fn_vk{CmdBeginRenderPass}, \n @fn_vk{CmdBeginRenderPass2} @m_class{m-label m-flat m-success} **KHR, 1.2**, \n @fn_vk{CmdNextSubpass}, \n @fn_vk{CmdNextSubpass2} @m_class{m-label m-flat m-success} **KHR, 1.2**, \n @fn_vk{CmdEndRenderpass}, \n @fn_vk{CmdEndRenderpass2} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref CommandBuffer::beginRenderPass(), \n @ref CommandBuffer::nextSubpass(), \n @ref CommandBuffer::endRenderPass()
@fn_vk{CmdBindDescriptorSets} | |
@fn_vk{CmdBindIndexBuffer} | |
@fn_vk{CmdBindPipeline} | |
@ -108,7 +108,6 @@ Vulkan function | Matching API
@fn_vk{CmdExecuteCommands} | |
@fn_vk{CmdFillBuffer} | |
@fn_vk{CmdInsertDebugUtilsLabelEXT} @m_class{m-label m-flat m-warning} **EXT** | |
@fn_vk{CmdNextSubpass}, \n @fn_vk{CmdNextSubpass2} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@fn_vk{CmdPipelineBarrier} | |
@fn_vk{CmdPushConstants} | |
@fn_vk{CmdResetEvent} | |
@ -635,7 +634,7 @@ Vulkan structure | Matching API
@type_vk{RayTracingPipelineInterfaceCreateInfoKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{RayTracingShaderGroupCreateInfoKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{Rect2D} | convertible from/to @ref Range2Di using @ref Magnum/Vk/Integration.h
@type_vk{RenderPassBeginInfo} | |
@type_vk{RenderPassBeginInfo} | @ref RenderPassBeginInfo
@type_vk{RenderPassAttachmentBeginInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{RenderPassCreateInfo}, \n @type_vk{RenderPassCreateInfo2} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref RenderPassCreateInfo
@type_vk{RenderPassMultiviewCreateInfo} @m_class{m-label m-flat m-success} **KHR, 1.1** | |
@ -669,8 +668,8 @@ Vulkan structure | Matching API
@type_vk{StencilOpState} | |
@type_vk{StridedDeviceAddressRegionKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{SubmitInfo} | |
@type_vk{SubpassBeginInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{SubpassEndInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{SubpassBeginInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref SubpassBeginInfo
@type_vk{SubpassEndInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref SubpassEndInfo
@type_vk{SubpassDependency}, \n @type_vk{SubpassDependency2} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref SubpassDependency
@type_vk{SubpassDescription}, \n @type_vk{SubpassDescription2} @m_class{m-label m-flat m-success} **KHR, 1.2** | @ref SubpassDescription
@type_vk{SubpassDescriptionDepthStencilResolve} @m_class{m-label m-flat m-success} **KHR, 1.2** | |

2
doc/vulkan-support.dox

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

73
src/Magnum/Vk/CommandBuffer.cpp

@ -28,6 +28,8 @@
#include "Magnum/Vk/Assert.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/Handle.h"
#include "Magnum/Vk/RenderPass.h"
#include "Magnum/Vk/Implementation/DeviceState.h"
namespace Magnum { namespace Vk {
@ -81,6 +83,77 @@ CommandBuffer& CommandBuffer::begin(const CommandBufferBeginInfo& info) {
return *this;
}
CommandBuffer& CommandBuffer::beginRenderPass(const RenderPassBeginInfo& info, const SubpassBeginInfo& beginInfo) {
_device->state().cmdBeginRenderPassImplementation(*this, *info, *beginInfo);
return *this;
}
void CommandBuffer::beginRenderPassImplementationDefault(CommandBuffer& self, const VkRenderPassBeginInfo& info, const VkSubpassBeginInfo& beginInfo) {
return (**self._device).CmdBeginRenderPass(self, &info, beginInfo.contents);
}
void CommandBuffer::beginRenderPassImplementationKHR(CommandBuffer& self, const VkRenderPassBeginInfo& info, const VkSubpassBeginInfo& beginInfo) {
return (**self._device).CmdBeginRenderPass2KHR(self, &info, &beginInfo);
}
void CommandBuffer::beginRenderPassImplementation12(CommandBuffer& self, const VkRenderPassBeginInfo& info, const VkSubpassBeginInfo& beginInfo) {
return (**self._device).CmdBeginRenderPass2(self, &info, &beginInfo);
}
CommandBuffer& CommandBuffer::beginRenderPass(const RenderPassBeginInfo& info) {
return beginRenderPass(info, SubpassBeginInfo{});
}
CommandBuffer& CommandBuffer::nextSubpass(const SubpassEndInfo& endInfo, const SubpassBeginInfo& beginInfo) {
_device->state().cmdNextSubpassImplementation(*this, *endInfo, *beginInfo);
return *this;
}
void CommandBuffer::nextSubpassImplementationDefault(CommandBuffer& self, const VkSubpassEndInfo&, const VkSubpassBeginInfo& beginInfo) {
return (**self._device).CmdNextSubpass(self, beginInfo.contents);
}
void CommandBuffer::nextSubpassImplementationKHR(CommandBuffer& self, const VkSubpassEndInfo& endInfo, const VkSubpassBeginInfo& beginInfo) {
return (**self._device).CmdNextSubpass2KHR(self, &beginInfo, &endInfo);
}
void CommandBuffer::nextSubpassImplementation12(CommandBuffer& self, const VkSubpassEndInfo& endInfo, const VkSubpassBeginInfo& beginInfo) {
return (**self._device).CmdNextSubpass2(self, &beginInfo, &endInfo);
}
CommandBuffer& CommandBuffer::nextSubpass(const SubpassEndInfo& endInfo) {
return nextSubpass(endInfo, SubpassBeginInfo{});
}
CommandBuffer& CommandBuffer::nextSubpass(const SubpassBeginInfo& beginInfo) {
return nextSubpass(SubpassEndInfo{}, beginInfo);
}
CommandBuffer& CommandBuffer::nextSubpass() {
return nextSubpass(SubpassBeginInfo{});
}
CommandBuffer& CommandBuffer::endRenderPass(const SubpassEndInfo& endInfo) {
_device->state().cmdEndRenderPassImplementation(*this, *endInfo);
return *this;
}
void CommandBuffer::endRenderPassImplementationDefault(CommandBuffer& self, const VkSubpassEndInfo&) {
return (**self._device).CmdEndRenderPass(self);
}
void CommandBuffer::endRenderPassImplementationKHR(CommandBuffer& self, const VkSubpassEndInfo& endInfo) {
return (**self._device).CmdEndRenderPass2KHR(self, &endInfo);
}
void CommandBuffer::endRenderPassImplementation12(CommandBuffer& self, const VkSubpassEndInfo& endInfo) {
return (**self._device).CmdEndRenderPass2(self, &endInfo);
}
CommandBuffer& CommandBuffer::endRenderPass() {
return endRenderPass(SubpassEndInfo{});
}
void CommandBuffer::end() {
MAGNUM_VK_INTERNAL_ASSERT_SUCCESS((**_device).EndCommandBuffer(_handle));
}

74
src/Magnum/Vk/CommandBuffer.h

@ -40,6 +40,8 @@
namespace Magnum { namespace Vk {
namespace Implementation { struct DeviceState; }
/**
@brief Command buffer begin info
@m_since_latest
@ -267,8 +269,80 @@ class MAGNUM_VK_EXPORT CommandBuffer {
*/
void end();
/**
* @brief Begin a new render pass
* @return Reference to self (for method chaining)
*
* If Vulkan 1.2 is not supported and the
* @vk_extension{KHR,create_renderpass2} extension is not enabled on
* the device, only the `contents` field from @p beginInfo is used to
* begin the render pass.
* @see @fn_vk_keyword{CmdBeginRenderPass2},
* @fn_vk_keyword{CmdBeginRenderPass}
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
CommandBuffer& beginRenderPass(const RenderPassBeginInfo& info, const SubpassBeginInfo& beginInfo = SubpassBeginInfo{});
#else
/* To avoid dependency on RenderPass.h */
CommandBuffer& beginRenderPass(const RenderPassBeginInfo& info, const SubpassBeginInfo& beginInfo);
CommandBuffer& beginRenderPass(const RenderPassBeginInfo& info);
#endif
/**
* @brief Transition to the next subpass of a render pass
* @return Reference to self (for method chaining)
*
* If Vulkan 1.2 is not supported and the
* @vk_extension{KHR,create_renderpass2} extension is not enabled on
* the device, @p endInfo is ignored and only the `contents` field from
* @p beginInfo is used to begin the next subpass
* @see @fn_vk_keyword{CmdNextSubpass2},
* @fn_vk_keyword{CmdNextSubpass}
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
CommandBuffer& nextSubpass(const SubpassEndInfo& endInfo = SubpassEndInfo{}, const SubpassBeginInfo& beginInfo = SubpassBeginInfo{});
/** @overload */
CommandBuffer& nextSubpass(const SubpassBeginInfo& beginInfo);
#else
/* To avoid dependency on RenderPass.h */
CommandBuffer& nextSubpass(const SubpassEndInfo& endInfo, const SubpassBeginInfo& beginInfo);
CommandBuffer& nextSubpass(const SubpassEndInfo& endInfo);
CommandBuffer& nextSubpass(const SubpassBeginInfo& beginInfo);
CommandBuffer& nextSubpass();
#endif
/**
* @brief Transition to the next subpass of a render pass
* @return Reference to self (for method chaining)
*
* If Vulkan 1.2 is not supported and the
* @vk_extension{KHR,create_renderpass2} extension is not enabled on
* the device, @p endInfo is ignored.
* @see @fn_vk_keyword{CmdEndRenderPass2},
* @fn_vk_keyword{CmdEndRenderPass}
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
CommandBuffer& endRenderPass(const SubpassEndInfo& info = SubpassEndInfo{});
#else
CommandBuffer& endRenderPass(const SubpassEndInfo& info);
CommandBuffer& endRenderPass();
#endif
private:
friend CommandPool;
friend Implementation::DeviceState;
MAGNUM_VK_LOCAL static void beginRenderPassImplementationDefault(CommandBuffer& self, const VkRenderPassBeginInfo& info, const VkSubpassBeginInfo& beginInfo);
MAGNUM_VK_LOCAL static void beginRenderPassImplementationKHR(CommandBuffer& self, const VkRenderPassBeginInfo& info, const VkSubpassBeginInfo& beginInfo);
MAGNUM_VK_LOCAL static void beginRenderPassImplementation12(CommandBuffer& self, const VkRenderPassBeginInfo& info, const VkSubpassBeginInfo& beginInfo);
MAGNUM_VK_LOCAL static void nextSubpassImplementationDefault(CommandBuffer& self, const VkSubpassEndInfo& endInfo, const VkSubpassBeginInfo& beginInfo);
MAGNUM_VK_LOCAL static void nextSubpassImplementationKHR(CommandBuffer& self, const VkSubpassEndInfo& endInfo, const VkSubpassBeginInfo& beginInfo);
MAGNUM_VK_LOCAL static void nextSubpassImplementation12(CommandBuffer& self, const VkSubpassEndInfo& endInfo, const VkSubpassBeginInfo& beginInfo);
MAGNUM_VK_LOCAL static void endRenderPassImplementationDefault(CommandBuffer& self, const VkSubpassEndInfo& endInfo);
MAGNUM_VK_LOCAL static void endRenderPassImplementationKHR(CommandBuffer& self, const VkSubpassEndInfo& endInfo);
MAGNUM_VK_LOCAL static void endRenderPassImplementation12(CommandBuffer& self, const VkSubpassEndInfo& endInfo);
/* Can't be a reference because of the NoCreate constructor */
Device* _device;

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

@ -26,6 +26,7 @@
#include "DeviceState.h"
#include "Magnum/Vk/Buffer.h"
#include "Magnum/Vk/CommandBuffer.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/Extensions.h"
#include "Magnum/Vk/Image.h"
@ -65,10 +66,19 @@ DeviceState::DeviceState(Device& device) {
if(device.isVersionSupported(Version::Vk12)) {
createRenderPassImplementation = &RenderPass::createImplementation12;
cmdBeginRenderPassImplementation = &CommandBuffer::beginRenderPassImplementation12;
cmdNextSubpassImplementation = &CommandBuffer::nextSubpassImplementation12;
cmdEndRenderPassImplementation = &CommandBuffer::endRenderPassImplementation12;
} else if(device.isExtensionEnabled<Extensions::KHR::create_renderpass2>()) {
createRenderPassImplementation = &RenderPass::createImplementationKHR;
cmdBeginRenderPassImplementation = &CommandBuffer::beginRenderPassImplementationKHR;
cmdNextSubpassImplementation = &CommandBuffer::nextSubpassImplementationKHR;
cmdEndRenderPassImplementation = &CommandBuffer::endRenderPassImplementationKHR;
} else {
createRenderPassImplementation = &RenderPass::createImplementationDefault;
cmdBeginRenderPassImplementation = &CommandBuffer::beginRenderPassImplementationDefault;
cmdNextSubpassImplementation = &CommandBuffer::nextSubpassImplementationDefault;
cmdEndRenderPassImplementation = &CommandBuffer::endRenderPassImplementationDefault;
}
}

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

@ -40,12 +40,19 @@ struct DeviceState {
explicit DeviceState(Device& instance);
void(*getDeviceQueueImplementation)(Device&, const VkDeviceQueueInfo2&, VkQueue&);
/** @todo put this eventually into a dedicated buffer / image state struct? */
/** @todo put the rest eventually into a dedicated buffer / image state /
... struct? */
void(*getBufferMemoryRequirementsImplementation)(Device&, const VkBufferMemoryRequirementsInfo2&, VkMemoryRequirements2&);
void(*getImageMemoryRequirementsImplementation)(Device&, const VkImageMemoryRequirementsInfo2&, VkMemoryRequirements2&);
VkResult(*bindBufferMemoryImplementation)(Device&, UnsignedInt, const VkBindBufferMemoryInfo*);
VkResult(*bindImageMemoryImplementation)(Device&, UnsignedInt, const VkBindImageMemoryInfo*);
VkResult(*createRenderPassImplementation)(Device&, const RenderPassCreateInfo&, const VkAllocationCallbacks*, VkRenderPass*);
void(*cmdBeginRenderPassImplementation)(CommandBuffer&, const VkRenderPassBeginInfo&, const VkSubpassBeginInfo&);
void(*cmdNextSubpassImplementation)(CommandBuffer&, const VkSubpassEndInfo&, const VkSubpassBeginInfo&);
void(*cmdEndRenderPassImplementation)(CommandBuffer&, const VkSubpassEndInfo&);
};
}}}

100
src/Magnum/Vk/RenderPass.cpp

@ -30,10 +30,12 @@
#include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Utility/Algorithms.h>
#include "Magnum/Math/Color.h"
#include "Magnum/Vk/Assert.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/Handle.h"
#include "Magnum/Vk/Image.h"
#include "Magnum/Vk/Integration.h"
#include "Magnum/Vk/Implementation/DeviceState.h"
namespace Magnum { namespace Vk {
@ -783,4 +785,102 @@ VkResult RenderPass::createImplementation12(Device& device, const RenderPassCrea
return device->CreateRenderPass2(device, info, callbacks, handle);
}
struct RenderPassBeginInfo::State {
Containers::Array<VkClearValue> clearValues;
};
RenderPassBeginInfo::RenderPassBeginInfo(const VkRenderPass renderPass, const VkFramebuffer framebuffer, const Range2Di& renderArea): _info{} {
_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
_info.renderPass = renderPass;
_info.framebuffer = framebuffer;
_info.renderArea = VkRect2D(renderArea);
}
RenderPassBeginInfo::RenderPassBeginInfo(NoInitT) noexcept {}
RenderPassBeginInfo::RenderPassBeginInfo(const VkRenderPassBeginInfo& info):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(info) {}
RenderPassBeginInfo::RenderPassBeginInfo(RenderPassBeginInfo&& 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.clearValueCount = 0;
other._info.pClearValues = nullptr;
}
RenderPassBeginInfo::~RenderPassBeginInfo() = default;
RenderPassBeginInfo& RenderPassBeginInfo::operator=(RenderPassBeginInfo&& other) noexcept {
using std::swap;
swap(other._info, _info);
swap(other._state, _state);
return *this;
}
RenderPassBeginInfo& RenderPassBeginInfo::clearColor(const UnsignedInt attachment, const Color4& color) {
VkClearValue value;
value.color = VkClearColorValue(color);
return clearInternal(attachment, value);
}
RenderPassBeginInfo& RenderPassBeginInfo::clearColor(const UnsignedInt attachment, const Vector4i& color) {
VkClearValue value;
value.color = VkClearColorValue(color);
return clearInternal(attachment, value);
}
RenderPassBeginInfo& RenderPassBeginInfo::clearColor(const UnsignedInt attachment, const Vector4ui& color) {
VkClearValue value;
value.color = VkClearColorValue(color);
return clearInternal(attachment, value);
}
RenderPassBeginInfo& RenderPassBeginInfo::clearDepthStencil(const UnsignedInt attachment, const Float depth, const UnsignedInt stencil) {
VkClearValue value;
value.depthStencil = {depth, stencil};
return clearInternal(attachment, value);
}
RenderPassBeginInfo& RenderPassBeginInfo::clearInternal(const UnsignedInt attachment, const VkClearValue& value) {
if(!_state) _state.emplace();
if(_state->clearValues.size() <= attachment)
arrayResize(_state->clearValues, Containers::NoInit, attachment + 1);
_state->clearValues[attachment] = value;
_info.clearValueCount = _state->clearValues.size();
_info.pClearValues = _state->clearValues;
return *this;
}
SubpassBeginInfo::SubpassBeginInfo(const SubpassContents contents): _info{} {
_info.sType = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO;
_info.contents = VkSubpassContents(contents);
}
SubpassBeginInfo::SubpassBeginInfo(NoInitT) noexcept {}
SubpassBeginInfo::SubpassBeginInfo(const VkSubpassBeginInfo& info):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(info) {}
SubpassEndInfo::SubpassEndInfo(): _info{} {
_info.sType = VK_STRUCTURE_TYPE_SUBPASS_END_INFO;
}
SubpassEndInfo::SubpassEndInfo(NoInitT) noexcept {}
SubpassEndInfo::SubpassEndInfo(const VkSubpassEndInfo& info):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(info) {}
}}

251
src/Magnum/Vk/RenderPass.h

@ -26,9 +26,11 @@
*/
/** @file
* @brief Class @ref Magnum::Vk::RenderPass
* @brief Class @ref Magnum::Vk::RenderPass, @ref Magnum::Vk::RenderPassBeginInfo, @ref Magnum::Vk::SubpassBeginInfo, @ref Magnum::Vk::SubpassEndInfo, enum @ref Magnum::Vk::SubpassContents
*/
#include <Corrade/Containers/Pointer.h>
#include "Magnum/Magnum.h"
#include "Magnum/Tags.h"
#include "Magnum/Vk/Handle.h"
@ -185,6 +187,253 @@ class MAGNUM_VK_EXPORT RenderPass {
HandleFlags _flags;
};
/**
@brief Render pass begin info
@m_since_latest
Wraps a @type_vk_keyword{RenderPassBeginInfo}.
@see @ref CommandBuffer::beginRenderPass()
*/
class MAGNUM_VK_EXPORT RenderPassBeginInfo {
public:
/**
* @brief Constructor
* @param renderPass A @ref RenderPass or a raw Vulkan render
* pass handle to begin an instance of
* @param framebuffer A @ref Framebuffer or a raw Vulkan
* framebuffer containing the attachments used with @p renderPass
* @param renderArea Render area affected by the render pass
* instance
*
* The following @type_vk{RenderPassBeginInfo} fields are pre-filled in
* addition to `sType`, everything else is zero-filled:
*
* - `renderPass`
* - `framebuffer`
* - `renderArea`
*
* If there are attachments with @ref AttachmentLoadOperation::Clear
* passed to @ref RenderPassCreateInfo::setAttachments() of
* @p renderPass, you need to call @ref clearColor() /
* @ref clearDepthStencil() with an attachment index corresponding to
* each of them.
*/
explicit RenderPassBeginInfo(VkRenderPass renderPass, VkFramebuffer framebuffer, const Range2Di& renderArea);
/**
* @brief Construct without initializing the contents
*
* Note that not even the `sType` field is set --- the structure has to
* be fully initialized afterwards in order to be usable.
*/
explicit RenderPassBeginInfo(NoInitT) noexcept;
/**
* @brief Construct from existing data
*
* Copies the existing values verbatim, pointers are kept unchanged
* without taking over the ownership. Modifying the newly created
* instance will not modify the original data nor the pointed-to data.
*/
explicit RenderPassBeginInfo(const VkRenderPassBeginInfo& info);
/** @brief Copying is not allowed */
RenderPassBeginInfo(const RenderPassBeginInfo&) = delete;
/** @brief Move constructor */
RenderPassBeginInfo(RenderPassBeginInfo&& other) noexcept;
~RenderPassBeginInfo();
/** @brief Copying is not allowed */
RenderPassBeginInfo& operator=(const RenderPassBeginInfo&) = delete;
/** @brief Move assignment */
RenderPassBeginInfo& operator=(RenderPassBeginInfo&& other) noexcept;
/**
* @brief Clear a floating-point or normalized color attachment
* @return Reference to self (for method chaining)
*
* @see @ref AttachmentLoadOperation::Clear
*/
RenderPassBeginInfo& clearColor(UnsignedInt attachment, const Color4& color);
/**
* @brief Clear a signed integral color attachment
* @return Reference to self (for method chaining)
*
* @see @ref AttachmentLoadOperation::Clear
*/
RenderPassBeginInfo& clearColor(UnsignedInt attachment, const Vector4i& color);
/**
* @brief Clear an unsigned integral color attachment
* @return Reference to self (for method chaining)
*
* @see @ref AttachmentLoadOperation::Clear
*/
RenderPassBeginInfo& clearColor(UnsignedInt attachment, const Vector4ui& color);
/**
* @brief Clear a depth/stencil attachment
* @return Reference to self (for method chaining)
*
* If the attachment is not a combined depth/stencil format, the unused
* value is ignored.
* @see @ref AttachmentLoadOperation::Clear
*/
RenderPassBeginInfo& clearDepthStencil(UnsignedInt attachment, Float depth, UnsignedInt stencil);
/** @brief Underlying @type_vk{RenderPassBeginInfo} structure */
VkRenderPassBeginInfo& operator*() { return _info; }
/** @overload */
const VkRenderPassBeginInfo& operator*() const { return _info; }
/** @overload */
VkRenderPassBeginInfo* operator->() { return &_info; }
/** @overload */
const VkRenderPassBeginInfo* operator->() const { return &_info; }
/** @overload */
operator const VkRenderPassBeginInfo*() const { return &_info; }
private:
RenderPassBeginInfo& clearInternal(UnsignedInt attachment, const VkClearValue& value);
VkRenderPassBeginInfo _info;
struct State;
Containers::Pointer<State> _state;
};
/**
@brief Subpass contents
@m_since_latest
Wraps @type_vk{SubpassContents}.
@see @ref SubpassBeginInfo::SubpassBeginInfo(),
@ref CommandBuffer::beginRenderPass(), @ref CommandBuffer::nextSubpass()
*/
enum class SubpassContents: Int {
/**
* Contents of the subpass will be recorded inline in the primary command
* buffer. @ref CommandBufferLevel::Secondary command buffers must not
* be executed within the subpass. This is the default used in the
* @ref SubpassBeginInfo constructor and consequently
* @ref CommandBuffer::beginRenderPass() / @ref CommandBuffer::nextSubpass().
*/
Inline = VK_SUBPASS_CONTENTS_INLINE,
/**
* Subpass contents are recorded in @ref CommandBufferLevel::Secondary
* command buffers that will be called from the primary command buffer.
* @todoc reference @fn_vk{CmdExecuteCommands} when exposed and mention
* it's the only allowed command until nextsubpass / renderpass end
*/
SecondaryCommandBuffers = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
};
/**
@brief Subpass begin info
@m_since_latest
Wraps @type_vk{SubpassBeginInfo}.
@see @ref CommandBuffer::beginRenderPass(), @ref CommandBuffer::nextSubpass()
*/
class MAGNUM_VK_EXPORT SubpassBeginInfo {
public:
/**
* @brief Constructor
* @param contents How commands in the subpass will be provided
*
* The following @type_vk{SubpassBeginInfo} fields are pre-filled in
* addition to `sType`, everything else is zero-filled:
*
* - `contents`
*/
explicit SubpassBeginInfo(SubpassContents contents = SubpassContents::Inline);
/**
* @brief Construct without initializing the contents
*
* Note that not even the `sType` field is set --- the structure has to
* be fully initialized afterwards in order to be usable.
*/
explicit SubpassBeginInfo(NoInitT) noexcept;
/**
* @brief Construct from existing data
*
* Copies the existing values verbatim, pointers are kept unchanged
* without taking over the ownership. Modifying the newly created
* instance will not modify the original data nor the pointed-to data.
*/
explicit SubpassBeginInfo(const VkSubpassBeginInfo& info);
/** @brief Underlying @type_vk{SubpassBeginInfo} structure */
VkSubpassBeginInfo& operator*() { return _info; }
/** @overload */
const VkSubpassBeginInfo& operator*() const { return _info; }
/** @overload */
VkSubpassBeginInfo* operator->() { return &_info; }
/** @overload */
const VkSubpassBeginInfo* operator->() const { return &_info; }
/** @overload */
operator const VkSubpassBeginInfo*() const { return &_info; }
private:
VkSubpassBeginInfo _info;
};
/**
@brief Subpass end info
@m_since_latest
Wraps @type_vk{SubpassEndInfo}.
@see @ref CommandBuffer::endRenderPass(), @ref CommandBuffer::nextSubpass()
*/
class MAGNUM_VK_EXPORT SubpassEndInfo {
public:
/**
* @brief Constructor
*
* The following @type_vk{SubpassEndInfo} fields are pre-filled in
* addition to `sType`, everything else is zero-filled:
*
* - *(none)*
*/
explicit SubpassEndInfo();
/**
* @brief Construct without initializing the contents
*
* Note that not even the `sType` field is set --- the structure has to
* be fully initialized afterwards in order to be usable.
*/
explicit SubpassEndInfo(NoInitT) noexcept;
/**
* @brief Construct from existing data
*
* Copies the existing values verbatim, pointers are kept unchanged
* without taking over the ownership. Modifying the newly created
* instance will not modify the original data nor the pointed-to data.
*/
explicit SubpassEndInfo(const VkSubpassEndInfo& info);
/** @brief Underlying @type_vk{SubpassEndInfo} structure */
VkSubpassEndInfo& operator*() { return _info; }
/** @overload */
const VkSubpassEndInfo& operator*() const { return _info; }
/** @overload */
VkSubpassEndInfo* operator->() { return &_info; }
/** @overload */
const VkSubpassEndInfo* operator->() const { return &_info; }
/** @overload */
operator const VkSubpassEndInfo*() const { return &_info; }
private:
VkSubpassEndInfo _info;
};
}}
#endif

5
src/Magnum/Vk/RenderPassCreateInfo.h

@ -64,7 +64,10 @@ enum class AttachmentLoadOperation: Int {
/**
* Previous contents are cleared to a value specified when a render pass
* instance is begun.
* instance is begun. You're required to provide a clear value for this
* attachment index using @ref RenderPassBeginInfo::clearColor() or
* @ref RenderPassBeginInfo::clearDepthStencil() when you begin render pass
* recording using @ref CommandBuffer::beginRenderPass().
*
* @m_class{m-note m-success}
*

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

@ -30,7 +30,10 @@
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Math/Color.h"
#include "Magnum/Math/Range.h"
#include "Magnum/Vk/Image.h"
#include "Magnum/Vk/Integration.h"
#include "Magnum/Vk/RenderPassCreateInfo.h"
namespace Magnum { namespace Vk { namespace Test { namespace {
@ -92,6 +95,21 @@ struct RenderPassTest: TestSuite::Tester {
void constructNoCreate();
void constructCopy();
void beginInfoConstruct();
void beginInfoConstructNoInit();
void beginInfoConstructClears();
void beginInfoConstructFromVk();
void beginInfoConstructCopy();
void beginInfoConstructMove();
void subpassBeginInfoConstruct();
void subpassBeginInfoConstructNoInit();
void subpassBeginInfoConstructFromVk();
void subpassEndInfoConstruct();
void subpassEndInfoConstructNoInit();
void subpassEndInfoConstructFromVk();
};
RenderPassTest::RenderPassTest() {
@ -164,7 +182,22 @@ RenderPassTest::RenderPassTest() {
&RenderPassTest::createInfoConvertToVk<VkRenderPassCreateInfo>,
&RenderPassTest::constructNoCreate,
&RenderPassTest::constructCopy});
&RenderPassTest::constructCopy,
&RenderPassTest::beginInfoConstruct,
&RenderPassTest::beginInfoConstructNoInit,
&RenderPassTest::beginInfoConstructClears,
&RenderPassTest::beginInfoConstructFromVk,
&RenderPassTest::beginInfoConstructCopy,
&RenderPassTest::beginInfoConstructMove,
&RenderPassTest::subpassBeginInfoConstruct,
&RenderPassTest::subpassBeginInfoConstructNoInit,
&RenderPassTest::subpassBeginInfoConstructFromVk,
&RenderPassTest::subpassEndInfoConstruct,
&RenderPassTest::subpassEndInfoConstructNoInit,
&RenderPassTest::subpassEndInfoConstructFromVk});
}
template<class> struct Traits;
@ -971,6 +1004,133 @@ void RenderPassTest::constructCopy() {
CORRADE_VERIFY(!std::is_copy_assignable<RenderPass>{});
}
void RenderPassTest::beginInfoConstruct() {
auto renderPass = reinterpret_cast<VkRenderPass>(0xbadbeef);
auto framebuffer = reinterpret_cast<VkFramebuffer>(0xdeadcafe);
RenderPassBeginInfo info{renderPass, framebuffer, Range2Di{{3, 7}, {15, 78}}};
CORRADE_COMPARE(info->renderPass, renderPass);
CORRADE_COMPARE(info->framebuffer, framebuffer);
CORRADE_COMPARE(Range2Di{info->renderArea}, (Range2Di{{3, 7}, {15, 78}}));
CORRADE_COMPARE(info->clearValueCount, 0);
CORRADE_VERIFY(!info->pClearValues);
}
void RenderPassTest::beginInfoConstructNoInit() {
RenderPassBeginInfo info{NoInit};
info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&info) RenderPassBeginInfo{NoInit};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY((std::is_nothrow_constructible<RenderPassBeginInfo, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, RenderPassBeginInfo>::value));
}
void RenderPassTest::beginInfoConstructClears() {
RenderPassBeginInfo info{{}, {}, {}};
info.clearColor(5, Color4{0.5f, 0.6f, 0.7f, 0.8f})
.clearColor(7, Vector4i{1, -2, 3, -4})
.clearColor(15, Vector4ui{8, 12, 33, 1})
/* Use one of the first IDs at last to verify the array doesn't get
shortened */
.clearDepthStencil(2, 15.0f, 1337);
CORRADE_COMPARE(info->clearValueCount, 16);
CORRADE_COMPARE(Color4{info->pClearValues[5].color}, (Color4{0.5f, 0.6f, 0.7f, 0.8f}));
CORRADE_COMPARE(Vector4i{info->pClearValues[7].color}, (Vector4i{1, -2, 3, -4}));
CORRADE_COMPARE(Vector4ui{info->pClearValues[15].color}, (Vector4ui{8, 12, 33, 1}));
CORRADE_COMPARE(info->pClearValues[2].depthStencil.depth, 15.0f);
CORRADE_COMPARE(info->pClearValues[2].depthStencil.stencil, 1337);
}
void RenderPassTest::beginInfoConstructFromVk() {
VkRenderPassBeginInfo vkInfo;
vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
RenderPassBeginInfo info{vkInfo};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
}
void RenderPassTest::beginInfoConstructCopy() {
CORRADE_VERIFY(!(std::is_copy_constructible<RenderPassBeginInfo>{}));
CORRADE_VERIFY(!(std::is_copy_assignable<RenderPassBeginInfo>{}));
}
void RenderPassTest::beginInfoConstructMove() {
RenderPassBeginInfo a{{}, {}, {}};
a.clearColor(5, Color4{0.5f, 0.6f, 0.7f, 0.8f});
CORRADE_COMPARE(a->clearValueCount, 6);
CORRADE_COMPARE(Color4{a->pClearValues[5].color}, (Color4{0.5f, 0.6f, 0.7f, 0.8f}));
RenderPassBeginInfo b = std::move(a);
CORRADE_COMPARE(a->clearValueCount, 0);
CORRADE_VERIFY(!a->pClearValues);
CORRADE_COMPARE(b->clearValueCount, 6);
CORRADE_COMPARE(Color4{b->pClearValues[5].color}, (Color4{0.5f, 0.6f, 0.7f, 0.8f}));
RenderPassBeginInfo c{VkRenderPassBeginInfo{}};
c = std::move(b);
CORRADE_COMPARE(b->clearValueCount, 0);
CORRADE_VERIFY(!b->pClearValues);
CORRADE_COMPARE(c->clearValueCount, 6);
CORRADE_COMPARE(Color4{c->pClearValues[5].color}, (Color4{0.5f, 0.6f, 0.7f, 0.8f}));
CORRADE_VERIFY(std::is_nothrow_move_constructible<RenderPassBeginInfo>::value);
CORRADE_VERIFY(std::is_nothrow_move_assignable<RenderPassBeginInfo>::value);
}
void RenderPassTest::subpassBeginInfoConstruct() {
SubpassBeginInfo info{SubpassContents::SecondaryCommandBuffers};
CORRADE_COMPARE(info->contents, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
}
void RenderPassTest::subpassBeginInfoConstructNoInit() {
SubpassBeginInfo info{NoInit};
info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&info) SubpassBeginInfo{NoInit};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY((std::is_nothrow_constructible<SubpassBeginInfo, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, SubpassBeginInfo>::value));
}
void RenderPassTest::subpassBeginInfoConstructFromVk() {
VkSubpassBeginInfo vkInfo;
vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
SubpassBeginInfo info{vkInfo};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
}
void RenderPassTest::subpassEndInfoConstruct() {
SubpassEndInfo info{};
CORRADE_VERIFY(info->sType);
}
void RenderPassTest::subpassEndInfoConstructNoInit() {
SubpassEndInfo info{NoInit};
info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&info) SubpassEndInfo{NoInit};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY((std::is_nothrow_constructible<SubpassEndInfo, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, SubpassEndInfo>::value));
}
void RenderPassTest::subpassEndInfoConstructFromVk() {
VkSubpassEndInfo vkInfo;
vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
SubpassEndInfo info{vkInfo};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::RenderPassTest)

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

@ -27,7 +27,15 @@
#include <Corrade/Containers/Array.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Math/Color.h"
#include "Magnum/Math/Range.h"
#include "Magnum/Vk/CommandBuffer.h"
#include "Magnum/Vk/CommandPoolCreateInfo.h"
#include "Magnum/Vk/DeviceProperties.h"
#include "Magnum/Vk/FramebufferCreateInfo.h"
#include "Magnum/Vk/Handle.h"
#include "Magnum/Vk/ImageCreateInfo.h"
#include "Magnum/Vk/ImageViewCreateInfo.h"
#include "Magnum/Vk/RenderPassCreateInfo.h"
#include "Magnum/Vk/Result.h"
#include "Magnum/Vk/VulkanTester.h"
@ -43,6 +51,8 @@ struct RenderPassVkTest: VulkanTester {
void constructMove();
void wrap();
void cmdBeginEnd();
};
RenderPassVkTest::RenderPassVkTest() {
@ -51,7 +61,9 @@ RenderPassVkTest::RenderPassVkTest() {
&RenderPassVkTest::constructSubpassNoAttachments,
&RenderPassVkTest::constructMove,
&RenderPassVkTest::wrap});
&RenderPassVkTest::wrap,
&RenderPassVkTest::cmdBeginEnd});
}
void RenderPassVkTest::construct() {
@ -129,6 +141,57 @@ void RenderPassVkTest::wrap() {
device()->DestroyRenderPass(device(), renderPass, nullptr);
}
void RenderPassVkTest::cmdBeginEnd() {
using namespace Math::Literals;
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* Using a depth attachment as well even though not strictly necessary to
catch potential unexpected bugs */
Image color{device(), ImageCreateInfo2D{ImageUsage::ColorAttachment,
VK_FORMAT_R8G8B8A8_UNORM, {256, 256}, 1}, MemoryFlag::DeviceLocal};
Image depth{device(), ImageCreateInfo2D{ImageUsage::DepthStencilAttachment,
VK_FORMAT_D24_UNORM_S8_UINT, {256, 256}, 1}, MemoryFlag::DeviceLocal};
ImageView colorView{device(), ImageViewCreateInfo2D{color}};
ImageView depthView{device(), ImageViewCreateInfo2D{depth}};
RenderPass renderPass{device(), RenderPassCreateInfo{}
.setAttachments({
{color.format(), AttachmentLoadOperation::Clear, {}},
{depth.format(), AttachmentLoadOperation::Clear, {}},
})
.addSubpass(SubpassDescription{}
.setColorAttachments({0})
.setDepthStencilAttachment(1)
)
/* Further subpasses with no attachments so we can test nextSubpass()
but don't need to specify subpass dependencies (which I have no idea
about yet) */
.addSubpass(SubpassDescription{})
.addSubpass(SubpassDescription{})
};
Framebuffer framebuffer{device(), FramebufferCreateInfo{renderPass, {
colorView,
depthView
}, {256, 256}}};
cmd.begin()
.beginRenderPass(RenderPassBeginInfo{renderPass, framebuffer, {{}, {256, 256}}}
.clearColor(0, 0x1f1f1f_rgbf)
.clearDepthStencil(1, 1.0f, 0))
.nextSubpass()
/* The above overload goes through a different code path than this */
.nextSubpass(SubpassEndInfo{})
.endRenderPass()
.end();
/* Err there's not really anything visible to verify */
CORRADE_VERIFY(cmd.handle());
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::RenderPassVkTest)

3
src/Magnum/Vk/Vk.h

@ -80,6 +80,7 @@ class Queue;
enum class QueueFlag: UnsignedInt;
typedef Containers::EnumSet<QueueFlag> QueueFlags;
class RenderPass;
class RenderPassBeginInfo;
class RenderPassCreateInfo;
/* AttachmentDescription, AttachmentReference, SubpassDescription,
SubpassDependency are useful only to be passed directly to
@ -87,6 +88,8 @@ class RenderPassCreateInfo;
enum class Result: Int;
class Shader;
class ShaderCreateInfo;
class SubpassBeginInfo;
class SubpassEndInfo;
enum class Version: UnsignedInt;
#endif

Loading…
Cancel
Save