Files
MapLibreParticleLab/docs/20_调查/10_架构调查报告_v1.md
OpenAI Codex 74be2a5052
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
docs: freeze particle architecture investigation and design
2026-08-29 12:33:09 +08:00

31 KiB
Raw Blame History

MapLibreParticleLab 架构调查报告 v1

调查日期:2026-08-29

调查分支:particle/main 调查性质:只读架构调查,不是粒子方案设计

1. 调查环境

  • 仓库:/mnt/sda1/MapLibreParticleLab,根目录包含 PARTICLE_BASELINE.md、include/、src/、platform/android/、platform/ios/、shaders/、particle-fixtures/ 和 docs/,确认是 MapLibreParticleLab。
  • 主机基线:Ubuntu 24.04 x86_64;项目基线记录的 Java 17、Android API 34、NDK 28.2.13676358、构建并行度 3 已读取自 PARTICLE_BASELINE.md 与 docs/00_项目规范/06_官方基线来源_v1.md。
  • 本次只执行文件搜索、源码阅读、配置阅读和 Git 查询;未运行构建、测试、依赖安装或会生成产物的命令。

2. Git、基线和规则读取

  • 分支:particle/main。
  • HEAD:127de2271480000fcc8f390d81cf446e98757800,最近提交主题为 docs: freeze particle project governance v1,时间为 2026-08-29 11:13:49 +08:00。
  • 远端:origin 为本地 Gitea SSH 地址;upstream 为 MapLibre Native GitHub,只启用 fetch,push 显式为 DISABLED。
  • 工作区:调查开始时无已跟踪修改;有一个未跟踪的当前任务书 docs/40_任务/10_架构调查指令书_v1.md。因此“工作区干净”检查结果为:未完成,原因是任务书本身在当前工作区未跟踪,非本次生成。
  • 当前基线:Android android-v13.4.1、iOS ios-v6.28.0、共用 Core 18545ca10d296704b2cba675b182ff2c8da24588。实际版本文件为 platform/android/VERSION 和 platform/ios/VERSION。
  • 已完整读取:根目录 AGENTS.md;PARTICLE_BASELINE.md;docs/00_项目总则/ 下当前四份总则;docs/00_项目规范/ 下当前六份规范及官方基线来源;当前 STEP-000 记录和报告;docs/40_任务/README.md;本任务书;调查、Step、报告 README;现有 docs/10_架构/MapLibre粒子总体架构_v1.md;粒子开发记录.md。
  • 本次未修改 docs/00_项目总则/、docs/00_项目规范/、生产代码、实验源码、构建配置或依赖。

3. 当前项目整体架构

3.1 工程形态

当前仓库不是 React Native、Expo 或 Bare RN 产品工程。根 package.json 的名称是 maplibre-native,脚本只有样式规范复制;tsconfig.json 只包含 .github/scripts/*.ts、scripts/**/*.mjs 和声明文件,并设置 noEmit。仓库没有业务页面、React 组件、react-native/Expo 依赖、Metro 配置或 Babel 配置。

因此任务书中的“业务/页面 → RN Map 组件 → RN 封装”在当前仓库不存在,不能据此补画一条虚构调用链。这里的实际入口是各平台 MapLibre SDK 示例、测试应用或直接使用 Native C++ API 的宿主。

3.2 主要目录

MapLibreParticleLab/
├── include/mbgl/          Core 对外 C++ API
├── src/mbgl/              Core 实现:Map、Style、Source、Render、gfx、线程
├── platform/android/      Android SDK、JNI、Java/Kotlin View、C++ backend、测试 App
├── platform/ios/          iOS SDK、MLNMapView、OpenGL/Metal backend、示例和测试
├── platform/darwin/       Darwin 公共绑定、CustomStyleLayer 和 CustomDrawableLayer
├── platform/node/         Node binding 与 Node 测试,不是 RN UI 宿主
├── shaders/               MapLibre 内置 GLSL/生成清单;无粒子 shader
├── particle-fixtures/     第一阶段离线粒子场/Mask fixture 占位目录
├── render-test/ test/     渲染测试、API 测试、fixture 和服务器测试
├── scripts/               样式代码、设备农场和工程脚本
├── docs/                  总则、架构、任务、调查、Step、报告
├── vendor/                第三方源码子模块
└── CMakeLists.txt、Makefile、bazel/、platform 构建文件

