Descriptor pool, Descriptor set, texture?

Hello,

Now that I understand (say almost) how to render a simple triangle, I’d like to render textures. But there is a problem. Scenes could (and generally they do) have several textures. Since Vulkan does not support bindless (and I suppose it is intented because if bindless exists, it is because it was costly to bind something in OpenGL. But in Vulkan not, so there is no need to use bindless), we should think how manage texture in a different way.

In OpenGL it was simple, Vulkan made me think a lot about it.

It comes to me (generally from the internet and spec) several ideas to render a mesh with a lot of textures.
[ol]
[li]Use VkUpdateDescriptorSet
[/li][li]use vkBindDescriptorSets
[/li][li]use texture/sampler Array
[/li][/ol]

The first idea is not a good one, since it is not allowed by Vulkan to update a used descriptorSets. And it should be slow to update all the descriptor several times.
The second idea is still about descriptorSets, but the idea here is to have a lot of descriptorSets (say one by texture)
The third one is not especially portable since it requires “SampledImageArrayDynamicIndexing” or use a tricky technics with push constants

So, according to me, the better idea is to use the second one, and I guess a vkBindDescriptorSet is not a heavy operation (but if I am wrong, tell me ^^).

Now that we have pointed out what the context is, we can go into the problem.

We have to tell Vulkan how much resources the pool need. But for example, if I need 1 000 descriptor sets? Is there a way to resize the pool? Or should we fix a size at the beginning?
When we are reading the doc, it is said : “maxPerStageDescriptorUniformBuffers is the maximum number of uniform buffers that can be accessible to a single shader stage in a pipeline layout”.
I understand that the total number of descriptorSet is “unlimited”. That’s it my idea which was to allocate a lot of descriptor sets was a good idea, and if the pool is running out of memory, we could create another one and use vkCopyDescriptorSet?

Was my reasonning good?
No? why?

Thanks :slight_smile:
Antoine

No; you should almost never have a descriptor set that holds a single texture. You have more per-object data than just one texture.

Resources should be grouped into descriptor sets based on how those resources are used.

Or using an array texture. Which is supported everywhere with at least 64 elements, but may not be able to do everything you need. Also, there’s nothing non-portable about using push constants; that’s a standard technique that you’d better get used to using if you want performance.

You have to get another pool.

But you should try to avoid a design where you have a descriptor set for every individual object. Try to find ways to make a descriptor set work for multiple objects by bundling data together.

[QUOTE=Alfonse Reinheart;41240]Or using an array texture. Which is supported everywhere with at least 64 elements, but may not be able to do everything you need. Also, there’s nothing non-portable about using push constants; that’s a standard technique that you’d better get used to using if you want performance.
[/QUOTE]

Hello and thanks for you answer again :).

I misexplain myself, I only mean that SampledImageArrayDynamicIndexing could be not portable. I know that push constants are portable :).

So, I thought to it during the night, and I come with a better idea that is “closer” to your advices.
Instead to have one descriptor set by “object”, I had the idea to use an array of samplers as you said.
The descriptor set will “manage” some textures, for example, 64 textures, and if we need another texture, we allocate a new descriptor set. We will use push constant to “select” which texture to use are.
Going that way, we avoid to allocate a lot of descriptor set, and we avoid to bind a lot of descriptorSet.

PS : you said “Which is supported everywhere with at least 64 elements, but may not be able to do everything you need.”

Where can I find the minimal number of binding?

Thanks :slight_smile:
Antoine

PS : you said “Which is supported everywhere with at least 64 elements, but may not be able to do everything you need.”

Well, that’s not what I said.

There are arrays of textures. And there are array textures. An array of textures is when you have a texture2D or a sampler2D which is declared as an array in GLSL or SPIR-V. An array texture is a single texture object which conceptually contains multiple images that are logically independent.


layout(set = 0, binding = 0) sampler2D arrayOfTextures[25];
layout(set = 0, binding = 1) sampler2DArray arrayTexture;

In order to select a texture out of an array of textures based on a uniform/push-constant value, the implementation must support SampledImageArrayDynamicIndexing. But that’s not what I was talking about.

You can always access an array texture with a dynamically uniform value. And it doesn’t even have to be dynamically uniform; the index into the array texture can be computed however you like. It’s just part of the texture coordinate:


texture(arrayTexture, vec3(texCoord, arrayIndex));

In addition to the above, there are more differences between array textures and arrays of textures. With an array texture, the array is fixed in memory. You specifiy a certain number of arrayLayers in VkImageCreateInfo. The size of the resulting texture is determined by this, and all memory for the array is allocated contiguously. By contract, with arrays of textures, you can mix-and-match different textures as you please.

Where can I find the minimal number of binding?

The maximum number of layers in an array texture is a standard limit: maxImageArrayLayers, which will be at least 64. The maximum size for an array of textures is merely the maximum number of textures that a particular stage can access: maxPerStageDescriptorSampledImages (at least 16). If you use a sampler* array rather than a texture* array, then you’re limited by the smaller of that and maxPerStageDescriptorSamplers (at least 16).

That being said, if hardware does allow you to use dynamically uniform indices with arrays of textures, then odds are good that your maxPerStageDescriptorSampledImages limit will be in the hundreds at least.

Ahaha, yes it seems I didn’t understant you are referring to array textures ^^.

The main problem with array texture is, like you pointed out, the size should be identical for all textures, and it is not obvious that all objects have exactly the same size.

However, I can proced that way.

I have a array textures.
When I want a new texture (let’s say 512 * 512), I look into all my arrays if there is one that is at the same size (512 * 512 * n).
If there is, I just have to “push” to push the new datas after the old ones, if there is not (or if the other is full).
It may be is less efficient than my approach using sampledImageArrayDynamicIndexing, but it is portable ^^.

Thanks :slight_smile:

You sound like you’re not really sure what your scene data will actually be, or you have no real control over it. The general idea with array textures is that you use them in accord with what your scene is.

For example, if you’re making a StarCraft-style RTS, you’d put each race’s unit textures in a single array texture, telling your artists to work within those limitations. Your buildings for each race would likewise have an array texture. Your background tilesets would have one as well. Then maybe one for doodads and such. And one for particle effects and so forth.

If you’re building a system that has to work with whatever gets thrown at it at any time, where you have no idea what you’re rendering and no control over the process, copying texture data around is almost certainly going to be slower than just changing descriptors. At the very least, it can easily lead to performance hitches. Especially since you absolutely have to synchronize those transfer operations.

The idea is to store all textures at the beginning of the application.

We build all texture arrays before “using” them.
Going that way, we don’t have to make transfer during the “rendering loop” and don’t waste performances :).