2016-02-23 36 views
1

我知道DirectX for Dx9至少有一個紋理對象,你只能得到CPU可訪問內存的一小部分紋理。我相信這是一個名爲「LockRect」的函數。 OpenGL有glGetTexImage(),但它抓取整個圖像,如果格式與紋理不同,那麼它將不得不在整個紋理轉移之前將整個紋理轉換爲新的像素格式。這個函數也不在OpenGL ES中。幀緩衝是另一種選擇,但我可以綁定一個framebuffer,在其中連接到紋理的顏色附件。然後有從幀緩衝區讀取的glReadPixels,所以它應該從紋理讀取。 glReadPixels有限的像素格式選項,所以轉換將不得不發生,但我可以讀取我需要的像素(這是隻有1個像素)。我沒有使用這種方法,但它似乎是可能的。如果任何人都可以確認framebuffer方法,那麼這是一個可行的選擇。那麼這種方法也適用於OpenGL ES 2+。檢索紋理像素數據的最有效方法?

還有其他方法嗎? framebuffer方法的效率如何(如果它工作的話),是否最終必須在讀取像素之前將整個紋理轉換爲所需格式,還是完全定義了實現?

編輯:@Nicol_Bolas請停止從標籤中刪除OpenGL並添加OpenGL-ES,OpenGL-ES不適用,OpenGL是。這是專門針對OpenGL的,但如果可能的話,我希望它是Open ES 2+兼容的,儘管它不一定是。如果只有OpenGL解決方案可用,那麼這是一個值得考慮的問題。謝謝。

回答

2

請注意,我沒有太多的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倍以上的幀也有明顯的影響,但是如果您正在處理過時的硬件,這可能值得再次思考。

+0

我想獲得一個紋理,一旦從磁盤加載到GPU內存中,內容不會發生變化。我不需要特定的格式,但是如果格式不匹配,使用'glReadPixels()'將需要進行某種計算,速度較慢但不確定多少。我只需要檢索一個像素,所以它不應該太糟糕,最糟糕的情況是像DXT這樣的壓縮格式。儘管如此,它會爲我節省一些工作。邏輯順序是獲取像素並將該像素用作渲染的輸入。還有與它一起進行的計算以及多個樣本。 – user3901459

+0

@ user3901459數據量並不會真正影響速度;總線延遲是主要的限制因素,而不是帶寬,所以一個像素與整個幀緩衝區大致相同。也就是說,如果你只想要上傳的數據,我認爲你正在討論這個錯誤。只要保留最初傳遞給OpenGL的圖像陣列即可。如果你從光盤加載壓縮格式有點困難,我沒有任何紋理壓縮的經驗,但大概你可以用軟件做到這一點,並完全切割GPU。 –

+0

在某些時候,帶寬會影響它,但對嗎?舉一個真正大的紋理爲例,抓住整個東西會讓它變慢?我想這取決於相對於延遲需要多長時間。將它全部保存在內存中並不是最好的,如果其他所有的都失敗了,我不得不這樣做,但它會使內存使用量增加一倍。特別是在像移動設備這樣的共享內存系統上。我猜想可以製作一些混合系統,讀取紋理並將其存儲在CPU內存中,如果它不被使用一段時間然後將其刪除。它仍然需要足夠快或者它會stu – user3901459

相關問題