Files
MapLibreParticleLab/docs/30_设计/STEP-058_WeatherLocalTargetFps与RepaintGate设计_v1.md
2026-09-07 15:16:18 +08:00

3.7 KiB
Raw Blame History

STEP-058 Weather-local Target FPS 与 Repaint Gate 设计

Host contract

WeatherRuntime.TargetFps 只提供 AUTO、FPS_30、FPS_60,默认 AUTO。WeatherRuntime.setTargetFps() 返回 typed CommandResult,getTargetFps() 返回当前 Host 选择。Host 不接触 RenderLayer、deadline、needsRepaint() 或 renderer requestRender() 细节;未来 RN 只包裹该 facade 方法。

Shared cadence authority

天气 cadence 归 RasterArrayTimelineRuntime 所有,与 source 的 T0/T1、MIX、playback 共存。它保存 target mode、单一 monotonic last cadence tick、deadline 判定和低频 tick 计数。Particle 与 WeatherColor renderer 都读取同一 timeline authority;没有各自 timer 或 gate。AUTO 始终 due,30/60 使用约 33.33/16.67ms 间隔,且 target 切换重置 cadence deadline,不改变 Timeline/field/window。

tick() 仅在 deadline 到达时推进真实 steady_clock elapsed;不把 1/30 或 1/60 写入 simulation delta。这样 particle lifecycle、Trail fade、Timeline playback 和速度仍使用真实 wall time。

Repaint 与 delayed wake-up

RenderRasterParticleLayer::needsRepaint() 与 RenderWeatherColorLayer::needsRepaint() 共享 source timeline 的 due 判定。Android WeatherRuntime 使用已有 MapLibreMap.triggerRepaint() 作为最小 delayed wake-up seam,在 READY 且至少一层需要天气持续动画时按目标间隔唤醒;AUTO 不安装天气 wake-up。Runtime disable/clear、两层 hidden 或错误状态会停止 wake-up。未使用 MapView#setMaximumFps(),因此 camera/其他 layer 仍可保持地图自身帧率。

地图高频 camera frame 在未到 deadline 时只重用现有粒子/Trail composite,不推进 State、Trail、Timeline 或 field upload;天气到 deadline 后两层再次消费同一 cadence。WeatherColor visibility 不依赖 particle visibility:Particle hidden + WeatherColor PLAY 仍可唤醒;两层 hidden、WeatherColor PAUSE 且 Particle hidden 时不持续唤醒。

动态修改与边界

target 切换仅更新 source/timeline cadence,不 reload Style、不重提交 field、不 reset particle State、不 clear Trail、不重建 field texture。clear/disabled 后 timeline 被清空,cadence naturally 无 due frame。Core 保留 canonical U/V、T0/T1/MIX、Runtime Field Window、OLD_T1→NEW_T0 reuse 与 only NEW_T1 upload。

测试策略

cadence deadline 通过显式 steady_clock::time_point/duration 的 deterministic 测试验证,不使用 sleep:AUTO always due、30/60 deadline 前后、target switch 和 single-authority 行为。Android popup 仅作为 Host 模拟器提供 FPS AUTO/30/60 与 HUD 显示;Android Gradle/设备验收另行执行。

STEP-058A shared advance 与 Runtime 生命周期修正

RasterArrayTimelineRuntime::advanceIfDue(now) 在同一 mutex 内完成 due 判定、cadence revision、真实 wall-time Timeline 推进和 frame 返回。Particle 与 WeatherColor 均可作为 consumer;先到者推进,后到者收到相同 cadenceRevision 且不会再次推进。Particle 用 revision 判断是否运行 State/Trail,因而 WeatherColor-only PLAY 不再依赖 Particle pass,也不会发生双 tick。

WeatherColor 在 PLAY 时参与 shared advance;PAUSE 时仅显示当前 frame,needsRepaint() 不主动保持连续刷新。Particle 保持 active 时,即使 Timeline PAUSE,仍按 cadence 推进自身 simulation。两层 hidden 时 facade 不再安装 delayed wake-up。

WeatherRuntime.dispose() 是 map/style-scoped、幂等的 ownership 结束接口:取消 Handler callback,旧 Runnable 被执行时也不会 repaint 或再次 schedule,后续 control API 拒绝或 fail-fast。Test App 在 style reload、离开 REAL WEATHER 与 Activity destroy 前都先 dispose 旧 Runtime。