334 lines
8.5 KiB
C++
334 lines
8.5 KiB
C++
#include <renderer/render_graph.h>
|
|
#include <renderer/rhi_module.h>
|
|
#include <utils/logger.h>
|
|
|
|
namespace extra2d {
|
|
|
|
// ========================================
|
|
// RenderPassContext 实现
|
|
// ========================================
|
|
|
|
TextureHandle
|
|
RenderPassContext::getTexture(RenderGraphResourceHandle handle) const {
|
|
if (graph) {
|
|
return graph->getTexture(handle);
|
|
}
|
|
return TextureHandle{};
|
|
}
|
|
|
|
// ========================================
|
|
// RenderGraphBuilder 实现
|
|
// ========================================
|
|
|
|
RenderGraphResourceHandle
|
|
RenderGraphBuilder::createTexture(const RenderGraphTextureDesc &desc) {
|
|
// 实际的资源创建由 RenderGraph 管理
|
|
// 这里只记录描述,返回临时句柄
|
|
textureDescs_.push_back(desc);
|
|
RenderGraphResourceHandle handle;
|
|
handle.index = static_cast<uint32_t>(textureDescs_.size()) - 1;
|
|
handle.type = RenderGraphResourceType::Texture;
|
|
return handle;
|
|
}
|
|
|
|
void RenderGraphBuilder::readResource(RenderGraphResourceHandle handle) {
|
|
// 记录资源读取依赖
|
|
// 用于后续的依赖分析和资源生命周期管理
|
|
}
|
|
|
|
void RenderGraphBuilder::writeResource(RenderGraphResourceHandle handle) {
|
|
// 记录资源写入依赖
|
|
}
|
|
|
|
void RenderGraphBuilder::setRenderTarget(
|
|
const RenderGraphRenderTargetDesc &desc) {
|
|
// 设置渲染目标
|
|
}
|
|
|
|
// ========================================
|
|
// RenderGraph 实现
|
|
// ========================================
|
|
|
|
RenderGraph::RenderGraph() = default;
|
|
|
|
RenderGraph::~RenderGraph() { shutdown(); }
|
|
|
|
RenderGraph::RenderGraph(RenderGraph &&other) noexcept
|
|
: passes_(std::move(other.passes_)),
|
|
executionOrder_(std::move(other.executionOrder_)),
|
|
textures_(std::move(other.textures_)),
|
|
nextResourceId_(other.nextResourceId_),
|
|
builder_(std::move(other.builder_)),
|
|
commandQueue_(std::move(other.commandQueue_)),
|
|
outputWidth_(other.outputWidth_), outputHeight_(other.outputHeight_),
|
|
frameIndex_(other.frameIndex_), compiled_(other.compiled_) {
|
|
other.nextResourceId_ = 1;
|
|
other.outputWidth_ = 1280;
|
|
other.outputHeight_ = 720;
|
|
other.frameIndex_ = 0;
|
|
other.compiled_ = false;
|
|
}
|
|
|
|
RenderGraph &RenderGraph::operator=(RenderGraph &&other) noexcept {
|
|
if (this != &other) {
|
|
shutdown();
|
|
|
|
passes_ = std::move(other.passes_);
|
|
executionOrder_ = std::move(other.executionOrder_);
|
|
textures_ = std::move(other.textures_);
|
|
nextResourceId_ = other.nextResourceId_;
|
|
builder_ = std::move(other.builder_);
|
|
commandQueue_ = std::move(other.commandQueue_);
|
|
outputWidth_ = other.outputWidth_;
|
|
outputHeight_ = other.outputHeight_;
|
|
frameIndex_ = other.frameIndex_;
|
|
compiled_ = other.compiled_;
|
|
|
|
other.nextResourceId_ = 1;
|
|
other.outputWidth_ = 1280;
|
|
other.outputHeight_ = 720;
|
|
other.frameIndex_ = 0;
|
|
other.compiled_ = false;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool RenderGraph::initialize() {
|
|
if (!commandQueue_.initialize()) {
|
|
E2D_LOG_ERROR("Failed to initialize CommandQueue");
|
|
return false;
|
|
}
|
|
|
|
E2D_LOG_INFO("RenderGraph initialized");
|
|
return true;
|
|
}
|
|
|
|
void RenderGraph::shutdown() {
|
|
destroyResources();
|
|
passes_.clear();
|
|
executionOrder_.clear();
|
|
commandQueue_.shutdown();
|
|
compiled_ = false;
|
|
|
|
E2D_LOG_INFO("RenderGraph shutdown");
|
|
}
|
|
|
|
RenderPass *RenderGraph::addPass(std::unique_ptr<RenderPass> pass) {
|
|
if (!pass)
|
|
return nullptr;
|
|
|
|
RenderPass *ptr = pass.get();
|
|
passes_.push_back(std::move(pass));
|
|
compiled_ = false; // 添加新通道需要重新编译
|
|
|
|
return ptr;
|
|
}
|
|
|
|
RenderPass *RenderGraph::addLambdaPass(
|
|
const std::string &name,
|
|
std::function<void(const RenderPassContext &)> executeFunc) {
|
|
// 创建一个简单的 lambda 渲染通道
|
|
class LambdaRenderPass : public RenderPass {
|
|
public:
|
|
std::string name;
|
|
std::function<void(const RenderPassContext &)> func;
|
|
|
|
LambdaRenderPass(const std::string &n,
|
|
std::function<void(const RenderPassContext &)> f)
|
|
: name(n), func(f) {}
|
|
|
|
const char *getName() const override { return name.c_str(); }
|
|
|
|
void execute(const RenderPassContext &ctx) override {
|
|
if (func) {
|
|
func(ctx);
|
|
}
|
|
}
|
|
};
|
|
|
|
return addPass(std::make_unique<LambdaRenderPass>(name, executeFunc));
|
|
}
|
|
|
|
bool RenderGraph::compile() {
|
|
if (compiled_)
|
|
return true;
|
|
|
|
// 清空之前的编译结果
|
|
executionOrder_.clear();
|
|
|
|
// 简单的编译策略:按添加顺序执行
|
|
// 实际实现中应该进行依赖分析和拓扑排序
|
|
for (auto &pass : passes_) {
|
|
if (pass->isEnabled()) {
|
|
executionOrder_.push_back(pass.get());
|
|
}
|
|
}
|
|
|
|
// 声明资源
|
|
for (auto *pass : executionOrder_) {
|
|
builder_.setCurrentPass(pass);
|
|
pass->declareResources(builder_);
|
|
}
|
|
|
|
// 创建资源
|
|
createResources();
|
|
|
|
compiled_ = true;
|
|
E2D_LOG_INFO("RenderGraph compiled with {} passes", executionOrder_.size());
|
|
|
|
return true;
|
|
}
|
|
|
|
void RenderGraph::execute(float deltaTime, const Mat4 &viewProjection) {
|
|
if (!compiled_) {
|
|
if (!compile()) {
|
|
E2D_LOG_ERROR("Failed to compile RenderGraph");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 更新全局 UBO
|
|
commandQueue_.updateGlobalUBO(viewProjection, deltaTime, outputWidth_,
|
|
outputHeight_);
|
|
|
|
// 获取 RHI 上下文
|
|
auto *rhiModule = RHIModule::get();
|
|
RHIContext *context = nullptr;
|
|
if (rhiModule && rhiModule->getDevice()) {
|
|
context = rhiModule->getDevice()->getContext();
|
|
}
|
|
|
|
// 创建执行上下文
|
|
RenderPassContext ctx;
|
|
ctx.context = context;
|
|
ctx.commandQueue = &commandQueue_;
|
|
ctx.graph = this;
|
|
ctx.deltaTime = deltaTime;
|
|
ctx.frameIndex = frameIndex_;
|
|
|
|
// 执行所有通道
|
|
for (auto *pass : executionOrder_) {
|
|
if (pass->isEnabled()) {
|
|
pass->execute(ctx);
|
|
}
|
|
}
|
|
|
|
// 执行命令队列
|
|
commandQueue_.execute();
|
|
|
|
// 结束帧
|
|
commandQueue_.endFrame();
|
|
|
|
// 调用 RHI 上下文的 endFrame 进行缓冲区交换
|
|
if (context) {
|
|
context->endFrame();
|
|
}
|
|
|
|
frameIndex_++;
|
|
}
|
|
|
|
TextureHandle RenderGraph::getTexture(RenderGraphResourceHandle handle) const {
|
|
auto it = textures_.find(handle.index);
|
|
if (it != textures_.end()) {
|
|
return it->second;
|
|
}
|
|
return TextureHandle{};
|
|
}
|
|
|
|
void RenderGraph::setOutputSize(uint32_t width, uint32_t height) {
|
|
outputWidth_ = width;
|
|
outputHeight_ = height;
|
|
}
|
|
|
|
void RenderGraph::createResources() {
|
|
auto *rhiModule = RHIModule::get();
|
|
if (!rhiModule || !rhiModule->getDevice())
|
|
return;
|
|
|
|
auto *device = rhiModule->getDevice();
|
|
|
|
// 创建渲染图内部资源
|
|
// 这里可以根据需要创建默认的后缓冲等
|
|
}
|
|
|
|
void RenderGraph::destroyResources() {
|
|
// 释放所有渲染图管理的资源
|
|
textures_.clear();
|
|
}
|
|
|
|
// ========================================
|
|
// GeometryRenderPass 实现
|
|
// ========================================
|
|
|
|
GeometryRenderPass::GeometryRenderPass(const std::string &name) : name_(name) {}
|
|
|
|
void GeometryRenderPass::declareResources(RenderGraphBuilder &builder) {
|
|
// 声明几何渲染通道的资源依赖
|
|
if (colorTarget_.isValid()) {
|
|
builder.writeResource(colorTarget_);
|
|
}
|
|
if (depthTarget_.isValid()) {
|
|
builder.writeResource(depthTarget_);
|
|
}
|
|
}
|
|
|
|
void GeometryRenderPass::execute(const RenderPassContext &ctx) {
|
|
// 几何渲染通道的执行逻辑
|
|
// 通常由外部的渲染系统填充具体的绘制命令
|
|
|
|
if (!ctx.commandQueue)
|
|
return;
|
|
|
|
// 清除颜色缓冲区
|
|
ctx.commandQueue->submitClear(Color::Black, CLEAR_COLOR_FLAG);
|
|
|
|
// 设置视口
|
|
if (ctx.graph) {
|
|
ctx.commandQueue->setViewport(
|
|
0, 0, static_cast<int32_t>(ctx.graph->getOutputWidth()),
|
|
static_cast<int32_t>(ctx.graph->getOutputHeight()));
|
|
}
|
|
}
|
|
|
|
// ========================================
|
|
// PostProcessRenderPass 实现
|
|
// ========================================
|
|
|
|
PostProcessRenderPass::PostProcessRenderPass(const std::string &name)
|
|
: name_(name) {}
|
|
|
|
void PostProcessRenderPass::declareResources(RenderGraphBuilder &builder) {
|
|
// 声明后期处理通道的资源依赖
|
|
if (inputTexture_.isValid()) {
|
|
builder.readResource(inputTexture_);
|
|
}
|
|
if (outputTarget_.isValid()) {
|
|
builder.writeResource(outputTarget_);
|
|
}
|
|
}
|
|
|
|
void PostProcessRenderPass::execute(const RenderPassContext &ctx) {
|
|
// 后期处理通道的执行逻辑
|
|
// 这里可以实现全屏四边形绘制等后期处理效果
|
|
|
|
if (!ctx.context || !ctx.commandQueue)
|
|
return;
|
|
|
|
// 获取命令列表
|
|
RHICommandList *cmdList = ctx.commandQueue->getCommandList();
|
|
if (!cmdList)
|
|
return;
|
|
|
|
// 绑定输入纹理
|
|
if (inputTexture_.isValid()) {
|
|
TextureHandle tex = ctx.getTexture(inputTexture_);
|
|
if (tex.isValid()) {
|
|
cmdList->setTexture(0, tex.get());
|
|
}
|
|
}
|
|
|
|
// 后期处理的具体实现由子类或外部提供
|
|
}
|
|
|
|
} // namespace extra2d
|