2013-11-28 20 views
1

我正在研究一個多線程應用程序,它可以將幾何體同時渲染到多個FBO。我遇到泄漏(如this question中所述)。如何完全取消綁定GL_ELEMENT_ARRAY_BUFFER?

我已經能夠縮小它 - 如果我做了一個改變,它不會泄漏 - 但我不明白爲什麼。

在每4個線程(每個都有自己的共享上下文),我做了以下每個渲染週期:

// Upload 

positionBuffer = getUnusedArrayBufferFromPool(); 
glBindBuffer(GL_ARRAY_BUFFER, positionBuffer); 
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*vertexCount, positions, GL_STREAM_DRAW); 

{ 
    GLuint vertexArray; 
    glGenVertexArrays(1, &vertexArray); 
    glBindVertexArray(vertexArray); 

    elementBuffer = getUnusedElementArrayBufferFromPool(); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*elementCount, elements, GL_STREAM_DRAW); 

    glBindVertexArray(0); 
    glDeleteVertexArrays(1, &vertexArray); 
} 

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 



// Render (possibly on a different context) 

GLuint vertexArray; 
glGenVertexArrays(1, &vertexArray); 
glBindVertexArray(vertexArray); 

glUseProgram(programName); 
{ 
    GLint positionAttribute = glGetAttribLocation(programName, "position"); 
    glBindBuffer(GL_ARRAY_BUFFER, positionBuffer); 
    glVertexAttribPointer((GLuint)positionAttribute, 4 /* XYZW */, GL_FLOAT, GL_FALSE, sizeof(float)*4, (void*)0); 
    glEnableVertexAttribArray((GLuint)positionAttribute); 

    { 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer); 
     glDrawElements(GL_TRIANGLES, (GLsizei)elementCount, GL_UNSIGNED_INT, (void*)0); 
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
    } 

    glDisableVertexAttribArray((GLuint)positionAttribute); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 
} 
glUseProgram(0); 

glBindVertexArray(0); 
glDeleteVertexArrays(1, &vertexArray); 



// Cleanup (possibly on a different context) 

glBindBuffer(GL_ARRAY_BUFFER, positionBuffer); 
glBufferData(GL_ARRAY_BUFFER, 0, 0, GL_STREAM_DRAW); 
glBindBuffer(GL_ARRAY_BUFFER, 0); 
throwArrayBufferBackInPool(positionBuffer); 

//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer); 
//glBufferData(GL_ELEMENT_ARRAY_BUFFER, 0, 0, GL_STREAM_DRAW); 
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 
//throwElementArrayBufferBackInPool(elementBuffer); // Why does this leak if we recycle it? 
glDeleteBuffers(1, &elementBuffer); 

如果我換的最後兩行 - 如果我扔元素緩衝回進入游泳池而不是在每個渲染週期中刪除它 - OpenGL驅動程序監視器指示出巨大的泄漏。

但我寧願將它集中,因爲每幀調用glDeleteBuffers()真的很慢。

我錯過了什麼?我假設我無法從某些東西中解除綁定elementBuffer - 而且有些東西持續引用它,導致泄漏 - 但我無法弄清楚是什麼。


編輯:不同的系統(的Mac OS 10.6)在剛剛測試 - 在該系統上,如果我再利用任何緩衝區泄漏。

編輯:我修改應用程序,以便GL_ARRAY_BUFFERGL_ELEMENT_ARRAY_BUFFER分別集中,並讓elementBuffer始終勢必GL_ELEMENT_ARRAY_BUFFER。但如果我throwElementArrayBufferBackInPool(elementBuffer);它仍然泄漏。

編輯:澄清了爲什麼我在上傳和渲染過程中創建和刪除VAO - 因爲它們可能發生在不同的共享GL上下文中,並且VAO無法在上下文之間共享。

編輯︰我修改我的應用程序提供零大小的緩衝區數據之前扔緩衝池回池,但它仍然泄漏一樣快。

+0

你可以解釋/顯示'throwElementArrayBufferBackInPool(...)'是如何實現的嗎? VAO是容器對象,如果你刪除一個綁定到一個緩衝對象(實際上是VAO追蹤的唯一緩衝對象綁定是**元素**緩衝區,頂點指針工作方式不同),而VAO本身不活動,那麼直到VAO對它的引用被刪除,緩衝區對象才被完全刪除。如果VAO在刪除元素緩衝區時處於活動狀態,則它會自動解除綁定。這*可能*在這種情況下是相關的,但我需要看到實施。 –

+0

您可以通過調用'glBufferData(...)'來調用大小,並保留一組保留但空的緩衝區名稱以供重用,而不是刪除緩衝區對象,從而可以解決所有這些問題。這將立即釋放數據存儲(相對而言),而不必等待所有上下文和容器對象的所有引用都被刪除。 –

+0

@ AndonM.Coleman:池只是C++ std :: vector的簡單線程封裝。我剛剛在這裏發佈了一個源摘錄:https://gist.github.com/smokris/7711889 – smokris

回答

1

您的緩衝池用於綁定GL_ARRAY_BUFFER以及GL_ELEMENT_ARRAY_BUFFER對象。更糟糕的是,您首先使用elementBuffer來綁定GL_ARRAY_BUFFER,但隨後將其用於GL_ELEMENT_ARRAY_BUFFER。我並沒有完全把頭埋在它的周圍,但是在混合命名空間和不一致的綁定使用之間,我會把錢放在那裏。

我的建議:爲GL_ELEMENT_ARRAY_BUFFER的使用創建一個單獨的緩衝區名稱池,並確保您始終如一地使用它。

+0

我修改了我的應用程序(以及上面的示例代碼),以便將'GL_ARRAY_BUFFER'與'GL_ELEMENT_ARRAY_BUFFER'分開存儲,並且'elementBuffer'一直綁定到'GL_ELEMENT_ARRAY_BUFFER'。但是,如果我'throwElementArrayBufferBackInPool(elementBuffer);'它仍然泄漏。 – smokris