3.3 入口和边界

  • Core 入口是 mbgl::Map(include/mbgl/map/map.hpp),通过构造时注入 RendererFrontend 和 MapObserver。
  • Android 入口是 MapView(platform/android/MapLibreAndroid/src/main/java/.../MapView.java),内部创建 MapRenderer、NativeMapView 和 Java/C++ JNI peer。
  • iOS 入口是 MLNMapView : UIView(platform/ios/src/MLNMapView.h),内部由 MLNMapViewImpl 连接 Core Map 和 OpenGL/Metal View。
  • 没有项目自有 assets/ 业务资源目录;test/fixtures 是 MapLibre 测试资源,particle-fixtures 目前仅包含 README 和五个 .gitkeep。
  • 现有 build-linux-opengl、build-particle 等是工作区中的构建目录,不视为源码模块。

4. 依赖与版本

类别 当前可确认内容 证据/结论
JavaScript 直接依赖 @maplibre/maplibre-gl-style-spec、simple-git、minimatch、npm-run-all、GitHub Actions 等 根 package.json;不是地图 UI 依赖
JavaScript 开发依赖 TypeScript、EJS、Express、AWS SDK、MVT/style fixtures 等 用于脚本、测试、设备农场和代码生成
RN/React/Expo 未找到 react、react-native、Expo、RN MapLibre 包 当前仓库没有 RN 产品层
Skia/Reanimated/WebGL JS 未找到项目直接依赖 不能假定存在
Android SDK platform/android/VERSION=13.4.1;compileSdk=34、minSdk=23;OpenGL/Vulkan/WebGPU flavor;Java SDK 直接依赖 GeoJSON、gestures 等 platform/android/MapLibreAndroid/build.gradle.kts
Android Core libmaplibre 由本仓库 C++ Core 构建并通过 JNI/Prefab 接入,不是另一个 RN 包 Android CMake、JNI 和 Prefab 配置
iOS SDK platform/ios/VERSION=6.28.0;Podspec 通过 ios-v#{version} release xcframework;iOS deployment target 12 platform/ios/MapLibre.podspec
iOS backend 当前源码含 OpenGL、Metal、WebGPU 条件路径;当前项目基线将 OpenGL 作为主线、Metal 作为后续验证方向 MLNMapView+Impl.mm 和各 backend 文件
lock 文件 根 package-lock.json lockfile v3、pnpm-lock.yaml lockfile v9;锁定 TypeScript 5.9.3 等脚本依赖 未安装/更新

需要区分:package.json 的版本 5.4.0 是 Native 仓库/脚本包版本;Android/iOS SDK 版本分别由各平台 VERSION 决定,不能把三者合并为一个 RN 版本。

5. MapLibre 实际接入链

当前无 RN 绑定,因此实际链路分为 Android SDK、iOS SDK 和直接 Core 三条:

Android Activity/Test App
  → MapView(FrameLayout)
  → MapRenderer + NativeMapView(Java JNI peer)
  → AndroidRendererFrontend
  → mbgl::Map / mbgl::Style
  → RendererFrontend::update(UpdateParameters)
  → Android MapRenderer render thread
  → mbgl::Renderer
  → RenderOrchestrator / RenderTree / RenderLayer / gfx::Drawable
  → Android OpenGL 或 Vulkan RendererBackend
  → Surface/TextureView → GPU
iOS App/Example
  → MLNMapView(UIView)
  → MLNMapViewImpl(MapObserver adapter)
  → mbgl::Map + RendererFrontend
  → RenderOrchestrator / RenderTree / RenderLayer / gfx
  → MLNMapViewOpenGLImpl(GLKView) 或 MLNMapViewMetalImpl(MTKView)
  → EAGL/CAMetalLayer → GPU
直接 Core 宿主
  → mbgl::Map(RendererFrontend, MapObserver)
  → Map::Impl::onUpdate()
  → Immutable Style/Source/Layer snapshot
  → Renderer::render()

当前能够确认的对象:MapView、Camera、Style、RasterSource、ImageSource、Vector/GeoJSON/CustomGeometrySource、Layer、MapObserver 事件和 CustomLayer。当前仓库没有 RN ShapeSource 组件层,也没有 RN onPress API;Android/iOS Native SDK 的点击、相机和样式 API 需分别通过各自 SDK 查询,不能移植成当前 RN 事实。

