继续向glBufferData添加新点的最佳方法是什么?

时间:2014-09-18 18:14:52

标签: c++ opengl

我正在使用OpenGL进行实验,以找到经常向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复制回缓冲区。所有这些,似乎效率低下。

有什么想法吗?什么是最佳实践?

2 个答案:

答案 0 :(得分:4)

  

当缓冲区的大小变得太小时,我再次调用glBufferData来增加缓冲区的大小,并将现有的点复制回来。

不错。事实上,这是做这些事情的推荐方式。但是不要让这些块太小。

  

理想情况下,我宁愿避免将点数据存储在计算机内存中,并将所有内容保存在GPU内存中。

这不是OpenGL的工作方式。缓冲区对象的内容可以根据需要在CPU和GPU内存之间自由交换。

  

但是当我调整缓冲区大小时,我必须将数据从缓冲区复制回CPU,然后调整缓冲区大小,最后将数据从CPU复制回缓冲区。所有这些,似乎效率低下。

正确。您希望避免OpenGL和宿主程序之间的副本。这就是为什么OpenGL-3.1和更高版本的函数glCopyBufferSubData在缓冲区之间复制数据的原因。当你需要调整缓冲区的大小时,你也可以创建一个新的缓冲区对象,并从旧的缓冲区复制到新的缓冲区对象^ 1。


[1]:也许你也可以通过利用名称孤儿来在同一个缓冲区对象名称中调整copys的大小;但我首先必须阅读规范,如果这是实际定义的,然后交叉指责所有实现都是正确的。

答案 1 :(得分:3)

之前我制作了一个科学图形程序,可以实时添加新的数据点。我所做的是使用标记GL_DYNAMIC_DRAW创建一个相当大的固定大小缓冲区,并使用glBufferSubData向其添加单个点。一旦填充,我创建了一个带有标志GL_STATIC_DRAW的新缓冲区并将所有数据移动到那里,然后从头开始再次填充GL_DYNAMIC_DRAW缓冲区。所以我最终得到了一些静态缓冲区,一个动态缓冲区,因为它们都是相同的大小(单调递增x坐标),计算用于绘制任何给定的数据段的缓冲区很容易。而且我从来没有调整其中任何一个,只需跟踪使用了多少动态缓冲区,并且只从中绘制了许多顶点。

我不认为我使用glCopyBufferSubData作为datenwolf建议,我在动态缓冲区中的数据的CPU内存中保留了一份副本,直到我可以将其刷新到新的静态缓冲区。但GPU-&gt; GPU复制会更好。我仍然会分配更多的块大小的缓冲区,并避免调整大小。