天天看點

Skia深入分析9——延遲渲染和顯示清單概念顯示清單——SkPicture延遲渲染——SkDeferredCanvas

android的硬體加速,是先将繪制指令存儲起來,然後回放,作為軟體繪制的引擎skia中同樣有這樣的機制。在android 4.4的版本中又加入了延遲渲染的canvas,它相當于預設使用顯示清單的canvas。

先得到顯示清單,再進行渲染,便有機會基于繪制api的整體情況做優化排程。比如使用gpu加速,裁剪過度繪制等。從原理上看,很可能在這一層級做比較大的效率提升,不過,由于android既定的渲染架構限制,盡管google在這方面做的東西很多,生效場景很少,收益也很有限。

skpicture的用法如下:

我們先看一下beginrecording函數:

如上述代碼所看到的,主要有兩種記錄方法,一種是skbboxhierarchyrecord,另一種是skpicturerecord。

skbboxhierarchyrecord:以 r-tree 算法組織繪制任務,這種方式需要計算繪制區域的包圍盒,在記錄文本繪制指令時這個計算還是相當耗時的,采用r-tree組織的好處是繪制指定區域時可以快速找出相關的繪制任務。

skpicturerecord:順序記錄方式,不做處理

圖檔存儲時需要判斷該圖檔是否是可變的(immutable),若不是可變的,需要複制圖檔到緩存。

skpaint的shader及各種特效隻存儲指針/引用。需要應用自行保證不做更改。

skpath也是複制了整個skpath及skpathref中所有點到緩存,注意到需要記錄和恢複的比較複雜的類,需要實作 writetomemory 和 readfrommemory 兩個方法

使用skwriter32寫入,在結束記錄後将其内容全部複制到 skpicture

created with raphaël 2.1.2skcanvas::drawpicturegpudeviceexperimental_drawpictureskpicture::drawskpictureplayback::drawyesno

鑒于gpu繪圖時還需要把之前存儲在緩存區的bitmap、path等上傳為紋理或vbo,直接以紋理/vbo建立緩存機制效率更高,是以有experimental_drawpicture一條分支,不過目前看來還是實驗階段。

具體如何回放的看src/core/skpictureplayback.cpp中skpictureplayback::draw函數即可,不詳述。

google的注釋很清楚地解釋了這個類的作用。這個類的用法和原始的skcanvas基本一緻。隻是設定了延遲屬性後,需要在使用繪圖結果前flush一下。

用法如下:

另外可以為skdeferredcanvas設定一個監聽器notificationclient:

class notificationclient {

public:

virtual ~notificationclient() {}

virtual void preparefordraw() {}//準備開始渲染時調用

virtual void storageallocatedforrecordingchanged(

size_t /newallocatedstorage/) {}

virtual void flusheddrawcommands() {}//目前繪制任務清空時調用,可以是拿去編碼/顯示/後處理等

virtual void skippedpendingdrawcommands() {}//目前繪制任務被取消掉時調用,可以用來清除額外的資源

};

繼續閱讀