2014-09-18 87 views
3

我正在做一個OpenGL實驗,以找到最經常/最有效的方式來非常頻繁地向glBufferData添加新數據。向glBufferData添加新點的最佳方法是什麼?

要做到這一點,我寫了一個小的2D繪圖程序,只需在移動鼠標時不斷添加點。

全功能如下:

void addPoint(double x, double y) 
{ 
    glBindBuffer(GL_ARRAY_BUFFER, pointVertBuffObj); 
    if (arrayOfPointCapacity < numOfPoints + 1) { 
     U32 size = (arrayOfPointCapacity + 8) * sizeof(Point2); 
     Point2 *tmp = (Point2*)realloc(arrayOfPoints, size); 
     arrayOfPoints = tmp; 
     arrayOfPointCapacity += 8; 
    } 
    arrayOfPoints[numOfPoints].x = x, 
    arrayOfPoints[numOfPoints].y = y; 
    U32 offset = numOfPoints * sizeof(Point2); 
    glBufferData(GL_ARRAY_BUFFER, numOfPoints * sizeof(Point2), arrayOfPoints, GL_DYNAMIC_DRAW); 
    numOfPoints++; 
} 

有新的數據每個我補充一點時間來重置glBufferData看來絕對是瘋了。我想過使用glBufferData來分配大量點並將這些點設置爲glBufferSubData。當緩衝區的大小變得太小時,我再次調用glBufferData增加緩衝區的大小,並將現有的點複製回來。

理想情況下,我寧願避免將點數據存儲在計算機內存中,並將所有內容都保存在GPU內存中。但是當我調整緩衝區大小時,我必須將數據從緩衝區複製回CPU,然後調整緩衝區的大小,最後將數據從CPU複製回緩衝區。所有這些,似乎也是低效的。

有什麼想法?什麼是最佳做法?

回答

4

當緩衝區的大小變得太小時,我再次調用glBufferData來增加緩衝區的大小,並將現有的點複製回來。

不是一個壞主意。事實上,這是做這些事情的推薦方式。但不要讓這些塊太小。

理想情況下,我寧願避免將點數據存儲在計算機內存中,並將所有內容都保存在GPU內存中。

這不是OpenGL的工作方式。根據需要,可以在CPU和GPU內存之間自由交換緩衝區對象的內容。

但是,當我調整緩衝區大小時,我必須將數據從緩衝區複製回CPU,然後調整緩衝區大小,最後將數據從CPU複製回緩衝區。所有這些,似乎也是低效的。

正確。你想避免OpenGL和主機程序之間的拷貝。這就是爲什麼在OpenGL-3.1中以及後來功能glCopyBufferSubData在緩衝區之間複製數據的原因。當你需要調整一個緩衝區的大小時,你也可以創建一個新的緩衝區對象並將其從舊的對象複製到新的對象^ 1。 [1]:也許你也可以通過利用名字孤兒來在同一個緩衝區對象名稱中調整拷貝大小;但我首先必須閱讀規範,如果這是實際定義的,然後交叉手指,所有的實現得到這個權利。

+0

你有一個「調整緩衝區大小是做這些事情的推薦方法」的源代碼?或者僅僅是你的建議? (不是一件壞事,因爲你是專家) – 2014-09-18 19:33:08

+0

很好的回答(像往常一樣thx)。現在,我不明白你的第二條評論「這不是OpenGL的工作原理」。是的,它可以使用類似glMapBuffer的東西交換,我想這就是你的意思,但這個過程似乎效率低下。現在我喜歡你的第三個選項(glCopyBufferSubData),但是當你做這個副本時,你可能會同時得到兩個大的緩衝區:舊的和新的大小合適的。如果兩者都很大,那麼正如我所說的,GPU必須對它們進行管理,直到完成複製,此時可以釋放第一個緩衝區。我不知道孤兒。聽起來不錯。 – user18490 2014-09-18 19:33:33

+0

@ BenVoigt:這不是OpenGL的建議,而是實現頁面內存分配器的一個很好的實踐。我在此提及有關內存分配器主題的大量出版物。最後歸結爲每個OpenGL對象都可以交換到主機內存的事實。因此,有效的內存塊粒度(這是您的程序「感覺」的)是主機系統頁面大小或GPU分頁大小中的較大者。即使GPU頁面更小,因爲內存事務發生在主機頁面上,這就是你最終得到的結果。 – datenwolf 2014-09-18 21:49:38

3

我製作了一個科學繪圖程序,可以實時添加新的數據點。我所做的是創建一個相當大的固定大小的緩衝區,標記爲GL_DYNAMIC_DRAW,並用glBufferSubData添加了個別點。一旦填滿,我創建了一個新的緩衝區,標誌爲GL_STATIC_DRAW,並將所有數據移動到那裏,然後從頭開始再次填充GL_DYNAMIC_DRAW緩衝區。所以我最終得到了少量的靜態緩衝區,一個動態緩衝區,並且因爲它們都是相同的大小(單調遞增的x座標),計算使用哪些緩衝區來繪製任何給定的數據段是很容易的。我從來不必調整它們中的任何一個,只需跟蹤動態緩衝區的使用量,並且只從其中繪製多個頂點。

我不認爲我使用glCopyBufferSubData,因爲datenwolf暗示,我在動態緩衝區中的數據的CPU內存中保留了一個副本,直到我可以將其刷新到新的靜態緩衝區。但GPU-> GPU複製會更好。我仍然會分配更多塊大小的緩衝區並避免調整大小。

+0

聰明的想法。感謝分享它。 – user18490 2014-09-18 19:37:35

相關問題