2016-06-05 4 views
0

Я пытаюсь выяснить, как эффективно очистить буфер хранения шейдеров. ОБП выглядит в моем шейдере:Эффективно очищает буфер хранения шейдеров

struct Type{ 
    vec4 A, B, C; 
}; 
layout (std430, binding = 1) buffer TypeBuffer { 
    Type items[]; 
}; 

Я пишу в этот буфер один раз за кадр, и это нужно, чтобы быть очищено в начале следующего кадра. Спецификация предлагает удобную функцию, чтобы сделать это:

glClearNamedBufferData(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data); 

К сожалению, ни internalFormat перечисления не соответствует формату типа. Мне кажется, что эта функция не подходит для очистки произвольных SSBO, хотя она явно предлагает очистить их в спецификациях.

На данный момент я торчащий к этому методу:

//Do this only once! 
    float* nullData = new float[N * sizeof(float) * 4 * 3]; 
    for(int i = 0; i < N * sizeof(float) * 4 * 3; i++){ 
    nullData[i] = 0.f; 
    } 
    glGenBuffers(1, &bufferID); 

    //Execute this every frame 
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, bufferID); 
    glBufferData(GL_SHADER_STORAGE_BUFFER, N * sizeof(float) * 4 * 3, nullData, GL_STATIC_READ); 
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); 

Если предположить, что я мог бы использовать glClearNamedBufferData, будет ли даже разница в производительности между этими двумя методами очистки? Есть ли более быстрый способ очистить SSBO каждый кадр по сравнению с моим текущим решением?

ответ

1

glClear[Named]BufferData непосредственно не обрабатывает сложные типы данных, такие как структуры. Он обрабатывает буфер как массив основных типов и устанавливает каждый отдельный элемент массива в одно и то же значение. Поэтому, если вы хотите использовать структуру, содержащую, например, две поплавки a и b, и вы хотите инициализировать буфер так, чтобы каждый элемент записи a был установлен в 0.0f, но каждый b до 1.0f было бы невозможно сделать это с помощью этого функция.

Однако, поскольку ваш буфер содержит только последовательность поплавков, вы можете очистить его как таковое с помощью internalFormat, установленного на GL_R32F. Поскольку вы используете vec4, «наиболее подходящий» формат будет фактически GL_RGBA32F.

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

Скорее всего, да. glBufferData должен будет повторно передать полный массив, в то время как вариант glClear[Named]BufferData просто должен передать данные для одного пикселя. Если буфер больше, чем несколько элементов, он будет намного быстрее.

Есть и другая разница. glBufferData не просто перезаписывает содержимое буфера (glBufferSubData сделает это), но он создает для него совершенно новое хранилище данных. Это может также повлиять на производительность, так или иначе. Например, вызов glClear[Named]BufferData может задерживаться до тех пор, пока GL не обработает текущее содержимое этого буфера. Фактические зависимости между операциями относительно этого буфера и неявные или явные синхронизации, которые могут потребоваться, будут в значительной степени влиять на производительность для разных сценариев.

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

1

Не имеет значения, нет ли значения internalformat, соответствующего вашим Type объявлениям.Что такое Type, в его основе?

Это 12 поплавков.

является a internalformat, который соответствует поплавком. Действительно, ваше ручное очищение буфера делает точно так, что: он создает не массив Type, а массив float. Он заполняет их нулями и записывает их в буфер. Поэтому просто скажите OpenGL, чтобы сделать это:

float val = 0.0f; 
glCreatNamedBufferData(buff, GL_R32F, GL_RED, GL_FLOAT, &val); 

Действительно, это даже не должно быть так сложно. Поскольку вы знаете, что IEEE-754 поплавки представляют значение 0.0 в виде последовательности байтов, содержащих все нули, можно просто очистить буфер для всех нулевых байт:

GLubyte val = 0; 
glClearNamedBufferData(buff, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, &val); 

Есть ли более быстрый способ очистить SSBO каждый кадр по сравнению с моим текущим решением?

С точки зрения выполнения клиринговой операции, почти наверняка.

Смежные вопросы