修复垂直中键拖拽后再平移的网格纵向跳变/绘制错误
症状:对某网格做一次纵向中键拖拽(幅值窗口上下平移)后,不松开中键、只做一点点
水平(或垂直)位移,该网格波形整体纵向错位(最多 15px),看起来像"纵向跳帧/抽搐"。
松开后再按下中键做同样的微小水平移动同样复现,且与缩放等级无关。
根因:RenderLaneLayerRegion 结束时无条件把 layer.anchorYMax 重置为"当前 yMax"。
该赋值只对"整块重画 / 纵向补条(整宽)"成立(那两种情况整块像素都对齐到当前映射),
对"横向补细条(整高)"不成立 —— 横向滚动只改一条竖带,其余像素仍在原锚点上。
纵向拖动以 kLayerRollQuantum = 16px 量化:|vOffset| < 16px 时不滚动、交给贴图偏移,
因此拖动停下时图层会残留一个 <16px 的纵向偏移且 anchorYMax != 当前 yMax。第一次水平
微移(哪怕只有 3px)就把该残余偏移静默清零(vOffset 变成 0),而像素并未上移 →
整个网格的波形相对正确位置纵向错位,错位量恰好等于那个残余量。
修法:RenderLaneLayerRegion 新增形参 double anchorYMax(本次渲染像素所对应的纵向锚点),
内部以它作为幅值映射基准(yMin = anchorYMax - laneSpan)渲染,并写回
layer.anchorYMax = anchorYMax。各调用点:
* 整块重画 / 纵向补条 / 待重画补齐:传当前 yMax(纵向补条传滚动后的 layer.anchorYMax,
与已滚动像素同一映射);
* 横向补细条:传 layer.anchorYMax(保持不变),细条因此与其余像素纵向同源,
残余偏移继续由贴图偏移承担。
vOffset == 0 时新逻辑与旧逻辑完全等价,故既有"仅水平/仅纵向平移"的像素结果不变。
验证:新增离屏探针 .preflight/perf/pancheck(窗口 SW_HIDE + 直接注入消息 + 读图层内部
anchorYMax/当前 yMax/vOffset + 把持按钮帧与释放后的整幅全质量帧做纵向互相关)。
修复前 A 场景 H step 1 起 vOff 从 -15.00 被清零为 +0.00、lane0 best dy=+15px(差异 39245);
修复后全程保持 -15.00、best dy=0(差异 1220,仅已知 <=0.5px 列相位残差)。
对照/中间网格/长距水平/斜向/松开重按共 7 个场景在缩放 0/8/26 步下全部 dy=0
(中间网格 +1px 为整像素量化残差)。make clean && make all 零警告。
This commit is contained in:
1 parent
7344bbe9c4
commit
de27d9b94f
3 files changed
+93
-12
No files matched your search
@@ -488,6 +488,59 @@ Documents/ 项目文档(含本文件)
|
||||
前台只在做位图搬运。
|
||||
- 跨进程验证:`BackgroundLayerRenderCount()` 为公开只读接口,`perf.exe ... 6` 结束时会打印总量。
|
||||
|
||||
### 9.16 修复「垂直中键拖拽后再平移,网格内容纵向跳变 / 绘制错误」(本轮)
|
||||
|
||||
#### 症状与复现
|
||||
|
||||
`VERY_BIG_DATA.CSV`(5 信号全选)下,任意缩放等级都对同一根网格成立:
|
||||
|
||||
1. 对某网格(如最上层「编码器A相」)按中键**纵向**拖拽约半个网格高,让该网格幅值窗口上下平移;
|
||||
2. **不松开**中键,只做**一点点水平位移**。
|
||||
|
||||
预期只有水平移动,实际该网格的波形**整体纵向错位**(最多 15px,视拖动落点而定),看起来像"纵向跳帧/抽搐"。
|
||||
若改为"松开后再按下中键做同样的微小水平移动",同样复现。
|
||||
|
||||
#### 根因:横向补细条时静默重置了图层的纵向锚点
|
||||
|
||||
图层用 `LaneLayer::anchorYMax`(渲染时该网格的 `yMax`)描述**像素的纵向映射**;贴图偏移
|
||||
`vOffset = round((anchorYMax - 当前 yMax) * pxPerValue)`。纵向拖动用 `kLayerRollQuantum = 16px` **量化**:
|
||||
`|vOffset| < 16px` 时不滚动,交给贴图偏移处理 —— 于是拖动停下时图层里会残留一个 `< 16px` 的纵向偏移,
|
||||
而 `anchorYMax != 当前 yMax`。
|
||||
|
||||
问题出在 `RenderLaneLayerRegion` 结束时**无条件** `layer.anchorYMax = 当前 yMax`。该赋值对
|
||||
「整块重画」「纵向补条(整宽)」成立(那两种情况整块像素都对齐到当前映射),但对
|
||||
**「横向补细条(整高)」不成立**:横向滚动只改一条竖带,其余像素仍在**原锚点**上。于是第一次水平移动
|
||||
(哪怕只有 3px)就把残余偏移**静默清零**(`vOffset` 变成 0),而像素并没有上移 → 整个网格的波形
|
||||
相对正确位置纵向错位恰好等于那个残余量。
|
||||
|
||||
#### 修法
|
||||
|
||||
`RenderLaneLayerRegion` 新增形参 `double anchorYMax`(本次像素所对应的纵向锚点):内部以它作为幅值映射
|
||||
基准(`yMin = anchorYMax - laneSpan`)渲染,并在结束时写入 `layer.anchorYMax = anchorYMax`。各调用点:
|
||||
|
||||
- 整块重画 / 纵向补条 / 待重画补齐:传**当前** `yMax`(纵向补条传滚动后的 `layer.anchorYMax`,与已滚动像素同一映射);
|
||||
- **横向补细条**:传 `layer.anchorYMax`(**保持不变**),细条因此与其余像素纵向同源,残余偏移继续由贴图偏移承担。
|
||||
|
||||
#### 验证(离屏,`.preflight/perf/pancheck`,窗口 `SW_HIDE` + 直接注入消息,不动鼠标/键盘/屏幕)
|
||||
|
||||
探针逐帧读出图层内部状态(`anchorYMax` / 当前 `yMax` / `vOffset`),并把持按钮帧与
|
||||
**释放后的整幅全质量帧**做纵向互相关,报告该网格的最佳纵向位移 `dy`。
|
||||
|
||||
| 场景(`VERY_BIG_DATA`,缩放 0 / 8 / 26 步) | 修复前 | 修复后 |
|
||||
| --- | --- | --- |
|
||||
| A 纵向拖半个网格高 → 持按钮水平微移 | **dy=+15px**(lane0 差异 39245) | **dy=0**(差异 1220,仅已知 ≤0.5px 列相位残差) |
|
||||
| B 仅纵向拖(对照) | dy=0 | dy=0 |
|
||||
| C 仅水平拖(对照) | dy=0 | dy=0 |
|
||||
| D 中间网格纵向+水平 | — | dy=+1(整像素量化残差) |
|
||||
| E 长距水平拖(越过 ±半屏余量)后再微移 | — | dy=0 |
|
||||
| F 斜向拖后再水平 | — | dy=0 |
|
||||
| G 纵向拖 → 松开 → 再按下中键水平微移 | — | dy=0 |
|
||||
|
||||
- 修复前 A 场景 `H step 1` 起 `vOff` 从 `-15.00` 被清零为 `+0.00`;修复后全程保持 `-15.00`(贴图偏移继续生效)。
|
||||
- `vOffset == 0` 时新逻辑与旧逻辑**完全等价**(横向补条传的锚点就是当前 `yMax`),因此既有的
|
||||
「仅水平平移」「仅纵向平移」行为与像素结果不变(已由对照场景 B/C 覆盖)。
|
||||
- `make clean && make all` 零警告。
|
||||
|
||||
---
|
||||
|
||||
## 10. 变更日志(本文件维护记录)
|
||||
@@ -518,6 +571,7 @@ Documents/ 项目文档(含本文件)
|
||||
| 2026-10-12 | DeepSeek-V4.1-Flash(**起源设备**) | **修复"上下拖动之后,左右/上下/斜向拖动都出现绘制错误"(真因:图层条带渲染时 GDI 网格线没被限制在条带内),并调整「弱峰调整」的弱峰/弱谷定义、默认幅度与数值符号显示**。① 根因:`PaintLane` 的 GDI 网格线裁剪矩形只限制了横向(`RectF(m_area.X, clipTop, m_area.Width, …)`),而**纵向补条是全宽 × 窄 y** —— GDI 绘制不受 GDI+ 裁剪约束,于是横向网格线被画到条带之外的已正确像素上、**覆盖在波形之上**,并**永久烘进图层**,随后每次平移都带着它一起漂移(用户看到"到处都有绘制错误")。修法:`laneClip = IntersectRect(m_area, 网格可见矩形)` 同时用于 `SetClip` 与 GDI 裁剪。② 新增离屏探针 `.preflight/dragcheck`(真文件 + 真中键拖拽消息:先上拖半个网格高,再左右/上下/斜向、最后拖出窗口;每帧把图层画布的有效条带与"同一 `wideMin` 的新渲染画布"逐像素比较):修复前被拖网格整行不一致(2410px ≈ 2 行全宽),修复后 ≤171px(仅补条边界的抗锯齿边缘)。③ 弱峰调整:**「是否偏弱」改为**"波峰必须同时低于左右两侧各自的(相邻波峰+相邻波谷)均值;波谷反之";默认幅度 **0%**(不改动);滑块右侧数值**始终带符号**(`+150%` / `-150%` / `0%`,验证 +150% 与 -150% 墨迹宽度一致且都比 `0%` 宽 ≥8px)。验证:`uitest` **441/441**、`dragcheck`/`panperf`/`layercheck`/`cursorcheck` 全过、`make clean && make all` 零警告。 |
|
||||
| 2026-10-12 | DeepSeek-V4.1-Flash(**起源设备**) | **「弱峰调整」升级为三组识别规则 + 滑动条 ±400% 梯度驱动**:第一类(两侧均值都要满足,原规则)在滑动条 0–200% 内走完自身 0–200%;第二类("或":任一侧均值满足即可)从 100% 起参与,own 幅度 = clamp(|a|-100%,0,200%);第三类(只与左右同类极值比较,最宽松)从 200% 起参与,own 幅度 = clamp(|a|-200%,0,200%);负值完全对称。每组自身的 ±200% 映射统一为:+100% → 左右同类极值中较温和的一侧、**+200% → 左右同类极值的均值**(不再取较大的那个);-100% → 相邻异类极值中较近的一个、**-200% → 相邻异类极值的均值**(不再取最小的那个)。同时满足多组时取**幅度绝对值最大**的组。验证:`uitest` **463/463**(第一类点 0/50/100/150/200% → 520/570/620/**625/630**;只满足第二类的峰 130 → 100% 不动、150%/200%/250%/300%/400% = 140/150/162.5/175/175;只满足第三类的峰 195 → 200% 不动、250%/300%/400% = 197.5/200/200;±400% 夹取;滑块中间 = 0%、两端 = ±400%)、`panperf`/`layercheck`/`cursorcheck`/`dragcheck` 全过、零警告。 |
|
||||
| 2026-10-12 | DeepSeek-V4.1-Flash(**起源设备**) | **修复"按住中键把视界纵向移动好几个网格高(或横向拖很远)后,出现大量绘制错误与持续抽搐"**:根因是 `RollWideBuffer` 对"位移超出余量"只做**排队等后续帧重画**(`QueueLaneRebuild` + `continue`)—— 该帧 `BlitWideBuffer` 取不到源行 → 网格里出现**空白条带**;且每帧都重新入队而 `RenderPendingLaneRebuilds(1)` 一帧只补 1 个网格 → **补不完 = 持续抽搐**;纵向余量只有 ±半个网格高,正常速度的纵向拖拽每帧就超过它,故几乎必现。修法:**只有"内容真的变了"才排队**,距离类问题一律本帧就地解决 —— 位移小于画布则滚动(O(1) BitBlt + 只补暴露细条),超出画布则**立刻整块重画并重新居中**(0.4ms/网格)。验证:新增探针 `.preflight/dragcheck` 按用户要求**全程按住中键不放**地做检查(图层条带逐像素 / 画布覆盖率 / 画面空白行数与墨迹占比),并把纵向滚动临时关掉做 A/B:立刻报 `layer band diff 76221 / drawing errors 11`,恢复后 **0 错误**;`uitest` **463/463**、`panperf`/`layercheck`/`cursorcheck` 全过、`make clean && make all` 零警告。 |
|
||||
| 2026-10-12 | DeepSeek-V4.1-Flash(**另一台设备**) | **修复「垂直中键拖拽后再平移,网格内容纵向跳变 / 绘制错误」**(详见 §9.16):根因是 `RenderLaneLayerRegion` 结束时**无条件**把 `layer.anchorYMax` 重置为"当前 `yMax`"—— 对整块重画 / 纵向补条成立,但**横向补细条(只改一条竖带、其余像素仍在原锚点)**不成立。纵向拖动以 `kLayerRollQuantum=16px` 量化,停下时图层会残留 `<16px` 的纵向偏移且 `anchorYMax != 当前 yMax`;第一次水平微移就把该偏移**静默清零**(`vOffset→0`)而像素未动 → 整个网格波形纵向错位(最多 15px)。修法:`RenderLaneLayerRegion` 新增形参 `anchorYMax`,内部以它作幅值映射基准(`yMin = anchorYMax - laneSpan`)渲染并写回 `layer.anchorYMax`;横向补条传 `layer.anchorYMax`(保持不变),整块重画/纵向补条传当前(或滚动后)`yMax`。`vOffset==0` 时新旧逻辑完全等价。验证:新增离屏探针 `.preflight/perf/pancheck`(窗口 `SW_HIDE` + 注入消息 + 读图层内部 `anchorYMax`/`vOffset` + 持按钮帧 vs 释放后整幅帧的纵向互相关):修复前 A 场景 `dy=+15px`(lane0 差异 39245),修复后 **`dy=0`**(差异 1220,仅已知列相位残差);对照/中间网格/长距水平/斜向/松开重按共 7 个场景在缩放 0/8/26 步下全部 `dy=0`(中间网格 `+1px` 为整像素量化残差);`make clean && make all` 零警告。 |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in new issue
Block a user