實現快速迭代的引擎設計 - Capcom RE Engine的架構與實現

[譯]實現快速迭代的引擎設計 - Capcom RE Engine的架構與實現

原文(日文):ラピッドイテレーションを実現するゲームエンジンの設計算法

CEDEC2016上的一個Session。基本上是根據PPT的翻譯(可能成爲筆記更恰當一點),夾雜了一些現場聽來的信息。PPT裏有不少優勢舉例基本沒什麼養分就省略了。沒正經的翻譯過文章,有錯誤歡迎指正。主要是來抱囧聚大腿的。編程

如下正文:session

引擎簡介

  • RE Engine是Capcom內部開發的次世代遊戲引擎
  • 支持PS4,XboxOne,PC(Steam/UWP)等平臺
  • 應用於開發中的項目生化危機7
  • 引擎特徵:高性能,高開發效率 <- 本文主要內容

遊戲開發循環

  • 編程 → Build → 確認 → ...
  • DCC工具編輯 → 資源轉換/導出 → 確認 → ...
  • 遊戲啓動 → 測試/試玩 → 參數調整 → ...
  • QA → Bug修正 → 打包 → ...

傳統開發流程中,上面各個步驟不是費時間就是須要大量手工操做,效率相對低下。 架構

快速開發的實現

→ 最終節省下來的時間用來提高遊戲質量框架

  • 減小等待時間(主要是Build以及資源轉換等)
  • 減小每回試錯的時間
  • 提升在運行環境(特別是主機上)中運行的頻率
  • 下降Bug率

RE Engine界面(譯註:基本與UE4或Unity相近,支持所見即所得的編輯方式) 

一些細節異步

  • 生化7目前大約有20萬行C#
  • Editor裏能夠直接運行(總體更像UE4一點),支持全部資源的從新載入
  • Scene是樹狀結構,有一個Master Scene,裏面有Chapter1Scene等,導出Master Scene就等因而打包遊戲。隨着遊戲流程Load/Unload Scene
  • 演講的 石田 智史 就是設計了MT Framework的人

Scene的結構示例 

----------------------------------------------------------------------------------------------------------分佈式

引擎架構

(譯註:演講包括了新舊引擎的對比,但舊引擎的參考價值不大,故基本省略) 函數

  • 工具架構(Editor)
    • 工具和Runtime用TCP/IP通訊同步
      • Runtime就算崩潰了Editor也能繼續運行
      • Runtime包含了各個平臺的實現(如PS4的Runtime)
    • 工具部分用WPF/C#開發,運行於Windows平臺
    • 問題點
      • Runtime使用C++,而工具使用C#開發(包括遊戲邏輯)
      • 通訊同步致使大量操做須要異步的實現,增長了複雜度
      • 通訊受限於傳輸速度
    • 解決方案
      • 統一通訊協議:二進制通訊,用C#的定義生成C++代碼,Query/Response形式
      • 遠程對象系統:跨語言,跨進程的標識對象
        • RuntimeType,RuntimeObject跟C#本身相似,成員貌似只是key-value對
        • 經過ObjectID來同步(ID的正負來標識Editor/Runtime)
        • 以手動同步爲主,也能夠註冊進Observer來監視更新,對性能有影響
        • Gizmo之類的輔助對象也採用相似的方法實現
      • 優勢
        • Runtime能夠自由切換
        • 能夠對應一些只能在實際環境確認的功能(VR,手機等)
        • Runtime常常會崩潰ww
  • 資源架構
    • File-Based(舊)→ Asset-Based(新):文件更容易產生冗餘,而且不利於Reload
    • 全部資源支持異步更新,用Cache加速資源轉換,根據依賴關係優化打包速度
    • 問題點
      • Scene加載的時候須要預載入全部資源
      • 引擎須要把握資源的載入順序
      • 須要實現異步載入的功能
    • 解決方案
      • 靜態資源依賴關係生成
        • 導入Asset的概念:在文件裏追加了Metadata
          • 工具啓動的時候載入全部的Asset,並生成依賴關係
        • 禁止代碼控制的資源載入(譯註:是否是徹底不支持動態載入沒有細說)
      • 嚴格的資源管理(譯註:聽起來自由度至關低,但畢竟是內部引擎估計能夠根據實際需求調整而不用Hack)
        • 禁止同步載入(容易致使Spike),而且異步載入有利於總體吞吐量
        • 強制實現Reload
        • 從遊戲代碼不能直接訪問資源

