mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-29 05:40:12 -04:00
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:
parent
d7ae9a866b
commit
dd7f543189
1 changed files with 61 additions and 48 deletions
|
|
@ -66,59 +66,72 @@ static struct wlr_vk_descriptor_pool *alloc_ds(
|
||||||
struct wl_list *pool_list, size_t *last_pool_size) {
|
struct wl_list *pool_list, size_t *last_pool_size) {
|
||||||
VkResult res;
|
VkResult res;
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
struct wlr_vk_descriptor_pool *pool;
|
|
||||||
wl_list_for_each(pool, pool_list, link) {
|
|
||||||
if (pool->free > 0) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) { // create new pool
|
|
||||||
pool = calloc(1, sizeof(*pool));
|
|
||||||
if (!pool) {
|
|
||||||
wlr_log_errno(WLR_ERROR, "allocation failed");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t count = 2 * (*last_pool_size);
|
|
||||||
if (!count) {
|
|
||||||
count = start_descriptor_pool_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
pool->free = count;
|
|
||||||
VkDescriptorPoolSize pool_size = {
|
|
||||||
.descriptorCount = count,
|
|
||||||
.type = type,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkDescriptorPoolCreateInfo dpool_info = {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
||||||
.maxSets = count,
|
|
||||||
.poolSizeCount = 1,
|
|
||||||
.pPoolSizes = &pool_size,
|
|
||||||
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
|
|
||||||
};
|
|
||||||
|
|
||||||
res = vkCreateDescriptorPool(renderer->dev->dev, &dpool_info, NULL,
|
|
||||||
&pool->pool);
|
|
||||||
if (res != VK_SUCCESS) {
|
|
||||||
wlr_vk_error("vkCreateDescriptorPool", res);
|
|
||||||
free(pool);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*last_pool_size = count;
|
|
||||||
wl_list_insert(pool_list, &pool->link);
|
|
||||||
}
|
|
||||||
|
|
||||||
VkDescriptorSetAllocateInfo ds_info = {
|
VkDescriptorSetAllocateInfo ds_info = {
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||||
.descriptorSetCount = 1,
|
.descriptorSetCount = 1,
|
||||||
.pSetLayouts = layout,
|
.pSetLayouts = layout,
|
||||||
.descriptorPool = pool->pool,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_vk_descriptor_pool *pool;
|
||||||
|
wl_list_for_each(pool, pool_list, link) {
|
||||||
|
if (pool->free > 0) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pool = calloc(1, sizeof(*pool));
|
||||||
|
if (!pool) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t count = 2 * (*last_pool_size);
|
||||||
|
if (!count) {
|
||||||
|
count = start_descriptor_pool_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool->free = count;
|
||||||
|
VkDescriptorPoolSize pool_size = {
|
||||||
|
.descriptorCount = count,
|
||||||
|
.type = type,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkDescriptorPoolCreateInfo dpool_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||||
|
.maxSets = count,
|
||||||
|
.poolSizeCount = 1,
|
||||||
|
.pPoolSizes = &pool_size,
|
||||||
|
.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
res = vkCreateDescriptorPool(renderer->dev->dev, &dpool_info, NULL,
|
||||||
|
&pool->pool);
|
||||||
|
if (res != VK_SUCCESS) {
|
||||||
|
wlr_vk_error("vkCreateDescriptorPool", res);
|
||||||
|
free(pool);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*last_pool_size = count;
|
||||||
|
wl_list_insert(pool_list, &pool->link);
|
||||||
|
|
||||||
|
ds_info.descriptorPool = pool->pool;
|
||||||
res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
|
res = vkAllocateDescriptorSets(renderer->dev->dev, &ds_info, ds);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
wlr_vk_error("vkAllocateDescriptorSets", res);
|
wlr_vk_error("vkAllocateDescriptorSets", res);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue