Array of sampler2D texture bindless problem

Hi!
I use a sampler2D array in an UBO in my fragment shader but, there is a problem.
Only the first sampler2D is drawn correctly.

Here is the fragment shader :

#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;
uniform float water;
in vec4 frontColor;
in vec2 fTexCoords;
in flat uint texIndex;
layout (location = 0) out vec4 fcolor;
void main() {
     uint nodeIdx = atomicCounterIncrement(nextNodeCounter);
     vec4 color = (haveTexture > 0) ? frontColor * texture2D(textures[texIndex-1], fTexCoords.xy) : frontColor;
     if (nodeIdx < maxNodes) {
          uint prevHead = imageAtomicExchange(headPointers, ivec2(gl_FragCoord.xy), nodeIdx);
          nodes[nodeIdx].color = color;
          nodes[nodeIdx].depth = gl_FragCoord.z;
          nodes[nodeIdx].next = prevHead;
     }
     fcolor = vec4(0, 0, 0, 0);
}

And here is the c++ code where I create my UBO :

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().transpose());
    GLuint64 handle_texture = glGetTextureHandleARB(allTextures[i]->getNativeHandle());
    glCheck(glMakeTextureHandleResidentARB(handle_texture));
    allSamplers.tex[i] = handle_texture;
    //std::cout<<"add texture : "<<allSamplers.tex[i]<<std::endl;
}
perPixelLinkedList.setParameter("textureMatrix", textureMatrices);
glCheck(glGenBuffers(1, &ubo));
unsigned int ubid;
glCheck(ubid = glGetUniformBlockIndex(perPixelLinkedList2.getHandle(), "ALL_TEXTURES"));
glCheck(glUniformBlockBinding(perPixelLinkedList2.getHandle(),    ubid, 0));
glCheck(ubid = glGetUniformBlockIndex(perPixelLinkedList.getHandle(), "ALL_TEXTURES"));
glCheck(glUniformBlockBinding(perPixelLinkedList.getHandle(),    ubid, 0));
backgroundColor = sf::Color::Transparent;
glCheck(glBindBuffer(GL_UNIFORM_BUFFER, ubo));
glCheck(glBufferData(GL_UNIFORM_BUFFER, sizeof(allSamplers),allSamplers.tex, GL_STATIC_DRAW));
glCheck(glBindBuffer(GL_UNIFORM_BUFFER, 0));
glCheck(glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo));
backgroundColor = sf::Color::Transparent;
glCheck(glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicBuffer));
glCheck(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, linkedListBuffer));

What’s wrong ?

Thanks!

Before posting next time, you might clean up your code a little so it’s more readable (e.g. delete excessive leading spaces, or at least make the indent consistent). I’ve done some of that for you.

Still, you can benefit from:

This’ll get rid of all those glCheck( ... ) wrappers, which further hinder readability.

Now to your problem. You might want to consider

In particular:

Also, are you sure that sizeof( allSamplers ) is what you think it is? It’s not completely clear from the code you posted (we’re missing type decls).

Before posting next time, you might clean up your code a little so it’s more readable (e.g. delete excessive leading spaces, or at least make the indent consistent). I’ve done some of that for you.

Ok.

Still, you can benefit from:

