Сделать буфер хранения шейдера доступным в разных шейдерных программах

Какой макет и привязку мне нужно сделать, чтобы (рабочий) буфер хранения шейдера читался во второй шейдерной программе? Я установил и заполнил 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);

Я надеюсь, что это проясняет вещи! Дайте мне знать, если у вас есть дополнительные вопросы.

Другие вопросы по тегам