forward.cpp

cross platform rendering playground

src/passes/forward/forward.cpp

7.29 KB
#include "forward.h"

#include "backend/rhi_types.h"
#include "renderer.h"
#include "shaders/renderer_types.h"

namespace forward {

Resources record(
    rhi::Device &device,
    Pipelines &pipelines,
    rhi::ShaderCompiler &sc,
    FrameGraph &fg,
    BufferHandle indirect,
    BufferHandle draw_count,
    BufferHandle visible,
    ImageHandle cascade[Light::CASCADE_COUNT],
    BufferHandle cluster_bounds,
    BufferHandle cluster_records,
    BufferHandle light_index_list,
    ddgi_trace::Resources &ddgi,
    ImageHandle &depth_texture
) {
    rhi::RenderPipelineDesc forward_p;
    forward_p.device = &device;
    forward_p.set_shaders(sc, "src/passes/forward/forward.slang", "vsMain", "fsMain");
    forward_p.set_depth_testing(true, false, rhi::PipelineCompareOp::EQUAL);
    forward_p.set_color_format(rhi::ImageFormat::RGBA16_FLOAT);
    forward_p.set_cull_mode(rhi::PipelineCullMode::BACK, rhi::PipelineTriangleWindingOrder::CW);
    forward_p.set_depth_format(rhi::ImageFormat::D32_FLOAT);
    forward_p.set_multisampling(MSAA_SAMPLE_COUNT);
    pipelines.add_render("Forward", forward_p);

    rhi::RenderPipelineDesc wireframe_p;
    wireframe_p.device = &device;
    wireframe_p.set_shaders(sc, "src/passes/forward/forward.slang", "vsMain", "fsWireMain");
    wireframe_p.set_depth_testing(true, false, rhi::PipelineCompareOp::GREATER_EQUAL);
    wireframe_p.set_cull_mode(rhi::PipelineCullMode::BACK, rhi::PipelineTriangleWindingOrder::CW);
    wireframe_p.set_polygon_mode(rhi::PipelineFillMode::WIREFRAME);
    wireframe_p.set_color_format(rhi::ImageFormat::RGBA16_FLOAT);
    wireframe_p.set_depth_format(rhi::ImageFormat::D32_FLOAT);
    wireframe_p.set_multisampling(MSAA_SAMPLE_COUNT);
    pipelines.add_render("Wireframe", wireframe_p);

    Resources res;
    res.hdr = fg.add_image({
        .desc = {.format = rhi::ImageFormat::RGBA16_FLOAT},
        .name = "fg/forward/hdr",
        .size_class = SizeOp::Swapchain,
        .view = {.type = rhi::ImageViewType::Sampled},
    });
    res.depth = depth_texture; // just to keep the passes after this working for now
    if constexpr (MSAA_SAMPLE_COUNT != rhi::SampleCount::Sample1) {
        res.hdr_msaa = fg.add_image({
            .desc = {.sample_count = MSAA_SAMPLE_COUNT, .format = rhi::ImageFormat::RGBA16_FLOAT},
            .name = "fg/forward/hdr-msaa",
            .size_class = SizeOp::Swapchain,
        });
        res.depth_msaa = fg.add_image({
            .desc = {.sample_count = MSAA_SAMPLE_COUNT, .format = rhi::ImageFormat::D32_FLOAT},
            .name = "fg/forward/depth-msaa",
            .size_class = SizeOp::Swapchain,
        });
    }

    auto &builder = fg.add_pass("Forward");
    builder.read(indirect, rhi::ResourceState::IndirectFetch);
    builder.read(draw_count, rhi::ResourceState::IndirectFetch);
    builder.read(visible, rhi::ResourceState::StorageRead);
    // Depth is tested (read) and stored (write): LOAD + depth-test + STORE.
    builder.read_write(res.depth, rhi::ResourceState::DepthDraw);
    for (u32 i = 0; i < Light::CASCADE_COUNT; ++i) {
        builder.read(cascade[i], rhi::ResourceState::TextureSample);
    }
    builder.read(cluster_bounds, rhi::ResourceState::StorageRead);
    builder.read(cluster_records, rhi::ResourceState::StorageRead);
    builder.read(light_index_list, rhi::ResourceState::StorageRead);
    builder.write(res.hdr, rhi::ResourceState::ColorDraw);
    if constexpr (MSAA_SAMPLE_COUNT != rhi::SampleCount::Sample1) {
        builder.write(res.hdr_msaa, rhi::ResourceState::ColorDraw);
        builder.write(res.depth_msaa, rhi::ResourceState::DepthDraw);
    }

    rhi::RenderPipeline &pipeline = pipelines.get_render("Forward");

    builder.execute([=, &pipeline](PassContext &ctx) {
        FrameData &frame = ctx.frame_data[ctx.frame_index];

        auto main_view = ctx.image_view(res.hdr, {.aspect = rhi::ImageAspect::Color, .mip_count = 1});
        auto depth_view = ctx.image_view(res.depth, {.aspect = rhi::ImageAspect::Depth, .mip_count = 1});

        rhi::RenderingInfo ri{};
        ri.colorAttachmentCount = 1;
        ri.colorAttachments[0].loadOp = rhi::LoadOp::CLEAR;
        ri.colorAttachments[0].clearValue.color.float32[0] = 0.0f;
        ri.colorAttachments[0].clearValue.color.float32[1] = 0.0f;
        ri.colorAttachments[0].clearValue.color.float32[2] = 0.0f;
        ri.colorAttachments[0].clearValue.color.float32[3] = 1.0f;
        ri.depthAttachment.loadOp = rhi::LoadOp::LOAD;
        ri.depthAttachment.clearValue.depthStencil = {0.0f, 0};

        // Views must outlive begin_rendering(); default (invalid) when MSAA is off.
        rhi::ImageView msaa_color{};
        rhi::ImageView msaa_depth{};
        if constexpr (MSAA_SAMPLE_COUNT != rhi::SampleCount::Sample1) {
            msaa_color = ctx.image_view(res.hdr_msaa, {.aspect = rhi::ImageAspect::Color, .mip_count = 1});
            msaa_depth = ctx.image_view(res.depth_msaa, {.aspect = rhi::ImageAspect::Depth, .mip_count = 1});

            // written by the resolve. MSAA contents are fully consumed by it.
            ri.colorAttachments[0].img = &msaa_color;
            ri.colorAttachments[0].storeOp = rhi::StoreOp::DISCARD;
            ri.colorAttachments[0].resolveImg = &main_view;
            ri.colorAttachments[0].resolveOp = rhi::ResolveOp::AVERAGE;
            ri.depthAttachment.img = &msaa_depth;
            ri.depthAttachment.storeOp = rhi::StoreOp::DISCARD;
            ri.depthAttachment.resolveImg = &depth_view;
            ri.depthAttachment.resolveOp = rhi::ResolveOp::MAX;
        } else {
            ri.colorAttachments[0].img = &main_view;
            ri.colorAttachments[0].storeOp = rhi::StoreOp::STORE;
            ri.depthAttachment.img = &depth_view;
            ri.depthAttachment.storeOp = rhi::StoreOp::STORE;
        }
        ri.width = ctx.render_width;
        ri.height = ctx.render_height;

        rhi::begin_rendering(ctx.cmd, ri);
        rhi::set_pipeline(ctx.cmd, pipeline);

        rhi::Viewport vp{};
        vp.width = (f32)ctx.render_width;
        vp.height = (f32)ctx.render_height;
        rhi::set_viewports(ctx.cmd, &vp);
        rhi::Rect scissor{};
        scissor.width = (i32)ctx.render_width;
        scissor.height = (i32)ctx.render_height;
        rhi::set_scissors(ctx.cmd, &scissor);

        FwdDrawPushConstants pc{};
        pc.frame = (u64)ctx.render_data->frame_ubo_view[ctx.frame_index].slot;
        pc.vertex = (u64)ctx.render_data->vertex_view.slot;
        pc.visible_items = ctx.get_buffer(visible).address;
        pc.ddgi_irradiance = (u32)ctx.view(ddgi.irradiance_img);
        pc.ddgi_distance = (u32)ctx.view(ddgi.distance_img);
        pc.ddgi_probe_state = ctx.get_buffer(ddgi.probe_state).address;

        {
            static_assert(sizeof(pc) <= 128, "push constants exceed global 128B range");
            char pc128[128] = {};
            std::memcpy(pc128, &pc, sizeof(pc));
            rhi::set_constants(ctx.cmd, pipeline, rhi::ShaderStage::ALL, sizeof(pc128), pc128);
        }

        rhi::set_index_buffer(ctx.cmd, ctx.render_data->index_buffer);
        rhi::draw_indexed_indirect(
            ctx.cmd,
            ctx.get_buffer(indirect),
            &ctx.get_buffer(draw_count),
            ctx.render_data->render_item_count,
            rhi::DRAW_INDEXED_INDIRECT_STRIDE,
            0,
            0
        );

        rhi::end_rendering(ctx.cmd);
    });
    return res;
}

} // namespace forward