6. MapLibre 生命周期

6.1 Core 生命周期

Map::Impl::onUpdate() 在连续模式下读取当前时间、更新 transition,构造包含 TransformState、style/source/layer immutable snapshot、图片、字体和 FileSource 的 UpdateParameters,再交给 RendererFrontend::update()。Map::triggerRepaint() 也只是触发同一更新路径。

Renderer::render() 创建并准备 RenderTree,Renderer::Impl::render() 依次执行:开始 frame、上传 source/layer 资源、更新 layer group、运行 tweaker、上传 drawable/render target、可选 3D pass、render target、清屏、opaque pass、translucent pass、debug pass、postRender、present、结束 frame,并回调 onDidFinishRenderingFrame。

6.2 Android

  • MapView.initializeDrawingSurface() 创建 MapRenderer 和 NativeMapView;Surface 创建后回到 UI 线程初始化 MapLibreMap 并调用 onStart()。
  • MapView.onStart/onResume/onPause/onStop/onDestroy 分别驱动 Java map/renderer;SurfaceView detach 会触发 native reset,Surface 销毁/重建可能导致 backend 和 Renderer 重建。
  • Java MapRenderer 的 onDrawFrame() 调用 JNI nativeRender();SurfaceView 由 MapLibreSurfaceView 的 render thread 请求 dirty/continuous frame,TextureView 由 TextureViewRenderThread 的事件队列和 request flag 驱动。
  • AndroidRendererFrontend::update() 保存最新 UpdateParameters,异步任务把它交给 MapRenderer 并调用 Java requestRender()。C++ render thread 只持有一次 render 所需的参数快照。
  • Native MapObserver 事件由 JNI 转回 Java MapChangeReceiver,包括 camera will/is/did、地图/样式加载、render frame start/end、idle、source 和 shader 事件。

6.3 iOS

  • MLNMapView 创建 Core Map 和 MLNMapViewImpl;实现通过编译宏选择 OpenGL、Metal 或 WebGPU backend。
  • 显示刷新由 CADisplayLink 调用 updateFromDisplayLink:;当 needsDisplayRefresh 或 pending completion 存在时,调用 backend View 的 setNeedsDisplay。
  • renderSync 清除刷新标记后调用 _rendererFrontend->render();渲染 View delegate 的 drawInRect:/drawInMTKView: 再调用 MLNMapViewImpl::render(),形成地图自己的渲染帧。
  • View 不可见、进入后台、销毁或恢复时,DisplayLink、drawable、backend 资源和 dormant 状态分别处理;具体资源重建依赖 backend 实现。
  • iOS delegate 可获得相机、地图/样式加载、render frame start/end、idle 等事件;CustomStyleLayer 的 drawInMapView:withContext: 在 MapLibre 的自定义 layer 绘制时调用。

6.4 TS/RN 层与内部事件

当前仓库没有 TS/RN 层,所以“TS/RN 直接获得的生命周期事件”:未确认/不适用,原因是该层不存在。Native SDK 可观察的事件如上;只存在于 Core/Renderer 的 UpdateParameters、RenderTree、LayerGroup、GPU command encoder 的内部状态,当前没有 JS 层封装。

7. 自定义渲染扩展点分类

A:当前项目已经直接使用

  • Core style::CustomLayer + CustomLayerHost + RenderCustomLayer:现有 Android Test App 的 CustomLayerActivity 和 C++ ExampleCustomLayer/ExampleVulkanCustomLayer 实际使用。
  • Darwin MLNCustomStyleLayer:iOS/Swift 示例实现 drawInMapView:withContext:,获得同一 frame 的 projection matrix;Metal 示例使用当前 render encoder。
  • Darwin MLNCustomDrawableStyleLayer/Core CustomDrawableLayer:示例 ExampleCustomDrawableStyleLayer 和 UI 测试实际使用,属于 Drawable/Builder 路径而不是 raw GL callback。
  • 内置 RenderLayer、LayerGroup、DrawableBuilder、DrawableTweaker、shader manifest、texture/buffer/render target:是当前地图本身的生产渲染链,粒子尚未接入。

