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

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

0 голосов
/ 23 марта 2019

Кажется, что вы в основном там, но есть несколько вещей, на которые стоит обратить внимание.

Согласна ли компоновка в обеих программах? макет (std140, связывание = 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);

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

...