Files
RemoteDesk/docs/gpu-acceleration.md
T
曾志威 19a8e03a83
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
Document all-Rust migration and extend native media stack
2026-08-14 14:31:57 +08:00

275 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 实现,不能报告为硬件 GPUMicrosoft Basic Display Adapter 也不能视为硬件编码器。
无硬件编码器时,系统自动应用软件上限。默认先尝试 1080p30/60 或实测可承受的更低档位;请求多路 4K/120 时,strict 性能模式返回 HARDWARE_ENCODER_UNAVAILABLEcompatibility 模式降档并明确显示 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 列表选择固定 AdapterLinux 始终使用 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 framebufferD3D11 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 复制并提示移动窗口或改选 Adaptercompatibility 才显示并允许 `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 AdapterLinux 仍使用原生渲染器并验证 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/4K30/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/驱动信息在诊断包中脱敏且不包含画面数据。