請注意,我沒有太多的ES經驗,所以在這種情況下可能有更好的方法來做到這一點。不過,普通的要點適用於普通的OpenGL或ES。
首先,最重要的性能考慮應該是當你在閱讀時。如果您在渲染時從視頻卡請求數據,則您的程序(CPU端)將不得不暫停,直到視頻卡返回數據爲止,由於無法發出更多渲染命令,渲染速度會降低。作爲一般規則,你應該總是上傳,渲染,下載 - 不要混合任何這些進程,它會極大地影響速度,以及依賴驅動程序/硬件/操作系統的程度。
我建議在渲染週期結束時使用glReadPixels()
。我懷疑這個函數的格式限制與framebuffer格式的限制有關;此外,你真的應該使用8位無符號或浮點數,both of which are supported。如果您有一些附帶條件不允許使用任何支持的格式,則應該說明具體情況,因爲可能有專門處理它的方法。
如果在渲染(而不是結束)的特定點需要幀緩衝區的內容,請創建第二個紋理+幀緩衝區(再次使用相同的格式)作爲有效的「後緩衝區」,然後從目標framebuffer到該紋理。這發生在視頻卡上,因此它不直接讀取總線延遲。下面是我寫的,做此操作:
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, backbufferTextureHandle);
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferHandle);
glCopyTexSubImage2D(
GL_TEXTURE_2D,
0, // level
0, 0, // offset
0, 0, // x, y
screenX, screenY);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebufferHandle);
然後,當你需要的數據,後備緩衝結合GL_READ_FRAMEBUFFER並在其上使用glReadPixels()
。
最後,您應該記住,下載數據仍然會停止CPU端。如果在顯示幀緩衝區之前下載,您將推遲顯示圖像,直到您可以再次執行命令,這可能會導致可見的延遲。因此,我建議還是使用非默認的幀緩衝,即使你只關心最後的緩衝狀態,結束渲染週期的影響:
(1)BLIT到默認的幀緩衝:
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // Default framebuffer
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebufferHandle);
glBlitFramebuffer(
0, 0, screenX, screenY,
0, 0, screenX, screenY,
GL_COLOR_BUFFER_BIT,
GL_NEAREST);
(2.)在給定情況下調用任何交換緩衝區命令。
(3.)您從framebuffer下載的電話(無論是glReadPixels()
或其他)。
至於blit/texcopy操作對速度的影響,它在大多數現代硬件上都非常好,我甚至沒有發現即使做了10倍以上的幀也有明顯的影響,但是如果您正在處理過時的硬件,這可能值得再次思考。
我想獲得一個紋理,一旦從磁盤加載到GPU內存中,內容不會發生變化。我不需要特定的格式,但是如果格式不匹配,使用'glReadPixels()'將需要進行某種計算,速度較慢但不確定多少。我只需要檢索一個像素,所以它不應該太糟糕,最糟糕的情況是像DXT這樣的壓縮格式。儘管如此,它會爲我節省一些工作。邏輯順序是獲取像素並將該像素用作渲染的輸入。還有與它一起進行的計算以及多個樣本。 – user3901459
@ user3901459數據量並不會真正影響速度;總線延遲是主要的限制因素,而不是帶寬,所以一個像素與整個幀緩衝區大致相同。也就是說,如果你只想要上傳的數據,我認爲你正在討論這個錯誤。只要保留最初傳遞給OpenGL的圖像陣列即可。如果你從光盤加載壓縮格式有點困難,我沒有任何紋理壓縮的經驗,但大概你可以用軟件做到這一點,並完全切割GPU。 –
在某些時候,帶寬會影響它,但對嗎?舉一個真正大的紋理爲例,抓住整個東西會讓它變慢?我想這取決於相對於延遲需要多長時間。將它全部保存在內存中並不是最好的,如果其他所有的都失敗了,我不得不這樣做,但它會使內存使用量增加一倍。特別是在像移動設備這樣的共享內存系統上。我猜想可以製作一些混合系統,讀取紋理並將其存儲在CPU內存中,如果它不被使用一段時間然後將其刪除。它仍然需要足夠快或者它會stu – user3901459