pipelines.cpp

cross platform rendering playground

src/pipelines.cpp

3.49 KB
#include "pipelines.h"

#include <volk.h>

#include "core/logger.h"

Pipelines::Pipelines(rhi::Device &device, rhi::ShaderCompiler &compiler) : device(device), compiler(compiler) {
}

rhi::RenderPipeline &Pipelines::add_render(const char *name, rhi::RenderPipelineDesc desc) {
    desc.name = name;
    u64 mtime = rhi::get_file_last_write_time(desc.shader_path.c_str());
    assert(desc.device != nullptr && "Pipelines::add_render: RenderPipelineDesc::device not assigned");
    rhi::RenderPipeline p = desc.build();
    auto it = render_entries.emplace(name, RenderEntry{std::move(desc), p, mtime}).first;
    return it->second.pipeline;
}

rhi::ComputePipeline &Pipelines::add_compute(const char *name, rhi::ComputePipelineDesc desc) {
    desc.name = name;
    u64 mtime = rhi::get_file_last_write_time(desc.shader_path.c_str());
    assert(desc.device != nullptr && "Pipelines::add_compute: ComputePipelineDesc::device not assigned");
    rhi::ComputePipeline p = desc.build();
    auto it = compute_entries.emplace(name, ComputeEntry{std::move(desc), p, mtime}).first;
    return it->second.pipeline;
}

rhi::RenderPipeline &Pipelines::get_render(const char *name) {
    return render_entries.at(name).pipeline;
}

rhi::ComputePipeline &Pipelines::get_compute(const char *name) {
    return compute_entries.at(name).pipeline;
}

void Pipelines::clear() {
    for (auto &[name, e] : render_entries) {
        if (rhi::valid(e.pipeline)) {
            rhi::destroy_pipeline(device, e.pipeline);
        }
    }
    render_entries.clear();
    for (auto &[name, e] : compute_entries) {
        if (rhi::valid(e.pipeline)) {
            rhi::destroy_pipeline(device, e.pipeline);
        }
    }
    compute_entries.clear();
}

void Pipelines::reload() {
    if (!compiler.recreate_session()) {
        VEL_ERROR("Reload aborted — failed to create fresh Slang session");
        return;
    }
    bool any = false;

    for (auto &[name, e] : render_entries) {
        u64 mtime = rhi::get_file_last_write_time(e.desc.shader_path.c_str());
        if (mtime == 0 || mtime == e.source_mtime) {
            continue;
        }

        rhi::RenderPipelineDesc new_desc = e.desc;
        new_desc.set_shaders(
            compiler, new_desc.shader_path.c_str(), new_desc.vs_entry.c_str(), new_desc.fs_entry.c_str()
        );

        rhi::RenderPipeline np = new_desc.build();
        if (!rhi::valid(np)) {
            VEL_ERROR("Reload failed for '{}' — keeping old version", name);
            continue;
        }

        rhi::device_wait_idle(device);
        rhi::destroy_pipeline(device, e.pipeline);
        e.pipeline = np;
        e.source_mtime = mtime;
        VEL_INFO("Reloaded '{}'", name);
        any = true;
    }

    for (auto &[name, e] : compute_entries) {
        u64 mtime = rhi::get_file_last_write_time(e.desc.shader_path.c_str());
        if (mtime == 0 || mtime == e.source_mtime) {
            continue;
        }

        rhi::ComputePipelineDesc new_desc = e.desc;
        new_desc.set_shader(compiler, new_desc.shader_path.c_str(), new_desc.cs_entry.c_str());

        rhi::ComputePipeline np = new_desc.build();
        if (!rhi::valid(np)) {
            VEL_ERROR("Reload failed for '{}' — keeping old version", name);
            continue;
        }

        rhi::device_wait_idle(device);
        rhi::destroy_pipeline(device, e.pipeline);
        e.pipeline = np;
        e.source_mtime = mtime;
        VEL_INFO("Reloaded '{}'", name);
        any = true;
    }

    if (!any) {
        VEL_INFO("No shaders changed");
    }
}