52 lines
6.2 KiB
Markdown
52 lines
6.2 KiB
Markdown
# 鼠标点击与画面跳转优化(2026-11-03)
|
||
|
||
本轮针对用户反馈的“鼠标拖动/点击有残影、点击后画面跳转慢”做了输入队列和低延迟呈现优化。已有单白色 Windows 远程光标、显示器开关自动恢复和 RKMPP/EGL 客户端均保留。
|
||
|
||
## 现场根因
|
||
|
||
1. **点击位置顺序会被旧的绝对鼠标移动批次覆盖。** Moonlight 上游为了减少包数,会让一个尚未发送的绝对鼠标包持续吸收后续位置。高速移动后点击时,点击包与位置包在网络队列中的边界不明确,画面中的 Windows 控件可能在旧位置响应。32 次左右交替点击的实测中,修改前收到 32 条点击记录,其中第 1、13 条落在错误的一侧(30/32 正确)。这是延迟体感之外的可重复顺序错误。
|
||
2. **鼠标移动合并会扫描 SDL 队列。** 原逻辑只按 `SDL_MOUSEMOTION` 类型取事件,可能跨过按钮/键盘/窗口事件,把点击后的移动提前合并。修改后只消费紧邻且属于同一鼠标设备/窗口/按键状态的移动,遇到边界立即停止,每次最多处理 64 条,避免输入线程长时间占用。
|
||
3. **低延迟模式的解码帧积压。** 当前服务端仍为软件 `libx264`、约 30 FPS;盒子已使用 `h264_rkmpp` + `drm_prime` + EGL/GLES。修改后的非 VSync pacing 呈现队列可以丢弃尚未呈现的等待帧,只保留最新等待帧,减少画面落后于点击的时间。正在呈现的帧、上一帧延迟释放和解码参考帧不会被释放。
|
||
|
||
## 实现
|
||
|
||
- `terminal/moonlight/patches/0001-vdi-input-and-latest-frame.patch`
|
||
- SDL 输入事件按边界合并。
|
||
- 绝对鼠标按钮使用该按钮事件的坐标先入队。
|
||
- `VDI_LATEST_FRAME=1` 且未启用 VSync pacing 时只替换等待呈现帧;默认 wrapper 开启,smooth/pacing 档保持上游行为。
|
||
- `terminal/moonlight/patches/0002-vdi-absolute-click-barrier.patch`
|
||
- 每个点击封住前一位置批次,点击后的移动进入新批次。
|
||
- 发送线程只解除自己包的“可吸收新位置”状态,不误清除点击后新批次。
|
||
- `terminal/kiosk-shell/scripts/vdi-moonlight-rkmpp` 默认 `VDI_LATEST_FRAME=1`,仍不创建本地黑光标、不叠加第二个光标。
|
||
- `tools/build-rkmpp-client.sh` 固定 Moonlight/MPP/FFmpeg 提交,构建前检查并幂等应用补丁;出现源码漂移会失败,不强行覆盖。
|
||
- `tools/set-desktop-responsiveness.ps1` 已在 Windows 登录用户会话执行:备份原设置,关闭窗口缩放动画、菜单等待从 400ms 改为 100ms;通过 `SystemParametersInfoW` 设置并读回校验成功,临时执行任务已删除。失败时脚本会自动恢复。
|
||
- 盒子显示守护改读 Xorg 当前配置 `xrandr --current`,保留热插拔恢复,避免每 2 秒重新探测 EDID/显示模式引发 vendor 驱动时钟日志;对应 9 个场景测试通过。
|
||
- 用户明确蓝框发生于盒子登录/选择桌面页:QLabel 继承 QFrame,原 `QFrame:hover` 蓝框会作用于文字。移除该悬停规则,卡片样式限定到对象名,移除登录输入框的蓝色焦点边框。实际悬停截图文字/卡片区域亮蓝色像素从 8,302 降到 0,按钮仍可正常使用。
|
||
|
||
## 自动化与现场测试
|
||
|
||
| 测试 | 结果 |
|
||
|---|---|
|
||
| SDL 事件边界、64 条上限、触摸鼠标隔离、最新帧 helper | 通过 |
|
||
| 绝对输入 1,000 轮“位置→位置→按下→位置→释放→位置” | 通过 |
|
||
| AddressSanitizer 版本上述 native 测试 | 通过,无内存错误 |
|
||
| 修改前 32 次交替点击 | 30/32 正确,错误序号 1、13 |
|
||
| 修改后 32 次交替点击 | 32/32 正确 |
|
||
| 修改后真实 RKMPP/EGL 串流 | 日志确认 `VDI latest-frame queue: enabled`、`h264_rkmpp`、2560×1440 DRM PRIME |
|
||
| 配对对照串流 | 原版:28.93 接收/28.48 渲染 FPS,队列 3.39ms,解码 10.49ms,呈现 6.84ms;补丁:28.40/28.09 FPS,队列 2.14ms,解码 7.96ms,呈现 6.12ms |
|
||
| 会话连续性 | 测试退出后没有遗留测试串流;显示守护 active;盒子仍 2560×1440 |
|
||
|
||
对照数据不是严格实验室基准:两段会话的网络、Windows 软件编码负载和页面内容会波动。补丁最明确的收益是点击顺序正确和队列深度下降约 1.25ms;它不能把当前服务端软件编码变成 NVENC,也不能保证端到端零延迟。测试期间出现过一次 Wi-Fi 从 completed 到 disconnected 后自动重连,受影响的数据已单独保留,未作为性能结论。
|
||
|
||
## Windows 桌面跳转动画
|
||
|
||
执行前 Windows 登录用户状态为 `DragFullWindows=1`、`MouseTrails=0`、`MinAnimate=1`、`MenuShowDelay=400`。已将窗口动画改为 0、子菜单等待改为 100ms,API 读回校验成功,保留完整窗口拖动和原远程单光标。原值备份到 `%LOCALAPPDATA%\VDI\desktop-responsiveness-before-20261103.json`,恢复使用同一脚本的 `-Restore`。这些设置只减少 Windows 自身的动画和子菜单等待,不代表网页加载或网络响应变快。API 依据为 [Microsoft SystemParametersInfoW](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow)。
|
||
|
||
## 当前状态与回退
|
||
|
||
补丁客户端已接入默认 wrapper,启用最新帧队列。kiosk 为移除蓝色悬停框做了局部编译、CTest 3/3、原监控器拉起新版页面;未运行完整部署脚本,未重启盒子、VM 或宿主。UI 和 wrapper 备份为 `~/vdi-terminal/backups/input-rendering-20261103-114542/`。补丁源码、测试和构建说明均在 `terminal/moonlight/`,证据在 `docs/evidence/input-latency-20261103/`。
|
||
|
||
如需临时回退客户端,下次启动 wrapper 时设置 `VDI_RKMPP_CLIENT=/home/armbian/vdi-build/rkmpp-experiment/build/moonlight/app/moonlight.before-input-20261103`、`VDI_LATEST_FRAME=0`。旧二进制 SHA256 为 `a3575f86b9ebfd3b9f2a6ae4c73b057b2c8cd489cc44549a8838ff459c5e89dc`,新二进制为 `35de7b1a4ade583823b23b5f2e012307f6d0a3848c8eb97bd6d4de9660afa00f`。回退后重新连接并查看统计;不要直接覆盖运行中的 ELF。
|
||
|
||
下一步为用户真实鼠标拖窗/右键/快速双击体验验收;严格延迟需通过高速摄像或外部触发测输入到屏幕 P50/P95。当前数据不能宣称“无延迟”,只能确认点击排序和客户端排队得到改善。
|