作者| 阿里文娛無線開發專家 風吟
一、背景
在當前直播和短視頻領域,各家公司為了吸引用戶和提升用戶體驗都在創新各種視頻玩法, 例如美顏、美妝、虛擬形象等。這些酷炫的效果背後其實是強大的渲染技術。優酷和來瘋也在 佈局這一領域,我們亟需一個底層渲染框架來高效地支撐我們的業務迭代。於是,自主開發一個跨平臺、可擴展、高性能的渲染引擎就被提上了日程。
二、引擎設計
1. 引擎特點
前面說了我們的目標是開發一個跨平臺、可擴展、高性能的渲染引擎。怎麼理解?下面詳細闡述一下:
1)跨平臺。
我們的業務場景涵蓋了移動端和 PC 端。為了提高開發效率,我們要把平臺無關的邏輯抽象成公共組件,例如渲染管線、後處理算法等,實現一份代碼,多端共用。
2)可擴展。
跨平臺解決了橫向的平臺差異問題,而可擴展就是解決業務迭代的縱向問題。 我們將渲染邏輯分解成一個一個的小“零件”,業務方可以像搭積木一樣自由組合這些“零件”, 而算法同學也可以很容易的造“零件”。這樣業務迭代就簡化成了簡單的加減法,效率大大提升。
3)高性能。
音視頻渲染,尤其是視頻渲染,是很耗費計算資源的。在端側有限的計算資源 前提下,還要能實現快速、高質量的渲染效果,就需要我們釐清渲染鏈路中的每個環節,剔除 冗餘邏輯,實現高效渲染。
2. 引擎架構
在以上思想的指導下,我將渲染引擎分成了兩層: 引擎層( Engine )和業務封裝層 (MediaSDK)。
1)引擎層是平臺無關的,使用 C++開發,渲染後端使用了各平臺都支持的 OpenGL 框架。 核心思想是把渲染鏈路抽象成有向無環圖(DAG),最基礎的組件抽象成插件(Plugin),所有 的數據源(Source)、算法(Filter)、輸出終端(End)都是插件,再定義好插件的輸入/輸出協 議,只要上下游插件的數據交互滿足協議就可以自由組合。引擎層的架構圖如下:
2)業務封裝層封裝了引擎層的調用邏輯,在 Android、iOS 和 Windows 平臺上對業務方提 供統一調用接口,方便業務同學使用,並提供日誌、監控和資源管理等能力。業務封裝層的架 構圖如下:
三、實踐
1. 技術挑戰 實現過程有兩個挑戰,一個是跨平臺,一個是高性能。
1)跨平臺
a)引擎層雖然使用了 OpenGL 作為渲染後端,但 Android 和 iOS 系統提供的是 OpenGL ES, Windows 提供的是 OpenGL,這兩個版本在 shader 語法上是有差別的,這就需要引擎和算法去 做適配。其次,要使用 OpenGL 需要在每個平臺上都實現一個上下文環境,iOS 是 EAGL,Android 是 EGL,Windows 是 WGL。各平臺雖然都有封裝好的 GL 組件,但是都不太好用(有 Bug), 最好的辦法還是自己調用底層 API,這就需要對 OpenGL 有一定的瞭解;
b)業務封裝層封裝了引擎層的底層接口,對外提供統一業務接口。而業務開發是平臺相關 的,語言也不盡相同,Android 是 Java,iOS 是 OC,Windows 是 C++。並且像相機、編/解碼器、 View 這些系統組件各平臺實現並不統一。因此開發業務封裝層需要對各語言和系統特性都有較 深入的理解,才能實現易用性和性能的統一。
2)高性能
a)一個思路是儘可能的使用 GPU,解放 CPU,因為 GPU 在視頻處理方面有天然優勢,引 擎裡的計算基本上都放在了 GPU 側,包括圖像色彩空間轉換、後處理等。而且在某些場景下還 會對圖像做下采樣,進一步降低 GPU 使用率;
b)即使算法都使用 GPU 實現,但是還要面對顯存-內存數據互傳的問題,從內存上載數據 到顯存和從顯存下載數據到內存都會阻塞 CPU,導致 CPU 佔用率高。解決方法一是引擎內部 數據都使用紋理傳遞,儘可能減少顯存-內存數據互傳。二是使用雙 PBO,異步傳輸數據,但這 個方案需要注意數據同步的問題。
2. 引擎落地
1)算法接入 由於引擎的算法實現都抽象成了插件,而且將渲染的公共邏輯都提取到基類,算法同學接入算法時只需要關注 shader 本身就可以了,接入是很方便的。理論上只要符合插件規範,任何算法甚至二方或者三方SDK 都是可以做成插件接入進來的。目前引擎接入的算法能力有:人臉 檢測、美顏、濾鏡、2D 貼紙,未來還將接入美妝、美體、3D 貼紙、Avatar 等。
2)業務接入
渲染引擎提供了多種輸入,如相機採集、幀序列等;多種輸出,如 UI、編碼、幀序列等, 結合前面提到的算法能力,業務方只需要調用簡單的幾個接口就可以定製自己的渲染管線,從 而實現自己的業務需求。目前渲染引擎接入了來瘋 iOS 和 Android 雙端,來瘋 PC 瀏覽器插件, 優來播 iOS 和 Android 雙端。並且穩定迭代了若干個版本,在多個業務場景中使用,例如秀場直播、電臺直播、錄屏直播等。
四、總結與展望
1.沉澱
回顧整個渲染引擎的開發過程,其實是踩了很多坑,也是對渲染技術的一次深入挖掘。整個架構的設計經受住了業務的考驗,也為今後類似 SDK 的開發提供了寶貴的經驗。
2.引擎存在的不足
雖然渲染引擎在目前的應用場景中運行良好,但還是存在一些不足,主要有兩點,一個是 OpenGL 天生的缺陷,即 OpenGL 上下文和線程是強相關的,導致渲染引擎設計上雖然是一個 DAG,但實際上管線的所有繪製操作都是串行的,不能充分發揮 GPU 性能;二是引擎內部數 據傳輸只支持 push 的方式,即只能上游推動下游消費數據,而不能下游主動從上游拉取數據消 費,這就制約了引擎的使用方式。
3.引擎 2.0
前面提到渲染引擎在低端機上性能不佳,主要原因是 OpenGL 渲染耗時。其實谷歌和蘋果 都已經在最新的代碼中將 OpenGL 標記為 deprecated,分別在推廣新一代渲染框架,即 Vulkan 和 Metal,而微軟也有自家的渲染框架,即 DirectX:
這些新框架思路大同小異,相比 OpenGL 的優點有:支持預編譯 shader、支持多 CPU 線程、 支持直接訪問 GPU CommandBuffer 等,對開發者更友好,運行效率更高,甚至能達到成倍性能提升。所以,未來渲染引擎的 2.0 版本將會支持多 backends,包括 Vulkan、Metal 和 DirectX, 以實現更好的性能。