diff --git a/docs/50_Step记录/STEP-088_静态底图缓存PoC与Renderer观测_v2.md b/docs/50_Step记录/STEP-088_静态底图缓存PoC与Renderer观测_v2.md new file mode 100644 index 000000000..ac4e69ab0 --- /dev/null +++ b/docs/50_Step记录/STEP-088_静态底图缓存PoC与Renderer观测_v2.md @@ -0,0 +1,139 @@ +# STEP-088 静态底图缓存 PoC 与 Renderer 观测 v2 + +## 状态 + +进行中 + +`ANDROID TEST APP PASS / WAITING FOR NAVSEA VALIDATION` + +STEP-088 尚未关闭,也不得据此进入 STEP-089/090。 + +## 本版目的 + +本文在 v1 实现记录基础上,记录 Android MapLibreAndroidTestApp 实机发现的 placement fallback 问题、Renderer 修正、Mac 最终复验和 Android Test App 运行态验收。v1 中的 retained underlay 架构、范围和 PoC 限制继续有效。 + +## 基线 + +- 仓库:`/Users/tei/dev/MapLibreParticleLab` +- 分支:`particle/main` +- v1 实现提交:`8b9ab303228c307612c47f7f3379ad06206ea14e` +- debug counters 日志提交:`e7d109246a225eb1c1b2f177aa30e3c7fcdf658e` +- Android placement-scoping 修正提交:`1d1a7915e0886c46be40f4fc9a2eff13192f804b` +- 当前版本坐标:`13.4.1-particle.10` + +## Android 首轮问题 + +较早安装的 STEP-088 APK 在 fixed camera / only Particle 场景持续 full-render fallback: + +```text +frame=1200 build=0 reuse=0 fallback=1199 invalidation=1199 +staticDraw=0 dynamicDraw=0 particleAdvance=1199 +``` + +根因是 retained eligibility 无条件受全局 placement transition、`placementChanged` 和 `symbolFadeChange` 约束。即使 retained static prefix 没有 symbol/placement layer,动态范围或全局 placement 状态也会阻止 cache build/reuse。 + +## Renderer 修正 + +- `RenderOrchestrator::retainedUnderlayUsesPlacement(boundary)` 只检查 boundary 之前的 retained static prefix。 +- static prefix 不使用 placement 时,全局 placement transition、`placementChanged` 和 `symbolFadeChange` 不再阻止 retained cache。 +- static prefix 真正使用 placement 时,上述 placement stability 保护仍然生效并安全 fallback。 +- 原有 3D、debug、legacy ordering、style-not-loaded、static transition、resource/compositor failure 等 fallback 不变。 +- debug-only `ParticleRetained` 周期日志保留 `reason=`,用于区分 `first-frame`、`camera-or-boundary`、`style-not-loaded`、`static-transition`、`static-placement` 等原因;Release/NDEBUG 语义不变。 + +## Android Validation 构建辅助 + +`platform/android/MapLibreAndroidTestApp/build.gradle.kts` 新增测试专用 property: + +```text +maplibre.validation.stripNativeDebugSymbols=true +``` + +默认 Debug 行为不变,仍保留 native debug symbols。只有 Validation 构建显式启用该 property 时才允许 strip native symbols;x86_64 Debug APK 由约 375 MB 降至约 57 MB。该改动不改变 Renderer、debug counters 或 `NDEBUG` 语义。 + +## RDC Mac 最终复验 + +- `cmake --build build-step088-opengl --target mbgl-test-runner -j3`:PASS / no work to do;RDC 已确认当前 placement-scoping 源码已编入 object。 +- STEP-088 定向测试:4/4 PASS: + - `RetainedDynamicBoundary.SelectsFirstCandidate` + - `RetainedLayerGroupRange.PreservesForwardReverseOriginalOrdinals` + - `RetainedUnderlayCache.BuildReuseAndInvalidation` + - `RetainedUnderlayCache.UnsupportedAndResourceFailureFallBackSafely` +- `cmake --build build-ios --config Debug --target mbgl-core -j3`:`BUILD SUCCEEDED`。 +- `git diff --check`:PASS。 + +上述命令均由 RDC 执行;Codex 文档与 Git 收尾阶段未重新执行 build/test。 + +## Android Test App 环境 + +- 设备:`192.168.200.139:5555` +- 设备标识:FZG1-2 +- 系统:Android 13 +- ABI:x86_64 +- App:MapLibreAndroidTestApp OpenGL Debug x86_64 +- Validation strip property:启用 +- 构建、安装、ADB 与 Activity 启动:均成功 + +## Android Test App 运行态结果 + +### Fixed camera / only Particle + +```text +frame=840 build=1 reuse=836 fallback=2 invalidation=3 +reason=first-frame staticDraw=2 dynamicDraw=5022 particleAdvance=839 +``` + +后续 `reuse` 持续增长,`staticDraw` 保持不变,证明 retained static prefix 首次 build 后被复用。 + +### Camera DATELINE + +- 变化前:`build=1`、`staticDraw=2`。 +- camera transition 后:`build=2`、`staticDraw=4`。 +- 随后 `reuse` 重新持续增长。 +- 观测原因:`reason=camera-or-boundary`。 + +结果符合 camera change → transition 期间安全 fallback/invalidate → 稳定后 rebuild 一次 → reuse。 + +### REAL WEATHER + +- `REAL_WEATHER_INITIAL_WINDOW_READY` 正常。 +- `WEATHER_COLOR_FIELD_READY` 正常。 +- GSI raster + WeatherColor + Particle 正常进入 retained path。 +- 代表数据:`frame=6960 build=3 reuse=6907 fallback=49 invalidation=52 staticDraw=6 particleAdvance=6959`。 +- fixed camera 后 `reuse` 持续增长,`staticDraw` 保持 6。 +- `TARGET_FPS_CHANGED target=FPS_30` 成功,缓存继续 reuse。 + +### Resize / rotation + +viewport 完成 `1280x680 → 800x1160 → 1280x680`。过渡期间出现安全的 `style-not-loaded` fallback;稳定后 rebuild 并继续 reuse。设备最终恢复 `accelerometer_rotation=1`、`user_rotation=0`。 + +### STATIC / ACTIVE + +- STATIC 时 RenderThread 约 0%。 +- ACTIVE 后恢复 continuous render,retained reuse 继续增长且 `staticDraw` 保持不变。 +- 旧 Test App 设备上 ACTIVE RenderThread 约 96%~107%,仅作为 Test App 对照,不代表 NavSea 最终性能。 + +### 异常扫描 + +未发现 `FATAL EXCEPTION`、`SIGSEGV`、`SIGABRT`、ANR、`GL_INVALID`、`EGL_BAD` 或 OOM。 + +## 当前验收边界 + +Android MapLibreAndroidTestApp 运行态验证为 PASS,但它不能替代 NavSea 复杂真实 Style 的最终验证。以下仍待 NavSea 完成: + +1. 真实复杂 Style 的视觉与 layer ordering。 +2. 大量 PBF/fill/line/symbol 下 retained static prefix 的 `staticDraw` 稳定性。 +3. Particle OFF/ON 的 RenderThread、main、JS CPU 对比。 +4. pan/zoom/resize/fallback 后无 stale underlay。 +5. only Particle 与 WeatherColor + Particle 在真实产品 layer stack 中的一致性。 + +## PoC 边界 + +- 未实现 STEP-089 production 全量 invalidation。 +- 未实现 STEP-090 animation-only CPU fast path。 +- 未修改 NavSea、React、Host API 或 C-001。 +- Android Test App PASS 不构成 STEP-088 overall CLOSED/PASS。 +- NavSea 验证完成前不得进入 STEP-089/090。 + +## 当前结论 + +placement-scoping 修正解决了 Android 上 static prefix 不含 placement 时的每帧 fallback。Mac OpenGL/Metal、Native 定向测试及 Android Test App 运行态均已通过;STEP-088 当前唯一剩余 Gate 是 NavSea 复杂真实 Style 验证。 diff --git a/docs/报告/STEP-088_静态底图缓存PoC与Renderer观测_Codex完成报告_v2.md b/docs/报告/STEP-088_静态底图缓存PoC与Renderer观测_Codex完成报告_v2.md new file mode 100644 index 000000000..95da36451 --- /dev/null +++ b/docs/报告/STEP-088_静态底图缓存PoC与Renderer观测_Codex完成报告_v2.md @@ -0,0 +1,172 @@ +# STEP-088 静态底图缓存 PoC 与 Renderer 观测 Codex 完成报告 v2 + +## 1. 执行结论 + +- 状态:`ANDROID TEST APP PASS / WAITING FOR NAVSEA VALIDATION` +- Android MapLibreAndroidTestApp 运行态验证:PASS。 +- STEP-088 overall:未关闭,不得写作 CLOSED/PASS。 +- NavSea 复杂真实 Style 尚未验证,因此不得进入 STEP-089/090。 + +## 2. Git 基线与提交 + +- 机器:Mac mini,Darwin x86_64 +- 仓库:`/Users/tei/dev/MapLibreParticleLab` +- 分支:`particle/main` +- 本轮起始 HEAD:`e7d109246a225eb1c1b2f177aa30e3c7fcdf658e` +- v1 实现提交:`8b9ab303228c307612c47f7f3379ad06206ea14e` +- 本轮代码修正提交:`1d1a7915e0886c46be40f4fc9a2eff13192f804b` +- 本轮代码提交信息:`fix: scope retained underlay placement fallback` +- 代码 push:成功,`e7d109246..1d1a7915e particle/main -> particle/main` +- 远端分支:`origin/particle/main` +- v2 文档 closeout commit 与最终 Final HEAD 记录在最终响应中,避免 Git commit 自引用。 + +## 3. Android 首轮失败事实 + +较早 STEP-088 APK 在 fixed camera / only Particle 场景的代表数据为: + +```text +frame=1200 build=0 reuse=0 fallback=1199 invalidation=1199 +staticDraw=0 dynamicDraw=0 particleAdvance=1199 +``` + +cache 从未 build。审查确认 retained path 无条件受全局 placement transition、`placementChanged` 和 `symbolFadeChange` 约束,导致 static prefix 不含 placement 时仍每帧 fallback。 + +## 4. 实际修改文件 + +代码提交只包含: + +- `src/mbgl/renderer/render_orchestrator.cpp` +- `src/mbgl/renderer/render_orchestrator.hpp` +- `src/mbgl/renderer/renderer_impl.cpp` +- `platform/android/MapLibreAndroidTestApp/build.gradle.kts` + +文档提交只包含: + +- `docs/50_Step记录/STEP-088_静态底图缓存PoC与Renderer观测_v2.md` +- `docs/报告/STEP-088_静态底图缓存PoC与Renderer观测_Codex完成报告_v2.md` + +未修改或提交 `AGENTS.md`、submodule、iOS dirty 文件、STEP-082/083 untracked、既有 untracked STEP-088 task/规划文档或其他用户文件。 + +## 5. Renderer placement-scoping 修正 + +- `RenderOrchestrator::retainedUnderlayUsesPlacement(boundary)` 只遍历 boundary 之前的 ordered layers,判断 retained static prefix 是否真正依赖 placement。 +- `retainedUnderlayIsStable(...)` 继续保护 light/static-layer transition;只有 static prefix 使用 placement 时才检查 `placementController.hasTransitions(...)`。 +- `Renderer::Impl::render(...)` 只有在 static prefix 使用 placement 时才要求 `placementChanged == false` 且 `symbolFadeChange == 0`。 +- fallback reason 拆分为 `static-transition` 与 `static-placement`,便于区分原因。 +- 无 boundary、empty prefix、style-not-loaded、3D、debug、legacy ordering、resource/compositor failure 等 STEP-088 fallback 未改变。 + +该修正只调整 retained static prefix 的 eligibility,没有实现 production 全量 invalidation,也没有改变动态 boundary、LayerGroup ordinal/depth、draw ordering、Host API 或 C-001。 + +## 6. Debug reason 日志 + +保留 debug-only `ParticleRetained` 周期日志中的: + +```text +reason= +``` + +它复用 `RetainedUnderlayCache::getLastInvalidationReason()`,用于 Android 验证 `first-frame`、`camera-or-boundary`、`style-not-loaded`、`static-transition` 和 `static-placement`。日志仍位于 `#ifndef NDEBUG`,不改变 Release 行为,也不增加 Host API。 + +## 7. Android Validation strip property + +MapLibreAndroidTestApp 增加: + +```text +maplibre.validation.stripNativeDebugSymbols=true +``` + +默认 Debug 构建继续 `keepDebugSymbols += "**/*.so"`。只有显式启用 Validation property 时才允许 strip native symbols,使 x86_64 Debug APK 从约 375 MB 降至约 57 MB。Debug counters 与 `NDEBUG` 语义不变。 + +## 8. RDC Mac 最终复验 + +- `cmake --build build-step088-opengl --target mbgl-test-runner -j3`:PASS / no work to do;源码/object 时间戳已确认当前 placement-scoping 修改已编入 object。 +- STEP-088 定向测试 4/4 PASS: + - `RetainedDynamicBoundary.SelectsFirstCandidate` + - `RetainedLayerGroupRange.PreservesForwardReverseOriginalOrdinals` + - `RetainedUnderlayCache.BuildReuseAndInvalidation` + - `RetainedUnderlayCache.UnsupportedAndResourceFailureFallBackSafely` +- `cmake --build build-ios --config Debug --target mbgl-core -j3`:`BUILD SUCCEEDED`。 +- `git diff --check`:PASS。 + +以上均由 RDC 执行。Codex 本次收尾未执行任何新 build/test、Gradle、ADB、Xcode 或设备操作。 + +## 9. Android Test App 环境 + +- 设备:`192.168.200.139:5555`,FZG1-2 +- Android:13 +- ABI:x86_64 +- 构建:MapLibreAndroidTestApp OpenGL Debug x86_64 +- Validation strip property:启用 +- build/install/ADB/Activity:成功 + +## 10. Android Test App 运行态结果 + +### Fixed camera / only Particle + +```text +frame=840 build=1 reuse=836 fallback=2 invalidation=3 +reason=first-frame staticDraw=2 dynamicDraw=5022 particleAdvance=839 +``` + +后续 `reuse` 持续增长,`staticDraw` 保持不变。 + +### Camera DATELINE + +`build` 从 1 增至 2,`staticDraw` 从 2 增至 4;随后 reuse 恢复持续增长,原因为 `camera-or-boundary`。符合 camera transition 后安全 invalidation/fallback、稳定后单次 rebuild/reuse。 + +### REAL WEATHER + +`REAL_WEATHER_INITIAL_WINDOW_READY` 和 `WEATHER_COLOR_FIELD_READY` 正常;GSI raster + WeatherColor + Particle 正常进入 retained path。代表数据: + +```text +frame=6960 build=3 reuse=6907 fallback=49 invalidation=52 +staticDraw=6 particleAdvance=6959 +``` + +fixed camera 后 reuse 持续增长、`staticDraw` 保持 6。`TARGET_FPS_CHANGED target=FPS_30` 成功,缓存继续 reuse。 + +### Resize / rotation + +viewport `1280x680 → 800x1160 → 1280x680`;过渡期间安全 `style-not-loaded` fallback,稳定后 rebuild/reuse。设备已恢复 `accelerometer_rotation=1`、`user_rotation=0`。 + +### STATIC / ACTIVE + +STATIC 时 RenderThread 约 0%;ACTIVE 后恢复 continuous render,retained reuse 继续增长且 `staticDraw` 不再增长。旧 Test App 设备上的 ACTIVE RenderThread 约 96%~107% 仅作 Test App 对照,不代表 NavSea 最终性能。 + +### 异常扫描 + +未发现 `FATAL EXCEPTION`、`SIGSEGV`、`SIGABRT`、ANR、`GL_INVALID`、`EGL_BAD` 或 OOM。 + +## 11. 验收结论与边界 + +Android MapLibreAndroidTestApp 已证明: + +- static prefix 不使用 placement 时,全局 placement 状态不再错误阻塞 retained cache; +- first build 后能够持续 reuse,static draw 不再随 Particle frame 增长; +- camera 和 viewport 变化会安全 invalidation/rebuild; +- GSI raster + WeatherColor + Particle、FPS 30、STATIC/ACTIVE 均可运行; +- 未发现 crash、ANR、GL/EGL 或 OOM 异常。 + +但 Test App 不能替代 NavSea 复杂真实 Style。以下仍无法验证: + +- 真实产品 layer stack 的视觉与 ordering; +- 大量 PBF/fill/line/symbol static prefix 的 `staticDraw` 行为; +- Particle OFF/ON RenderThread、main、JS CPU 收益; +- pan/zoom/resize/fallback 后是否始终无 stale underlay。 + +因此 STEP-088 overall 仍为 `ANDROID TEST APP PASS / WAITING FOR NAVSEA VALIDATION`,不是 CLOSED/PASS。 + +## 12. 范围与未完成事项 + +- 未进入 STEP-089 production invalidation。 +- 未进入 STEP-090 animation-only fast path。 +- 未修改 NavSea、React、Host API 或 C-001。 +- NavSea 复杂真实 Style 验证完成前,不得进入 STEP-089/090。 + +## 13. Git 收尾 + +- Renderer/Validation fix commit:`1d1a7915e0886c46be40f4fc9a2eff13192f804b` +- Commit message:`fix: scope retained underlay placement fallback` +- Push result:成功,`e7d109246..1d1a7915e particle/main -> particle/main` +- Remote branch:`origin/particle/main` +- v2 文档 closeout commit hash、message、push result 与最终 Final HEAD:由最终响应记录。