Skip to content

fix: delete backdrop renderer on invalidated - #740

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
caixr23:master
Oct 30, 2026
Merged

deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
caixr23:master

Conversation

@caixr23

@caixr23 caixr23 commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor
  1. RhiManager now connects to QSGRenderContext::invalidated (DirectConnection) and destroys the Renderer immediately in destroyRenderer(), rather than waiting until RhiManager's destructor runs during QObject child cleanup.
  2. Renderer holds a reference to QSGRenderContext's ShaderManager child; deleting the renderer after that child is gone causes a SIGSEGV in ~Renderer -> ShaderManager::clearCachedRendererData. Handling invalidated matches Qt's QSGRhiLayer pattern.
  3. sync(), preprocess(), and render() now bail out when renderer (or m_rhi in preprocess) is null, preventing operations on a destroyed RHI context.
  4. context/renderer are initialized to nullptr in the constructor, and destroyRenderer() is reused from both invalidated and ~RhiManager.
  5. Added regression test destroyWithBackdropNodeOnRhi, which renders a frame with DQuickBackdropBlitter then destroys the window; it crashed before this fix and exits cleanly after.

Log: Fixed exit crash caused by DBackdropBlitter renderer lifecycle

Influence:

  1. Close windows in existing InWindowBlur demos/apps and confirm no crash on the default RHI rendering path.
  2. Run related scenes with the software scene graph backend to confirm the guards preserve behavior when RhiManager is not created.
  3. On Qt6, exercise window teardown with OpenGL/Vulkan/D3D/Metal RHI backends, with and without DTK_DISABLE_INWINDOWBLUR.
  4. Run the new regression test ut_DQuickInWindowBlur.destroyWithBackdropNodeOnRhi and verify it passes.

fix: 在 invalidated 时销毁 backdrop renderer

  1. RhiManager 现在以直连连接监听 QSGRenderContext::invalidated,在信号 发出时立即通过 destroyRenderer() 销毁 Renderer,不再等到 RhiManager 析构 (QObject 子对象清理阶段)才执行。
  2. Renderer 持有 QSGRenderContext 的 QObject 子对象 ShaderManager 的 引用;在 ShaderManager 销毁后才 delete Renderer,会在 ~Renderer → ShaderManager::clearCachedRendererData 中访问已释放内存并崩溃。Qt 对 QSGRhiLayer 也是同样处理。
  3. sync()、preprocess()、render() 在 renderer(preprocess 中还包含 m_rhi)为空时直接返回,避免在已销毁的 RHI context 上继续渲染。
  4. 构造函数将 context/renderer 初始化为 nullptr,删除逻辑集中到 destroyRenderer(),析构函数也调用它。
  5. 新增回归用例 destroyWithBackdropNodeOnRhi:先通过 DQuickBackdropBlitter 渲染一帧再销毁窗口;修复前会崩溃,修复后可正常
    退出。

Log: 修复 DBackdropBlitter 渲染器生命周期导致的退出崩溃

Influence:

  1. 运行已有的 InWindowBlur 示例/应用并关闭窗口,确认默认 RHI 渲染路径不 崩溃。
  2. 使用软件场景图后端运行相关场景,确认未创建 RhiManager 时保护逻辑不影 响原有行为。
  3. 在 Qt6 下分别使用 OpenGL/Vulkan/D3D/Metal RHI 后端测试窗口销毁,并分 别设置/不设置 DTK_DISABLE_INWINDOWBLUR。
  4. 运行新增回归用例 ut_DQuickInWindowBlur.destroyWithBackdropNodeOnRhi, 确认通过。

PMS: TASK-397773

Summary by Sourcery

Fix backdrop renderer teardown so windows close safely after RHI rendering contexts are invalidated.

Bug Fixes:

  • Prevent exit-time crashes by destroying the backdrop renderer when the QSG render context is invalidated.
  • Guard rendering operations against missing renderer or RHI state after context invalidation.

Enhancements:

  • Centralize renderer cleanup and initialize RHI manager state safely.

Tests:

  • Add a Qt 6 regression test covering window destruction after an RHI backdrop frame has rendered.

18202781743
18202781743 previously approved these changes Oct 29, 2026
Comment thread tests/ut_dquickinwindowblur.cpp Outdated
@sourcery-ai

sourcery-ai Bot commented Oct 29, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR fixes an exit-time SIGSEGV by deleting the backdrop renderer synchronously when QSGRenderContext is invalidated, before its ShaderManager child is destroyed, and adds null guards plus a regression test for RHI window teardown.

Sequence diagram for safe RHI renderer teardown

