Magnum::Vk::RenderPass class new in Git master

Render pass.

Wraps a VkRenderPass, represents a collection of attachment descriptions, subpasses and their dependencies. The render pass description is independent of any specific image views used for attachments, these two are connected together in a Framebuffer.

Render pass creation

A RenderPassCreateInfo consists of:

A render pass has to have at least one subpass. It's common to have just one subpass, but while the subpass isn't required to operate on any attachments, such case is rather rare. Following is a simple setup for one subpass operating on a color and a combined depth/stencil attachment. Each AttachmentDescription describes a concrete attachment and particular SubpassDescription::setColorAttachments() / setColorAttachments() then reference it by an index.

In addition to a format, each AttachmentDescription has to specify an AttachmentLoadOperation that happens at the render pass begin — whether we want to preserve the contents, clear them or discard — and similarly an AttachmentStoreOperation at the end. Then, the ImageLayout parameters specify what implicit layout transitions (if any) need to happen between start of the render pass and the first subpass, between subpasses and between last subpass and end of the render pass.

The following snippet shows attachment and subpass setup for a single-pass color/depth render. Commonly the image is used in some way after the render pass, in this case it'll get transferred to the host, as indicated by ImageLayout::TransferSource. That will also need an explicit subpass dependency, as explained below.

#include <Magnum/Vk/RenderPassCreateInfo.h>



Vk::RenderPass renderPass{device, Vk::RenderPassCreateInfo{}
    .setAttachments({
        Vk::AttachmentDescription{Vk::PixelFormat::RGBA8Srgb,
            Vk::AttachmentLoadOperation::Clear,
            Vk::AttachmentStoreOperation::Store,
            Vk::ImageLayout::Undefined,
            Vk::ImageLayout::TransferSource},
        Vk::AttachmentDescription{Vk::PixelFormat::Depth24UnormStencil8UI,
            Vk::AttachmentLoadOperation::Clear,
            Vk::AttachmentStoreOperation::DontCare,
            Vk::ImageLayout::Undefined,
            Vk::ImageLayout::DepthStencilAttachment}
    })
    .addSubpass(Vk::SubpassDescription{}
        .setColorAttachments({
            Vk::AttachmentReference{0, Vk::ImageLayout::ColorAttachment}
        })
        .setDepthStencilAttachment(
            Vk::AttachmentReference{1, Vk::ImageLayout::DepthStencilAttachment}
        )
    )

Subpass dependencies

As shown above, the application is required to specify ImageLayout at the start and end of the render pass as well as layouts in which the attachments are expected to be inside a particular subpass, and Vulkan then takes care of doing layout transitions at a proper time. If a transition from one layout to another needs to occur, a SubpassDependency defines when, and if none is explicitly specified, an implicit dependency is added by Vulkan. The above setup can be visualized as this, with implicit transitions shown as arrows:

RenderPass layout transition cluster_renderpass Render pass cluster_subpass Subpass colorUndefined Undefined colorAttachment Color Attachment colorUndefined->colorAttachment Clear depthUndefined Undefined depthAttachment Depth Attachment depthUndefined->depthAttachment Clear transferSource Transfer Source colorAttachment->transferSource Store

The implicit dependencies added by Vulkan only ensure that the transition from ImageLayout::Undefined to ColorAttachment / DepthStencilAttachment happen at some point before the start of the renderpass, and the transition to TransferSource is eventually done as well. In this case the initial transition is fine; for the transfer layout transition we however need it to happen before we do the actual transfer:

    .setDependencies({
        Vk::SubpassDependency{
            /* An operation external to the render pass depends on the first
               subpass */
            0, Vk::SubpassDependency::External,
            /* where transfer gets executed only after color output is done */
            Vk::PipelineStage::ColorAttachmentOutput,
            Vk::PipelineStage::Transfer,
            /* and color data written are available for the transfer to read */
            Vk::Access::ColorAttachmentWrite,
            Vk::Access::TransferRead}
    })
};

Render pass recording

A render pass recording inside a CommandBuffer is begun with CommandBuffer::beginRenderPass(), to which point Vulkan schedules all implicit layout transitions. Together with a render pass you need to supply a compatible Framebuffer containing actual image views for each attachment and a clear value for each attachment that had AttachmentLoadOperation::Clear specified. After that you can execute CommandBuffer commands that are allowed inside a render pass:

Vk::CommandBuffer cmd = ;
cmd.begin()
   
   .beginRenderPass(Vk::RenderPassBeginInfo{renderPass, framebuffer}
        .clearColor(0, 0x1f1f1f_srgbf)
        .clearDepthStencil(1, 1.0f, 0))

Advancing to the next subpass (if any) can be done with nextSubpass(), and finally endRenderPass() ends the render pass. As with render pass begin, these make Vulkan schedule implicit layout transitions between subpasses and at render pass end.

   .endRenderPass()
   
   .end();

Public static functions

static auto wrap(Device& device, VkRenderPass handle, HandleFlags flags = {}) -> RenderPass
Wrap existing Vulkan handle.

Constructors, destructors, conversion operators

RenderPass(Device& device, const RenderPassCreateInfo& info) explicit
Constructor.
RenderPass(NoCreateT) explicit
Construct without creating the render pass.
RenderPass(const RenderPass&) deleted
Copying is not allowed.
RenderPass(RenderPass&& other) noexcept
Move constructor.
~RenderPass()
Destructor.
operator VkRenderPass()

Public functions

auto operator=(const RenderPass&) -> RenderPass& deleted
Copying is not allowed.
auto operator=(RenderPass&& other) -> RenderPass& noexcept
Move assignment.
auto handle() -> VkRenderPass
Underlying VkRenderPass handle.
auto handleFlags() const -> HandleFlags
Handle flags.
auto release() -> VkRenderPass
Release the underlying Vulkan render pass.

Function documentation

static RenderPass Magnum::Vk::RenderPass::wrap(Device& device, VkRenderPass handle, HandleFlags flags = {})

Wrap existing Vulkan handle.

Parameters
device Vulkan device the render pass is created on
handle The VkRenderPass handle
flags Handle flags

The handle is expected to be originating from device. Unlike a render pass created using a constructor, the Vulkan render pass is by default not deleted on destruction, use flags for different behavior.

Magnum::Vk::RenderPass::RenderPass(Device& device, const RenderPassCreateInfo& info) explicit

Constructor.

Parameters
device Vulkan device to create the render pass on
info Render pass creation info

If Vulkan 1.2 is not supported and the KHR_create_renderpass2 extension is not enabled on device, only the subset provided by RenderPassCreateInfo::vkRenderPassCreateInfo() is used to create the render pass.

Magnum::Vk::RenderPass::RenderPass(NoCreateT) explicit

Construct without creating the render pass.

The constructed instance is equivalent to moved-from state. Useful in cases where you will overwrite the instance later anyway. Move another object over it to make it useful.

Magnum::Vk::RenderPass::~RenderPass()

Destructor.

Destroys associated VkRenderPass handle, unless the instance was created using wrap() without HandleFlag::DestroyOnDestruction specified.

Magnum::Vk::RenderPass::operator VkRenderPass()

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

VkRenderPass Magnum::Vk::RenderPass::release()

Release the underlying Vulkan render pass.

Releases ownership of the Vulkan render pass and returns its handle so vkDestroyRenderPass() is not called on destruction. The internal state is then equivalent to moved-from state.