Search code examples
openglglsltextures

Bindless array texture not working


I store an object's material in a array texture 2D comprised of the diffuse, bump, specular, etc. The handle to this texture array is then stored per vertex, along side the vertex, uv, normal arrays in a VAO, instead of using UBO's or SSBO's to achieve the same purpose.

My goal is to compress an entire model into a single vertex array object, since a model may have many meshes and each mesh may have its own texture. This way with the texture handle stored per vertex, I could just render the entire model in 1 draw call.

The problem is that all object's render black, suggesting to me that the sampler isn't working or somehow the handle isn't getting transferred all the way through. The shader program compiles successfully, and the geometry is rendering correctly (that is, I can substitute the final diffuse color with a fixed color and see the scene).


Texture Creation:

void TextureManager::FinishWorkOrders()
{
    for ( ... ) {
        Material_WorkOrder *material = Mat_Work_Orders[x];   
        glGenTextures(1, material->gl_array_ID);
        glBindTexture(GL_TEXTURE_2D_ARRAY, *material->gl_array_ID);
        glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, material->size.x, material->size.y, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, material->textureData);
        glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_GENERATE_MIPMAP, GL_TRUE);
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);

        // Material handle is of type GLuint64
        *material->handle = glGetTextureHandleARB(*material->gl_array_ID);
        glMakeTextureHandleResidentARB(*material->handle);
    }
}

VAO generation:

GLuint ModelManager::genVAO(const vector<vec3> &vs, const vector<vec2> &uv, const vector<vec3> &nm, const vector<vec3> &tg, const vector<vec3> &bt, const vector<GLuint64*> &ts)
{
    AttribBuffers b;
    GLuint vao = 0;
    size_t arraySize = vs.size();
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);
    glGenBuffers(MAX_BUFFERS, b.buffers);

    // Vertex array
    glBindBuffer(GL_ARRAY_BUFFER, b.buffers[0]);
    glBufferData(GL_ARRAY_BUFFER, arraySize * sizeof(vec3), &vs[0][0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    ...

    // Texture Handle array
    glBindBuffer(GL_ARRAY_BUFFER, b.buffers[5]);
    glBufferData(GL_ARRAY_BUFFER, arraySize * sizeof(GLuint64), &ts[0], GL_STATIC_DRAW);
    glEnableVertexAttribArray(5);
    glVertexAttribLPointer(5, 1, GL_UNSIGNED_INT64_ARB, 0, 0);

    glBindVertexArray(0);
    return vao;
}

Shader Usage:

Vertex:

#version 450
#extension GL_ARB_bindless_texture : require
#extension GL_ARB_gpu_shader5 : require 
#extension GL_ARB_gpu_shader_int64 : require

layout (location = 0) in vec3 vertex;

...

layout (location = 5) in uint64_t texHandle;

flat out uint64_t TextureHandle;

void main(void)
{
    TextureHandle           = texHandle;

    ...

    gl_Position             = worldMVP * v;         
}

Fragment:

#version 450
#extension GL_ARB_bindless_texture : require
#extension GL_ARB_gpu_shader5 : require 
#extension GL_ARB_gpu_shader_int64 : require

flat in uint64_t TextureHandle;

layout (location = 0) out vec4 DiffuseOut; 

void main()                                 
{                           
    sampler2DArray MaterialMap = sampler2DArray(TextureHandle);

    ... 

    DiffuseOut = texture(MaterialMap, vec3(TexCoord0, 0));
}

Solution

  • The issue is that glBufferData can't accept a vector of pointers.

    I set up my data this way so that the last vertex attribute array was an array of Gluint64* handles for 2 reasons: 1) so that the appropriate texture per triangle would just stream from the vertex shader to the fragment shader, 2) so that I could create the array ahead of time and wait for the texture to be created and update the array automatically by just updating the underlying pointers separately

    This can work, but the vector needs to be changed from type GLuint* to GLuint (drop the pointer).