glDrawArrays место записи нарушения прав доступа

Я пытаюсь визуализировать очень большое облако точек (700 млн. Точек) и glDrawArrays отладчик вызовов выдает исключение местоположения записи нарушения доступа. Я использую тот же код для рендеринга облаков меньшего размера (100 млн), и все работает отлично. У меня также достаточно оперативной памяти (32 ГБ) для хранения данных.

Для хранения облака точек я использую 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, но я не нашел ни одной.
Любая подсказка, как решить эту проблему, будет оценена.

3

Решение

Я подозреваю, что ваша проблема связана с размером GLsizeiptr,

Это тип данных, используемый для представления размеров в буферных объектах OpenGL, и он обычно является 32-разрядным.

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

Существует серьезная проблема с попыткой выделить столько байтов в GL, если он использует 32-битные указатели:

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

Если sizeof (GLsizeiptr) на вашей реализации 4 тогда у вас не будет другого выбора, кроме как разделить ваш массив. 32-битный GLsizeiptr только позволяет хранить 4 смежных гигабайта памяти, но вы можете обойти это, если вместо этого будете использовать 3 однокомпонентных массива. Используя вершинный шейдер, вы можете восстановить эти 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 ГиБ) не является вашей самой большой проблемой. Вы должны думать о количестве VRAM на вашем GPU, потому что в идеале буферные объекты предназначены для хранения на GPU. Любая часть объекта буфера, которая слишком велика для хранения в памяти GPU, должна будет передаваться по шине PCIe (в наши дни), когда она используется.

0

Другие решения

Вы можете рисовать данные небольшими партиями. Хотя нет предопределенного верхнего предела для размера буфера, хранение 8 ГБ данных в одном буфере много. Я не очень удивлен, что что-то взорвется.

Я бы, вероятно, начал с хранения примерно 1 миллиона или не более нескольких миллионов точек в каждом буфере. Затем используйте пул буферов с этим фиксированным размером, достаточным для размещения всех ваших точек данных.

Это может даже повысить производительность, поскольку позволяет начать отправлять вызовы отрисовки перед копированием всех данных в буферы. Это даст вам лучшее совпадение между работой процессора и графического процессора.

С количеством данных, которые вы перетасовываете, вы можете также захотеть использовать glMapBuffer()/glUnmapBuffer() вместо glBufferData(), Как правило, это позволяет избежать одной операции копирования данных.

0

По вопросам рекламы [email protected]