From: Mike Blumenkrantz Date: Wed, 30 Jun 2021 18:35:02 +0000 (-0400) Subject: zink: handle broken resource mapping deadlocks X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8dd314d2035876c62292f633819105939c3f6933;p=platform%2Fupstream%2Fmesa.git zink: handle broken resource mapping deadlocks some apps (most notably Wolfenstein: The New Order) have broken multi-context buffer usage in which one context will attempt to write to a buffer while another context holds unflushed usage, and the unflushed context will never flush until the buffer write completes it's impossible to handle this scenario correctly without deadlocking, so add some handling to try waiting and then yolo the buffer write if a deadlock would occur Part-of: --- diff --git a/src/gallium/drivers/zink/zink_batch.c b/src/gallium/drivers/zink/zink_batch.c index 5df3887..28c60d8 100644 --- a/src/gallium/drivers/zink/zink_batch.c +++ b/src/gallium/drivers/zink/zink_batch.c @@ -804,8 +804,8 @@ zink_batch_usage_check_completion(struct zink_context *ctx, const struct zink_ba return zink_check_batch_completion(ctx, u->usage); } -void -zink_batch_usage_wait(struct zink_context *ctx, struct zink_batch_usage *u) +static void +batch_usage_wait(struct zink_context *ctx, struct zink_batch_usage *u, bool trywait) { if (!zink_batch_usage_exists(u)) return; @@ -814,9 +814,25 @@ zink_batch_usage_wait(struct zink_context *ctx, struct zink_batch_usage *u) ctx->base.flush(&ctx->base, NULL, PIPE_FLUSH_HINT_FINISH); else { //multi-context mtx_lock(&u->mtx); - cnd_wait(&u->flush, &u->mtx); + if (trywait) { + struct timespec ts = {0, 10000}; + cnd_timedwait(&u->flush, &u->mtx, &ts); + } else + cnd_wait(&u->flush, &u->mtx); mtx_unlock(&u->mtx); } } zink_wait_on_batch(ctx, u->usage); } + +void +zink_batch_usage_wait(struct zink_context *ctx, struct zink_batch_usage *u) +{ + batch_usage_wait(ctx, u, false); +} + +void +zink_batch_usage_try_wait(struct zink_context *ctx, struct zink_batch_usage *u) +{ + batch_usage_wait(ctx, u, true); +} diff --git a/src/gallium/drivers/zink/zink_batch.h b/src/gallium/drivers/zink/zink_batch.h index f911a4f..9c9caa1 100644 --- a/src/gallium/drivers/zink/zink_batch.h +++ b/src/gallium/drivers/zink/zink_batch.h @@ -121,6 +121,9 @@ zink_batch_usage_check_completion(struct zink_context *ctx, const struct zink_ba void zink_batch_usage_wait(struct zink_context *ctx, struct zink_batch_usage *u); +void +zink_batch_usage_try_wait(struct zink_context *ctx, struct zink_batch_usage *u); + #ifdef __cplusplus } #endif diff --git a/src/gallium/drivers/zink/zink_bo.h b/src/gallium/drivers/zink/zink_bo.h index 4d3a89b..b58c6c2 100644 --- a/src/gallium/drivers/zink/zink_bo.h +++ b/src/gallium/drivers/zink/zink_bo.h @@ -183,6 +183,15 @@ zink_bo_usage_wait(struct zink_context *ctx, struct zink_bo *bo, enum zink_resou } static inline void +zink_bo_usage_try_wait(struct zink_context *ctx, struct zink_bo *bo, enum zink_resource_access access) +{ + if (access & ZINK_RESOURCE_ACCESS_READ) + zink_batch_usage_try_wait(ctx, bo->reads); + if (access & ZINK_RESOURCE_ACCESS_WRITE) + zink_batch_usage_try_wait(ctx, bo->writes); +} + +static inline void zink_bo_usage_set(struct zink_bo *bo, struct zink_batch_state *bs, bool write) { if (write) diff --git a/src/gallium/drivers/zink/zink_resource.c b/src/gallium/drivers/zink/zink_resource.c index af55ab2..e3b793e 100644 --- a/src/gallium/drivers/zink/zink_resource.c +++ b/src/gallium/drivers/zink/zink_resource.c @@ -1859,6 +1859,7 @@ zink_buffer_map(struct pipe_context *pctx, !res->obj->host_visible)) { assert(!(usage & (TC_TRANSFER_MAP_THREADED_UNSYNC | PIPE_MAP_THREAD_SAFE))); if (!res->obj->host_visible || !(usage & PIPE_MAP_ONCE)) { +overwrite: trans->offset = box->x % screen->info.props.limits.minMemoryMapAlignment; trans->staging_res = pipe_buffer_create(&screen->base, PIPE_BIND_LINEAR, PIPE_USAGE_STAGING, box->width + trans->offset); if (!trans->staging_res) @@ -1880,9 +1881,14 @@ zink_buffer_map(struct pipe_context *pctx, } if (!(usage & PIPE_MAP_UNSYNCHRONIZED)) { - if (usage & PIPE_MAP_WRITE) + if (usage & PIPE_MAP_WRITE) { + if (!(usage & PIPE_MAP_READ)) { + zink_resource_usage_try_wait(ctx, res, ZINK_RESOURCE_ACCESS_RW); + if (zink_resource_has_unflushed_usage(res)) + goto overwrite; + } zink_resource_usage_wait(ctx, res, ZINK_RESOURCE_ACCESS_RW); - else + } else zink_resource_usage_wait(ctx, res, ZINK_RESOURCE_ACCESS_WRITE); res->obj->access = 0; res->obj->access_stage = 0; diff --git a/src/gallium/drivers/zink/zink_resource.h b/src/gallium/drivers/zink/zink_resource.h index 4f2eb8f..652585c 100644 --- a/src/gallium/drivers/zink/zink_resource.h +++ b/src/gallium/drivers/zink/zink_resource.h @@ -132,6 +132,12 @@ zink_resource_usage_check_completion(struct zink_screen *screen, struct zink_res } static inline void +zink_resource_usage_try_wait(struct zink_context *ctx, struct zink_resource *res, enum zink_resource_access access) +{ + zink_bo_usage_try_wait(ctx, res->obj->bo, access); +} + +static inline void zink_resource_usage_wait(struct zink_context *ctx, struct zink_resource *res, enum zink_resource_access access) { zink_bo_usage_wait(ctx, res->obj->bo, access);