fix(UI): 浮层不再被下层边界穿透 + 菜单条目裁剪 + 修正性能误判
## 0. 仓库同步 远端 gitea 已把 UI_Refactor 合入 main(PR #1,合并提交 322b658,分支保留)。 main 与 UI_Refactor 均同步到该提交;dev 分支远端从未存在(意外产物),本地已删除。 ## 1. 修正上一轮的性能误判(重要) 上一轮报告称「PlotView 基线每帧在 WarmLaneLayersStep 上多花约 2.4ms」。本轮用两级计时查证, 该结论是错的: 排空前 idle 2.60 ms ← 含"图层预热队列排空"的瞬时成本 排空后 idle 0.53 ms ← 真正的稳态 强制整帧 idle 0.46 ms 那 2.4ms 是载入 283 个网格后给 16 个网格补建宽基底图层的**瞬时**开销(每帧补 1 个,约 16 帧结束), 属于设计内的预热,不存在每帧白烧的固定成本。 仍修掉顺带发现的一处顺序问题:RollWideBuffer 原来对全部 283 个网格先算 LaneLayerKey() (逐网格内容哈希 ≈0.7ms/帧)再判断可视性,且离屏网格的"结构不可用"分支会逐帧把它们塞进 待重画队列再被清掉。现在把 LaneVisuallyRelevant 判断提到循环最前面(见函数内注释)。 ## 2. 浮动面板被网格边界穿透(层级 + 挖洞 + 裁剪) 根因:PlotView::CollectDebugBoxes 把网格盒子与面板盒子放在同一绘制层,只靠 depth 排序; 而调试线画在所有内容之后,"后画"只决定谁压谁,不能阻止下层组件的线仍然可见。 修复三步: - 收集面板前 boxes.PushLayer() ⇒ 面板层高于网格层; - 每个面板 boxes.AddOccluder(layout.panel) ⇒ 绘制更低层盒子时用 Region::Exclude 挖洞; - boxes.SetClip(layout.panel) ⇒ 面板内部元素(如滚出内容区的行)不再登记到面板外。 ## 3. 滚动时面板/菜单边界闪烁或溢出 滚动容器里的条目矩形始终存在,只是绘制时被裁剪掉;调试层读到这些矩形就会给"看不见的内容"画框, 滚动时条目不断进出可视区,框也就不断出现/消失 ⇒ 闪烁 / "边界超出菜单"。 - 面板内容裁到 layout.panel; - 菜单条目裁到 m_scrollEnabled ? m_scrollViewport : m_rect;二级子菜单条目裁到 m_subRect。 ## 4. 顺带小优化 EdgePanelLayoutFor 单次约 2~3µs,283 网格 × 5 类 = 1415 次/帧。现在先看该网格的 5 个面板 open 标志,全关就跳过内层循环。 ## 5. 验证 - make release / make debug 零 error 零 warning;TargetCheck.exe 909,824 B(888.5 KiB < 900 KiB)。 - 新增探针 .preflight/lbpanel 10/10: panel-open / panel-contents-clipped-to-panel / panel-registered-as-occluder / no-lane-bounds-inside-panel(面板内网格层颜色像素=0)/ scrolling-actually-happened (真滚动 0.0→1295.1)/ panel-boxes-stable-while-scrolling(11/11 帧签名一致)/ menu-open-scrollable / no-box-escapes-menu / scrolled-out-items-not-collected。 - 回归:lbcovr 7/7、lbzorder 4/4、lbresid 5/5、lbcheck 21/21、uicheck 69/69。 - rendercheck:8 个场景哈希与上一轮**逐一相同** + FUNC 7/7(本轮不应改变任何正常绘制像素)。 ## 6. 文档 Documents/UI_Refactor_Plan.md / UI_Refactor_Progress.md / UI_Refactor_Report.md 追加第十阶段; Documents/agent_mem.md 同步变更日志与「2026-10-29 第十二轮」的结论修正、浮层三件事、踩坑。
This commit is contained in:
1 parent
322b6582d7
commit
739a523af5
7 files changed
+321
-15
No files matched your search
@@ -3035,6 +3035,8 @@ else if (panelOnly) { /* 只回送“本帧重绘过的区域并集” */ }
|
||||
|
||||
| 2026-10-28 | DeepSeek-V4.1-Flash(**UI_Refactor 分支**) | **边界从补丁改成机制:取消内缩 + 文本几何身份 + 补漏 + 提速(详见 §12 末尾「2026-10-28 第十一轮」)**。① **取消内缩**(第九轮为"父子共边不叠粗"加的 1px 内缩**已作废**):胶囊形元素(GX 徽标 30×17、圆角=高的一半)的可见边界就在外接矩形上,内缩会让圆弧留在框外;正确语义是"子框后画覆盖父框的边"。② **文本获得几何身份**:`PaintUtil` 新增 `UiTextRectSink` / `UiSetTextRectSink` / `UiSetTextRectOffset` / `UiGetTextRectSink`,在 `DrawUiText()`/`UiTextAtClipped()` 里按对齐方式 + 实测宽高把矩形收窄成墨迹矩形回报;`UiDebugBoxList` 直接继承它 ⇒ 65 处文本调用点一行都不用改。③ **缓存命中的行也要有文本框**:行位图渲染时用本地 `RowTextCollector` 收集(位图坐标)→ 存 `RowBitmapCache::textRects` → 贴图时按 `(originX,originY)` 回放;⚠️ **必须无条件收集**,否则"关调试时滚过列表 → 开调试"会命中缓存而永远无文本框。④ **补齐 PlotView 漏项**:`m_timeAxisRect` / `m_scrollBarRect` / `BackToTopRect()` / `m_cursorSpanRect` / `m_cursorLabelRects` / `EditFieldRect()`。⑤ **描边提速**:图元 12→8(4 边 + 4 自适应角块),`paintBoxes` **5.892→4.028ms**;⚠️ 图元数量是唯一瓶颈(`FillPath` ≈20µs/次、GDI `PolyPolygon` 5688 矩形 114ms,都更慢,别换)。验证:新增探针 `.preflight/lbcovr` **7/7**(时间轴/滚动条/回到最上方/GX 胶囊框重合/文本框/缓存行文本框/关闭清空);`lbcheck` 21/21、`lbresid` 5/5、`lbzorder` 4/4、`uicheck` 69/69;`rendercheck` 整帧与区域哈希与上一轮**逐一相同** + FUNC 7/7;零 warning;`TargetCheck.exe` **909,824 字节(888.5 KiB)**。⑥ 已知既有问题:`PlotView` 基线每帧在 `WarmLaneLayersStep()` 花约 2.4ms(与本功能无关)。 |
|
||||
|
||||
| 2026-10-29 | DeepSeek-V4.1-Flash(**本机**) | **远端同步 + 既有性能问题查证 + 浮层层级修复(详见 §12 末尾「2026-10-29 第十二轮」)**。⓪ **仓库**:远端 `gitea` 已把 `UI_Refactor` 合入 `main`(PR #1,`322b658`,分支保留);`main` 与 `UI_Refactor` 均同步到 `322b658`;**`dev` 已删除**(远端从未存在,意外产物)。① **上一轮"基线每帧多花 2.4ms"的结论是错的**:实测排空前 idle=2.60ms、**排空后稳态 0.53ms**、强制整帧 0.46ms ⇒ 那 2.4ms 是"载入 283 网格后给 16 个网格补建宽基底图层"的**瞬时**预热成本(每帧补 1 个,约 16 帧结束)。⚠️ 性能结论必须区分稳态与瞬时。② 仍修掉一处顺序问题:`RollWideBuffer` 原来对**全部** 283 网格先算 `LaneLayerKey()`(≈0.7ms/帧)再判可视性,且离屏网格会逐帧入队再被清掉;现在 `LaneVisuallyRelevant` 提到循环最前面。③ **浮层不被下层覆盖 = 三件事缺一不可**:`PushLayer()`+`(layer,depth)` 排序(谁压谁)、`AddOccluder()`+`Region::Exclude`(下层盒不进入浮层区域)、`SetClip()`(滚出可视区的条目不登记)。`PlotView::CollectDebugBoxes` 收集浮动面板前 PushLayer 并对每个面板 AddOccluder+SetClip;`PopupMenu::CollectDebugBoxes` 条目裁到 `m_scrollEnabled ? m_scrollViewport : m_rect`、子菜单条目裁到 `m_subRect` —— 修掉"网格边界穿透面板""滚动时面板/菜单边界闪烁或溢出"。④ `EdgePanelLayoutFor` 前置"该网格是否有面板展开"的廉价判据。验证:新增探针 `.preflight/lbpanel` **10/10**(面板遮挡 / 面板内容裁剪 / 滚动不闪烁 / 菜单条目裁剪 / 真滚动 1295px);`lbcovr` 7/7、`lbzorder` 4/4、`lbresid` 5/5、`lbcheck` 21/21、`uicheck` 69/69;`rendercheck` 8 场景哈希**与上一轮逐一相同** + FUNC 7/7;零 warning;`TargetCheck.exe` **909,824 字节(888.5 KiB)**。⚠️ 探针判"盒子越界"必须按绘制层过滤;构造「所属网格」菜单必须带分隔线+尾部固定项才会启用滚动区。 |
|
||||
|
||||
## 11. 跨设备协作须知(起源设备视角)
|
||||
|
||||
> **本文件是唯一权威记忆**。所有设备 / Agent 共用它,**不要再新建 `agent_mem_origin.md` 等旁支记忆文件**。
|
||||
@@ -8261,3 +8263,67 @@ rendercheck 整帧与区域哈希与上一轮逐一相同 + FUNC 7/7(调试功
|
||||
|
||||
`PlotView` 基线每帧在 `WarmLaneLayersStep()` 上花约 2.4ms(9.06 vs 6.66),
|
||||
与本功能无关,值得单独优化。
|
||||
|
||||
---
|
||||
|
||||
## 本轮(2026-10-29 第十二轮,本机):分支同步 + 既有性能问题 + 浮层层级修复
|
||||
|
||||
### 0. 仓库约定变更
|
||||
|
||||
* 远端 `gitea` 已把 `UI_Refactor` 合入 `main`(PR #1,合并提交 `322b658`),**分支保留**。
|
||||
* `main` 与 `UI_Refactor` 均已同步到 `322b658`。
|
||||
* **`dev` 分支已删除**(远端从未存在,用户确认为意外产物)。
|
||||
|
||||
### 1. 「既有性能问题」的结论修正(重要)
|
||||
|
||||
上一轮报告里"`PlotView` 基线每帧多花 2.4ms"**是错的**:
|
||||
|
||||
```
|
||||
排空前 idle 2.60 ms ← 含"图层预热队列排空"的瞬时成本
|
||||
排空后 idle 0.53 ms ← 真正的稳态
|
||||
强制整帧 idle 0.46 ms
|
||||
```
|
||||
|
||||
那 2.4ms 是载入 283 网格后给 16 个网格补建宽基底图层的**瞬时**开销(每帧补 1 个,约 16 帧结束)。
|
||||
⚠️ **性能结论必须区分"稳态"与"瞬时"**,否则会把预热成本误判成常态浪费。
|
||||
|
||||
顺着这条线确实修掉一处顺序问题:`RollWideBuffer` 原来对**所有** 283 个网格先算
|
||||
`LaneLayerKey()`(逐网格内容哈希 ≈0.7ms/帧)再判断可视性;且离屏网格的"结构不可用"分支
|
||||
会逐帧把它们塞进待重画队列。**现在把 `LaneVisuallyRelevant` 判断提到循环最前面**
|
||||
(见函数内注释),离屏网格既不哈希也不入队。
|
||||
|
||||
### 2. 浮层不被下层覆盖 = 三件事(缺一不可)
|
||||
|
||||
| 机制 | 作用 |
|
||||
| --- | --- |
|
||||
| `PushLayer()` + `(layer, depth)` 排序 | 决定两个盒子重叠时**谁压谁** |
|
||||
| `AddOccluder()` + `Region::Exclude` | 让**更低层**的盒子整体不进入浮层区域 |
|
||||
| `SetClip()` | 让**滚动容器里滚出的条目**不再登记/绘制(否则会"闪烁"/"溢出") |
|
||||
|
||||
* `PlotView::CollectDebugBoxes`:收集浮动面板前 `PushLayer()`,每个面板
|
||||
`AddOccluder(layout.panel)` + `SetClip(layout.panel)`(面板内部元素也不越界)。
|
||||
* `PopupMenu::CollectDebugBoxes`:条目裁到 `m_scrollEnabled ? m_scrollViewport : m_rect`;
|
||||
二级子菜单条目裁到 `m_subRect`。
|
||||
|
||||
### 3. 验证
|
||||
|
||||
```
|
||||
lbpanel 10/10(新增:面板遮挡 / 面板内容裁剪 / 滚动不闪烁 / 菜单条目裁剪 / 真滚动 1295px)
|
||||
lbcovr 7/7 · lbzorder 4/4 · lbresid 5/5 · lbcheck 21/21 · uicheck 69/69
|
||||
rendercheck 8 场景哈希与上一轮逐一相同 + FUNC 7/7(本轮不改变任何正常绘制像素)
|
||||
零 warning;TargetCheck.exe 909,824 B(888.5 KiB)
|
||||
```
|
||||
|
||||
### 4. 踩坑
|
||||
|
||||
* 探针判断"盒子是否越界"必须**按绘制层过滤**:信号面板样式区、标签栏 ✕ 等盒子可能恰好与
|
||||
菜单同列,直接按坐标判会误报"菜单条目溢出"。
|
||||
* 构造「所属网格」菜单必须带**分隔线 + 尾部固定项**,否则 `PopupMenuLayout` 的滚动区不启用
|
||||
(`pinnedFrom` 只在找到分隔线时才 > 0)。
|
||||
* 计时探针必须先**排空预热队列**再测稳态,否则首帧的图层补齐会污染平均值。
|
||||
|
||||
### 5. 已知近似
|
||||
|
||||
面板层只比网格层高 1,而**文本盒子**固定在 layer 2 收集 ⇒ 面板自己的文字框正常显示,
|
||||
但"图例文字"若与面板重叠仍会画在面板上(当前布局下不重叠)。彻底解决需要让文本收集器
|
||||
在面板绘制期间使用面板层的层号。
|
||||
Reference in new issue
Block a user