Skia深入分析8——Skia的GPU繪圖

目錄(?)[+]

Skia的GPU繪圖

一、Skia-GPU概述

在Android4.2到Android5.0的過程中,skia中開發較頻繁的部分莫過於GPU加速部分和延遲渲染機制,儘管目前來看幾乎沒有用到,但後續很可能會在Frameworks層引入。 
Android上面,只可能使用OpenGL,因此作爲使用OpenGL的繪圖引擎,關注如下要點即可: 
1、OpenGL上下文如何建立(關係到如何顯示繪製結果) 
2、頂點如何生成 
3、着色器如何管理,特效怎麼設置 
4、紋理、vbo、字體cache等緩存管理機制 
由於OpenGL編程本身很複雜,東西也很多,這裏只是介紹一下用法和流程框架,有興趣研究的可按上述問題細看。

二、用法

<code class="hljs lasso has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*獲取OpenGL上下文*/</span>
GrContextFactory contextFactory;
GrContext<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">*</span> context <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> contextFactory<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>get(GrContextFactory<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;">::kNative_GLContextType</span>);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*創建指定大小格式Surface,並由Surface中取出Canvas*/</span>
const SkImageInfo info <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> SkImageInfo<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;">::MakeN32Premul</span>(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">720</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1080</span>);
SkSurface<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">*</span> surface <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> SkSurface<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;">::NewRenderTarget</span>(context, info);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//實際上是創建一個紋理,並創建相應的fbo與之綁定,以作爲渲染目標</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//或者用 NewScratchRenderTarget,這個會用緩存過的目標紋理</span>
SkCanvas<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">*</span> canvas <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> surface<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-></span>getCanvas();
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*執行繪製*/</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*canvas->drawColor(0x0);*/</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*..........*/</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*..........*/</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*..........*/</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*繪製完成,取出像素*/</span>
SkBitmap output;
output<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>setInfo(info);
canvas<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-></span>readPixels(<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">&</span>output);
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*又或者讀到GraphicBuffer上*/</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*輸入 ANativeWindow_Buffer outBuffer*/</span>
canvas<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">-></span>readPixels(info, outputBuffer<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>bits, outputBuffer<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>stride<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">*</span><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">/*ARGB*/</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li></ul>

Skia創建GPU上下文時,其Surface並不關聯Android裏面的顯示系統,因此是無法直接渲染上屏的,在繪製完成之後需要額外的一次readPixels,也即內存拷貝,這使其不適合做實時渲染。只是在做比較複雜的效果,如Bicubic插值、光照、模糊時,可以用一用。 
關於 Skia的特效,可以看 include/effects 和 src/effects 目錄下面的代碼,這裏面是CPU方式實現的。由於很少見用到,之前並沒有介紹。 
對應的gpu特效實現見 include/gpu 和 src/gpu/effects目錄下的代碼。

三、流程與框架

SkGpu的一次繪製基本流程如下:

SkCanvasSkGpuDeviceGrContextGrDrawTargetGrGpuGrGLInterface

SkCanvas:如之前章節所述,下發命令,保留Layer 
SkGpuDevice:處理退化情況,將SkPaint轉化爲GrPaint 
GrContext:構建形(頂點Vertex)且處理抗鋸齒,描述色(GrDrawState) 
GrDrawTarget:描述繪圖目標,起接口作用,將材料打包爲Drawinfo,由子類執行 onDraw方法。 
GrGpu:設定Shader、設定頂點,調用OpenGL接口渲染 
GrGLInterFace:由於各個廠商支持的OpenGL標準版本有所不同,且一些廠商會增加一些接口,這一層做一個API適配,這樣平臺相關的代碼就集中在此層級。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章