diff --git a/src/gallium/drivers/freedreno/freedreno_batch_cache.c b/src/gallium/drivers/freedreno/freedreno_batch_cache.c index a5231c643aa..05ae98c24f8 100644 --- a/src/gallium/drivers/freedreno/freedreno_batch_cache.c +++ b/src/gallium/drivers/freedreno/freedreno_batch_cache.c @@ -170,9 +170,33 @@ fd_bc_flush(struct fd_context *ctx, bool deferred) assert_dt */ if (deferred) { struct fd_batch *current_batch = fd_context_batch(ctx); + struct fd_batch *deps[ARRAY_SIZE(cache->batches)] = {0}; + unsigned ndeps = 0; + + /* To avoid a dependency loop, pull out any batches that already + * have a dependency on the current batch. This ensures the + * following loop adding a dependency to the current_batch, all + * remaining batches do not have a direct or indirect dependency + * on the current_batch. + * + * The batches that have a dependency on the current batch will + * be flushed immediately (after dropping screen lock) instead + */ + for (unsigned i = 0; i < n; i++) { + if ((batches[i] != current_batch) && + fd_batch_has_dep(batches[i], current_batch)) { + /* We can't immediately flush while we hold the screen lock, + * but that doesn't matter. We just want to skip adding any + * deps that would result in a loop, we can flush after we've + * updated the dependency graph and dropped the lock. + */ + fd_batch_reference_locked(&deps[ndeps++], batches[i]); + fd_batch_reference_locked(&batches[i], NULL); + } + } for (unsigned i = 0; i < n; i++) { - if (batches[i] != current_batch) { + if (batches[i] && (batches[i] != current_batch)) { fd_batch_add_dep(current_batch, batches[i]); } } @@ -180,6 +204,14 @@ fd_bc_flush(struct fd_context *ctx, bool deferred) assert_dt fd_batch_reference_locked(¤t_batch, NULL); fd_screen_unlock(ctx->screen); + + /* If we have any batches that we could add a dependency on (unlikely) + * flush them immediately. + */ + for (unsigned i = 0; i < ndeps; i++) { + fd_batch_flush(deps[i]); + fd_batch_reference(&deps[i], NULL); + } } else { fd_screen_unlock(ctx->screen);