From c083ee5cb719a6adc360d9b65b804ec59d4ed5bf Mon Sep 17 00:00:00 2001 From: atdunbg Date: Mon, 5 Oct 2026 11:21:50 +0800 Subject: [PATCH] Fix PIE deadlock when playing a scene without a primary camera BuildFrame returned false (skip frame) when the game view had no primary camera, skipping the WaitFence/ResetFence/submit chain - the frame-slot fence never got signaled, so the next WaitFence on that slot blocked forever. Reproduced instantly by playing an empty scene with embedded PIE; latent in manual fullscreen preview too. Game view now falls back to the editor camera instead of skipping the frame, keeping the per-slot fence cadence intact. Viewport warning text updated to mention the editor-view fallback. --- App/editor/ViewportPanel.cpp | 9 +++++---- Engine/src/Renderer/SceneRenderer.cpp | 21 +++++++++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/App/editor/ViewportPanel.cpp b/App/editor/ViewportPanel.cpp index ac846c1..3242f2e 100644 --- a/App/editor/ViewportPanel.cpp +++ b/App/editor/ViewportPanel.cpp @@ -310,8 +310,8 @@ std::optional ViewportPanel::Draw(const EditorContext &ctx, // 占一行布局 → 滚动条出现/消失循环 → avail 抖动 → 渲染分辨率 // 每帧重报(视口疯狂顶动);且默认字体无中文字形(显示 ?) if (playing) { - // 运行态无 primary 相机实体 = 游戏画面黑屏(BuildFrame - // 跳帧),提示补相机(Hierarchy 右键或 Add Component) + // 运行态无 primary 相机实体:渲染回退编辑器视角(保持帧 + // 管线节拍),提示补相机 ECS::TransformComponent *camT = nullptr; if (ViewCamera(ctx, camT) == nullptr) { const ImVec2 imgMin = ImGui::GetItemRectMin(); @@ -319,8 +319,9 @@ std::optional ViewportPanel::Draw(const EditorContext &ctx, ImVec2(imgMin.x + 8.0f, imgMin.y + size.y * 0.5f), IM_COL32(255, 120, 80, 230), - "No primary camera entity - add a Camera " - "component and check 'Primary'"); + "No primary camera entity - showing editor " + "view. Add a Camera component and check " + "'Primary'"); } } diff --git a/Engine/src/Renderer/SceneRenderer.cpp b/Engine/src/Renderer/SceneRenderer.cpp index e36a994..5a28527 100644 --- a/Engine/src/Renderer/SceneRenderer.cpp +++ b/Engine/src/Renderer/SceneRenderer.cpp @@ -278,16 +278,21 @@ namespace Engine if (m_DisplayMode == kDisplayViewport && !m_GameView) { camTransform = &m_EditorCamera.GetTransform(); camera = &m_EditorCamera.GetController(); - } else if (auto* cameraComp = scene.GetPrimaryCamera(&camTransform)) { - camera = &cameraComp->camera; - } - if (!camera || !camTransform) { - // 游戏形态无 primary 相机:本帧跳过(安全网) - return false; // 拾取请求未消费,留待下一帧重试 + } else { + if (auto* cameraComp = scene.GetPrimaryCamera(&camTransform)) { + camera = &cameraComp->camera; + } + if (!camera || !camTransform) { + // 游戏形态无 primary 相机:回退编辑器相机渲染(视口有 + // 橙色提示引导补相机)。绝不能跳帧——跳过 submit 会漏 + // 掉本槽位 fence 的 signal,下一轮该槽位 WaitFence 永 + // 久阻塞 = 整个渲染死锁(空场景 Play 卡死的根因) + camTransform = &m_EditorCamera.GetTransform(); + camera = &m_EditorCamera.GetController(); + } } - // 拾取请求落帧(一次性消费:本帧 HitProxy 渲染 + 像素拷贝)。 - // 放在相机校验之后:跳帧时请求保留,不丢点击 + // 拾取请求落帧(一次性消费:本帧 HitProxy 渲染 + 像素拷贝) m_Frame.pickRequest = m_PendingPick; m_PendingPick.active = false; // 选中实体落帧(持续状态,不做一次性清除)。