B:当前依赖已暴露,但目标粒子业务尚未使用

  • Android Java CustomLayer(String id, long host) 暴露了 native host 指针入口,但 Java API 明确标注 experimental/do not use;当前只在 SDK test app 示例使用,粒子业务未使用。
  • Android CustomGeometrySource 和 iOS MLNComputedShapeSource 已暴露,能提供按 tile 的 GeoJSON/几何数据;当前没有粒子/格点数据实现。
  • Core gfx::Context 已有 createTexture2D、createDynamicTexture、createRenderTarget、uniform buffer、createDrawableBuilder、generic shader 和 upload pass 接口;这些是现有通用基础设施,不等于粒子专用 API。

C:Native Core 支持,但当前高层封装未统一暴露

  • CustomLayerHost::render() 可拿到 width/height、center、zoom、bearing、pitch、FOV、projection matrix 和 near-clipped matrix;Vulkan/Metal 还有 backend-specific render parameters。Android 高层 Java host 没有一个类型安全的 CustomLayerRenderParameters API,应用级可直接使用范围未确认。
  • Core RenderLayer、RenderOrchestrator、LayerManager、RendererObserver 和 gfx backend 内部 hook 可承载 native 粒子实现,但它们是 Core 内部边界,不是当前 RN/业务 API。
  • iOS MLNBackendResource 可暴露 Metal view/device/render pass/command buffer;这是 iOS Native API,当前仓库没有 RN 统一桥接。

D:当前代码无法确认

  • React Native UI/Main Thread、JS bridge、TurboModule/Fabric、RN requestAnimationFrame 或 Reanimated frame callback:当前项目没有 RN host,无法确认。
  • 任何外部 Overlay 与 MapLibre View 的同步质量:当前正式边界禁止外部 Overlay,仓库也没有粒子 Overlay 实现,因此没有实测数据。
  • 未实现的粒子 shader、GPU ping-pong state、trail render target、velocity texture 的具体格式和生命周期:当前只有架构草图,没有实现。

8. Android 渲染架构

  • 原生 View:MapView 是 FrameLayout,将 SurfaceView 或 TextureView renderer 放在 child index 0;不是 RN View。
  • renderer:Java MapRenderer 仅负责生命周期、JNI 和调度;C++ MapRenderer 持有 Android backend、Core Renderer、ActorRef、update mutex 和 renderer observer。
  • backend:Gradle flavor 通过 -DMLN_WITH_OPENGL=ON 或 -DMLN_WITH_VULKAN=ON 构建;C++ AndroidGLRendererBackend 和 AndroidVulkanRendererBackend 分别管理 EGL/GL 或 Vulkan surface/swapchain/device。
  • 帧驱动:SurfaceView 默认可以 WHEN_DIRTY,CONTINUOUS 用于连续渲染/benchmark;TextureView 自有 render thread。Core update 通过 AndroidRendererFrontend 调用 requestRender。
  • 相机:Java MapLibreMap/Transform 调 JNI,NativeMapView 调 Core jumpTo/easeTo/flyTo、坐标投影和反投影;完整 matrix 仍在 Core Transform/Paint/CustomLayer 参数中。
  • 自定义入口:Core CustomLayer 和 Android wrapper/test example 明确存在;但 Java host 是原始 long,生命周期、指针归属、context loss 和参数传递要求高,不能当作稳定业务接口。
  • Native Module:未找到 RN NativeModule/TurboModule/Fabric。Android 的 NativeMapView 是 MapLibre Java/C++ peer/JNI,不是 RN module;当前不存在“Native Module 接触 RN MapView 实例”的事实。

