一直說要對不同渲染狀態的對象進行排序 但是排序的優先順序應該是什麼呢?

問題1:

排序的優先順序

主要是 渲染目標 頂點緩衝區 索引緩衝區 頂點數組對象 紋理 著色器程序

應該按照什麼優先順序排序 才比較合理

個人認為是:

渲染目標 著色器程序 紋理 頂點緩衝區 索引緩衝區 頂點數組對象

不過說實話 我都不是很清楚 渲染狀態到底指什麼

哪些狀態的切換時有很大性能代價的

問題2:

所謂的狀態切換 是不是 只有在調用DrawCall之後 才會產生影響

比如我在未調用DrawCall之前 比如當前 紋理單元0 綁定了 紋理0

我現在bind紋理1 然後修改一下它的環繞模式

然後再綁定回 紋理0

會有性能影響么


瀉藥。

樓主問的兩個問題很好,但是都是沒有明確答案的問題。

第0個問題:什麼是「渲染狀態」?

就是一切可以控制繪製結果的數據都算是渲染狀態。也就是說幾乎但凡你能通過API改變的Data,都可以算作是渲染狀態。包括Shader這樣的,也算是渲染狀態。

第2個問題:狀態切換的優化。

優化前要先看狀態切換的成本。狀態切換的成本主要來自於:

  1. 驅動對改變後的狀態進行有效性驗證。

  2. 渲染狀態從CPU到GPU的傳輸。

  3. 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 Target

2. 其它

這個「其它」非常微妙。驅動不同、硬體設計不同,都會使得狀態切換的成本有所差異。只有Console這種硬體確定的程序才有可能考慮順序,PC上的程序一般不用考慮這個,除非遇到了特殊的情況。

作業交畢 @Milo Yip


入門的話,可以從學習減少貼圖切換次數開始


推薦閱讀:

Minecraft那些方塊用OpenGL怎麼畫比較好?
Unity-Shader和OpenGL-Shader有什麼不同之處?
Shader 在現在圖形管線中可以負責多少部分?
如何評價CSDN學院姜雪偉的《3D遊戲引擎高端實戰培訓》課程?
在 OS X 下怎麼寫新版本的 OpenGL?

TAG:編程 | OpenGL | OpenGLES |