Files
MapLibreParticleLab/docs/30_设计/STEP-094_通用RenderSegment模型与Style分类Diagnostics设计_v1.md
tei 9d1f66c169
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
docs: close STEP-094 render segment validation
2026-09-25 13:56:50 +09:00

9.7 KiB
Raw Permalink Blame History

STEP-094 通用 Render Segment 模型与 Style 分类 Diagnostics 设计 v1

1. 目标与边界

Renderer 只接收 Style 顺序和一组连续 Segment 定义。每个 Segment 的执行策略只有 RETAINED 或 CONTINUOUS;不引入 LOW/MEDIUM/HIGH,不识别 AIS、Route、Weather 等业务语义,不改变 Style Z-order,也不增加 Anchor/Marker Layer。

V12 的 Bottom Retained / Continuous / Top Retained 是本模型的兼容特例。新实现只有一套 resolved topology;旧 setContinuousLayerRange() 先转换为通用 Segment Plan,再进入同一 Renderer 路径。

2. 公共数据模型

Core 公共类型位于 include/mbgl/renderer/render_segment.hpp:

RenderSegmentPlan
  schemaVersion = 1
  segments[1..N]
    strategy = RETAINED | CONTINUOUS
    startLayerId = 第 1 段省略;后续段必填

RN 公共类型位于 packages/maplibre-particle-rn/src/types.ts,RendererRuntime.setRenderSegmentPlan(reactTag, plan) 接收 typed object。TurboModule、Android/iOS package bridge 与 platform API 内部使用 schema-versioned JSON,JS 调用方不接触 raw JSON。

3. Config / Resolve 生命周期

  1. map-scoped runtime state 保存 active config、configSource 和单调递增 configRevision。
  2. setRenderSegmentPlan() 将 active source 切到 explicit-render-segment-plan。
  3. setContinuousLayerRange() 将 active source 切到 continuous-range-compat,不会再并存第二套 Renderer topology。
  4. 没有显式配置时,既有 startsRetainedDynamicRange() 仅通过 unconfigured/legacy adapter 生成兼容 plan。
  5. RenderOrchestrator 只在 config、Style ready、Layer add/remove/change 时重新解析 boundary ID 和 diagnostics metadata;Particle 高频 Fast Path 不扫描/复制 Style 字符串,也不 stringify JSON。
  6. topologyRevision 只在 resolved strategy/begin/end 签名变化时递增。Visibility 变化更新 visible,不改变 topology revision。

显式 plan 合法条件:definitions 非空;第 0 段无 boundary;第 1..N-1 段 boundary 存在、非空且 index 严格递增;每段非空;完整覆盖 [0, layerCount)。失败时 segments 为空、valid=false、释放旧 cache 并走 full renderer;ordered styleLayers 仍可读取。

4. V12 Compatibility Mapping

旧闭区间 [startLayerId,endLayerId] 解析为:

startIndex > 0                -> RETAINED   [0,startIndex)
                               CONTINUOUS [startIndex,endIndex+1)
endIndex+1 < styleLayerCount  -> RETAINED   [endIndex+1,layerCount)

因此自然退化为 R-C-R、R-C、C-R 或 C。configSource=continuous-range-compat。旧 getRetainedUnderlayDiagnostics() 继续保留摘要;多段真实事实以新 API 为准。

5. Renderer 执行与 Cache Ownership

Resolved Segment 保留 Style 全局 layerIndex 和 LayerGroup 原 ordinal。Retained 构建继续使用 opaque reverse / translucent forward;Continuous 直接绘制同一全局 index 范围。parameters.currentLayer 和 depthRangeSize 不按 Segment 重新编号。

Renderer 按 resolved topology 动态创建 retainedSegmentCaches[segmentIndex]:

  • RETAINED:独立 RetainedUnderlayCache、key、revision、texture、compositor 和 counters;
  • CONTINUOUS:对应 slot 为空,不创建 retained texture/FBO/compositor;
  • topology 改变:旧 cache 在 Renderer 线程释放,不能迁移或 composite stale resource;
  • GPU resource 仍由 prepareResources() lazy 创建,稳定 viewport 复用。

主 buffer 按 Segment 顺序执行:Retained composite 或 Continuous direct render。相邻同策略不会合并。

6. Invalidation

Layer immutable Impl identity 与全局 Style index 组成 retained Segment content fingerprint。Layer property/visibility 在某 retained Segment 内变化时,只推进该 Segment 的 content revision;其他 retained Segment 可继续 reuse。

以下仍保守 invalidate 全部 retained Segment:camera/viewport/pixel ratio、source/tile、image/sprite/glyph、placement/transition、context reset、debug/3D、style reload、resource/compositor failure。原因是当前 Core 没有足够稳定的通用 source-to-render-segment dependency graph;本 Step 不扩建该图。

7. Particle Fast Path

恰好一个 Continuous Segment、其内容满足既有 Particle-only 支持条件、所有实际 Retained cache 有效时,沿用 V12 Fast Path。缺少某个不存在的 retained cache 不构成 miss。

多个 Continuous Segment 暂不做高级 Fast Path:gate 以 unsupported-continuous-layer fail closed,进入正常 full CPU frame;Segment topology、cache 与 Z-order 不变。

8. Android / iOS / RN API

RN RendererRuntime
  setRenderSegmentPlan(reactTag, typedPlan)
  getRenderSegmentDiagnostics(reactTag)
        ↓ schemaVersion=1 JSON transport
WeatherRuntimeBridge(既有唯一 bridge)
        ↓
Android MapLibreMap / iOS MLNMapView
        ↓
mbgl::Map typed RenderSegmentPlan / RenderSegmentDiagnostics
        ↓
