愛奇藝自研 UI 引擎渲染技術分析
點選上方 “ 開發者技術前線 ”, 選擇“星標”
13點21分打卡 就是真愛
來源:愛奇藝技術產品團隊 | 本期 責編:可可
摘要
我們都知道,好的視訊內容可以吸引更多使用者。那麼在好的內容基礎上,我們希望用更好的架構及渲染技術,不斷迭代出更輕、更炫、更平滑的客戶端,保證使用者有更好的體驗。在此驅動下我們致力於開發一套高效的跨平臺渲染引擎Lyra,為使用者提供新的體驗。本文主要詳細闡述在PC客戶端上引入的新渲染技術。
愛奇藝PC客戶端之前使用的UI引擎是公司內部開發的QuiLib。QuiLib是基於開源的uilib和DuiLib開發的輕量級的UI引擎。QuiLib使用了DirectUI框架,其主要思想就是控制元件無視窗化。雖然在很長一段時間內,QuiLib都發揮著至關重要的作用,但是隨著渲染技術和計算機技術的發展,QuiLib暴露了它的很多缺點。
QuiLib的渲染的流程
QuiLib的動畫Timer、業務邏輯、佈局、渲染等均在主執行緒,這樣每一個階段的耗時都會導致整個流程的推遲或卡頓,其主要問題有:
(1)繪製效能差,如當UI元素進行alpha或者旋轉變化時,paint慢且需要多次記憶體拷貝,效率很低;
(2)冗餘layout,排版效率低,一次業務處理過程中若對某個節點多次操作,會導致該節點冗餘layout;
(3)動畫不流暢,每組動畫都有獨立的時間線,同時主執行緒負載太重,任何一環耗時,都會導致動畫不平滑,使用者體驗差。
其次,在元件架構層面,QuiLib也存在一些欠缺。
元件架構圖
從元件架構圖可以看出:QuiLib基於Windows和GDI圖形庫;QuiLib 沒有利用D3D等3D圖形技術來給UI渲染提速,並且重度使用了GDI,無法做到渲染跨平臺化。這樣會導致如下問題:不能充分利用顯示卡的效能,不支援跨平臺化。
技術引入
為了解決現在的框架(即Quilib)具有的以上問題,我們做出了以下的技術解決方案:
(1)3D渲染:充分利用顯示卡效能,加速圖形渲染速度;
(2)非同步渲染:把渲染流程細劃為業務邏輯、樣式變化、佈局、生成渲染命令、執行渲染命令、合成渲染層和重新整理到螢幕幾個階段;每個執行緒使用一個唯一的動畫時間線,來驅動動畫;
(3)分層渲染:根據情況,自動把某些頻繁渲染的元素從主渲染層提升為單獨的渲染層,這樣每個層都進行單獨的渲染流程,最後再把這些渲染結果合成並且上傳到螢幕;
引入新的設計思想和渲染技術,能夠讓基於Lyra開發的PC應用執行更平滑,達到和mac系統上應用一樣的平滑度。
技術實踐
為了實踐以上設計思想和渲染技術,我們開發了一個新的UI渲染引擎並且命名為Lyra(天琴座),寓意希望新的UI渲染引擎像天琴座一樣燦爛。
跨平臺和GPU渲染圖形庫
Lyra一開始就致力於跨平臺和GPU加速渲染。通過調研和比較現在流行的圖形庫及遊戲渲染引擎,Lyra最終選擇了使用skia。
Lyra引擎元件架構圖:闡述了新UI引擎的層級關係
skia具有如下這些優點:
(1)跨平臺;
(2)高效基本圖元渲染;
(3)高效的字型處理及文字渲染;
(4)豐富的影象格式支援;
(5)支援3D渲染,可以無縫切換為2D渲染。
得益於skia 3D & 2D backend的無縫切換,lyra可以針對不同的機器配置選擇不同的渲染方式,優化Layered視窗這種需要渲染後處理的特殊情況,支援執行時渲染方式的自動fallback。也正是3D & 2D backend的無縫切換也導致skia資源佔用很高,為了優化資源佔用及命令序列化,也需要做很多侵佔式的定製,在此不詳述了。
非同步渲染
Lyra使用了多執行緒渲染技術:UI主執行緒主要負責與使用者互動,Render執行緒主要負責圖形渲染。
Lyra新的渲染流程圖
如上圖:Lyra把渲染流程細分為更多的步驟:Event&Message、樣式變化、Layout、Paint(生成繪製命令)、Execute(執行繪製命令)、合成、重新整理到視窗。在渲染過程中,比較耗時的幾個點就是使用者邏輯處理、Layout和執行渲染命令、合成。
Lyra把Paint以及其之前和Execute以及其之後分為兩大塊,這兩大塊是並行執行。這樣的好處是:執行渲染命令的耗時不會導致使用者響應延遲,主執行緒的Timer等比較耗時的邏輯也不會導致渲染延遲;同時形成渲染流水,執行靈活的幀選擇策略,最大化渲染效率,提高響應速度。
動畫系統由基於執行緒的唯一Timer來驅動,保證一個執行緒一個時間線,這樣減少了Timer資源的消耗,提高了動畫的渲染效率。同時將動畫分為主執行緒動畫和render執行緒動畫,主執行緒動畫操作邏輯渲染節點,Render執行緒動畫驅動layer層相關動畫。動畫系統自動將不同的動畫附著到不同的執行緒。通過如此設計可以支援3D動效、複雜動效,各部件聯動,最大化動畫幀率。
分層渲染
我們知道一個UI程式,大部分時候只有個別元素在響應事件。比如旋轉時,理論上我們只需要繪製正在旋轉的這個元素就可以。所以基於這種理念,Lyra實現了分層渲染技術,針對於每個元素,Lyra內部會根據情況建立新層或者銷燬多餘的層。
分層渲染,需要解決以下問題:各種樹之間的邏輯關係;何時建立新的層。
我們用一個示例來說明分層技術的實現原理。
只有主層
在這個示例中,UI第一次展示時,只有主層,如下圖所示:
建立分層渲染中的所有樹:
(1)解析xml生成一棵Control樹,這棵樹主要負責處理事件和訊息,以及管理各個Control的生命週期;
(2)生成一棵RenderObject樹,這棵樹的RenderObject和Control樹中的Control有一一對映關係,並且RenderObject生命週期的管理完全由Control負責;
(3)Lyra根據需要會生成一棵RenderLayer樹,同時也會生成一棵GraphicsLayer樹;GraphicsLayer樹上的結點和RenderLayer樹上的結點有一一對映關係。
構建新層
當用戶旋轉其中一個元素時,就需要建立新的層。旋轉C-5時,樹之間的關係以及層之間關係就有如下圖新的變化:
這裡Lyra根據需要會生成新的層RL-Rotation(對應於RO-5)和RL-Fake(對應於RO-6)。
非同步繪製
示例中的3層在UI主執行緒生成繪製命令,並且交換到Render執行緒,下圖展示了非同步繪製:
RenderLayer樹來負責驅動關聯於它上的RenderObject的Paint,生成繪製命令。 GraphicsLayer對應於真正的LyraSurface,會驅動RenderLayer生成繪製命令,並且把繪製命令交換到渲染執行緒。
渲染執行緒在接收到繪製命令後,填充螢幕畫素,如下圖所示:
Lyra合成器會驅動GraphicsLayer在渲染執行緒中執行繪製命令,並且合成繪製結果,最後重新整理到螢幕上。
本文主要簡述了Lyra渲染技術相關的一些突破性工作:
(1)3D渲染、跨平臺渲染;
(2)非同步渲染,基於執行緒Timer驅動的動畫系統;
(3)分層渲染。如果你想深入瞭解或者使用Lyra,可以直接在公眾號上留言。
開發者技術前線 ,彙集技術前線快訊和關注行業趨勢,大廠乾貨,是開發者經歷和成長的優秀指南。
喜歡就點個好看吧!