My attempt at bindless textures not working....

Started by
5 comments, last by AverageJoeSSU 9 years, 2 months ago

Double EDIT: I have updated my renderer with a prototype to test this feature. and glMakeTextureHandleNonResident seems to not do anything.

I used the following code as a test to see how much memory i have (at the end of my Renderer::Draw() before unbinding the GLContext):


    GLint currentAvailableVideoMemory = -1;
    glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &currentAvailableVideoMemory);
    GLint totalAvailableVideoMemory = -1;
    glGetIntegerv(GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX, &totalAvailableVideoMemory);
    float percent = (float)currentAvailableVideoMemory/(float)totalAvailableVideoMemory * 100.0f;
    fprintf(stdout, "VRAM (%d MB) Usage: %f%% \n", totalAvailableVideoMemory/1024, 100.0f - percent);
    fflush(stdout);

which reports 95.xxx% always...

And in gDebugger i always have the same number of texture objects.

when i add 100 images. i get a couple of frames and then the renderer dies, asummingly because the textures are not actually made NonResident.

Is there something i need to be doing to ensure that non resident calls are executed? Could this be a bug in the nvidia linux driver?

EDIT: stupid shader in/out blocks didnt match... thanks compiler!

Here is the output for my program, i also checked in gDebugger and the texture loads just fine.

Vendor: 4.4.0 NVIDIA 343.36
Supported GLSL version is 4.40 NVIDIA via Cg compiler.
Aspect Ratio: 2.400000
vbo: 1
index buffer: 2
Shader Source: #version 440
layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec2 TexCoords;
uniform mat4 worldMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
out block
{
vec2 Texcoord;
} Out;
void main()
{
mat4 mvp = projectionMatrix * viewMatrix * worldMatrix;
Out.Texcoord = vec2(TexCoords.x, 1.0-TexCoords.y);
gl_Position = mvp * vec4(VertexPosition, 1.0);
}
../shaders/simpleTexture.vert Compilation Successful
Shader Source: #version 440
//#extension GL_NV_gpu_shader5 : require // for 64-bit integer types
#extension GL_ARB_bindless_texture : require
in block
{
vec2 texCoords;
} In;
layout (bindless_sampler) uniform sampler2D textureID;
layout (location = 0) out vec4 FragColor;
void main()
{
FragColor = texture(textureID, In.texCoords);
}
../shaders/simpleTexture.frag Compilation Successful
Linking Shader Program: simpleTexture.vert
Shader Link Successful
GL_ACTIVE_UNIFORMS = 4
0) type:mat4 name:projectionMatrix location:0
1) type:sampler2D name:textureID location:1
2) type:mat4 name:viewMatrix location:2
3) type:mat4 name:worldMatrix location:3
width: 500, height 331:
Done Loading Texture...
SOIL loading error: 'Image loaded'
texture handle pointer: 4294969856
My question is, given those shaders and the fact that glGetTextureHandleARB returns non 0, should it work? (of course given the correct geometry and uvs)

------------------------------

redwoodpixel.com

Advertisement
I didn't use bindless so far, but I read into it.

My first question would be:

-Did you make the texture resident?
-Did you use the correct function to set the uniform (ProgramUniformHandleui64/ProgramUniformHandleui64ARB)?
-What does actually happen when you try to draw?

Okay...

Texture Creation


