docs: preserve particle task history and RDC workflow rules
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
This commit is contained in:
63
AGENTS.md
63
AGENTS.md
@@ -89,3 +89,66 @@ Codex 的核心角色是“实现者”,不作为其自身修改结果的唯
|
|||||||
每一阶段必须有 `docs/50_Step记录/STEP-xxx_*.md`。完成报告固定写入 `docs/报告/STEP-xxx_<主题>_Codex完成报告_vN.md`(仅在任务要求 Codex 完成报告时)。
|
每一阶段必须有 `docs/50_Step记录/STEP-xxx_*.md`。完成报告固定写入 `docs/报告/STEP-xxx_<主题>_Codex完成报告_vN.md`(仅在任务要求 Codex 完成报告时)。
|
||||||
|
|
||||||
修改结束必须按当前构建规范验证、更新 Step、追加 `粒子开发记录.md`,并明确所有未完成/阻塞。Git 提交必须 scoped,禁止把既有无关 dirty/untracked 一并提交。
|
修改结束必须按当前构建规范验证、更新 Step、追加 `粒子开发记录.md`,并明确所有未完成/阻塞。Git 提交必须 scoped,禁止把既有无关 dirty/untracked 一并提交。
|
||||||
|
## 8. Codex 写代码,RDC 执行编译 / 测试
|
||||||
|
|
||||||
|
本项目固定采用以下闭环,除非用户在当前任务中明确另行授权:
|
||||||
|
|
||||||
|
1. **Codex 负责实现与修复。**
|
||||||
|
- 读取当前任务、设计、源码与错误信息;
|
||||||
|
- 修改代码、测试代码、构建脚本和任务要求的文档;
|
||||||
|
- 分析 RDC 返回的编译、链接、测试、codegen、打包失败;
|
||||||
|
- 根据真实错误继续修复代码。
|
||||||
|
|
||||||
|
2. **RDC / 普通 Terminal 负责实际编译与验证。**
|
||||||
|
- CMake / Ninja / Bazel 编译;
|
||||||
|
- C++ / OpenGL / Metal 定向测试;
|
||||||
|
- codegen、链接、打包、artifact 检查;
|
||||||
|
- 其他耗时构建或机械性验证。
|
||||||
|
Codex 不应自行启动、等待或轮询这些长时间命令。
|
||||||
|
|
||||||
|
3. **固定闭环:**
|
||||||
|
`Codex 写代码 → Codex 停止并给出精确验证命令 → RDC 执行 → RDC 返回结果 → 若失败,Codex 分析并修复 → RDC 再验证`。
|
||||||
|
|
||||||
|
4. **失败日志只回传必要信息。**
|
||||||
|
- RDC 保留完整 stdout/stderr;
|
||||||
|
- 成功时只返回 exit code、耗时和必要摘要;
|
||||||
|
- 失败时优先返回首个真实 error、相关 target、前后必要上下文和日志路径;
|
||||||
|
- 不把完整大型 build log 反复送入 Codex。
|
||||||
|
|
||||||
|
5. **Codex 禁止行为。**
|
||||||
|
- 未经用户明确授权,不得自行执行长时间编译、链接、codegen、打包或大型测试;
|
||||||
|
- 不得创建 background terminal 等待 build;
|
||||||
|
- 不得高频轮询构建状态;
|
||||||
|
- 不得为了等待编译而自行切换模型或启动第二个 Codex 实例;
|
||||||
|
- 不得把“编译未完成”当作理由持续占用高能力模型。
|
||||||
|
|
||||||
|
6. **RDC 发现问题后的处理。**
|
||||||
|
- RDC 可以直接处理范围明确、风险低、原因清楚的小问题,包括:
|
||||||
|
- 构建命令、CMake/Bazel 配置、链接配置、平台条件、测试条件等小型工程问题;
|
||||||
|
- 单文件或少量文件内、无需重新设计架构的小型源码修正;
|
||||||
|
- 明确的编译错误、声明/定义不一致、include/宏条件、简单 ABI/平台兼容问题;
|
||||||
|
- 不改变既定业务语义和总体架构的局部修复。
|
||||||
|
- RDC 修完后应立即重新编译/测试验证,不必为了这类小问题启动 Codex。
|
||||||
|
- 以下情况才交给 Codex:
|
||||||
|
- 大规模逻辑修改;
|
||||||
|
- 跨模块或跨层重构;
|
||||||
|
- renderer / runtime / API 设计需要重新判断;
|
||||||
|
- 需要新增较完整功能或大量代码;
|
||||||
|
- 用户明确指定“这是 Codex 代码任务”。
|
||||||
|
- 一旦 RDC 判断修复范围开始扩大、需要重新设计或无法通过少量明确修改解决,应停止继续扩改,把错误证据和现状交给 Codex。
|
||||||
|
|
||||||
|
7. **用户可见性。**
|
||||||
|
- 本项目未经用户明确授权,不得使用后台/headless Codex 执行任务;
|
||||||
|
- Codex 默认运行在用户可见的 Terminal/TUI 中;
|
||||||
|
- 当前 Mac 上如需启动或恢复 Codex,必须优先使用现有 GNU Screen 会话 `7445.codex`;
|
||||||
|
- 不得另起隐藏的 Codex 进程或新的不可见会话,除非用户明确授权;
|
||||||
|
- 用户应能够通过该 screen 会话直接看到 Codex 的输入、输出和当前状态。
|
||||||
|
|
||||||
|
8. **任务书冲突处理。**
|
||||||
|
- 若旧任务书写有“Codex 必须执行编译/测试”,但用户未在当前任务明确重新授权,则以本节为准:
|
||||||
|
Codex 只准备代码与验证命令,RDC 负责实际执行。
|
||||||
|
- 只有用户在当前任务中明确要求“由 Codex 执行某项编译/测试”时,Codex 才可执行该项。
|
||||||
|
|
||||||
|
核心原则:
|
||||||
|
|
||||||
|
> Codex 负责写和改;RDC 负责跑和验;RDC 报错,再交回 Codex 修。
|
||||||
|
|||||||
113
docs/40_任务/STEP-082_XCFramework_Bazel_Codegen阻塞收尾_Codex任务_v1.md
Normal file
113
docs/40_任务/STEP-082_XCFramework_Bazel_Codegen阻塞收尾_Codex任务_v1.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# STEP-082 XCFramework Bazel Codegen 阻塞收尾 Codex 任务 v1
|
||||||
|
|
||||||
|
## 1. 当前基线
|
||||||
|
|
||||||
|
- 项目:`/Users/tei/dev/MapLibreParticleLab`
|
||||||
|
- 分支:`particle/main`
|
||||||
|
- 起始 HEAD:`dd9687f5ed6bb9be4b58b73f2efd39f54faef7d6`
|
||||||
|
- `origin/particle/main` 应与起始 HEAD 一致。
|
||||||
|
- STEP-082 当前状态:`IMPLEMENTED / WAITING_MAC_XCFRAMEWORK_VALIDATION`。
|
||||||
|
- 本任务仍属于 STEP-082 收尾,不创建 STEP-083,不进入 RN/JS/NavSea。
|
||||||
|
|
||||||
|
开始前必须读取:
|
||||||
|
- `docs/报告/STEP-082_iOS_Native_FieldRuntime_Facade与XCFramework发行基线_Codex完成报告_v1.md`
|
||||||
|
- `docs/50_Step记录/STEP-082_iOS_Native_FieldRuntime_Facade与XCFramework发行基线_v1.md`
|
||||||
|
- `bazel/core.bzl`
|
||||||
|
- `BUILD.bazel`
|
||||||
|
- `scripts/generate-style-code.mjs`
|
||||||
|
- `CMakeLists.txt`
|
||||||
|
|
||||||
|
## 2. 已知阻塞与调查结论
|
||||||
|
|
||||||
|
当前 `bazel build //platform/ios:MapLibre.dynamic` 在 `//:generated_style_code` 阶段失败:
|
||||||
|
`src/mbgl/style/layers/particle_validation_layer.cpp` 被声明为 generator 输出,但 `scripts/generate-style-code.mjs` 不生成它。
|
||||||
|
|
||||||
|
当前只读核对显示:
|
||||||
|
- `particle_validation_layer.cpp` 是仓库中已存在的手写源文件;
|
||||||
|
- CMake 在 `CMakeLists.txt` 中把它作为普通源文件直接编译;
|
||||||
|
- `bazel/core.bzl` 目前把它放在 `MLN_GENERATED_STYLE_SOURCE`;
|
||||||
|
- style generator 只遍历 style spec 中的正式 layer type 并生成对应标准 style layer 文件。
|
||||||
|
|
||||||
|
这说明高概率是 Bazel 文件分类错误,而不是 generator 缺功能。Codex 必须先自行核对真实代码和 Git 历史后再修改。## 3. 本次唯一目标
|
||||||
|
|
||||||
|
用最小改动修复 Bazel 对 `particle_validation_layer.cpp` 的源文件分类,使:
|
||||||
|
1. 它不再作为 `generated_style_code` 的声明输出;
|
||||||
|
2. 它仍然作为 Core 普通源文件参与 Bazel 构建;
|
||||||
|
3. 不改变现有 CMake 编译行为;
|
||||||
|
4. 不改变 Particle Validation Layer、RasterParticle、WeatherColor、QBIN、Metal 或 Runtime 语义。
|
||||||
|
|
||||||
|
优先方案是:若调查确认该文件确属手写源文件,则从 `MLN_GENERATED_STYLE_SOURCE` 移出并纳入正确的普通 Core source 集合。不得为了通过构建而让 generator 复制、伪造或空生成该文件。
|
||||||
|
|
||||||
|
## 4. 必做清单
|
||||||
|
|
||||||
|
- [ ] 核对起始 branch / HEAD / remote / dirty。
|
||||||
|
- [ ] 用 Git 历史确认 `particle_validation_layer.cpp` 的来源和预期性质。
|
||||||
|
- [ ] 最小修复 Bazel source classification。
|
||||||
|
- [ ] `bazel build //:generated_style_code` 通过。
|
||||||
|
- [ ] `bazel build //platform/ios:MapLibre.dynamic` 通过。
|
||||||
|
- [ ] 验证生成的 `MapLibre.dynamic.xcframework` 中包含 public `MLNParticleFieldRuntime.h`。
|
||||||
|
- [ ] 验证 umbrella/public header 链可见 `MLNParticleFieldRuntime`。
|
||||||
|
- [ ] 验证 binary 中存在该 facade 的 Objective-C public symbol/class。
|
||||||
|
- [ ] 验证 `MLNMapView_Private.h` 没有被导出为 public header。
|
||||||
|
- [ ] 若正式 XCFramework 可压缩,则生成临时 zip,记录真实文件大小与 SHA-256;大二进制默认不提交 Git。
|
||||||
|
- [ ] 更新 `release/maplibre-particle/ios/release-manifest.json` 中可由本次真实构建确认的字段;URL 尚未发布时保持明确占位,不伪造远端地址。
|
||||||
|
- [ ] `git diff --check` PASS。
|
||||||
|
- [ ] 更新 STEP-082 Step 记录和 `粒子开发记录.md`。
|
||||||
|
- [ ] 生成 `docs/报告/STEP-082_iOS_Native_FieldRuntime_Facade与XCFramework发行基线_Codex完成报告_v2.md`。
|
||||||
|
- [ ] scoped commit、push 到 `origin/particle/main`,记录 Final HEAD。
|
||||||
|
|
||||||
|
## 5. 严格禁止
|
||||||
|
|
||||||
|
不得:
|
||||||
|
- 修改 `scripts/generate-style-code.mjs` 去伪造 particle validation 输出,除非调查证明它本应由 style spec 生成;若出现这种相反证据,先在报告中说明,不要扩大实现。
|
||||||
|
- 修改 Particle renderer、Metal shader、QBIN decoder、FieldProfile、BindingProjection、粒子 physics。
|
||||||
|
- 修改 `packages/maplibre-particle-rn/`、`integration/react-native/` 或 NavSea。
|
||||||
|
- 重做 STEP-081 真机 smoke。
|
||||||
|
- 开始 STEP-083。
|
||||||
|
- 为通过构建删除或停用 Particle Validation Layer。
|
||||||
|
- 使用 `git add -A`、`git add .`、`git reset --hard`、`git clean`。## 6. 用户已有 dirty,必须原样保护
|
||||||
|
|
||||||
|
以下路径不得修改、暂存、提交:
|
||||||
|
- `docs/doxygen/doxygen-awesome-css`
|
||||||
|
- `platform/ios/app/MBXAppDelegate.m`
|
||||||
|
- `platform/windows/vendor/vcpkg`
|
||||||
|
|
||||||
|
另外,现有未跟踪任务书:
|
||||||
|
- `docs/40_任务/STEP-082_iOS_Native_FieldRuntime_Facade与XCFramework发行基线_Codex任务_v1.md`
|
||||||
|
不得为了清理工作树而删除或改写。
|
||||||
|
|
||||||
|
本任务书自身也不要求提交;提交时只显式 stage 本次实现与正式记录文件。
|
||||||
|
|
||||||
|
## 7. 构建与验证要求
|
||||||
|
|
||||||
|
macOS 上使用仓库当前真实工具链。编译输出遵循全局 `$build-output-throttle`。
|
||||||
|
|
||||||
|
至少执行:
|
||||||
|
- `bazel build //:generated_style_code`
|
||||||
|
- `bazel build //platform/ios:MapLibre.dynamic`
|
||||||
|
|
||||||
|
若第二条成功,必须直接检查实际 XCFramework,不允许只根据 Bazel exit code 判定:
|
||||||
|
- public Headers;
|
||||||
|
- umbrella import;
|
||||||
|
- Objective-C class/symbol;
|
||||||
|
- private header 排除;
|
||||||
|
- artifact 路径、大小;
|
||||||
|
- zip SHA-256(若生成 zip)。
|
||||||
|
|
||||||
|
如果修复第一个 blocker 后暴露新的、与本次 Bazel/iOS packaging 直接相关的小型问题,可以继续最小修复并验证;如果新问题涉及 renderer/Core 语义或较大架构改动,停止并报告,不得扩大范围。
|
||||||
|
|
||||||
|
## 8. 关闭判定
|
||||||
|
|
||||||
|
只有以下全部成立,STEP-082 才可改为 `CLOSED / PASS`:
|
||||||
|
- Bazel generated style target PASS;
|
||||||
|
- `MapLibre.dynamic` XCFramework build PASS;
|
||||||
|
- `MLNParticleFieldRuntime.h` 确认存在于 public Headers;
|
||||||
|
- public ObjC facade symbol/class 确认存在;
|
||||||
|
- `MLNMapView_Private.h` 未 public export;
|
||||||
|
- artifact size 与真实 SHA-256 已记录;
|
||||||
|
- `git diff --check` PASS;
|
||||||
|
- v2 完成报告、Step 记录、粒子开发记录更新;
|
||||||
|
- scoped commit 已 push,local HEAD == `origin/particle/main`;
|
||||||
|
- 用户三处 dirty 和旧任务书保持未触碰。
|
||||||
|
|
||||||
|
若任一门槛未满足,保持 `IMPLEMENTED / WAITING_MAC_XCFRAMEWORK_VALIDATION` 或明确 BLOCKED,不得写 PASS。
|
||||||
@@ -0,0 +1,801 @@
|
|||||||
|
# STEP-082 iOS Native FieldRuntime Facade 与 XCFramework 发行基线 — Codex 任务 v1
|
||||||
|
|
||||||
|
状态:READY FOR IMPLEMENTATION
|
||||||
|
项目:MapLibreParticleLab / 粒子系统
|
||||||
|
目标分支:`particle/main`
|
||||||
|
任务基线 HEAD:`3e03949d3411c830cfff4bf320cd350f5b6a7527`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 开始前必须确认
|
||||||
|
|
||||||
|
先完整阅读本任务文件,再开始修改。
|
||||||
|
|
||||||
|
开始时只读执行并记录:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git branch --show-current
|
||||||
|
git rev-parse HEAD
|
||||||
|
git rev-parse origin/particle/main
|
||||||
|
git status --short
|
||||||
|
```
|
||||||
|
|
||||||
|
预期:
|
||||||
|
|
||||||
|
```text
|
||||||
|
branch = particle/main
|
||||||
|
HEAD = origin/particle/main = 3e03949d3411c830cfff4bf320cd350f5b6a7527
|
||||||
|
```
|
||||||
|
|
||||||
|
已知且必须保持不动的用户无关修改:
|
||||||
|
|
||||||
|
```text
|
||||||
|
docs/doxygen/doxygen-awesome-css
|
||||||
|
platform/ios/app/MBXAppDelegate.m
|
||||||
|
platform/windows/vendor/vcpkg
|
||||||
|
```
|
||||||
|
|
||||||
|
若还有新的未知 dirty:
|
||||||
|
|
||||||
|
- 不自动清理;
|
||||||
|
- 不 reset;
|
||||||
|
- 不 checkout 覆盖;
|
||||||
|
- 不纳入本任务 commit;
|
||||||
|
- 在完成报告中说明。
|
||||||
|
|
||||||
|
### 执行清单
|
||||||
|
|
||||||
|
开始实施前建立简短勾选清单,至少包含:
|
||||||
|
|
||||||
|
- [ ] iOS public Native FieldRuntime facade
|
||||||
|
- [ ] MapView-owned 生命周期
|
||||||
|
- [ ] V4 submit / binding / forecast / clear
|
||||||
|
- [ ] fail-closed / style reload 安全
|
||||||
|
- [ ] public header 无 Core 类型泄漏
|
||||||
|
- [ ] XCFramework public header / symbol 验证
|
||||||
|
- [ ] distribution-ready 元数据
|
||||||
|
- [ ] 中文设计/Step/完成报告
|
||||||
|
- [ ] git diff --check
|
||||||
|
- [ ] scoped commit / push
|
||||||
|
- [ ] 最终逐项对照
|
||||||
|
|
||||||
|
不得静默跳过;无法完成必须明确写明。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 1. 本 Step 的定位
|
||||||
|
|
||||||
|
STEP-081 已正式 `CLOSED / PASS`。
|
||||||
|
|
||||||
|
本任务禁止重新做:
|
||||||
|
|
||||||
|
- Uniform East
|
||||||
|
- Uniform North
|
||||||
|
- Vortex
|
||||||
|
- QBIN T0 / MID / T1
|
||||||
|
- Clear / Clear 后重建
|
||||||
|
- STEP081 readback
|
||||||
|
- 固定绿线
|
||||||
|
- Point fallback
|
||||||
|
- STEP-081 Metal pipeline cache 根因复验
|
||||||
|
|
||||||
|
STEP-082 是新的产品化前置层:
|
||||||
|
|
||||||
|
```text
|
||||||
|
RN / Consumer(后续 STEP-083)
|
||||||
|
↓
|
||||||
|
MapLibre iOS public ObjC API
|
||||||
|
↓
|
||||||
|
MLNParticleFieldRuntime
|
||||||
|
↓
|
||||||
|
MLNMapView private implementation seam
|
||||||
|
↓
|
||||||
|
mbgl::Style / RasterArraySource / QBIN V4
|
||||||
|
↓
|
||||||
|
WeatherColor / RasterParticle / Metal
|
||||||
|
```
|
||||||
|
|
||||||
|
本 Step 只做到 **公开 Native facade + 正式 XCFramework 导出基线**。
|
||||||
|
|
||||||
|
不做 RN TurboModule。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 2. 已确认的当前真实事实
|
||||||
|
|
||||||
|
实施前只需快速复核,不得重新做大范围架构调查。
|
||||||
|
|
||||||
|
## 2.1 当前 RN package 是 Android-only Native
|
||||||
|
|
||||||
|
当前:
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/maplibre-particle-rn/package.json
|
||||||
|
version = 13.4.1-particle.5
|
||||||
|
```
|
||||||
|
|
||||||
|
`files` 没有 `ios`。
|
||||||
|
|
||||||
|
`react-native.config.js` 仅有 Android。
|
||||||
|
|
||||||
|
这是 STEP-083 的工作,不在本 Step 修改。
|
||||||
|
|
||||||
|
## 2.2 STEP-081 private seam 不能作为正式 SDK API
|
||||||
|
|
||||||
|
当前:
|
||||||
|
|
||||||
|
```text
|
||||||
|
platform/ios/src/MLNMapView_Private.h
|
||||||
|
```
|
||||||
|
|
||||||
|
暴露:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
- (mbgl::Map &)mbglMap;
|
||||||
|
```
|
||||||
|
|
||||||
|
但该 header 属于:
|
||||||
|
|
||||||
|
```text
|
||||||
|
MLN_IOS_PRIVATE_HEADERS
|
||||||
|
```
|
||||||
|
|
||||||
|
不在 `MapLibre.dynamic.xcframework` 正式 public headers 中。
|
||||||
|
|
||||||
|
因此本任务必须新增一个正式 public facade,而不是把 `MLNMapView_Private.h` 暴露出去。
|
||||||
|
|
||||||
|
## 2.3 Particle/Weather 类型继续保持 Core-only
|
||||||
|
|
||||||
|
当前 Darwin LayerManager 已注册:
|
||||||
|
|
||||||
|
```text
|
||||||
|
RasterParticleLayerFactory
|
||||||
|
WeatherColorLayerFactory
|
||||||
|
```
|
||||||
|
|
||||||
|
为 Core-only layer。
|
||||||
|
|
||||||
|
不要新建:
|
||||||
|
|
||||||
|
```text
|
||||||
|
MLNRasterParticleLayer
|
||||||
|
MLNWeatherColorLayer
|
||||||
|
MLNRasterArraySource
|
||||||
|
```
|
||||||
|
|
||||||
|
RN / Host 仍通过 Style JSON 创建:
|
||||||
|
|
||||||
|
```text
|
||||||
|
raster-array
|
||||||
|
weather-color
|
||||||
|
raster-particle
|
||||||
|
```
|
||||||
|
|
||||||
|
Native facade 只负责找到这些对象并提交/控制数据。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 3. 目标架构
|
||||||
|
|
||||||
|
## 3.1 新增公开 iOS Runtime facade
|
||||||
|
|
||||||
|
推荐类型:
|
||||||
|
|
||||||
|
```text
|
||||||
|
MLNParticleFieldRuntime
|
||||||
|
MLNParticleFieldRuntimeConfiguration
|
||||||
|
MLNMapView+ParticleFieldRuntime
|
||||||
|
```
|
||||||
|
|
||||||
|
如果现有 ObjC 命名规范要求轻微调整,可以调整文件名,但必须在设计文档说明。
|
||||||
|
|
||||||
|
禁止使用:
|
||||||
|
|
||||||
|
```text
|
||||||
|
STEP081*
|
||||||
|
Smoke*
|
||||||
|
Fixture*
|
||||||
|
NavSea*
|
||||||
|
```
|
||||||
|
|
||||||
|
作为公开 Native 类型名。
|
||||||
|
|
||||||
|
## 3.2 Public API 绝不能暴露 Core 类型
|
||||||
|
|
||||||
|
公开 header 只能依赖:
|
||||||
|
|
||||||
|
- Foundation
|
||||||
|
- MapLibre public Objective-C 类型
|
||||||
|
|
||||||
|
禁止出现在 public header:
|
||||||
|
|
||||||
|
```text
|
||||||
|
mbgl::Map
|
||||||
|
mbgl::Style
|
||||||
|
mbgl::style::RasterArraySource
|
||||||
|
std::vector
|
||||||
|
std::unique_ptr
|
||||||
|
void * core handle
|
||||||
|
raw Core pointer
|
||||||
|
MLNMapView_Private.h
|
||||||
|
```
|
||||||
|
|
||||||
|
QBIN payload 使用:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
NSData *
|
||||||
|
```
|
||||||
|
|
||||||
|
而不是文件 URL。
|
||||||
|
|
||||||
|
“本地文件读取”属于后续 RN bridge 边界,不进入 Native SDK facade。
|
||||||
|
|
||||||
|
## 3.3 MapView-owned 生命周期
|
||||||
|
|
||||||
|
目标语义与 Android map-owned `WeatherRuntime` 一致:
|
||||||
|
|
||||||
|
```text
|
||||||
|
MLNMapView
|
||||||
|
owns
|
||||||
|
MLNParticleFieldRuntime
|
||||||
|
```
|
||||||
|
|
||||||
|
必须提供等价的:
|
||||||
|
|
||||||
|
- replace/create
|
||||||
|
- current runtime
|
||||||
|
- dispose
|
||||||
|
|
||||||
|
行为。
|
||||||
|
|
||||||
|
建议:
|
||||||
|
|
||||||
|
```objc
|
||||||
|
- replaceParticleFieldRuntimeWithConfiguration:
|
||||||
|
- particleFieldRuntime
|
||||||
|
- disposeParticleFieldRuntime
|
||||||
|
```
|
||||||
|
|
||||||
|
可使用 category + associated object,或符合当前 iOS SDK 结构的等价方式。
|
||||||
|
|
||||||
|
要求:
|
||||||
|
|
||||||
|
1. `MLNParticleFieldRuntime` 不得强引用 MapView 形成循环;
|
||||||
|
2. MapView 释放后 runtime 不得访问悬空 Core;
|
||||||
|
3. replace 必须先 dispose 旧 runtime;
|
||||||
|
4. dispose 幂等;
|
||||||
|
5. runtime 不保存 `RasterArraySource *` 等跨 style 生命周期 Core pointer;
|
||||||
|
6. 每次命令通过当前 MapView/current style 重新查找目标 source/layer。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 4. Configuration
|
||||||
|
|
||||||
|
Configuration 至少包含:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sourceId
|
||||||
|
weatherColorLayerId
|
||||||
|
particleLayerId
|
||||||
|
```
|
||||||
|
|
||||||
|
要求:
|
||||||
|
|
||||||
|
- 初始化时字符串非空;
|
||||||
|
- Runtime 不硬编码 RN package ID;
|
||||||
|
- RN package 后续仍可使用当前固定值:
|
||||||
|
- `rn-weather-fields`
|
||||||
|
- `rn-weather-color`
|
||||||
|
- `rn-weather-particles`
|
||||||
|
- Native SDK 保持 Host-neutral。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 5. attach / replace 时的对象验证
|
||||||
|
|
||||||
|
创建 runtime 时必须检查当前 style 中:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sourceId -> RasterArraySource
|
||||||
|
weatherColorLayerId -> WeatherColor layer
|
||||||
|
particleLayerId -> RasterParticle layer
|
||||||
|
```
|
||||||
|
|
||||||
|
验证必须基于 Core 真实类型,而不是只检查字符串 ID。
|
||||||
|
|
||||||
|
失败时:
|
||||||
|
|
||||||
|
- 不创建“半可用” runtime;
|
||||||
|
- 返回明确错误;
|
||||||
|
- 不创建第二套 source/layer;
|
||||||
|
- 不偷偷替换 style;
|
||||||
|
- 不吞掉错误后返回成功。
|
||||||
|
|
||||||
|
Style 尚未 ready 时也必须明确失败。
|
||||||
|
|
||||||
|
后续 Host 会在 style ready 后重试/attach。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 6. STEP-082 必须实现的 QBIN V4 API
|
||||||
|
|
||||||
|
本 Step 只冻结新的 V4 产品主链。
|
||||||
|
|
||||||
|
至少实现:
|
||||||
|
|
||||||
|
```text
|
||||||
|
submitEncodedField
|
||||||
|
setEncodedColorBinding
|
||||||
|
setEncodedParticleBinding
|
||||||
|
setEncodedForecastTime
|
||||||
|
setEncodedForecastPlaybackState
|
||||||
|
setEncodedForecastPlaybackSpeed
|
||||||
|
clearEncodedField
|
||||||
|
clearAllEncodedFields
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6.1 submitEncodedField
|
||||||
|
|
||||||
|
输入语义与当前 Android/Core 保持一致:
|
||||||
|
|
||||||
|
```text
|
||||||
|
fieldKey
|
||||||
|
fieldID
|
||||||
|
generation
|
||||||
|
dataVersion
|
||||||
|
contractJson
|
||||||
|
NSData * qbin
|
||||||
|
```
|
||||||
|
|
||||||
|
必须继续复用现有:
|
||||||
|
|
||||||
|
```text
|
||||||
|
parseResolvedFieldProfileContractJson(...)
|
||||||
|
RasterArraySource::submitEncodedField(...)
|
||||||
|
```
|
||||||
|
|
||||||
|
禁止在 ObjC facade 中重新实现 QBIN decoder。
|
||||||
|
|
||||||
|
必须继续遵守:
|
||||||
|
|
||||||
|
- `generation > 0`
|
||||||
|
- `dataVersion >= 0`
|
||||||
|
- ID UTF-8 边界与当前 V4 contract 一致
|
||||||
|
- contract JSON 有明确大小上限
|
||||||
|
- QBIN transport 有明确上限
|
||||||
|
- 空 payload 拒绝
|
||||||
|
- invalid contract fail-closed
|
||||||
|
|
||||||
|
建议继续保持当前 64 MiB payload 上限与 256 KiB contract 上限;若 Core 当前权威 guard 已定义同一值,应优先复用,不复制新的魔法数字。
|
||||||
|
|
||||||
|
## 6.2 结果映射
|
||||||
|
|
||||||
|
必须提供稳定 ObjC enum / typed result,能够无损表达当前 Core:
|
||||||
|
|
||||||
|
```text
|
||||||
|
ACCEPTED_INSERTED
|
||||||
|
ACCEPTED_REPLACED_REVISION
|
||||||
|
DUPLICATE
|
||||||
|
REJECTED_DECODE
|
||||||
|
REJECTED_CONTRACT
|
||||||
|
REJECTED_INVALID_FIELD_KEY
|
||||||
|
REJECTED_IDENTITY_CONFLICT
|
||||||
|
REJECTED_STALE_REVISION
|
||||||
|
REJECTED_INCOMPATIBLE
|
||||||
|
REJECTED_CAPACITY
|
||||||
|
```
|
||||||
|
|
||||||
|
“source missing / runtime disposed / style not ready”属于 facade/lifecycle 错误,不得伪装成某个 Core submit result。
|
||||||
|
|
||||||
|
## 6.3 Binding
|
||||||
|
|
||||||
|
Color Binding 必须保持:
|
||||||
|
|
||||||
|
```text
|
||||||
|
fieldKey
|
||||||
|
semanticID
|
||||||
|
groupID
|
||||||
|
expectedValueClass
|
||||||
|
expectedUnitID
|
||||||
|
```
|
||||||
|
|
||||||
|
支持:
|
||||||
|
|
||||||
|
```text
|
||||||
|
SCALAR
|
||||||
|
VELOCITY_COMPONENT
|
||||||
|
DIRECTION_ANGLE
|
||||||
|
```
|
||||||
|
|
||||||
|
Particle Binding 必须保持:
|
||||||
|
|
||||||
|
```text
|
||||||
|
VECTOR_COMPONENTS
|
||||||
|
DIRECTION_ANGLE
|
||||||
|
```
|
||||||
|
|
||||||
|
inactive selector 仍必须严格为:
|
||||||
|
|
||||||
|
```text
|
||||||
|
semanticID = 0
|
||||||
|
groupID = 0
|
||||||
|
```
|
||||||
|
|
||||||
|
不得按“是否为空”猜模式。
|
||||||
|
|
||||||
|
## 6.4 Forecast
|
||||||
|
|
||||||
|
保留 Core-owned:
|
||||||
|
|
||||||
|
```text
|
||||||
|
requested forecast time
|
||||||
|
play / pause
|
||||||
|
playback speed
|
||||||
|
T0 / T1 / mix
|
||||||
|
boundary reuse
|
||||||
|
```
|
||||||
|
|
||||||
|
ObjC runtime 只转发命令。
|
||||||
|
|
||||||
|
禁止复制 Forecast Clock。
|
||||||
|
|
||||||
|
## 6.5 Clear
|
||||||
|
|
||||||
|
实现:
|
||||||
|
|
||||||
|
```text
|
||||||
|
clearEncodedField(fieldKey)
|
||||||
|
clearAllEncodedFields()
|
||||||
|
```
|
||||||
|
|
||||||
|
Clear 后必须触发必要 rerender / resource release 路径,但不得增加 STEP081 临时 readback。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 7. Renderer / Style 边界
|
||||||
|
|
||||||
|
本任务不得改变:
|
||||||
|
|
||||||
|
- QBIN V2 格式
|
||||||
|
- FieldProfile contract
|
||||||
|
- BindingProjection
|
||||||
|
- V4 materialization
|
||||||
|
- T0/T1 interpolation
|
||||||
|
- Metal particle physics
|
||||||
|
- 1 px current-endpoint Metal coverage
|
||||||
|
- WeatherColor/RasterParticle shader 语义
|
||||||
|
|
||||||
|
如果 facade 接入暴露出 Core 缺陷:
|
||||||
|
|
||||||
|
- 先停止扩大修改;
|
||||||
|
- 在完成报告中列出 blocker;
|
||||||
|
- 不以“顺便重构 renderer”解决。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 8. Public Header / XCFramework 接线
|
||||||
|
|
||||||
|
必须把新 public API 正式加入 iOS framework 导出链。
|
||||||
|
|
||||||
|
至少检查并按真实结构更新:
|
||||||
|
|
||||||
|
```text
|
||||||
|
platform/ios/bazel/files.bzl
|
||||||
|
platform/ios/src/Mapbox.h
|
||||||
|
platform/ios/BUILD.bazel
|
||||||
|
```
|
||||||
|
|
||||||
|
若实现文件属于现有 source list 自动包含机制,按真实情况处理,不得重复注册。
|
||||||
|
|
||||||
|
最终产出的:
|
||||||
|
|
||||||
|
```text
|
||||||
|
MapLibre.dynamic.xcframework
|
||||||
|
```
|
||||||
|
|
||||||
|
必须包含新 public header。
|
||||||
|
|
||||||
|
同时确认:
|
||||||
|
|
||||||
|
- `MLNMapView_Private.h` 仍然不是 public header;
|
||||||
|
- 没有把任何 Core header 整包暴露给 Consumer;
|
||||||
|
- 新 public header 可以单独被 Objective-C Consumer import;
|
||||||
|
- public symbol 存在于 framework binary。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 9. Distribution-ready 基线
|
||||||
|
|
||||||
|
当前 MLRN 11.3.6 iOS 通过 SwiftPM distribution 消费 MapLibre Native。
|
||||||
|
|
||||||
|
本 Step **不创建远端 Git 仓库,不擅自打 release tag,不发布公网 Swift Package**。
|
||||||
|
|
||||||
|
但必须在仓库中建立一个最小、可审计的 iOS Particle binary distribution 说明/模板,建议放在:
|
||||||
|
|
||||||
|
```text
|
||||||
|
release/maplibre-particle/ios/
|
||||||
|
```
|
||||||
|
|
||||||
|
至少包含:
|
||||||
|
|
||||||
|
```text
|
||||||
|
README.md
|
||||||
|
Package.swift.template
|
||||||
|
release-manifest.json
|
||||||
|
```
|
||||||
|
|
||||||
|
或与现有 release 目录规范等价的结构。
|
||||||
|
|
||||||
|
`Package.swift.template` 的目标是后续独立 distribution repo 可以直接使用:
|
||||||
|
|
||||||
|
```text
|
||||||
|
binaryTarget(name: "MapLibre", url: "...MapLibre.dynamic.xcframework.zip", checksum: "...")
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
- product/module 名必须保持 `MapLibre`,以满足 MLRN import;
|
||||||
|
- 不允许再生成第二个不同 module 名并要求 MLRN 同时链接两份 MapLibre;
|
||||||
|
- URL 可以先用明确占位符;
|
||||||
|
- checksum 必须在真实 zip 生成后记录真实值;
|
||||||
|
- 若当前 Step 尚不能生成正式 zip,则 manifest 明确标记 `NOT_BUILT`,禁止伪造 hash。
|
||||||
|
|
||||||
|
建议 external distribution version 独立采用语义版本,例如:
|
||||||
|
|
||||||
|
```text
|
||||||
|
6.28.0-particle.1
|
||||||
|
```
|
||||||
|
|
||||||
|
但不要直接修改 `platform/ios/VERSION=6.28.0`,除非通过构建系统审查确认不会破坏 upstream-compatible framework version。
|
||||||
|
|
||||||
|
本 Step 的核心是建立“MapLibre module 不变 + 自定义 binary distribution version 独立管理”的边界。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 10. MLRN 11.3.6 后续兼容性记录
|
||||||
|
|
||||||
|
STEP-082 不写 RN module,但设计文档必须记录下一 Step 已确认的 iOS 视图链:
|
||||||
|
|
||||||
|
```text
|
||||||
|
reactTag
|
||||||
|
-> React View Registry
|
||||||
|
-> Fabric ComponentView
|
||||||
|
-> contentView
|
||||||
|
-> MLNMapView
|
||||||
|
-> public MLNParticleFieldRuntime
|
||||||
|
```
|
||||||
|
|
||||||
|
同时记录:
|
||||||
|
|
||||||
|
- MLRN 11.3.6 是当前 peer dependency;
|
||||||
|
- 后续 STEP-083 不建立第二套 Map registry;
|
||||||
|
- 不依赖 MLRN private ObjC header 作为长期 API;
|
||||||
|
- 后续通过 `$MLRN_SPM_SPEC` 让 MLRN 与 Particle Bridge 使用同一份自定义 `MapLibre` binary。
|
||||||
|
|
||||||
|
不要在本 Step 修改:
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/maplibre-particle-rn/
|
||||||
|
integration/react-native/
|
||||||
|
NavSea
|
||||||
|
```
|
||||||
|
|
||||||
|
除非仅为文档引用且任务确实需要;默认都不改。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 11. 测试与验证
|
||||||
|
|
||||||
|
## 11.1 必做静态检查
|
||||||
|
|
||||||
|
必须执行:
|
||||||
|
|
||||||
|
```text
|
||||||
|
git diff --check
|
||||||
|
```
|
||||||
|
|
||||||
|
并检查:
|
||||||
|
|
||||||
|
1. public header 没有 `mbgl::`;
|
||||||
|
2. public header 没有 STL 类型;
|
||||||
|
3. `MLNMapView_Private.h` 未进入 public header list;
|
||||||
|
4. Core-only layer/source wrapper 没有被新增;
|
||||||
|
5. Android/RN 文件没有变化;
|
||||||
|
6. STEP-081 临时诊断代码没有恢复。
|
||||||
|
|
||||||
|
## 11.2 Objective-C / Objective-C++ 编译
|
||||||
|
|
||||||
|
如果执行环境是 macOS:
|
||||||
|
|
||||||
|
- 使用当前仓库真实 iOS build 工具链;
|
||||||
|
- 编译输出遵循全局 `$build-output-throttle`;
|
||||||
|
- 构建包含新 facade 的 iPhoneOS arm64 或正式 XCFramework target;
|
||||||
|
- 不需要重新做 STEP-081 真机视觉 smoke。
|
||||||
|
|
||||||
|
如果执行环境不是 macOS:
|
||||||
|
|
||||||
|
- 不得伪造 iOS build PASS;
|
||||||
|
- 完成源码/构建图静态接线;
|
||||||
|
- 完成报告标记 `WAITING_MAC_XCFRAMEWORK_VALIDATION`。
|
||||||
|
|
||||||
|
## 11.3 XCFramework 验证
|
||||||
|
|
||||||
|
如果成功生成 XCFramework,必须验证:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Headers 中存在新 public header
|
||||||
|
Mapbox.h 可导入该 API
|
||||||
|
framework binary 中存在对应 public ObjC symbol
|
||||||
|
MLNMapView_Private.h 不在导出 Headers
|
||||||
|
```
|
||||||
|
|
||||||
|
并记录 zip:
|
||||||
|
|
||||||
|
```text
|
||||||
|
文件名
|
||||||
|
size
|
||||||
|
SHA-256
|
||||||
|
```
|
||||||
|
|
||||||
|
可将临时大产物保留在 build/release 临时目录,但是否提交大二进制必须遵守仓库现有规则;默认不要把 XCFramework zip 直接提交进 Git。
|
||||||
|
|
||||||
|
## 11.4 本 Step 不做
|
||||||
|
|
||||||
|
禁止:
|
||||||
|
|
||||||
|
- Android Gradle
|
||||||
|
- APK
|
||||||
|
- ADB
|
||||||
|
- Android 设备
|
||||||
|
- STEP-081 iPad 视觉复测
|
||||||
|
- RN iOS build
|
||||||
|
- NavSea build
|
||||||
|
- provider/network 测试
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 12. 文档输出
|
||||||
|
|
||||||
|
所有文档使用中文。
|
||||||
|
|
||||||
|
必须新增/更新:
|
||||||
|
|
||||||
|
```text
|
||||||
|
docs/30_设计/STEP-082_iOS_Native_FieldRuntime_Facade与XCFramework发行设计_v1.md
|
||||||
|
docs/50_Step记录/STEP-082_iOS_Native_FieldRuntime_Facade与XCFramework发行基线_v1.md
|
||||||
|
粒子开发记录.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Codex 完成报告必须固定生成到:
|
||||||
|
|
||||||
|
```text
|
||||||
|
docs/报告/STEP-082_iOS_Native_FieldRuntime_Facade与XCFramework发行基线_Codex完成报告_v1.md
|
||||||
|
```
|
||||||
|
|
||||||
|
若同名报告已存在,递增 v2/v3,不覆盖旧报告。
|
||||||
|
|
||||||
|
完成报告至少写明:
|
||||||
|
|
||||||
|
- 起始 HEAD
|
||||||
|
- 结束 HEAD
|
||||||
|
- 修改文件
|
||||||
|
- 新 public API
|
||||||
|
- 生命周期模型
|
||||||
|
- V4 API 覆盖
|
||||||
|
- public/private header 检查
|
||||||
|
- XCFramework build 结果
|
||||||
|
- artifact/hash(若有)
|
||||||
|
- 未完成/阻塞
|
||||||
|
- Git commit hash
|
||||||
|
- commit message
|
||||||
|
- push result
|
||||||
|
- remote branch
|
||||||
|
- Final HEAD
|
||||||
|
- 无关 dirty 未触碰确认
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 13. Git 边界
|
||||||
|
|
||||||
|
只提交本 STEP 相关修改。
|
||||||
|
|
||||||
|
禁止:
|
||||||
|
|
||||||
|
```text
|
||||||
|
git add -A
|
||||||
|
git add .
|
||||||
|
git reset --hard
|
||||||
|
git checkout -- <用户无关文件>
|
||||||
|
git clean
|
||||||
|
```
|
||||||
|
|
||||||
|
必须显式按文件/目录暂存。
|
||||||
|
|
||||||
|
提交前再次检查:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git status --short
|
||||||
|
git diff --check
|
||||||
|
git diff --cached --stat
|
||||||
|
git diff --cached
|
||||||
|
```
|
||||||
|
|
||||||
|
建议实现提交 message:
|
||||||
|
|
||||||
|
```text
|
||||||
|
feat: add ios particle field runtime facade
|
||||||
|
```
|
||||||
|
|
||||||
|
若文档收尾需要第二个 scoped commit,可使用:
|
||||||
|
|
||||||
|
```text
|
||||||
|
docs: record STEP-082 ios runtime distribution baseline
|
||||||
|
```
|
||||||
|
|
||||||
|
提交后:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git push origin particle/main
|
||||||
|
```
|
||||||
|
|
||||||
|
若 push 失败,不得宣称成功。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 14. STEP-082 关闭门槛
|
||||||
|
|
||||||
|
只有同时满足以下条件,才可判定本 Step `CLOSED / PASS`:
|
||||||
|
|
||||||
|
- [ ] public iOS FieldRuntime facade 已实现;
|
||||||
|
- [ ] MapView-owned lifecycle 已实现;
|
||||||
|
- [ ] V4 submit/binding/forecast/clear 已接通现有 Core;
|
||||||
|
- [ ] public API 无 Core/STL 类型泄漏;
|
||||||
|
- [ ] style reload / source missing fail-closed;
|
||||||
|
- [ ] `MLNMapView_Private.h` 仍为 private;
|
||||||
|
- [ ] XCFramework public header 接线完成;
|
||||||
|
- [ ] macOS 环境下 XCFramework/arm64 compile 已通过;
|
||||||
|
- [ ] 若产出 zip,SHA-256 已记录;
|
||||||
|
- [ ] distribution-ready 模板/manifest 已建立;
|
||||||
|
- [ ] 没有修改 RN/Android/NavSea;
|
||||||
|
- [ ] 没有重新验证 STEP-081;
|
||||||
|
- [ ] 3 处用户无关 dirty 未触碰;
|
||||||
|
- [ ] `git diff --check` PASS;
|
||||||
|
- [ ] 中文 Step 记录与完成报告已更新;
|
||||||
|
- [ ] scoped commit 已完成;
|
||||||
|
- [ ] push `origin/particle/main` 成功;
|
||||||
|
- [ ] Final HEAD 已记录。
|
||||||
|
|
||||||
|
如果 macOS/XCFramework 构建条件不可用:
|
||||||
|
|
||||||
|
```text
|
||||||
|
IMPLEMENTED / WAITING_MAC_XCFRAMEWORK_VALIDATION
|
||||||
|
```
|
||||||
|
|
||||||
|
不得写 `CLOSED / PASS`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# 15. 下一 Step 边界
|
||||||
|
|
||||||
|
STEP-082 通过后,下一任务才是:
|
||||||
|
|
||||||
|
```text
|
||||||
|
STEP-083
|
||||||
|
iOS RN TurboModule + Fabric reactTag/MLNMapView Bridge + Custom MapLibre SwiftPM Consumer
|
||||||
|
```
|
||||||
|
|
||||||
|
STEP-083 预计负责:
|
||||||
|
|
||||||
|
```text
|
||||||
|
packages/maplibre-particle-rn/ios
|
||||||
|
Podspec / codegen
|
||||||
|
React View Registry
|
||||||
|
contentView -> MLNMapView
|
||||||
|
本地 QBIN file:// -> NSData
|
||||||
|
调用 STEP-082 public facade
|
||||||
|
$MLRN_SPM_SPEC 指向自定义 MapLibre binary distribution
|
||||||
|
RN Test Host iOS
|
||||||
|
V4 T0 / MID / T1 / Clear
|
||||||
|
```
|
||||||
|
|
||||||
|
本 STEP 不提前进入该范围。
|
||||||
@@ -0,0 +1,609 @@
|
|||||||
|
# STEP-083 iOS RN 统一 FieldRuntime / TurboModule / Fabric 与 XCFramework 消费 Codex 任务 v1
|
||||||
|
|
||||||
|
## 0. 任务定位
|
||||||
|
|
||||||
|
本任务是 STEP-082 之后的一个完整实现批次,不再拆成多个很小的 Step。
|
||||||
|
|
||||||
|
目标是让当前已经在 Android 使用的同一套 React Native / JS FieldRuntime 公共 API,在 iOS 上获得真实 native 实现,并通过 React Native Fabric 的 reactTag 找到当前 MLRN MapView,最终调用 STEP-082 已冻结并验证的 iOS Native FieldRuntime / MapLibre Core。
|
||||||
|
|
||||||
|
完成后应形成:
|
||||||
|
|
||||||
|
JS/TS FieldRuntime
|
||||||
|
→ 同一 NativeWeatherRuntimeBridge TurboModule ABI
|
||||||
|
→ iOS ObjC++ TurboModule
|
||||||
|
→ 当前 Fabric / MLRN MapView
|
||||||
|
→ public MLNMapView / MLNParticleFieldRuntime
|
||||||
|
→ Shared Core / Renderer / Metal
|
||||||
|
|
||||||
|
不得建立 iOS 第二套 JS API、第二套 Map registry、第二套 QBIN/Field contract。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 正式跨项目依据
|
||||||
|
|
||||||
|
开始前必须以以下正式约束为准,不以聊天记忆替代:
|
||||||
|
|
||||||
|
- Integration repo HEAD:`39ad8415fbdb76c1822460bb09f3a3f35fe141e0`
|
||||||
|
- Contract:`C-001`
|
||||||
|
- `contracts/PARTICLE_NAVSEA_BOUNDARY.md`
|
||||||
|
- `rfc/RFC-001_RN公共API与接入基线.md`
|
||||||
|
- `coordination/TEAM_MODEL.md`
|
||||||
|
- `WORKFLOW.md`
|
||||||
|
|
||||||
|
RFC-001 已接受的关键事实:
|
||||||
|
|
||||||
|
1. 当前公共 RN 包为 `@navsea/maplibre-particle-rn@13.4.1-particle.5`。
|
||||||
|
2. Map / Camera 继续由 `@maplibre/maplibre-react-native@11.3.6` 提供,Particle 包不得转导出或复制 MapView。
|
||||||
|
3. Particle 是纯 Field Renderer 控制面,不负责 provider、HTTP、缓存、Route/ETA 或 NavSea 业务。
|
||||||
|
4. Android 当前已有 RN bridge + Native + QBIN V4;iOS RN 在本任务前未实现。
|
||||||
|
5. Android / iOS 必须共享同一 Shared Core 与同一公共 RN 语义;不得平台分叉。
|
||||||
|
|
||||||
|
Integration 的 `PARTICLE_IOS_STATUS.md` / compatibility 在本任务创建时仍保留 STEP-082 验证前的旧状态,但 Particle 仓库实际 STEP-082 已于当前 HEAD 正式 CLOSED / PASS。不得因为 Integration 状态文件滞后而重新打开 STEP-082。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 起始 Git 基线
|
||||||
|
|
||||||
|
仓库:
|
||||||
|
|
||||||
|
`/Users/tei/dev/MapLibreParticleLab`
|
||||||
|
|
||||||
|
分支:
|
||||||
|
|
||||||
|
`particle/main`
|
||||||
|
|
||||||
|
起始 HEAD / origin:
|
||||||
|
|
||||||
|
`44af5e68b8569d90c26e37c2a5ae5493a5b485eb`
|
||||||
|
|
||||||
|
STEP-082 关键提交:
|
||||||
|
|
||||||
|
- implementation blocker close:
|
||||||
|
`136ed726cf749c24b3673c046581a38ef48be390`
|
||||||
|
- STEP-082 final closeout:
|
||||||
|
`44af5e68b8569d90c26e37c2a5ae5493a5b485eb`
|
||||||
|
|
||||||
|
STEP-082 已验证发行产物:
|
||||||
|
|
||||||
|
- `bazel-bin/platform/ios/MapLibre.dynamic.xcframework.zip`
|
||||||
|
- distributionVersion:`6.28.0-particle.1`
|
||||||
|
- module:`MapLibre`
|
||||||
|
- size:`24639200` bytes
|
||||||
|
- SHA-256:
|
||||||
|
`64faa174c5c0dc0a2da3e289f0beaf2dedf7298665e3345f39836729b668e239`
|
||||||
|
- device:arm64
|
||||||
|
- simulator:arm64 + x86_64
|
||||||
|
- public `MLNParticleFieldRuntime.h`:两个 slice 均存在
|
||||||
|
- `Mapbox.h`:两个 slice 均导入该 header
|
||||||
|
- `MLNMapView_Private.h`:public export count = 0
|
||||||
|
- ObjC class symbols:device/simulator 均存在
|
||||||
|
|
||||||
|
必须先阅读:
|
||||||
|
|
||||||
|
- `docs/50_Step记录/STEP-082_iOS_Native_FieldRuntime_Facade与XCFramework发行基线_v1.md`
|
||||||
|
- `docs/报告/STEP-082_iOS_Native_FieldRuntime_Facade与XCFramework发行基线_Codex完成报告_v2.md`
|
||||||
|
- `release/maplibre-particle/ios/release-manifest.json`
|
||||||
|
- `platform/ios/src/MLNParticleFieldRuntime.h`
|
||||||
|
- `platform/ios/src/MLNParticleFieldRuntime.mm`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 当前 RN 公共 API 是冻结基线
|
||||||
|
|
||||||
|
以下文件是本任务必须兼容的公共面:
|
||||||
|
|
||||||
|
- `packages/maplibre-particle-rn/src/NativeWeatherRuntimeBridge.ts`
|
||||||
|
- `packages/maplibre-particle-rn/src/FieldRuntime.ts`
|
||||||
|
- `packages/maplibre-particle-rn/src/types.ts`
|
||||||
|
- `packages/maplibre-particle-rn/src/EncodedFieldGuards.ts`
|
||||||
|
|
||||||
|
当前 Android reference implementation:
|
||||||
|
|
||||||
|
- `packages/maplibre-particle-rn/android/src/main/java/org/navsea/maplibre/particle/weather/WeatherRuntimeBridgeModule.kt`
|
||||||
|
- `WeatherRuntimeBridgePackage.kt`
|
||||||
|
- 当前 JNI / WeatherRuntime Android 实现与 guard/error 语义
|
||||||
|
|
||||||
|
### 3.1 硬性一致性要求
|
||||||
|
|
||||||
|
本任务原则上不得改变:
|
||||||
|
|
||||||
|
- TurboModule 名称:`WeatherRuntimeBridge`
|
||||||
|
- `NativeWeatherRuntimeBridge.ts` 方法名
|
||||||
|
- 参数顺序与 primitive ABI
|
||||||
|
- TypeScript public `FieldRuntime` 方法名
|
||||||
|
- `types.ts` public union / enum 字符串
|
||||||
|
- V4 submit result 字符串
|
||||||
|
- V3 submit result 字符串
|
||||||
|
- `CommandResult = ACCEPTED | REJECTED`
|
||||||
|
- JS 层 encoded guard 语义
|
||||||
|
- V4 contract JSON field names
|
||||||
|
- inactive selector `(0,0)` ABI
|
||||||
|
- `reactTag` 作为 MapView 入口的调用方式
|
||||||
|
|
||||||
|
不得让 NavSea / Test Host 写:
|
||||||
|
|
||||||
|
`Platform.OS === "ios" ? iOS专用API : AndroidAPI`
|
||||||
|
|
||||||
|
也不得新增第二套 iOS JS module。
|
||||||
|
|
||||||
|
### 3.2 JS 文案允许修正
|
||||||
|
|
||||||
|
`FieldRuntime.ts` 当前 `nativeBridge()` 的错误文本仍写死 “requires the Android WeatherRuntimeBridge native module”。
|
||||||
|
|
||||||
|
iOS 模块完成后必须改成平台中性的错误文本,但不得改变 API 类型或成功路径。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 第一阶段:真实代码调查,禁止凭猜测实现
|
||||||
|
|
||||||
|
在写 iOS bridge 前必须完成一次短而完整的只读调查,并在 v1 完成报告中记录结果。
|
||||||
|
|
||||||
|
### 4.1 调查当前 MLRN 11.3.6
|
||||||
|
|
||||||
|
必须取得并检查 `@maplibre/maplibre-react-native@11.3.6` 的真实 iOS source / podspec / codegen 配置。
|
||||||
|
|
||||||
|
可通过当前 Test Host 安装依赖、npm pack 或其他不会改变产品版本锁的方式取得源码。
|
||||||
|
|
||||||
|
必须确认:
|
||||||
|
|
||||||
|
1. Fabric 下 MapView ComponentView 的实际 ObjC/ObjC++ 类名。
|
||||||
|
2. `reactTag` 在 RN 0.85.2 / Fabric 中如何从当前 surface/UIManager 安全 resolve ComponentView。
|
||||||
|
3. MLRN ComponentView 内实际持有/暴露的 content view 类型。
|
||||||
|
4. 如何从该 content view 获得真正的 public `MLNMapView`。
|
||||||
|
5. 哪些接口是 MLRN public/稳定 seam,哪些是私有实现。
|
||||||
|
6. MLRN 11.3.6 的 MapLibre iOS binary dependency 方式。
|
||||||
|
7. 当前版本是否支持 `$MLRN_SPM_SPEC` 或等价官方/仓库已有 override;必须以真实 podspec/source 为准,不得凭记忆发明变量。
|
||||||
|
|
||||||
|
### 4.2 调查 RN 0.85.2 TurboModule iOS codegen
|
||||||
|
|
||||||
|
必须检查当前 RN 0.85.2 codegen 生成的 iOS Spec / base class pattern,确认:
|
||||||
|
|
||||||
|
- ObjC++ module class声明/继承方式;
|
||||||
|
- Promise resolve/reject ABI;
|
||||||
|
- module provider / codegen registration;
|
||||||
|
- 新架构 Fabric / TurboModule 的实际编译入口;
|
||||||
|
- package podspec 需要包含哪些 generated files / dependency。
|
||||||
|
|
||||||
|
### 4.3 做一张 parity matrix
|
||||||
|
|
||||||
|
在完成报告中列出当前 `NativeWeatherRuntimeBridge.ts` 每一个方法:
|
||||||
|
|
||||||
|
- Android 当前实现
|
||||||
|
- iOS 可映射到哪个 public Native/Core seam
|
||||||
|
- 是否需要扩展 `MLNParticleFieldRuntime`
|
||||||
|
- 最终 parity 状态
|
||||||
|
|
||||||
|
不得只实现 Wind V4 后声称“接口一致”。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 第二阶段:iOS TurboModule 与 Fabric reactTag → MLNMapView
|
||||||
|
|
||||||
|
### 5.1 新增 iOS package 实现
|
||||||
|
|
||||||
|
在 `packages/maplibre-particle-rn/` 中增加正式 iOS native implementation,并补齐 RN package iOS autolinking 所需文件。
|
||||||
|
|
||||||
|
预期包括但不限于:
|
||||||
|
|
||||||
|
- iOS ObjC++ TurboModule implementation
|
||||||
|
- 必要的 package podspec / codegen 接线
|
||||||
|
- `package.json files` 纳入 iOS / podspec
|
||||||
|
- `react-native.config.js` 正确支持 iOS(若当前 RN autolinking 实际需要)
|
||||||
|
- README / CHANGELOG 更新
|
||||||
|
|
||||||
|
实际文件名必须遵循当前 RN 0.85.2 codegen 生成基类和模块注册要求,不得照旧版 RN 模板硬套。
|
||||||
|
|
||||||
|
### 5.2 reactTag 规则
|
||||||
|
|
||||||
|
每一个需要 Map 的 native command 都必须:
|
||||||
|
|
||||||
|
1. 验证 reactTag 为正整数;
|
||||||
|
2. 在 Main/UI thread 执行 view lookup;
|
||||||
|
3. 从当前 Fabric surface/UIManager 重新 resolve reactTag;
|
||||||
|
4. 确认它确实是当前 MLRN MapView ComponentView/content view;
|
||||||
|
5. 获得当前真实 `MLNMapView`;
|
||||||
|
6. 再调用 MapView-owned Particle runtime。
|
||||||
|
|
||||||
|
禁止:
|
||||||
|
|
||||||
|
- 缓存 reactTag → map 指针;
|
||||||
|
- 建立全局/静态 Map registry;
|
||||||
|
- 缓存跨 style / surface 生命周期的 `MLNMapView *`;
|
||||||
|
- 通过 private Core 指针绕过 public MLN facade;
|
||||||
|
- 用 Test App private seam 作为 RN 正式 API。
|
||||||
|
|
||||||
|
### 5.3 Map 生命周期
|
||||||
|
|
||||||
|
`attach` 必须对应 Android 现有语义:
|
||||||
|
|
||||||
|
- 当前 Map 存在;
|
||||||
|
- style ready;
|
||||||
|
- 配置要求的 `raster-array` source / `weather-color` / `raster-particle` 已存在并类型正确;
|
||||||
|
- attach/re-attach 的 replace/dispose 语义稳定;
|
||||||
|
- runtime 由 MapView 持有;
|
||||||
|
- bridge 不持有第二份 runtime owner。
|
||||||
|
|
||||||
|
`detach`:
|
||||||
|
|
||||||
|
- 对当前 MapView 的 runtime 执行 dispose;
|
||||||
|
- 不销毁 MapView;
|
||||||
|
- 不缓存 stale runtime。
|
||||||
|
|
||||||
|
后续每条 command 都必须针对当前 MapView/current runtime执行,style reload 后按 Native facade fail-closed。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 第三阶段:Android ↔ iOS 公共行为完整对齐
|
||||||
|
|
||||||
|
### 6.1 V4 必须完整实现
|
||||||
|
|
||||||
|
至少包括:
|
||||||
|
|
||||||
|
- `submitEncodedField`
|
||||||
|
- `setEncodedColorBinding`
|
||||||
|
- `setEncodedParticleBinding`
|
||||||
|
- `setEncodedForecastTime`
|
||||||
|
- `setEncodedForecastPlaybackState`
|
||||||
|
- `setEncodedForecastPlaybackSpeed`
|
||||||
|
- `clearEncodedField`
|
||||||
|
- `clearAllEncodedFields`
|
||||||
|
|
||||||
|
QBIN 必须从本地绝对 path / `file://` URI读取为 bytes,再交给 `MLNParticleFieldRuntime`;JS 不解码 QBIN。
|
||||||
|
|
||||||
|
文件 guard 必须与 Android 当前 contract 等价:
|
||||||
|
|
||||||
|
- local file only;
|
||||||
|
- readable regular file;
|
||||||
|
- 1..64 MiB;
|
||||||
|
- read 时防文件长度变化;
|
||||||
|
- contract JSON 上限与 encoded ID UTF-8 byte guard保持一致;
|
||||||
|
- 不使用 Base64 / JS number[]。
|
||||||
|
|
||||||
|
### 6.2 V3 与当前公共控制面也必须审计并实现 parity
|
||||||
|
|
||||||
|
当前 RN public Spec 不只有 V4。
|
||||||
|
|
||||||
|
必须逐项处理:
|
||||||
|
|
||||||
|
- `submitWindField`
|
||||||
|
- `submitField`
|
||||||
|
- `clearWindFields`
|
||||||
|
- `clearFields`
|
||||||
|
- `getState`
|
||||||
|
- `setFieldValueSource`
|
||||||
|
- `setParticleAdvectionScale`
|
||||||
|
- `setWeatherEnabled`
|
||||||
|
- `setWeatherColorVisible`
|
||||||
|
- `setParticleVisible`
|
||||||
|
- `setTargetFps`
|
||||||
|
- `setForecastTime`
|
||||||
|
- `setPlaybackState`
|
||||||
|
- `setPlaybackSpeed`
|
||||||
|
- `setWeatherColorStops`
|
||||||
|
- `setParticleColor`
|
||||||
|
- `setTrailColor`
|
||||||
|
- `setParticleCount`
|
||||||
|
- `setParticleLineWidth`
|
||||||
|
- `setParticleLength`
|
||||||
|
- `setParticleOpacity`
|
||||||
|
- `setTrailOpacity`
|
||||||
|
- `setTrailFade`
|
||||||
|
- `setWeatherColorOpacity`
|
||||||
|
|
||||||
|
原因:RFC-001 当前 NavSea 事实仍包含 Wind V4 + Wave/Rain/Tide V3;不能靠 iOS-specific JS branch规避。
|
||||||
|
|
||||||
|
### 6.3 如果 082 facade 覆盖不足
|
||||||
|
|
||||||
|
当前 `MLNParticleFieldRuntime` 主要冻结 V4 submit/binding/forecast/clear。
|
||||||
|
|
||||||
|
如 parity audit 证明 V3 / state / visual control 在 iOS 已有 Shared Core 能力但没有 public ObjC facade:
|
||||||
|
|
||||||
|
- 允许在本 STEP-083 内最小扩展 `MLNParticleFieldRuntime.h/.mm`;
|
||||||
|
- 仅做现有 Core 能力的薄 public facade;
|
||||||
|
- Android API/Shared Core contract不改变;
|
||||||
|
- 不把 provider、NavSea、RN 类型写进 Core;
|
||||||
|
- 仍保持每次 command current-style lookup 与 fail-closed;
|
||||||
|
- public header 不泄漏 C++/STL/private Core 类型。
|
||||||
|
|
||||||
|
如某个现有 RN public method 在 iOS 根本没有对应 Shared Core 语义,且实现它必须新增/改变跨平台公共协议:
|
||||||
|
|
||||||
|
**停止扩大该部分并在报告中明确 BLOCKED。不得:**
|
||||||
|
|
||||||
|
- 返回假的 ACCEPTED;
|
||||||
|
- 写 no-op stub;
|
||||||
|
- iOS 永久返回 REJECTED 却仍宣称 parity;
|
||||||
|
- 在 JS 用 Platform.OS 绕过;
|
||||||
|
- 私自创建 iOS-only public protocol。
|
||||||
|
|
||||||
|
需要新的跨平台语义时必须回到 Integration RFC/Contract。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Error / Promise 语义对齐
|
||||||
|
|
||||||
|
以 Android `WeatherRuntimeBridgeModule.kt` 为 reference。
|
||||||
|
|
||||||
|
iOS 必须尽量保持相同 reject code 和触发条件:
|
||||||
|
|
||||||
|
- `INVALID_ARGUMENT`
|
||||||
|
- `MAP_VIEW_NOT_FOUND`
|
||||||
|
- `MAP_NOT_READY`
|
||||||
|
- `STYLE_NOT_READY`
|
||||||
|
- `RUNTIME_DISPOSED`
|
||||||
|
- `SOURCE_MISSING`
|
||||||
|
- `NATIVE_REJECTED`
|
||||||
|
- 以及当前 attach / weather-object readiness 已有的稳定错误码
|
||||||
|
|
||||||
|
Core V4 submit rejection 仍作为 **resolved `EncodedFieldSubmitResult`** 返回,不得错误地全部转成 Promise reject。
|
||||||
|
|
||||||
|
Facade/lifecycle/file/ABI 错误使用 Promise reject。
|
||||||
|
|
||||||
|
同类输入在 Android 与 iOS 的成功/reject类别不得无理由分叉。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. XCFramework / MapLibre 单实例消费
|
||||||
|
|
||||||
|
这是本任务的关键发行门槛之一。
|
||||||
|
|
||||||
|
### 8.1 只能有一个 MapLibre.framework
|
||||||
|
|
||||||
|
MLRN 与 Particle iOS bridge 必须消费 **同一个** STEP-082 custom MapLibre module/product。
|
||||||
|
|
||||||
|
禁止:
|
||||||
|
|
||||||
|
- MLRN 拉官方 MapLibre,而 Particle bridge再静态/动态链接另一份 custom MapLibre;
|
||||||
|
- App 中出现两个 `MapLibre.framework`;
|
||||||
|
- 两份 ObjC class runtime;
|
||||||
|
- 私自 rename module 绕开 duplicate symbol。
|
||||||
|
|
||||||
|
### 8.2 使用真实 MLRN 11.3.6 支持的 override
|
||||||
|
|
||||||
|
先调查 MLRN 11.3.6 podspec / SPM consumer。
|
||||||
|
|
||||||
|
如果真实支持 `MLRN_SPM_SPEC`,按其实际格式接 STEP-082 custom distribution。
|
||||||
|
|
||||||
|
如果实际版本使用其他机制,按真实机制实现,并在报告记录。
|
||||||
|
|
||||||
|
不能凭聊天记忆写一个未被 MLRN 读取的环境变量。
|
||||||
|
|
||||||
|
### 8.3 本地验证允许使用 STEP-082 artifact
|
||||||
|
|
||||||
|
当前 artifact 尚未远端发布,manifest URL 为 `LOCAL_BUILD`。
|
||||||
|
|
||||||
|
本任务测试阶段允许用本地 `MapLibre.dynamic.xcframework.zip` / 解包后的 XCFramework 做可重复的 local consumer 验证。
|
||||||
|
|
||||||
|
不得伪造远端 URL。
|
||||||
|
|
||||||
|
远端正式发布可以后续单独处理;但本 STEP 必须证明 iOS RN/Test Host 能消费同一 custom MapLibre binary。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. RN package 版本规则
|
||||||
|
|
||||||
|
本任务首先完成实现与验证,不为了“有 iOS 文件”立即发布新 npm。
|
||||||
|
|
||||||
|
当前 `13.4.1-particle.5` 与 Android Native `.5` 是 RFC-001 正式发布基线。
|
||||||
|
|
||||||
|
除非任务过程中发现已有正式 release 流程明确要求同步 bump,否则:
|
||||||
|
|
||||||
|
- 不擅自发布 `.6`;
|
||||||
|
- 不让 RN package version 与 Android Native strict lock失配;
|
||||||
|
- 可以在工作树/Test Host 用 source package验证 iOS。
|
||||||
|
|
||||||
|
最终若需要新跨平台发行版本,在 STEP-083 验证通过后单独记录 release decision。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Test Host:同一 JS 代码验证 Android/iOS
|
||||||
|
|
||||||
|
优先复用:
|
||||||
|
|
||||||
|
`integration/react-native/MapLibreParticleRNTestHost/`
|
||||||
|
|
||||||
|
当前它没有生成 iOS 工程。
|
||||||
|
|
||||||
|
本任务应让它具备 iOS validation 能力,但不要复制第二份业务 App。
|
||||||
|
|
||||||
|
### 10.1 JS 层不得另写 iOS 页面
|
||||||
|
|
||||||
|
同一个 `App.tsx` / `FieldRuntime` 调用路径用于 Android 与 iOS。
|
||||||
|
|
||||||
|
允许平台专属的 build/config/native files,不允许平台专属业务调用。
|
||||||
|
|
||||||
|
### 10.2 iOS 最小验收内容
|
||||||
|
|
||||||
|
至少准备并尽可能实际执行:
|
||||||
|
|
||||||
|
1. dependency install;
|
||||||
|
2. RN codegen;
|
||||||
|
3. TypeScript typecheck;
|
||||||
|
4. iOS project/prebuild/pods 或实际当前工具链对应生成流程;
|
||||||
|
5. simulator 或 device Debug build;
|
||||||
|
6. module link/launch smoke;
|
||||||
|
7. Map reactTag attach;
|
||||||
|
8. V4 Wind Golden T0/T1 submit;
|
||||||
|
9. color/particle binding;
|
||||||
|
10. forecast time midpoint;
|
||||||
|
11. PLAY/PAUSE/speed;
|
||||||
|
12. clear selected / clear all;
|
||||||
|
13. detach/re-attach;
|
||||||
|
14. style/source not ready fail-closed;
|
||||||
|
15. 验证没有 duplicate MapLibre framework/class。
|
||||||
|
|
||||||
|
如真实运行需要用户手工设备操作,Codex必须把代码、测试入口和明确验收步骤准备完整;不得把未运行项目写 PASS。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. 允许修改范围
|
||||||
|
|
||||||
|
主要允许:
|
||||||
|
|
||||||
|
- `packages/maplibre-particle-rn/src/`(仅为平台中性错误文本/必要 codegen 修正;不得分叉 public API)
|
||||||
|
- `packages/maplibre-particle-rn/ios/` 新增
|
||||||
|
- `packages/maplibre-particle-rn/*.podspec` / package/autolinking配置
|
||||||
|
- `packages/maplibre-particle-rn/package.json`(仅 package files/codegen/build必要项;默认不 bump version)
|
||||||
|
- `packages/maplibre-particle-rn/react-native.config.js`
|
||||||
|
- `packages/maplibre-particle-rn/README.md`
|
||||||
|
- `packages/maplibre-particle-rn/CHANGELOG.md`
|
||||||
|
- `integration/react-native/MapLibreParticleRNTestHost/` 的 iOS build/config/test入口
|
||||||
|
- 如 parity 必需:`platform/ios/src/MLNParticleFieldRuntime.h/.mm` 的薄 facade 扩展
|
||||||
|
- 必要 iOS Bazel/public header build graph,前提是不改变 Shared Core contract
|
||||||
|
- STEP-083 设计/记录/报告文件
|
||||||
|
|
||||||
|
不得修改:
|
||||||
|
|
||||||
|
- NavSea 仓库
|
||||||
|
- Android public RN API签名
|
||||||
|
- Android Kotlin/JNI行为,除非只是无语义的测试/编译兼容且报告说明;默认不改
|
||||||
|
- QBIN/FieldProfile/BindingProjection contract
|
||||||
|
- Renderer/Metal particle physics
|
||||||
|
- provider/network/cache/Route/ETA
|
||||||
|
- STEP-081/082 已关闭事实
|
||||||
|
- unrelated submodule / user dirty
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. 必须保护的现有 dirty / untracked
|
||||||
|
|
||||||
|
以下必须原样保护,不得暂存或提交:
|
||||||
|
|
||||||
|
- `docs/doxygen/doxygen-awesome-css`
|
||||||
|
- `platform/ios/app/MBXAppDelegate.m`
|
||||||
|
- `platform/windows/vendor/vcpkg`
|
||||||
|
|
||||||
|
现有未跟踪任务书也不得删除、改写、提交:
|
||||||
|
|
||||||
|
- `docs/40_任务/STEP-082_XCFramework_Bazel_Codegen阻塞收尾_Codex任务_v1.md`
|
||||||
|
- `docs/40_任务/STEP-082_iOS_Native_FieldRuntime_Facade与XCFramework发行基线_Codex任务_v1.md`
|
||||||
|
|
||||||
|
本 STEP-083 任务书自身默认也不要求提交。
|
||||||
|
|
||||||
|
禁止:
|
||||||
|
|
||||||
|
- `git add -A`
|
||||||
|
- `git add .`
|
||||||
|
- `git reset --hard`
|
||||||
|
- `git clean`
|
||||||
|
|
||||||
|
只允许 scoped stage。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. 验证要求
|
||||||
|
|
||||||
|
### 13.1 静态/代码
|
||||||
|
|
||||||
|
至少:
|
||||||
|
|
||||||
|
- package TypeScript typecheck
|
||||||
|
- RN Codegen 成功生成 iOS/Android Spec,且 Android ABI未意外变化
|
||||||
|
- iOS ObjC++ compile / Xcode build能证明 module与 generated spec匹配
|
||||||
|
- podspec lint/解析或等价 CocoaPods 集成检查
|
||||||
|
- `git diff --check`
|
||||||
|
- package tarball 内容检查:必须包含 iOS native files / podspec,不丢现有 Android/src
|
||||||
|
|
||||||
|
编译输出遵循全局 `$build-output-throttle`。
|
||||||
|
|
||||||
|
### 13.2 公共 API parity
|
||||||
|
|
||||||
|
完成报告必须逐项证明:
|
||||||
|
|
||||||
|
- public TS API无 iOS新增/删减
|
||||||
|
- Native Spec无平台分叉
|
||||||
|
- Android既有 API仍可 codegen
|
||||||
|
- iOS module实现同一 Spec
|
||||||
|
- 关键 error code/submit result映射一致
|
||||||
|
- Test Host JS 不需要 Platform.OS分支
|
||||||
|
|
||||||
|
### 13.3 MapLibre binary identity
|
||||||
|
|
||||||
|
必须检查最终 iOS build graph:
|
||||||
|
|
||||||
|
- 只解析一个 MapLibre module/product;
|
||||||
|
- 实际链接的是 STEP-082 custom binary;
|
||||||
|
- `MLNParticleFieldRuntime` symbol可见;
|
||||||
|
- 无 duplicate framework/class warning;
|
||||||
|
- MLRN 与 Particle bridge看到同一 ObjC runtime class。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. 执行策略
|
||||||
|
|
||||||
|
这是复杂任务,可以在一个 STEP 内分“调查 → 实现 → 构建/验证 → 收尾”四个阶段,但不要人为拆成 STEP-083A/B/C/D。
|
||||||
|
|
||||||
|
遇到小型编译/Pod/codegen/headers问题,Codex继续最小修复并验证。
|
||||||
|
|
||||||
|
只有遇到以下情况才停止:
|
||||||
|
|
||||||
|
1. 需要改变当前 RN public API;
|
||||||
|
2. 需要改变 C-001 Shared Core contract;
|
||||||
|
3. 需要新增跨平台 semantic/error/lifecycle协议;
|
||||||
|
4. MLRN 11.3.6 无法在不双链接 MapLibre 的情况下消费 custom binary,需要新的架构决定。
|
||||||
|
|
||||||
|
停止时写明确 blocker,不得用 stub/Platform.OS/第二 registry绕过。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. Git 与文档输出
|
||||||
|
|
||||||
|
实质进展后更新:
|
||||||
|
|
||||||
|
- `粒子开发记录.md`
|
||||||
|
- 新建:
|
||||||
|
`docs/50_Step记录/STEP-083_iOS_RN统一FieldRuntime_TurboModule_Fabric与XCFramework消费_v1.md`
|
||||||
|
|
||||||
|
Codex完成报告固定生成:
|
||||||
|
|
||||||
|
`docs/报告/STEP-083_iOS_RN统一FieldRuntime_TurboModule_Fabric与XCFramework消费_Codex完成报告_v1.md`
|
||||||
|
|
||||||
|
报告至少写:
|
||||||
|
|
||||||
|
- 调查结论
|
||||||
|
- parity matrix
|
||||||
|
- MLRN 11.3.6 Fabric lookup真实路径
|
||||||
|
- RN 0.85.2 TurboModule registration真实路径
|
||||||
|
- package/podspec改动
|
||||||
|
- Native facade扩展(如有)
|
||||||
|
- custom MapLibre single-binary消费方式
|
||||||
|
- typecheck/codegen/build/test结果
|
||||||
|
- 未实际运行项
|
||||||
|
- user dirty保护情况
|
||||||
|
- commit hash / message
|
||||||
|
- push result
|
||||||
|
- remote branch
|
||||||
|
- Final HEAD
|
||||||
|
|
||||||
|
在合适检查点做 scoped commit;完成范围才提交,不要带入 unrelated dirty。
|
||||||
|
|
||||||
|
最终 push:
|
||||||
|
|
||||||
|
`origin/particle/main`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. CLOSED / PASS 门槛
|
||||||
|
|
||||||
|
只有全部成立才能标记 STEP-083 `CLOSED / PASS`:
|
||||||
|
|
||||||
|
- iOS native module 实现现有同一 `NativeWeatherRuntimeBridge` Spec;
|
||||||
|
- JS/TS public API 不分叉;
|
||||||
|
- reactTag → 当前 Fabric/MLRN view → public MLNMapView 链真实成立;
|
||||||
|
- bridge 不缓存 Map/Core pointer,不建立第二 registry;
|
||||||
|
- V4 入口完整;
|
||||||
|
- V3 + 当前公共控制面 parity audit 完成,所有方法真实实现或已由正式跨平台决定处理;
|
||||||
|
- iOS package autolinking/codegen可用;
|
||||||
|
- MLRN 与 bridge只消费一个 STEP-082 custom MapLibre;
|
||||||
|
- iOS compile/link成功;
|
||||||
|
- Test Host 至少完成真实 module/link/attach smoke;QBIN/Field功能未实际运行的项目不得伪报 PASS;
|
||||||
|
- `git diff --check` PASS;
|
||||||
|
- 完成报告与 Step记录更新;
|
||||||
|
- scoped commit/push成功;
|
||||||
|
- local HEAD == `origin/particle/main`;
|
||||||
|
- 三处用户 dirty和历史任务书未触碰。
|
||||||
|
|
||||||
|
若代码完整但真实 iOS runtime/device验收尚未完成,应写:
|
||||||
|
|
||||||
|
`IMPLEMENTED / WAITING_IOS_VALIDATION`
|
||||||
|
|
||||||
|
不得提前写 CLOSED/PASS。
|
||||||
357
docs/40_任务/STEP-088_静态底图缓存PoC与Renderer观测_Codex任务_v1.md
Normal file
357
docs/40_任务/STEP-088_静态底图缓存PoC与Renderer观测_Codex任务_v1.md
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
# STEP-088 静态底图缓存 PoC 与 Renderer 可观测性 Codex 任务 v1
|
||||||
|
|
||||||
|
## 1. 任务目标
|
||||||
|
基于最新 origin/particle/main 实际代码,实现第一阶段 Retained Static Underlay PoC。
|
||||||
|
|
||||||
|
核心目标:
|
||||||
|
- Camera 固定、Style/Tile 稳定、存在 WeatherColor/Particle 时,把动态层之前连续普通 LayerGroup 前缀 render 到 offscreen texture。
|
||||||
|
- 后续 Particle Tick 继续走当前 onUpdate/createRenderTree,但不再重复 draw 静态前缀,而复用 cached underlay texture。
|
||||||
|
- Particle simulation/render 继续按 cadence 正常。
|
||||||
|
- 增加 Renderer 可观测性。
|
||||||
|
- 本任务只执行 STEP-088,不得执行 STEP-089/090。
|
||||||
|
|
||||||
|
## 2. 执行基线
|
||||||
|
直接在主仓库:
|
||||||
|
/Users/tei/dev/MapLibreParticleLab
|
||||||
|
|
||||||
|
目标主线:
|
||||||
|
origin/particle/main
|
||||||
|
|
||||||
|
执行前:
|
||||||
|
1. git fetch origin particle/main。
|
||||||
|
2. 确认本地 HEAD、origin/particle/main、git status。
|
||||||
|
3. 不 reset/clean,不覆盖用户既有未提交修改。
|
||||||
|
4. 如存在无关本地修改,只修改、stage、commit STEP-088 相关文件。
|
||||||
|
5. 以当前实际代码为准,不得凭旧版本猜接口。
|
||||||
|
|
||||||
|
必须阅读:
|
||||||
|
- docs/40_任务/粒子连续渲染静态底图缓存与动画快路径优化规划_v1.md
|
||||||
|
- 本任务书
|
||||||
|
- docs/20_调查/STEP-086_Particle连续渲染唤醒MapLibre整图成本调查_v1.md
|
||||||
|
- docs/00_项目总则/
|
||||||
|
- docs/00_项目规范/
|
||||||
|
- 根目录 AGENTS.md(如存在)
|
||||||
|
|
||||||
|
## 3. 开工前只读确认
|
||||||
|
必须确认并在完成报告记录:
|
||||||
|
- RenderRasterParticleLayer::needsRepaint()
|
||||||
|
- RenderWeatherColorLayer::needsRepaint()
|
||||||
|
- Renderer::render()
|
||||||
|
- RenderOrchestrator::createRenderTree()
|
||||||
|
- RenderOrchestrator::hasTransitions()
|
||||||
|
- renderer_impl.cpp 的 updateLayers/processChanges
|
||||||
|
- LayerGroup tweaker/upload
|
||||||
|
- visitRenderTargets
|
||||||
|
- main clear
|
||||||
|
- opaque/translucent pass
|
||||||
|
- present
|
||||||
|
- RenderTarget / OffscreenTexture
|
||||||
|
- Heatmap/Hillshade offscreen + texture composite 样板
|
||||||
|
|
||||||
|
涉及文件至少:
|
||||||
|
- src/mbgl/renderer/layers/render_particle_validation_layer.cpp
|
||||||
|
- src/mbgl/renderer/layers/render_weather_color_layer.cpp
|
||||||
|
- src/mbgl/renderer/renderer.cpp
|
||||||
|
- src/mbgl/renderer/render_orchestrator.cpp/.hpp
|
||||||
|
- src/mbgl/renderer/renderer_impl.cpp/.hpp
|
||||||
|
- include/mbgl/renderer/render_target.hpp
|
||||||
|
- src/mbgl/renderer/render_target.cpp
|
||||||
|
- src/mbgl/renderer/layers/render_heatmap_layer.cpp
|
||||||
|
- src/mbgl/renderer/layers/render_hillshade_layer.cpp
|
||||||
|
|
||||||
|
## 4. 修改一:retained dynamic boundary
|
||||||
|
重点修改:
|
||||||
|
- src/mbgl/renderer/render_layer.hpp
|
||||||
|
- src/mbgl/renderer/layers/render_weather_color_layer.hpp
|
||||||
|
- src/mbgl/renderer/layers/render_raster_particle_layer.hpp
|
||||||
|
|
||||||
|
增加仅 Renderer 内部使用的虚函数,语义类似:
|
||||||
|
virtual bool startsRetainedDynamicRange() const { return false; }
|
||||||
|
|
||||||
|
WeatherColor 与 RasterParticle override=true。
|
||||||
|
|
||||||
|
规则:
|
||||||
|
- 两者同时存在取最小实际 layerIndex。
|
||||||
|
- only Particle 使用 Particle index。
|
||||||
|
- 无 candidate 时完全走原 Renderer。
|
||||||
|
- 禁止根据 React layer ID/name 字符串硬编码。
|
||||||
|
- 禁止让 NavSea/Host 传 boundary。
|
||||||
|
- 不新增 public API。
|
||||||
|
|
||||||
|
## 5. 修改二:RenderOrchestrator LayerGroup 分段访问
|
||||||
|
重点修改:
|
||||||
|
- src/mbgl/renderer/render_orchestrator.hpp
|
||||||
|
- src/mbgl/renderer/render_orchestrator.cpp
|
||||||
|
|
||||||
|
必要时小改:
|
||||||
|
- include/mbgl/renderer/layer_group.hpp
|
||||||
|
- src/mbgl/renderer/layer_group.cpp
|
||||||
|
|
||||||
|
需要:
|
||||||
|
- 查询 retained dynamic boundary。
|
||||||
|
- 遍历 boundary 之前 groups。
|
||||||
|
- 遍历 boundary 及之后 groups。
|
||||||
|
- forward/reverse 都支持。
|
||||||
|
- callback 能获得完整原始 LayerGroup 序列 ordinal。
|
||||||
|
|
||||||
|
可采用 before/from visitor 或更通用 indexed/range visitor。
|
||||||
|
|
||||||
|
关键:
|
||||||
|
parameters.currentLayer、depthRangeSize、opaque/translucent ordering 必须与完整遍历等价。
|
||||||
|
不得让 dynamic subset 从 0 重新编号导致 depth/transparency 变化。
|
||||||
|
|
||||||
|
## 6. 修改三:Renderer-owned RetainedUnderlayCache
|
||||||
|
优先新增:
|
||||||
|
- src/mbgl/renderer/retained_underlay_cache.hpp
|
||||||
|
- src/mbgl/renderer/retained_underlay_cache.cpp
|
||||||
|
|
||||||
|
并在 CMakeLists.txt 真实 source list 注册。
|
||||||
|
|
||||||
|
至少维护:
|
||||||
|
- offscreen renderable / texture
|
||||||
|
- viewport size
|
||||||
|
- boundary
|
||||||
|
- valid
|
||||||
|
- buildCount
|
||||||
|
- reuseCount
|
||||||
|
- fallbackCount
|
||||||
|
- last invalidation reason
|
||||||
|
|
||||||
|
不要修改 Heatmap/Hillshade RenderTarget 原有语义。
|
||||||
|
|
||||||
|
STEP-088 至少保证:
|
||||||
|
- resource 创建失败 -> full-render fallback
|
||||||
|
- viewport resize -> invalid
|
||||||
|
- boundary change -> invalid
|
||||||
|
- has3D -> fallback
|
||||||
|
- Debug Overdraw 等明显不兼容模式 -> fallback
|
||||||
|
- context 不可用 -> 不复用
|
||||||
|
- Camera fingerprint 连续相同、style loaded、2D、boundary stable 才允许 reuse
|
||||||
|
|
||||||
|
任何不能证明安全的状态都 full render。
|
||||||
|
|
||||||
|
## 7. 修改四:Renderer::Impl 分离 Static Underlay / Dynamic Range
|
||||||
|
重点:
|
||||||
|
- src/mbgl/renderer/renderer_impl.hpp
|
||||||
|
- src/mbgl/renderer/renderer_impl.cpp
|
||||||
|
|
||||||
|
STEP-088 必须保留:
|
||||||
|
- Renderer::render -> createRenderTree
|
||||||
|
- source update/prepare
|
||||||
|
- layer prepare
|
||||||
|
- updateLayers
|
||||||
|
- LayerGroup tweaker/upload
|
||||||
|
|
||||||
|
只修改真正 draw 阶段。
|
||||||
|
|
||||||
|
目标流程:
|
||||||
|
1. existing independent RenderTargets。
|
||||||
|
2. cache invalid 时,boundary 前 LayerGroups render 到 offscreen 并 mark valid。
|
||||||
|
3. main clear。
|
||||||
|
4. composite cached underlay texture。
|
||||||
|
5. boundary 及之后 opaque/translucent 正常 render。
|
||||||
|
6. legacy items 按安全规则。
|
||||||
|
7. debug。
|
||||||
|
8. present。
|
||||||
|
|
||||||
|
Underlay offscreen 优先透明 clear。
|
||||||
|
main framebuffer 保持原 backgroundColor/depth/stencil 语义。
|
||||||
|
必须确认 background layer optimized-as-color 路径。
|
||||||
|
|
||||||
|
## 8. Legacy RenderItems
|
||||||
|
renderer_impl.cpp translucent pass 仍有 legacy layerRenderItems。
|
||||||
|
|
||||||
|
必须确认是否有 boundary 以下 legacy item。
|
||||||
|
- 无法安全按 layerIndex 切分时不纳入 cache。
|
||||||
|
- 可能破坏 ordering 时 fallback full render。
|
||||||
|
- 不得静默改变顺序。
|
||||||
|
|
||||||
|
## 9. 修改五:cached texture compositor
|
||||||
|
不要正式复用 LocationIndicatorTexturedShader。
|
||||||
|
|
||||||
|
建议新增:
|
||||||
|
RetainedUnderlayCompositeShader
|
||||||
|
|
||||||
|
职责:
|
||||||
|
- viewport/fullscreen quad
|
||||||
|
- sample cached RGBA
|
||||||
|
- 正确 premultiplied alpha
|
||||||
|
- 不做 color ramp
|
||||||
|
- 不做 map transform
|
||||||
|
- 不做 Particle 业务
|
||||||
|
|
||||||
|
按当前真实 shader 注册规则检查/修改至少:
|
||||||
|
- include/mbgl/shaders/shader_source.hpp
|
||||||
|
- src/mbgl/shaders/shader_source.cpp
|
||||||
|
- include/mbgl/shaders/shader_defines.hpp
|
||||||
|
- include/mbgl/shaders/shader_manifest.hpp
|
||||||
|
- include/mbgl/shaders/gl/shader_info.hpp
|
||||||
|
- src/mbgl/shaders/gl/shader_info.cpp
|
||||||
|
- src/mbgl/gl/renderer_backend.cpp
|
||||||
|
- src/mbgl/mtl/renderer_backend.cpp
|
||||||
|
- cmake/opengl.cmake
|
||||||
|
- cmake/metal.cmake
|
||||||
|
- 新增 GL/Metal compositor shader 文件
|
||||||
|
|
||||||
|
如当前 shader codegen 要求生成文件,按真实 codegen 走。
|
||||||
|
Android OpenGL 与 iOS Metal 语义都要完整。
|
||||||
|
|
||||||
|
## 10. Renderer Debug Counters
|
||||||
|
修改:
|
||||||
|
- include/mbgl/particle/renderer_debug_counters.hpp
|
||||||
|
|
||||||
|
至少新增:
|
||||||
|
- FullRendererFrame
|
||||||
|
- RetainedUnderlayBuild
|
||||||
|
- RetainedUnderlayReuse
|
||||||
|
- RetainedUnderlayFallback
|
||||||
|
- RetainedUnderlayInvalidation
|
||||||
|
- RetainedUnderlayStaticGroupDraw
|
||||||
|
- RetainedDynamicGroupDraw
|
||||||
|
|
||||||
|
要求:
|
||||||
|
- NDEBUG 下 no-op
|
||||||
|
- 不增加 Host API
|
||||||
|
- 不每帧刷大量日志
|
||||||
|
|
||||||
|
允许有限首次日志:cache enabled/build/fallback reason。
|
||||||
|
|
||||||
|
## 11. Native 定向测试
|
||||||
|
不新增或运行 Jest。
|
||||||
|
|
||||||
|
至少覆盖:
|
||||||
|
Boundary:
|
||||||
|
- 无 Weather/Particle -> disabled
|
||||||
|
- only Particle
|
||||||
|
- Weather + Particle 不同顺序
|
||||||
|
|
||||||
|
LayerGroup range:
|
||||||
|
- before/from
|
||||||
|
- forward/reverse
|
||||||
|
- original ordinal
|
||||||
|
|
||||||
|
Cache:
|
||||||
|
- first build
|
||||||
|
- reuse
|
||||||
|
- resize invalid
|
||||||
|
- boundary change invalid
|
||||||
|
- unsupported 3D fallback
|
||||||
|
|
||||||
|
Failure:
|
||||||
|
- compositor/resource 创建失败 -> safe fallback/no crash
|
||||||
|
|
||||||
|
测试放当前 renderer test 真实结构,不新造孤立测试框架。
|
||||||
|
|
||||||
|
## 12. Mac 编译与验证
|
||||||
|
|
||||||
|
本任务采用仓库 AGENTS.md 的固定闭环:
|
||||||
|
|
||||||
|
`Codex 写代码 → RDC 执行编译/测试 → 失败则把错误证据交回 Codex 修复 → RDC 再验证`
|
||||||
|
|
||||||
|
Codex 本轮负责:
|
||||||
|
- 完成 Renderer / OpenGL / Metal 相关源码与测试代码实现;
|
||||||
|
- 给出 RDC 需要执行的精确命令;
|
||||||
|
- 不自行启动、等待或轮询长时间编译/测试;
|
||||||
|
- RDC 返回失败日志后,继续分析并修复代码。
|
||||||
|
|
||||||
|
由 RDC / 普通 Terminal 实际执行:
|
||||||
|
- 编译受影响 Renderer C++ target;
|
||||||
|
- 编译 OpenGL compositor shader 相关 target;
|
||||||
|
- 编译 Metal compositor shader 相关 target;
|
||||||
|
- 运行直接相关 C++ 定向测试;
|
||||||
|
- git diff --check。
|
||||||
|
|
||||||
|
RDC 返回结果时:
|
||||||
|
- 成功:返回 exit code、耗时、target 摘要;
|
||||||
|
- 失败:返回首个真实 error、相关 target、必要上下文和完整日志路径;
|
||||||
|
- 不把完整大型 build log 反复送入 Codex。
|
||||||
|
|
||||||
|
明确禁止 Codex 执行:
|
||||||
|
- CMake / Ninja / Bazel 长时间编译;
|
||||||
|
- OpenGL / Metal 长时间构建等待;
|
||||||
|
- Android Gradle build;
|
||||||
|
- AAR/APK build/install;
|
||||||
|
- ADB;
|
||||||
|
- Android App 启动/清数据;
|
||||||
|
- Android 真机/虚拟机;
|
||||||
|
- Jest。
|
||||||
|
|
||||||
|
Android 最终由用户手工验证。
|
||||||
|
|
||||||
|
## 13. PoC 验收证据
|
||||||
|
理想 fixed Camera + Particle ~30 FPS:
|
||||||
|
- RetainedUnderlayBuild ≈ 1
|
||||||
|
- RetainedUnderlayReuse 持续增长
|
||||||
|
- ParticleSimulationAdvance 持续增长
|
||||||
|
- RetainedUnderlayStaticGroupDraw 建 cache 后不随 Particle FPS 增长
|
||||||
|
- RetainedDynamicGroupDraw 持续增长
|
||||||
|
|
||||||
|
如 Mac 无法跑完整 Particle runtime:
|
||||||
|
- 完成 Native 定向/静态验证
|
||||||
|
- 给出用户最少 Android 手工验证项
|
||||||
|
- 最终状态必须:IMPLEMENTED / WAITING FOR ANDROID VALIDATION
|
||||||
|
- 不得写 CLOSED / PASS
|
||||||
|
|
||||||
|
## 14. 本任务明确不做
|
||||||
|
- production 全部 tile/style/placement invalidation
|
||||||
|
- Map::Impl::onUpdate fast path
|
||||||
|
- 跳过 createRenderTree
|
||||||
|
- 跳过 source->update
|
||||||
|
- 跳过 TilePyramid::update
|
||||||
|
- 跳过普通 prepare
|
||||||
|
- 新 Host API
|
||||||
|
- NavSea React 修改
|
||||||
|
- AIS 专项优化
|
||||||
|
- 通用任意 static/dynamic RenderGraph
|
||||||
|
- STEP-089
|
||||||
|
- STEP-090
|
||||||
|
|
||||||
|
## 15. 文档输出
|
||||||
|
必须生成:
|
||||||
|
- docs/50_Step记录/STEP-088_静态底图缓存PoC与Renderer观测_v1.md
|
||||||
|
- docs/报告/STEP-088_静态底图缓存PoC与Renderer观测_Codex完成报告_v1.md
|
||||||
|
|
||||||
|
如同主题已有,递增版本,不覆盖旧报告。
|
||||||
|
|
||||||
|
Step 记录至少写:
|
||||||
|
- 当前问题
|
||||||
|
- 实现结构
|
||||||
|
- boundary
|
||||||
|
- underlay cache flow
|
||||||
|
- PoC 限制
|
||||||
|
- 用户 Android 手工验证项
|
||||||
|
|
||||||
|
完成报告必须写:
|
||||||
|
- 起始 HEAD / 最终 HEAD
|
||||||
|
- 修改文件
|
||||||
|
- boundary 实现位置
|
||||||
|
- LayerGroup 分段实现位置
|
||||||
|
- cache/compositor 实现位置
|
||||||
|
- debug counters
|
||||||
|
- 测试/编译结果
|
||||||
|
- Android 未执行项
|
||||||
|
- fallback
|
||||||
|
- 是否满足进入 STEP-089 条件
|
||||||
|
- final commit hash
|
||||||
|
- commit message
|
||||||
|
- push result
|
||||||
|
- remote branch
|
||||||
|
- Final HEAD
|
||||||
|
|
||||||
|
## 16. Git 收尾
|
||||||
|
完成后:
|
||||||
|
1. 只 stage/commit STEP-088 相关文件。
|
||||||
|
2. 不提交当前主仓库既有无关 dirty/untracked 内容。
|
||||||
|
3. commit message 建议:feat: add retained underlay render cache poc
|
||||||
|
4. push 到 origin/particle/main。
|
||||||
|
5. push 前 fetch;远端前进时安全整合本任务。
|
||||||
|
6. push 失败不得声称完成。
|
||||||
|
7. 最终确认任务提交已在 origin/particle/main。
|
||||||
|
|
||||||
|
## 17. 最终响应
|
||||||
|
直接逐项报告:
|
||||||
|
- 已完成
|
||||||
|
- 未完成
|
||||||
|
- 无法验证
|
||||||
|
|
||||||
|
不要再输出实施计划。
|
||||||
156
docs/40_任务/粒子连续渲染静态底图缓存与动画快路径优化规划_v1.md
Normal file
156
docs/40_任务/粒子连续渲染静态底图缓存与动画快路径优化规划_v1.md
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
# MapLibreParticleLab 粒子连续渲染静态底图缓存与动画快路径优化规划 v1
|
||||||
|
|
||||||
|
## 1. 目标
|
||||||
|
STEP-086 已确认:Particle / WeatherColor 的 needsRepaint 会通过全局 repaint 让完整 MapLibre scene 连续出帧。React 不会每帧重新提交 PBF,但 Native Renderer 会重复进入 source/layer orchestration,并重新提交静态 PBF/fill/line/symbol draw。
|
||||||
|
|
||||||
|
本规划目标:
|
||||||
|
- 地图真实变化时仍走 Full Frame。
|
||||||
|
- Camera、Style、Tile 稳定且只有 WeatherColor/Particle 动画时,复用 Static Underlay。
|
||||||
|
- NavSea / React 不参与 Renderer cache 管理。
|
||||||
|
- 不改变 NavSea ↔ Particle C-001 公共边界。
|
||||||
|
|
||||||
|
## 2. 当前关键代码
|
||||||
|
必须以当前 origin/particle/main 实际代码为准,重点包括:
|
||||||
|
- src/mbgl/renderer/layers/render_particle_validation_layer.cpp
|
||||||
|
- src/mbgl/renderer/layers/render_weather_color_layer.cpp
|
||||||
|
- src/mbgl/renderer/render_orchestrator.cpp/.hpp
|
||||||
|
- src/mbgl/renderer/renderer.cpp
|
||||||
|
- src/mbgl/renderer/renderer_impl.cpp/.hpp
|
||||||
|
- src/mbgl/map/map_impl.cpp
|
||||||
|
- include/mbgl/renderer/render_target.hpp
|
||||||
|
- src/mbgl/renderer/render_target.cpp
|
||||||
|
- src/mbgl/renderer/layers/render_heatmap_layer.cpp
|
||||||
|
- src/mbgl/renderer/layers/render_hillshade_layer.cpp
|
||||||
|
|
||||||
|
## 3. 核心结构
|
||||||
|
不增加永久 public static/dynamic layer flag。采用 Renderer 内部 retained dynamic boundary:
|
||||||
|
- WeatherColor 是 boundary candidate。
|
||||||
|
- RasterParticle 是 boundary candidate。
|
||||||
|
- 同时存在时取最小 layerIndex。
|
||||||
|
- boundary 之前连续 LayerGroup 前缀作为 Static Underlay。
|
||||||
|
- boundary 及之后继续实时绘制。
|
||||||
|
- 没有 boundary 时完全保持原 Renderer。
|
||||||
|
|
||||||
|
Layer 顺序、parameters.currentLayer、depthRangeSize、opaque/translucent 原始 ordinal 必须保持,不允许对子集从 0 重新编号而改变透明/depth 语义。
|
||||||
|
|
||||||
|
## 4. Static Underlay Cache
|
||||||
|
建议 Renderer-owned helper:
|
||||||
|
- src/mbgl/renderer/retained_underlay_cache.hpp
|
||||||
|
- src/mbgl/renderer/retained_underlay_cache.cpp
|
||||||
|
|
||||||
|
职责:
|
||||||
|
- offscreen renderable / texture
|
||||||
|
- viewport size
|
||||||
|
- boundary
|
||||||
|
- valid/invalid
|
||||||
|
- invalidation reason
|
||||||
|
- build/reuse/fallback 计数
|
||||||
|
- compositor resources
|
||||||
|
|
||||||
|
不改变 Heatmap/Hillshade RenderTarget 现有行为;复用现有 gfx::OffscreenTexture / RenderTarget / Drawable / shader abstraction。
|
||||||
|
|
||||||
|
## 5. Texture Composite
|
||||||
|
使用独立语义的 RetainedUnderlayCompositeShader:
|
||||||
|
- viewport/fullscreen quad
|
||||||
|
- sample cached RGBA texture
|
||||||
|
- 正确 premultiplied alpha
|
||||||
|
- 不做 map transform / color ramp / Particle 业务
|
||||||
|
|
||||||
|
不要长期复用 LocationIndicatorTexturedShader。
|
||||||
|
|
||||||
|
## 6. STEP-088
|
||||||
|
先只消除静态地图重复 GPU draw,仍保留:
|
||||||
|
- Map::Impl::onUpdate
|
||||||
|
- UpdateParameters
|
||||||
|
- createRenderTree
|
||||||
|
- source update / TilePyramid update
|
||||||
|
- source/layer prepare
|
||||||
|
- updateLayers
|
||||||
|
- LayerGroup tweaker/upload
|
||||||
|
|
||||||
|
Render 阶段:
|
||||||
|
1. cache invalid:boundary 前 LayerGroups render 到 offscreen。
|
||||||
|
2. cache valid:跳过 boundary 前静态 draw。
|
||||||
|
3. main framebuffer clear。
|
||||||
|
4. composite cached underlay。
|
||||||
|
5. boundary 及之后 WeatherColor/Particle/动态 overlay 正常绘制。
|
||||||
|
6. present。
|
||||||
|
|
||||||
|
## 7. STEP-089
|
||||||
|
在 STEP-088 实机通过后再做 production invalidation:
|
||||||
|
- Camera center/zoom/bearing/pitch
|
||||||
|
- viewport/pixelRatio
|
||||||
|
- style/layer add/remove/reorder/change
|
||||||
|
- source/tile/bucket/drawable 变化
|
||||||
|
- sprite/image/glyph
|
||||||
|
- symbol placement/fade
|
||||||
|
- context/surface recreation
|
||||||
|
- 3D/terrain/custom/debug fallback
|
||||||
|
- OpenGL/Metal 一致生命周期
|
||||||
|
|
||||||
|
## 8. STEP-090 条件步骤
|
||||||
|
只有 STEP-089 后真实 NavSea profile 仍证明主要 CPU 落在:
|
||||||
|
- Map::Impl::onUpdate
|
||||||
|
- createRenderTree
|
||||||
|
- Vector/PBF source update
|
||||||
|
- TilePyramid update
|
||||||
|
- source/layer prepare
|
||||||
|
才进入 Animation-only fast path。
|
||||||
|
|
||||||
|
如果 STEP-089 已满足性能目标,不执行 STEP-090。
|
||||||
|
|
||||||
|
## 9. STEP-088 安全边界
|
||||||
|
PoC reuse 至少要求:
|
||||||
|
- 2D
|
||||||
|
- Camera fingerprint 连续一致
|
||||||
|
- viewport 不变
|
||||||
|
- style loaded
|
||||||
|
- boundary 不变
|
||||||
|
- context/resource 正常
|
||||||
|
|
||||||
|
以下至少 fallback full render:
|
||||||
|
- has3D
|
||||||
|
- Debug Overdraw
|
||||||
|
- cache texture/compositor 创建失败
|
||||||
|
- viewport resize
|
||||||
|
- boundary change
|
||||||
|
- context 不可用
|
||||||
|
- legacy RenderItem ordering 无法证明安全
|
||||||
|
- 其他不能证明 cache 正确的状态
|
||||||
|
|
||||||
|
原则:不确定就 full render,不用 stale cache 换性能。
|
||||||
|
|
||||||
|
## 10. 观测
|
||||||
|
复用 include/mbgl/particle/renderer_debug_counters.hpp,建议增加:
|
||||||
|
- FullRendererFrame
|
||||||
|
- RetainedUnderlayBuild
|
||||||
|
- RetainedUnderlayReuse
|
||||||
|
- RetainedUnderlayFallback
|
||||||
|
- RetainedUnderlayInvalidation
|
||||||
|
- RetainedUnderlayStaticGroupDraw
|
||||||
|
- RetainedDynamicGroupDraw
|
||||||
|
|
||||||
|
固定 Camera + Particle 约 30 FPS 时,理想:
|
||||||
|
- RetainedUnderlayBuild ≈ 1
|
||||||
|
- RetainedUnderlayReuse 持续增长
|
||||||
|
- ParticleSimulationAdvance 持续增长
|
||||||
|
- StaticGroupDraw 建 cache 后不随 Particle FPS 增长
|
||||||
|
- DynamicGroupDraw 持续增长
|
||||||
|
|
||||||
|
## 11. 不允许
|
||||||
|
- React RAF 驱动
|
||||||
|
- Host renderFastFrame/cacheMapNow/invalidateBasemap API
|
||||||
|
- NavSea 手工管理 renderer cache
|
||||||
|
- 修改 C-001
|
||||||
|
- 永久 public static/dynamic flag
|
||||||
|
- 改变 Style layer ordering
|
||||||
|
- STEP-088 就跳过 source/update/prepare
|
||||||
|
- Android/iOS 不同 renderer semantics
|
||||||
|
- stale cache
|
||||||
|
|
||||||
|
## 12. 执行顺序
|
||||||
|
1. STEP-088:PoC + observability
|
||||||
|
2. 用户 Android/NavSea 真机验证
|
||||||
|
3. STEP-089:production invalidation/fallback
|
||||||
|
4. 用户再次 profile
|
||||||
|
5. 只有 CPU orchestration 仍是瓶颈时才 STEP-090
|
||||||
Reference in New Issue
Block a user