9. iOS 渲染架构

  • 原生 View:MLNMapView 继承 UIView;内部由 MLNMapViewImpl 将 Core MapObserver 与 ObjC delegate 接起来。
  • OpenGL:MLNMapViewOpenGLImpl 持有 gl::RendererBackend、Renderable 和 GLKView/EAGL context;GLKView delegate 的绘制回调进入 Core render。
  • Metal:MLNMapViewMetalImpl 持有 Metal backend、MTKView、command queue/buffer 和 render pass descriptor;drawInMTKView: 调 impl->render(),Core 负责 command encoding/present。
  • Camera/transform:Core TransformState 生成 TransformParameters 的 projection/aligned/near-clipped matrices;MLNCustomStyleLayer 将这些和中心、zoom、方向、pitch、FOV 传给 ObjC drawing context。
  • 自定义接口:MLNCustomStyleLayer 是可确认的 Native custom layer;Metal 下可以使用当前 encoder,OpenGL 下存在 deprecated EAGL context API。MLNCustomDrawableStyleLayer 是另一条 Drawable/Builder 接口。
  • Native 对象范围:iOS adapter 能访问 Core Map、RendererFrontend 和 backend resource;公开的业务层主要通过 MLNMapView、MLNStyle、MLNStyleLayer 及 delegate 访问。没有 RN 连接层,RN 侧范围为 未确认。
  • Android/iOS 差异:Android 有明确 OpenGL/Vulkan flavor 和实验性 raw host;iOS 示例有成熟的 ObjC/Swift CustomStyleLayer 与 Metal encoder 上下文。两者虽共享 Core CustomLayer 接口,但高层资源和生命周期 API 不一致。

10. JS/UI/Native/Worker/Render/GPU 边界

[不存在的 JS/RN 业务层]
             │  当前仓库无桥接事实
             ▼
Android UI thread / iOS main thread
  ├─ Native MapView、Camera、Style API
  ├─ Core Map 所在线程(由宿主创建线程决定)
  └─ MapObserver 回调
             ▼ immutable UpdateParameters / mailbox / async task
MapLibre Worker/FileSource
  ├─ Style/tile 解析、布局、bucket/buffer 计算
  └─ FileSource 网络/缓存/离线 I/O
             ▼
MapLibre Render thread(Android 明确独立;iOS 当前 render delegate 路径需遵循宿主主线程/渲染上下文约束)
  → Renderer → RenderTree → LayerGroup/Drawable → gfx Context/CommandEncoder
  → OpenGL/Vulkan/Metal backend → GPU
  • 高频数据若走不存在的 JS bridge,当前没有事实可测;按现有边界,不能将每帧大数组交给 Java/ObjC API 作为已支持能力。
  • Android 的 UpdateParameters 在 frontend 与 render peer 之间异步保存并加锁,渲染使用最新快照;Java requestRender 只触发帧,不传粒子数据。
  • iOS setNeedsRerender 只设置刷新标记,CADisplayLink/UIView backend 再进入 render;这不是 JS 每帧回调。
  • Native 每帧回调存在:Core MapObserver/RendererObserver 的 render frame 事件,以及 CustomLayerHost render callback;它们位于地图渲染链内部。
  • GPU 资源直接更新位置存在于 Core gfx::Context、UploadPass、Drawable、Texture、RenderTarget 和 backend command encoder;当前没有对业务开放的跨平台粒子资源接口。

11. Camera、Matrix 与坐标转换能力

信息 JS/RN Native SDK Core 内部/CustomLayer 当前结论
center/zoom/bearing/pitch 当前无 RN host,未确认 Android MapLibreMap、iOS MLNMapView/delegate 可访问部分状态 TransformState 全部存在,CustomLayer 参数传出 可由 Native/Core 获取
bounds/viewport 无 RN host SDK 有尺寸和相机/投影 API TransformState::getSize、frustum offset、tile cover Core 信息完整
screen ↔ geographic 无 RN host Android NativeMapView 和 iOS 公共 API 有相应能力 latLngToScreenCoordinate、screenCoordinateToLatLng 已确认 Core 能力
projection/unprojection 未确认 高层不统一暴露 raw matrix Core getProjMatrix、projection/inverse matrices、camera utility 内部可用
view/transform matrix 未确认 iOS CustomStyleLayer 以 projection context 形式收到;Android Java wrapper 未提供同等类型 API TransformState::matrixFor、TransformParameters、PaintParameters 跨平台高层不一致

证据:TransformParameters 保存 projMatrix、alignedProjMatrix、nearClippedProjMatrix;CustomLayerRenderParameters 从同一 PaintParameters.state 读取中心、zoom、bearing、pitch、FOV 和 projection matrix;PaintParameters::matrixForTile 负责 tile matrix。

