修复上下拖动时的绘制异常/抽搐(纵向预渲染补齐)+「弱峰增强」升级为「弱峰调整」(-200%–+200%)

一、纵向绘制异常/抽搐的根因
上一轮给图层加了「上下各半个网格高」的纵向预渲染余量,但"偏移超出余量"时仍走**排队整块重画**
(一帧只补一个网格):重画生效前 BlitWideBuffer 只能贴出有像素的那一部分,其余行留在底色上
= 网格内出现空白条带("绘制错误");且重画后的锚点与"贴图偏移"不同源 = 波形"没按预期移动"。
鼠标按在最上方网格一路拖到窗口最下方(离开网格很远)时,每帧的幅值位移都远超余量 → 每帧触发整块
重画 = 抽搐;左右拖动时若鼠标同时有纵向位移,同样触发。

二、修法:与横向完全同构的纵向滚动
- RenderLaneLayerRegion 增加 stripY/stripH(纵向条带),可只补画"新暴露的一整条"。
- RollWideBuffer 新增纵向滚动:BitBlt 整块上/下移 roll 行 → 补画暴露的那一条 →
  layer.anchorYMax -= roll / pxPerValue(与横向 wideMin 同一套记账)。
  必须在横向补条之前(横向补条会用当前 yMax 重置图层锚点,顺序反了细条会带上错的纵向偏移)。
- 滚动量量化(kLayerRollQuantum = 16 像素):不足量子的偏移不滚,交给贴图的 srcY 偏移处理,
  使画布映射在拖动中保持稳定、折线缓存(键含幅值映射)得以命中。
  未量化时"每帧滚 1~30 行"会让折线每帧重算(实测滚动 3~4ms + 整帧 10~14ms)。

三、「弱峰调整」(原「弱峰增强」)
- 术语统一:ComputeWeakPeakAdjust、WeakPeakItem.amountPercent(-200–200,默认 150)、面板标题
  「弱峰调整」、标签「调整幅度 %」、光标胶囊尾缀、构建信号名「<原信号> (弱峰调整 X% M次迭代)」。
- 滑块量程 -200% – +200%,0 在正中间(ratio = (amount/200 + 1) / 2);数值列加宽以容纳 "-200%"。
- 目标值(识别规则与旧实现完全相同;amount = 幅度/100):
  *  0 ≤ a ≤ 1:当前值 → 同类极值中较温和的一侧;
  *  1 < a ≤ 2:该侧 → 另一侧(与旧实现逐位一致);
  * -1 ≤ a < 0:当前值 → 相邻异类极值中较近的一个(波峰看较高的波谷、波谷看较低的波峰);
  * -2 ≤ a < -1:较近的异类极值 → 较远的那个(弱峰被压平甚至抹除,左右平滑过渡)。
- 负幅度不得反向增强:目标夹在"不越过当前值"的一侧。平滑偏移的逐点过渡逻辑未改动。

四、验证(全部离屏,不占用鼠标/键盘/屏幕)
- uitest 443/443:[X] 正幅度 0/50/100/150/200% → 峰 550/555/560/580/600(旧值逐位保持)、
  谷 450/445/440/420/400;新增负幅度 -50/-100/-200% → 峰 500/450/400、谷 500/550/560;
  超范围夹取、"未反向增强"(极值点)、健康峰不动;滑块中间 = 0%、拖出两端 = ±200%;
  构建信号名含「弱峰调整」;[AH] 纯竖直拖拽 16 帧仅 2 次图层重画。
- panperf:拖出网格 900px + 对角平移 31 帧,被拖网格的空白行数与整幅重绘逐帧一致(64 vs 64
  → 无空白条带),帧时 10~13ms,末帧差异与水平基线同量级(已知的 ≤0.5px 整数像素残差)。
- layercheck:clobbers=0/24、pan frames wrong=0/4、居中图层 vs 整幅重绘逐像素 0 差异;
  cursorcheck 30/30;make clean && make all 零警告。
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-10-12 17:10:51 +08:00
1 parent cb030573fa
commit ff3319b842
7 files changed
+380 -224

No files matched your search

