tu: Faster descriptor set allocator
memmove was slow on large number of descriptor when destroying some of them. util_vma_heap is perfect for the task, ANV and RADV already use it. It also simplifies the code. Signed-off-by: Danylo Piliaiev <dpiliaiev@igalia.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38053>
This commit is contained in:
committed by
Marge Bot
parent
562bb8b62b
commit
62f0ef3445
@@ -617,58 +617,27 @@ tu_descriptor_set_create(struct tu_device *device,
|
||||
return vk_error(device, VK_ERROR_OUT_OF_POOL_MEMORY);
|
||||
}
|
||||
|
||||
/* try to allocate linearly first, so that we don't spend
|
||||
* time looking for gaps if the app only allocates &
|
||||
* resets via the pool. */
|
||||
if (pool->current_offset + layout_size <= pool->size) {
|
||||
set->mapped_ptr = (uint32_t*)(pool_base(pool) + pool->current_offset);
|
||||
set->va = pool->host_bo ? 0 : pool->bo->iova + pool->current_offset;
|
||||
uint64_t current_offset = pool->current_offset;
|
||||
|
||||
if (!pool->host_memory_base) {
|
||||
pool->entries[pool->entry_count].offset = pool->current_offset;
|
||||
pool->entries[pool->entry_count].size = layout_size;
|
||||
pool->entries[pool->entry_count].set = set;
|
||||
pool->entry_count++;
|
||||
}
|
||||
pool->current_offset += layout_size;
|
||||
} else if (!pool->host_memory_base) {
|
||||
uint64_t offset = 0;
|
||||
int index;
|
||||
if (!pool->host_memory_base) {
|
||||
uint64_t pool_vma_offset =
|
||||
util_vma_heap_alloc(&pool->bo_heap, set->size, 1);
|
||||
if (!pool_vma_offset)
|
||||
return vk_error(device, VK_ERROR_FRAGMENTED_POOL);
|
||||
|
||||
for (index = 0; index < pool->entry_count; ++index) {
|
||||
if (pool->entries[index].size == 0)
|
||||
continue;
|
||||
|
||||
if (pool->entries[index].offset - offset >= layout_size)
|
||||
break;
|
||||
offset = pool->entries[index].offset + pool->entries[index].size;
|
||||
}
|
||||
|
||||
if (pool->size - offset < layout_size) {
|
||||
vk_object_free(&device->vk, NULL, set);
|
||||
assert(pool_vma_offset >= TU_POOL_HEAP_OFFSET &&
|
||||
pool_vma_offset <= pool->size + TU_POOL_HEAP_OFFSET);
|
||||
set->offset = pool_vma_offset - TU_POOL_HEAP_OFFSET;
|
||||
current_offset = set->offset;
|
||||
} else {
|
||||
if (current_offset + set->size > pool->size)
|
||||
return vk_error(device, VK_ERROR_OUT_OF_POOL_MEMORY);
|
||||
}
|
||||
|
||||
set->mapped_ptr = (uint32_t*)(pool_base(pool) + offset);
|
||||
set->va = pool->host_bo ? 0 : pool->bo->iova + offset;
|
||||
pool->current_offset += set->size;
|
||||
}
|
||||
|
||||
memmove(&pool->entries[index + 1], &pool->entries[index],
|
||||
sizeof(pool->entries[0]) * (pool->entry_count - index));
|
||||
pool->entries[index].offset = offset;
|
||||
pool->entries[index].size = layout_size;
|
||||
pool->entries[index].set = set;
|
||||
pool->entry_count++;
|
||||
} else
|
||||
return vk_error(device, VK_ERROR_OUT_OF_POOL_MEMORY);
|
||||
} else if (!pool->host_memory_base) {
|
||||
/* Also keep track of zero sized descriptor sets, such as descriptor
|
||||
* sets with just dynamic descriptors, so that we can free the sets on
|
||||
* vkDestroyDescriptorPool().
|
||||
*/
|
||||
pool->entries[pool->entry_count].offset = ~0;
|
||||
pool->entries[pool->entry_count].size = 0;
|
||||
pool->entries[pool->entry_count].set = set;
|
||||
pool->entry_count++;
|
||||
set->mapped_ptr = (uint32_t*)(pool_base(pool) + current_offset);
|
||||
set->va = pool->host_bo ? 0 : pool->bo->iova + current_offset;
|
||||
}
|
||||
|
||||
if (layout->has_immutable_samplers) {
|
||||
@@ -693,6 +662,7 @@ tu_descriptor_set_create(struct tu_device *device,
|
||||
|
||||
vk_descriptor_set_layout_ref(&layout->vk);
|
||||
list_addtail(&set->pool_link, &pool->desc_sets);
|
||||
pool->entry_count++;
|
||||
|
||||
*out_set = set;
|
||||
return VK_SUCCESS;
|
||||
@@ -701,30 +671,17 @@ tu_descriptor_set_create(struct tu_device *device,
|
||||
static void
|
||||
tu_descriptor_set_destroy(struct tu_device *device,
|
||||
struct tu_descriptor_pool *pool,
|
||||
struct tu_descriptor_set *set,
|
||||
bool free_bo)
|
||||
struct tu_descriptor_set *set)
|
||||
{
|
||||
assert(!pool->host_memory_base);
|
||||
|
||||
if (free_bo && !pool->host_memory_base) {
|
||||
for (int i = 0; i < pool->entry_count; ++i) {
|
||||
if (pool->entries[i].set == set) {
|
||||
if (set->size) {
|
||||
ASSERTED uint32_t offset =
|
||||
(uint8_t *) set->mapped_ptr - pool_base(pool);
|
||||
assert(pool->entries[i].offset == offset);
|
||||
} else {
|
||||
assert(pool->entries[i].size == 0);
|
||||
}
|
||||
|
||||
memmove(&pool->entries[i], &pool->entries[i+1],
|
||||
sizeof(pool->entries[i]) * (pool->entry_count - i - 1));
|
||||
--pool->entry_count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (set->size) {
|
||||
util_vma_heap_free(&pool->bo_heap,
|
||||
(uint64_t) set->offset + TU_POOL_HEAP_OFFSET,
|
||||
set->size);
|
||||
}
|
||||
|
||||
pool->entry_count--;
|
||||
vk_object_free(&device->vk, NULL, set);
|
||||
}
|
||||
|
||||
@@ -793,8 +750,6 @@ tu_CreateDescriptorPool(VkDevice _device,
|
||||
uint64_t host_size = pCreateInfo->maxSets * sizeof(struct tu_descriptor_set);
|
||||
host_size += dynamic_size;
|
||||
size += host_size;
|
||||
} else {
|
||||
size += sizeof(struct tu_descriptor_pool_entry) * pCreateInfo->maxSets;
|
||||
}
|
||||
|
||||
pool = (struct tu_descriptor_pool *) vk_object_zalloc(
|
||||
@@ -806,6 +761,12 @@ tu_CreateDescriptorPool(VkDevice _device,
|
||||
pool->host_memory_base = (uint8_t*)pool + sizeof(struct tu_descriptor_pool);
|
||||
pool->host_memory_ptr = pool->host_memory_base;
|
||||
pool->host_memory_end = (uint8_t*)pool + size;
|
||||
} else {
|
||||
if (bo_size) {
|
||||
util_vma_heap_init(&pool->bo_heap, TU_POOL_HEAP_OFFSET,
|
||||
bo_size + TU_POOL_HEAP_OFFSET);
|
||||
pool->bo_heap.alloc_high = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bo_size) {
|
||||
@@ -845,6 +806,20 @@ fail_alloc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
tu_destroy_descriptor_pool_entries(struct tu_device *device,
|
||||
struct tu_descriptor_pool *pool)
|
||||
{
|
||||
list_for_each_entry_safe (struct tu_descriptor_set, set, &pool->desc_sets,
|
||||
pool_link) {
|
||||
vk_descriptor_set_layout_unref(&device->vk, &set->layout->vk);
|
||||
if (!pool->host_memory_base)
|
||||
tu_descriptor_set_destroy(device, pool, set);
|
||||
}
|
||||
|
||||
list_inithead(&pool->desc_sets);
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL
|
||||
tu_DestroyDescriptorPool(VkDevice _device,
|
||||
VkDescriptorPool _pool,
|
||||
@@ -858,18 +833,12 @@ tu_DestroyDescriptorPool(VkDevice _device,
|
||||
|
||||
TU_RMV(resource_destroy, device, pool);
|
||||
|
||||
list_for_each_entry_safe(struct tu_descriptor_set, set,
|
||||
&pool->desc_sets, pool_link) {
|
||||
vk_descriptor_set_layout_unref(&device->vk, &set->layout->vk);
|
||||
}
|
||||
|
||||
if (!pool->host_memory_base) {
|
||||
for(int i = 0; i < pool->entry_count; ++i) {
|
||||
tu_descriptor_set_destroy(device, pool, pool->entries[i].set, false);
|
||||
}
|
||||
}
|
||||
tu_destroy_descriptor_pool_entries(device, pool);
|
||||
|
||||
if (pool->size) {
|
||||
if (!pool->host_memory_base)
|
||||
util_vma_heap_finish(&pool->bo_heap);
|
||||
|
||||
if (pool->host_bo)
|
||||
vk_free2(&device->vk.alloc, pAllocator, pool->host_bo);
|
||||
else
|
||||
@@ -887,19 +856,15 @@ tu_ResetDescriptorPool(VkDevice _device,
|
||||
VK_FROM_HANDLE(tu_device, device, _device);
|
||||
VK_FROM_HANDLE(tu_descriptor_pool, pool, descriptorPool);
|
||||
|
||||
list_for_each_entry_safe(struct tu_descriptor_set, set,
|
||||
&pool->desc_sets, pool_link) {
|
||||
vk_descriptor_set_layout_unref(&device->vk, &set->layout->vk);
|
||||
}
|
||||
list_inithead(&pool->desc_sets);
|
||||
tu_destroy_descriptor_pool_entries(device, pool);
|
||||
|
||||
if (!pool->host_memory_base) {
|
||||
for(int i = 0; i < pool->entry_count; ++i) {
|
||||
tu_descriptor_set_destroy(device, pool, pool->entries[i].set, false);
|
||||
}
|
||||
pool->entry_count = 0;
|
||||
if (!pool->host_memory_base && pool->size) {
|
||||
util_vma_heap_finish(&pool->bo_heap);
|
||||
util_vma_heap_init(&pool->bo_heap, TU_POOL_HEAP_OFFSET,
|
||||
pool->size + TU_POOL_HEAP_OFFSET);
|
||||
}
|
||||
|
||||
pool->entry_count = 0;
|
||||
pool->current_offset = 0;
|
||||
pool->host_memory_ptr = pool->host_memory_base;
|
||||
|
||||
@@ -967,7 +932,7 @@ tu_FreeDescriptorSets(VkDevice _device,
|
||||
}
|
||||
|
||||
if (set && !pool->host_memory_base)
|
||||
tu_descriptor_set_destroy(device, pool, set, true);
|
||||
tu_descriptor_set_destroy(device, pool, set);
|
||||
}
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "vk_descriptor_set_layout.h"
|
||||
|
||||
#include "tu_sampler.h"
|
||||
#include "util/vma.h"
|
||||
|
||||
/* The hardware supports up to 8 descriptor sets since A7XX.
|
||||
* Note: This is the maximum across generations, not the maximum for a
|
||||
@@ -26,6 +27,12 @@
|
||||
*/
|
||||
#define MAX_SET_SIZE ((1 << 28) * 4)
|
||||
|
||||
/* The vma heap reserves 0 to mean NULL; we have to offset by some amount to
|
||||
* ensure we can allocate the entire BO without hitting zero. The actual
|
||||
* amount doesn't matter.
|
||||
*/
|
||||
#define TU_POOL_HEAP_OFFSET 32
|
||||
|
||||
struct tu_descriptor_set_binding_layout
|
||||
{
|
||||
VkDescriptorType type;
|
||||
@@ -116,6 +123,7 @@ struct tu_descriptor_set
|
||||
|
||||
struct tu_descriptor_set_layout *layout;
|
||||
struct tu_descriptor_pool *pool;
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
|
||||
uint64_t va;
|
||||
@@ -132,13 +140,6 @@ struct tu_descriptor_set
|
||||
VK_DEFINE_NONDISP_HANDLE_CASTS(tu_descriptor_set, base, VkDescriptorSet,
|
||||
VK_OBJECT_TYPE_DESCRIPTOR_SET)
|
||||
|
||||
struct tu_descriptor_pool_entry
|
||||
{
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
struct tu_descriptor_set *set;
|
||||
};
|
||||
|
||||
struct tu_descriptor_pool
|
||||
{
|
||||
struct vk_object_base base;
|
||||
@@ -154,9 +155,10 @@ struct tu_descriptor_pool
|
||||
|
||||
struct list_head desc_sets;
|
||||
|
||||
struct util_vma_heap bo_heap;
|
||||
|
||||
uint32_t entry_count;
|
||||
uint32_t max_entry_count;
|
||||
struct tu_descriptor_pool_entry entries[0];
|
||||
};
|
||||
VK_DEFINE_NONDISP_HANDLE_CASTS(tu_descriptor_pool, base, VkDescriptorPool,
|
||||
VK_OBJECT_TYPE_DESCRIPTOR_POOL)
|
||||
|
||||
Reference in New Issue
Block a user