Extra2D/src/renderer/renderer_module.cpp

277 lines
7.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <assets/assets_module.h>
#include <platform/window_module.h>
#include <renderer/render_graph.h>
#include <renderer/renderer_module.h>
#include <renderer/rhi_module.h>
#include <utils/logger.h>
namespace extra2d {
RendererModule::RendererModule() = default;
RendererModule::~RendererModule() = default;
bool RendererModule::init() {
E2D_LOG_INFO("正在初始化渲染模块...");
// 绑定事件监听器
onRenderBeginListener_.bind([this]() { onRenderBegin(); });
onRenderSubmitListener_.bind(
[this](const RenderCommand &cmd) { onRenderSubmit(cmd); });
onRenderSetCameraListener_.bind(
[this](const Mat4 &viewProj) { onRenderSetCamera(viewProj); });
onRenderEndListener_.bind([this]() { onRenderEnd(); });
onResizeListener_.bind([this](int32 w, int32 h) { onResize(w, h); });
onShowListener_.bind([this]() { onWindowShow(); });
E2D_LOG_INFO("渲染模块已初始化 (等待窗口显示)");
return true;
}
void RendererModule::onWindowShow() {
if (initialized_) {
return;
}
E2D_LOG_INFO("正在初始化渲染模块上下文...");
// 初始化 RHI 模块
auto *rhiModule = RHIModule::get();
if (!rhiModule) {
E2D_LOG_ERROR("RHI 模块不可用");
return;
}
if (!rhiModule->getDevice()) {
// RHI 设备尚未初始化,这是正常的时序问题
// RHIModule 会在窗口显示后初始化设备,然后再次触发此函数
E2D_LOG_INFO("RHI 设备尚未就绪,等待 RHI 初始化...");
return;
}
// 初始化渲染图
if (!renderGraph_.initialize()) {
E2D_LOG_ERROR("初始化渲染图失败");
return;
}
commandQueue_ = renderGraph_.getCommandQueue();
// 添加默认的几何渲染通道
auto geometryPass = std::make_unique<GeometryRenderPass>("Geometry");
renderGraph_.addPass(std::move(geometryPass));
E2D_LOG_INFO("已添加默认几何渲染通道");
auto windowModule = getModule<WindowModule>();
if (!windowModule) {
E2D_LOG_ERROR("窗口模块不可用");
return;
}
setViewport(0, 0, static_cast<int32>(windowModule->getSize().w),
static_cast<int32>(windowModule->getSize().h));
initialized_ = true;
E2D_LOG_INFO("渲染模块上下文初始化成功");
}
void RendererModule::shutdown() {
E2D_LOG_INFO("正在关闭渲染模块...");
renderGraph_.shutdown();
commandQueue_ = nullptr;
initialized_ = false;
// 注意:事件监听器是值类型,会在析构时自动清理
E2D_LOG_INFO("渲染模块关闭完成");
}
RHIContext *RendererModule::getRHIContext() const {
auto *rhiModule = RHIModule::get();
if (rhiModule && rhiModule->getDevice()) {
return rhiModule->getDevice()->getContext();
}
return nullptr;
}
Handle<Material> RendererModule::getDefaultMaterialHandle() const {
auto *assets = getAssets();
return assets ? assets->getDefaultMaterial() : Handle<Material>::invalid();
}
Handle<Mesh> RendererModule::getDefaultQuadHandle() const {
auto *assets = getAssets();
return assets ? assets->getDefaultQuad() : Handle<Mesh>::invalid();
}
Handle<Texture> RendererModule::getDefaultTextureHandle() const {
auto *assets = getAssets();
return assets ? assets->getDefaultTexture() : Handle<Texture>::invalid();
}
void RendererModule::setViewport(int32 x, int32 y, int32 width, int32 height) {
viewportX_ = x;
viewportY_ = y;
viewportWidth_ = width;
viewportHeight_ = height;
viewportAdapter_.update(width, height);
// 更新渲染图输出尺寸
renderGraph_.setOutputSize(static_cast<uint32_t>(width),
static_cast<uint32_t>(height));
// 通过 RHI 设置视口
if (initialized_) {
auto *context = getRHIContext();
if (context) {
auto result = viewportAdapter_.getResult();
context->setViewport(static_cast<int32_t>(result.viewport.x),
static_cast<int32_t>(result.viewport.y),
static_cast<uint32_t>(result.viewport.w),
static_cast<uint32_t>(result.viewport.h));
}
}
}
void RendererModule::clear(const Color &color, uint32 flags) {
if (!initialized_)
return;
if (commandQueue_) {
commandQueue_->submitClear(color, flags);
}
}
void RendererModule::onRenderBegin() {
if (!initialized_) {
return;
}
// 重置统计
stats_ = {};
// 开始渲染帧 - 清空命令队列准备接收新的渲染命令
if (commandQueue_) {
commandQueue_->beginFrame();
}
// 帧开始
}
void RendererModule::onRenderSubmit(const RenderCommand &cmd) {
if (!initialized_ || !commandQueue_) {
E2D_LOG_WARN("onRenderSubmit: 渲染模块未初始化或没有命令队列");
return;
}
(void)cmd; // 避免未使用警告
// 将渲染命令转换为绘制命令提交到队列
switch (cmd.type) {
case RenderCommandType::DrawMesh: {
auto *assets = getAssets();
if (!assets)
return;
// 获取材质,如果没有指定则使用默认材质
Material *material = assets->get(cmd.drawMesh.material);
if (!material) {
material = assets->get(assets->getDefaultMaterial());
}
// 获取网格,如果没有指定则使用默认四边形
Mesh *mesh = assets->get(cmd.drawMesh.mesh);
if (!mesh) {
mesh = assets->get(assets->getDefaultQuad());
}
if (material && mesh) {
Transform transform(cmd.drawMesh.pos, cmd.drawMesh.scale,
cmd.drawMesh.rot);
commandQueue_->submitDraw(Ptr<Material>(material), Ptr<Mesh>(mesh),
transform, cmd.drawMesh.color);
stats_.commandsSubmitted++;
} else {
E2D_LOG_WARN("提交绘制命令失败: 材质={}, 网格={}",
material ? "有效" : "", mesh ? "有效" : "");
}
break;
}
case RenderCommandType::SetViewport: {
setViewport(cmd.viewport.x, cmd.viewport.y, cmd.viewport.width,
cmd.viewport.height);
break;
}
case RenderCommandType::Clear: {
clear(cmd.clear.color, cmd.clear.flags);
break;
}
}
}
void RendererModule::onRenderSetCamera(const Mat4 &viewProj) {
if (!initialized_) {
return;
}
viewProjectionMatrix_ = viewProj;
// 更新全局 UBO通过 RenderGraph 的命令队列)
// 实际的 UBO 更新会在 RenderGraph 执行时进行
}
void RendererModule::onRenderEnd() {
if (!initialized_) {
E2D_LOG_WARN("onRenderEnd: 渲染模块未初始化");
return;
}
// 执行渲染图,传递视图投影矩阵
renderGraph_.execute(0.016f, viewProjectionMatrix_);
// 获取统计信息
if (commandQueue_) {
const auto &stats = commandQueue_->getStats();
stats_.drawCalls = stats.drawCalls;
// 每60帧输出一次统计信息
static uint32_t frameCount = 0;
if (++frameCount % 60 == 0) {
E2D_LOG_INFO("渲染统计: 绘制调用={}, 三角形数={}, 顶点数={}, "
"管线绑定={}, 纹理绑定={}, 缓冲区绑定={}",
stats.drawCalls, stats.triangles, stats.vertices,
stats.pipelineBinds, stats.textureBinds, stats.bufferBinds);
}
}
// 渲染完成
}
void RendererModule::onResize(int32 width, int32 height) {
setViewport(0, 0, width, height);
}
void RendererModule::executeCommand(const RenderCommand &cmd) {
// 此方法保留用于直接执行特定命令
// 大部分命令现在通过 RenderGraph 处理
switch (cmd.type) {
case RenderCommandType::SetViewport:
setViewport(cmd.viewport.x, cmd.viewport.y, cmd.viewport.width,
cmd.viewport.height);
break;
case RenderCommandType::Clear:
clear(cmd.clear.color, cmd.clear.flags);
break;
default:
break;
}
}
} // namespace extra2d