| /* | |
| * Copyright 2025 Rive | |
| */ | |
| #pragma once | |
| #include <vulkan/vulkan.h> | |
| #include "rive/renderer/vulkan/vulkan_context.hpp" | |
| #include "rive/renderer/gpu.hpp" | |
| namespace rive::gpu | |
| { | |
| class DrawPipelineLayoutVulkan; | |
| class PipelineManagerVulkan; | |
| // Rive-specific options for configuring a render pass. | |
| enum class RenderPassOptionsVulkan | |
| { | |
| none = 0, | |
| // No need to attach the COLOR texture as an input attachment. There are | |
| // no advanced blend modes so we can use built-in hardware blending. | |
| fixedFunctionColorOutput = 1 << 0, | |
| // rasterOrdering or depthStencil only: The render pass has a fullscreen | |
| // draw at the end that resolves rendering data into the renderTarget. | |
| // (e.g., by transferring color from offscreen or manually averaging MSAA.) | |
| manuallyResolved = 1 << 1, | |
| // rasterOrdering mode only: Store all transient attachments to memory | |
| // so the render pass can be interrupted and restarted. | |
| rasterOrderingInterruptible = 1 << 2, | |
| // rasterOrdering mode only: This render pass is resuming after an | |
| // interrupt; load all transient attachments from memory. | |
| rasterOrderingResume = 1 << 3, | |
| // Atomic mode only: Use an offscreen texture to render color, but also | |
| // attach the real target texture at the COALESCED_ATOMIC_RESOLVE index, | |
| // and render to it directly in the atomic resolve step. | |
| atomicCoalescedResolveAndTransfer = 1 << 4, | |
| // MSAA only, while using LoadAction::preserveRenderTarget: We have to | |
| // initialize the (transient) MSAA color attachment from an offscreen | |
| // texture bound as an input attachment, because the final render target | |
| // itself can't be bound as an input attachment. | |
| msaaSeedFromOffscreenTexture = 1 << 5, | |
| }; | |
| constexpr static int RENDER_PASS_OPTION_COUNT = 6; | |
| // This masks out RenderPassOptions that don't affect layout, allowing different | |
| // render passes to reference the same VkPipelineLayout where possible. | |
| // e.g., RenderPassOptions that deal with interrupting a render pass don't | |
| // affect layout. | |
| constexpr static RenderPassOptionsVulkan RENDER_PASS_OPTIONS_LAYOUT_MASK = | |
| ~(RenderPassOptionsVulkan::rasterOrderingInterruptible | | |
| RenderPassOptionsVulkan::rasterOrderingResume); | |
| class RenderPassVulkan | |
| { | |
| public: | |
| constexpr static uint64_t FORMAT_BIT_COUNT = 9; | |
| constexpr static uint64_t LOAD_OP_BIT_COUNT = 2; | |
| constexpr static uint64_t KEY_NO_INTERLOCK_MODE_BIT_COUNT = | |
| FORMAT_BIT_COUNT + RENDER_PASS_OPTION_COUNT + LOAD_OP_BIT_COUNT; | |
| constexpr static uint64_t KEY_BIT_COUNT = | |
| KEY_NO_INTERLOCK_MODE_BIT_COUNT + gpu::INTERLOCK_MODE_BIT_COUNT; | |
| static_assert(KEY_BIT_COUNT <= 32); | |
| // Shader unique keys also include the interlock mode, so we don't always | |
| // need it in the render pass key. | |
| static uint32_t KeyNoInterlockMode(RenderPassOptionsVulkan, | |
| VkFormat renderTargetFormat, | |
| gpu::LoadAction); | |
| static uint32_t Key(gpu::InterlockMode, | |
| RenderPassOptionsVulkan, | |
| VkFormat renderTargetFormat, | |
| gpu::LoadAction); | |
| RenderPassVulkan(PipelineManagerVulkan*, | |
| gpu::InterlockMode, | |
| RenderPassOptionsVulkan, | |
| VkFormat renderTargetFormat, | |
| gpu::LoadAction); | |
| ~RenderPassVulkan(); | |
| RenderPassVulkan(const RenderPassVulkan&) = delete; | |
| RenderPassVulkan& operator=(const RenderPassVulkan&) = delete; | |
| const DrawPipelineLayoutVulkan* drawPipelineLayout() const | |
| { | |
| return m_drawPipelineLayout; | |
| } | |
| operator VkRenderPass() const { return m_renderPass; } | |
| private: | |
| const rcp<VulkanContext> m_vk; | |
| // Raw pointer into impl->m_drawPipelineLayouts. RenderContextVulkanImpl | |
| // ensures the pipline layouts outlive this RenderPass instance. | |
| const DrawPipelineLayoutVulkan* m_drawPipelineLayout = nullptr; | |
| VkRenderPass m_renderPass = VK_NULL_HANDLE; | |
| }; | |
| } // namespace rive::gpu |