Bindless textures in OpenGL

I am investigating OpenGL support for bindless textures. I understand that SPIR-V does not support the GL_ARB_bindless_texture extension, to turn a uvec2 into a sampler.

In Vulkan I achieved this with a storage buffer full of sampler objects. Does this work in OpenGL?:

layout(binding = 3) uniform sampler2D texture2DSampler[256];

This is producing an error in SPIR-V:

ERROR: test.frag:15: 'binding' : sampler binding not less than gl_MaxCombinedTextureImageUnits (using array)

Does the storage-block-of-samplers approach work in OpenGL, and if so is there any disadvantage of using that verses “real” bindless textures? I prefer to keep using SPIR-V if possible.

Also, any ideas why my textures appear black? It’s been a while since I touched OpenGL. The handle created is non-zero:

bool RenderTexture::SetPixels(shared_ptr<Buffer> pixels, const int miplevel, const int face)
{
	for (int n = 0; n < pixels->GetSize(); ++n) pixels->PokeByte(n, 255);
	Assert(pixels->GetSize() == size.x * size.y * 4);

	glCreateTextures(GL_TEXTURE_2D, 1, &id);
	glTextureStorage2D(id, 1, GL_RGBA8, size.x, size.y);
	glTextureSubImage2D(
		id,
		// level, xoffset, yoffset, width, height
		0, 0, 0, size.x, size.y,
		GL_RGBA, GL_UNSIGNED_BYTE,
		pixels->Data());
	//glGenerateTextureMipmap(id);

	glTextureParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTextureParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTextureParameteri(id, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTextureParameteri(id, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTextureParameteri(id, GL_TEXTURE_WRAP_R, GL_REPEAT);

	// Retrieve the texture handle after we finish creating the texture
	handle = glGetTextureHandleARB(id);
	return handle != 0;
}

If I upload my texture as a uniform and use conventional texture lookups, the texture appears correctly. So the problem lies with the bindless texture handle.

The material is storing a texture handle, not a sampler object. I’m not sure if OpenGL has sampler objects?

Ah, I had to make it resident.

No.

OpenGL implementation limitations on the number of textures generally do not allow for arrays of samplers of that size. Vulkan implementations generally do allow for it. This has to do with some inherent differences with the implementation of the resource models between the two.

Some implementations of OpenGL bindless textures are basically doing what you’re doing with that array, just hidden behind the scenes. When you make a texture resident in OpenGL, what the implementation does is add the texture to an array that is invisibly associated with your shaders that use bindless texturing. That array has a maximum size, which is why you need to make sure not to make too many textures resident all at the same time. There’s also a way to map the texture handle to an array index.

But this can’t be done in the OpenGL resourcing model the way you would under Vulkan.

OpenGL has sampler objects as a distinct thing, and you can combine a sampler with a texture to create a new bindless handle for that combination of the two.

What you can’t do is create an image without a “sampler;” all OpenGL textures have sampler data associated with them, even if you never use it.

1 Like