3

I'm trying to visualize very large point cloud (700 mln points) and on glDrawArrays call debugger throws access violation writing location exception. I'm using the same code to render smaller clouds (100 mln) and everything works fine. I also have enough RAM memory (32GB) to store the data.

To store point cloud I'm using std::vector<Point3D<float>> where Point3D is

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

Vertex array and buffer initialization:

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);

Drawing call:

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

I also checked if there was OpenGL error thrown but I haven't found any.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Amadeusz
  • 1,488
  • 14
  • 21
  • I don't see a glGenBuffers call in your snippet, but you could just have omitted that. But geez, 2.8GiB of data is quite a chunk to chew down for a VBO. It's rare enough that I suggest it, but I'd suggest you try good old legacy client side vertex arrays. And hey, they even work with 3.3 compatibility profile. Just don't create neither a VBO nor a VAO and give glVertexAttribPointer a pointer to the data in your process' address space. – datenwolf Dec 21 '14 at 00:14
  • I'm not sure but I think when you assign GL_FLOATS your maximum number of vertices will be 2**32 = 4,294,967,296. If you surpass this number it could yell access violation. You could split up the data. – Thellimist Dec 21 '14 at 01:03
  • datenwolf: Yes I omitted glGenBuffers for more simplicity. My goal is to achieve the best performance also and what you suggest might resolve the memory issue but it will create performance problem. Correct me if I'm, wrong. – Amadeusz Dec 21 '14 at 09:08
  • Furkan: If that is an issue I would expect error to be thrown when loading data to buffer with glBufferData() or on std::vector allocation. Also my dataset is smaller than the number you gave me. Splitting up the data may resolve my problem, but I would like to avoid it if possible. – Amadeusz Dec 21 '14 at 09:23
  • You are on a 64-bit platform I assume if you have memory that large. Can you verify that `sizeof (GLsizeiptr)` is in fact **8**? 700 million * 4 * 3 > a 32-bit pointer can reference. You might be overflowing the size parameter when you allocate your buffer. The size of `GLsizeiptr` is going to dictate the largest contiguous block of memory you can allocate; there is no other API limit you can query for that sort of thing... but using 3 non-contiguous arrays instead of 1 interleaved array may help you bypass that sort of limit. – Andon M. Coleman Dec 21 '14 at 17:53

2 Answers2

0

You could draw the data in smaller batches. While there is no predefined upper limit for the size of a buffer, storing 8 GBytes of data in a single buffer is a lot. I'm not very surprised that something would blow up.

I would probably start with storing something like 1 million, or at most a few million, points in each buffer. Then use a pool of buffers with this fixed size, enough to accommodate all your data points.

This might even be beneficial for you performance, because it allows you start submitting draw calls before copying all your data into buffers. This will give you better overlap between CPU and GPU work.

With the amount of data you are shuffling around, you may also want to look into using glMapBuffer()/glUnmapBuffer() instead of glBufferData(). This generally avoids one copy operation for the data.

Reto Koradi
  • 53,228
  • 8
  • 93
  • 133
  • I would like to avoid splitting up the data if possible bacause it will create for me more synchronization problems. But it may be the solution, so I will for sure try this. Also thanks for great advice with glMapBuffer()/glUnmapBuffer() - if it's faster and safer than glBufferData() I will definitely use it. – Amadeusz Dec 21 '14 at 09:18
0

I suspect your problem is due to the size of GLsizeiptr.

This is the data type used to represent sizes in OpenGL buffer objects, and it is typically 32-bit.

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

There is a serious issue with trying to allocate that many bytes in GL if it is using 32-bit pointers:

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

If sizeof (GLsizeiptr) on your implementation is 4 then you will have no choice but to split your array up. A 32-bit GLsizeiptr only allows you to store 4 contiguous GiB of memory, but you can work around this if you use 3 single-component arrays instead. Using a vertex shader you can reconstruct these 3 separate (small enough) arrays like so:

#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);
}

Performance is going to be awful, but that is one way to approach the problem with minimal effort.


By the way, the amount of system memory here (32 GiB) is not your biggest issue. You should be thinking in terms of the amount of VRAM on your GPU because ideally buffer objects are designed to be stored on the GPU. Any part of the buffer object that is too large to be stored in GPU memory will have to be transferred over the PCIe (these days) bus when it is used.

Community
  • 1
  • 1
Andon M. Coleman
  • 42,359
  • 2
  • 81
  • 106
  • Thank you very much for pointing it out. Size of my GLsizeiptr is 8, but I see now that my problem lies here. In fact my first data structure was 3 seperate arrays, but I abandoned that idea because some libraries that I use need continous XYZ arrays input and I wanted to avoid double data representation, but now I see that I may not have a choice :( – Amadeusz Dec 23 '14 at 08:18