移動平臺延遲渲染

寫主機(jī)世代演進(jìn)的時候提到過延遲渲染。這次就給同學(xué)們講一下移動平臺延遲渲染的實現(xiàn),并利用openGL擴(kuò)展,充分優(yōu)化延遲渲染的幾個性能瓶頸。如果是有意從事引擎開發(fā)、TA的同學(xué)請一定把這些概念弄清。
回顧openGL ES 3.0
要說openGL ES 3.0相比openGL ES 2.0的最重大進(jìn)步之處,我個人認(rèn)為有如下幾個:
VAO/UBO
Instanced Rendering
Tranform feedback
Multiple Render Target
當(dāng)然SSO,Immutable Texture Storage,half-float color,VTF等特性也都很重要
而在這些新特性之中,MRT可以說是最重要的特性,因為它可以完全改變渲染的方式,產(chǎn)生新的可能性。而其他API一般是性能提升/用法改進(jìn),沒有MRT的革命性。
Multiple Render Targets
MRT,可以在一個drawCall向多張貼圖進(jìn)行渲染(至少為4),MRT最主要的用途,就是實現(xiàn)各種上級渲染,比如Deferred Shading,forward+ Shading,Deferred+ Shading。
延遲渲染一般分三個階段:
Geometry State:幾何階段收集場景的color,normal,depth,albedo信息
Lighting Stage:估計每個像素影響的光照信息
Shading State:依靠光源信息來計算場景最終的顏色

幾何階段代碼實現(xiàn)


延遲渲染的優(yōu)缺點:
優(yōu)點:
能同時處理眾多光源
提供穩(wěn)定的幀率
缺點:
消耗大量的顯存和帶寬
光照階段所有材質(zhì)必須使用完全相同的光照模型
不能很好的支持半透明
不支持硬件抗鋸齒
優(yōu)化:使用Framebuffer Fetch
延遲渲染在光照處理階段,要對幾何階段產(chǎn)生的4個RT進(jìn)行采樣,需要消耗大量的帶寬??梢允褂?nbsp;Framebuffer Fetch
擴(kuò)展來減少采樣時的帶寬消耗。
EXT_shader_framebuffer_fetch
語法:

使用 Framebuffer Fetch
后渲染流程簡化為入下圖所示。

優(yōu)化++:使用Shader Pixel Local Storage
有了Framebuffer Fetch雖然可以減小硬件采樣時的效率損失,但是還是要消耗大量的顯存和帶寬,優(yōu)化要優(yōu)化瓶頸,有沒有處理這個問題的方法。當(dāng)然有,就是 Shader Pixel Local Storage
。
Shader Pixel Local Storage 是一個可以完全扭轉(zhuǎn)MRT所有IO消耗的擴(kuò)展??梢哉f,是一個神擴(kuò)展。它的原理很簡單,就是將數(shù)據(jù)存在GPU的片上緩存而不寫入主存(顯存)。當(dāng)然原理聽著簡單,實現(xiàn)起來可并不容易。因為緩存很小也很貴。不過,得益于幾乎所有主流的移動 GPU 都是 Tile based,以瓦片為單位存儲消耗就很小了,在緩存上也完全存的下。

主流桌面GPU沒有 Tile based,故桌面 GPU 也沒有支持 Shader Pixel Local Storage 的,可惜。F+這種瓦片渲染普遍基于計算著色器實現(xiàn),十分精細(xì)
要使用Shader Pixel Local Storage,首先開啟擴(kuò)展
#extension GL_EXT_shader_pixel_local_storage : enable
之后使用 Pixel Local Storage 存儲結(jié)構(gòu)代替MRT即可, Pixel Local Storage 存儲結(jié)構(gòu)和 shader io block 很接近,但是需要描述Qualifier和layout:

實例:



Pixel Local Storage
Pixel Local Storage優(yōu)化的延遲渲染完整shader實例代碼(使用最基礎(chǔ)的diffuse光照模型)
幾何處理階段

估算光源

最終著色(resolve everything)

Shader Pixel Local Storage和MRT性能比較:


小結(jié)
本文標(biāo)題是延遲渲染,所以實現(xiàn)的都是延遲渲染。依靠擴(kuò)展實現(xiàn)延遲渲染,其實沒那么費(但是半透明以及MSAA的問題依舊存在)。其實依靠移動平臺的這些優(yōu)勢做F+優(yōu)勢更明顯。到此,其實也能說明一個老生常談的問題,那就是 openGL 其實沒那么差。
metal作為openGL的精神繼承人,在繼承AMD mantle API高效的同時,實現(xiàn)得比openGL還要簡單,還吸收了MSAA depth/stencil resolve,framebuffer fetch, shader local storage等openGL擴(kuò)展作為標(biāo)準(zhǔn)的一部分,充分說明了APPLE務(wù)實的作風(fēng)。反觀vulkan的設(shè)計,太學(xué)院派了,非常復(fù)雜不說,甚至相比openGL本身還出現(xiàn)了功能上的缺失真的不知道怎么評價。
APPLE metal設(shè)計之初的核心思路是讓buffer格式被CPU和GPU同時支持,來處理openGL buffer在內(nèi)存和顯存之間的反復(fù)拷貝的問題,可以說一開始是很面向移動設(shè)備的。而AMD mantle最初的設(shè)計核心是讓Pipeline state的狀態(tài)一致可預(yù)測,減少Pipeline狀態(tài)切換和狀態(tài)檢查的性能損失。補充一下,免得誤導(dǎo)。
參考文獻(xiàn)
Advances in OpenGL ES 3.0 - Apple iOS7 Tech Talks 2013
Deferred Rendering Techniques on Mobile Devices - Ashley Vaughan Smith[GPU pro 5]
Bandwidth Efficient Graphics with ARM? Mali? GPUs - Marius Bj?rge[GPU pro 5]