sequenceDiagram
    participant Window as QQuickWindow
    participant Context as QSGRenderContext
    participant Manager as RhiManager
    participant Renderer as Renderer
    participant Shader as ShaderManager

    Window->>Context: invalidated()
    Context-->>Manager: destroyRenderer()
    Manager->>Renderer: delete renderer
    Renderer->>Shader: clearCachedRendererData()
    Context->>Shader: destroy ShaderManager
    Window->>Manager: ~RhiManager()
    Manager->>Manager: destroyRenderer()
Loading

Flow diagram for renderer invalidation guards

flowchart LR
    A[QSGRenderContext invalidated] --> B["destroyRenderer()"]
    B --> C["renderer = nullptr"]
    C --> D{sync, preprocess, or render}
    D -->|renderer or m_rhi unavailable| E[Return without rendering]
    D -->|resources available| F[Continue RHI rendering]
Loading

File-Level Changes

Change Details Files
Align the backdrop renderer lifetime with QSGRenderContext invalidation to avoid teardown-order crashes.
  • Initialize context and renderer safely.
  • Connect invalidated with a direct connection to destroy the renderer immediately.
  • Centralize cleanup in destroyRenderer() and reuse it during destruction.
  • Guard synchronization and rendering paths after renderer or RHI invalidation.
src/private/dbackdropnode.cpp
Add a regression test covering RHI backdrop teardown after a completed render frame.
  • Render a BackdropBlitter frame before destroying the window.
  • Skip environments without an applicable RHI or enabled InWindowBlur path.
  • Verify window teardown completes without the prior renderer/ShaderManager crash.
