vincent
vincent

Reputation: 1390

OpenGL Bindless Textures: Bind to uniform sampler2D array

I am looking into using bindless textures to rapidly display a series of images. My reference is the OpenGL 4.5 redbook. The book says I can sample bindless textures in a shader with this fragment shader:

#version 450 core
#extension GL_ARB_bindless_texture : require

in FS_INPUTS {
   vec2 i_texcoord;
   flat int i_texindex;
};

layout (binding = 0) uniform ALL_TEXTURES {
   sampler2D fs_textures[200];
};

out vec4 color;

void main(void) {
   color = texture(fs_textures[i_texindex], i_texcoord);
};

I created a vertex shader that looks like this:

#version 450 core

in vec2 vert;
in vec2 texcoord;
uniform int texindex;

out FS_INPUTS {
   vec2 i_texcoord;
   flat int i_texindex;
} tex_data;

void main(void) {
   tex_data.i_texcoord = texcoord;
   tex_data.i_texindex = texindex;
   gl_Position = vec4(vert.x, vert.y, 0.0, 1.0);
};

As you may notice, my grasp of whats going on is a little weak.

In my OpenGL code, I create a bunch of textures, get their handles, and make them resident. The function I am using to get the texture handles is 'glGetTextureHandleARB'. There is another function that could be used instead, 'glGetTextureSamplerHandleARB' where I can pass in a sampler location. Here is what I did:

Texture* textures = new Texture[load_limit];
GLuint64* tex_handles = new GLuint64[load_limit];

for (int i=0; i<load_limit; ++i)
{
    textures[i].bind();
    textures[i].data(new CvImageFile(image_names[i]));
    tex_handles[i] = glGetTextureHandleARB(textures[i].id());
    glMakeTextureHandleResidentARB(tex_handles[i]);
    textures[i].unbind();
}

My question is how do I bind my texture handles to the ALL_TEXTURES uniform attribute of the fragment shader? Also, what should I use to update the vertex attribute 'texindex' - an actual index into my texture handle array or a texture handle?

Upvotes: 4

Views: 8411

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 473174

It's bindless texturing. You do not "bind" such textures to anything.

In bindless texturing, the data value of a sampler is a number. Specifically, the number returned by glGetTextureHandleARB. Texture handles are 64-bit unsigned integer.

In a shader, values of sampler types in buffer-backed interface blocks (UBOs and SSBOs) are 64-bit unsigned integers. So an array of samplers is equivalent in structure to an array of 64-bit unsigned integers.

So in C++, a struct equivalent to your ALL_TEXTURES block would be:

struct AllTextures
{
    GLuint64 textures[200];
};

Well, assuming you properly use std140 layout, of course. Otherwise, you'd have to query the layout of the structure.

At this point, you treat the buffer as no different from any other UBO usage. Build the data for the shader by sticking an AllTextures into a buffer object, then bind that buffer as a UBO to binding 0. You just need to fill the array in with the actual texture handles.

Also, what should I use to update the vertex attribute 'texindex' - an actual index into my texture handle array or a texture handle?

Well, neither one will work. Not the way you've written it.

See, ARB_bindless_texture does not allow you to access any texture you want in any way at any time from any shader invocation. Unless you are using NV_gpu_shader5, the code leading to the texture access must be based on dynamically uniform expressions.

So unless every vertex in your rendering command gets the same index or handle... you cannot use them to pick which texture to use. Even instancing will not save you, since dynamically uniform expressions don't care about instancing.

If you want to render a bunch of quads without having to change uniforms between them (and without having to rely on an NVIDIA extension), then you have a few options. Most hardware that supports bindless texture also supports ARB_shader_draw_parameters. This gives you access to gl_DrawID, which represents the current index of a rendering command within a glMultiDraw-style command. And that extension explicitly declares that gl_DrawID is dynamically uniform.

So you could use that to select which texture to render. You simply need to issue a multi-draw command where you render the same mesh data over and over, but it gets a different gl_DrawID index in each case.

Upvotes: 10

Related Questions