fix(plotview): 修复面板条目栏悬停时预览曲线高亮丢失 + 极端工况绘制管线提速

一、悬停高亮回归修复
- 根因:高亮画在预览曲线绘制路径里,而该路径在命中静态场景缓存时完全不会被调用
  (悬停态又不参与 SceneContentHash),因此缓存命中帧永远看不到高亮。
- 修法:拆出 PaintDerivedCurvesFor(hoverOnly) 两态,新增 PaintDerivedHoverHighlight,
  在 paintOverlays() 中紧跟 PaintHoverHighlight 以前景方式绘制(面板之下、光标之上)。
  高亮仍按面板种类(均值滤波/中心轴/弱峰调整)分别判定。

二、预览曲线绘制重写(单条 15ms → 1.7ms)
- 稠密区间改用与波形基底同一套「逐像素列 min/max 包络带」+ 一次 FillPath;
  旧抽稀折线在稠密视界下每段都是竖直满幅,GDI+ 描边代价正比于覆盖像素数
  (3200 顶点满幅锯齿抗锯齿 128ms / 无抗锯齿 31ms,包络带 1.9ms)。
- 列密度自适应:中等密度 2px/列,极密(>8 采样/像素)4px/列。
- 稀疏区间保持逐点折线;附带修复「等间隔抽样漏掉尖峰」。

三、预览曲线像素缓存层(Picture cache + pan roll)
- 45 条曲线画进带 alpha 的 32bpp DIB,正常帧只做一次 AlphaBlend(1~2ms)。
- 纯平移时整行 memmove 一个 dx 并只重画新露出的竖带(与宽缓冲区滚动同构),
  因此拖动视界的每帧代价与信号数无关。
- 内容指纹 = SceneContentHash(含样式/派生参数/网格几何) ⊕ 曲线发布序号;高亮不进指纹。

四、其他热点
- 光标取值胶囊不再逐帧重算并发布 45 条曲线(CurveSpanFor 新增 computeIfMissing),
  只取已覆盖的缓存曲线,未命中退到最新曲线或本帧不标注。
- 样式补丁路径不再同步重建网格图层(宽基底 2 倍宽 × 2 倍高,实测单次 2.2 秒),
  且开启派生功能时直接走整幅重绘(补丁会覆盖缓存中已烘入的曲线像素)。

实测(15 信号合并一条网格 + 全部实验性功能,1600x900 离屏探针):
拖动视界 264→5.9ms,双光标拖动 187→20.9ms,弱峰滑块 555→89ms,
改信号颜色 2661→200ms,悬停面板行 225→38ms,深放大拖动 207→23.8ms。
全屏 1920x1080:拖动视界 9.3ms。

验证:新增离屏探针 p27 8/8(悬停高亮在缓存命中帧可见、平移/缩放/改颜色后的叠加层
与「完全重画」参考帧逐像素一致 diff=0);p20 9/9、p21 9/9、p22 14/14、p23 8/8、p25 12/12;
make release / make debug 零 warning;Release 814,080 B。规则已同步到 Documents/agent_mem.md。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-11-02 18:47:21 +08:00
1 parent ea704b03ea
commit 0c320cf1b3
6 files changed
+797 -33

No files matched your search

@@ -57,6 +57,32 @@ namespace jdi
inline const size_t kMaxPolylinePoints = 20000; /**< 单条折线最大顶点数(上限保护)。 */
inline const size_t kPolylinePointsPerPixel = 2; /**< 每个像素列允许的折线顶点数(上/下包络两顶点)。 */
inline const size_t kMinPolylinePoints = 512; /**< 折线最少顶点数(窗口很窄时仍保留细节)。 */
/**
* @brief 派生预览曲线走「逐像素列包络带」时,每列抽样几个采样。
*
* 稠密视界(可见采样数 > 像素列数)下预览曲线若按抽稀折线绘制,相邻顶点的 y
* 会整幅跳变 ⇒ GDI+ 描边代价 ∝ 覆盖像素数,实测单条曲线 76~128ms。
* 改为逐列记录上下包络后一次 FillPath,单条曲线降到约 2ms(约 60 倍)。
* 每列抽样 4 个点即可得到饱满的包络(再多只影响饱满度,不影响代价量级)。
*/
inline const size_t kDerivedCurveSamplesPerColumn = 4;
/**
* @brief 派生预览曲线包络带的**列密度分母**:每 N 个设备像素一列。
*
* 包络带的填充代价主要取决于**边数**与**覆盖面积**(实测同一形状 1600 列 ≈ 24ms、
* 400 列 ≈ 6.4ms):预览曲线是半透明叠加层、且本来就是“逐列 min/max”的聚合结果,
* 横向 4px 的分辨率损失在稠密视界下不可辨(尖峰仍不会丢:每列取的是该列的极值)。
* 稀疏区间仍走逐点折线(见 `PaintDerivedCurve`),不受影响。
*/
inline const size_t kDerivedCurveColumnDivisor = 4;
/**
* @brief 判定“极密视界”的采样密度阈值(采样/设备像素),超过时包络带列密度降到
* `kDerivedCurveColumnDivisor`,否则用 2 像素一列。
*
* 中等密度(1~8 采样/像素)下预览曲线形状本身还有细节,用 2 像素一列即可保住观感;
* 极密视界下每列内部就是一条满幅噪声带,4 像素一列肉眼无差别、代价再降一半。
*/
inline const size_t kDerivedCurveVeryDenseSamplesPerPixel = 8;
/**
* @brief 图层**纵向滚动**的量化阈值(位图像素)。
*