+40
View File
@@ -514,6 +514,7 @@ Documents/ 项目文档(含本文件)
| 2026-10-12 | DeepSeek-V4.1-Flash(**起源设备**) | 弱峰增强的参数输入改回**逐信号滑块**(每信号两条轨道:增强等级 0–200% / 迭代次数 N),并让「迭代次数 N」**上限可就地编辑**:点击滑块右侧数值 → 整行变成输入框(`EditFilter::BYTE` 只收数字、空内容显示灰提示当前上限、`0`/超限/空 保持原值、下调后当前迭代次数自动被夹到新上限);上限进 `PanelSlotKey` 但不进 `SceneContentHash`(不影响波形重画)。离屏测试 **409/409 通过**。 |
| 2026-10-12 | DeepSeek-V4.1-Flash(**起源设备**) | **修复"斜向/不规则拖拽自由移动视界时的卡顿、掉帧与波形错误绘制"、"预览曲线不如普通信号细腻(无抗锯齿)"、"拖动参数滑块时预览曲线跳帧闪烁"**。① 根因:拖拽平移的**纵向分量**会逐帧小改被拖网格的 `yMin/yMax`,而**网格幅值范围同时参与「宽基底可用性」几何指纹与每个网格的图层键**,于是每帧都退化成整幅重绘(`m_fastFrame` 关抗锯齿)+ 5 个网格全部入队(一帧只补 1 个)→ 质量下降、卡顿、图层相互不一致(断线)。修法:`SceneContentHash` 新增 `includeLaneRange`(`SceneGeometryHash()` = `false,true,false`,幅值不进"能不能走快路径"的判定),幅值改由**逐网格** `LaneLayerHash(laneIndex)`(`LaneLayerKey` 的基)承担 → 只让真正变化的那个网格失效;并把 `RenderPendingLaneRebuilds(1)` **移到 `BlitWideBuffer` 之前**(本帧补好的网格本帧就可见)。② 预览曲线抗锯齿不再因交互(`m_fastFrame`)关闭(仅保留"陡峭段过多"这一条形同无声的逃生口)。③ `AcquireNewestCurve` 改为**只按「信号 + 曲线种类」匹配**(参数无关,优先挑覆盖所需区间的条目)→ 拖参数滑块时用上一帧的曲线顶替,后台算好再无缝替换,**不再闪烁/消失**。离屏验证:斜向拖拽 40/40 帧走宽基底快路径(中位 9.2ms,无尖峰),参数连改 10 次 **0 个空白帧**,抗锯齿回归断言(快帧混淆边缘像素 8149/8404);`uitest` **420/420 通过**、`panperf` PASS、`layercheck` 保持"0 次视界覆盖 / 平移对齐 ≤1px"。 |
| 2026-10-12 | DeepSeek-V4.1-Flash(**起源设备**) | **修复"深放大下左右平移流畅、上下/斜向平移卡顿"(用户猜测:上下没有预渲染机制——已证实)与"深放大时拖拽光标跑飞"**。① 量化复现:`panperf` 新增纯竖直拖拽 + 逐帧统计**图层重画次数**,并在 5 网格全开 4 类悬浮面板(20 个)后对比 —— 竖直拖拽中位 **166.6ms/帧**、水平 **37.7ms/帧**(4.4 倍差距,用户报告的"上下卡顿"正是它)。② 主因是**面板像素图层被幅值范围击穿**:`PanelGlobalKey()` 计入 `visual.yMin/yMax`,平移的纵向分量每帧小改幅值 → 整层 20 个面板每帧重画(去掉后 166.6→**24.8ms**);次因是**图层没有纵向预渲染余量**(幅值一变就整块重画,实测 40 帧里 40 次 → 修复后 **1 次**)。③ 修法:`LaneLayer` 增加 `marginY/anchorYMax/pxPerValue`,幅值范围按**像素行**精确扩展(上下各半个网格高)、贴图时按 `(anchorYMax - 当前 yMax) * pxPerValue` 取纵向偏移,图层指纹只计幅值**跨度**不计绝对范围;幅值刻度改以**前台可见网格**的跨度/高度取 `NiceStep`(保证与整幅渲染逐像素同源);网格分界线移出图层(改由宽基底路径的 `PaintLaneDividers()` 补画,否则纵向偏移会把它带走)。④ 光标:深放大下平移会把时间光标甩到视界外很远(像"跑飞/丢失")—— 新增 `ClampCursorsAfterPan()`,在**平移**(中键/左键拖拽、Shift+滚轮、方向键)之后夹取;**离散**的视图变化(选区放大/适应视图/按网格时间轴展开)仍然不移动光标;抓取被钉在边缘的光标读数时不再沿用抓取偏移(否则首帧会跳到视界外再被夹回边缘)。验证:`uitest` **432/432**(新增 `[AI]`:贴边读数抓取后光标落在鼠标处误差 0.0px、中键平移 1.5 屏 0 帧出界且跟手)、`panperf` 竖直 3.8~5.0ms(40 帧仅 1 次图层重画)、水平 6.5ms 持平、`layercheck` 0 视界覆盖、新增探针 `.preflight/cursorcheck` 30/30。 |
| 2026-10-12 | DeepSeek-V4.1-Flash(**起源设备**) | **修复"纵向预渲染带出的绘制异常/抽搐"(中键上下拖动、尤其拖到网格之外时),并把「弱峰增强」升级为「弱峰调整」(幅度 -200% – +200%,负值削弱)**。① 绘制异常根因:上一轮给图层加了纵向余量,但"偏移超出余量"仍走**排队整块重画**(一帧只补 1 个网格)→ 重画完成前 `BlitWideBuffer` 只能贴出部分行、**其余留空**(网格内出现空白条带),且重画与贴图的锚点不同源 = "波形没按预期移动";鼠标拖到网格外很远时每帧都触发 → 抽搐。修法:与横向**同构的纵向滚动**(BitBlt 整块滚动 + 只补画暴露的一整条,`anchorYMax -= roll/pxPerValue`),并且**必须先于横向补条**;滚动量**量化**(`kLayerRollQuantum = 16` 像素,不足量子交给贴图 `srcY` 偏移)以保持画布映射稳定、让折线缓存命中(未量化时每帧滚 1~30 行 → 折线每帧重算)。验证:`panperf` 拖出网格 900px 时被拖网格的**空白行数与整幅重绘逐帧一致**(64 vs 64,即无空白条带),竖直拖拽 16 帧仅 2 次图层重画。② 弱峰调整:`ComputeWeakPeakAdjust`(原 `ComputeWeakPeakBoost`)+ `WeakPeakItem.amountPercent`(-200–200,默认 150),面板「增强等级 %」→「调整幅度 %」、滑块量程 -200%–+200%(**0 在正中间**)、数值列加宽以容纳 "-200%";识别规则与旧实现完全一致,正幅度段与旧实现**逐位相同**,负幅度段改为以相邻**异类**极值(波峰看相邻波谷)为参照:-100% 拉到**较近**的那个、-200% 拉到较远的那个(压平/抹除,左右平滑过渡),且**不得反向增强**。离屏验证:`uitest` **443/443**(正幅度 0/50/100/150/200% → 550/555/560/580/600 逐位保持;负幅度 -50/-100/-200% → 峰 500/450/400、谷 500/550/560;超范围夹取;健康峰不动)、`panperf`/`layercheck`/`cursorcheck` 全过。 |
---
@@ -2679,3 +2680,42 @@ Documents/ 项目文档(含本文件)
- 20 个悬浮面板时:竖直 **166.6 → 24.8ms/帧**,水平 37.7 → 38.8ms(持平)——"上下比左右卡"的不对称消失。
- `layercheck`:`clobbers=0/24`、`pan frames wrong=0/4`、居中图层 vs 整幅重绘逐像素 0 差异;新增探针 `.preflight/cursorcheck`(真文件 + 真缩放)**30/30**(单/双光标拖拽、贴边读数抓取、中键/键盘/滚轮平移)。
- `make clean && make all` 零警告。
---
## 本轮(2026-10-12,起源设备):纵向滚动补齐(消除绘制异常)+「弱峰调整」(-200%–+200%)
用户报告:① 上下拖动视界确实流畅了,但**绘制出现错误**——网格内的信号没有按预期移动,并出现抽搐帧;**尤其把中键按在最上方网格上、一路拖到窗口最下方(鼠标离开网格很远)**时最明显;左右拖动同样出现。② 把「弱峰增强」升级为「弱峰调整」:面板的「增强等级」改为「调整幅度」,量程 -200% – +200%,0 以上与原算法一致,0 以下为**削弱**(把弱峰压向相邻波谷、甚至抹除,左右平滑过渡;波谷反之)。
### A. 绘制异常/抽搐的根因(上一轮纵向余量只补了一半)
上一轮给图层加了「上下各半个网格高」的纵向余量,并把幅值平移改成**贴图纵向偏移**,但"偏移超出余量"时仍然走**排队整块重画**(`QueueLaneRebuild` → `RenderPendingLaneRebuilds(1)`,一帧只补一个网格)。于是:
1. 重画要到(最多)下一帧才生效,而 `BlitWideBuffer` 本帧就按新偏移取源行 → 源行超出画布时 **只能贴出有像素的那一段,其余行留在底色上 = 网格内出现空白条带**("绘制错误")。
2. 重画后的锚点与"贴图偏移"不同源 → 波形在"偏移画法"与"重画后的居中画法"之间跳 = "没按预期移动"。
3. 鼠标拖到网格外很远时,每帧的幅值位移都远超余量 → **每帧都触发整块重画**(画布比可见网格高 3 倍,代价不小)= 抽搐。
### B. 修法:与横向**完全同构**的纵向滚动
- `RenderLaneLayerRegion` 增加 `stripY/stripH`(纵向条带),因此可以只补画"新暴露的一整条"(整宽 × n 行)。
- `RollWideBuffer` 里新增纵向滚动:`BitBlt` 整块上/下移 `roll` 行 → 补画暴露的那一条 → `layer.anchorYMax -= roll / pxPerValue`(与横向 `layer.wideMin += shift / scale` 同一套记账)。
⚠️ **必须在横向补条之前**:横向补条会用"当前 `yMax`"重置图层锚点,顺序反了细条会带上错的纵向偏移。
⚠️ **滚动量量化**(`kLayerRollQuantum = 16` 像素):不足量子的偏移**不滚**,交给贴图的 `srcY` 偏移处理。 这样画布映射在拖动过程中保持稳定 → 折线缓存(键含幅值映射)命中;未量化时"每帧滚 1~30 行" 会让折线每帧重算(实测滚动 3~4ms + 整帧 10~14ms)。余量(上下各半个网格高)足以吸收 16px 的残差, 所以"不滚只偏移"绝不会贴出空白。
### C. 「弱峰调整」(原「弱峰增强」)
- 术语统一:`ComputeWeakPeakAdjust`、`WeakPeakItem.amountPercent`(-200–200,默认 150)、 面板标题「弱峰调整」、标签「调整幅度 %」、光标胶囊尾缀「弱峰调整」、 构建信号名 `<原信号> (弱峰调整 X% M次迭代)`(X 可为负)。
- 滑块:量程 -200% – +200%,**0 在正中间**(`ratio = (amount/200 + 1) / 2`);数值列宽度改为量 `"-200%"`。
- 目标值(`amount` = 幅度/100,识别规则**与旧实现完全相同**):
* `0 ≤ a ≤ 1`:当前值 → 同类极值中**较温和**的一侧(波峰取较低的波峰、波谷取较高的波谷);
* `1 < a ≤ 2`:该侧 → 另一侧(**与旧实现逐位一致**。⚠️ 波峰 `lower + (a-1)*(upper-lower)`、 波谷 `upper - (a-1)*(upper-lower)` 方向相反,符号不能写成一样——本轮先写错,被既有测试立刻抓住);
* `-1 ≤ a < 0`:当前值 → 相邻**异类**极值中**较近**的一个(波峰取较高的波谷、波谷取较低的波峰);
* `-2 ≤ a < -1`:较近的异类极值 → 较远的那个。即 -100% 拉到较近的波谷、-200% 拉到较远的波谷, 弱峰被压平甚至抹除,左右波形平滑过渡(波谷反向同理)。
* ⚠️ 负幅度**不得反向增强**:目标夹在"不越过当前值"的一侧(噪声使异类极值落在错侧时)。
- 平滑偏移(相邻极值之间的 smoothstep 过渡)**逐字未改**,因此负幅度下"一个极值被压低、相邻被抬高"时, 两者之间的**中间采样点可能越过中值线**——这是平滑过渡的正常结果, **不要把"逐点不得越过中值"写成断言**(只在极值点上断言"未反向增强")。
### D. 验证(全部离屏,不占用鼠标/键盘/屏幕)
- `uitest` **443/443**:`[X]` 正幅度 0/50/100/150/200% → 峰 550/555/560/580/600(**旧值逐位保持**)、 谷 450/445/440/420/400;新增负幅度 -50/-100/-200% → 峰 **500/450/400**、谷 **500/550/560**; 超范围(+7 / -7)夹取;"未反向增强"(极值点)与"健康峰不动"; 滑块:中间 = 0%、右端(拖出)= +200%、左端(拖出)= -200%;构建信号名含「弱峰调整」; `[AH]` 纯竖直拖拽 16 帧仅 **2** 次图层重画(量化滚动)。
- `panperf`:拖出网格 900px(鼠标远在窗口外)+ 对角平移 31 帧,**被拖网格的空白行数与整幅重绘逐帧一致** (64 vs 64 → 无空白条带)、帧时 10~13ms(滚动 2~4ms)、末帧与整幅重绘的差异与水平基线同量级 (best integer shift (-1,0),即已知的 ≤0.5px 整数像素残差)。
- `layercheck`:`clobbers=0/24`、`pan frames wrong=0/4`、居中图层 vs 整幅重绘逐像素 0 差异; `cursorcheck` 30/30;`make clean && make all` 零警告。