Texture &tex = (*textures)[desc.filename];
    if (tex.name.compare(desc.filename) == 0) {
        return tex;
    }

    if (desc.width < 1 && desc.height < 1)
    {
        //bad input
    }
    int width, height, channels;
    unsigned char *textureData = SOIL_load_image
            (
                    std::string(TEXTURE_DIRECTORY).append(desc.filename).c_str(),
                    &width, &height, &channels,
                    SOIL_LOAD_AUTO
            );

    fprintf(stdout, "width: %d, height %d: \n" , width, height);
    fprintf(stdout, "Done Loading Texture... \n");
    printf( "SOIL loading error: '%s'\n", SOIL_last_result() );
    fflush(stdout);

    GLuint textureHandle;
    glGenTextures(1, &textureHandle);

    glBindTexture(GL_TEXTURE_2D, textureHandle);

    glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, textureData);

    //set texture parameters
    glTexParameteri(textureHandle, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(textureHandle, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameteri(textureHandle, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(textureHandle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glGenerateMipmap(GL_TEXTURE_2D);

    //get GPU PTR
    GLuint64 textureGPU_ptr = glGetTextureHandleARB(textureHandle);

    fprintf(stdout, "texture pointer: %lu \n", textureGPU_ptr);
    fflush(stdout);


    //Make the handle resident on the GPU before using it.
    //Here we assume that we are creating a texture because we want to display it.
    //If we didnt want to display it right away, we wouldnt make it resident.
    //We can also move textures off the GPU by calling glMakeTextureHandleNonResidentARB
    glMakeTextureHandleResidentARB(textureGPU_ptr);


    tex.TextureID = textureGPU_ptr;
    tex.width = desc.width;
    tex.height = desc.height;

    //if everything checks out, assign the name so it becomes valid in the hashmap.
    tex.name = desc.filename;
    glBindTexture(GL_TEXTURE_2D, 0);
    return tex;

Square mesh data...


    
    struct Vertex {
    float x, y, z;
    float u0, v0;
};

    name = "square";

    vertexBufferSize = 4;
    indexBufferSize = 6;

    meshData = new Vertex[vertexBufferSize];
    for(int i = 0; i < vertexBufferSize; i++)

    meshData[0].x = -0.5f;
    meshData[0].y = -0.5f;
    meshData[0].z = 0.0f;
    meshData[0].u0 = 0.0f;
    meshData[0].v0 = 0.0f;

    meshData[1].x = -0.5f;
    meshData[1].y = 0.5f;
    meshData[1].z = 0.0f;
    meshData[1].u0 = 0.0f;
    meshData[1].v0 = 1.0f;

    meshData[2].x = 0.5f;
    meshData[2].y = 0.5f;
    meshData[2].z = 0.0f;
    meshData[2].u0 = 0.0f;
    meshData[2].v0 = 1.0f;

    meshData[3].x = 0.5;
    meshData[3].y = -0.5;
    meshData[3].z = 0.0;
    meshData[3].u0 = 1.0;
    meshData[3].v0 = 0.0;

    indexData = new unsigned short[indexBufferSize];
    indexData[0] = 0;
    indexData[1] = 1;
    indexData[2] = 2;
    indexData[3] = 0;
    indexData[4] = 2;
    indexData[5] = 3;


}

the setUniformTextureHandle64NV call above actually calls glUniformHandle64ARB


void Shader::setUniformTextureHandle64NV(GLuint location, GLuint64 value) {
//Runtime function
glProgramUniformHandleui64ARB(this->ShaderProgram, location, value);
}

and the shaders again:


#version 440

layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec2 TexCoords;

uniform mat4 worldMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;

out block
{
    vec2 Texcoord;
} Out;

void main()
{
    mat4 mvp = projectionMatrix * viewMatrix * worldMatrix;
    Out.Texcoord = vec2(TexCoords.x, 1.0-TexCoords.y);
    gl_Position = mvp * vec4(VertexPosition, 1.0);
}


#version 440
//#extension GL_NV_gpu_shader5 : require    // for 64-bit integer types
#extension GL_ARB_bindless_texture : require

in block
{
    vec2 texCoords;
} In;

layout (bindless_sampler) uniform sampler2D textureID;

layout (location = 0) out vec4 FragColor;

void main()
{
    FragColor = texture(textureID, In.texCoords);
}

Here are images:

[attachment=25574:bindlessNotWorking.png]

[attachment=25575:textureAndStack.png]

------------------------------

redwoodpixel.com

I actually tried just doing regular binding and i get the same result.

Do i NEED to bind a "sampler"?

maybe its my VAO... it's pretty straightforward


vertexBufferSize = desc.vertexBufferSize;
    indexBufferSize = desc.indexBufferSize;

    glGenVertexArrays(1, &vaoID);
    glBindVertexArray(vaoID);

    glGenBuffers(1, &vboID);
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*vertexBufferSize, &desc.meshData[0].x, GL_STATIC_DRAW);

    glGenBuffers(1, &indexID);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short)*indexBufferSize, desc.indexData, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(12));     

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexID);

    fprintf(stdout, "vbo: %d\n", vboID);
    fprintf(stdout, "index buffer: %d\n", indexID);
    fflush(stdout);

    glBindVertexArray(0); // Disable our Vertex Array Object
}

------------------------------

redwoodpixel.com

I wanted to keep my issues with bindless in the same thread, as to keep things somewhat tied together.

See latest edit at the top for details.

I could post more detailed code if needed, But it seems like a simple thing.

What are the requirements for making a resident texture non resident? By definition, what does making a texture non resident actually do?

A comment in the spec says that if the texture isnt going to be used "for a while" it can be made non resident, maybe the GPU won't specifically release the memory if it has plenty? Perhaps the crashing i am seeing is when it actually starts releasing and adding textures from VRAM.

------------------------------

redwoodpixel.com

So I think it actually is working.... what throws me off is that vram seems to stabilize... so the driver must keep residency memory reserved using a data structure of some sort (makes sense).

i can handle 80 high rez images w/ mipmaps (basically camera animates over them (by 2s).

------------------------------

redwoodpixel.com

Phew, I grossly misunderstood bindless texturing. Residency is only for the texture handles. Sparse Texture support is for residency of texture memory. Luckily the two work together quite well, so if I add sparse texture immutable storage I can leverage the same querys of determining bindless residency to deal with sparse residency.

------------------------------

redwoodpixel.com

This topic is closed to new replies.

Advertisement