zink: defer batch state resets more competently

previously batch states would defer resource object destruction until
"later", which was somewhat unreliable in the event that the batch state
wasn't checked again for a long while

instead, defer all "large" batch states and then reset them in the submit
thread, which should yield more consistent results, including in scenarios
with multiple contexts in use

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37068>
This commit is contained in:
Mike Blumenkrantz
2025-08-22 13:20:25 -04:00
committed by Marge Bot
parent 6dd081ab1b
commit 067873d4a4
3 changed files with 53 additions and 18 deletions
+42 -18
View File
@@ -56,12 +56,10 @@ reset_obj_list(struct zink_screen *screen, struct zink_batch_state *bs, struct z
}
/* reset a given batch state */
void
zink_reset_batch_state(struct zink_context *ctx, struct zink_batch_state *bs)
static void
reset_batch_state_internal(struct zink_screen *screen, struct zink_batch_state *bs)
{
MESA_TRACE_FUNC();
struct zink_screen *screen = zink_screen(ctx->base.screen);
VkResult result = VKSCR(ResetCommandPool)(screen->dev, bs->cmdpool, 0);
if (result != VK_SUCCESS)
mesa_loge("ZINK: vkResetCommandPool failed (%s)", vk_Result_to_str(result));
@@ -83,16 +81,6 @@ zink_reset_batch_state(struct zink_context *ctx, struct zink_batch_state *bs)
reset_obj(screen, bs, obj);
}
/* this is where bindless texture/buffer ids get recycled */
for (unsigned i = 0; i < 2; i++) {
while (util_dynarray_contains(&bs->bindless_releases[i], uint32_t)) {
uint32_t handle = util_dynarray_pop(&bs->bindless_releases[i], uint32_t);
bool is_buffer = ZINK_BINDLESS_IS_BUFFER(handle);
struct util_idalloc *ids = i ? &ctx->di.bindless[is_buffer].img_slots : &ctx->di.bindless[is_buffer].tex_slots;
util_idalloc_free(ids, is_buffer ? handle - ZINK_MAX_BINDLESS_HANDLES : handle);
}
}
/* queries must only be destroyed once they are inactive */
set_foreach_remove(&bs->active_queries, entry) {
struct zink_query *query = (void*)entry->key;
@@ -179,6 +167,20 @@ zink_reset_batch_state(struct zink_context *ctx, struct zink_batch_state *bs)
bs->has_unsync = false;
}
static void
reset_batch_state_ctx(struct zink_context *ctx, struct zink_batch_state *bs)
{
/* this is where bindless texture/buffer ids get recycled */
for (unsigned i = 0; i < 2; i++) {
while (util_dynarray_contains(&bs->bindless_releases[i], uint32_t)) {
uint32_t handle = util_dynarray_pop(&bs->bindless_releases[i], uint32_t);
bool is_buffer = ZINK_BINDLESS_IS_BUFFER(handle);
struct util_idalloc *ids = i ? &ctx->di.bindless[is_buffer].img_slots : &ctx->di.bindless[is_buffer].tex_slots;
util_idalloc_free(ids, is_buffer ? handle - ZINK_MAX_BINDLESS_HANDLES : handle);
}
}
}
/* this is where deferred resource unrefs occur */
static void
unref_resources(struct zink_screen *screen, struct zink_batch_state *bs)
@@ -190,6 +192,15 @@ unref_resources(struct zink_screen *screen, struct zink_batch_state *bs)
}
}
void
zink_reset_batch_state(struct zink_context *ctx, struct zink_batch_state *bs)
{
struct zink_screen *screen = zink_screen(ctx->base.screen);
reset_batch_state_ctx(ctx, bs);
reset_batch_state_internal(screen, bs);
unref_resources(screen, bs);
}
/* utility for resetting a batch state; called on context destruction */
void
zink_clear_batch_state(struct zink_context *ctx, struct zink_batch_state *bs)
@@ -437,15 +448,17 @@ find_completed_batch_state(struct zink_context *ctx)
struct zink_batch_state *bs = NULL;
/* states are stored sequentially, so if the first one doesn't work, none of them will */
for (struct zink_batch_state *i = ctx->batch_states; i; i = i->next) {
for (struct zink_batch_state *i = ctx->batch_states, *j = i ? i->next : NULL; i; i = j, j = j ? j->next : NULL) {
/* only a submitted state can be reused */
if (p_atomic_read(&i->fence.submitted) &&
/* a submitted state must have completed before it can be reused */
(zink_screen_check_last_finished(screen, i->fence.batch_id) ||
p_atomic_read(&i->fence.completed))) {
pop_batch_state(ctx);
zink_reset_batch_state(ctx, bs);
return i;
reset_batch_state_ctx(ctx, i);
simple_mtx_lock(&screen->active_batch_states_lock);
zink_batch_state_append(&screen->active_batch_states, &screen->last_active_batch_state, i);
simple_mtx_unlock(&screen->active_batch_states_lock);
} else {
return bs;
}
@@ -811,7 +824,18 @@ end:
cnd_broadcast(&bs->usage.flush);
p_atomic_set(&bs->fence.submitted, true);
unref_resources(screen, bs);
simple_mtx_lock(&screen->active_batch_states_lock);
simple_mtx_lock(&screen->free_batch_states_lock);
for (struct zink_batch_state *i = screen->active_batch_states, *j = i ? i->next : NULL; i; i = j, j = j ? j->next : NULL) {
reset_batch_state_internal(screen, i);
unref_resources(screen, i);
zink_batch_state_append(&screen->free_batch_states, &screen->last_free_batch_state, i);
}
screen->active_batch_states = NULL;
screen->last_active_batch_state = NULL;
simple_mtx_unlock(&screen->free_batch_states_lock);
simple_mtx_unlock(&screen->active_batch_states_lock);
}
/* called during flush */
+7
View File
@@ -1474,6 +1474,12 @@ zink_destroy_screen(struct pipe_screen *pscreen)
zink_batch_state_destroy(screen, bs);
bs = bs_next;
}
bs = screen->active_batch_states;
while (bs) {
struct zink_batch_state *bs_next = bs->next;
zink_batch_state_destroy(screen, bs);
bs = bs_next;
}
if (VK_NULL_HANDLE != screen->debugUtilsCallbackHandle) {
VKSCR(DestroyDebugUtilsMessengerEXT)(screen->instance, screen->debugUtilsCallbackHandle, NULL);
@@ -3658,6 +3664,7 @@ zink_internal_create_screen(const struct pipe_screen_config *config, int64_t dev
}
simple_mtx_init(&screen->free_batch_states_lock, mtx_plain);
simple_mtx_init(&screen->active_batch_states_lock, mtx_plain);
simple_mtx_init(&screen->dt_lock, mtx_plain);
util_idalloc_mt_init_tc(&screen->buffer_ids);
+4
View File
@@ -1369,6 +1369,10 @@ struct zink_screen {
struct zink_batch_state *last_free_batch_state; //for appending
simple_mtx_t free_batch_states_lock;
struct zink_batch_state *active_batch_states; //active batch states
struct zink_batch_state *last_active_batch_state; //for appending
simple_mtx_t active_batch_states_lock;
simple_mtx_t semaphores_lock;
struct util_dynarray semaphores;
struct util_dynarray fd_semaphores;