277 lines
7.6 KiB
C++
277 lines
7.6 KiB
C++
#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
|