让远程桌面更好的支持游戏

云游戏为什么要用到远程桌面

对于单进程单窗口的游戏只需要捕捉一个渲染画面,云游戏采用hook+sandboxie的方式基本可以在默认桌面模拟出完整的独立运行环境。但是对于带启动器的游戏,上面的方案并不能很好的工作,因为用户可能随时切换窗口或者游戏存在不确定的弹窗,为此需要给游戏提供独立的操作桌面(类似ecs,相当于一个游戏分配一个虚拟机)。

如果一个虚拟机只跑一个游戏,也会造成成本提升/资源浪费。由于服务器由硬件厂家提供,我们几乎没有diy的空间,同时我们也没有kvm的能力储备,所以调研方向变成了怎么在一个虚拟机上运行多个桌面。windows会给每个单独登录的用户分配独立的桌面,于是远程桌面自然成了首选方案。

远程桌面中运行游戏遇到的典型问题

游戏启动异常


通过逆向游戏进程发现是游戏主动检测远程桌面抛出异常 (通过GetSystemMetrics SM_REMOTESESSION)

解决方案:注入dll hook GetSystemMetrics或者驱动动态修改相关内存

游戏启动弹窗


通过逆向游戏进程发现是系统dxgi.dll返回失败导致游戏以为显卡有问题

dxgi.dll的实现,如果是远程桌面显示器那么直接返回失败

解决方案:patch dxgi.dll然后签名,覆盖原始文件

远程桌面内主动修改分辨率

由于原始桌面的限制,远程桌面内不允许修改分辨率(手动和代码修改都不行)

然而dxgi.dll经过patch后游戏已经能获取到完整的分辨率列表,游戏内用户主动修改分辨率会无效,体验略奇怪

解决方案:远程桌面的客户端选用 https://github.com/FreeRDP/FreeRDP 或者商店版本的mstsc,hook游戏的win32u.dll NtUserChangeDisplaySettings, 当修改分辨率的时候参数透传给freerdp/mstsc, 同步等待操作完成。

rdp对帧数的限制

帧率其实有两个,一个是游戏自身的帧率,一个是dxgi抓屏的帧率
https://learn.microsoft.com/zh-cn/troubleshoot/windows-server/remote/frame-rate-limited-to-30-fps
rdp的fps也是最玄学的部分,微软官方还写了文章教你设置fps。其实文章并不准确,因为windows用户态的Sleep函数精度无法保证。

帧速率映射
15 decimal = 60 帧
10 decimal = 40 帧
5 decimal = 20 帧
1 decimal = 4 帧

通过010暴搜DWMFRAMEINTERVAL,定位到关键的几个文件

逆向发现如果开启远程桌面,dxgkrnl.sys会专门启动内核线程进行vsync模拟, 同时dwm.exe会额外加载rdsdwmdr.dll进行离屏渲染逻辑

v11即注册表配置的值

大概分析逻辑后对相关的文件patch魔改,使得《坦克世界》rdp下双开都能稳定在60fps(目前的业务需求只需要60即可,其实能在60-90之间任意值稳定)

posted @ 2024-10-28 09:43  tieyan  阅读(19)  评论(0编辑  收藏  举报