Bindless Textures?

Does Vulkan support something like OpenGL 4.3 bindless textures? I have a shader that needs to be able to access many different textures. If not, then what is the minimum guaranteed number of textures slots?

So, searching the forum for Vulkan and Bindless lead to this question from 2+ years ago. That being said, it’s worth revisiting to clarify matters.

Vulkan doesn’t need bindless textures in the same way that OpenGL does. That doesn’t make the idea of bindless worthless in Vulkan. It’s just that in OpenGL, one of the main reasons to use it is to avoid the cost of changing texture bindings, which is a fundamentally costly operation.

Modifying descriptor sets is a costly operation in Vulkan, but not nearly so much as changing bindings in OpenGL. The main issue in Vulkan is that you have to do the synchronization yourself, unless you have otherwise ensured that the descriptor set you are modifying is not being used by a rendering command that has not completed execution. Generally speaking, you would be swapping descriptor sets in the middle of a scene, not modifying them.

While that might be cheaper than OpenGL texture binding, it’s not as cheap as possible. It still represents a state change, so it costs something. And probably more of a “something” than a push constant change.

You can still get most of the effects of “bindless” textures by using a sampler array. And I don’t mean an array texture; I mean a sampler2D[Count] array. In OpenGL, such an array would consume Count individual texture units. But in Vulkan, that entire array is a single descriptor location; it is an arrayed descriptor.

In Vulkan, the limits on number of sampled images, storage images, and samplers per stage and total are governed by several individual limitations. On modern desktop hardware, you’ll find that the limits on sampled images and storage images are… large. Intel supports between 768 and 1200 sampled images, with NVIDIA and AMD supporting thousands, if not MAX_UINT.

The point being that the number of such images isn’t a particular problem (the “minimum guaranteed” is low, but real implementation limits are not). But there is one potential problem.

If the implementation does not offer the feature shaderSampledImageArrayDynamicIndexing (or you don’t turn it on), then you cannot sample from an array of sampled images/textures with an index which is not a compile-time constant. And not every implementation offers that feature, though all desktop implementations do.

Now, I could point out that doing this limits you to only using dynamically uniform indices. But that limitation also exists for ARB_bindless_texture; it’s only NVIDIA’s NV_gpu_shader5 that removes that limitation.

With all of that in hand, you can effectively build the equivalent of bindless texturing. Making an image resident and getting its “handle” is equivalent to just putting the texture in the descriptor array. Converting the “handle” into a texture means fetching the texture from the sampler array. The mapping is pretty close to 1:1.

VK_EXT_descriptor_indexing provides features that make descriptor arrays like this even more flexible with regard to implementing “bindless” of this form.

NVIDIA is currently exploring VK_NVX_image_view_handle, which is the API side of bindless texturing. But there is no SPIR-V extension to consume this handle, so the extension by itself isn’t worth much.

1 Like

Like I said, I actually need a shader to be able to access a large number of textures. This is not about switching textures for different draw calls.

I’m assuming a 2D array texture is possible? (Basically just a volume texture.) It looks like that is the only safe option.

And what’s wrong with the method I outlined? How “large number” are we talking about?

That depends on how you define “safe”. Yes, implementations have to provide array textures, but the minimum number of array layers required is only 256. So you’re still going to have to query the limit and adjust your code accordingly.

2D texture arrays are possible ( but limited as Alfonse wrote )
Arrays of image descriptors ( also known as arrays of textures ) are also possible - these would be good for you, because you may use textures with different sizes and formats.

…but the real equivalent of bindless textures is extension named VK_EXT_descriptor_indexing.
Vulkan specification guarantees that you may put even 500.000 textures in it.
And the extension is already implemented by NVidia, AMD and Intel as far as I am aware.

Related thread:

At first pass, I don’t really understand what you are saying, but I will look into in more detail when I get to the implementation of this.

The need to access 1000 different textures within a single pass is not out of the question.

At this time I am interested in all PC (including Mac) hardware. When you say “desktop” are you implying that mobile (laptop) GPUs may not support the required functionality?

When I refer to “mobile GPUs”, I basically mean things running iOS or Android. Things running those OSs will typically use mobile-class hardware. Essentially, anything that only runs OpenGL ES (NVIDIA’s mobile GPUs being the only exception).

Things running desktop operating systems will typically use desktop-class hardware.

Thanks. I think the smart thing to do is implement the fast path (“bindless” textures), the not-so-fast path (texture switching), and skip array textures.

It work good. Me happy.

Typically, you need to sample the images in one pipeline stage, so instead of maxDescriptorSetSampledImages and maxDescriptorSetStorageImages, the relevant limits would be maxPerStageDescriptorSampledImages and maxPerStageDescriptorStorageImages, would they not?
Those limits are significantly lower.