Bindless textures, pixel are flickering on the window, driver issue?

Hi! I use 3 shaders, the goal is the check the most opaque fragment over the refractable objects, and then hide refraction if there is an opaque fragment before.

The code worked well until I use bindless texturing.
I think it’s a driver issue but I post here to be sure it’s it.

In this shader the texture is ok :

const std::string fragmentShader = R"(#version 460
                                                  #extension GL_ARB_bindless_texture : enable
                                                  struct NodeType {
                                                      vec4 color;
                                                      float depth;
                                                      uint next;
                                                  };
                                                  layout(binding = 0, offset = 0) uniform atomic_uint nextNodeCounter;
                                                  layout(binding = 0, r32ui) uniform uimage2D headPointers;
                                                  layout(binding = 0, std430) buffer linkedLists {
                                                      NodeType nodes[];
                                                  };
                                                  layout(std140, binding=0) uniform ALL_TEXTURES {
                                                      sampler2D textures[200];
                                                  };
                                                  uniform uint maxNodes;
                                                  uniform float haveTexture;
                                                  uniform sampler2D texture;
                                                  in vec4 frontColor;
                                                  in vec2 fTexCoords;
                                                  in flat uint texIndex;
                                                  layout (location = 0) out vec4 fcolor;
                                                  void main() {
                                                       uint nodeIdx = atomicCounterIncrement(nextNodeCounter);
                                                       vec4 texel = (texIndex != 0) ? frontColor * texture2D(textures[texIndex-1], fTexCoords.xy) : frontColor;
                                                       if (nodeIdx < maxNodes) {
                                                            uint prevHead = imageAtomicExchange(headPointers, ivec2(gl_FragCoord.xy), nodeIdx);
                                                            nodes[nodeIdx].color = texel;
                                                            nodes[nodeIdx].depth = gl_FragCoord.z;
                                                            nodes[nodeIdx].next = prevHead;
                                                       }
                                                       fcolor = vec4(0, 0, 0, 0);
                                                  })";

But in this shader, no textures, alpha is always 0.

const std::string buildAlphaBufferFragmentShader = R"(#version 460
                                                                  #extension GL_ARB_bindless_texture : enable
                                                                  layout(std140, binding=0) uniform ALL_TEXTURES {
                                                                    sampler2D textures[200];
                                                                  };
                                                                  layout(binding = 0, rgba32f) uniform image2D alphaBuffer;
                                                                  layout (location = 0) out vec4 fColor;
                                                                  uniform sampler2D texture;
                                                                  uniform sampler2D depthBuffer;
                                                                  uniform float haveTexture;
                                                                  uniform float layer;
                                                                  uniform float nbLayers;
                                                                  uniform vec3 resolution;
                                                                  in vec4 frontColor;
                                                                  in vec2 fTexCoords;
                                                                  in flat uint texIndex;
                                                                  void main() {
                                                                      vec4 texel = (texIndex != 0) ? frontColor * texture2D(textures[texIndex-1], fTexCoords.xy) : frontColor;
                                                                      float current_alpha = texel.a;
                                                                      vec2 position = (gl_FragCoord.xy / resolution.xy);
                                                                      vec4 depth = texture2D (depthBuffer, position);
                                                                      vec4 alpha = imageLoad(alphaBuffer,ivec2(gl_FragCoord.xy));
                                                                      float l = layer / nbLayers;
                                                                      float z = gl_FragCoord.z;
                                                                      if ((l > depth.y || l == depth.y && z > depth.z) && current_alpha > alpha.a) {
                                                                          fColor = vec4(0, l, z, current_alpha);
                                                                          imageStore(alphaBuffer,ivec2(gl_FragCoord.xy),vec4(0, l, z, current_alpha));
                                                                      } else {
                                                                          fColor = alpha;
                                                                      }
                                                                  }
                                                                  )";

This is really strange because I use the same UBO for the two shaders and the same code to bind to UBOs to all my shaders :

