9.6 KiB
Particle V13 严格代码审查报告
日期:2026-09-25(Asia/Tokyo) 审查性质:Mac 仓库只读代码审查、历史任务/报告交叉核对、定向原生测试复跑。未修改业务源码、未执行设备 GPU runtime 或 profiler。
1. 审查基线和证据分级
- Mac:
/Users/tei/dev/MapLibreParticleLab;分支:particle/main。 - HEAD 与
origin/particle/main一致:ee0b89e711bf01335b3aa71d36def785cd97fec3;工作树 clean。 - V13 功能提交:
016fd1fff6a33cf795c10d4f5c5413d308383677。发布版本:13.4.1-particle.13。 - Integration 主线:
39ad8415fbdb76c1822460bb09f3a3f35fe141e0。 - 参照:
docs/40_任务/STEP-092...、STEP-093...、STEP-094...任务;对应docs/报告/与docs/50_Step记录/;STEP-088/089/090 性能历史报告。 - 本次独立复跑:Render Segment/Retained/Fast Path 43/43 PASS;Field/QBIN/Viewport Reseed 69/69 PASS;V13 RN package TypeScript PASS。
- 当前 RN Test Host
npm run typecheck失败(exit 2):TS2307 无法解析@navsea/maplibre-particle-rn,伴随 TS7006。Host package.json 仍指向.10。此前 Codex 使用临时工作树依赖通过,不等于当前默认安装可重复验证。 - STEP-094 报告记录 OpenGL、Metal 构建、Codegen、Android Validation APK 通过;Android/iOS V13 runtime、GPU frame/visual、功耗与长时间运行仍 NOT RUN。此报告不将历史 Android 性能测量冒充 V13 性能。
2. 审查结论
没有在已复跑的纯数据结构/协议测试中发现失败;但 V13 在高频渲染、Metal 多段重建、GPU 资源分配和真实运行态验收上存在明确风险。不能由 43 项纯 Native 测试和编译 PASS 推断任意 R/C 交错的 GPU 输出、跨平台性能已经验收。
F01 — P1:完整 Diagnostics 深复制进入每帧热路径(源码确定)
证据:src/mbgl/renderer/renderer_impl.cpp:206-208,500-505;src/mbgl/renderer/retained_underlay_runtime_state.hpp:243-254。
tryRenderParticleFastFrame() 和 render() 调用 renderSegmentSnapshot();该函数在互斥锁内复制完整 RenderSegmentDiagnostics(含 styleLayers 与每个 Segment 的重复 layers/字符串),再补几个状态字段。一次 fast frame 可能复制两次。与 pull-based 诊断的设计意图不一致。
修复:增加只读的轻量 hot-path 状态(enabled/configRevision/topologyRevision 等);完整快照只在外部 pull 时构造;快照构建/复制次数做计数,稳定 30/60 FPS 应接近零。
F02 — P1:Metal Retained 构建逐段 GPU 同步等待(源码确定,运行影响待 profile)
证据:renderer_impl.cpp:790-824;retained_underlay_cache.cpp:316-322;src/mbgl/mtl/command_encoder.cpp:29-31;src/mbgl/mtl/offscreen_texture.cpp:86-91。
finishBuild()->present(*offscreenTexture)->swap() 内部 commit() 后 waitUntilCompleted()。一帧多个 Retained 段失效时,可能产生多次串行 CPU/GPU 同步。使用 Metal System Trace / GPU Capture 测量 waitUntilCompleted 时间和 command-buffer 数量,再设计保持依赖顺序的异步提交/跨 pass 协调;不可仅删除 wait 而不确保纹理可读。
F03 — P1:缓存内容失效与 GPU 资源销毁耦合(源码确定)
证据:retained_underlay_cache.cpp:203-209,241-255,364-374。
revisionChanged 使 invalidate() 与 releaseResources() 一起发生,即使 viewport 未变、GPU context 有效,重建时仍需重新创建纹理和 composite group。普通 camera、source/tile、content revision 在多 Retained 段下会放大分配/销毁和相关同步。
修复:分离 contentDirty 与 resourceInvalid,同尺寸同 context 保留 allocation、重新 clear/build;context loss、尺寸不兼容、显式关闭/释放时才销毁。用 peak GPU bytes、textureCreate、resourceRelease、每帧 build/reuse 证明收益与正确性。
F04 — P1:多缓存没有 GPU 内存预算(源码确定,OOM 影响待量化)
证据:renderer_impl.cpp:506-524;retained_underlay_cache.cpp:241-251;mtl/offscreen_texture.cpp:20-55;gl/offscreen_texture.cpp:18-35。
每个 Retained Segment 均拥有完整 viewport 的 RGBA + depth/stencil 离屏资源;总成本约随 retainedCount×width×height 增长。相邻 R-R 也各自独立,符合契约,但高像素 iPad 与多段场景缺乏实际 bytes/peak/budget 观测。先增加预算与失败时的安全 full-render fallback,切勿通过强制合并相邻 R-R 破坏 V13 契约。
F05 — P1:V13 Test Host 默认安装不可复现(已复现失败)
证据:integration/react-native/MapLibreParticleRNTestHost/package.json 指向 .10;当前 npm run typecheck exit 2;报告也明确临时本地替换后已恢复旧依赖。
修复:将 Test Host 依赖和 lockfile 与已发布 .13 精确对应,重新安装并验证 V13 typecheck/codegen/iOS & Android bridge/真实运行;测试日志注明源包及 Native 精确版本。不得将临时链接环境结果写成默认环境 PASS。
F06 — P1:多 Continuous 的 Particle Fast Path 固定 fallback(明确设计限制)
证据:renderer_impl.cpp:45-57,198-287 和 particle_fast_path.hpp:110-140,STEP-094 设计与报告。
N 个 Continuous 中只支持恰好一个的 Fast Path;R-C-R-C-R 场景总走 Full CPU。STEP-090 历史 A/B 场景 RenderThread 约为 fast ON 21.7% / OFF 97.0%,只是历史参考,不能直接视作 V13 数据。先采集 V13 多 C 的 CPU/GPU 帧时间与频率,再设计可组合的 multi-C fast path;绝不可为性能偷偷移动 Style Layer 或合并相邻段。
F07 — P2:范围访问反复计算线性 ordinal(源码确定)
证据:src/mbgl/renderer/render_orchestrator.hpp:156-180,std::distance(multimap.begin(), lower_bound(...))。每个 Segment 的 opaque/translucent、build、upload/tweaker 路径可重复触发定位。
修复:在 LayerGroup topology 变化时预计算有序索引/ordinal;高频 render 只用稳定区间和 ordinal,避免多段场景重复 O(N) 前缀遍历。
F08 — P2:多段失效粒度仍过宽(明确设计限制)
证据:renderer_impl.cpp:565-646;render_orchestrator.cpp:156-158,1005-1018。Layer Impl fingerprint 可局部失效;source/tile/image/glyph/placement 与聚合 retainedSupported 仍可能使全部 R fallback/build。应先用 sourceId 与 Segment 关联建立有证据的保守依赖关系,无法归属继续全局失效,不得牺牲安全。
F09 — P2:Diagnostics 资源指标可能发生归属偏差(源码路径风险)
证据:retained_underlay_runtime_state.hpp:173-240 更新新 topology/entry;renderer_impl.cpp:506-524 随后 clear() 旧 caches;旧对象析构在 retained_underlay_cache.cpp:364-374 用旧 segmentIndex 报 release。不同 topology 的相同 index 可能指向新段,旧资源的释放计数可能归于新段或被 Continuous cache=null 丢弃。建议使用 cache generation/unique ID 归属,或在更换 diagnostics topology 前记录旧 generation 的 release;聚合 totals 与 per-generation 分离。
F10 — P2:发布与协调状态资料漂移(核对事实)
Integration 的 status/、compatibility/MATRIX.md 仍描述 .5 / iOS XCFramework 等旧状态,Mac 粒子仓库已发布 .13。应由粒子负责人维护正式兼容矩阵,区分“Particle 已发布”和“NavSea 已接入/验证”,不得仅根据旧矩阵断言 V13 不存在或已在 NavSea 生效。
3. 正确性与验证缺口
以下不是已证实的渲染 bug,而是必须在设备上验证的风险:
- V13 segmented pass 改变了 opaque/translucent、offscreen composite 的执行拆分;纯 resolver GTest 不覆盖 GPU blending/depth/stencil 与 Metal/OpenGL 的最终像素。
- 必须覆盖 R-C-R、C-R-R、R-R-C、R-C-R-C-R、相邻 R-R 独立 cache、全 R、全 C,特别是透明航标/半透明颜色场与动态粒子叠加。
- hidden boundary、invalid/recovery、Style layer insert/remove/reorder、Resize/Rotate/Pan/Zoom/Pitch、Context loss、Cache ON/OFF、Source/Tile mutation、切换 Plan 后的下一帧,均需要截图/帧采样和资源 counter 交叉验收。
- STEP-093/094 报告已明确运行态 NOT RUN,因此不以原生编译 PASS 代替此项。
4. 推荐执行顺序(分批,降低反复安装成本)
A. 无需设备的修复:先处理 F01 快照深复制、F05 Test Host 精确版本与复现、F07 ordinal、F09 诊断归属;增加纯 C++ 定向回归。每阶段只做对应范围,不把源文件无关改动混入。
B. Metal 资源修复:合并 F02/F03/F04,统一处理 GPU 对象分配与同步、资源预算;OpenGL/Metal 静态编译和 Native regression 先行;再一次集中到 iPhone/iPad 采集 GPU Frame Capture。
C. 正式运行态验收:集中执行 topology、alpha/depth、invalid/recovery、30/60 FPS、稳定/变更、内存峰值、30 分钟以上长稳态;记录相同设备、相同 Style、相同视口的 V12/V13 或 V13 ON/OFF 成对指标,不外推历史数字。
D. 后续性能架构:在基础正确性通过后,再研究多 Continuous Fast Path 和 source-to-segment 精确依赖。保持 Style Z-order 唯一顺序源、不合并同策略相邻段、不引入业务频率分类。
5. 最终判定边界
- 纯 Native tests:43/43 + 69/69 PASS;RN V13 package TS PASS。
- Test Host 默认环境:FAIL(缺失模块 /
.10引用)。 - 源码性能问题:F01/F02/F03/F07 的触发调用链得到静态确认;真实节省量仍需设备测量。
- V13 Android/iOS GPU runtime、完整画面、内存和长时间性能:本次 NOT RUN;不声称生产级全量 PASS。
- Mac Git:HEAD 与 origin 一致,工作树 clean;未修改粒子源码。