一直說要對不同渲染狀態的對象進行排序 但是排序的優先順序應該是什麼呢?
問題1:
排序的優先順序主要是 渲染目標 頂點緩衝區 索引緩衝區 頂點數組對象 紋理 著色器程序應該按照什麼優先順序排序 才比較合理
個人認為是:渲染目標 著色器程序 紋理 頂點緩衝區 索引緩衝區 頂點數組對象不過說實話 我都不是很清楚 渲染狀態到底指什麼哪些狀態的切換時有很大性能代價的
問題2:所謂的狀態切換 是不是 只有在調用DrawCall之後 才會產生影響比如我在未調用DrawCall之前 比如當前 紋理單元0 綁定了 紋理0我現在bind紋理1 然後修改一下它的環繞模式然後再綁定回 紋理0
會有性能影響么
瀉藥。
樓主問的兩個問題很好,但是都是沒有明確答案的問題。
第0個問題:什麼是「渲染狀態」?
就是一切可以控制繪製結果的數據都算是渲染狀態。也就是說幾乎但凡你能通過API改變的Data,都可以算作是渲染狀態。包括Shader這樣的,也算是渲染狀態。
第2個問題:狀態切換的優化。
優化前要先看狀態切換的成本。狀態切換的成本主要來自於:- 驅動對改變後的狀態進行有效性驗證。
- 渲染狀態從CPU到GPU的傳輸。
- CPU/GPU的同步。
考慮到1和2,驅動對渲染狀態的設置總是漸增(Incremental)的。
實現這一目標主要有兩種方式:全State的比較,或通過Dirty Bits記錄通過API設置的屬性。前者成本高,是局部最優解;後者成本低,對一般應用效果好,但是Worst Case(比如在同一個Draw里總是出現A-B-A這種狀態設置順序)會很吃虧。當然也可以將Dirty Bits和State Compare結合到一起去。比如像下面這樣:if updatedRenderState.Flags().count() &< COMPARISON_THRESHOLD:
stateDiff = compareState( updatedRenderState.oldState(), updatedRenderState.newState() )
FlushStateToHardware(stateDiff)
else:
FlushStateToHardware( updateRenderState.dirtyState() )
總體來說,對爛代碼越友好的驅動程序,所付出的Cost就越高。不同的公司會有不同的Trade-Off,Trade-Off的基準以Benchmark為主(Gfx Bench/3D Mark,etc.),也有部分遊戲。但是這些程序 —— 除非是特別測試驅動性能的Case —— 通常都是業界翹楚,不會在這些問題上犯很明顯的錯誤。所以我覺得驅動都還是傾向於用低成本的辦法為主。
第1個問題:狀態切換的優先順序。
樓主的描述基本正確。
現代硬體基本都支持多套Context同時存儲於Chip上(相當於一個State Object FIFO)。在常規程序中,渲染狀態的傳輸和寄存器的設置所花費的時間,可以被渲染本身所完全隱藏。在這種情況下不管你怎麼調整順序,都沒什麼特別大的影響。
成本主要來自於狀態切換成本中的1和3。1的Cost很高,這是Draw Call成本的主要來源。應用程序合併Draw Call,或者是使用相同State繪製不同的IB(其實也有影響,比如Topology可能要參與進去,取決於驅動實現),主要節省的都是1的成本。對於3來說,只有少數幾種情況:Present,Lock/Unlock using resource(Discard和Nooverwrite除外),Set Rendering Target會導致阻塞。但是一旦阻塞了,成本很高。如果驅動對Draw是緩式提交的,那麼阻塞將會讓你損失幾乎一幀的時間。因此,狀態切換的優先順序是:
1. Render Target2. 其它這個「其它」非常微妙。驅動不同、硬體設計不同,都會使得狀態切換的成本有所差異。只有Console這種硬體確定的程序才有可能考慮順序,PC上的程序一般不用考慮這個,除非遇到了特殊的情況。
作業交畢 @Milo Yip入門的話,可以從學習減少貼圖切換次數開始
推薦閱讀:
※Minecraft那些方塊用OpenGL怎麼畫比較好?
※Unity-Shader和OpenGL-Shader有什麼不同之處?
※Shader 在現在圖形管線中可以負責多少部分?
※如何評價CSDN學院姜雪偉的《3D遊戲引擎高端實戰培訓》課程?
※在 OS X 下怎麼寫新版本的 OpenGL?