std::vector<Texture*> allTextures = Texture::getAllTextures();
        Samplers allSamplers{};
        std::vector<math::Matrix4f> textureMatrices;
        for (unsigned int i = 0; i < allTextures.size(); i++) {
            textureMatrices.push_back(allTextures[i]->getTextureMatrix());
            GLuint64 handle_texture = glGetTextureHandleARB(allTextures[i]->getNativeHandle());
            glCheck(glMakeTextureHandleResidentARB(handle_texture));
            allSamplers.tex[i].handle = handle_texture;
            //std::cout<<"add texture i : "<<i<<" id : "<<allTextures[i]->getNativeHandle()<<std::endl;
        }
        sBuildDepthBuffer.setParameter("textureMatrix", textureMatrices);
        sBuildDepthBufferNormal.setParameter("textureMatrix", textureMatrices);
        sBuildAlphaBuffer.setParameter("textureMatrix", textureMatrices);
        sBuildAlphaBufferNormal.setParameter("textureMatrix", textureMatrices);
        sLinkedList.setParameter("textureMatrix", textureMatrices);
        sLinkedListNormal.setParameter("textureMatrix", textureMatrices);
        glCheck(glGenBuffers(1, &ubo));
        unsigned int ubid;
        glCheck(ubid = glGetUniformBlockIndex(sLinkedList.getHandle(), "ALL_TEXTURES"));
        glCheck(glUniformBlockBinding(sLinkedList.getHandle(),    ubid, 0));
        glCheck(ubid = glGetUniformBlockIndex(sLinkedListNormal.getHandle(), "ALL_TEXTURES"));
        //std::cout<<"shader handle : "<<sLinkedListNormal.getHandle()<<std::endl;
        glCheck(glUniformBlockBinding(sLinkedListNormal.getHandle(),    ubid, 0));
        glCheck(ubid = glGetUniformBlockIndex(sBuildDepthBuffer.getHandle(), "ALL_TEXTURES"));
        glCheck(glUniformBlockBinding(sBuildDepthBuffer.getHandle(),    ubid, 0));
        glCheck(ubid = glGetUniformBlockIndex(sBuildDepthBufferNormal.getHandle(), "ALL_TEXTURES"));
        glCheck(glUniformBlockBinding(sBuildDepthBufferNormal.getHandle(),    ubid, 0));
        glCheck(ubid = glGetUniformBlockIndex(sBuildAlphaBuffer.getHandle(), "ALL_TEXTURES"));
        glCheck(glUniformBlockBinding(sBuildAlphaBuffer.getHandle(),    ubid, 0));
        //std::cout<<"shader handle : "<<sBuildAlphaBufferNormal.getHandle()<<std::endl;
        glCheck(ubid = glGetUniformBlockIndex(sBuildAlphaBufferNormal.getHandle(), "ALL_TEXTURES"));
        glCheck(glUniformBlockBinding(sBuildAlphaBufferNormal.getHandle(),    ubid, 0));

        //std::cout<<"ubid : "<<ubid<<std::endl;
        backgroundColor = sf::Color::Transparent;
        glCheck(glBindBuffer(GL_UNIFORM_BUFFER, ubo));
        glCheck(glBufferData(GL_UNIFORM_BUFFER, sizeof(Samplers),allSamplers.tex, GL_STATIC_DRAW));
        //std::cout<<"size : "<<sizeof(Samplers)<<" "<<alignof (alignas(16) uint64_t[200])<<std::endl;
        glCheck(glBindBuffer(GL_UNIFORM_BUFFER, 0));
        glCheck(glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo));
        glCheck(glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicBuffer));
        glCheck(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, linkedListBuffer));

        for (unsigned int i = 0; i < Batcher::nbPrimitiveTypes; i++) {
            vbBindlessTex[i].setPrimitiveType(static_cast<sf::PrimitiveType>(i));
        }

I printed values of texIndex and fTexCoords into the textures to see if they are correct and they are correctly affected.
I also passed a color the the colour output of the shader, to see if my draw functions are correct and they are correct.

