Буфер хранения OpenGL Shader / memoryBarrierBuffer - PullRequest
0 голосов
/ 26 сентября 2018

В настоящее время я создал два SSBO для обработки некоторых источников света, потому что интерфейс VS-FS in out не может обрабатывать много источников света (я использую затенение вперед).Для первого я передаю значения только шейдеру (в основном одно только для чтения) [cpp]:

struct GLightProperties
{
    unsigned int numLights;
    LightProperties properties[];
};

...

glp = (GLightProperties*)malloc(sizeof(GLightProperties) + sizeof(LightProperties) * lastSize);

...

glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLightProperties) + sizeof(LightProperties) * lastSize, glp, GL_DYNAMIC_COPY);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);

Файл шейдера [GLSL]:

layout(std430, binding = 1) buffer Lights
{
    uint numLights;
    LightProperties properties[];
}lights;

Итак, это первоеSSBO работает нормально.Однако в другом, целью которого является интерфейс VS-FS, есть некоторые проблемы:

glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo2);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * 4 * 3 * lastSize, nullptr, GL_DYNAMIC_COPY);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);

GLSL:

struct TangentProperties
{
    vec4 TangentLightPos;
    vec4 TangentViewPos;
    vec4 TangentFragPos;
};

layout(std430, binding = 0) buffer TangentSpace
{
    TangentProperties tangentProperties[];
}tspace;

Итак, вы заметили, что я передаю nullptrglBufferData потому что vs запишет в буфер, а fs прочитает его содержимое.Как и в сценарии VS:

for(int i = 0; i < lights.numLights; i++)
{
    tspace.tangentProperties[index].TangentLightPos.xyz = TBN * lights.properties[index].lightPosition.xyz;
    tspace.tangentProperties[index].TangentViewPos.xyz  = TBN * camPos;
    tspace.tangentProperties[index].TangentFragPos.xyz  = TBN * vec3(worldPosition);
    memoryBarrierBuffer();
}

После этого ФС считывает значения, которые оказываются просто мусором.Я что-то не так делаю с барьерами памяти?

Выход получается следующим образом: Pixels bugging

1 Ответ

0 голосов
/ 26 сентября 2018

ОК, давайте уберем очевидную ошибку:

for(int i = 0; i < lights.numLights; i++)
{
    tspace.tangentProperties[index].TangentLightPos.xyz = TBN * lights.properties[index].lightPosition.xyz;
    tspace.tangentProperties[index].TangentViewPos.xyz  = TBN * camPos;
    tspace.tangentProperties[index].TangentFragPos.xyz  = TBN * vec3(worldPosition);
    memoryBarrierBuffer();
}

index никогда не меняется в этом цикле, поэтому вы пишете только один свет, ивы пишете только значения last lights.Все остальные источники света будут иметь мусорные / неопределенные значения.

Так что вы, вероятно, имели в виду i, а не index.

Но это только начало проблемы.Видите ли, если вы сделаете это изменение, вы получите следующее:

for(int i = 0; i < lights.numLights; i++)
{
    tspace.tangentProperties[i].TangentLightPos.xyz = TBN * lights.properties[i].lightPosition.xyz;
    tspace.tangentProperties[i].TangentViewPos.xyz  = TBN * camPos;
    tspace.tangentProperties[i].TangentFragPos.xyz  = TBN * vec3(worldPosition);
}
memoryBarrierBuffer();

Обратите внимание, что барьер находится за пределами цикла.

Это создает новую проблему.В этом коде каждый вызов вершинного шейдера будет записываться в один и тот же буфер памяти .В конце концов, SSBO не являются переменными VS output .Выходные переменные хранятся как часть вершины.Затем растеризатор интерполирует эти данные вершин по всему примитиву при растеризации, что обеспечивает входные значения для FS.Таким образом, одна VS не может растоптать выходные переменные другой VS.

Этого не происходит с SSBO.Каждая VS действует на одинаковую память SSBO.Так что, если они пишут с одинаковыми индексами одного и того же массива, они пишут по одному и тому же адресу памяти.Что является условием гонки (поскольку не может быть никакой синхронизации между вызовами родного брата) и, следовательно, неопределенным поведением.

Итак, единственный способ , который вы пытаетесь сделать, может сработать, есливаш буфер содержит numLights записей для каждой вершины во всей сцене .

Это принципиально неразумное количество места.Даже если бы вы могли сократить его до количества вершин в конкретном вызове отрисовки (что выполнимо, но я не буду говорить, как), вы все равно отставали бы в производительности.Каждый вызов FS должен выполнять чтение 144 байтов данных для каждого источника света (3 записи таблицы, по одному для каждой вершины треугольника), линейно интерполировать эти значения и затем выполнять вычисления освещения.

Для вас было бы быстрее просто передать матрицу TBN в качестве выхода VS и выполнить умножение матрицы в FS.Да, это многократное умножение матриц, но графические процессоры действительно быстры при умножении матриц и очень медленно при чтении памяти.

Кроме того, пересмотрите, нужно ли вам положение фрагмента касательного пространства.Вообще говоря, вы никогда не делаете.

...