严格同步结论:在 Core 的同一渲染帧内,CustomLayer callback 可以获得地图当前 transform,因此“Core 内部同帧使用地图矩阵”已确认;但“Android/iOS 业务高层均能以统一公开 API 获取并接入粒子”未确认,当前不能宣称跨平台正式实现已具备严格同步能力。

12. 帧驱动能力

已确认:Android SurfaceView/TextureView render loop、Android requestRender/CONTINUOUS、iOS CADisplayLink、GLKView/MTKView draw callback、MapLibre triggerRepaint、Core CustomLayer render callback。

未确认/不适用:当前没有 RN requestAnimationFrame、RN animation frame、Reanimated frame callback 或 JS 每帧回调。

地图 Renderer 的帧驱动不是独立于地图的粒子动画时钟:Core Map::Impl::onDidFinishRenderingFrame 在 needsRepaint 或 transition 时重新 onUpdate();平台再请求下一帧。若未来另建独立动画循环,现有代码无法保证它与相机快照、drawable context、present 时刻一致,可能产生一帧延迟、不同步或重复渲染;这里只记录风险,不作方案选择。

13. 当前数据与粒子相关实验代码

  • particle-fixtures/README.md 明确第一阶段禁止真实天气服务器,具体数据格式在设计冻结后确定;coastal-mask/、shear/、uniform-east/、uniform-north/、vortex/ 目前均只有 .gitkeep。
  • 全仓库排除 vendor、node_modules、build 后搜索 particle/wind/current/wave/vector field/rasterarray/velocity,没有发现粒子运行时、速度场解析、粒子 shader、GPU ping-pong 或 trail 实现。
  • 现有 raster 文件是 MapLibre 常规 RasterSource/RasterLayer 测试和内置 raster shader;interpolate 多数是 Style Spec/通用工具,不是向量场插值实现。
  • shaders/ 有 raster、heatmap、hillshade、fill、line、symbol、custom geometry 等现有地图 shader,没有 particle、velocity 或 trail shader。
  • Android/iOS custom layer 示例是图形 API 示例/测试用途,不是粒子基础代码;应分类为“仅实验/示例用途”,不能直接判定为最终可复用粒子实现。

14. 海洋/气象格点数据可经过的现有层

阶段 当前仓库事实
Fetch Core FileSource 支持样式、tile、资源和缓存;没有粒子气象数据协议或 fixture loader
ArrayBuffer/TypedArray JS 侧只有 Node/脚本和测试用途;未发现粒子 ArrayBuffer/TypedArray 模型
二进制解码 Core 有 tile、PBF、图片等既有解码;没有速度场/海洋格点解码器
Grid 数据模型 没有项目粒子 Grid/经纬度格点类型;grid_index 等是通用地图工具或测试
插值 有通用数值/Style 插值工具;没有已确认的向量场双线性/球面插值模块
内存结构 Core 可用 immutable/vector/CPU buffer;没有粒子数据生命周期模型
GPU upload gfx Context、UploadPass、Texture2D、UniformBuffer、RenderTarget、Drawable 已存在
Shader uniform 内置 shader 与 global/layer uniform 已存在;没有粒子 uniform contract
缓存/生命周期 FileSource、tile cache、style snapshot 和 gfx resource 生命周期已存在;粒子数据生命周期未实现

可复用基础设施只能确认到通用地图层:FileSource/离线 fixture 测试体系、immutable snapshot、thread pool、gfx Context/Texture/Buffer/RenderTarget/Drawable、shader registry 和 frame observer。未来粒子数据格式、解析、插值、上传策略均未确定。

15. 性能与线程风险