So I really don’t know what’s wrong, I tested everything, event to calculate size of all uniforms to set them to a multiple of 16 but nothing seems to solve this problem.

So I think it’s a driver issue, everything is ok, excepts the UBO of sampler2D which is empty excepts in my per pixel linked list fragment shader so the UBO is not binbed to all my shaders.

Ok It seems it’s because glBindBufferBase is binding the buffers for every shaders!
But I use different renderer so different buffers, so I need to bind/unbind the buffers because I use a single opengl context by render.
so I do this and it’s ok :

if (frameBuffer.getSettings().versionMajor >= 4 && frameBuffer.getSettings().versionMinor >= 3) {
            glCheck(glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo));
            glCheck(glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicBuffer));
            glCheck(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, linkedListBuffer));
            //std::cout<<"draw nex frame"<<std::endl;
            math::Matrix4f viewMatrix = view.getViewMatrix().getMatrix().transpose();
            math::Matrix4f projMatrix = view.getProjMatrix().getMatrix().transpose();
            perPixelLinkedList.setParameter("projectionMatrix", projMatrix);
            perPixelLinkedList.setParameter("viewMatrix", viewMatrix);
            perPixelLinkedList2.setParameter("projectionMatrix", projMatrix);
            perPixelLinkedList2.setParameter("viewMatrix", viewMatrix);
            for (unsigned int i = 0; i < Batcher::nbPrimitiveTypes; i++) {
                vbBindlessTex[i].clear();
            }
            std::vector<TransformMatrix*> tm;
            for (unsigned int i = 0; i < m_instances.size(); i++) {
                if (m_instances[i].getAllVertices().getVertexCount() > 0) {
                    if (m_instances[i].getVertexArrays()[0]->getEntity()->isWater()) {
                        perPixelLinkedList.setParameter("water", 1.0f);
                    } else {
                        perPixelLinkedList.setParameter("water", 0.0f);
                    }
                    if (core::Application::app != nullptr) {
                        float time = core::Application::getTimeClk().getElapsedTime().asSeconds();
                        perPixelLinkedList.setParameter("time", time);
                    }
                    matrices.clear();
                    tm = m_instances[i].getTransforms();
                    for (unsigned int j = 0; j < tm.size(); j++) {
                        tm[j]->update();
                        std::array<float, 16> matrix = tm[j]->getMatrix().transpose().toGlMatrix();
                        for (unsigned int n = 0; n < 16; n++) {
                            matrices.push_back(matrix[n]);
                        }
                    }
                    glCheck(glBindBuffer(GL_ARRAY_BUFFER, vboWorldMatrices));
                    glCheck(glBufferData(GL_ARRAY_BUFFER, matrices.size() * sizeof(float), &matrices[0], GL_DYNAMIC_DRAW));
                    glCheck(glBindBuffer(GL_ARRAY_BUFFER, 0));
                    if (m_instances[i].getVertexArrays().size() > 0) {
                        Entity* entity = m_instances[i].getVertexArrays()[0]->getEntity();
                        for (unsigned int j = 0; j < m_instances[i].getVertexArrays().size(); j++) {
                            if (entity == m_instances[i].getVertexArrays()[j]->getEntity()) {

                                unsigned int p = m_instances[i].getVertexArrays()[j]->getPrimitiveType();
                                for (unsigned int k = 0; k < m_instances[i].getVertexArrays()[j]->getVertexCount(); k++) {
                                    //std::cout<<"add vertices : "<<" i : "<<i<<" j : "<<"k : "<<k<<" size  : "<<vbBindlessTex[p].getVertexCount()<<std::endl;
                                    vbBindlessTex[p].append((*m_instances[i].getVertexArrays()[j])[k], (m_instances[i].getMaterial().getTexture() != nullptr) ? m_instances[i].getMaterial().getTexture()->getNativeHandle() : 0);
                                }
                            }
                        }
                    }
                    //std::cout<<"texture : "<<m_instances[i].getMaterial().getTexture()<<std::endl;
                    //std::cout<<"entity : "<<m_instances[i].getVertexArrays()[0]->getEntity()->getRootEntity()->getType()<<std::endl;
                    if (m_instances[i].getMaterial().getTexture() != nullptr) {



                        //std::cout<<"texture"<<std::endl;
                        math::Matrix4f texMatrix = m_instances[i].getMaterial().getTexture()->getTextureMatrix();
                        //perPixelLinkedList.setParameter("textureMatrix", texMatrix);
                        perPixelLinkedList.setParameter("haveTexture", 1.f);
                    } else {
                        //std::cout<<"no texture"<<std::endl;
                        perPixelLinkedList.setParameter("haveTexture", 0.f);
                    }
                }
            }
            currentStates.blendMode = sf::BlendNone;
            currentStates.shader = &perPixelLinkedList;
            currentStates.texture = nullptr;
            for (unsigned int p = 0; p < Batcher::nbPrimitiveTypes; p++) {
                if (vbBindlessTex[p].getVertexCount() > 0) {
                    vbBindlessTex[p].update();
                    frameBuffer.drawInstanced(vbBindlessTex[p], vbBindlessTex[p].getPrimitiveType(), 0, vbBindlessTex[p].getVertexCount(), tm.size(), currentStates, vboWorldMatrices);
                    vbBindlessTex[p].clear();
                }
            }
            //std::cout<<"nb instances : "<<m_normals.size()<<std::endl;
            for (unsigned int i = 0; i < m_normals.size(); i++) {

               if (m_normals[i].getAllVertices().getVertexCount() > 0) {
                    //std::cout<<"next frame draw normal"<<std::endl;
                    if (m_normals[i].getMaterial().getTexture() == nullptr) {
                        perPixelLinkedList2.setParameter("haveTexture", 0.f);
                    } else {
                        math::Matrix4f texMatrix = m_normals[i].getMaterial().getTexture()->getTextureMatrix();
                        //perPixelLinkedList2.setParameter("textureMatrix", texMatrix);
                        perPixelLinkedList2.setParameter("haveTexture", 1.f);
                    }
                    if (m_normals[i].getVertexArrays()[0]->getEntity()->isWater()) {
                        perPixelLinkedList2.setParameter("water", 1.0f);
                    } else {
                        perPixelLinkedList2.setParameter("water", 0.0f);
                    }
                    if (core::Application::app != nullptr) {
                        float time = core::Application::getTimeClk().getElapsedTime().asSeconds();
                        perPixelLinkedList2.setParameter("time", time);
                    }
                    unsigned int p = m_normals[i].getAllVertices().getPrimitiveType();
                    for (unsigned int j = 0; j < m_normals[i].getAllVertices().getVertexCount(); j++) {
                        vbBindlessTex[p].append(m_normals[i].getAllVertices()[j],(m_normals[i].getMaterial().getTexture() != nullptr) ? m_normals[i].getMaterial().getTexture()->getNativeHandle() : 0);
                    }

                }
            }
            currentStates.blendMode = sf::BlendNone;
            currentStates.shader = &perPixelLinkedList2;
            currentStates.texture = nullptr;
            for (unsigned int p = 0; p < Batcher::nbPrimitiveTypes; p++) {
                if (vbBindlessTex[p].getVertexCount() > 0) {
                    vbBindlessTex[p].update();
                    frameBuffer.drawVertexBuffer(vbBindlessTex[p], currentStates);
                }
            }

            glCheck(glFinish());
            glCheck(glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT));
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
            vb.clear();
            vb.setPrimitiveType(sf::Quads);
            Vertex v1 (sf::Vector3f(0, 0, quad.getSize().z));
            Vertex v2 (sf::Vector3f(quad.getSize().x,0, quad.getSize().z));
            Vertex v3 (sf::Vector3f(quad.getSize().x, quad.getSize().y, quad.getSize().z));
            Vertex v4 (sf::Vector3f(0, quad.getSize().y, quad.getSize().z));
            vb.append(v1);
            vb.append(v2);
            vb.append(v3);
            vb.append(v4);
            vb.update();
            math::Matrix4f matrix = quad.getTransform().getMatrix().transpose();
            perPixelLinkedListP2.setParameter("worldMat", matrix);
            currentStates.shader = &perPixelLinkedListP2;
            frameBuffer.drawVertexBuffer(vb, currentStates);
            glCheck(glFinish());
            frameBuffer.display();
            glCheck(glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0));
            glCheck(glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, 0));
            glCheck(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0));

