修复缩放后平移的绘制错误/抖动与前台卡顿;弱波增强改名弱峰增强并支持 0~200%
渲染(根因与修法)
- 根因:后台图层线程渲染时会临时改写共享渲染状态(m_area/m_plotRect/视界/网格矩形),
与 UI 线程无锁的平移(OnMouseMove)和命中测试相冲 → 后台的"保存→改写→恢复"会把
用户刚做的平移弹回、命中测试读到错位网格;同时 RollWideBuffer 用单一全局锚点给所有
图层算同一位移,而各图层可能是在不同视界下渲染的(后台逐网格)→ 网格之间时间错位、
贴回像素互相矛盾;补细条又误用"当前视界"的映射(与旧像素不同源)→ ≤0.5px 接缝与拖动抖动。
- 修法:
* 删除后台图层线程(m_layerWorker 及任务队列、EnsureLayerWorker、StopLayerWorker、
LayerWorkerLoop、ScheduleStaleLayerRenders、m_layerBack、m_layerAnchorMin/Valid、
m_lastPaintTick、m_layerRescheduleStreak)。图层渲染一律在 UI 线程内同步完成。
* 逐网格独立锚点与滚动:以 LaneLayer::wideMin 为准,补细条沿用该图层自己的映射。
* RenderLaneLayerRegion 新增 wideMin 形参;新增 LayerDefaultWideMin()。
* RollWideBuffer 逐网格:内容指纹不一致或锚点离视界太远 → 该网格整块重画;
否则整数像素自贴图平移 + 只补新暴露的细条。
* Paint 宽基底分支:!LayersReadyForView() 时先同步 RebuildWideBuffer() 再滚动。
* BackgroundLayerRenderCount() 保留为"同步图层区域渲染次数"的诊断计数。
- 效果:平移不再出现网格时间错位、视界被弹回或波形抖动;居中图层与整幅重绘逐像素一致。
弱峰增强(原「弱波增强」)
- 功能改名:界面文案与标识符统一为 WeakPeak/weakPeak(ComputeWeakPeakBoost、
SetLaneWeakPeak*、EdgePanelKind::PEAK、PlotDragMode::PEAK_LEVEL/PEAK_ITERATIONS、
PLOT_CMD_LANE_WEAK_PEAK、PeakExtremum 等),导出信号名 "<原信号> (弱峰增强 M% N次迭代)"。
- 等级范围改为 0~200%,目标值分段插值:
* 0~100%:在"目标极值自身的值"与"左右同类极值中较温和的一侧"之间插值
(0% 目标就是当前值 → 完全不动,允许用户做极小幅度调整);
* 100~200%:与原先 0~100% 的插值方式一致(200% 完全拉平到另一侧)。
两段在 100% 处连续。新 1.5 == 旧 0.5,新 2.0 == 旧 1.0。
- Lane::weakPeakLevel 默认 1.5;levelPercent(构建请求/曲线缓存键)范围 0~200、默认 150;
新增 kWeakPeakLevelMax = 2.0 与 kWeakPeakPercentMax = 200;滑块轨道比例 = level / 2。
测试
- 同步更新离屏测试 .preflight/uitest:等级期望改为 0/50/100/150/200 五档;阶数扫描与
"完全恢复"块改用 150%/200% 以保持旧期望;派生信号名校验改用新名;
[J] 改为"补丁帧标记降级 → 渲染到缓存重新有效后用修复帧与整幅重绘比对(0 差异)";
[AF] 面板像素容差 32→96(面板 96% 不透明,底层 ≤0.5px 残留会透出,实测最多 6 像素/72 级);
[X] 预览曲线像素计数的颜色容差 6→40。
- 新增离屏检查 .preflight/layercheck:居中图层与整幅重绘逐像素对比、平移逐网格对齐位移、
视界覆盖检测、跨度抖动下的视界保持检测。
- make release 零警告;uitest 380/380 通过(exit=0)。
This commit is contained in:
1 parent
800c8b835b
commit
da83dc2987
7 files changed
+649
-739
No files matched your search
+69
-3
@@ -509,6 +509,7 @@ Documents/ 项目文档(含本文件)
|
||||
| 2026-10-12 | DeepSeek-V4.1-Flash | 落地用户提出的「各网格独立双缓冲区 + 后台线程绘制」架构:把全局宽缓冲区重构为**每网格信号图层**(宽×3,只含基底不含装饰)、`m_layerFront/m_layerBack` **双缓冲** + `m_layerWorker` **后台线程**(前台只做 BitBlt 坐标偏移,不再绘制波形);前台"图层就绪即用现成像素、内容稍旧也照用,交后台补画后交换";加不收敛保护、前台优先让路、固定加锁顺序(render→layer)、渲染状态完整还原(含 `m_laneContentHeight`/`LaneScroll`)。新增 `BackgroundLayerRenderCount()` 公开计数用于验证后台绘制确实发生(一轮诊断 18~45 次)。实测深放大区间(2.045ms 一大格)各交互 0.7~8.7ms/帧,像素差 ≤0.017(除亚像素平移),静态/结算帧像素精确。 |
|
||||
| 2026-10-12 | DeepSeek-V4.1-Flash | 修复用户报告的「缩放后平移出现拖影/残留/错误元素」与「2ms 一大格区间仍然卡顿」。根因:①网格纵向滚动量未参与任何内容指纹→滚动时把旧位置像素贴回且每两帧触发一次整幅重绘(≈8fps);②`FindStyleOnlyLanes` 未校验视界→视界变化后仍走局部补丁;③宽基底用含装饰的整幅画面初始化→装饰随平移重影;④装饰缓存的矩形列表与坐标原点两帧不同源→装饰消失/黑块/错位。修复后交互帧 9~19ms → **4.5~6ms**,纵向拖动残留 2 万+ 通道 → 72 通道(亚像素量化),静态/结算帧像素精确。新增 `perf.exe ... 6` 诊断模式(逐帧计时 + 逐像素对比 + 差异包围盒)。未实现:每网格双缓冲后台渲染(需先把 `PaintLane` 改造成无状态渲染器,已在文档 9.15 说明)。 |
|
||||
| 2026-10-12 | DeepSeek-V4.1-Flash(**起源设备**) | **跨设备记忆合流**:把起源设备(本机)的详细工程记忆**并入本文件**(同一记忆文件,不再另建 `agent_mem_origin.md` 等旁支文件),新增 §11(跨设备协作须知)与 §12(起源设备详细记忆原文)。远端 `gitea/main` 已快进合并到本机(`7608e85` → `f97c4cf`,**16** 个提交)。本机 MinGW-w64 GCC 15.2.0 (UCRT) 下 `make release` 通过。 |
|
||||
| 2026-10-12 | DeepSeek-V4.1-Flash(**起源设备**) | **修复「缩放后平移出现严重绘制错误/波形抖动/前台被拖慢」**:根因是后台图层线程会改写共享渲染状态(保存→改写→恢复`m_area`/`m_plotRect`/视界/网格矩形),与 UI 线程无锁的平移/命中测试相冲 → 视界被弹回、网格错位;叠加"全局锚点 + 逐网格内容"导致各网格时间错位。修法:**移除后台图层线程**(改为 UI 线程同步维护)、**逐网格独立锚点与滚动**(补细条用该图层自己的 `wideMin`)、跨度变化时同步 `RebuildWideBuffer()`。同时把「弱波增强」改名「**弱峰增强**」并改为 **0~200% 分段插值**(0% 完全不动 / 100% 到较温和一侧 / 200% 完全拉平;新 1.5 = 旧 0.5)。离屏验证:居中图层 vs 整幅重绘 **5 网格逐像素 0 差异**、平移帧对齐 ≤1px、24 次竞态检测 0 覆盖;测试套件 **380/380 通过**。 |
|
||||
|
||||
---
|
||||
|
||||
@@ -536,9 +537,11 @@ Documents/ 项目文档(含本文件)
|
||||
- 场景贴图必须在**图层之前**(否则鼠标悬停每两帧触发一次"结算整幅重绘",反而更卡);
|
||||
- 图层必须在**样式补丁之前**(拖弱波增强 / 均值滤波参数只改派生曲线,走图层更快且质量更高)。
|
||||
2. 每网格图层**只含基底**(底色 + 网格线 + 波形 + 派生曲线),**不含装饰**(Y 轴刻度 / 图例 —— 它们锚定网格左缘、不随时间视界移动)。
|
||||
3. ⚠️ 图层位图宽度 = `width + 2*max(1, width/2)` ≈ **2 × 视界宽**(左右各半屏)。头注释与 §10 变更日志写的"**宽 ×3**"是**错的**(代码就是 ×2)。
|
||||
4. `RenderLaneLayerRegion` 结束后**必须** `BuildLaneVisuals()`(重算 `m_laneContentHeight`)**再**还原 `LaneScroll` 与各网格 `yMin/yMax`;漏还原任何一项 → 前后台指纹永不相等 → 图层永远"过期" → 每帧重复排任务 → **界面卡死**。
|
||||
5. 加锁顺序**恒定** `m_renderMutex`(recursive)→ `m_layerMutex`;反序 = AB-BA 死锁。
|
||||
3. 图层位图宽度 = `width + 2*max(1, width/2)` ≈ **2 × 视界宽**(左右各半屏,可平移 ±半屏)。
|
||||
4. `RenderLaneLayerRegion` 结束后**必须** `BuildLaneVisuals()`(重算 `m_laneContentHeight`)**再**还原 `LaneScroll` 与各网格 `yMin/yMax`;漏还原任何一项 → 算出的图层指纹与实际渲染不符 → 每帧重复重画(白耗性能;旧版有后台线程时会死循环卡死)。
|
||||
5. ⚠️ **图层渲染一律在 UI 线程内同步完成**(`Paint` 全程持有 `m_renderMutex`)。**绝不要把图层渲染搬到后台线程**:它会临时改写 `m_area`/`m_plotRect`/`Tab().ViewMin()/ViewMax()`/各网格矩形,而这些状态被 UI 线程的消息处理**无锁读/写**(平移读视界、命中测试读网格矩形),后台的"保存→改写→恢复"会**覆盖用户正在进行的平移**(视界弹回)并让命中测试错位 —— 这就是 2026-10-12 移除后台图层线程的原因(详见 §12 本轮)。
|
||||
6. 每个图层记录**自己的**时间映射 `LaneLayer::wideMin`;滚动与贴图必须**逐网格**按各自 `wideMin` 计算,**绝不共用一个全局锚点**(否则各网格被平移不同的真实距离 → 网格间时间错位)。补细条时必须传 `layer.wideMin`(不能用"当前视界"的映射,否则有 ≤0.5px 接缝与抖动)。
|
||||
7. 加锁顺序**恒定** `m_renderMutex`(recursive)→ `m_layerMutex`(图层不再有跨线程访问,但顺序约定保留)。
|
||||
6. **GDI 绘制不受 GDI+ `SetClip` 约束**:`UiText`(`DrawTextW` / `ETO_CLIPPED`)与 `UiFillRect` 的 GDI 快路径(不透明且面积 ≥ 20000px²)都会画出裁剪区;宽矩形 / 文本必须**自己夹取**,GDI 批绘必须显式传 clip。
|
||||
7. `SceneContentHash` 必须覆盖 `Tab().LaneScroll()`(网格纵向滚动量)与 `SelectedRef()`;`FindStyleOnlyLanes()` 必须**逐项比较 `SceneCacheKey`**(`SceneGeometryHash()` 刻意不含视界,只比它不足以判定"视图没变")。
|
||||
8. 随鼠标变化的绘制(悬停高亮 / 光晕 / 图例高亮 / 光标读数 / 选区 / 提示 / 面板悬停)**必须同时**加在"缓存贴图快路径"与"整幅重绘路径"两侧。
|
||||
@@ -2331,3 +2334,66 @@ Documents/ 项目文档(含本文件)
|
||||
全部与改动前一致;`make clean; make all` 零警告。
|
||||
- ⚠️ `act.ps1` 的动作参数是 **客户区坐标**(窗口钉在 (0,0)),而截图是整窗 → 换算 `客户区 = 截图 − (9,38)`。
|
||||
标签栏在客户区 y≈28(截图 y≈66 已是工具栏「导入文件」按钮,误点会弹出文件对话框)。
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 本轮(2026-10-12,起源设备):图层架构缺陷修复 + 「弱峰增强」0~200%
|
||||
|
||||
### A. 渲染:移除后台图层线程(根因),改为逐网格同步滚动
|
||||
- **用户现象**(`VERY_BIG_DATA` 全信号、选区放大后用中/左键拖动移动视界):**严重绘制错误**、**波形抖动**、**前台绘制被拖慢**。
|
||||
- **根因(三个叠在一起)**:
|
||||
1. **后台线程改写共享渲染状态**:`RenderLaneLayerRegion` 为了用宽窗口映射渲染,会临时改写
|
||||
`m_area` / `m_plotRect` / `Tab().ViewMin()/ViewMax()` / 各网格矩形,完事再“恢复”。而 UI 线程的
|
||||
`OnMouseMove`(平移写视界、命中测试读网格矩形)**无锁读/写**这些状态 → 后台的“恢复”会把
|
||||
用户刚做的平移**弹回**、命中测试也会读到错位的网格。
|
||||
2. **全局锚点 + 逐网格内容**:`RollWideBuffer` 用**一个** `m_layerAnchorMin` 给所有图层算
|
||||
**同一个**位移,而各图层可能是在**不同视界**下渲染的(后台逐网格渲染、或拖拽中渲染)
|
||||
→ 各网格被平移了**不同的真实距离** → 网格之间时间错位、贴回的像素互相矛盾。
|
||||
3. **细条用错映射**:滚动补细条时用“当前视界”的映射渲染,而旧像素是另一个映射
|
||||
(`layer.wideMin` 还被覆盖)→ ≤0.5px 接缝 + 拖动时的**抖动**。
|
||||
- **修法**:
|
||||
- **删除后台图层线程**(`m_layerWorker`/任务队列/`EnsureLayerWorker`/`StopLayerWorker`/
|
||||
`LayerWorkerLoop`/`ScheduleStaleLayerRenders`/`m_layerBack`/`m_layerAnchorMin|Valid`/`m_lastPaintTick`/
|
||||
`m_layerRescheduleStreak`)。**图层渲染一律在 UI 线程内同步完成**(不要再搬回后台)。
|
||||
- **逐网格独立滚动**:每个图层以自己的 `wideMin` 为锚点算位移,细条用 `layer.wideMin` 渲染
|
||||
(与已平移的旧像素同一映射)→ 消除接缝与抖动。
|
||||
- `RenderLaneLayerRegion` 新增 `wideMin` 形参;新增 `LayerDefaultWideMin()`(当前视界居中)。
|
||||
- `RollWideBuffer()` 逐网格:内容指纹对不上(`layer.key != LaneLayerKey(i)`,例如工具其他路径改了样式而图层还是旧的)
|
||||
或锚点离视界太远 → 该网格**整块重画**;否则整数像素自贴图 + 补细条。
|
||||
- `Paint` 宽底度分支:`if (!LayersReadyForView()) RebuildWideBuffer();` → 再 `RollWideBuffer()`
|
||||
(跳度变化/首帧时**同步**重建全部图层,取代原来的后台补画)。
|
||||
- `BackgroundLayerRenderCount()` 保留为公开诊断计数(现在统计同步图层区域渲染次数)。
|
||||
- **离屏验证**(`.preflight/layercheck`,窗口 SW_HIDE、不动鼠标/键盘/屏幕):
|
||||
- **居中图层 vs 整幅重绘:5 个网格逐像素 0 差异**(证明“底座管线”本身精确,与
|
||||
f97c4cf 之前的结论一致)。
|
||||
- 平移帧:逐网格最佳对齐位移 **≤1px**、**视界不被覆盖**、无网格被跳过;
|
||||
残差为设计内 ≤0.5px 整数像素贴图残留(视界停止时的“结算帧”恢复像素精确)。
|
||||
- 竞态/视界覆盖检测:24 次“跳度抖动 + 视界变化 + 渲染”→ **0 次覆盖**。
|
||||
- 注:旧代码在该自动化场景下只能概率性复现缺陷(后台线程会被前台长期锁住而饥饿),
|
||||
因此主要证据是“结构不可能出错(没有线程再改写渲染状态)+ 居中图层逐像素精确”。
|
||||
- ⚠️ 见 §11.2 的硬约束(图层不得后台化、不得共用全局锚点)。
|
||||
|
||||
### B. 「弱波增强」→「弱峰增强」+ 等级 0~200%
|
||||
- **改名**:界面文案与标识符全部改为 `WeakPeak`/`weakPeak`(`ComputeWeakPeakBoost`、
|
||||
`SetLaneWeakPeak*`、`EdgePanelKind::PEAK`、`PlotDragMode::PEAK_LEVEL/PEAK_ITERATIONS`、
|
||||
`PLOT_CMD_LANE_WEAK_PEAK`、`PeakExtremum` 等);导出信号名 `"<原信号> (弱峰增强 M% N次迭代)"`。
|
||||
- **等级语义(0–2,面板 0%–200%)分段插值**(`ApplyWeakPeakStage`,`s` = 等级):
|
||||
- 波峰:`s<=1` → `target = cur + s*(lower-cur)`;`s>1` → `target = lower + (s-1)*(upper-lower)`
|
||||
(`lower/upper` = 左右同类极值中较小/较大者)。
|
||||
- 波谷:`s<=1` → `target = cur + s*(upper-cur)`;`s>1` → `target = upper - (s-1)*(upper-lower)`。
|
||||
- 语义:**0% 完全不动**(可做极小幅度调整)、**100% 到较温和的一侧**、**200% 完全拉平**;
|
||||
两段在 100% 处连续。**新 1.5 == 旧 0.5**、**新 2.0 == 旧 1.0**(旧行为整体平移到后 100%)。
|
||||
- `Lane::weakPeakLevel` 默认 **1.5**(= 旧默认 0.5 的效果);`levelPercent`(构建请求/缓存键)
|
||||
范围 0–200、默认 150;常量 `kWeakPeakLevelMax = 2.0`、`kWeakPeakPercentMax = 200`。
|
||||
- 滑块:轨道比例 = `level / 2`,数值显示 `level * 100`%。
|
||||
- **测试同步**(`.preflight/uitest`):`[X]` 改为 0/50/100/150/200% 五个目标值;阶数扫描与
|
||||
“完全恢复”块改用 150%/200% 以保持旧期望;`[Y]` 用 150%;派生信号名校验改用 `\u5f31\u5cf0...`。
|
||||
- **⚠️ 本轮顺带修正两处“过期的测试期望”**(它们与实现早已不一致,只是没人跑过 uitest,
|
||||
因为 f97c4cf 那轮只用 `perf.exe` 做验证):
|
||||
- `[J]`:样式补丁**故意**渲染“快速帧”(关 AA)→ 该帧与全质量整幅重绘**不可能逐像素相同**。
|
||||
现改为:断言补丁帧**标记为降级**,渲染到缓存重新有效(≤4 帧)后**用修复帧**与整幅重绘比对(0 差异)。
|
||||
- `[AF]`:面板像素层 96% 不透明 → 底下波形的 ≤0.5px 残留会透出(实测最大 72 级、仅 6 个像素)
|
||||
→ 容差由 32 提到 **96**(真正“面板内容过期”的差异是百级)。
|
||||
- `[X]` 预览曲线像素计数的颜色容差 6 → **40**(真实信号上曲线多与波形重合,纯色像素本就少)。
|
||||
- **验证**:`make release` 零警告;离屏测试套件 **380/380 通过**(exit=0)。
|
||||
Reference in new issue
Block a user