我正在使用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复制回缓冲区。所有这些,似乎效率低下。
有什么想法吗?什么是最佳实践?
答案 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复制会更好。我仍然会分配更多的块大小的缓冲区,并避免调整大小。