Bindless Textures + Instancing

I would like to render instanced geometry with a per-instance texture. To do so, I want to create a Vertex Attrib (that is consumed in a per-instance basis) containing the texture handler and create the sampler2D in the shader using the bindless_texture NVIDIA extension. I want to do so because the number of instances is dynamic and they are created an destroyed during runtime so I cannot allocate an statically allocated array of textureHandles as in the example in the extension specification.

//Create the textures and obtain the handles
foreach instance
	glGenTextures(1, &this->gpuTextureId);
	glBindTexture(GL_TEXTURE_2D, this->gpuTextureId);

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ResX, ResY, 0, GL_RGBA, GL_UNSIGNED_BYTE, info); 
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);	// Linear Filtering
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);	// Linear Filtering

	// Get a handle for the texture.
	this->gpuTextureHandlerId = glGetTextureHandleNV(this->gpuTextureId);

	// Make the handle resident before using it.
//Pass the handle to the buffer

	glGenBuffers(1, &this->instanceTextureHandlerVboId);

	glVertexAttribPointer(INSTANCE_TEXTURE_LOCATION, 1, GL_UNSIGNED_INT64_NV, GL_FALSE, sizeof(GLuint64), 0); 
	glVertexAttribDivisor(INSTANCE_TEXTURE_LOCATION, 1);

	glBufferData(GL_ARRAY_BUFFER, sizeof(GLuint64) * this->numElements, instanceTextureHandle, GL_DYNAMIC_DRAW); //instanceTextureHandle contains the texture handles for all the instances.

As for the shader:

#version 430
#extension GL_NV_bindless_texture : require
#extension GL_NV_gpu_shader5 : require 

in vec2 ex_textCoord;
layout(location = 6) in  uint64_t in_textHandler;

out vec4 out_Color;

void main(void)
	sampler2D s = sampler2D(in_textHandler);
	out_Color = texture(s, ex_textCoord);

The problem is that I cannot send the 64-bit pointer to the shader. If it was a Uniform I could use “glUniformHandleui64NV(location, instanceTextureHandle[i]);” I use GL_UNSIGNED_INT64_NV or GL_DOUBLE in the glVertexAttribPointer without success.

Can it be done?

Thanks in advance.


Since you want the vertex attribute to be an integer in the shader you’ll want glVertexAttribIPointer (notice the “I”). On a quick glance the bindless texture extension does not add 64bit integer vertex attributes (may have missed it), but you could split the value into two 32bit values and pass them as a 2 element unsigned int vector.

I use GL_UNSIGNED_INT64_NV or GL_DOUBLE in the glVertexAttribPointer without success.

Of course they don’t work. glVertexAttribPointer can only feed floating-point attributes. Thus, whatever type you pass will be converted into a 32-bit float. All integers will be assumed to be either signed or unsigned normalized values. Doubles will be (likely at great performance cost) converted into 32-bit floats before the shader reads them.

This is why glVertexAttrib[b]I[/b]Pointer and glVertexAttrib[b]L[/b]Pointer exist. The first feeds integer attributes and the second feeds double-precision attributes.

Unfortunately, NVIDIA decided to be terribly inconsistent with how 64-bit integer attributes are treated. They’re integer attributes, so they should have used IPointer. But because they’re 64-bits in size, they decided to use LPointer. So you have to use that one with GL_UNSIGNED_INT64_NV.

Lots of thanks, it worked!

Just one note:
Since we send our data to the fragment shader through the vertex shader, we also need to add the “flat” qualifier to the output variable of the vertex shader and also to the corresponding input variable of the fragment.
Don’t know why but it’s explained in the extension specification:

In the following example, the sampler to use is selected in a vertex
shader, passed to the fragment shader as a (flat) input, and then used for
a texture lookup.

Without this qualifier it does not work.

The value is an integer. And interpolation isn’t allowed for integers.