資源依賴關係示例 工具

  • 腳本架構
    • 舊引擎開發遊戲即便用上分佈式Build多的時候也要15分鐘,而且容易崩潰,內存破壞
    • 新引擎開發遊戲時,遊戲的邏輯部分徹底使用C#,Build最多10秒,內存管理更好
    • 問題點
      • C#比C++更慢(Marshal,異常)(譯註:猜想Marshal應該主要是與SDK的交互或者與第三方庫的交互)
      • GC致使的長時間中止
      • 主機平臺兼容性差(JIT禁用等)
    • 解決方案
      • 自制C#虛擬機(REVM)
        • 以AOT爲前提,不支持JIT
        • 提升C++親和性,下降Marshal開銷
          • 重寫C#對象佈局 ↓ ,包了一層C++對象在裏面,Marshal的時候能夠直接傳指針。RC爲引用計數。
          • C# → C++:利用Clang解析C++代碼,生成供C#訪問的接口,最終和直接調用C++函數開銷相同
          • C++ → C#:利用template,最終和函數指針開銷相同(譯註:黑魔法沒仔細看。。。)
        • 更輕量的標準庫(從Core FX搬)
        • 編譯
          • 開發時:MicroCode(IL不適合解釋執行,自制MicroCode) → 解釋執行
          • Release時:C++(il2cpp)→ 編譯(Marshal部分inline展開)
            • 編譯時間:分散編譯15分鐘左右(跟舊引擎相近)

C#的編譯流程(Release時生成C++代碼) 
C#與C++的運行速度比較(有了GC當後盾對象生成快了不少) 
開發時與實際運行時的效率比較(譯註:能夠看出來開發時候也不是特別慘) 佈局

  • 自制實時垃圾回收(譯註:有些概念不太懂就沒詳細解釋了)
    • 現有的GC不適合遊戲
      • 分代GC:Major GC致使的長時間中止
      • 並行GC:GC執行中的速度低下,須要足夠的空餘內存
      • 自動引用計數方式:循環引用的泄露,對引用計數操做的高Overhead
    • 適合遊戲的實時GC(FrameGC)
      • 限定於遊戲應用
      • 主循環的同期點
      • C#做爲腳本的前提
    • 特徵
      • 預測,可控的中止時間(GC中)
      • 即時釋放性(譯註:用完的內存儘早釋放)
      • 能夠更有效的利用全部內存
      • 在多核環境下發揮性能
      • 與C++的親和性
    • GC算法(譯註:原ppt內有簡單的流程動畫說明可供參考)
      • LocalObject:TLS,存在LocalTable裏(固然也是TLS),C#生成的對象都做爲LocalObject
      • GlobalObject:全部線程都能訪問,C++生成的對象都做爲GlobalObject
      • LocalObject → GlobalObject(譯註:有點相似C#的Box只不過這裏不是stack和heap的區別而是可訪問線程和所屬Table的區別)
      • LocalFrame GC:C#的函數調用都結束的時候執行,釋放全部LocalObject(譯註:跟函數調用完了退棧差很少)
      • Local GC:LocalTable滿了的時候執行,根據引用計數釋放LocalObject(實際不多發生)
      • GlobalObject 釋放
        • 由各個線程增減引用計數,爲0了就釋放
        • 當沒有全部線程裏都沒有C#的棧(C#的調用都結束)的時候,執行Global GC(釋放全部被有被用到的)
      • 循環引用由Incremental Cycle GC釋放
        • (譯註:基本上就是掃一遍找出循環部分)
        • 每幀Check循環引用的輔助表CycleRoot,按需GC
    • FrameGC的Overhead
      • Write Barrier:線程內的直接Check引用計數,跨線程的利用InterlockedCAS
      • LocalObject→GlobalObject:相似↑

FrameGC的一幀的Profile結果(譯註:整數估計是Profile的Sample數)

----------------------------------------------------------------------------------------------------------

總結

  • C#就是好!
    • 生產效率大幅提高
    • 杜絕應用層(遊戲邏輯)產生的崩潰狀況
  • 執行效率沒有問題!
    • REVM比寫的挫的C++更快
    • FrameGC改變了GC不適合遊戲的常識

----------------------------------------------------------------------------------------------------------

現場Q&A

    • C#版本? 6.0 可是由於造了GC因此不算徹底支持。
    • 支持yield嗎?應該不支持(?),C#的部分不支持跨幀的處理。
    • 開發人數?開始2人 x 3個月,後來加了5,6人又作了幾個月。(譯註:聽起來有點快的可怕,不過去年CEDEC的時候就有相關消息了因此實際應該更長一點)。感謝評論裏@大薩比補充,現場有提到了開發速度快是由於RE引擎基於panta rhei開發。
    • 序列化用了什麼?第三方庫?沒有,由於涉及到ID之類的問題因此本身寫了。
    • 轉成C++代碼的時候出現問題了怎麼辦?那是bug...初期會有,如今已經基本沒有了。順便轉出來的C++代碼很長,VisualStudio會打不開...
    • 遊戲部分徹底是C#嗎?徹底是。
    • 若是開發遊戲的那邊提需求呢?由於是內部引擎因此能夠商量,但不會讓他們直接改。
    • 場景中的頂點數之類的統計數據能夠取得嗎?Asset的meta信息裏有,能夠作。可是美術基本不關心這個....
    • WPF的框架?Livet。
    • 中間件是集成到引擎裏?是的。
    • 對中間件有什麼要求?省內存,跑的快(笑)
相關文章
相關標籤/搜索