feat: 帧率控制——手动限帧 + VSync 开关

- Application 帧率控制 API:SetLimitFps/SetTargetFps/SetVSync。
  限帧目标最低 24fps(防止过低刷新导致交互卡死),无上限;
  vsync 开启时 present 自带节奏,手动限帧不生效
- 限帧策略:sleep 到剩 ~2ms 后自旋,精度高且不烧 CPU
- Swapchain 加 VSync 开关:ChoosePresentMode 按开关选
  Mailbox(低延迟垂直同步)/ Immediate(不限速可撕裂),
  FIFO 兜底;切换经 SetVSync → 重建 swapchain(复用 HandleResize)
- Scene Debug 面板新增 Frame 区块(vsync/limit/目标滑条)
- Run 循环新增 CPU 归属遥测(update/ui/render/total,每 120 帧)
This commit is contained in:
2026-09-22 20:33:10 +08:00
parent cef32ea1ba
commit d8274e8bdc
7 changed files with 102 additions and 11 deletions
+35 -10
View File
@@ -24,7 +24,6 @@
#include <GLFW/glfw3.h>
#include "Engine/ImGui/ImGuiLayer.h"
using namespace Engine;
using namespace Engine::ECS;
@@ -66,17 +65,21 @@ protected:
camera.camera.SetPosition(glm::vec3(0.0f, 0.0f, 7.0f));
// 背包实体 × 3(悬浮在地面上方)
for (int i = 0; i < 3; ++i) {
auto e = scene.CreateEntity("Backpack" + std::to_string(i));
auto size = 10;
for (int i = 0; i < size; ++i) {
for (int j = 0 ; j < size; j ++)
{
auto e = scene.CreateEntity("Backpack" + std::to_string(i));
e.AddComponent<TransformComponent>()
.SetPosition(glm::vec3((i - 1) * 1.5f, 0.0f, 0.0f))
.SetScale(glm::vec3(0.5f))
.Compose();
e.AddComponent<TransformComponent>()
.SetPosition(glm::vec3((i - size * 0.5) * 1.5f, 0.0f, (j - size * 0.5) * 1.5f))
.SetScale(glm::vec3(0.5f))
.Compose();
e.AddComponent<MeshRendererComponent>(MeshRendererComponent{backpack});
e.AddComponent<MeshRendererComponent>(MeshRendererComponent{backpack});
m_Spinners.push_back(e);
m_Spinners.push_back(e);
}
}
// 灯光实体(第一个灯 = 阴影光源)
@@ -102,7 +105,6 @@ protected:
// 旋转动画:编辑 Transform 分量后 Compose 重算 world
for (size_t i = 0; i < m_Spinners.size(); ++i) {
auto& t = m_Spinners[i].GetComponent<TransformComponent>();
t.position = glm::vec3((static_cast<f32>(i) - 1.0f) * 1.5f, 0.0f, 0.0f);
t.rotation.y = m_Time * 60.0f + static_cast<f32>(i) * 40.0f;
t.scale = glm::vec3(0.5f);
t.Compose();
@@ -163,6 +165,29 @@ protected:
ImGui::Text(" %-12s %.3f ms", names[i].c_str(), times[i]);
}
// 帧率控制
auto& app = *this;
ImGui::Separator();
ImGui::Text("Frame");
bool vsync = app.GetVSync();
if (ImGui::Checkbox("VSync", &vsync)) {
app.SetVSync(vsync);
}
bool limit = app.GetLimitFps();
if (ImGui::Checkbox("Limit FPS", &limit)) {
app.SetLimitFps(limit);
}
if (limit) {
if (vsync) {
ImGui::TextDisabled("(vsync 开启时限帧无效)");
} else {
f32 target = app.GetTargetFps();
if (ImGui::SliderFloat("target fps", &target, 24.0f, 360.0f, "%.0f")) {
app.SetTargetFps(target);
}
}
}
ImGui::Separator();
ImGui::Text("fps: %.1f frame: %llu",
1.0f / GetDeltaTime(),