render/vulkan: Handle multi-descriptor sets

A combined image sampler may need several descriptors in a descriptor
set. We are not currently checking how many descriptors are required,
nor is it presumably guaranteed that such multi-descriptor allocation
will not fail due to fragmentation.

If the pool free counter is not zero, try to allocate but continue with
the next pool and fall back to creating a new pool if the allocation
failed.

Fixes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/4010
This commit is contained in:
Kenny Levinsen 2025-09-08 15:40:55 +02:00 committed by Simon Ser
parent d7ae9a866b
commit dd7f543189

View file

@ -66,16 +66,35 @@ static struct wlr_vk_descriptor_pool *alloc_ds(
struct wl_list *pool_list, size_t *last_pool_size) {
VkResult res;
bool found = false;
VkDescriptorSetAllocateInfo ds_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.descriptorSetCount = 1,
.pSetLayouts = layout,
};
struct wlr_vk_descriptor_pool *pool;
wl_list_for_each(pool, pool_list, link) {
if (pool->free > 0) {
found = true;
break;
ds_info.descriptorPool = pool->pool;
res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
switch (res) {
case VK_ERROR_FRAGMENTED_POOL:
case VK_ERROR_OUT_OF_POOL_MEMORY:
// Descriptor sets with more than one descriptor can cause us
// to run out of pool memory early or lead to fragmentation
// that makes the pool unable to service our allocation
// request. Try the next pool or allocate a new one.
continue;
case VK_SUCCESS:
--pool->free;
return pool;
default:
wlr_vk_error("vkAllocateDescriptorSets", res);
return NULL;
}
}
}
if (!found) { // create new pool
pool = calloc(1, sizeof(*pool));
if (!pool) {
wlr_log_errno(WLR_ERROR, "allocation failed");
@ -111,14 +130,8 @@ static struct wlr_vk_descriptor_pool *alloc_ds(
*last_pool_size = count;
wl_list_insert(pool_list, &pool->link);
}
VkDescriptorSetAllocateInfo ds_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.descriptorSetCount = 1,
.pSetLayouts = layout,
.descriptorPool = pool->pool,
};
ds_info.descriptorPool = pool->pool;
res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
if (res != VK_SUCCESS) {
wlr_vk_error("vkAllocateDescriptorSets", res);