Я обнаружил странное поведение драйверов, которое не могу понять при использовании OpenGL 4.3.
Я рисую некоторые треугольники с glDrawArraysIndirect()
на стандартном FBO.
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, command);
glBindVertexArray(VAO);
glDrawArraysIndirect(GL_TRIANGLES, nullptr);
glBindVertexArray(0);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
command
определяется следующим образом:
struct DrawArraysIndirectCommand
{
GLuint count;
GLuint primCount;
GLuint first;
GLuint baseInstance;
};
Он обновляется в фрагментном шейдере предыдущего вызова отрисовки, сделанного на внеэкранном FBO, где он связан как атомарныйcounter:
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, command);
В фрагментном шейдере он обновляется следующим образом:
layout(binding = 0, offset = 0) uniform atomic_uint vertex_count;
main() {
...
if(some condition) { atomicCounterIncrement(vertex_count); }
...
}
Проблема возникает из-за разного поведения драйверов nvidia и драйверов intel. Сначала я связывал command
в качестве атомарного счетчика в начале программы, перед любым вызовом отрисовки, и никогда не отменял его до конца программы:
init() {
// Generation of the buffer
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, command); // <--- FIX
}
draw() {
glBindFramebuffer(GL_FRAMEBUFFER, offscreen_FBO);
// Clear indirect draw command buffer
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, command);
glBufferSubData(GL_DRAW_INDIRECT_BUFFER, 0, sizeof(DrawArraysIndirectCommand),
&clearedCommand);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
glBindVertexArray(VAO2);
// Draw call in which the command is updated from the fragment shader
glDrawArrays(GL_TRIANGLES, 0, another_vertex_count);
glBindVertexArray(0);
//use of the updated command in another draw call...
}
Таким образом, он работал нормальнос драйверами nvidia. Но когда я тестировал приложение с драйверами Intel, оно работало всего несколько минут, а затем зависало (сбой произошел в графическом драйвере, но ошибки не было). Я решил эту проблему, привязав атомный счетчик каждый раз перед вызовом отрисовки:
draw() {
glBindFramebuffer(GL_FRAMEBUFFER, offscreen_FBO);
// Clear indirect draw command buffer
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, command);
glBufferSubData(GL_DRAW_INDIRECT_BUFFER, 0, sizeof(DrawArraysIndirectCommand),
&clearedCommand);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, command); // <--- FIX
glBindVertexArray(VAO2);
// Draw call in which the command is updated from the fragment shader
glDrawArrays(GL_TRIANGLES, 0, another_vertex_count);
glBindVertexArray(0);
//use of the updated command in another draw call...
}
Таким образом, он отлично работает и на драйверах Intel. Но почему? Зачем мне каждый раз перепривязывать? Это как если бы драйвер иногда терял привязку, но нет других glBindBufferBase()
, которые связываются с тем же индексом. Я думаю, что проблема связана с тем фактом, что command
используется как в качестве атомного счетчика, так и в качестве косвенного буфера команд, но я не могу понять ссылку.