如何讓手游更省帶寬,耗電量更少?渲染或是其中一個可突破的點。本文中,騰訊游戲學院專家Hailong將從為大家解析TBR渲染架構的特點。
什么是TBR?
全稱是Tile Based Rendering,主要用在移動設備(手機、平板)上的一種渲染架構,渲染時將屏幕分割成小塊,分別渲染。每塊大小為16×16 或32×32等(不同產品各不相同),特點是省帶寬,耗電小。
與之對應的是IMR(Immediate Mode Rendering),提交的每個渲染要求都會立即開始,這是一種簡單而又粗暴的思路,優點缺點都非常明顯,如果不用為性能擔憂,這種方式會很省事。
片上緩存(On-Chip Buffer)
TBR設備在GPU內部集成有很小的片上緩存(On-Chip Buffer),片上緩存,在渲染時會先將一個Tile內的圖像先渲染到片上緩存,然后在拷貝到主顯存中。而IMR渲染則是直接由GPU操作顯存。片上緩存相比於顯存中的Frame Buffer具有更快的訪問速度,但是只有很小的存儲空間(16×16像素或32×32像素)。
與IMR相比,TBR在GPU上多出一塊片上緩存。
IMR與TBR在渲染流程上的對比(紅色陰影表示帶寬消耗熱點)
由上圖可以看出,IMR和TBR在帶寬消耗上有比較大的差異,左側的IMR渲染時,Depth Test和Alpha Test等由於需要頻繁訪問顯存,導致有很大的帶寬消耗。而右側的TBR渲染方式由於Depth Test和Alpha Test都只需要跟片上緩存交互即可,避免了和顯存之間的帶寬消耗。
Tiling(分塊)
為了能夠按照逐個Tile渲染,在一幀的繪圖指令全部提交完成並經過頂點運算后后,會在記錄下每個Tile中對應的Triangle List。並保存在FrameBuffer中,等待光柵化時從FrameBuffer讀取相應的Tile的TriangleList進行處理。
Resove和Restore
由於GPU的片上緩存的存儲空間非常有限,因此渲染完成一個Tile之后,需要將結果復制到FrameBuffer中,這個過程稱作Resove。
如果一幀內需要多遍渲染時,在對Tile進行渲染的時候往往需要從FrameBuffer中將對應Tile中舊的數據讀取到片上緩存,這個過程稱為Restore。
Resove和Restore會導致大量的帶寬消耗,需要盡量避免。
如果在渲染過程中需要頻繁的切換FrameBuffer,要注意調用順序,避免浪費帶寬。
會導致Resove+Restore的OpenGL ES調用。
eglSwapBuffers
glBindFramebuffer
glTexImage2D,glTexSubImage2D,
glBufferData,glBufferSubData
glCopyTexImage2D ,glCopyTexSubImage2
glReadPixels()
(參考:Adreno_Developer_Guide.pdf第38頁)
實例:為什么在Unity中使用Grap Pass實現屏幕扭曲非常慢?
由於Unity中的Grap Pass是插在渲染過程中的,每渲染一次,會調用一次glBufferSubData,會導致Resorve和Restore。
可能做的優化:
等場景全部渲染完之后再在最上層疊加一個扭曲效果。
跟其他后處理合並處理。
實例:關於后處理
每個后處理會導至少增加一次Resorve。
可能的優化:
將多種后處理效果放在一個shader中可以減少Resove發生次數。
某些效果低分辨率可以減少帶寬。
實例:實時陰影
Shadow map方式實現的實時陰影,需要首先將攝像機放在光源處,將場景深度渲染到一張紋理上,因此除了draw call的增加外,帶寬的增加也很多。
可能的優化:
使用更小的RT。
如果能接受的話,可以嘗試鎮魔曲中影子的做法,即將主角壓扁,用黑色紋理渲出來。
減少帶寬消耗的建議
1、減少頂點數和圖片尺寸。
2、圖片壓縮(ETC,ATC,PVRTC等)。
3、除界面外,幾乎所有貼圖都建議生成Mipmap(減小帶寬消耗,增加緩存命中)。
4、盡量減少Resove和Restore,盡量減小RenderTexture的尺寸。
全屏后處理
實時陰影(shadow map)
扭曲
實時反射
5、優化Shader。
使用低精度浮點數
TBR特有的兩個OpenGL ES擴展
1、Framebuffer Fetch
允許Shader中直接訪問片上緩存中當前的顏色和深度。
可以用來實現高效的Color Grading、高度霧之類。
2、Pixel Local Storage
允許在片上緩存中存儲和讀取自定義的數據格式,大小為每像素128字節或256字節。
可以用來實現高效的延遲光照渲染(在片上緩存中保存G-Buffer)。