寫在最前
關於mali的架構的一點深入瞭解,將現有的GPU的基本流程和mali的做對比,提出其中的優點與缺點。原文地址:https://developer.arm.com/graphics/developer-guides/tile-based-rendering
傳統GPU
傳統GPU的架構一般被稱爲Immediate mode GPU.主要的流程就是vertex shader 和 fragment shader順序執行,僞代碼如下:
for draw in renderPass:
for primitive in draw:
for vertex in primitive:
execute_vertex_shader(vertex)
for fragment in primitive:
execute_fragment_shader(fragment)
數據流是這樣的:
優點
主要優點就是vertex的輸出能夠留在片上,可以被下一階段直接快速讀取。
缺點
如果有很大的圖形(主要是三角形)需要被渲染,那framebuffer就會很大,比如對於整個屏幕的顏色渲染或者深度渲染就會消耗很多存儲資源,但是片上是沒有這麼多資源的,因此就要頻繁讀取DDR。很多和當前frame有關的操作( 比如blending, depth testing 或者 stencil testing)都需要讀取這個working set,因此需要的帶寬是很大的,並且這樣能耗也很高,對於移動設備來說,這種方式很不利於設備運行。
Tile-based GPU
因此mali的GPU提出了Tile-based概念,就是將圖像分成16*16的小塊。分小塊進行渲染,最後寫入到DDR,就能夠減少讀寫DDR的頻率,進而解決上述問題。不過分塊需要知道整個圖像的幾何學信息,所以操作分成了兩步:
- 第一步執行幾何學相關的操作,併產生tile list.
- 第二步對每一個tile執行fragment操作,完成之後寫入內存
僞代碼如下:
# Pass one
for draw in renderPass:
for primitive in draw:
for vertex in primitive:
execute_vertex_shader(vertex)
append_tile_list(primitive)
# Pass two
for tile in renderPass:
for primitive in tile:
for fragment in primitive:
execute_fragment_shader(fragment)
數據流如下:
優點
顯而易見,解決了傳統模型的帶寬問題,因爲fragment shader每次都是讀取一個小塊放在片上,不需要頻繁讀取內存,直到最後操作完成,再寫入內存。甚至還能夠通過壓縮tile的方法進一步減少對於內存的讀寫。另外在圖像有一些區域固定不動的時候,通過調用函數判斷tile是否相同,減少重複的渲染。
缺點
這個操作需要在vertex階段之後,將輸出的幾何數據寫入到DDR,然後才被fragment shader讀取。這之間也就是tile寫入DDR的開銷和fragment shader渲染讀取DDR開銷的平衡。另外還有一些操作(比如tessellation)也不適用於Tile-based GPU。
總結
現在屏顯的分辨率越來越大從1080p到1440p再到4K,可以遇見的,mali這種架構將在未來大規模使用。
不過也有一些陷阱,開發者需要避開。首先是要合理設置render pass以充分利用這種架構的特點;其次要了解這種幾何學分割所能得到的好處。