OpenGL Чтение из текстурного блока, в настоящее время связанного с кадровым буфером

Я столкнулся с проблемой при попытке чтения данных из текстурного блока, который в данный момент подключен к кадровому буферу рисования. Ошибки удаляются, пока я использую glTextureBarrier между вызовами отрисовки. Однако я пытаюсь устранить вызовы отрисовки, так что это неоптимальное решение. Спецификация OpenGL 4.5 (раздел 9.3 Циклы обратной связи между текстурами и кадровым буфером) гласит, что

Механизмы для прикрепления текстур к объекту кадрового буфера не предотвращают присоединение к объекту одно- или двумерного уровня текстуры, грани уровня текстуры карты куба или слоя двумерного массива или трехмерной текстуры. Нарисуйте кадровый буфер, пока та же самая текстура связана с текстурным блоком. В то время как это условие выполняется, операции текстурирования, получающие доступ к этому изображению, будут давать незавершенные результаты, как описано в конце раздела 8.14. ... В частности, значения отрисованных фрагментов не определены, если какой-либо этап шейдера извлекает тексели, и те же самые тексели записываются через выходные данные фрагмента шейдера, даже если операции чтения и записи не находятся в одном и том же вызове отрисовки, если не применяется любое из следующих исключений:

Чтение и запись выполняются из / в непересекающиеся наборы текселей (после учета правил фильтрации текстур).

Существует только одно чтение и запись каждого текселя, и чтение происходит в вызове фрагментного шейдера, который записывает один и тот же тексел (например, используя texelFetch2D(sampler, ivec2(gl_FragCoord.xy), 0);),

Если texel был написан, то для безопасного чтения результата выборка texel должна быть в последующем вызове отрисовки, разделенном командой void TextureBarrier( void ); TextureBarrier гарантирует, что запись завершена, и кэши были аннулированы до выполнения последующих вызовов отрисовки.

Я делаю это до 4 других текстур без проблем. Для этих текстур я делаю только одно чтение и одну запись с одного и того же текселя, поэтому они охватываются вторым исключением. Текстура, вызывающая проблему, требует некоторой фильтрации, поэтому мне нужно более одного чтения и с разных текселей перед записью. Я подумал, что это может быть разрешено через 1-е исключение, поэтому я поместил их в текстуру массива, чередуя, какой слой был прочитан и записан. Идея заключалась в том, что это создаст настройку, в которой операции чтения и записи будут разделять / переставлять множество текселей. Это не помогло.

Я также пытался выполнять glTextureBarrier только при каждом другом вызове отрисовки, чтобы проверить, не является ли это третьим вызовом отрисовки, вызвавшим проблему. Это дало разные (все еще неправильные) результаты, когда я постоянно использовал барьеры, а когда - нет.

Вызовы отрисовки рисуют одну точку в 0,0,0, которая превращается в полноэкранный квад в геометрическом шейдере.

Обновить

Я прослеживаю данные объема.

Настройка кадрового буфера

    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, rayPositionTexture, 0);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, rayDirectionTexture, 0);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, IORTexture, 0);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, resultTexture, 0);
    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, rayOffsetTexture, 0, 0);
    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, rayOffsetTexture, 0, 1);

Shader

...
uniform sampler2D RayPositionTexture;
uniform sampler2D RayDirectionTexture;
uniform sampler2DArray RayOffsetTexture;
uniform sampler2D IORTexture;
uniform sampler2D ColorTexture;
...
flat in uint offsetIndex;
layout(location = 0) out vec4  outRayPosition;
layout(location = 1) out vec4  outRayDirection;
layout(location = 2) out float outIOR;
layout(location = 3) out vec4  outColor;
layout(location = 4) out vec4  outRayOffsetA;
layout(location = 5) out vec4  outRayOffsetB;
...
vec3 filteredOffset(ivec2 Pixel)
{
    vec3 Offset = vec3(0.0);
    float TotalWeight = 0.0;
    for(int i = -KernelRadius; i <= KernelRadius; i++)
    {
        for (int j = -KernelRadius; j <= KernelRadius; j++)
        {
            ivec2 SampleOffset = ivec2(i,j);
            ivec3 SampleLocation = ivec3(Pixel + SampleOffset, offsetIndex);
            vec3  Sample = texelFetch(RayOffsetTexture, SampleLocation, 0).xyz;
            float Weight = KernelRadius > 0 ? gauss(SampleOffset) : 1.0f;

            Offset += Sample * Weight;
            TotalWeight += Weight;
        }
    }
    Offset = Offset / TotalWeight;
    return Offset;
}
...
        //if (offsetIndex == 1)
        outRayOffsetA = vec4(RayDirection.xyz - RayDirectionNew, 0.0);
        //else
        outRayOffsetB = vec4(RayDirection.xyz - RayDirectionNew, 0.0);
        outIOR = IOR;
    } else {
        // if (offsetIndex == 1)
        outRayOffsetA = vec4(0.0);
        // else
        outRayOffsetB = vec4(0.0);
        outIOR = PreviousIOR;
        //imageStore(VolumeBackTexture, Pixel, vec4(1.0));
    }
    outColor = Color;
...

Рисовать звонки

GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 };
glDrawBuffers(6, drawBuffers);

// Run shader
glBindVertexArray(pointVAO);
float distance = 0.0f;
for (int i = 0; distance < 1.73205080757f; i++)
{
    glTextureBarrier();
    glDrawArrays(GL_POINTS, i, 1); 
    distance += fUnitStep;
}
glBindVertexArray(0);

Вышеуказанное без текстурного барьера дает те же результаты (неправильный результат), что и

glBindVertexArray(pointVAO);
glDrawArrays(GL_POINTS, 0, int(std::ceil(1.73205080757f / fUnitStep)));
glBindVertexArray(0); 

0 ответов

Чтобы ответить на этот вопрос, здесь необходим TextureBarrier, потому что я хотел читать только что нарисованные тексели. Это можно сделать безопасно только в том случае, если предыдущий вызов отрисовки завершен и кэши текстур были признаны недействительными, что в точности и гарантирует TextureBarrier.

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