ci / rust (push) Canceled after 0s
ci / web (push) Canceled after 0s
ci / package-preview (push) Canceled after 0s
ci / package-installer (push) Canceled after 0s
ci / linux-agent (push) Canceled after 0s
ci / edge-service (push) Canceled after 0s
ci / coturn-pop (push) Canceled after 0s
ci / package-windows-host (push) Canceled after 0s
275 lines
12 KiB
Markdown
275 lines
12 KiB
Markdown
# RemoteDesk Windows 客户端 GPU 加速设计
|
||
|
||
## 1. 目标
|
||
|
||
Windows 客户端的 UI、远程视频、RDP 图形和终端均支持 GPU 加速。核心目标:
|
||
|
||
- Linux H.264 由原生 helper 在 D3D11 surface 中硬解和呈现。
|
||
- 避免持续 GPU→CPU→GPU 往返。
|
||
- RDP 只上传变化区域,不重复复制完整 framebuffer。
|
||
- 终端和 UI 使用 GPU 渲染。
|
||
- 支持 Intel、AMD、NVIDIA 以及多 GPU 主机。
|
||
- 驱动重置或硬解不可用时严格模式明确失败,显式 compatibility 才允许回退。
|
||
|
||
这里的“零拷贝”特指未压缩视频像素从捕获到编码、或从解码到呈现不经过 CPU map/copy。压缩码流和 RTP 包仍可经过普通内存。跨 Adapter GPU copy 不算零拷贝。
|
||
|
||
### Windows Headless compatibility 模式
|
||
|
||
没有独立 GPU 不等于一定没有 DXGI 输出:机器可能存在 Intel 核显、虚拟 GPU、Microsoft Basic Display Adapter 或 WARP。采集端必须以运行时结果区分这些情况,不得因为成功创建 ID3D11Texture2D 就报告硬件加速。
|
||
|
||
探测顺序:
|
||
|
||
1. 枚举 DXGI Adapter 和 Output。
|
||
2. 尝试创建 D3D11 device 和 Desktop Duplication。
|
||
3. 尝试 AcquireNextFrame,并验证连续帧。
|
||
4. 探测 NVENC、AMF/VCE/VCN、Quick Sync 的实际编码能力。
|
||
5. 硬件路径不可用时,若用户显式选择 compatibility,则允许 WARP/CPU surface 和 x264、x265、SVT-AV1。
|
||
|
||
compatibility 路径必须报告 adapter_type、surface_type、cpu_map_count、cpu_upload_bytes、encoder_backend、software_encode_latency_us、encode_fps 和 degraded。WARP 是软件 D3D 实现,不能报告为硬件 GPU;Microsoft Basic Display Adapter 也不能视为硬件编码器。
|
||
|
||
无硬件编码器时,系统自动应用软件上限。默认先尝试 1080p30/60 或实测可承受的更低档位;请求多路 4K/120 时,strict 性能模式返回 HARDWARE_ENCODER_UNAVAILABLE,compatibility 模式降档并明确显示 software/degraded。软件视频队列有界、允许丢帧,且不阻塞输入和音频线程。
|
||
|
||
## 2. 渲染架构
|
||
|
||
```text
|
||
Tauri Client
|
||
├── WebView2 UI -> Chromium GPU compositor
|
||
├── xterm.js -> WebView2 GPU text compositor
|
||
├── RDP helper -> IronRDP/D3D11 native window
|
||
└── Native video helper -> GStreamer/D3D11 native window
|
||
```
|
||
|
||
JavaScript 不读取远程视频像素;原生 helper 的视频帧不经过 Tauri IPC。
|
||
|
||
## 3. 零拷贝状态模型
|
||
|
||
每个 Linux 桌面会话报告实际路径:
|
||
|
||
```text
|
||
zero_copy 同一 GPU surface 直接经过硬件编解码/呈现
|
||
gpu_copy 原始像素仅在 GPU 间或 GPU surface 间复制
|
||
cpu_upload CPU 捕获/解码后上传 GPU
|
||
software CPU 色彩转换或软件编解码
|
||
```
|
||
|
||
Agent 和 native helper 只有在 tracer/ETW/驱动指标证明原始帧未被 CPU map 时才能报告 `zero_copy`。默认 `required_end_to_end` 要求两端均为 `zero_copy`;任一端为其他状态都结束媒体协商。`compatibility` 必须由用户显式开启。切换 GPU、分辨率或显示器后必须重新验证,不能沿用之前状态。
|
||
|
||
## 4. GPU 枚举与选择
|
||
|
||
客户端通过 DXGI 枚举:
|
||
|
||
- Adapter LUID、名称、Vendor/Device ID。
|
||
- Dedicated/Shared video memory。
|
||
- D3D feature level。
|
||
- Hardware/Software/Remote adapter 类型。
|
||
- 每个显示器所属 output 与 adapter。
|
||
|
||
选择模式:
|
||
|
||
1. 默认(推荐):Linux native helper 和 RDP helper 都选择窗口当前显示器 Adapter。
|
||
2. 手动:从 Rust 枚举的物理 GPU 列表选择固定 Adapter;Linux 始终使用 native-video helper。
|
||
3. 手动 GPU 不存在时可回到窗口 Adapter 重新验证,但驱动失效、不支持 codec 或发生跨 GPU copy 时,Linux 严格会话失败且不改写配置。
|
||
4. WARP 仅用于 RDP 或显式 compatibility,不能满足 Linux 双端零拷贝。
|
||
|
||
GPU 选择持久化使用 LUID/PCI identity 的稳定组合,不只保存容易变化的枚举序号。
|
||
|
||
配置优先级:主机级手动选择 > 全局手动选择 > 默认模式。运行时诊断同时展示“用户选择”和“实际生效”Adapter。
|
||
|
||
## 5. Linux 视频硬解码
|
||
|
||
### 5.1 默认原生零拷贝路径
|
||
|
||
```text
|
||
RTP H.264
|
||
-> GStreamer depay/parse
|
||
-> D3D11 hardware decoder
|
||
-> GstD3D11Memory
|
||
-> d3d11videosink
|
||
-> native HWND
|
||
```
|
||
|
||
decoder、sink、swap chain 和窗口 output 必须位于同一 DXGI Adapter。通过 GStreamer tracer、ETW/GPUView 和 CPU map 计数共同验证;仅成功创建硬件 decoder 不足以报告 `zero_copy`。
|
||
|
||
### 5.2 Compatibility 软件回退路径
|
||
|
||
```text
|
||
RTP H.264
|
||
-> software decoder
|
||
-> CPU frame
|
||
-> D3D11 upload
|
||
-> child HWND
|
||
```
|
||
|
||
该路径同样只属于显式 compatibility。触发条件包括:
|
||
|
||
- 硬件不支持 codec/profile/level。
|
||
- 驱动创建 decoder 失败。
|
||
- GPU session 数量达到限制。
|
||
- device removed/reset 后重建失败。
|
||
|
||
UI 明确显示“软件解码”,并降低最大分辨率/帧率,防止 CPU 过载被误诊为网络问题。严格模式不进入该路径。
|
||
|
||
## 6. 编码能力协商
|
||
|
||
Native helper 报告经过验证的精确解码能力和实际会话 stats:
|
||
|
||
```text
|
||
codec
|
||
profile/level
|
||
max_width/max_height
|
||
max_fps
|
||
bit_depth
|
||
hardware/software
|
||
adapter_id
|
||
```
|
||
|
||
能力检测必须尝试创建 decoder 或执行短样本解码。仅查询 API 支持列表不足以证明驱动可用。
|
||
|
||
Windows `native-video --probe-h264-file` 已提供真实 H.264 容器首帧解码源码入口,并强制输出同 device NV12 DXGI texture;`--play-h264-file` 进一步按媒体时间戳读取动态可见尺寸,以 D3D11 VideoProcessor 将 texture subresource 转换和缩放到同 device swap chain,全链路不调用 CPU frame map。它们用于排除纯 capability 查询和明显 CPU buffer 路径。最终硬解/零拷贝结论仍必须结合 ETW/GPUView,不能只依据 `IMFDXGIBuffer` 或 VideoProcessor。
|
||
|
||
首版 H.264 8-bit。HEVC/AV1 在 Intel、AMD、NVIDIA 的实际硬解矩阵通过后增加。HDR、10-bit 和色彩管理单独设计,不与基础 GPU 加速捆绑。
|
||
|
||
## 7. RDP GPU 路径
|
||
|
||
IronRDP 图形输出分两类:
|
||
|
||
1. 已解码 bitmap/dirty rect:上传变化区域到 D3D11 texture。
|
||
2. 可获得的现代 RDP 视频 surface:评估直接硬解和 GPU surface 路径。
|
||
|
||
当前源码已在一次 redraw 前把所有待呈现区域合并为一个有界矩形,并满足:
|
||
|
||
- 重叠或邻近区域合并。
|
||
- 已被新 update 覆盖的旧区域丢弃。
|
||
- 上传 buffer 复用,不为每个 rect 分配资源。
|
||
- IronRDP 只转换 dirty region 的像素块,不为每次更新重建完整 CPU framebuffer。
|
||
- 纹理尺寸只在远端 framebuffer 尺寸变化时重建。
|
||
- 输入和控制不等待 GPU fence。
|
||
|
||
该实现优先保证更新不丢失;相距很远的区域也会合并为包围矩形,后续可在实机 profile 证明收益后改为有限多矩形上传。会话诊断返回最近一次上传模式和实际上传像素数,便于判断合并范围是否过大。
|
||
|
||
RDP AVC/AVC444 硬解是否可由 IronRDP 暴露,属于 M0 验证项。若只能获得 CPU framebuffer,D3D11 upload 仍保持呈现端加速,但不能宣称完整硬件解码。
|
||
|
||
RDP 不受 Linux `zero_copy_policy` 强制约束。CPU framebuffer 路径固定报告 `cpu_upload`;未来只有解码 surface 能直接导入同一 D3D11 Adapter 并通过 ETW 验证时,才报告 `zero_copy`。
|
||
|
||
## 8. UI 与终端
|
||
|
||
- Tauri UI 使用 WebView2 GPU compositor。
|
||
- xterm.js 使用浏览器文本/Canvas renderer,但不承担视频帧。
|
||
- RDP helper 的轻量 egui 工具栏使用 wgpu。
|
||
- WebView2 GPU process crash 由主程序检测并重建对应窗口。
|
||
- UI 动画不能抢占远程视频线程或频繁触发全窗口重绘。
|
||
|
||
## 9. 多 GPU
|
||
|
||
常见场景:核显连接显示器,独显负责高性能任务。策略:
|
||
|
||
- Native 默认让 decoder/sink 跟随窗口显示器 Adapter;手动模式使用指定 Adapter。
|
||
- 用户选择独显解码但显示器属于核显时,严格模式拒绝跨 GPU 复制并提示移动窗口或改选 Adapter;compatibility 才显示并允许 `gpu_copy`。
|
||
- 跨显示器移动完成并稳定一段时间后,再评估重建 pipeline。
|
||
- 不在拖动过程中连续重建 decoder。
|
||
- 重建时保持最后一帧,完成后请求 IDR。
|
||
- 多会话按 Adapter 统计硬解 session 和显存预算。
|
||
|
||
## 10. 显存与资源预算
|
||
|
||
每个会话记录:
|
||
|
||
- decode surfaces 数量与格式。
|
||
- framebuffer/texture 尺寸。
|
||
- swap chain buffers。
|
||
- staging/upload buffers。
|
||
- terminal glyph atlas。
|
||
|
||
策略:
|
||
|
||
- 队列有界,过期视频帧优先丢弃。
|
||
- 后台会话降低呈现帧率。
|
||
- 显存压力上升时先降低非活动会话质量。
|
||
- 达到硬解 session 上限时,严格会话提示用户关闭其他会话;只有 compatibility 可以软件回退。
|
||
- 4K/多显示器连接前估算资源,不等 OOM 后处理。
|
||
|
||
## 11. Device Lost
|
||
|
||
Native helper 处理 `DXGI_ERROR_DEVICE_REMOVED/RESET/HUNG`:
|
||
|
||
```text
|
||
Running
|
||
-> GpuLost
|
||
-> stop presenting/input capture
|
||
-> collect removal reason
|
||
-> release swap chain/decoder resources
|
||
-> recreate adapter/device/pipeline
|
||
-> request keyframe/full RDP refresh
|
||
-> Running | SoftwareFallback | Failed
|
||
```
|
||
|
||
GPU 重建不销毁远端会话。连续失败超过阈值后,严格模式结束本地呈现;compatibility 才允许回退软件,并保留可导出的错误信息。
|
||
|
||
## 12. 色彩和缩放
|
||
|
||
- 首版统一 SDR sRGB 输出。
|
||
- 保留视频原始颜色信息用于诊断。
|
||
- 缩放在 GPU 完成,支持 fit、1:1 和 stretch(默认不使用 stretch)。
|
||
- 黑边和 viewport 必须参与鼠标坐标逆变换。
|
||
- HiDPI 变化同时更新 WebView CSS/device pixel ratio、native helper 像素尺寸和远端显示请求。
|
||
- HDR/ICC/10-bit 属于后续专项,不能未经验证直接透传。
|
||
|
||
## 13. 用户设置
|
||
|
||
GPU 选项:
|
||
|
||
- 默认(推荐):Linux native helper 与 RDP 使用窗口显示器 Adapter。
|
||
- 手动:下拉选择 Intel/AMD/NVIDIA Adapter,Linux 仍使用原生渲染器并验证 output 是否同 Adapter。
|
||
- Compatibility:用户明确允许原生 helper 使用软件解码,不满足双端零拷贝。
|
||
|
||
全局设置定义默认策略,每个 HostProfile 可以选择“继承全局”或覆盖 GPU。切换 Linux GPU 只重建当前 native 会话的 decoder/sink,不重启主程序。
|
||
|
||
诊断页展示实际生效值:
|
||
|
||
- GPU、LUID、驱动版本。
|
||
- 配置模式、用户选择与实际生效 Adapter。
|
||
- 解码器和 profile。
|
||
- D3D11/CPU memory path。
|
||
- Native renderer mode 和 hardware decode 状态。
|
||
- decode/render/upload time。
|
||
- dropped/late frames。
|
||
- device reset count。
|
||
|
||
## 14. 性能目标
|
||
|
||
| 场景 | 工程目标 |
|
||
|---|---|
|
||
| 1080p60 Linux Native | Agent/client 双端已验证零拷贝,原始帧无 CPU/cross-GPU copy |
|
||
| 4K60 Linux Native | 同 Adapter D3D11 surface 零拷贝;跨 GPU 时拒绝严格会话 |
|
||
| 1080p RDP | dirty rect 上传,静态桌面低 GPU/CPU 占用 |
|
||
| 多会话 | 后台限帧,前台输入与呈现不受阻塞 |
|
||
| 终端高频输出 | GPU 字形复用,滚动缓存有界 |
|
||
|
||
目标数值需要在 M0 使用真实硬件基线锁定,不仅依靠虚拟 GPU 或软件适配器。
|
||
|
||
## 15. 测试矩阵
|
||
|
||
- Intel 核显、AMD 显卡、NVIDIA 显卡。
|
||
- 单 GPU、混合 GPU、RDP/虚拟环境下 WARP。
|
||
- H.264 不同 profile/level 和异常码流。
|
||
- 720p/1080p/1440p/4K,30/60 fps。
|
||
- 单/双显示器,100%~200% DPI。
|
||
- 跨 GPU 显示器移动。
|
||
- 驱动重置、睡眠恢复和显示器热插拔。
|
||
- 多会话显存/硬解 session 压力。
|
||
- Compatibility 软件回退与恢复硬件路径,以及严格模式拒绝路径。
|
||
- 手动 GPU 触发 native helper,并验证实际 Adapter LUID。
|
||
- 零拷贝 `required_end_to_end/compatibility`、DMA-BUF/D3D11 surface、跨 GPU 和 CPU/software 拒绝。
|
||
|
||
测试使用 GPUView/ETW、GStreamer tracer 和应用 metrics 交叉验证,不能只看任务管理器的“Video Decode”百分比。
|
||
|
||
## 16. 发布门槛
|
||
|
||
- 至少 Intel/AMD/NVIDIA 各一种环境通过 1080p60。
|
||
- Native 路径证明客户端没有 GPU→CPU→GPU 或跨 Adapter copy。
|
||
- Wayland DMA-BUF 与 Xorg DRI3 到硬件编码器通过 CPU map/copy 验证,严格模式不会静默回退。
|
||
- Device Lost 可恢复或明确回退,不导致应用整体崩溃。
|
||
- 多 GPU 选择可诊断,错误 Adapter 不会静默黑屏。
|
||
- Compatibility 软件回退时自动降低质量上限;严格模式从不自动进入该路径。
|
||
- GPU/驱动信息在诊断包中脱敏且不包含画面数据。
|