But there is a real problem : I’ve random pixel colours wich are flickering on the window!

When I use multiple contexts I don’t have this problem but I have the problem which I mentionned above, empty textures in my FBO so fragments are displaying over others but I hate using multiple opengl context and people clearly adviced me to use only a single opengl context excepts if I use multiple windows or threads.

But it seems I’ve the problem since I use bindless textures, I didn’t have those problems with glBindTexture. (and I used one context per FBO before but now I use one context for all my FBO)

I corrected the opengl errors when I made the same texture resident more than once but that didn’t solve the problem.
And I’ve not other errors, event with opengl debug callback functions.

I tried to use a different binding point too but didn’t worked too.

Ok I solved it!
I used one context by FBO and UBO are not shared between opengl context (that was the initial problem) so I had to create one UBO by context and bind them with gBindBufferBase.

I hate to do that I prefer to use a single context but it solves the pixel flickering problem I had when using only one context and I can’t solve this bug for now because I don’t know why it bugs, usually when I have display bug it’s because I forget to unbind something, but this time I’ve unbind everything so I think it’s a driver issue when I’m using one context and bin/unbind buffers with glBindBufferBase pixels are flickering.

FBOs are not sharable between contexts, but buffer objects are.

Ah :o I had to make this to make it works :

glCheck(glGenBuffers(1, &ubo));
        glCheck(glBindBuffer(GL_UNIFORM_BUFFER, ubo));
        glCheck(glBufferData(GL_UNIFORM_BUFFER, sizeof(Samplers),allSamplers.tex, GL_STATIC_DRAW));
        glCheck(glBindBuffer(GL_UNIFORM_BUFFER, 0));
        glCheck(glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo));
        depthBuffer.setActive();
        glCheck(glGenBuffers(1, &ubo2));
        glCheck(glBindBuffer(GL_UNIFORM_BUFFER, ubo2));
        glCheck(glBufferData(GL_UNIFORM_BUFFER, sizeof(Samplers),allSamplers.tex, GL_STATIC_DRAW));
        glCheck(glBindBuffer(GL_UNIFORM_BUFFER, 0));
        glCheck(glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo2));
        alphaBuffer.setActive();
        glCheck(glGenBuffers(1, &ubo3));
        glCheck(glBindBuffer(GL_UNIFORM_BUFFER, ubo3));
        glCheck(glBufferData(GL_UNIFORM_BUFFER, sizeof(Samplers),allSamplers.tex, GL_STATIC_DRAW));
        glCheck(glBindBuffer(GL_UNIFORM_BUFFER, 0));
        glCheck(glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo3));
        environmentMap.setActive();
        //std::cout<<"size : "<<sizeof(Samplers)<<" "<<alignof (alignas(16) uint64_t[200])<<std::endl;

        /*glCheck(glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo2));
        glCheck(glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo3));*/
        glCheck(glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicBuffer));
        glCheck(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, linkedListBuffer));

Otherwise the textures handles are not binded into all my shaders it’s like if glBindBufferBase only bind the buffer for the current active context.

All state changes are limited to the current context. That’s the point of contexts. Multi-threaded rendering would be impossible if a state change in one thread affected calls issued from other threads.

Ok, I understand now, thanks! I use a single thread but need to use several contexts to make it works, if I do multi-threading one day I’ll use vulkan, that’s what people recommanded to me.