风险 等级 当前证据与边界
JS 高频循环/每帧 JS→Native 尚无法判断 当前无 JS/RN 宿主;若未来新增,仓库没有现成桥接基准
大数组/JSON/ArrayBuffer 跨桥复制 高 当前 MapLibre update 是 immutable snapshot/异步传递,未提供粒子大数组桥接;跨平台高层接口若采用逐帧对象传输会形成风险
Native→GPU 重复复制 中 gfx upload/update 能力存在,但粒子资源尚未定义,复制次数无法实测
Texture 高频重建 中 Context 有 Texture2D/DynamicTexture;RenderCustomLayer 示例未提供粒子资源复用策略
Camera 变化触发大规模重算 中 Map update 会重新计算 RenderTree、tile/layer evaluation;未来粒子若绑定 camera 需避免把每帧状态误当 style/source 变更
React re-render 尚无法判断 没有 React/RN 工程
外部 Overlay 不同步 低(当前)/架构禁止 当前没有外部粒子 Overlay;正式规则也禁止该路径
Android/iOS 实现分叉 高 同 Core 但高层 CustomLayer、context/encoder、线程和 surface 生命周期不同
GPU context/surface loss 高 Android onSurfaceCreated 会 mark context lost 并重建 backend/Renderer;CustomLayer 有 contextLost;iOS 后台/视图重建也涉及资源生命周期
MapView 销毁后资源泄漏 中 Core/RenderCustomLayer 有 deinitialize/contextLost 路径,raw long host 和应用归属仍需后续设计验证
Render pass 顺序/状态污染 高 CustomLayer 在 translucent pass;raw backend callback 需要遵守当前 render pass 和状态恢复约束

16. 当前架构图

16.1 App / MapLibre 总体调用图

Android 示例或 iOS 示例
  └→ 平台 MapView
       └→ 平台 RendererFrontend / MapObserver adapter
            └→ mbgl::Map
                 ├→ Style / Source / Layer snapshot
                 ├→ Worker + FileSource
                 └→ Renderer → RenderTree → gfx → 平台 GPU backend

16.2 JS → Native → MapLibre 调用链

JS/RN 业务入口:不存在于当前仓库
  └→ RN MapLibre binding:不存在于当前仓库
       └→ Android Java MapView 或 iOS MLNMapView:由外部宿主提供
            └→ JNI/ObjC++ adapter
                 └→ mbgl::Map → RendererFrontend → Renderer → GPU

16.3 Android

UI thread: MapView / MapLibreMap / NativeMapView JNI
      └→ AndroidRendererFrontend + AsyncTask/mailbox
Render thread: MapRenderer → Renderer → RenderOrchestrator
      └→ OpenGL EGL 或 Vulkan device/swapchain
      └→ SurfaceView/TextureView → GPU
Workers/FileSource: tile/style parsing、layout、I/O

16.4 iOS

main/UI: MLNMapView(UIView) + CADisplayLink
      └→ MLNMapViewImpl(MapObserver) + RendererFrontend
draw callback: GLKView 或 MTKView
      └→ mbgl::Renderer → RenderTree → gfx command encoder
      └→ EAGL/OpenGL 或 Metal command buffer → GPU

16.5 数据与渲染边界

FileSource / tile / offline fixture
  → immutable Source/Layer/UpdateParameters
  → RenderTree / RenderSource / RenderLayer
  → gfx Texture/Buffer/Drawable/RenderTarget
  → backend command encoding
  → GPU

粒子 field / particle state / trail:当前不存在;未来位置为 [未确认]

17. 关键结论分类

17.1 已确认事实

  1. 当前仓库是 MapLibre Native monorepo,不是 RN app。
  2. Android 13.4.1、iOS 6.28.0 和 Core commit 已从版本文件/基线确认。
  3. Core 的真实主链是 Map → RendererFrontend → UpdateParameters → Renderer → RenderTree/Orchestrator → Layer/Drawable → gfx backend。
  4. Android 有 OpenGL/Vulkan flavor、独立 renderer thread、JNI Map peer 和实验性 CustomLayer。
  5. iOS 有 MLNMapView、CADisplayLink、OpenGL/Metal backend、Native CustomStyleLayer 和 Drawable 示例。
  6. Core CustomLayer render 参数包含相机和 projection 信息;CustomLayer callback 在地图 render pass 内执行。
  7. 现有 fixture 只有目录占位;没有粒子运行时、格点模型、粒子 shader 或速度场解析器。
  8. Core 已有可复用的 immutable snapshot、worker/FileSource、gfx texture/buffer/render target/drawable/upload/shader registry 基础设施。

17.2 当前限制

  • 没有 RN 页面、RN binding、Metro/Babel、NativeModule/TurboModule/Fabric,因此不能从本仓库确认 RN 到 MapView 的调用和生命周期。
  • Android CustomLayer 的 Java API 使用 raw native host 指针且标记 experimental;与 iOS CustomStyleLayer 的上下文能力不对称。
  • 正式粒子数据格式、内存模型、插值、GPU state、trail 和跨平台资源生命周期尚不存在。
  • 不可把现有 RasterSource 直接解释为 Raster/Vector Field source;它当前只处理常规 raster tile/image。
  • 本次未进行设备运行时验证,不能把静态可见接口写成已验证的帧率、延迟或 context-loss 行为。

