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: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19056>
This commit is contained in:
Mike Blumenkrantz
2022-10-12 17:35:03 -04:00
committed by Marge Bot
parent 765debc602
commit d1acd88c14
2 changed files with 43 additions and 0 deletions

View File

@@ -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))