http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-TileBasedArchitectures.pdf
tbr 和tbdr是gpu的一種架構 硬件層面的事情和deferred shading是兩回事
有關blend的開銷
immediate模式 要走相對較慢的 memory read-modify-write framebuffer
tile based模式 就在on chip tile buffer上用專門的硬件做了 基本沒有開銷 而如果在shader里面寫會占shader吞吐量
所以這段的建議就是如果做透明的話 推薦用blend 而不在shader里做
而透明與不透明相比 透明(無論哪種方式alpha blend, alpha test, alpha to coverage)總會導致 對於透明物體后面的fragment來講hidden surface removal 和earlyz 失效
==============
===================
tbr multisampling對帶寬的影響情況是這樣的
multisamp的瓶頸是帶寬, 4x為例 訪問framebuffer的帶寬變為之前的4倍 (一個pixel 4個sample)
如果是tbt這部分 都在tile buffer上做 做完 一次送到framebuffer (resolved 之后 相當於一個pixel1個sample)
開銷包含以下兩部分
1.tile buffer上的大小需要4倍,廠商在開ms的情況下,減小tile size 為了省下buffer大小,這對性能有些許沖擊,half size不會導致half performace
如果程序的瓶頸是shading吞吐量 tile buffer size減小 只會對性能有很很輕微的影響(比幾乎無影響高一點 minor impact也就是除非程序瓶頸就是在這里了
2 第二種類型的開銷在immediate mode下也是同樣存在的 會增加大概10%的fragments(數量)的計算 具體數量取決於場景
不只是cover center的 frag參與 只要cover sample的 frags都會算在內
==============
介於profile 不那么准確好用了
建議 開發初期 確定復雜度預算 trigngles ,textures ,shader complexity等等,這個我有做
來避免 geometry 超過一個最高的量引發的切分 性能會大幅下降
它最后說這段很詭異 應該是舉了個反例: 你在draw 后面加glclear ,那個draw可能不會被提交 引擎這邊給優化掉了之類吧
要確保命令按預期執行 應該是這意思
=========================================
總結 performance的核心是 測試 測試 測試 因為硬件 driver都是不同的
對於tb GPU
1. clear color , depth ,stencil在每幀開始的時候
2.For each framebuffer, bind it once during the frame, and submit all the commands for the frame before unbinding it or using the results.
這步是在避免framebuffer的bind
3.latency for gpu query
4.保證多邊形數量在合理范圍,避免那次跳崖式下跌
5.有了隱藏面消除 不需要對opaquel從前向后排序(powerVR),不是tb的gpu需要這樣做,考慮用z pre pass
6.多利用cheap的multisample
7.移動平台performance和電量消耗取平衡 兩者都要兼顧
=================
tbr 透明要不要cpu排序?? (要排, opaque不排是因為被剔掉了
對於這種情況 是不是完全隱藏面消除就失效了 一個不透明場景 前面蒙上一層透明面片
我估計這是對一個tile來講的 場景不要大塊很多透明 透明后面不要太多東西 省掉的是透明后面frag的計算
這段括號里的理解是不對的 粒度肯定不是tile是pixel 分兩個passtrans就不會使opaque的hsr失效 后面有論證
===============
基本方法:1 減少狀態切換
2 texture 壓縮
3.減少drawcalls
4.降低shader復雜度
各種差異性 導致優化需要持續profiling 並試驗
所以我們不應該記一些方法 而是要知道 每種特性如何影響性能
(這兩點深切贊同)
鎖低幀可以延長電量
在達到目標幀率之后還可以持續優化 以減少電量消耗
移動平台 performance and power consumption
帶寬--移動數據 費電
immediate mode下pixel需要 read depth/stencil write depth/stencil(opt) write color 這里消耗帶寬
tbr可以省電 把數據放在計算器旁邊(on-chip) 最后往framebuffer放一次
GPU的tbr就是為了省帶寬 進而省電
depth/stencil test和blend都是在tile上做
tbdr的gpu 會用專門的硬件單元 收集到所有的vertex 的信息 用相應的數據結構 包含vertex position ,vertex output, triangle indices, fragment state等
這部分叫做frame data/polygon lists/parameter buffer
這部分是有開銷的 如果曲面細分導致vertex過多 這部分開銷就會抵消掉tbdr的優勢
tbdr mode 在每一幀構造的是上文提到的frame data(所有vertex)信息 而不是frame buffer 在性能調優的時候需要銘記這一點
drawcall越多這部分數據就越大
(看到一個黑科技using half the depth range on alternate frames to avoid clearing the depth buffer 這個應該是immediate 模式下 為了避免清depth的一種方法 分開用
避免寫這兩塊buffer都到了這種程度 說明開銷很高了)
tbdr要clear 避免tile buffer copy回 framebuffer 和從framebuffer copy數據去tilebuffer
相關mask也設置上
clear只是clear 推薦用e EXT_discard_framebuffer 這個擴展可以真正告訴driver 那部分frame buffer的內容可以丟棄 driver可以做他想做的比如rtt時候復用framebuffer不用再copy一份了
====================================
擴展里面提供了一種按tile局部更新的方法(好方法啊!)比如 ui界面很多地方不用更新只是某個圖標更新 那其它地方只是從framebuffercopy到tilebuffer就可以
這個不默認提供 因為copy有開銷 參見clear那部分
glStartTilingQCOM(x , y , width , height , GL_NONE );
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glViewport(x , y , width , height );
// Draw the scene
glEndTilingQCOM( GL_COLOR_BUFFER_BIT0_QCOM); eglSwapBuffers(dpy , surface );
這兩個擴展EGL_SWAP_BEHAVIOR to EGL_BUFFER_PRESERVED.
==========================
Flushing
glflush--提交command buffer 清空緩存(cb相關的 包含其它資源buffer) 拿framebuffer的時候會引發flush 執行完命令才能拿結果
這里講了一下
1.framebuffer 如果要訪問 肯定需要先把里面的東西shader完 即使是再gpu里訪問也是一樣的
2.如果glBindFramebuffer會導致前面那個fm2 unbound 這樣fm2會shade return
這就解釋了為什么要減少不必要的framebuffer bound 最好的情況是用到的fm一幀只綁一次(這段出現的fm都是destination)
這就解釋了為什么smpass cubemap pass reflection pass都是一個在前面
3. vertex一直增加會引發一個是平時flush開銷16倍的flush (面片在幾十萬級別不會觸發 1M也沒事 大了沒測)
通過提前的測試找到這個vertex的數量避免這種問題發生
===============================
Latency
最后一段latency的問題
數據被同時訪問時會存在driver的 copy on write 費memory 解決方法是 把一塊資源一次更新好 不要改一下給gpu處理下再改再給gpu
============================================
Hidden Surface Removal
overdraw 部分的開銷分析
immediate 兩部分開銷1overdraw的shading計算2判斷遮擋時對depth color buffer 的訪問寫回
tbr 2沒有 只有1 所以上層要有深度從近到遠排序 利用earlyz把1去掉
tbdr(powervr) 2沒有 1也完全沒有 這樣就不需要上層對opaque排序了
hsr失效 :
fragment里面替換遮擋像素
discard,sample mask,alpha test,alphatocoverage, blend
所以這些應該只在需要的時候開 即使有切換狀態的開銷
沒有hsr的平台考慮 z pre pass
可以去掉大量overdraw shader計算
開銷分析
immediate 1depth pass 的開銷 2帶寬開銷 兩個pass都訪問depth
tbr 1depth pass 的開銷 2沒有訪問memory的帶寬開銷(直接在tile上做了),有pass1到pass2 copy frame data的開銷(vertex那些)
這樣看來這個zprepass的實現 復用了gpu內部的信息--frame data這是怎么做到的--render to vertex buffer 上層做
https://www.csee.umbc.edu/~olano/s2006c03/scheuermann.pdf 這個是dx9的 很舊了 新的直接用gs輸出vb再拿來用之類的就可以
所以 帶寬limited的app tbr架構的用zprepass會比immediate有效些
=============
mali fpk forward pixel kill
===============
發現個好東西 opengl insights.pdf
=============
總結
1.一個pass開始的時候clear (或者用ext discard) framebuffer--color depth stencil
2.避免反復綁定framebuffer,一開始綁好,之后這塊buffer上的cmd盡可能一次提交
3.考慮tbr,tbdr的latency和傳統模式有區別需要處理 ocquery用上一幀數據,不要卡住當前幀,vb cb動態更新有copy EGL KHR image pixmap or GLX EXT texture from pixmap這倆擴展也會卡住,考慮latency的意思就是關注那些會卡住當前幀的事情 cpu等gpu返回
4.頂點個數需要測出來 這塊顯卡的上限 在technique stander的時候做 各個顯卡 找到那個16倍flush
5.tbdr不用上層 opaque排序,沒有hsr就手寫zprepass
6.考慮使用廉價multisample
7.關注用電量高於幀率
=============
我之前忽視了一點 tbdr意味着處理的粒度是一個pass
而不是一個frame 不是只有一次flush才會觸發 frame buffer 的read/write
切換rt都會的 read pix也會
在一個pass之內 rt上每塊tile vs會全部處理完 在最后deferred 處理fs 之后blit到frame buffer上
--------以上這種理解意味着 如果 場景后面有pp 之后畫ui中間切過rt ui透明並不會使rsr失效 因為隱藏面那個pass已經提過frame buffer了
之后額外又有一次 frame buffer 到tile mem的blit 又往上畫了透明 ui所以沒有多少消耗 (沒有讓復雜場景的隱藏面消除失效)
=======================所以這段profiling的看法更新一下
profiling 的話 gpu query在此類硬件上 以pass為粒度是可用的,但metal對gpu query的支持不是很友善 是cmd starttime endtime
(運行時 用gpu query拿精確時間 實時顯示 是個人認為最有效的方法 )
硬件的處理順序是 每個pass 所有vertex 之后按tile處理fragment這樣拿到的commend buffer里面的 粒度不在pass之內的marker是可用的
此平台推薦方法 debug menu做開關檢驗impact ,用某些工具
=========
接着這點 我又有了新的認識 這就是為什么opaque transparent分開分倆pass的原因
這樣transparent就不會讓opaque 的隱藏面消除失效了 opaque的東西已經提交了
opaque-alpla test ---alpha blend 提交順序
http://cdn.imgtec.com/sdk-documentation/PowerVR+Series5.Architecture+Guide+for+Developers.pdf
接着上面的路往下理解 如果transparent不會讓hsr失效
要注意的是什么呢 是opaque里面的alphatest 我這里還真有這個 先opaque后alphaatest 這樣會好些 這里還需要繼續理解下
應該是當前tile失效 不僅僅是像素失效
---
前面那篇paper里面 framedata framebuffer這個詞誤導我了 我現在90%+確定粒度是 pass 不是一幀
https://wiki.mozilla.org/Platform/GFX/MobileGPUs
================================
這個事情我今天完全想明白了
xcode 的instrument印證了我的想法
tbdr的粒度就是 逐個pass的對應 instrument里面每個encoder
我之前很好奇 既然是deferred為什么instrument能query到准確時間
這就是因為 tbdr是deferred到一個pass結束的時候 而不是一幀結束
一個pass結束的時候是個籠統的概念 這個是我2.0的認識
更精確的3.0版本的描述是這樣的
fbo的unbound
bind new fbo(not quite sure 比如不是mrt的情況下 因為就一個)
geometry 超大導致的強制flush
swapbuffer
readpixel
等等這些 導致framebuffer resolve
然后接着解釋instrument 可以發現encoder的時間是准確的 里面drawcall的時間是總的encoder的時間除以里面drawcall的個數
是估摸的 所以hsr就在這里面咯
並且這個結果也和 metal的api是一致的 這一個encoder就對應一塊cmdbuffer metal的gpuquery是拿一個cmd的start-endtime
這樣也同時意味着unity的底層 在metal這里是分cmd提交的 這樣我就也可以像instrument那樣拿到每個pass的時間顯示出來了
所以接下來我要做實時顯示gpu時間在metal上
==========================================
本文一共三篇比較重要的refs 建議閱讀它們仨
=================================================
今天做了測試 印證了我之前的看法
測試用例
alphatest 面片
alphablend 面片
opque面片 (觸發hsr)
高費ps
pc 100000 Max
iphonex 1000-100 Max
for(int ind; ind<Max;ind++)
{testdata+=exp(testdata);}
測試結果:
1.手機有hsr功能
2.unity 因為把 opque和trandparent作為兩個pass alphablend並沒有使opaque的hsr失效
alphablend當然會使transparent pass的hsr失效
3.alphatest的不透明部分hsr是生效的 discard部分 當然hsr失效 --這里更新了一點我之前的認識 alphatest的粒度是像素 不是一個obj 現在想想顯而易見 扔掉的肯定是那個像素的depth 在那個pipeline里面那時還有什么obj 或者primitive
還有個測試結果順便貼下 unity 的aplha blend很費alu的bound
alphatest基本沒有開銷 這三個都用的surfaceshader(這里數據和實時監測數據不一致 xcodeprofile顯示alphatest有4ms開銷但實時運行沒有。。。<1ms)
hsr是perpixel的
這里的測試有個問題 沒有排除上述所謂的hsr只是個earlyz 所以需要增加一步測試 渲染次序 把高費ps提前 之后列結果
=======================================
https://developer.apple.com/documentation/metal/mtldevice/ios_and_tvos_devices/about_gpu_family_4
這篇也很推薦
蘋果沒有公布A7到A10的 tbdr arch技術細節 但是根據這段能看到和powerVR有不同 apple自己的意思是tbdr有所提升 隱含discard那條 和我測下來 alphatest性能不錯也是符合的 問題是unity沒用metal2。。。。
=====================================================================
https://www.imgtec.com/blog/the-dr-in-tbdr-deferred-rendering-in-rogue/
遇到透明之后 會flush之前的數據從isp到fs
把這個trans pixel和之前hsr的最后一個(visible) blend 這個和測試數據一直相符合
alphatest
會先刷isp 全部opaque shader算完再把 discard的pixel返回isp
----------------------
powervr有Firmware 把傳統驅動(cpu做的)一些graphics process event放到 firmware里減少對cpu的依賴