17.3 候选扩展点(不作最终选择)

  1. Core CustomLayerHost/RenderCustomLayer 的同帧 callback。
  2. Core CustomDrawableLayer + DrawableBuilder/Tweaker/gfx resource。
  3. 新的隔离 Core particle render layer,与现有 RasterLayer/WeatherColorLayer 分离。
  4. 现有 Source/Tile/FileSource/fixture 管线的薄接入,用于离线数据而非直接改造 RasterSource。
  5. 平台薄接入:Android 复用 renderer surface/context 生命周期,iOS 复用 CustomStyleLayer/Metal 或 Core adapter 的同帧 transform。

这些只是调查候选;本报告不决定 CPU/GPU、CustomLayer 最终是否采用、OpenGL/Vulkan/Metal 路线、数据纹理格式、shader 架构或线程模型。

17.4 未确认问题

问题 当前无法确认原因 是否阻塞 20_架构设计 最小确认方式
实际目标产品的 RN 宿主和 binding 版本 不在当前仓库 否;当前阶段可先按 Native Core 事实设计边界 后续由产品宿主提供 package/native 工程清单
Android 业务侧能否稳定创建并持有 CustomLayerHost 当前只有 raw long 示例和 JNI peer 否,但影响平台薄接入细节 单独最小 Android 示例运行验证,不改本阶段代码
iOS 当前正式发布构建究竟启用 OpenGL 还是 Metal 源码同时支持,构建宏由外部工程决定 否;设计需保留 backend 分支 读取目标 Pod/Xcode 构建设置或做最小设备验证
Core render thread 与 iOS app main thread 的确切调度策略 静态源码能确认 DisplayLink/MTKView callback,不能确认目标宿主调度 否 目标 iOS scheme 的运行时线程标记/最小 sample
粒子目标场的具体文件格式、范围、时间步长 fixture 只有占位目录且设计尚未冻结 否;属于后续数据设计输入 由设计阶段冻结离线 fixture contract
目标设备的 GPU 特性、纹理格式和可用 compute 能力 当前没有设备矩阵或运行时探测结果 否;可在设计中标注 capability gate Android/iOS 设备专项最小验证
旋转、pitch、wrap、frustum 下粒子坐标的最终视觉约束 Core matrix 可用,但粒子规则尚未定义 否 进入 20_架构设计 后以 fixture 和截图测试确认

18. 是否追加调查、是否进入 20_架构设计

选择:A,可以直接进入 20_架构设计。

理由:本次已确认项目实际形态、Core 调用链、Android/iOS render lifecycle、CustomLayer/gfx 位置、相机矩阵来源、frame driver、现有数据基础设施和主要风险。未确认项主要是外部目标宿主、运行时设备和未来数据 contract,不满足“必须先追加一个调查任务”的必要条件;它们可作为 20_架构设计 的约束和验证清单。

下一阶段必须继续遵守:不复制 Mapbox 新源码或 Windy APK 代码;粒子模块高度隔离;WeatherColorLayer 与 RasterParticleLayer 分离;Wind=GLOBAL;Wave/Tide/Current=OCEAN_ONLY 并共用 Land/Ocean Mask;第一阶段只使用离线 fixture;平台只做薄接入。

19. 本次未做和边界声明

  • 未创建粒子实现、shader、CustomLayer 实现、Native Module 或架构重构。
  • 未升级/安装 npm、Gradle、Pod 或其他依赖。
  • 未修改 Android/iOS 原生工程、Gradle/Podfile/Metro/Babel/TypeScript 配置。
  • 未运行构建和测试,因为任务明确为只读调查,且构建可能写入产物;历史基线构建 PASS 仅引用已有基线记录,不作为本次重新验证结果。
  • 按用户前置要求,未自行创建或改写 Step 文件;现有 docs/50_Step记录/STEP-000_完整环境初始化_v1.md 的文件内容仍为“进行中”,本报告不改动其历史状态。