讓遠端桌面更好的支援遊戲

tieyan發表於2024-10-28

雲遊戲為什麼要用到遠端桌面

對於單程序單視窗的遊戲只需要捕捉一個渲染畫面,雲遊戲採用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之間任意值穩定)

相關文章