That’s what I’ve done with a more complicated code I’ve found (the code presented on the link you gave me doesn’t compile) but no error messages are returned with this code :

    namespace odfaeg {
        namespace graphic {
            namespace gl_api
            {
                 /** Récupère une fonction dans la dll OpenGL actuellement chargée
                @param p_strName
                    Le nom de la fonction
                @param p_func
                    Reçoit la fonction
                @return
                    true si la fonction a été trouvée, false sinon
                */
                template< typename Func >
                bool GetFunction( std::string const & p_strName, Func & p_func )
                {
                    #if defined( _WIN32 )
                        p_func = reinterpret_cast< Func >( wglGetProcAddress( p_strName.c_str() ) );
                    #elif defined( __linux__ )
                        p_func = reinterpret_cast< Func >( glXGetProcAddress( (GLubyte const 
                        *)p_strName.c_str() ) );
                    #endif
                    return p_func != NULL;
                }

                #define MAKE_GL_EXTENSION( x )	static const std::string x = "GL_"#x;

                MAKE_GL_EXTENSION( ARB_debug_output )
                MAKE_GL_EXTENSION( AMDX_debug_output )

                //! Dit que l'on veut les informations de debug en synchrone
                static const int iGL_DEBUG_OUTPUT_SYNCHRONOUS = 0x8242;
                static const int iGL_DEBUG_OUTPUT = 0x92E0;
                /** Les types d'informations
                */
                typedef enum eGL_DEBUG_TYPE : uint32_t
                {	eGL_DEBUG_TYPE_ERROR				= 0x824C
                ,	eGL_DEBUG_TYPE_DEPRECATED_BEHAVIOR	= 0x824D
                ,	eGL_DEBUG_TYPE_UNDEFINED_BEHAVIOR	= 0x824E
                ,	eGL_DEBUG_TYPE_PORTABILITY			= 0x824F
                ,	eGL_DEBUG_TYPE_PERFORMANCE			= 0x8250
                ,	eGL_DEBUG_TYPE_OTHER				= 0x8251
                }	eGL_DEBUG_TYPE;

                /** Les sources des informations
                */
                typedef enum eGL_DEBUG_SOURCE : uint32_t
                {	eGL_DEBUG_SOURCE_API                = 0x8246
                ,	eGL_DEBUG_SOURCE_WINDOW_SYSTEM      = 0x8247
                ,	eGL_DEBUG_SOURCE_SHADER_COMPILER    = 0x8248
                ,	eGL_DEBUG_SOURCE_THIRD_PARTY        = 0x8249
                ,	eGL_DEBUG_SOURCE_APPLICATION        = 0x824A
                ,	eGL_DEBUG_SOURCE_OTHER				= 0x824B
                }	eGL_DEBUG_SOURCE;

                /** Les catégories d'informations
                */
                typedef enum eGL_DEBUG_CATEGORY : uint32_t
                {	eGL_DEBUG_CATEGORY_API_ERROR			= 0x9149
                ,	eGL_DEBUG_CATEGORY_WINDOW_SYSTEM		= 0x914A
                ,	eGL_DEBUG_CATEGORY_DEPRECATION			= 0x914B
                ,	eGL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR	= 0x914C
                ,	eGL_DEBUG_CATEGORY_PERFORMANCE			= 0x914D
                ,	eGL_DEBUG_CATEGORY_SHADER_COMPILER		= 0x914E
                ,	eGL_DEBUG_CATEGORY_APPLICATION			= 0x914F
                ,	eGL_DEBUG_CATEGORY_OTHER				= 0x9150
                }	eGL_DEBUG_CATEGORY;

                /** Les importances des informations
                */
                typedef enum eGL_DEBUG_SEVERITY : uint32_t
                {	eGL_DEBUG_SEVERITY_HIGH		= 0x9146
                ,	eGL_DEBUG_SEVERITY_MEDIUM	= 0x9147
                ,	eGL_DEBUG_SEVERITY_LOW		= 0x9148
                }	eGL_DEBUG_SEVERITY;
            }

            //*************************************************************************************************

            typedef void (CALLBACK * PFNGLDEBUGPROC)( uint32_t source, uint32_t type, uint32_t id, 
            uint32_t severity, int length, const char * message, void * userParam );
            typedef void (CALLBACK * PFNGLDEBUGAMDPROC)( uint32_t id, uint32_t category, uint32_t 
            severity, int length, const char* message, void* userParam );
            typedef void (CALLBACK * PFNGLDEBUGMESSAGECALLBACK)( PFNGLDEBUGPROC 
            callback, void * userParam );
            typedef void (CALLBACK * PFNGLDEBUGMESSAGECALLBACKAMD)( 
            PFNGLDEBUGAMDPROC callback, void * userParam );


           PFNGLDEBUGMESSAGECALLBACK glDebugMessageCallback = NULL;
           PFNGLDEBUGMESSAGECALLBACKAMD glDebugMessageCallbackAMD = NULL;

        void OpenGL::LoadDebugFunctions()
        {
            std::string l_strExtensions = (char const *)glGetString( GL_EXTENSIONS );

            if( l_strExtensions.find( gl_api::ARB_debug_output ) != std::string::npos )
            {
                if( !gl_api::GetFunction( "glDebugMessageCallback", glDebugMessageCallback ) )
                {
                    if( !gl_api::GetFunction( "glDebugMessageCallbackARB", glDebugMessageCallback ) )
                    {
                        std::cout << "Unable to retrieve function glDebugMessageCallback" << std::endl;
                    }
                }
            }
            else if( l_strExtensions.find( gl_api::AMDX_debug_output ) != std::string::npos )
            {
                if( !gl_api::GetFunction( "glDebugMessageCallbackAMD", glDebugMessageCallbackAMD ) )
                {
                    std::cout << "Unable to retrieve function glDebugMessageCallbackAMD" << std::endl;
                }
            }
        }

        void OpenGL::InitialiseDebugFunctions()
        {
            if( glDebugMessageCallback )
            {
                //std::cout<<"init debug functions"<<std::endl;
                glDebugMessageCallback( PFNGLDEBUGPROC( &CallbackDebugLog ), NULL );
                glEnable( gl_api::iGL_DEBUG_OUTPUT_SYNCHRONOUS );
            }
            else if( glDebugMessageCallbackAMD )
            {
                //std::cout<<"init debug functions AMD"<<std::endl;
                 glDebugMessageCallbackAMD( PFNGLDEBUGAMDPROC( &CallbackDebugLogAMD ), NULL );
                 glEnable(gl_api::iGL_DEBUG_OUTPUT);
                 glEnable(gl_api::iGL_DEBUG_OUTPUT_SYNCHRONOUS);

            }
        }

        void OpenGL::CallbackDebugLog( uint32_t source, uint32_t type, uint32_t id, uint32_t severity, int length, const char * message, void * userParam  )
        {
            std::cout << "OpenGL Debug - ";

            switch( source )
            {
            case gl_api::eGL_DEBUG_SOURCE_API:				std::cout << "Source:OpenGL\t";			    break;
            case gl_api::eGL_DEBUG_SOURCE_WINDOW_SYSTEM:	std::cout << "Source:Windows\t";			break;
            case gl_api::eGL_DEBUG_SOURCE_SHADER_COMPILER:	std::cout << "Source:Shader compiler\t";	break;
            case gl_api::eGL_DEBUG_SOURCE_THIRD_PARTY:		std::cout << "Source:Third party\t";		break;
            case gl_api::eGL_DEBUG_SOURCE_APPLICATION:		std::cout << "Source:Application\t";		break;
            case gl_api::eGL_DEBUG_SOURCE_OTHER:			std::cout << "Source:Other\t";				break;
            }

            switch( type )
            {
            case gl_api::eGL_DEBUG_TYPE_ERROR:					std::cout << "Type:Error\t";				break;
            case gl_api::eGL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:	std::cout << "Type:Deprecated behavior\t";	break;
            case gl_api::eGL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:		std::cout << "Type:Undefined behavior\t";	break;
            case gl_api::eGL_DEBUG_TYPE_PORTABILITY:			std::cout << "Type:Portability\t";			break;
            case gl_api::eGL_DEBUG_TYPE_PERFORMANCE:			std::cout << "Type:Performance\t";			break;
            case gl_api::eGL_DEBUG_TYPE_OTHER:					std::cout << "Type:Other\t";				break;
            }

            std::cout << "ID:" << id << "\t";

            switch( severity )
            {
            case gl_api::eGL_DEBUG_SEVERITY_HIGH:	std::cout << "Severity:High\t";	    break;
            case gl_api::eGL_DEBUG_SEVERITY_MEDIUM:	std::cout << "Severity:Medium\t";	break;
            case gl_api::eGL_DEBUG_SEVERITY_LOW:	std::cout << "Severity:Low\t";  	break;
            }

            std::cout << "Message:" << message << std::endl;
        }

        void OpenGL::CallbackDebugLogAMD( uint32_t id, uint32_t category, uint32_t severity, int length, const char* message, void* userParam )
        {
            std::cout << "OpenGL Debug - ";

            switch( category )
            {
            case gl_api::eGL_DEBUG_CATEGORY_API_ERROR:			std::cout << "Category:OpenGL\t";				break;
            case gl_api::eGL_DEBUG_CATEGORY_WINDOW_SYSTEM:		std::cout << "Category:Windows\t";				break;
            case gl_api::eGL_DEBUG_CATEGORY_DEPRECATION:		std::cout << "Category:Deprecated behavior\t";	break;
            case gl_api::eGL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR:	std::cout << "Category:Undefined behavior\t";	break;
            case gl_api::eGL_DEBUG_CATEGORY_PERFORMANCE:		std::cout << "Category:Performance\t";			break;
            case gl_api::eGL_DEBUG_CATEGORY_SHADER_COMPILER:	std::cout << "Category:Shader compiler\t";		break;
            case gl_api::eGL_DEBUG_CATEGORY_APPLICATION:		std::cout << "Category:Application\t";			break;
            case gl_api::eGL_DEBUG_CATEGORY_OTHER:				std::cout << "Category:Other\t";				break;
            }

            std::cout << "ID:" << id << "\t";

            switch( severity )
            {
            case gl_api::eGL_DEBUG_SEVERITY_HIGH:	std::cout << "Severity:High\t";	break;
            case gl_api::eGL_DEBUG_SEVERITY_MEDIUM:	std::cout << "Severity:Medium\t";	break;
            case gl_api::eGL_DEBUG_SEVERITY_LOW:	std::cout << "Severity:Low\t"; 	break;
            }

            std::cout << "Message:" << message << std::endl;
        }
    } 
}