RetainedUnderlayRuntimeState + RenderOrchestrator + RendererImpl

Android platform 内部 API 为 setRenderSegmentPlan(String) / getRenderSegmentDiagnostics();iOS 为 setRenderSegmentPlanJSON: / renderSegmentDiagnosticsJSON。Core API 保持 typed。JSON/schema/strategy 非法时返回 REJECTED,同时把 active topology 置 invalid,避免继续复用旧 cache。

9. Diagnostics Schema

Snapshot 为 pull-based。顶层包含 enabled/configured/valid/configSource/configRevision/topologyRevision/counts/coverage/fallback/reason/Fast Path counters;styleLayers[] 始终按 Style 顺序;segments[] 包含 begin/end、实际 Layer 成员。Retained 的 cache 为 object;Continuous 的 cache=null,不会伪装为 disabled retained cache。

完整示例:

{
  "schemaVersion": 1,
  "enabled": true,
  "configured": true,
  "valid": true,
  "configSource": "explicit-render-segment-plan",
  "configRevision": 7,
  "topologyRevision": 4,
  "styleLayerCount": 6,
  "segmentCount": 4,
  "retainedSegmentCount": 3,
  "continuousSegmentCount": 1,
  "coverageComplete": true,
  "fallback": false,
  "lastReason": "none",
  "fastPathEligible": true,
  "fastPathActive": true,
  "fastPathFallbackReason": "none",
  "fastPathHit": 120,
  "fastPathMiss": 3,
  "fullCpuFrame": 4,
  "styleLayers": [
    {"layerIndex":0,"layerId":"background","layerType":"background","visible":true,"sourceId":null,"sourceLayer":null},
    {"layerIndex":1,"layerId":"water","layerType":"fill","visible":true,"sourceId":"chart","sourceLayer":"water"},
    {"layerIndex":2,"layerId":"rn-weather-color","layerType":"weather-color","visible":true,"sourceId":"rn-weather-fields","sourceLayer":null},
    {"layerIndex":3,"layerId":"rn-weather-particles","layerType":"raster-particle","visible":true,"sourceId":"rn-weather-fields","sourceLayer":null},
    {"layerIndex":4,"layerId":"land-area","layerType":"fill","visible":true,"sourceId":"chart","sourceLayer":"land"},
    {"layerIndex":5,"layerId":"ais-layer","layerType":"symbol","visible":true,"sourceId":"ais","sourceLayer":null}
  ],
  "segments": [
    {"segmentIndex":0,"strategy":"RETAINED","configuredStartLayerId":null,"beginIndex":0,"endExclusive":2,"resolvedStartLayerId":"background","resolvedEndLayerId":"water","layerCount":2,"layers":[{"layerIndex":0,"layerId":"background","layerType":"background","visible":true,"sourceId":null,"sourceLayer":null},{"layerIndex":1,"layerId":"water","layerType":"fill","visible":true,"sourceId":"chart","sourceLayer":"water"}],"cache":{"cacheState":"reuse","contentRevision":19,"build":1,"reuse":120,"invalidation":0,"lastInvalidationReason":"none","textureCreate":1,"compositeCreate":1,"resourceRelease":0}},
    {"segmentIndex":1,"strategy":"CONTINUOUS","configuredStartLayerId":"rn-weather-color","beginIndex":2,"endExclusive":4,"resolvedStartLayerId":"rn-weather-color","resolvedEndLayerId":"rn-weather-particles","layerCount":2,"layers":[{"layerIndex":2,"layerId":"rn-weather-color","layerType":"weather-color","visible":true,"sourceId":"rn-weather-fields","sourceLayer":null},{"layerIndex":3,"layerId":"rn-weather-particles","layerType":"raster-particle","visible":true,"sourceId":"rn-weather-fields","sourceLayer":null}],"cache":null},
    {"segmentIndex":2,"strategy":"RETAINED","configuredStartLayerId":"land-area","beginIndex":4,"endExclusive":5,"resolvedStartLayerId":"land-area","resolvedEndLayerId":"land-area","layerCount":1,"layers":[{"layerIndex":4,"layerId":"land-area","layerType":"fill","visible":true,"sourceId":"chart","sourceLayer":"land"}],"cache":{"cacheState":"ready","contentRevision":22,"build":2,"reuse":80,"invalidation":1,"lastInvalidationReason":"layer-mutation","textureCreate":2,"compositeCreate":2,"resourceRelease":1}},
    {"segmentIndex":3,"strategy":"RETAINED","configuredStartLayerId":"ais-layer","beginIndex":5,"endExclusive":6,"resolvedStartLayerId":"ais-layer","resolvedEndLayerId":"ais-layer","layerCount":1,"layers":[{"layerIndex":5,"layerId":"ais-layer","layerType":"symbol","visible":true,"sourceId":"ais","sourceLayer":null}],"cache":{"cacheState":"reuse","contentRevision":11,"build":1,"reuse":40,"invalidation":0,"lastInvalidationReason":"none","textureCreate":1,"compositeCreate":1,"resourceRelease":0}}
  ]
}

有效 snapshot 保证 Segment layers 拼接等于 styleLayers,Layer 不重号、不遗漏、不重复。RN Test Host 的按钮只在用户操作时配置/拉取并显示一次完整 JSON,不轮询、不逐帧打印。

10. 当前限制

  • 多 Continuous 只保证正确 full renderer,不提供高级 Particle Fast Path。
  • Source/Tile mutation 尚无通用 dependency graph,仍全 retained invalidation。
  • Legacy diagnostics 只是兼容摘要,不能表达任意 N Segment。
  • OpenGL/Metal 编译、Native tests、Android codegen/Gradle 与设备运行由 RDC 独立验证后才能形成 PASS 事实。