Files
MapLibreParticleLab/docs/报告/STEP-100_SourceScoped_RenderSegment局部失效_Codex完成报告_v1.md
tei 524aaf4af5
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
fix: localize retained segment source invalidation
2026-10-06 17:18:09 +09:00

10 KiB
Raw Permalink Blame History

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.hpp
  • src/mbgl/renderer/render_orchestrator.hpp
  • src/mbgl/renderer/render_orchestrator.cpp
  • src/mbgl/renderer/renderer_impl.cpp
  • src/mbgl/renderer/retained_underlay_cache.cpp
  • src/mbgl/renderer/retained_underlay_runtime_state.hpp
  • src/mbgl/renderer/render_segment_json.hpp
  • packages/maplibre-particle-rn/src/types.ts

Test App / tests:

  • platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/particle/Step099ReadinessFixture.kt
  • platform/android/MapLibreAndroidTestApp/src/main/java/org/maplibre/android/testapp/activity/particle/ParticleCoreLayerValidationActivity.kt
  • test/renderer/retained_underlay_cache.test.cpp

工具:

  • tools/particle_android_validation/build_validation_apk.sh
    • RDC 修复 unzip | awk ... exit 在 pipefail 下偶发 SIGPIPE/141;
    • 仅移除 awk 的提前 exit,不改变 APK 验证语义。

文档:

  • docs/40_任务/STEP-100_SourceScoped_RenderSegment局部失效_Codex任务_v2.md
  • docs/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 审计确认未修改:

  • tryRenderParticleFastFrame
  • particleFastPathNonCameraInputsMatch
  • singleContinuousSegment
  • 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 的核心实现目标全部成立:

  1. global revision 继续增长;
  2. R1 GeoJSON mutation 不再 invalid/rebuild R0;
  3. R0 buildDelta=0;
  4. R0 invalidationDelta=0;
  5. R0 reuseDelta>0;
  6. transient unrelated unloaded 不影响 R0 reuse;
  7. permanent unrelated unloaded 不影响 R0 reuse;
  8. mixed Reuse/Fallback 实际发生;
  9. Fast Path 语义未放宽。

因此本 Step 功能与 Android runtime 验收:

PASS / CLOSED。

下一步允许进入 V18 unified release。