9.7 KiB
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 生命周期
- map-scoped runtime state 保存 active config、
configSource和单调递增configRevision。 setRenderSegmentPlan()将 active source 切到explicit-render-segment-plan。setContinuousLayerRange()将 active source 切到continuous-range-compat,不会再并存第二套 Renderer topology。- 没有显式配置时,既有
startsRetainedDynamicRange()仅通过unconfigured/legacyadapter 生成兼容 plan。 - RenderOrchestrator 只在 config、Style ready、Layer add/remove/change 时重新解析 boundary ID 和 diagnostics metadata;Particle 高频 Fast Path 不扫描/复制 Style 字符串,也不 stringify JSON。
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 事实。