GLuint64 is 64 bits so 8 bytes how can I tell to c++ to align my GLuint64 to 16 bytes ? (I thinks that’s the problem)
Here is the c++ struct.

struct Samplers {
      GLuint64 tex[200];
};

Also, are you sure that sizeof( allSamplers ) is what you think it is? It’s not completely clear from the code you posted (we’re missing type decls).

The value of sizeof(allSamplers) is 1600 bytes which is correct (8*200)

EDIT : I tried this but that doesn’t work :

    struct Samplers {           
           alignas(16) GLuint64 tex[200];
    };

the structure size is not changed. (1600 instead of 16*200=3200)

i`ve asked the same question here some time ago and solved it like that:

Fragmentshader example:

#version 450 core

#extension GL_ARB_bindless_texture : enable

layout (bindless_sampler) uniform;

in vec2 texcoord;

layout (std140, binding = 1) uniform TextureBlock {
    uvec4 maps[1024];
};

layout (location = 0) out vec4 out_color;

/* fix: because of layout std140 16byte alignment, get uvec2 from array of uvec4 */
uvec2 GetTexture(uint index)
{
    uint index_corrected = index / 2;
    if (index % 2 == 0)
        return maps[index_corrected].xy;
    return maps[index_corrected].zw;
}

void main ()
{
    /* create samplers from uvec2 */
    sampler2D tex1 = sampler2D(GetTexture(0));
    sampler2D tex2 = sampler2D(GetTexture(1));

    vec4 color1 = texture(tex1, texcoord);
    vec4 color2 = texture(tex2, texcoord);

    out_color = (color1 + color2) / 2;
}

Ok now it’s working!!!

Sloved, thanks!!!