Program Listing for File RenderPassHelper.hpp

Program Listing for File RenderPassHelper.hpp#

↰ Return to documentation for file (Src/GraphicsEngineVulkan/common/RenderPassHelper.hpp)

#pragma once

#include <span>

#include <vulkan/vulkan.hpp>

namespace Kataglyphis {

// Single-sample, stencil don't-care; a multisampled or stencil-using attachment builds its own and says why.
constexpr vk::AttachmentDescription buildAttachmentDescription(vk::Format format,
  vk::ImageLayout final_layout,
  vk::AttachmentLoadOp load_op = vk::AttachmentLoadOp::eClear,
  vk::AttachmentStoreOp store_op = vk::AttachmentStoreOp::eStore,
  vk::ImageLayout initial_layout = vk::ImageLayout::eUndefined)
{
    vk::AttachmentDescription description{};
    description.format = format;
    description.samples = vk::SampleCountFlagBits::e1;
    description.loadOp = load_op;
    description.storeOp = store_op;
    description.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
    description.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
    description.initialLayout = initial_layout;
    description.finalLayout = final_layout;
    return description;
}

// Always the full extent; a pass needing a partial render area builds its own and says why.
constexpr vk::RenderPassBeginInfo buildRenderPassBeginInfo(vk::RenderPass render_pass,
  vk::Framebuffer framebuffer,
  vk::Extent2D extent,
  std::span<const vk::ClearValue> clear_values)
{
    return vk::RenderPassBeginInfo{ render_pass,
        framebuffer,
        vk::Rect2D{ vk::Offset2D{ 0, 0 }, extent },
        static_cast<uint32_t>(clear_values.size()),
        clear_values.data() };
}

// Borrows both spans and depth_attachment: they must outlive the createRenderPass call.
constexpr vk::SubpassDescription buildSubpassDescription(std::span<const vk::AttachmentReference> color_attachments,
  const vk::AttachmentReference *depth_attachment,
  std::span<const vk::AttachmentReference> input_attachments = {})
{
    vk::SubpassDescription subpass{};
    subpass.pipelineBindPoint = vk::PipelineBindPoint::eGraphics;
    subpass.colorAttachmentCount = static_cast<uint32_t>(color_attachments.size());
    subpass.pColorAttachments = color_attachments.data();
    subpass.pDepthStencilAttachment = depth_attachment;
    subpass.inputAttachmentCount = static_cast<uint32_t>(input_attachments.size());
    subpass.pInputAttachments = input_attachments.data();
    return subpass;
}

// Borrows all three spans; pNext is left for the caller (CascadedShadowMap chains multiview).
constexpr vk::RenderPassCreateInfo buildRenderPassCreateInfo(std::span<const vk::AttachmentDescription> attachments,
  std::span<const vk::SubpassDescription> subpasses,
  std::span<const vk::SubpassDependency> dependencies)
{
    return vk::RenderPassCreateInfo{ vk::RenderPassCreateFlags{},
        static_cast<uint32_t>(attachments.size()),
        attachments.data(),
        static_cast<uint32_t>(subpasses.size()),
        subpasses.data(),
        static_cast<uint32_t>(dependencies.size()),
        dependencies.data() };
}

// The depth buffer is shared across frames in flight, so the last write must land before this clear; not by-region.
constexpr vk::SubpassDependency buildExternalColorDepthDependency()
{
    vk::SubpassDependency dependency{};
    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    dependency.dstSubpass = 0;
    dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput
                              | vk::PipelineStageFlagBits::eEarlyFragmentTests
                              | vk::PipelineStageFlagBits::eLateFragmentTests;
    dependency.srcAccessMask =
      vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
    dependency.dstStageMask =
      vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests;
    dependency.dstAccessMask =
      vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
    dependency.dependencyFlags = vk::DependencyFlags{};
    return dependency;
}

// PostStage's colour-only twin: orders its load against SkyBox's earlier write to the same swapchain image.
constexpr vk::SubpassDependency buildExternalColorDependency()
{
    vk::SubpassDependency dependency{};
    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
    dependency.dstSubpass = 0;
    dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
    dependency.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
    dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
    dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite;
    dependency.dependencyFlags = vk::DependencyFlags{};
    return dependency;
}

// Idempotent: a null device is a no-op and the handle is nulled through the reference.
inline void destroyRenderPass(vk::Device device, vk::RenderPass &render_pass)
{
    if (!device) { return; }
    if (render_pass) {
        device.destroyRenderPass(render_pass);
        render_pass = nullptr;
    }
}

}// namespace Kataglyphis