12 KiB
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 就报告硬件加速。
探测顺序:
- 枚举 DXGI Adapter 和 Output。
- 尝试创建 D3D11 device 和 Desktop Duplication。
- 尝试 AcquireNextFrame,并验证连续帧。
- 探测 NVENC、AMF/VCE/VCN、Quick Sync 的实际编码能力。
- 硬件路径不可用时,若用户显式选择 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. 渲染架构
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 桌面会话报告实际路径:
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。
选择模式:
- 默认(推荐):Linux native helper 和 RDP helper 都选择窗口当前显示器 Adapter。
- 手动:从 Rust 枚举的物理 GPU 列表选择固定 Adapter;Linux 始终使用 native-video helper。
- 手动 GPU 不存在时可回到窗口 Adapter 重新验证,但驱动失效、不支持 codec 或发生跨 GPU copy 时,Linux 严格会话失败且不改写配置。
- WARP 仅用于 RDP 或显式 compatibility,不能满足 Linux 双端零拷贝。
GPU 选择持久化使用 LUID/PCI identity 的稳定组合,不只保存容易变化的枚举序号。
配置优先级:主机级手动选择 > 全局手动选择 > 默认模式。运行时诊断同时展示“用户选择”和“实际生效”Adapter。
5. Linux 视频硬解码
5.1 默认原生零拷贝路径
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 软件回退路径
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:
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 图形输出分两类:
- 已解码 bitmap/dirty rect:上传变化区域到 D3D11 texture。
- 可获得的现代 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:
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/驱动信息在诊断包中脱敏且不包含画面数据。