10 KiB
STEP-100 SourceScoped RenderSegment 局部失效 — 完成报告 v1
1. 最终结论
CLOSED / PASS(功能与 Android 运行态目标确认)。
Codex 实现使用:
- model:
gpt-6-sol - reasoning effort:
high
RDC 独立完成:
- 源码 diff 审计;
- Android x86_64 OpenGL 全量 native build;
- Validation APK;
- FZG1-2 自动安装与 T1/T2/T3/T4;
- STEP-100 60 秒 locality window;
- validation build script 小型工程修复;
- Git diff/status 审计。
本 Step 核心目标已确认:
动态 GeoJSON Source 更新只影响依赖它的 RETAINED Segment;无关 R0 cache 不再跟着 invalid/rebuild,并且在 global loaded=false 时仍可安全 reuse。
Native host GTest 因当前 Intel Mac 缺 libuv 未执行;曾尝试 Homebrew 安装,但 Homebrew 要连带升级 CMake/OpenSSL/Python 且 Intel 已无 bottle 支持,因此 RDC 主动终止,未把环境变化作为任务依赖。Android 最终 C++ native build 与设备运行态用于本轮功能验收。
Jest:NOT RUN,用户未要求。
2. Git / 基线
- worktree:
/Users/tei/dev/MapLibreParticleLab-step100 - branch:
step100-segment-local-source-invalidation - start HEAD:
c4b481fd2c5b5da20d31f6ae54011f0552d7dbd0 - start remote:
origin/particle/main = c4b481fd2c5b5da20d31f6ae54011f0552d7dbd0 - frozen V17 tag:
maplibre-particle/rn/13.4.1-particle.17 - frozen V17 commit:
e8b451fe70054107773e82484c80e90df3889147 - V17 tag/release worktree:未修改。
最终 STEP-100 commit / push / remote HEAD 在 Git 收尾后由最终交付回读记录,避免文档自引用。
3. 实际修改
生产源码:
include/mbgl/renderer/render_segment.hppsrc/mbgl/renderer/render_orchestrator.hppsrc/mbgl/renderer/render_orchestrator.cppsrc/mbgl/renderer/renderer_impl.cppsrc/mbgl/renderer/retained_underlay_cache.cppsrc/mbgl/renderer/retained_underlay_runtime_state.hppsrc/mbgl/renderer/render_segment_json.hpppackages/maplibre-particle-rn/src/types.ts
Test App / tests:
platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/particle/Step099ReadinessFixture.ktplatform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/particle/ParticleCoreLayerValidationActivity.kttest/renderer/retained_underlay_cache.test.cpp
工具:
tools/particle_android_validation/build_validation_apk.sh- RDC 修复
unzip | awk ... exit在pipefail下偶发 SIGPIPE/141; - 仅移除 awk 的提前 exit,不改变 APK 验证语义。
- RDC 修复
文档:
docs/40_任务/STEP-100_SourceScoped_RenderSegment局部失效_Codex任务_v2.mddocs/50_Step记录/STEP-100_SourceScoped_RenderSegment局部失效_v1.md- 本报告;
粒子开发记录.md
4. 生产设计
4.1 Source-scoped revision
新增正式 source-scoped revision bookkeeping。
明确的 Source/Tile mutation:
- source diff;
- feature state;
- tile changed;
推进对应 sourceId revision。
现有 global retainedUnderlayContentRevision 继续增长,供:
- compatibility;
- diagnostics;
- Fast Path fail-closed。
RETAINED Segment cache 不再直接以 global Source/Tile revision 作为内容 revision。
4.2 Segment dependency
正式 renderer 与 diagnostics 共用 source→segment 依赖推导。
规则:
- layer sourceId 决定 source dependency;
- source-less background 不制造假 dependency;
- shared source 可影响多个 segment;
- symbol 的 glyph/image/placement 作为明确 global prerequisite;
- 真正无法证明的 dependency fail closed。
4.3 Per-segment readiness
未修改:
Source::isLoaded();renderTreeParameters->loaded = styleLoaded && isLoaded()。
full CPU retained path 增加 per-segment source readiness/stability:
- dependent source unloaded → 仅该 Segment fallback;
- dependent source fading → 仅该 Segment unstable;
- unrelated source unloaded/fading → 不影响该 Segment;
- style/image/sprite/glyph/placement/context 等 global prerequisite 仍 fail closed。
4.4 Mixed Build / Reuse / Fallback
移除 retained full-CPU path 的 all-or-none useRetainedRanges 依赖。
每个 RETAINED Segment独立决定:
- Build
- Reuse
- Fallback
主 buffer 按 Style Segment 顺序执行:
- RETAINED Build/Reuse → composite cache
- RETAINED Fallback → live render only that range
- CONTINUOUS → live render
因此允许:
R0 = Reuse
C = Live
R1 = Fallback
不再因为 R1 fallback 把 R0 一起变成 live redraw。
Fast Path gate / singleContinuousSegment / multi-continuous Fast Path:未修改。
5. Android build
首次标准 validation script 的 Gradle 本体实际结果:
BUILD SUCCESSFUL in 12s
86 actionable tasks: 6 executed, 80 up-to-date
但脚本在 Gradle 成功后以 141 退出。RDC 用 bash -x 精确定位到:
LIB_BYTES="$(unzip ... | awk '/.../ {print $1; exit}')"
在 set -o pipefail 下触发 SIGPIPE。
RDC 仅去掉 awk 的 exit,重跑标准脚本:
RC=0
[validation-apk] BUILD SUCCESS
最终 APK:
- variant:OpenglDebug
- ABI:x86_64
- apk bytes:61,956,640
- libmaplibre.so bytes:39,636,472
- SHA-256:
86e22bf081bf7d3196f0bf0e7c56af51bde01e9f0b01e0bab238cb794273315a
证据:
artifacts/maplibre-particle/android-validation/
6. 设备
- serial:
192.168.200.139:5555 - model:FZG1-2
- Android:13
- API:33
- ABI:x86_64
APK 覆盖安装成功,ParticleCoreLayerValidationActivity 冷启动成功。
STEP-100 log:
artifacts/maplibre-particle/android-validation/step100-logcat.txt
log SHA-256:
e9d18ea987d12cb30e321d0d9c669b2588972aac89e5277920bf1fa9fee8146b
7. T1 STATIC
运行约 20 秒。
aggregate:
falseWindowCount=1
falseWindowAvgMs=203
falseWindowMaxMs=203
openFalseWindowMs=0
最终:
- R0 build=1
- R0 reuse=1217
- R0 decision=reuse
- R1 build=1
- R1 reuse=1187
- R1 decision=reuse
静态 R-C-R 正常。
8. T4 R-C-R 主验收
结构:
R0 -> step099-static
C -> particle-fixture
R1 -> step099-dynamic (+ framework annotation source if present)
window marker:
baseline tick=8 17:05:21.642
final tick=130 17:06:23.240
窗口约 61.6 秒。
dynamic update 总计:68 次。
global revision:
128 -> 973
说明 global compatibility revision 仍正常增长,没有通过停掉 global revision“作弊”。
R0
baseline:
build=1
reuse=132
invalidation=20
srcRev=5127273714767523329
decision=reuse
final:
build=1
reuse=4042
invalidation=20
srcRev=5127273714767523329
decision=reuse
Delta:
buildDelta = 0
invalidationDelta = 0
reuseDelta = +3910
sourceRevision = unchanged
硬门槛 PASS。
R1
baseline:
build=5
invalidation=26
final:
build=135
invalidation=211
动态 Source mutation 正常驱动 R1。
mutation diagnostics 持续:
sourceId=step099-dynamic
affected=[2]
scope=source-local-diagnostic
loaded false windows
T4:
falseWindowCount=5
falseWindowAvgMs=202
falseWindowMaxMs=203
openFalseWindowMs=0
即 transient global loaded=false 仍存在,但不再让 R0 build/invalidation 增长。
9. T2 双 GeoJSON readiness 回归
约 35 秒。
aggregate:
falseWindowCount=6
falseWindowAvgMs=203
falseWindowMaxMs=205
openFalseWindowMs=0
R0 在动态窗口保持:
- build=1
- invalidation=18
- revision unchanged
- reuse 持续增长。
R1 随两个动态 GeoJSON 持续 build/invalidate。
结论: DYNAMIC_SOURCE_READINESS_THRASH 仍是 global loaded 事实,但不再误伤无关 retained cache。
10. T3 permanently unready unrelated source
step099-unready-raster-array:
- no layer;
- enabled=false;
- isLoaded=false。
global:
renderOrchestratorLoaded=false
openFalseWindowMs=21468
约 21.468 秒持续 false。
与此同时:
R0:
- build=1
- invalidation=19
- reuse:11 → 1200
- decision=reuse
R1:
- build=1
- invalidation=19
- reuse:11 → 1200
- decision=reuse
因此:
global loaded 仍保持旧兼容语义,但 unrelated permanently-unready source 已不能把无关 RETAINED Segment 拖成 style-not-loaded fallback。
硬门槛 PASS。
11. Mixed fallback
T4 中 R1 fallbackCount 从约 21 增长到 76,而 R0 fallback 计数保持不变,同时 R0 reuse 持续增长。
这证明运行期间真实发生了:
R0 = Reuse
R1 = transient Fallback / rebuild
而不是只有“两个段都 ready”的理想场景。
未观察到 crash / ANR。
12. Fast Path 边界
RDC diff 审计确认未修改:
tryRenderParticleFastFrameparticleFastPathNonCameraInputsMatchsingleContinuousSegment- multi-continuous fail-closed
- global Fast Path signature/fade/contentRevision/pending/placement 等 gate。
STEP-100 只修 full CPU retained locality。
13. Native host tests
Codex 已新增 RenderSegmentLocality.* C++ 测试源码。
RDC 尝试恢复 macos-metal test runner,但 host configure 需要 libuv,当前未安装。
尝试 brew install libuv 时发现 Intel Homebrew 会连带升级:
- CMake
- OpenSSL
- Python
- ca-certificates 等
且当前 Intel macOS 已无官方 bottle 支持。为避免污染开发环境,RDC 主动停止。
因此:
- Native host GTest:ENV BLOCKED / NOT RUN
- Android C++ full native build:PASS
- Android device runtime:PASS
14. Jest / iOS
- Jest:NOT RUN。
- iOS runtime:本 Step 未运行。
- V18 unified release:在 STEP-100 Git 收尾后单独执行。
15. 最终判定
STEP-100 的核心实现目标全部成立:
- global revision 继续增长;
- R1 GeoJSON mutation 不再 invalid/rebuild R0;
- R0 buildDelta=0;
- R0 invalidationDelta=0;
- R0 reuseDelta>0;
- transient unrelated unloaded 不影响 R0 reuse;
- permanent unrelated unloaded 不影响 R0 reuse;
- mixed Reuse/Fallback 实际发生;
- Fast Path 语义未放宽。
因此本 Step 功能与 Android runtime 验收:
PASS / CLOSED。
下一步允许进入 V18 unified release。