我應該多久調用一次OpenGL函數,如glEnable()
或glEnableClientState()
及其對應的glDisable
對應函數?它們是打算在應用程序開始時調用一次,還是應該讓它們禁用,並且只啓用我立即需要繪製某些內容的功能?是否有性能差異?每次我畫什麼,我應該調用glEnable和glDisable嗎?
回答
「這取決於」。
如果您的整個應用程序只使用啓用/禁用狀態的一種組合,那麼無論如何只需在開始和結束時設置它。
大多數現實世界的應用需要混合,然後你不得不打電話glEnable()
啓用某些特定國家(或多個),執行繪圖調用,然後再次glDisable()
他們,當你做了「清除階段」。
狀態排序,狀態跟蹤和許多優化方案源於此,因爲狀態切換有時很昂貴。
如果你發現你經常檢查狀態變量的值,然後調用glEnable/glDisable,你可以通過使用屬性堆棧(glPushAttrib/glPopAttrib)來清理一些東西。
屬性堆棧允許您隔離代碼的區域,並且對一個節中的屬性所做的更改不會影響其他節中的屬性狀態。
void drawObject1(){
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
/* Isolated Region 1 */
glPopAttrib();
}
void drawObject2(){
glPushAttrib(GL_ENABLE_BIT);
glEnable(GL_FOG);
glEnable(GL_GL_POINT_SMOOTH);
/* Isolated Region 2 */
glPopAttrib();
}
void drawScene(){
drawObject1();
drawObject2();
}
雖然GL_LIGHTING
和GL_DEPTH_TEST
在drawObject1設置他們的狀態不會保留到drawObject2。在glPushAttrib不存在的情況下,情況並非如此。另外請注意,在函數調用結束時不需要調用glDisable,glPopAttrib完成這項工作。
就性能而言,個別函數調用glEnable/glDisable的開銷很小。如果您需要處理很多狀態,您可能需要創建自己的狀態管理器或對glGetInteger進行多次調用,然後採取相應措施。增加的機器和控制流程可能導致代碼不透明,難以調試,並且更難以維護。這些問題可能會使其他更有成效的優化變得更加困難。
歸因堆棧可以幫助維護抽象層並創建隔離區。
,我是教經驗法則說,它幾乎總是更便宜,只是使能/禁止隨意,而不是檢查當前狀態,如果只需要改變。
這就是說,馬克的答案是絕對可行的。
首先,您使用哪種OpenGL版本?你的目標羣體擁有哪一代圖形硬件?知道這將使得更容易給出更正確的答案。我的答案假設OpenGL 2.1。
OpenGL是一種狀態機,意味着只要狀態發生變化,該狀態就變爲「當前」,直到程序員用新的OpenGL API調用明確地再次更改。此規則的例外情況存在,例如客戶端狀態數組調用使當前頂點顏色未定義。但這些是定義規則的例外。
「」一旦在應用程序開始時「沒有多大意義,因爲在應用程序仍在運行時,有時需要銷燬OpenGL上下文。我假設你是指在每個窗口創建之後。這對您以後不需要更改的狀態有效。示例:如果所有繪圖調用都使用相同的頂點數組數據,則不需要使用glDisableClientState將其禁用。
有很多與舊的固定功能管道相關的啓用/禁用狀態。簡單的兌換是:使用着色器!如果你的目標是最多五年的一代卡片,它可能無論如何都會模仿帶着色器的固定功能流水線。通過使用着色器,您或多或少地完全控制了轉換和光柵化階段發生的事情,並且可以使用制服創建自己的「狀態」,這些狀態對於更改/更新非常便宜。
知道OpenGL是一個像我上面說過的狀態機應該清楚地表明,只要有可能,就應該努力將狀態更改保持在最低限度。但是,最有可能的其他事情遠比啓用/禁用狀態調用影響性能。如果你想了解它們,請閱讀。
與舊的固定功能狀態調用和其相關聯的狀態不的費用並不簡單啓用/禁用狀態可以以成本有很大的不同。值得注意的是,連接着色器和綁定名稱(紋理,程序,緩衝對象的「名稱」)通常相當昂貴。這就是爲什麼很多遊戲和應用程序會根據紋理對網格的繪製順序進行排序。這樣,他們不必將兩次相同的紋理綁定在一起。然而,現在,着色器程序也是如此。如果你不需要,你不想兩次綁定相同的着色器程序。此外,並非所有特定OpenGL版本中的所有功能都在所有卡上進行了硬件加速,即使這些卡的供應商聲稱它們符合OpenGL標準。合規意味着他們遵循規範,而不是他們必須有效地運行所有的特徵。在這方面應該記住GL_ARB __imaging中的一些函數,如glHistogram和glMinMax。
結論:除非有明顯的理由不使用着色器!它可以讓你免去很多不必要的州電話,因爲你可以使用制服。你知道,OpenGL着色器已經存在了大約六年。另外,啓用/禁用狀態變化的開銷可能是是一個問題,但通常還有更多優化其他更昂貴的狀態更改,如glUseProgram,glCompileShader,glLinkprogram,glBindBuffer和glBindTexture。
P.S:OpenGL 3.0刪除了客戶端狀態啓用/禁用調用。它們是隱式啓用的,因爲繪製數組是繪製此版本的唯一方法。立即模式被刪除。 gl..Pointer調用也被刪除,因爲一個真的只需要glVertexAttribPointer。
- 1. 的OpenGL glEnable(GL_COLOR_MATERIAL),其次是glDisable(GL_COLOR_MATERIAL)
- 2. .NET ApplicationSettingsBase我應該在每次加載時調用Upgrade()嗎?
- 3. 我應該在每次需要此服務時調用getSystemService一次嗎?
- 4. 每次應用程序重新啓動時,我應該調用setMinimumBackgroundFetchInterval嗎?
- 5. 我的功能應該調用什麼?
- 6. 我應該使用什麼來調度
- 7. 爲什麼每次我調用它時都會執行兩次該方法?
- 8. unSubscribeOn調用了什麼線程?我們應該叫它嗎?
- 9. GMSGroundOverlay動畫 - 我應該使用CATiledLayer嗎?
- 10. 爲什麼我沒有安裝django,我應該運行pip安裝多次嗎?
- 11. 我應該在事務中包裝每個db調用嗎?
- 12. GoogleApiClient onConnectionSuspended,我應該再次調用mGoogleApiClient.connect()嗎?
- 13. 每次我要求位置更新時,我應該使用android LocationManager.getBestProvider嗎?
- 14. 我應該在我的NSCell上調用什麼方法
- 15. 我應該同步notifyObservers調用嗎?
- 16. 我應該調用base.OnAuthorization(filterContext)嗎?
- 17. 我應該*真的*調用DataBind()嗎?
- 18. 我應該在ServiceController上調用Close()嗎?
- 19. 我應該改變繪畫順序嗎?
- 20. 我應該多次調用dns_get_record(),還是調用一次DNS_ANY?
- 21. Mysqli - 我應該每次重新連接嗎?
- 22. 我應該在每次查詢之前ping mysql服務器嗎?
- 23. SQL - 我應該在每次查詢後終止連接嗎?
- 24. 每次發佈後我應該關閉頻道/連接嗎?
- 25. 我應該每次爲PHP創建數據庫連接嗎?
- 26. 我應該通過什麼參數來調用該方法C#
- 27. 我應該結束每個elseif塊嗎?
- 28. 我應該允許多次登錄嗎?
- 29. 我應該兩次轉義值嗎?
- 30. iphone:我應該學什麼?
..及其客戶端副本glPush/PopClientAttrib – 2009-04-29 13:15:24