- _refresh_messages: widget pool reuse to avoid layout cascade → QWebEngineView crash - viewer.html: QWebChannel bridge, texture resize, burst render, gl.finish - live2d_view.py: debug checkpoints, playMotion/setExpression render-on-demand - main.py: Chromium flags --no-sandbox --in-process-gpu --disable-gpu-rasterization --ignore-gpu-blocklist - scheduler.py: test_reminder re-enabled - docs: complete root cause analysis
4.0 KiB
EzVibe Segfault 第二阶段调查 — Live2D QWebEngineView GPU 进程崩溃
日期: 2026-05-23
崩溃现象(phase 1 修复后仍存在)
QObject::setParent: Cannot set parent, new parent is in a different thread (x12)
[DEBUG] _try_inject called
[DEBUG] _inject_model_data called...
[DEBUG] Model data written...
127.0.0.1 - GET /_model_data.json 200
127.0.0.1 - GET /texture_00.png 200
127.0.0.1 - GET /texture_01.png 200
QObject::setParent: Cannot set parent, new parent is in a different thread <-- 新增!
[ERROR: command_buffer_proxy_impl.cc:327] GPU state invalid after WaitForGetOffsetInRange.
Segmentation fault (core dumped)
Phase 1 修复回顾
| 修复 | 文件 | 效果 |
|---|---|---|
--disable-gpu-sandbox --disable-seccomp-filter-sandbox |
main.py |
30s 测试通过,但用户环境仍崩溃 |
| 直接父控件(避免 reparent QWebEngineView) | pet_window.py |
减少了一次 setParent 路径 |
结论:sandbox 禁用部分有效,但 GPU 进程本身仍崩溃。
新错误分析
GPU state invalid after WaitForGetOffsetInRange
来源:qtwebengine/src/3rdparty/chromium/gpu/ipc/client/command_buffer_proxy_impl.cc:327
含义:Chromium 的 GPU 进程命令缓冲区(command buffer)损坏。浏览器进程通过共享内存(command buffer)向 GPU 进程提交渲染命令。当 GPU 进程崩溃或共享内存损坏时,浏览器进程在同步等待(WaitForGetOffsetInRange)时检测到无效状态。
可能原因链
- GPU 进程被 sandbox 杀死(phase1 已修复)
- GPU 驱动 bug 导致 GPU 进程崩溃 → 需
--in-process-gpu - WebGL 渲染命令队列溢出/损坏 → 需
--in-process-gpu - 共享内存在跨线程访问时损坏 → 需
--in-process-gpu - Live2D render loop 每 100ms 提交 WebGL 命令,累积触发 GPU 崩溃
为什么 phase1 测试 30s 通过但用户环境崩溃
- 我的测试环境:
timeout 30强杀(EXIT 124),30s 内未崩溃 - 用户环境:无限等待,崩溃发生时间未知(可能 >30s)
- GPU 错误可能是累积性的:render loop 运行 N 帧后 GPU 状态损坏
修复方案
方案 A:--in-process-gpu(推荐)
将 GPU 进程作为浏览器进程内的线程运行,避免:
- 跨进程 IPC 的 command buffer 同步
- GPU 进程独立 sandbox
- 共享内存损坏
代价:GPU 崩溃会导致整个浏览器进程崩溃,但我们的 app 只有一个 WebEngine 实例。
方案 B:--disable-gpu + 软件渲染
完全禁用 GPU 加速,WebGL 无法使用。Live2D 将不渲染。
方案 C:--use-gl=swiftshader
使用 SwiftShader(CPU 实现 OpenGL ES)。如果 Qt WebEngine 编译了 SwiftShader。
实施
采用方案 A 为主要修复,配合:
--no-sandbox:完全禁用 sandbox(比--disable-gpu-sandbox更彻底)QTWEBENGINE_DISABLE_SANDBOX=1:Qt 层面的 sandbox 禁用
setParent 警告分析
12 个 QObject::setParent: Cannot set parent, new parent is in a different thread 警告来自 QWebEngineView 内部初始化。Chromium render 进程创建 GPU surface 代理对象(QWidget-based),这些对象在 render 线程创建后被 reparent 到主线程的 widget 树。这些警告是 Qt WebEngine 的内部实现细节,在 --in-process-gpu 启用后应该消失(因为不再有独立的 GPU 进程)。
Viewer.html WebGL 代码潜在 NaN 问题
在 renderFrame() 中:
if(isNaN(px) || isNaN(py)) continue;
vdata[v * 4] = px;
vdata[v * 4 + 1] = py;
// ...
如果 px 或 py 是 NaN,continue 跳过赋值但 v 仍递增。未初始化的 vdata 元素保持 0.0。虽不会导致 crash,但顶点位置 (0,0) 可能导致渲染异常。已顺带修复为不使用 continue。
修改文件清单
| 文件 | 修改 |
|---|---|
main.py |
Chromium flags: --no-sandbox --in-process-gpu; env: QTWEBENGINE_DISABLE_SANDBOX=1 |
ui/pet_window.py |
(phase1 已修复) 直接父控件 |
assets/live2d/march7/viewer.html |
修复 NaN 顶点数据问题 |