v3dv: add reference counting for descriptor set layouts

The spec states that descriptor set layouts can be destroyed almost
at any time:

   "VkDescriptorSetLayout objects may be accessed by commands that
    operate on descriptor sets allocated using that layout, and those
    descriptor sets must not be updated with vkUpdateDescriptorSets
    after the descriptor set layout has been destroyed. Otherwise,
    descriptor set layouts can be destroyed any time they are not in
    use by an API command."

Based on a similar fix for RADV.

Gitlab: https://gitlab.freedesktop.org/mesa/mesa/-/issues/5893
Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15634>
This commit is contained in:
Iago Toral Quiroga
2022-03-29 09:02:06 +02:00
committed by Marge Bot
parent ca861bd6f4
commit 7f6ecb8667
2 changed files with 56 additions and 8 deletions

View File

@@ -314,8 +314,8 @@ v3dv_CreatePipelineLayout(VkDevice _device,
for (uint32_t set = 0; set < pCreateInfo->setLayoutCount; set++) {
V3DV_FROM_HANDLE(v3dv_descriptor_set_layout, set_layout,
pCreateInfo->pSetLayouts[set]);
v3dv_descriptor_set_layout_ref(set_layout);
layout->set[set].layout = set_layout;
layout->set[set].dynamic_offset_start = dynamic_offset_count;
for (uint32_t b = 0; b < set_layout->binding_count; b++) {
dynamic_offset_count += set_layout->binding[b].array_size *
@@ -351,6 +351,10 @@ v3dv_DestroyPipelineLayout(VkDevice _device,
if (!pipeline_layout)
return;
for (uint32_t i = 0; i < pipeline_layout->num_sets; i++)
v3dv_descriptor_set_layout_unref(device, pipeline_layout->set[i].layout);
vk_object_free(&device->vk, pAllocator, pipeline_layout);
}
@@ -478,6 +482,8 @@ descriptor_set_destroy(struct v3dv_device *device,
{
assert(!pool->host_memory_base);
v3dv_descriptor_set_layout_unref(device, set->layout);
if (free_bo && !pool->host_memory_base) {
for (uint32_t i = 0; i < pool->entry_count; i++) {
if (pool->entries[i].set == set) {
@@ -543,6 +549,15 @@ v3dv_ResetDescriptorPool(VkDevice _device,
return VK_SUCCESS;
}
void
v3dv_descriptor_set_layout_destroy(struct v3dv_device *device,
struct v3dv_descriptor_set_layout *set_layout)
{
assert(set_layout->ref_cnt == 0);
vk_object_base_finish(&set_layout->base);
vk_free2(&device->vk.alloc, NULL, set_layout);
}
VKAPI_ATTR VkResult VKAPI_CALL
v3dv_CreateDescriptorSetLayout(VkDevice _device,
const VkDescriptorSetLayoutCreateInfo *pCreateInfo,
@@ -588,12 +603,18 @@ v3dv_CreateDescriptorSetLayout(VkDevice _device,
uint32_t size = samplers_offset +
immutable_sampler_count * sizeof(struct v3dv_sampler);
set_layout = vk_object_zalloc(&device->vk, pAllocator, size,
VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT);
/* Descriptor set layouts are reference counted and therefore can survive
* vkDestroyPipelineSetLayout, so they need to be allocated with a device
* scope.
*/
set_layout =
vk_zalloc(&device->vk.alloc, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
if (!set_layout)
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
vk_object_base_init(&device->vk, &set_layout->base,
VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT);
struct v3dv_sampler *samplers = (void*) &set_layout->binding[num_bindings];
assert(pCreateInfo->bindingCount == 0 || num_bindings > 0);
@@ -602,7 +623,7 @@ v3dv_CreateDescriptorSetLayout(VkDevice _device,
VkResult result = vk_create_sorted_bindings(pCreateInfo->pBindings,
pCreateInfo->bindingCount, &bindings);
if (result != VK_SUCCESS) {
vk_object_free(&device->vk, pAllocator, set_layout);
v3dv_descriptor_set_layout_destroy(device, set_layout);
return vk_error(device, result);
}
@@ -610,6 +631,7 @@ v3dv_CreateDescriptorSetLayout(VkDevice _device,
set_layout->flags = pCreateInfo->flags;
set_layout->shader_stages = 0;
set_layout->bo_size = 0;
set_layout->ref_cnt = 1;
uint32_t descriptor_count = 0;
uint32_t dynamic_offset_count = 0;
@@ -712,7 +734,7 @@ v3dv_DestroyDescriptorSetLayout(VkDevice _device,
if (!set_layout)
return;
vk_object_free(&device->vk, pAllocator, set_layout);
v3dv_descriptor_set_layout_unref(device, set_layout);
}
static inline VkResult
@@ -731,7 +753,7 @@ out_of_pool_memory(const struct v3dv_device *device,
static VkResult
descriptor_set_create(struct v3dv_device *device,
struct v3dv_descriptor_pool *pool,
const struct v3dv_descriptor_set_layout *layout,
struct v3dv_descriptor_set_layout *layout,
struct v3dv_descriptor_set **out_set)
{
struct v3dv_descriptor_set *set;
@@ -836,6 +858,7 @@ descriptor_set_create(struct v3dv_device *device,
}
}
v3dv_descriptor_set_layout_ref(layout);
*out_set = set;
return VK_SUCCESS;

View File

@@ -1645,7 +1645,7 @@ struct v3dv_descriptor_set {
struct v3dv_descriptor_pool *pool;
const struct v3dv_descriptor_set_layout *layout;
struct v3dv_descriptor_set_layout *layout;
/* Offset relative to the descriptor pool bo for this set */
uint32_t base_offset;
@@ -1699,10 +1699,35 @@ struct v3dv_descriptor_set_layout {
/* Number of dynamic offsets used by this descriptor set */
uint16_t dynamic_offset_count;
/* Descriptor set layouts can be destroyed even if they are still being
* used.
*/
uint32_t ref_cnt;
/* Bindings in this descriptor set */
struct v3dv_descriptor_set_binding_layout binding[0];
};
void
v3dv_descriptor_set_layout_destroy(struct v3dv_device *device,
struct v3dv_descriptor_set_layout *set_layout);
static inline void
v3dv_descriptor_set_layout_ref(struct v3dv_descriptor_set_layout *set_layout)
{
assert(set_layout && set_layout->ref_cnt >= 1);
p_atomic_inc(&set_layout->ref_cnt);
}
static inline void
v3dv_descriptor_set_layout_unref(struct v3dv_device *device,
struct v3dv_descriptor_set_layout *set_layout)
{
assert(set_layout && set_layout->ref_cnt >= 1);
if (p_atomic_dec_zero(&set_layout->ref_cnt))
v3dv_descriptor_set_layout_destroy(device, set_layout);
}
struct v3dv_pipeline_layout {
struct vk_object_base base;