glDrawArrays访问冲突写入位置

时间:2014-12-21 00:01:09

标签: c++ opengl access-violation gldrawarrays

我正在尝试可视化非常大的点云(700毫升点),并且在glDrawArrays调用调试器会抛出访问冲突写入位置异常。我使用相同的代码来渲染较小的云(100万),一切正常。我还有足够的RAM内存(32GB)来存储数据。

要存储点云我正在使用std::vector<Point3D<float>>,其中Point3D是

template <class T>
union Point3D
{
    T data[3];
        struct{
            T x;
            T y;
            T z;
        };
}

顶点数组和缓冲区初始化:

glBindVertexArray(pxCloudHeader.uiVBA);

glBindBuffer(GL_ARRAY_BUFFER, pxCloudHeader.xVBOs.uiVBO_XYZ);
glBufferData(GL_ARRAY_BUFFER, pxCloudHeader.iPointsCount * sizeof(GLfloat) * 3, &p3DfXYZ->data[0], GL_STREAM_DRAW);
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);

glBindVertexArray(0);

绘图电话:

glBindVertexArray(pxCloudHeader.uiVBA);
glDrawArrays(GL_POINTS, 0, pxCloudHeader.iPointsCount); // here exception is thrown
glBindVertexArray(0);

我还检查了是否抛出了OpenGL错误,但我没有找到任何错误。 任何提示如何处理这个问题将不胜感激。

2 个答案:

答案 0 :(得分:0)

您可以小批量绘制数据。虽然缓冲区的大小没有预定义的上限,但在单个缓冲区中存储8 GB的数据很多。我不会对某些东西会爆炸感到惊讶。

我可能会开始在每个缓冲区中存储大约100万个,或者最多几百万个点。然后使用具有此固定大小的缓冲池,足以容纳所有数据点。

这甚至可能对您的表现有益,因为它允许您在将所有数据复制到缓冲区之前开始提交绘图调用。这将使您在CPU和GPU工作之间获得更好的重叠。

根据您随机播放的数据量,您可能还希望使用glMapBuffer() / glUnmapBuffer()代替glBufferData()。这通常可以避免数据的一次复制操作。

答案 1 :(得分:0)

我怀疑您的问题是由于GLsizeiptr

的大小造成的

这是用于表示OpenGL缓冲区对象中的大小的数据类型,通常为32位。

700 million vertices * 4-bytes per-component * 3-components = 8,400,000,000 bytes

如果使用32位指针,尝试在GL中分配那么多字节存在严重问题:

8400000000 & 0xFFFFFFFF = 4,105,032,704 (half as many bytes as you actually need)

如果您的实施中的sizeof (GLsizeiptr) 4 ,那么您将别无选择,只能拆分阵列。 32位GLsizeiptr仅允许您存储4个连续的GiB内存,但如果您使用3个单组件数组,则可以解决此问题。使用顶点着色器,您可以重建这三个独立的(足够小的)数组,如下所示:

#version 330

layout (location = 0) in float x; // Vertex Attrib Ptr. 0
layout (location = 1) in float y; // Vertex Attrib Ptr. 1
layout (location = 2) in float z; // Vertex Attrib Ptr. 2

void main (void)
{
  gl_Position = vec4 (x,y,z,1.0);
}

性能可怕,但这是以最小的努力解决问题的一种方法。


顺便说一下,这里的系统内存量(32 GiB)不是你最大的问题。你应该考虑GPU上的VRAM数量,因为理想情况下缓冲对象被设计为存储在GPU上。缓冲区对象中任何太大而无法存储在GPU内存中的部分都必须在使用时通过PCIe(目前)总线传输。