Медленный рендеринг после большой передачи с графического процессора на оперативную память?

Я пытался визуализировать облако точек (>100 миллионов точек), я перенес все данные в GPU и просто использовал имя буфера для доступа к ним. Все работает нормально, пока я не реализовал функцию, которая требует от меня переноса всех данных обратно в оперативную память.

Вот как я передаю данные в GPU:

glBindVertexArray(vao);

// some data
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * GetSize()  * 3, &vertices[0], GL_STATIC_DRAW); // pos

// some attributes
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0); // pos

...
// some other code
...

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

glDisableVertexAttribArray(0);

// Clear the contents in the RAM
vertices.clear();
vertices.shrink_to_fit();

Затем мне в какой-то момент понадобилась функция, чтобы вернуть данные, чтобы сохранить изменения, вот что я сделал:

// restore data back to RAM
// this code was called for >4000 times

glBindBuffer(GL_ARRAY_BUFFER, c.vbo);
c.vertices.clear();
c.vertices.resize(c.sizeg);
glGetBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec3) * c.sizeg, &c.vertices[0].position.x);

После этого программа будет зависать каждый раз, когда мне нужно отобразить это облако точек.

Я удалил все остальные коды, чтобы протестировать только этот код, и именно этот фрагмент кода для передачи данных вызвал задержку

Такое ощущение, что внутри графического процессора копируется огромное количество данных каждый раз, когда я пытаюсь отобразить данные, из-за которых он зависает. Однако после того, как я перенес данные обратно из графического процессора в оперативную память, данные, которые изначально находились внутри графического процессора, остались нетронутыми. Я думал, что рендеринг должен быть таким же плавным, как и раньше, но это не так.

Изменилось ли что-то в состоянии OpenGL, вызвавшее эту задержку?


person Zhou Zhi Hua    schedule 25.09.2020    source источник
comment
каждый раз, когда происходит отставание, я замечал резкое снижение производительности графического процессора в 3D и копировании в диспетчере ресурсов Windows, что дает мне подсказку, что мой графический процессор должен делать что-то еще во время задержки вместо рисования.   -  person Zhou Zhi Hua    schedule 25.09.2020


Ответы (1)


Вы дали обещание OpenGL. Тогда ты нарушил свое обещание. Так что OpenGL наказал вас за это.

Вы сообщили OpenGL о том, как вы собираетесь использовать этот буферный объект:

GL_STATIC_DRAW

Это означает, что вы сказали OpenGL, что будете писать в буфер (DRAW), но не читать из него. И вы сказали, что будете писать на него редко (STATIC). Таким образом, реализация OpenGL поместила хранилище объекта буфера в место, оптимальное для доступа к графическому процессору, но не для доступа к центральному процессору.

Затем вы читаете оттуда. Вы сделали то, что обещали OpenGL, но не собирались делать.

Теперь люди (множество) постоянно нарушают подобные обещания реализациям OpenGL. Поэтому многие реализации в основном перестали им верить. То есть вместо того, чтобы слушать, что вы говорите, что собираетесь делать с буфером, они обращают внимание на то, что вы на самом деле делаете.

Реализация видела, что вы читали из буфера. Таким образом, предполагается, что вы намерены делать это с некоторой регулярностью. Таким образом, теперь он переносит хранилище буфера в место, более оптимальное для чтения ЦП... но менее оптимальное для чтения ГП.

В современном OpenGL есть API для создания буферных объектов, где ложь больше не разрешена. Вы указываете, какие операции вы можете использовать с буфером, и реализация OpenGL будет удерживать вас на этом, делая все остальные попытки доступа невозможными.

Если вы используете API буферного хранилища, то весьма вероятно, что попытка чтения из буфера с помощью glGetBufferSubData не приведет к тому, что API просто перетасует память. Предотвращение перетасовки хранилища — половина цели этого API. Если вы все еще получаете этот эффект замедления от своей реализации, возможно, вы мало что можете сделать, чтобы остановить его в OpenGL.

Наиболее эффективной альтернативой (кроме использования Vulkan, где у вас есть полный контроль над памятью) было бы просто вообще не пытаться читать ее из OpenGL. То есть не относитесь к хранилищу графического процессора как к чему-то, что вы можете просто прочитать, когда вам понадобятся какие-то данные. Если вам нужно использовать данные на ЦП, сохраните их там. То есть сохранить его копию и в памяти процессора.

person Nicol Bolas    schedule 25.09.2020