mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-06 02:58:05 +02:00
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: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19141>
This commit is contained in:
parent
5e05d98848
commit
8dd314d203
5 changed files with 45 additions and 5 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -182,6 +182,15 @@ zink_bo_usage_wait(struct zink_context *ctx, struct zink_bo *bo, enum zink_resou
|
|||
zink_batch_usage_wait(ctx, bo->writes);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -131,6 +131,12 @@ zink_resource_usage_check_completion(struct zink_screen *screen, struct zink_res
|
|||
return zink_bo_usage_check_completion(screen, res->obj->bo, access);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue