/*
Crafter®.Graphics
Copyright (C) 2026 Catcrafts®
catcrafts.net

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 3.0 as published by the Free Software Foundation;

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
*/
module;
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
#include "vulkan/vulkan.h"
#endif // !CRAFTER_GRAPHICS_WINDOW_DOM
export module Crafter.Graphics:RenderPass;
import std;
import :GraphicsTypes;

export namespace Crafter {
    struct Window;

#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
    // Conservative union of every pipeline stage that can write the swapchain
    // storage image: a compute pass via COMPUTE_SHADER, a ray-tracing pass via
    // RAY_TRACING_SHADER, plus TRANSFER for any blit/copy writer. Used as the
    // RenderPass default (a pass that doesn't narrow its own stage) and as the
    // fallback when there are no passes to derive a real union from. Far tighter
    // than ALL_COMMANDS, but never under-synchronises a polymorphic pass.
    inline constexpr VkPipelineStageFlags kSwapchainWriterStages =
        VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
      | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR
      | VK_PIPELINE_STAGE_TRANSFER_BIT;
#endif // !CRAFTER_GRAPHICS_WINDOW_DOM

    struct RenderPass {
        virtual void Record(GraphicsCommandBuffer cmd, std::uint32_t frameIdx, Window& window) = 0;
        virtual ~RenderPass() = default;
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
        // Pipeline stage at which this pass reads and writes the swapchain
        // storage image. The frame loop uses this to scope the inter-pass and
        // frame-edge barriers to the stages that actually touch the image
        // instead of ALL_COMMANDS. A subclass MUST narrow this to its real
        // stage (RTPass -> RAY_TRACING_SHADER, a compute pass -> COMPUTE_SHADER):
        // the default is the conservative writer union so an un-overridden pass
        // can never be under-synchronised, only over-synchronised.
        virtual VkPipelineStageFlags SwapchainStage() const { return kSwapchainWriterStages; }
#endif // !CRAFTER_GRAPHICS_WINDOW_DOM
    };

#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
    // Union of the swapchain-access stages declared by `passes` — the "real"
    // per-pass stage union the frame-edge barriers (acquire dst / present src)
    // narrow to: an all-compute frame yields COMPUTE_SHADER only, a frame with
    // any RT pass folds in RAY_TRACING_SHADER, and so on. Falls back to the
    // conservative writer union when there are no passes (the image is still
    // transitioned, just never written), so the barrier is always well-formed.
    inline VkPipelineStageFlags SwapchainStageUnion(std::span<RenderPass* const> passes) {
        if (passes.empty()) return kSwapchainWriterStages;
        VkPipelineStageFlags stages = 0;
        for (RenderPass* pass : passes) stages |= pass->SwapchainStage();
        return stages;
    }

    // The inter-pass swapchain barrier (replacing the old queue-wide
    // VkMemoryBarrier at the #115 location). Scoped to the swapchain image's
    // single colour subresource so only that image's shader caches round-trip —
    // unrelated buffers/images stay resident — exactly as the intra-pass UI
    // barrier already does. The image is bound as a storage image and stays in
    // VK_IMAGE_LAYOUT_GENERAL, so this is a pure memory dependency (no layout
    // transition). The execution scope (stage masks) is supplied per pass pair
    // by the caller via vkCmdPipelineBarrier.
    inline VkImageMemoryBarrier BuildSwapchainInterPassBarrier(VkImage image) {
        return {
            .sType               = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
            .srcAccessMask       = VK_ACCESS_SHADER_WRITE_BIT,
            .dstAccessMask       = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
            .oldLayout           = VK_IMAGE_LAYOUT_GENERAL,
            .newLayout           = VK_IMAGE_LAYOUT_GENERAL,
            .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
            .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
            .image               = image,
            .subresourceRange    = {
                .aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT,
                .baseMipLevel   = 0,
                .levelCount     = 1,
                .baseArrayLayer = 0,
                .layerCount     = 1,
            },
        };
    }
#endif // !CRAFTER_GRAPHICS_WINDOW_DOM
}
