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
@@ -677,3 +677,89 @@ rendercheck 8 个场景的整帧与区域哈希与上一轮**
|
||||
* 把浮层的 `clip` 设成菜单本体会把展开到本体外的二级子菜单整个裁掉(上一轮遗留,已确认仍正确)。
|
||||
* `UiDebugBoxList` 直接当收集器用时,`OnTextRect` 需要有自己的 `depth`(文本用 4),
|
||||
不能沿用调用点当时的 depth —— 否则文本与容器同色。
|
||||
|
||||
---
|
||||
|
||||
## 第十二轮(2026-10-29):分支同步 + 既有性能问题 + 浮层层级修复
|
||||
|
||||
### 0. 仓库同步
|
||||
|
||||
| 项 | 结果 |
|
||||
| --- | --- |
|
||||
| `git fetch gitea --prune` | 新增 `gitea/UI_Refactor`;`gitea/main` 前进到合并提交 `322b658` |
|
||||
| `main` | 快进到 `322b658`(本地原先落后 22 个提交,现在与远端一致) |
|
||||
| `dev` | 远端不存在该分支 ⇒ **本地已删除**(用户确认是意外产物) |
|
||||
| `UI_Refactor` | 快进到 `322b658`(它原本是合并提交的祖先),继续作为工作分支 |
|
||||
|
||||
### 1. 进度总览
|
||||
|
||||
| # | 任务 | 状态 | 验证 |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | 分支同步 / 删 `dev` | ✅ | `git branch -vv` |
|
||||
| 2 | 定位"空闲帧比强制整帧慢"的真因 | ✅ | 两级计时探针 |
|
||||
| 3 | `RollWideBuffer` 把可视性判断提到最前 | ✅ | 排空后稳态 0.53ms |
|
||||
| 4 | 浮动面板另起绘制层 + 遮挡矩形 + 内容裁剪 | ✅ | `lbpanel` |
|
||||
| 5 | 菜单条目裁到可视区 | ✅ | `lbpanel` |
|
||||
| 6 | `EdgePanelLayoutFor` 前置廉价判据 | ✅ | 收集耗时 0.082→0.075ms |
|
||||
| 7 | 文档 + 共享记忆 | ✅ | — |
|
||||
|
||||
### 2. "既有性能问题"的真相
|
||||
|
||||
用两级计时(先整体、再拆到 `WarmLaneLayersStep` 内部)测出:
|
||||
|
||||
```
|
||||
排空前 idle(静态场景命中) 2.60 ms ← 之前误以为是稳态
|
||||
排空后 idle(稳态) 0.53 ms
|
||||
强制整帧 idle 0.46 ms
|
||||
[warm] render=1.3~2.8ms (pending=16→0) ← 每帧补 1 个网格图层
|
||||
```
|
||||
|
||||
结论修正:**不存在**每帧白烧的固定开销;那 2.4ms 是"图层预热队列排空"的**瞬时**成本
|
||||
(16 个网格 × 每帧补 1 个,约 16 帧后结束)。
|
||||
|
||||
但确实发现一处顺序问题:`RollWideBuffer` 对**所有** 283 个网格计算 `LaneLayerKey()`
|
||||
(逐网格内容哈希,实测约 0.7ms/帧),然后才判断是否可视并 `continue`;
|
||||
而且离屏网格的"结构不可用"分支还会把它们**逐帧塞进待重画队列**(再被 `remove_if` 清掉)。
|
||||
现在把可视性判断提到循环最前面 ⇒ 离屏网格既不哈希也不入队。
|
||||
|
||||
### 3. 浮动面板被网格边界穿透(层级 + 挖洞)
|
||||
|
||||
根因:`PlotView::CollectDebugBoxes` 把**网格盒子与面板盒子放在同一个绘制层**,
|
||||
只靠 `depth` 排序 —— 而调试线画在所有内容之后,"后画"只能决定谁压在谁上面,
|
||||
**不能阻止下层组件的线仍然可见**。
|
||||
|
||||
修复三步:
|
||||
1. 收集面板前 `boxes.PushLayer()` ⇒ 面板层高于网格层;
|
||||
2. 每个面板 `boxes.AddOccluder(layout.panel)` ⇒ 绘制更低层盒子时用 `Region::Exclude` 挖洞;
|
||||
3. `boxes.SetClip(layout.panel)` ⇒ 面板内部的元素(如滚动出内容区的行)也不再登记/绘制到面板外。
|
||||
|
||||
### 4. 滚动时面板边界闪烁 / 菜单条目"仍然在绘制"
|
||||
|
||||
同一类问题:**滚动容器里的条目矩形仍然存在,只是不绘制**。
|
||||
|
||||
* 面板:内容区滚出的行 → 现在裁到 `layout.panel`;
|
||||
* 菜单:`m_itemRects` 含**滚出视口**的条目 → 现在裁到 `m_scrollViewport`(可滚动时)或 `m_rect`;
|
||||
二级子菜单条目裁到 `m_subRect`。
|
||||
|
||||
实测(`lbpanel`):
|
||||
```
|
||||
panel 层 escaped=0;菜单层 belowViewport=0;菜单层 fully-outside=0
|
||||
面板内网格层颜色像素 = 0
|
||||
滚动 0.0 → 1295.1(确认真滚动了),面板盒子签名 11/11 帧完全一致
|
||||
```
|
||||
|
||||
### 5. 验证
|
||||
|
||||
```
|
||||
make release / make debug 零 error 零 warning;TargetCheck.exe 909,824 B(888.5 KiB)
|
||||
lbcovr 7/7 · lbpanel 10/10(新增)· lbzorder 4/4 · lbresid 5/5 · lbcheck 21/21 · uicheck 69/69
|
||||
rendercheck 8 场景哈希与上一轮逐一相同 + FUNC 7/7
|
||||
```
|
||||
|
||||
### 6. 踩坑
|
||||
|
||||
* 探针里"盒子是否越界"必须**按绘制层过滤**:别的组件(信号面板样式区、标签栏 ✕)
|
||||
可能恰好与菜单同列,直接按坐标判会把它们误当成"菜单条目溢出"。
|
||||
* 构造"所属网格"菜单必须带**分隔线 + 尾部固定项**,否则 `PopupMenuLayout` 的
|
||||
滚动区根本不会启用(`pinnedFrom` 只在找到分隔线时才 > 0)。
|
||||
* 计时探针的迭代次数太少(20 次)时,首帧的图层补齐会污染平均值 —— 必须先排空预热队列再测稳态。
|
||||
Reference in new issue
Block a user