VK_ERROR_OUT_OF_POOL_MEMORY when allocating second descriptor sets

#1

Push Descriptors are broken on many Android’s except for the newest models so I reworked my code to use the descriptor pool / sets way of handling descriptors. On my PC I’m telling Vulkan to use app version 1.1 and everything works well. I allocate the pool and allocate descriptor sets as I need them up to what the pool holds. At this point everything works as expected.

For comparability on older Androids, I set the Vulkan app version to 1.0. On my PC, setting Vulkan to use app version 1.0, now the second time I allocate a descriptor set, I get validation errors about “out of pool memory”. At first I thought I broke something, spent a day stepping through the code, validating all values, can’t see anything wrong, very baffling… but then I remembered that I changed Vulkan to use app version 1.0. Changed it back to 1.1 and everything works as before.

The best I can determine is that under app version 1.0, your first descriptor set allocation will work but any subsequent allocations will fail. It doesn’t matter that you allocated a pool for 100 descriptor sets and the first allocation against the pool is just 1. What also sucks is that regardless of the app version, Android descriptor set allocation always fails on the second attempt.

The only workaround I can think of right now is on the first descriptor set allocation, allocate the whole pool worth of descriptor sets at once and hand them out as needed.

#2

Until the advent of the KHR_maintenance1 extension, attempting to allocate more stuff from your descriptor pool than it can provide was not a diagnosis error. Or at least, not distinct from device/system memory exhaustion. This means that, unless you enable that extension in 1.0, there isn’t really a way to tell if you’ve over-allocated from a descriptor pool.

KHR_maintenance1 was adopted into core Vulkan 1.1, so all 1.1 implementations can report this error. In short, your code is probably buggy, but 1.0 can’t tell you about it.

The number of sets is not the only thing that matters with descriptor pools. The number of descriptors and of which types is part of the pool, and allocating more than those numbers can give rise to this error as well.

Assuming you’re not actually exceeding these limits (and that your code is not otherwise broken), then this means there’s some bug in the implementation that won’t allow you to allocate twice no matter what. It’s just that this bug can only be visible if you allow it to report this error.

#3

On my PC with app version 1.0, I can see the validation errors complaining about exceeding the pool.

Upon further investigation, it looks like under Vulkan app version 1.0, VkDescriptorPoolCreateInfo.maxSets is being ignored. Even though it’s value is 200 (frame buffer size * 100), the pool thinks it only contains 2 descriptor sets. In doing a test where I try to allocate all 100 descriptor sets at once right after the pool was created, validation error says… Unable to allocate 200 descriptors of type… This pool only has 2 descriptors of this type remaining.

VkDescriptorPoolCreateInfo poolInfo = {};
    poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
    poolInfo.poolSizeCount = descriptorPoolVec.size();
    poolInfo.pPoolSizes = descriptorPoolVec.data();
    poolInfo.maxSets = m_framebufferVec.size() * descData.m_descPoolMax;
    poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;

sType:VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO
pNext:0x0
flags:1
maxSets:200
poolSizeCount:2

Is the pool memory allocated via poolInfo.poolSizeCount * poolInfo.maxSets? That’s what it seems like the online documentation states.

#4

The error you got says “Unable to allocate 200 descriptors of type… This pool only has 2 descriptors of this type remaining.” You are confusing “descriptor set” with “descriptor”.

A descriptor set is a set of descriptors, with the arrangement of those descriptors within the set defined by a descriptor set layout. A set would contain, for example, a UBO binding, a couple of texture bindings, maybe an SSBO binding, etc. Each of those things is a descriptor.

A descriptor pool doesn’t just specify the number of sets you can allocate. You also specify how many descriptors you can allocate for those sets and of which type those descriptors are.

So, let’s say that you have a descriptor set layout that has a UBO binding and two texture bindings. That’s three descriptors within the set. If you want to create a pool from which you can allocate 200 descriptor sets which use that layout, your descriptor pool info must do all of the following:

  1. Specify a maxSets value of at least 200.
  2. Provide a VkDescriptorPoolSize for UBO bindings that says that you want at least 200 such descriptors.
  3. Provide a VkDescriptorPoolSize for texture bindings that says that you want to have at least 400 such descriptors.

#2 and 3 define how many descriptors from those sets can be allocated by the pool. If you don’t do 2 and 3 correctly, you will get that error, because you will try to allocate more descriptors than are in the pool. Not more descriptor sets, more descriptors.

This is not about descriptor sets; you are exceeding the limits on the number of descriptors of those particular types.

That is, whatever descriptorPoolVec contains is incorrect.

#5

Thank you for your response. Ok, I think I understand what’s going on here. I’ve read the online docs on VkDescriptorPoolCreateInfo many times over on many occasions and it’s never been clear to me.

I was under the impression that pool allocation was more automatic. I thought the VkDescriptorPoolSize specified what was in your set (example: 1 UBO, 1 texture) and the poolInfo.maxSets was how many you wanted of that set (200). My thinking was it would just allocate the pool by duplicating VkDescriptorPoolSize 200 time.

From what you explained, I would have to fill VkDescriptorPoolSize with 200 UBS and 200 texture descriptors. At this point, poolInfo.maxSets is just a counter of sorts and has no effect on pool allocation.

If that’s correct, I think I’ve got it. Thanks for your help!