freedreno/batch: fix dependency loop detection
authorRob Clark <robdclark@chromium.org>
Wed, 31 Jul 2019 19:30:24 +0000 (12:30 -0700)
committerRob Clark <robdclark@chromium.org>
Fri, 2 Aug 2019 17:24:14 +0000 (10:24 -0700)
We can have a scenario like:

  A -> B
  A -> C -> B

When adding the A->C dependency, it doesn't really matter that C depends
on something that A depends on, that isn't a necessary condition for a
dependency loop.

Instead what we want to know is that nothing C depends on, directly or
indirectly, depends on A.  We can detect this by recursively OR'ing the
dependents_mask of C and all it's dependencies.

Signed-off-by: Rob Clark <robdclark@chromium.org>
src/gallium/drivers/freedreno/freedreno_batch.c

index 6bab243453dcc226266763d155d66d8beab31e43..52870cd0aa1a9d7237fb179d454ec9b6164737ae 100644 (file)
@@ -401,31 +401,30 @@ fd_batch_flush(struct fd_batch *batch, bool sync)
        fd_batch_reference(&tmp, NULL);
 }
 
-/* does 'batch' depend directly or indirectly on 'other' ? */
-static bool
-batch_depends_on(struct fd_batch *batch, struct fd_batch *other)
+/* find a batches dependents mask, including recursive dependencies: */
+static uint32_t
+recursive_dependents_mask(struct fd_batch *batch)
 {
        struct fd_batch_cache *cache = &batch->ctx->screen->batch_cache;
        struct fd_batch *dep;
+       uint32_t dependents_mask = batch->dependents_mask;
 
-       if (batch->dependents_mask & (1 << other->idx))
-               return true;
+       foreach_batch(dep, cache, batch->dependents_mask)
+               dependents_mask |= recursive_dependents_mask(dep);
 
-       foreach_batch(dep, cache, other->dependents_mask)
-               if (batch_depends_on(batch, dep))
-                       return true;
-
-       return false;
+       return dependents_mask;
 }
 
 void
 fd_batch_add_dep(struct fd_batch *batch, struct fd_batch *dep)
 {
+       pipe_mutex_assert_locked(batch->ctx->screen->lock);
+
        if (batch->dependents_mask & (1 << dep->idx))
                return;
 
        /* a loop should not be possible */
-       debug_assert(!batch_depends_on(dep, batch));
+       debug_assert(!((1 << batch->idx) & recursive_dependents_mask(dep)));
 
        struct fd_batch *other = NULL;
        fd_batch_reference_locked(&other, dep);