From d1acd88c1466a854a8a0466d697b068ebeaa8a9f Mon Sep 17 00:00:00 2001 From: Mike Blumenkrantz Date: Wed, 12 Oct 2022 17:35:03 -0400 Subject: [PATCH] zink: prevent ballooning of view object memory if a resource is in use every frame and never goes idle, it becomes impossible to execute pruning, as there is no tracking for when views are no longer in use to avoid eventually ooming in this scenario, add some data to zink_resource_object which can effectively "queue" pruning of these views if ballooning is detected at a time when the views are guaranteed to be safe to delete Part-of: --- src/gallium/drivers/zink/zink_batch.c | 41 +++++++++++++++++++++++++++++++++++ src/gallium/drivers/zink/zink_types.h | 2 ++ 2 files changed, 43 insertions(+) diff --git a/src/gallium/drivers/zink/zink_batch.c b/src/gallium/drivers/zink/zink_batch.c index 39ce61c..38bac79 100644 --- a/src/gallium/drivers/zink/zink_batch.c +++ b/src/gallium/drivers/zink/zink_batch.c @@ -14,6 +14,8 @@ #endif #include "wsi_common.h" +#define MAX_VIEW_COUNT 500 + void debug_describe_zink_batch_state(char *buf, const struct zink_batch_state *ptr) { @@ -36,6 +38,20 @@ reset_obj(struct zink_screen *screen, struct zink_batch_state *bs, struct zink_r while (util_dynarray_contains(&obj->views, VkImageView)) VKSCR(DestroyImageView)(screen->dev, util_dynarray_pop(&obj->views, VkImageView), NULL); } + obj->view_prune_count = 0; + obj->view_prune_timeline = 0; + simple_mtx_unlock(&obj->view_lock); + } else if (util_dynarray_num_elements(&obj->views, VkBufferView) > MAX_VIEW_COUNT && !zink_bo_has_unflushed_usage(obj->bo)) { + /* avoid ballooning from too many views on always-used resources: */ + simple_mtx_lock(&obj->view_lock); + /* ensure no existing view pruning is queued, double check elements in case pruning just finished */ + if (!obj->view_prune_timeline && util_dynarray_num_elements(&obj->views, VkBufferView) > MAX_VIEW_COUNT) { + /* prune all existing views */ + obj->view_prune_count = util_dynarray_num_elements(&obj->views, VkBufferView); + /* prune them when the views will definitely not be in use */ + obj->view_prune_timeline = MAX2(obj->bo->reads ? obj->bo->reads->usage : 0, + obj->bo->writes ? obj->bo->writes->usage : 0); + } simple_mtx_unlock(&obj->view_lock); } util_dynarray_append(&bs->unref_resources, struct zink_resource_object*, obj); @@ -133,6 +149,31 @@ unref_resources(struct zink_screen *screen, struct zink_batch_state *bs) { while (util_dynarray_contains(&bs->unref_resources, struct zink_resource_object*)) { struct zink_resource_object *obj = util_dynarray_pop(&bs->unref_resources, struct zink_resource_object*); + if (obj->view_prune_timeline && zink_screen_check_last_finished(screen, obj->view_prune_timeline)) { + simple_mtx_lock(&obj->view_lock); + /* check again under lock in case multi-context use is in the same place */ + if (obj->view_prune_timeline && zink_screen_check_last_finished(screen, obj->view_prune_timeline)) { + /* prune `view_prune_count` views */ + if (obj->is_buffer) { + VkBufferView *views = obj->views.data; + for (unsigned i = 0; i < obj->view_prune_count; i++) + VKSCR(DestroyBufferView)(screen->dev, views[i], NULL); + } else { + VkImageView *views = obj->views.data; + for (unsigned i = 0; i < obj->view_prune_count; i++) + VKSCR(DestroyImageView)(screen->dev, views[i], NULL); + } + size_t offset = obj->view_prune_count * sizeof(VkBufferView); + uint8_t *data = obj->views.data; + /* shift the view array to the start */ + memcpy(data, data + offset, obj->views.size - offset); + /* adjust the array size */ + obj->views.size -= offset; + obj->view_prune_count = 0; + obj->view_prune_timeline = 0; + } + simple_mtx_unlock(&obj->view_lock); + } zink_resource_object_reference(screen, &obj, NULL); } while (util_dynarray_contains(&bs->unref_semaphores, VkSemaphore)) diff --git a/src/gallium/drivers/zink/zink_types.h b/src/gallium/drivers/zink/zink_types.h index c66397c..67a1da0 100644 --- a/src/gallium/drivers/zink/zink_types.h +++ b/src/gallium/drivers/zink/zink_types.h @@ -959,6 +959,8 @@ struct zink_resource_object { VkBuffer storage_buffer; simple_mtx_t view_lock; + uint32_t view_prune_count; //how many views to prune + uint32_t view_prune_timeline; //when to prune struct util_dynarray views; union { -- 2.7.4