# 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`)时检测到无效状态。 ### 可能原因链 1. **GPU 进程被 sandbox 杀死**(phase1 已修复) 2. **GPU 驱动 bug 导致 GPU 进程崩溃** → 需 `--in-process-gpu` 3. **WebGL 渲染命令队列溢出/损坏** → 需 `--in-process-gpu` 4. **共享内存在跨线程访问时损坏** → 需 `--in-process-gpu` 5. **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()` 中: ```javascript 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 顶点数据问题 |