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:
1 parent
ea704b03ea
commit
0c320cf1b3
6 files changed
+797
-33
No files matched your search
@@ -2020,7 +2020,8 @@ namespace jdi
|
||||
int points, int iterations, int amountPercent,
|
||||
std::size_t begin, std::size_t end,
|
||||
std::size_t& spanBegin,
|
||||
bool allowAsyncCompute) const
|
||||
bool allowAsyncCompute,
|
||||
bool computeIfMissing) const
|
||||
{
|
||||
spanBegin = 0;
|
||||
const std::size_t count = signal.values.size();
|
||||
@@ -2058,6 +2059,34 @@ namespace jdi
|
||||
return &hit->values;
|
||||
}
|
||||
|
||||
// 1b) 「只读」模式(光标取值胶囊):**绝不新建计算任务 / 条目**。
|
||||
if (!computeIfMissing)
|
||||
{
|
||||
if (const CurveEntry* stale = AcquireNewestCurve(key, begin, end, spanBegin))
|
||||
{
|
||||
return &stale->values;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 1b) “只读”模式(光标取值胶囊):**绝不新建计算任务/条目**。
|
||||
//
|
||||
// ⚠️⚠️ 为什么必须这么做(用户 2026-11-02 反馈“拖光标时有明显卡顿”):
|
||||
// 胶囊只为“光标所在的那两个采样”取值,请求窗口只有几个采样 —— 但缓存键里含窗口,
|
||||
// 而窗口随光标每帧都在变 ⇒ 每帧都未命中 ⇒ 每帧同步计算并 `PublishCurve` 一次。
|
||||
// 15 信号 × 3 种曲线 = 每帧 45 次发布,条目列表不断变长,`Acquire*` 的线性搜索
|
||||
// 也随之变慢(实测拖动光标单帧 200ms,其中约 150ms 来自这 45 次重算 + 发布)。
|
||||
// 现在:命中就取(绘制路径发布的窗口**带保护带**、覆盖整个可见区间,正常情况一定命中),
|
||||
// 没命中就退到同 (信号, 种类) 的最新曲线,再没有就本帧不标注。
|
||||
if (!computeIfMissing)
|
||||
{
|
||||
if (const CurveEntry* stale = AcquireNewestCurve(key, begin, end, spanBegin))
|
||||
{
|
||||
return &stale->values;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 2) 代价较大时交后台计算,本帧先用最新旧曲线顶替(双缓冲)。
|
||||
// 这样绘制线程永远不做重计算,拖动滑块/光标/视界/缩放的反馈因此始终跟手。
|
||||
//
|
||||
|
||||
Reference in new issue
Block a user