tests/ut_dquickinwindowblur.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/private/dbackdropnode.cpp" line_range="385-386" />
<code_context>
     }

     bool preprocess(QRhiRenderTarget *rt, qreal &oldDPR, QRhiCommandBuffer* &oldCB, QSurface *forceSurface = nullptr) {
+        if (Q_UNLIKELY(!renderer || !m_rhi))
+            return false;
+
         QRhiCommandBuffer *cb = nullptr;
</code_context>
<issue_to_address>
**Rendering crashes without an RHI**

When `QSGRhiSupport::createRhi()` returns no RHI during initialization or resource exhaustion, `preprocess()` returns false, but `RhiNode::render()` continues to access `RhiManager::rhi()` or `this->rhi->rhi()` with a null RHI, crashing the render thread and the app.

Make `RhiNode::render()` stop before accessing the manager’s RHI when no RHI was created.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment on lines +385 to +386
if (Q_UNLIKELY(!renderer || !m_rhi))
return false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Rendering crashes without an RHI

When QSGRhiSupport::createRhi() returns no RHI during initialization or resource exhaustion, preprocess() returns false, but RhiNode::render() continues to access RhiManager::rhi() or this->rhi->rhi() with a null RHI, crashing the render thread and the app.

Make RhiNode::render() stop before accessing the manager’s RHI when no RHI was created.

Prompt for AI agents
In `src/private/dbackdropnode.cpp` at lines 385-386:

**Rendering crashes without an RHI**

When `QSGRhiSupport::createRhi()` returns no RHI during initialization or resource exhaustion, `preprocess()` returns false, but `RhiNode::render()` continues to access `RhiManager::rhi()` or `this->rhi->rhi()` with a null RHI, crashing the render thread and the app.

Make `RhiNode::render()` stop before accessing the manager’s RHI when no RHI was created.

18202781743
18202781743 previously approved these changes Oct 29, 2026
1. RhiManager now connects to QSGRenderContext::invalidated
(DirectConnection) and destroys the Renderer immediately in
destroyRenderer(), rather than waiting until RhiManager's destructor
runs during QObject child cleanup.
2. Renderer holds a reference to QSGRenderContext's ShaderManager
child; deleting the renderer after that child is gone causes a SIGSEGV
in ~Renderer -> ShaderManager::clearCachedRendererData. Handling
invalidated matches Qt's QSGRhiLayer pattern.
3. sync(), preprocess(), and render() now bail out when renderer (or
m_rhi in preprocess) is null, preventing operations on a destroyed RHI
context.
4. context/renderer are initialized to nullptr in the constructor, and
destroyRenderer() is reused from both invalidated and ~RhiManager.
5. Added regression test destroyWithBackdropNodeOnRhi, which renders a
frame with DQuickBackdropBlitter then destroys the window; it crashed
before this fix and exits cleanly after.

Log: Fixed exit crash caused by DBackdropBlitter renderer lifecycle

Influence:
1. Close windows in existing InWindowBlur demos/apps and confirm no
crash on the default RHI rendering path.
2. Run related scenes with the software scene graph backend to confirm
the guards preserve behavior when RhiManager is not created.
3. On Qt6, exercise window teardown with OpenGL/Vulkan/D3D/Metal RHI
backends, with and without DTK_DISABLE_INWINDOWBLUR.
4. Run the new regression test
ut_DQuickInWindowBlur.destroyWithBackdropNodeOnRhi and verify it passes.

fix: 在 invalidated 时销毁 backdrop renderer

1. RhiManager 现在以直连连接监听 QSGRenderContext::invalidated,在信号
发出时立即通过 destroyRenderer() 销毁 Renderer,不再等到 RhiManager 析构
(QObject 子对象清理阶段)才执行。
2. Renderer 持有 QSGRenderContext 的 QObject 子对象 ShaderManager 的
引用;在 ShaderManager 销毁后才 delete Renderer,会在 ~Renderer →
ShaderManager::clearCachedRendererData 中访问已释放内存并崩溃。Qt 对
QSGRhiLayer 也是同样处理。
3. sync()、preprocess()、render() 在 renderer(preprocess 中还包含
m_rhi)为空时直接返回,避免在已销毁的 RHI context 上继续渲染。
4. 构造函数将 context/renderer 初始化为 nullptr,删除逻辑集中到
destroyRenderer(),析构函数也调用它。
5. 新增回归用例 destroyWithBackdropNodeOnRhi:先通过
DQuickBackdropBlitter 渲染一帧再销毁窗口;修复前会崩溃,修复后可正常
退出。

Log: 修复 DBackdropBlitter 渲染器生命周期导致的退出崩溃

Influence:
1. 运行已有的 InWindowBlur 示例/应用并关闭窗口,确认默认 RHI 渲染路径不
崩溃。
2. 使用软件场景图后端运行相关场景,确认未创建 RhiManager 时保护逻辑不影
响原有行为。
3. 在 Qt6 下分别使用 OpenGL/Vulkan/D3D/Metal RHI 后端测试窗口销毁,并分
别设置/不设置 DTK_DISABLE_INWINDOWBLUR。
4. 运行新增回归用例 ut_DQuickInWindowBlur.destroyWithBackdropNodeOnRhi,
确认通过。

PMS: TASK-397773
@deepin-ci-robot

Copy link
Copy Markdown
Contributor

deepin pr auto review

🤖 AI 代码审查报告

总体评分: 100 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 本次提交修复了窗口销毁时 RhiManager 的 renderer 因在 QObject 子对象清理阶段才被 delete, 导致 ~Renderer 访问已释放的 ShaderManager 而引发 SIGSEGV 的崩溃问题。修复方案正确地将 renderer 的销毁时机提前到 QSGRenderContext::invalidated 信号触发时,并在 sync/preprocess/render 三个方法中增加空指针保护。四维度分析均未发现问题,代码注释详尽,测试用例覆盖完整,无安全漏洞。

🔍 详细分析

1. 语法逻辑 ✅

评价: 语法正确,逻辑清晰 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: ['无需修改,语法逻辑完全正确。']


2. 代码质量 ✅

评价: 代码结构清晰,注释完整 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: ['无需修改,代码质量和注释完整度均达标。']


3. 代码性能 ✅

评价: 性能良好,资源使用合理 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: ['无需修改,性能表现良好。']


4. 代码安全 🔒

评价: 存在0个安全漏洞 ✅ 通过

🔐 发现 0 个安全漏洞

安全漏洞详情:
✅ 未发现安全漏洞

建议: ['无需修改,代码安全合规。']


💡 改进建议代码示例

// 当前代码已正确修复了生命周期问题,无需额外修改。
// 核心修复模式如下(已存在于提交中):
//
// 在 RhiManager 构造函数中连接 invalidated 信号:
//   connect(context, &QSGRenderContext::invalidated,
//           this, &RhiManager::destroyRenderer, Qt::DirectConnection);
//
// 在 sync/preprocess/render 中增加空指针保护:
//   if (Q_UNLIKELY(!renderer))
//       return;
//
// destroyRenderer() 方法确保原子销毁:
//   void destroyRenderer() {
//       delete renderer;
//       renderer = nullptr;
//   }

本报告由 AI 代码审查工具自动生成

@deepin-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, caixr23

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@caixr23

caixr23 commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

/merge

@deepin-bot

deepin-bot Bot commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

This pr cannot be merged! (status: unstable)

@caixr23

caixr23 commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

/forcemerge

@deepin-bot

deepin-bot Bot commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

This pr force merged! (status: unstable)

@deepin-bot
deepin-bot Bot merged commit 0159003 into linuxdeepin:master Oct 30, 2026
19 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants