288 信号卡顿根治 + 中心轴面板重做 + 标签页默认状态
一、卡顿真因(实测 29.8ms/帧 → 6.6ms/帧) 1. 中心轴面板高度没有上限:288 个信号时面板高 9996px(绘图区只有 1141px) ⇒ PanelRectInsideLayer 恒为假 ⇒ 面板像素缓存一次都存不进去 ⇒ 每帧全量重画。 2. PanelGlobalKey 混入鼠标驱动状态(m_hoverSignal / m_hoverLane / m_hoverCursor / CursorTime / EdgeRangeMin/Max)⇒ 鼠标一动键就变 ⇒ 所有面板每帧重画; PanelSlotKey 里还会为每个信号调一次 EdgeCenterCountsFor(单帧 288 次查询)。 3. 缓存命中路径的投影(与面板同大的半透明抗锯齿圆角矩形)每帧重画,GDI+ 实测 > 20ms。 修法: * 新增 PlotView::InputIsInteractive()(拖拽中 / 鼠标 140ms 内移动过)。交互期间冻结 全部鼠标驱动项与统计数字、跳过投影、统计预算降到 8 万(静止时 40 万)。 m_meanRowHoverLane/Ref 例外 —— 它直接改面板像素且只在进出某行时变化。 * kEdgeScanPairsPerFrame 由 1,200,000 降为 400,000。 * 中心轴面板重做为可滚动列表 ⇒ 面板高度被绘图区夹住、缓存可用、只画可见行。 二、「中心轴边沿计数」面板重做(与「均值滤波」同风格) 条目栏为信号色叠底的可折叠栏 + 右端复选框;栏下同一行显示「上升沿 / 下降沿」; 再下面两行滑块(均值点数 / 迭代次数,标签不带 X/N),数值可点击输入上限、 右侧复位按钮;整个面板可滚动;未勾选时条目栏不可展开。 新增 Lane::edgeCenterScroll + SetLaneEdgeCenterScroll;交互复用 MEAN_* 拖拽模式 + m_meanDragCenter / m_editMeanCenter 标志分派;光标形状与均值滤波一致。 三、标签页 * 唯一标签页点 ✕ 不再弹警告:直接 erase 后 NewTab(true),名字必然为「视图 1」。 * 新建标签页(含手动新建)默认:组全部折起、无选中信号(清空全局 Selected)、 样式区无目标。 四、验证 .preflight/bugcheck.exe 59/59(A1 空闲 0.7ms、A2 平移 2.5ms、A3 双光标 2.4ms、 A4 自由标记 5.2ms、A5 中心轴拖动 6.6ms;B3 真实 WM_TIMER+WM_PAINT 路径; B5 快速连点与动画反向;C 中心轴面板交互;D 标签页默认状态) panelcheck 71/71、markercheck 13/13、ringcheck 6/6 make release / make debug 零 warning
This commit is contained in:
1 parent
8271879ede
commit
944c074ab3
11 files changed
+618
-122
No files matched your search
@@ -8941,3 +8941,115 @@ rendercheck 8 个场景哈希与基线完全一致;make release / make debug
|
||||
白改了一轮断言。
|
||||
* ⚠️ PowerShell 里用 `'...'` 拼接含 `%d` / 引号 / 长中文的补丁串极易被截断(出现 `>>` 续行提示后
|
||||
只能 Ctrl+C)。**补丁一律写成 `.git\xxx.ps1`(纯 ASCII)+ `%TEMP%\xxx.txt` 数据文件**。
|
||||
|
||||
---
|
||||
|
||||
## 2026-11-02 第十九轮(本机):288 信号卡顿根治 + 中心轴面板重做 + 标签页默认状态
|
||||
|
||||
### 1. 卡顿真因:**面板缓存键把"鼠标驱动的一切"都混了进去**
|
||||
|
||||
复现:`VERY_BIG_DATA.CSV` + `MF4-Record.MF4` 全部信号合并到**同一网格**(288 信号),
|
||||
开「中心轴边沿计数」后拖动横向光标/移动鼠标,实测 **29.8ms/帧**(修复后 **6.6ms**)。
|
||||
|
||||
分解(`.preflight/bugcheck.exe` A5b):
|
||||
|
||||
| 场景 | 单帧 |
|
||||
| --- | --- |
|
||||
| 面板开 + 统计开 | 27.6ms |
|
||||
| **面板关 + 统计开** | **4.1ms** |
|
||||
| 面板关 + 统计关 | 6.6ms(噪声) |
|
||||
|
||||
⇒ 27.6−4.1 ≈ **23ms 全在面板绘制**,而**不是**统计扫描。三个叠加原因:
|
||||
|
||||
1. ⚠️⚠️ **中心轴面板高度没有上限**:`itemized` 旧分支按"每个勾选信号两行 + 每行 22px"
|
||||
累加,288 个信号 ⇒ **面板高 9996px**(绘图区只有 1141px)。`PanelRectInsideLayer()`
|
||||
因此永远为假 ⇒ **面板像素缓存一次都存不进去** ⇒ 每帧全量重画 288 行。
|
||||
2. ⚠️⚠️ **`PanelGlobalKey` 混入鼠标驱动状态**:`m_hoverSignal` / `m_hoverLane` /
|
||||
`m_hoverCursor` / `Tab().CursorTime()` / `EdgeRangeMin/Max` 等只要鼠标一动就变
|
||||
⇒ `panelGlobalSame` 每帧为假 ⇒ 所有面板每帧重画。而 `PanelSlotKey` 里还会为**每个信号**
|
||||
调一次 `EdgeCenterCountsFor`(含区间边界块扫描)⇒ 单帧 288 次查询。
|
||||
3. 缓存命中路径里的**投影**(与面板同大的半透明抗锯齿圆角矩形,400×950px)每帧重画,
|
||||
GDI+ 软件渲染实测 > 20ms。
|
||||
|
||||
**修法**:
|
||||
* 新增 `PlotView::InputIsInteractive()`(正在拖拽、或鼠标在 `kEdgeScanInteractiveIdleMs`
|
||||
= 140ms 内移动过)。**交互期间**:
|
||||
- `PanelGlobalKey` 冻结全部鼠标驱动项(`m_hoverSignal` / `m_hoverLegend` / `m_hoverLane` /
|
||||
`m_hoverCursor` / `m_cursorHover` / `CursorTime` / `EdgeRangeMin/Max`)与
|
||||
`mouseDrivenOverlay`;`PanelSlotKey` 跳过整段边沿统计数字;
|
||||
- 缓存命中路径**跳过投影**;`m_edgeScanBudget` 用 `kEdgeScanPairsPerFrameInteractive`(8 万,
|
||||
静止时 40 万)。
|
||||
- ⚠️ **`m_meanRowHoverLane/Ref` 必须例外**:它直接改变面板像素、且只在进出某一行时变 ——
|
||||
一起冻结的话"鼠标移到条目栏上高亮"就永远不出现。
|
||||
- 鼠标停下 140ms 后键自动恢复 ⇒ 面板重画一次显示最终数字(不会"停在统计中")。
|
||||
* 统计预算 `kEdgeScanPairsPerFrame` **1,200,000 → 400,000**(中心轴每个采样对还要按
|
||||
`均值点数 × 迭代次数` 算一次均值窗口 ⇒ 120 万对 ≈ 3 千万次浮点运算/帧)。
|
||||
* **中心轴面板重做为可滚动列表**(见第 2 节)⇒ 面板高度被 `m_plotRect.Height` 夹住、
|
||||
缓存能存进去、只画可见行。
|
||||
|
||||
### 2. 「中心轴边沿计数」面板重做(与「均值滤波」完全同风格)
|
||||
|
||||
用户要求:条目栏是**信号色叠底的折叠栏**、右端复选框代表"是否统计该信号"、栏下**同一行**
|
||||
显示「上升沿 / 下降沿」、再下面两行滑块(均值点数 / 迭代次数,标签不带 X/N)、
|
||||
数值可点击输入上限、右侧复位按钮、整个面板可滚动、**未勾选时条目栏不可展开**。
|
||||
|
||||
实现要点:
|
||||
* `EdgePanelLayoutFor`:`listStyle = (meanFilter || centerAxis)` 取代原来的 `if (meanFilter)`;
|
||||
`itemized` 现在**只剩** `weakPeak`。中心轴的内容 = 条目栏 + (勾选且未收起时)
|
||||
**统计行 + 两行滑块**(统计行在 `rowStats`,滑块复用 `rowLevel*` / `rowIter*`)。
|
||||
* 新增 `Lane::edgeCenterScroll`(+ `LaneCarry` 同步)+ `PlotView::SetLaneEdgeCenterScroll()`。
|
||||
滚动偏移通过 `layout.scrollOffset` 自动进 `PanelSlotKey`(无需额外 mix)。
|
||||
* 滑块最大值:**均值滤波 = 1**(用户 2026-10-30 要求不能为 0),**中心轴 = 0**
|
||||
(0 = 不平滑,直接对原始值统计边沿,保持旧语义)。
|
||||
* 交互复用 `PlotDragMode::MEAN_POINTS / MEAN_ITERATIONS / MEAN_SCROLL` + 新标志
|
||||
`m_meanDragCenter`(拖拽/滚动目标面板)+ `m_editMeanCenter`(上限输入目标面板);
|
||||
复位按钮、点击数值改上限、滚轮翻页、光标形状(条目栏/数值/复位=手型,滑块=左右箭头,
|
||||
滚动条=上下箭头)全部共用同一段代码。
|
||||
* 参数/勾选变化必须 `InvalidateEdgeScansFor(signal, true)`(定向作废,避免"改一个参数
|
||||
其它信号也重算")。
|
||||
|
||||
### 3. 标签页
|
||||
|
||||
* ⚠️ **唯一标签页点 ✕ 不再弹警告**:`CloseTab` 在 `m_tabs.size() <= 1` 时直接 erase 再
|
||||
`NewTab(true)` ⇒ 名字必然是「视图 1」(`m_tabs` 清空后 `NextTabName()` 取最小未占用编号)。
|
||||
⚠️ erase 与 `NewTab` 之间**不要**碰 `m_panel` / `m_plot`(上下文仍指向已释放的 `TabConfig`)。
|
||||
* **新建标签页的默认状态**(手动新建也走同一入口):`NewTab()` 里新增
|
||||
`m_dataSet.SetSelected(SignalRef())` —— 选中状态是**全局共享**的,不清掉的话新页会带着
|
||||
上一个页的选中信号 ⇒ 样式编辑区有自己的"目标"。清空后样式区回到「未选择信号」。
|
||||
组全部折起由 `SetGroupsCollapsedByDefault(true)` + `SetAllCollapsed(true)` 保证(既有行为)。
|
||||
|
||||
### 4. 顺带修正
|
||||
|
||||
* `PanelGlobalKey` 里 `m_hoverCursor/m_cursorHover/m_hoverLane` 也纳入交互冻结(只影响叠加层)。
|
||||
* 光标形状:`QueryCursor` 对 MEAN/CENTER 可滚动列表补上条目栏/数值/复位/滑块/滚动条的
|
||||
手型与箭头(原来只有 PEAK 有)。
|
||||
|
||||
### 5. 验证
|
||||
|
||||
```
|
||||
.preflight/bugcheck.exe 59/59
|
||||
A1 空闲 0.7ms · A2 平移 2.5ms · A3 双光标 2.4ms · A4 自由标记光标 5.2ms
|
||||
A5 中心轴拖动 6.6ms(修前 29.8ms)
|
||||
A5b 分解:面板开 5.7ms / 面板关 4.9ms / 无光标 7.2ms;面板 460.5px(修前 9996px)
|
||||
B 组名展开/收起(283 行):行集合 0 ↔ 283、签名自洽
|
||||
B3 真实消息路径(WM_LBUTTONDOWN/UP + WM_TIMER + WM_PAINT):展开 90 帧 / 收起 95 帧
|
||||
B5 快速连点 3 次 / 动画中途反向:三角与行集合始终一致
|
||||
C 中心轴面板:未勾选条目栏点击无效 / 复选框启用 / 整行收起展开 /
|
||||
拖滑块 90% → 45 点 / 复位 → 5 点且上限 50 / 滚轮滚动 60px
|
||||
D 唯一标签页关闭 → 「视图 1」+ 全折起 + 无选中;手动新建同样
|
||||
.preflight/panelcheck.exe 71/71 markercheck.exe 13/13 ringcheck.exe 6/6
|
||||
make release / make debug 零 warning
|
||||
```
|
||||
|
||||
### 6. 踩坑
|
||||
|
||||
* ⚠️⚠️ **`PaintEdgeCursor` 的"笨重"必须先分段测量**:本轮一开始把 30ms 归因于"统计扫描"
|
||||
和"统计数字进缓存键",改了预算与键都不见效;直到做了「面板开/关」「统计开/关」的
|
||||
A/B 才定位到**面板高度超界 ⇒ 像素缓存从未命中**。**判据要用"缓存是否真的被用上"
|
||||
(`m_panelSlots[0].key != 0` + `PanelRectInsideLayer`),而不是"看起来像重画"**。
|
||||
* ⚠️ 探针里模拟点击面板前**必须关掉其它实验性功能**:它们默认位置同样在绘图区右上角,
|
||||
`TopPanelAtPoint` 只返回最上层那一个 ⇒ 命中全被另一个面板抢走(表现为"点了没反应")。
|
||||
* ⚠️ 组名行的点击热区:`X = 行矩形 40%` 处是名称(BODY),`x = 40px` 附近是**复选框**
|
||||
(`RowPart::CHECK`)—— 想测折叠必须点名称区。
|
||||
* ⚠️ 「行集合签名是否稳定」不能作为断言:动画**结束那一帧**签名必然变化一次(动画标记位
|
||||
从 5 → 0),这是正确的。要断言的是"动画结束后 `m_rowsSignature == RowsSignature()`"。
|
||||
Reference in new issue
Block a user