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() {}//目前繪制任務被取消掉時調用,可以用來清除額外的資源
};