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