Сделать буфер хранения шейдера доступным в разных шейдерных программах
Какой макет и привязку мне нужно сделать, чтобы (рабочий) буфер хранения шейдера читался во второй шейдерной программе? Я установил и заполнил SSBO, который успешно связал и использовал в геометрическом шейдере. Этот шейдер читает и пишет в этот SSBO - проблем пока нет. Там нет рендеринга.
На следующем этапе мой проход рендеринга (вторая шейдерная программа) должен иметь доступ к этим данным. Идея состоит в том, чтобы иметь большой набор данных, в то время как вершинный шейдер второй программы использует только некоторые индексы для каждого вызова рендера, чтобы выбрать определенные значения этого SSBO.
Я пропускаю какие-то конкретные команды привязки или я поставил их не в том месте?
Согласован ли макет в обеих программах? Я испортил экземпляры?
Я просто не могу найти примеры SSBO, используемых в двух программах..
Создание, наполнение и привязка:
float data[48000];
data[0] = -1.0;
data[1] = 1.0;
data[2] = -1.0;
data[3] = -1.0;
data[4] = 1.0;
data[5] = -1.0;
data[6] = 1.0;
data[7] = 1.0;
data[16000] = 0.0;
data[16001] = 1.0;
data[16002] = 0.0;
data[16003] = 0.0;
data[16004] = 1.0;
data[16005] = 0.0;
data[16006] = 1.0;
data[16007] = 1.0;
GLuint ssbo;
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo);
Экземпляр в геометрии шейдера
layout(std140, binding = 1) buffer mesh
{
vec2 points[8000];
vec2 texs[8000];
vec4 colors_and_errors[8000];
} mesh_data;
Второй экземпляр в вершинном шейдере другой программы
layout(std140, binding = 1) buffer mesh
{
vec2 points[8000];
vec2 texs[8000];
vec4 colors_and_errors[8000];
} mesh_data;
Работают ли экземпляры друг против друга? Прямо сейчас я не публикую свои привязки, сделанные в цикле рендеринга, так как я не уверен, что я там делаю. Я пытался связать до / после изменения используемой программы; безуспешно.
У кого-нибудь есть идея?
РЕДАКТИРОВАТЬ: я также должен привязать SSBO ко второй программе за пределами цикла рендеринга? По-другому, чем первая привязка?
РЕДАКТИРОВАТЬ: Хотя я не решил эту конкретную проблему, я нашел обходной путь, который может быть даже больше в смысле opengl.
Я использовал SSBO первой программы в качестве атрибутов вершин во второй программе. Эта и функция индексированного рендеринга opengl решили эту проблему.
(Должно ли это быть помечено как решенное?)
1 ответ
Кажется, что вы в основном там, но есть несколько вещей, которые вы должны остерегаться.
Согласован ли макет в обеих программах? расположение (std140, binding = 1) буферной сетки
Вы должны быть осторожны с этим макетом. std140 будет округлять выравнивания до vec4, поэтому больше не будет совпадать с данными, которые вы предоставляете из кода C. В этом случае std430 должен работать для вас.
Должен ли я также привязать SSBO ко второй программе вне цикла рендеринга? По-другому, чем первая привязка?
После того, как вы связали SSBO один раз, предполагая, что обе программы используют одну и ту же точку привязки (в вашем примере это так), тогда у вас все будет хорошо. Обмен данными между программами в порядке, но требуется синхронизация. Вы можете усилить это с помощью барьера памяти.
Вы не упоминаете VAO, но вы сможете использовать SSBO только после того, как привязали VAO (а не по умолчанию).
Я думаю, что это лучше всего объяснить на примере.
Вершинный шейдер для первой программы. Он использует данные буфера для своих координат позиции и текстуры, а затем переворачивает позиции в Y.
layout(std430, binding = 1) buffer mesh {
vec4 points[3];
vec2 texs[3];
} mesh_data;
out highp vec2 coords;
void main() {
coords = mesh_data.texs[gl_VertexID];
gl_Position = mesh_data.points[gl_VertexID];
mesh_data.points[gl_VertexID] = vec4(gl_Position.x, -gl_Position.y, gl_Position.zw);
}
Проверен шейдер для второй программы. Он просто использует данные, но не изменяет их.
layout(std430, binding = 1) buffer mesh {
vec4 points[3];
vec2 texs[3];
} mesh_data;
out highp vec2 coords;
void main() {
coords = mesh_data.texs[gl_VertexID];
gl_Position = mesh_data.points[gl_VertexID];
}
В приложении необходимо привязать VAO.
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
Затем настройте свой SSBO.
float const data[] = {
-0.5f, -0.5f, 0.0f, 1.0,
0.0f, 0.5f, 0.0f, 1.0,
0.5f, -0.5f, 0.0f, 1.0,
0.0f, 0.0f,
0.5f, 1.0f,
1.0f, 0.0f
};
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo);
Сделайте розыгрыш при помощи первой программы.
glUseProgram(first_program);
glDrawArrays(GL_TRIANGLES, 0, 3);
Вставьте барьер памяти, чтобы обеспечить завершение записи из предыдущего вызова отрисовки, прежде чем следующий вызов отрисовки попытается прочитать из буфера.
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
Сделайте розыгрыш при помощи второй программы.
glUseProgram(second_program);
glDrawArrays(GL_TRIANGLES, 0, 3);
Я надеюсь, что это проясняет вещи! Дайте мне знать, если у вас есть дополнительные вопросы.