第十七篇:使用窗口的cache屬性加速SOUI的渲染


內容渲染速度是決定一個UI成敗的關鍵。無論UI做得多華麗,沒有速度都沒有意義。

在MFC,WTL等開發框架下,每個控件都是一個窗口,窗口只需要畫前景,背景。因為窗口之間的內容不需要做混合,一個子窗口的一次刷新只涉及該窗口本身,和其它窗口無關,因此這樣效率很高。但是美中不足在於,窗口之間內容是孤立的,要想不同窗口之間的內容更協調,對美術有很高的要求,同時也基本只能適應個別窗口大小相對固定的場景。

要使UI更加漂亮,最簡單有效的方法就是采用alpha混合的方式將各層的窗口相互混合,這樣窗口之間沒有了邊界的感覺,從而使得UI更像一個整體,這也是現代UI的主要實現方式。

想像一下,如果一個最上層的子窗口內容發生了變化,UI系統如何把窗口內容繪制出來呢?

首先需要通知UI系統的渲染對象說我的窗口顯示區域內容發生了變化,請求重繪。

UI系統拿到渲染對象后,對渲染范圍設定剪裁區(clip),防止刷新那些不需要重繪的區域。

UI系統從最頂層的窗口開始依次繪制每一層的和剪裁區重疊的窗口的內容(不同窗口之間繪制內容的混合由繪制方法定義,例如圖片可能是利用alpha通道)。

為了防止繪制過程中出現閃爍,一般上面繪制都是在一個內存繪圖設備(如內存DC)上進行。在全部繪制完成后,將繪制內容再呈現到屏幕。

那么問題來了:一般子窗口會比父窗口小,子窗口請求重繪時,要執行父窗口的繪制函數,如果父窗口沒有根據當前的剪裁范圍來確定自己的繪制范圍,那么盡管有剪裁區限制了不會繪制超出邊界,在實際執行過程中,超出剪裁區的繪制行為也可能極大的影響UI的性能。

如何解決這個問題呢?

解決的方法可以有很多,比如在每個窗口的繪制方法都實現只繪制在剪裁區的那部分(實際上實現起來非常麻煩,附加的剪裁區計算也可能成為新的繪制瓶頸);又比如每個窗口都保留背景窗口的內容,當窗口需要刷新時,直接直接把背景內容拿過來在上面畫。

第二種方法看起來效率是最高的,但是實際上可能並不高:雖然在繪制自己的內容時速度快了,問題是自己更新以后,還需要同時更新它的上層窗口的緩存,可能導致內存開銷大,效率也不高。

在SOUI中,我們采用了第三種方法:給窗口加一個cache屬性。

當cache=0時,窗口的繪制和前面提到的流程一樣,只是如果窗口比較大,而需要一時半會的區域比較小時,速度慢一點。

如果cache=1,則窗口繪制的內容會被保存到一張緩存位圖上,當其它窗口刷新並導致該窗口重繪時,直接從緩存中復制出來就可以了。

假定一個窗口使用一張小圖片進行九宮格拉伸繪制出來,繪制整個窗口由於拉伸中的插值等一系列的計算,繪制可能需要消耗大量的CPU時間,而有了緩存以后,只在第一次繪制的時候使用圖片繪制方法進行繪制,其它時間都是直接從緩存復制,效率能夠極大的提高。

很顯然,cache屬性在提高渲染效率的同時,也需要開辟一塊緩存來保存繪制內容,也就是常見的空間換時間的方法。因此如果繪制本身速度就足夠快,那么完全可以不使用緩存(比如給一個窗口填充一個純色的矩形)。

總結:

cache可以提高繪制速度,但是是以更高的內存占用為代價的,應該只在需要的地方使用(例如頂層背景窗口)。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM