fix: 退出 SIGSEGV 与 VkShaderEXT 泄漏——生命周期三层秩序
- 根因:~Application 体内 Logger::Shutdown() 先于成员析构执行, Device 销毁期间 Vulkan validation 回调仍打日志 → spdlog 悬空调用 - 修复:app 置于 main 独立作用域,所有成员析构完毕后再 Shutdown - 退出序 = waitIdle(~Application 体内)→ 成员析构(shader 等 Device 子对象销毁)→ Logger::Shutdown - 顺带注释掉窗口全透明(调试期遗留)
This commit is contained in:
+55
-38
@@ -14,6 +14,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <Engine/Core/Application.h>
|
#include <Engine/Core/Application.h>
|
||||||
|
#include <Engine/Core/Time.h>
|
||||||
#include <Engine/Core/Window.h> // SetInputCapture(Application.h 只前置声明)
|
#include <Engine/Core/Window.h> // SetInputCapture(Application.h 只前置声明)
|
||||||
#include <Engine/Core/Log.h>
|
#include <Engine/Core/Log.h>
|
||||||
#include <Engine/Core/Stats.h>
|
#include <Engine/Core/Stats.h>
|
||||||
@@ -67,15 +68,22 @@ namespace
|
|||||||
// Editor 注入:引擎门面 + 沙盒能力回调(环境异步切换等)
|
// Editor 注入:引擎门面 + 沙盒能力回调(环境异步切换等)
|
||||||
InitEditor();
|
InitEditor();
|
||||||
|
|
||||||
SetEnv();
|
// 默认环境(IBL 四件套):经资产层加载(compute 预积分,毫秒级),
|
||||||
|
// 其余环境在 Stats 面板里按需 lazy 加载后切换
|
||||||
|
const auto env = GetAssets().LoadEnvironment(kEnvPaths[0]);
|
||||||
|
if (env.Valid()) {
|
||||||
|
GetRenderer().SetEnvironment(GetAssets().GetEnvironment(env));
|
||||||
|
}
|
||||||
|
|
||||||
const auto suntemple = GetAssets().LoadModel("assets/models/demo/asset.fbx");
|
/*
|
||||||
|
const auto suntemple = GetAssets().LoadModel(kTemplePath);
|
||||||
auto entityhandle = scene.CreateEntity("SunTemple");
|
auto entityhandle = scene.CreateEntity("SunTemple");
|
||||||
entityhandle.AddComponent<MeshRendererComponent>(MeshRendererComponent{suntemple});
|
entityhandle.AddComponent<MeshRendererComponent>(MeshRendererComponent{suntemple});
|
||||||
|
*/
|
||||||
|
|
||||||
scene.CreateEntity();
|
scene.CreateEntity("test entity");
|
||||||
scene.CreateEntity();
|
scene.CreateEntity("test entity");
|
||||||
scene.CreateEntity();
|
scene.CreateEntity("test entity");
|
||||||
|
|
||||||
const auto gun = GetAssets().LoadModel("assets/models/m1911/M1911.fbx");
|
const auto gun = GetAssets().LoadModel("assets/models/m1911/M1911.fbx");
|
||||||
if (gun.Valid()) {
|
if (gun.Valid()) {
|
||||||
@@ -84,10 +92,23 @@ namespace
|
|||||||
m_Gun.AddComponent<AnimationComponent>();
|
m_Gun.AddComponent<AnimationComponent>();
|
||||||
auto& gt = m_Gun.GetComponent<TransformComponent>();
|
auto& gt = m_Gun.GetComponent<TransformComponent>();
|
||||||
gt.SetPosition(glm::vec3(0.0f, 1.2f, -6.0f));
|
gt.SetPosition(glm::vec3(0.0f, 1.2f, -6.0f));
|
||||||
|
// 物理验证:Dynamic 刚体(默认 Box halfExtents 0.5),
|
||||||
|
// 出生位置悬空 → 应下落至地面静止(Transform 由物理写回)
|
||||||
|
m_Gun.AddComponent<RigidBodyComponent>();
|
||||||
} else {
|
} else {
|
||||||
ENGINE_WARN("m1911 model not loaded, animation test skipped");
|
ENGINE_WARN("m1911 model not loaded, animation test skipped");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 地面:程序化纯色平面(半边长 15,中心 y=-0.5)+ 静态盒刚体
|
||||||
|
const auto ground = GetAssets().CreatePlane(15.0f, 140, 140, 145);
|
||||||
|
m_Ground = scene.CreateEntity("Ground");
|
||||||
|
m_Ground.GetComponent<TransformComponent>()
|
||||||
|
.SetPosition(glm::vec3(0.0f, -0.5f, 0.0f)); // dirty → 帧循环统一 Compose
|
||||||
|
m_Ground.AddComponent<MeshRendererComponent>(MeshRendererComponent{ground});
|
||||||
|
auto& groundRb = m_Ground.AddComponent<RigidBodyComponent>();
|
||||||
|
groundRb.type = RigidBodyComponent::BodyType::Static;
|
||||||
|
groundRb.boxHalfExtents = glm::vec3(15.0f, 0.1f, 15.0f); // 平面顶点烘焙 ±15,不能用默认 0.5
|
||||||
|
|
||||||
/*
|
/*
|
||||||
const auto gun = GetAssets().LoadModel("assets/models/m1911/M1911.fbx");
|
const auto gun = GetAssets().LoadModel("assets/models/m1911/M1911.fbx");
|
||||||
if (gun.Valid()) {
|
if (gun.Valid()) {
|
||||||
@@ -177,26 +198,24 @@ namespace
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnUpdate(f32 deltaTime) override
|
void OnUpdate(const FrameTime& frameTime) override
|
||||||
{
|
{
|
||||||
// 暂停时冻结动画时钟(帧历史验证:暂停后 Temporal Diff
|
// 相机(WASD/Space/Shift 移动;位姿读写实体 Transform)。
|
||||||
// 视图应在 2 帧内整屏变黑;相机移动同样会被 diff 捕捉到)
|
// 编辑器相机走真实轨:暂停(timeScale=0)时仍可飞行观察
|
||||||
if (!m_PauseAnim)
|
|
||||||
{
|
|
||||||
m_Time += deltaTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 相机(WASD/Space/Shift 移动;位姿读写实体 Transform)
|
|
||||||
m_Camera.GetComponent<CameraComponent>()
|
m_Camera.GetComponent<CameraComponent>()
|
||||||
.camera.Update(GetWindow(),
|
.camera.Update(GetWindow(),
|
||||||
m_Camera.GetComponent<TransformComponent>(),
|
m_Camera.GetComponent<TransformComponent>(),
|
||||||
deltaTime);
|
frameTime.UnscaledDt());
|
||||||
|
|
||||||
// 旋转动画:编辑 Transform 分量后 Compose 重算 world
|
// 旋转动画:编辑 Transform 分量后 Compose 重算 world。
|
||||||
|
// 动画时钟 = Time::Elapsed()(scaled 累计,暂停自动冻结——
|
||||||
|
// 帧历史验证:暂停后 Temporal Diff 视图 2 帧内整屏变黑)
|
||||||
for (size_t i = 0; i < m_Spinners.size(); ++i)
|
for (size_t i = 0; i < m_Spinners.size(); ++i)
|
||||||
{
|
{
|
||||||
auto& t = m_Spinners[i].GetComponent<TransformComponent>();
|
auto& t = m_Spinners[i].GetComponent<TransformComponent>();
|
||||||
t.SetRotation(glm::vec3(0.0f, m_Time * 60.0f + static_cast<f32>(i) * 40.0f, 0.0f));
|
t.SetRotation(glm::vec3(
|
||||||
|
0.0f, static_cast<f32>(Time::Elapsed()) * 60.0f +
|
||||||
|
static_cast<f32>(i) * 40.0f, 0.0f));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,15 +253,6 @@ namespace
|
|||||||
ENGINE_INFO("App: window resized to {}x{}", event.width, event.height);
|
ENGINE_INFO("App: window resized to {}x{}", event.width, event.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetEnv(int index = 0) {
|
|
||||||
// 默认环境(IBL 四件套):经资产层加载(compute 预积分,毫秒级),
|
|
||||||
// 其余环境在 Stats 面板里按需 lazy 加载后切换
|
|
||||||
const auto env = GetAssets().LoadEnvironment(kEnvPaths[index]);
|
|
||||||
if (env.Valid()) {
|
|
||||||
GetRenderer().SetEnvironment(GetAssets().GetEnvironment(env));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Editor 注入:门面指针 + 反向能力回调(面板 → 沙盒)
|
// Editor 注入:门面指针 + 反向能力回调(面板 → 沙盒)
|
||||||
void InitEditor()
|
void InitEditor()
|
||||||
@@ -254,7 +264,8 @@ namespace
|
|||||||
ctx.app = this;
|
ctx.app = this;
|
||||||
ctx.getEnvIndex = [this] { return m_EnvIndex; };
|
ctx.getEnvIndex = [this] { return m_EnvIndex; };
|
||||||
ctx.setEnvIndex = [this](int index) { m_EnvIndex = index; };
|
ctx.setEnvIndex = [this](int index) { m_EnvIndex = index; };
|
||||||
ctx.pauseAnim = &m_PauseAnim;
|
// 继承原沙盒默认:初始暂停(StatsPanel 的 Pause Simulation 开关恢复)
|
||||||
|
Time::SetTimeScale(0.0f);
|
||||||
m_Editor->Init(ctx);
|
m_Editor->Init(ctx);
|
||||||
|
|
||||||
// 输入归属:覆盖 EnableImGui 的全局 WantCapture* 谓词
|
// 输入归属:覆盖 EnableImGui 的全局 WantCapture* 谓词
|
||||||
@@ -275,8 +286,6 @@ namespace
|
|||||||
EntityHandle m_Ground{};
|
EntityHandle m_Ground{};
|
||||||
EntityHandle m_Gun{}; // 骨骼动画验证实体(M1911)
|
EntityHandle m_Gun{}; // 骨骼动画验证实体(M1911)
|
||||||
std::vector<EntityHandle> m_Spinners;
|
std::vector<EntityHandle> m_Spinners;
|
||||||
f32 m_Time = 0.0f;
|
|
||||||
bool m_PauseAnim = true; // 冻结动画时钟(Editor 面板可开关)
|
|
||||||
int m_EnvIndex = kDefaultEnv;
|
int m_EnvIndex = kDefaultEnv;
|
||||||
|
|
||||||
// ---- 异步模型加载(SunTemple)----
|
// ---- 异步模型加载(SunTemple)----
|
||||||
@@ -287,17 +296,25 @@ namespace
|
|||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
SandboxApp app;
|
Logger::Initialize();
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
app.Run();
|
SandboxApp app;
|
||||||
}
|
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
ENGINE_FATAL("Exception: {}", e.what());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
app.Run();
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
ENGINE_FATAL("Exception: {}", e.what());
|
||||||
|
Logger::Shutdown();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} // app 析构:成员(Device/Renderer/Window…)全部销毁完毕
|
||||||
|
|
||||||
|
// 日志必须最后关:Device 析构期间 Vulkan validation 回调仍在
|
||||||
|
// 打日志(销毁资源时报 VUID),logger 先亡 = 悬空调用 SIGSEGV
|
||||||
|
Logger::Shutdown();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,14 @@
|
|||||||
// 和事件钩子(OnEvent + 类型化事件)定义程序行为;
|
// 和事件钩子(OnEvent + 类型化事件)定义程序行为;
|
||||||
// runtime、editor 等不同程序形态只是不同的派生类。
|
// runtime、editor 等不同程序形态只是不同的派生类。
|
||||||
//
|
//
|
||||||
// 主循环固定为:PollEvents → OnUpdate(dt) → [NewFrame → OnRenderOverlay →
|
// 主循环固定为:PollEvents → OnUpdate(FrameTime) → [NewFrame → OnRenderOverlay →
|
||||||
// BuildDrawData] → 主渲染(Renderer.Render)→ 判退出。
|
// BuildDrawData] → 主渲染(Renderer.Render)→ 判退出。
|
||||||
// UI 构建与 GPU 提交分离:OnRenderOverlay 只"声明"控件,真正的 draw data
|
// UI 构建与 GPU 提交分离:OnRenderOverlay 只"声明"控件,真正的 draw data
|
||||||
// 提交发生在主渲染管线中的 ImGui pass(Forward 之后、Present 之前,
|
// 提交发生在主渲染管线中的 ImGui pass(Forward 之后、Present 之前,
|
||||||
// loadOp=Load 叠加)。主渲染是框架行为,派生类不可覆盖也不会丢失;
|
// loadOp=Load 叠加)。主渲染是框架行为,派生类不可覆盖也不会丢失;
|
||||||
// 框架自身永远不绘制任何 ImGui 控件——UI 内容全部由派生类定义。
|
// 框架自身永远不绘制任何 ImGui 控件——UI 内容全部由派生类定义。
|
||||||
// dt 由框架统一计时(含首帧与卡顿钳制),派生层无需自己管理。
|
// 时间由框架单源采集:帧首 Time::BeginFrame 落定 FrameTime(含卡顿钳制),
|
||||||
|
// 派生层经 OnUpdate(frame) 或 Time 门面只读,不再自己碰 chrono。
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef HELLOVULKAN_APPLICATION_H
|
#ifndef HELLOVULKAN_APPLICATION_H
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
|
|
||||||
#include <Engine/Core/Types.h>
|
#include <Engine/Core/Types.h>
|
||||||
#include <Engine/Core/Event.h>
|
#include <Engine/Core/Event.h>
|
||||||
|
#include <Engine/Core/Time.h>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ namespace Engine {
|
|||||||
class Window;
|
class Window;
|
||||||
class Renderer;
|
class Renderer;
|
||||||
class ImGuiLayer;
|
class ImGuiLayer;
|
||||||
|
class PhysicsWorld;
|
||||||
|
|
||||||
namespace ECS { class Scene; }
|
namespace ECS { class Scene; }
|
||||||
namespace Assets { class AssetManager; }
|
namespace Assets { class AssetManager; }
|
||||||
@@ -69,7 +72,7 @@ namespace Engine {
|
|||||||
Renderer& GetRenderer() const { return *m_Renderer; }
|
Renderer& GetRenderer() const { return *m_Renderer; }
|
||||||
ECS::Scene& GetScene() const { return *m_Scene; }
|
ECS::Scene& GetScene() const { return *m_Scene; }
|
||||||
Assets::AssetManager& GetAssets() const { return *m_Assets; }
|
Assets::AssetManager& GetAssets() const { return *m_Assets; }
|
||||||
f32 GetDeltaTime() const { return m_DeltaTime; }
|
PhysicsWorld& GetPhysics() const { return *m_Physics; }
|
||||||
u64 GetFrameCount() const { return m_FrameCount; }
|
u64 GetFrameCount() const { return m_FrameCount; }
|
||||||
|
|
||||||
// ImGui相关
|
// ImGui相关
|
||||||
@@ -83,8 +86,9 @@ namespace Engine {
|
|||||||
// 框架装配完成(Window/Renderer 可用),派生类做初始化(建场景等)
|
// 框架装配完成(Window/Renderer 可用),派生类做初始化(建场景等)
|
||||||
virtual void OnInit() {}
|
virtual void OnInit() {}
|
||||||
|
|
||||||
// 每帧逻辑更新(输入、动画、物理……)
|
// 每帧逻辑更新(输入、动画、物理……)。frame 当帧只读:
|
||||||
virtual void OnUpdate(f32 deltaTime) {}
|
// Dt() = scaled(游戏逻辑),UnscaledDt() = 真实(编辑器相机/UI)
|
||||||
|
virtual void OnUpdate(const FrameTime& frame) {}
|
||||||
|
|
||||||
// 主渲染之后、当帧提交之前的叠加层钩子(ImGui/调试视图/编辑器 UI)。
|
// 主渲染之后、当帧提交之前的叠加层钩子(ImGui/调试视图/编辑器 UI)。
|
||||||
// 主渲染由框架固定执行;这里只负责"额外的"渲染,不覆写则无叠加层。
|
// 主渲染由框架固定执行;这里只负责"额外的"渲染,不覆写则无叠加层。
|
||||||
@@ -115,12 +119,12 @@ namespace Engine {
|
|||||||
Scope<ECS::Scene> m_Scene;
|
Scope<ECS::Scene> m_Scene;
|
||||||
Scope<Renderer> m_Renderer;
|
Scope<Renderer> m_Renderer;
|
||||||
Scope<Assets::AssetManager> m_Assets;
|
Scope<Assets::AssetManager> m_Assets;
|
||||||
|
Scope<PhysicsWorld> m_Physics; // Jolt 物理(Run 起循环时创建)
|
||||||
// 注意成员序:ImGuiLayer 必须后声明(先于 Renderer/Window 析构,
|
// 注意成员序:ImGuiLayer 必须后声明(先于 Renderer/Window 析构,
|
||||||
// 其后端销毁需要 Device 与 GLFWwindow 存活)
|
// 其后端销毁需要 Device 与 GLFWwindow 存活)
|
||||||
Scope<ImGuiLayer> m_ImGuiLayer;
|
Scope<ImGuiLayer> m_ImGuiLayer;
|
||||||
|
|
||||||
bool m_Running = false;
|
bool m_Running = false;
|
||||||
f32 m_DeltaTime = 0.0f;
|
|
||||||
u64 m_FrameCount = 0;
|
u64 m_FrameCount = 0;
|
||||||
|
|
||||||
// 帧率控制
|
// 帧率控制
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <Engine/Core/Window.h>
|
#include <Engine/Core/Window.h>
|
||||||
#include <Engine/Core/Log.h>
|
#include <Engine/Core/Log.h>
|
||||||
#include <Engine/ECS/Scene.h>
|
#include <Engine/ECS/Scene.h>
|
||||||
|
#include <Engine/Physics/PhysicsWorld.h>
|
||||||
#include <Engine/Renderer/Renderer.h>
|
#include <Engine/Renderer/Renderer.h>
|
||||||
#include <Engine/Assets/AssetManager.h>
|
#include <Engine/Assets/AssetManager.h>
|
||||||
#include <Engine/Vulkan/Device.h>
|
#include <Engine/Vulkan/Device.h>
|
||||||
@@ -22,7 +23,6 @@ namespace Engine {
|
|||||||
|
|
||||||
Application::Application(const std::string& title, u32 width, u32 height)
|
Application::Application(const std::string& title, u32 width, u32 height)
|
||||||
{
|
{
|
||||||
Logger::Initialize();
|
|
||||||
|
|
||||||
m_Window = CreateScope<Window>(title, width, height);
|
m_Window = CreateScope<Window>(title, width, height);
|
||||||
|
|
||||||
@@ -56,7 +56,10 @@ namespace Engine {
|
|||||||
|
|
||||||
if (m_ImGuiLayer) m_ImGuiLayer.reset();
|
if (m_ImGuiLayer) m_ImGuiLayer.reset();
|
||||||
|
|
||||||
Logger::Shutdown();
|
// 注意:这里不能 Logger::Shutdown()——成员析构(Device 销毁等)
|
||||||
|
// 在函数体之后才执行,期间 Vulkan validation 回调仍会打日志,
|
||||||
|
// logger 先亡会导致悬空调用 SIGSEGV。Shutdown 移到 main 的
|
||||||
|
// app 作用域结束之后(所有成员析构完毕)。
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::EnableImGui()
|
void Application::EnableImGui()
|
||||||
@@ -94,18 +97,31 @@ namespace Engine {
|
|||||||
|
|
||||||
OnInit();
|
OnInit();
|
||||||
|
|
||||||
|
// 物理世界(场景实体搭建完后创建)
|
||||||
|
m_Physics = CreateScope<PhysicsWorld>(*m_Scene, m_Assets.get());
|
||||||
|
// 物理调试图元 → 渲染侧(PhysicsDebugPass 每帧上传绘制)
|
||||||
|
m_Renderer->SetPhysicsDebugSource(&m_Physics->GetDebugFrame());
|
||||||
|
|
||||||
while (m_Running) {
|
while (m_Running) {
|
||||||
const auto frameStart = std::chrono::steady_clock::now();
|
const auto frameStart = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
m_Window->PollEvents();
|
m_Window->PollEvents();
|
||||||
|
|
||||||
auto now = std::chrono::steady_clock::now();
|
auto now = std::chrono::steady_clock::now();
|
||||||
f32 dt = std::chrono::duration<f32>(now - m_LastFrameTime).count();
|
const f64 dt = std::chrono::duration<f64>(now - m_LastFrameTime).count();
|
||||||
// 钳制卡顿(断点/窗口拖动导致的超大 dt),避免物理/动画穿模
|
// 钳制卡顿(断点/窗口拖动导致的超大 dt),避免物理/动画穿模;
|
||||||
m_DeltaTime = std::clamp(dt, 0.0f, 0.25f);
|
// 帧首落定 FrameTime(时间单源),业务当帧只读
|
||||||
|
Time::BeginFrame(std::clamp(dt, 0.0, 0.25), m_FrameCount);
|
||||||
|
const FrameTime& frame = Time::Current();
|
||||||
m_LastFrameTime = now;
|
m_LastFrameTime = now;
|
||||||
|
|
||||||
OnUpdate(m_DeltaTime);
|
// 物理步进(OnUpdate 之前,Unity FixedUpdate→Update 语义):
|
||||||
|
// 动态体姿态写回 Transform 并标脏,UpdateTransforms 统一重算;
|
||||||
|
// 吃 scaled dt → timeScale=0(编辑器暂停)时 accumulator 冻结,
|
||||||
|
// SyncScene 对账仍跑(拖静态体照常同步)
|
||||||
|
m_Physics->Step(frame.Dt());
|
||||||
|
|
||||||
|
OnUpdate(frame);
|
||||||
|
|
||||||
// 延迟销毁在渲染前统一 flush,保证渲染遍历时池结构不变
|
// 延迟销毁在渲染前统一 flush,保证渲染遍历时池结构不变
|
||||||
m_Scene->FlushDestroyQueue();
|
m_Scene->FlushDestroyQueue();
|
||||||
@@ -130,7 +146,7 @@ namespace Engine {
|
|||||||
|
|
||||||
// ---- 主渲染(框架行为):RG 顺序 Forward → ImGui(loadOp=Load) →
|
// ---- 主渲染(框架行为):RG 顺序 Forward → ImGui(loadOp=Load) →
|
||||||
// Present,draw data 在 ImGui pass 里才真正提交 GPU ----
|
// Present,draw data 在 ImGui pass 里才真正提交 GPU ----
|
||||||
m_Renderer->Render(*m_Scene, *m_Assets, m_DeltaTime);
|
m_Renderer->Render(*m_Scene, *m_Assets, frame.Dt());
|
||||||
|
|
||||||
// ---- 帧率控制:vsync 开启时 present 自带节奏;否则按目标限帧 ----
|
// ---- 帧率控制:vsync 开启时 present 自带节奏;否则按目标限帧 ----
|
||||||
// 策略:先 sleep 到剩 ~2ms,再自旋——精度高且不烧 CPU
|
// 策略:先 sleep 到剩 ~2ms,再自旋——精度高且不烧 CPU
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ namespace Engine
|
|||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
glfwSetWindowOpacity(m_Window, 0.0f);
|
// glfwSetWindowOpacity(m_Window, 0.0f);
|
||||||
|
|
||||||
ENGINE_INFO("Window created: {} ({}x{})", title, width, height);
|
ENGINE_INFO("Window created: {} ({}x{})", title, width, height);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user