shithub: dav1d

Download patch

ref: 6f979f815bb9256aa4e71f493c71f70dd94ced2f
parent: 82cce09a19199b62fd67a9307b64fd96d7ede33b
author: Janne Grunau <[email protected]>
date: Mon Nov 5 15:03:55 EST 2018

tile threading: pass decoding errors through progress tracking

See #127

--- a/src/decode.c
+++ b/src/decode.c
@@ -2733,15 +2733,24 @@
                     for (int tile_col = 0; tile_col < f->frame_hdr.tiling.cols;
                          tile_col++)
                     {
+                        int progress;
                         Dav1dTileState *const ts =
                             &f->ts[tile_row * f->frame_hdr.tiling.cols + tile_col];
 
-                        if (atomic_load(&ts->progress) <= sby) {
+                        if ((progress = atomic_load(&ts->progress)) <= sby) {
                             pthread_mutex_lock(&ts->tile_thread.lock);
-                            while (atomic_load(&ts->progress) <= sby)
+                            while ((progress = atomic_load(&ts->progress)) <= sby)
                                 pthread_cond_wait(&ts->tile_thread.cond,
                                                   &ts->tile_thread.lock);
                             pthread_mutex_unlock(&ts->tile_thread.lock);
+                        }
+                        if (progress == TILE_ERROR) {
+                            const uint64_t all_mask = ~0ULL >> (64 - f->n_tc);
+                            pthread_mutex_lock(&f->tile_thread.lock);
+                            while (f->tile_thread.available != all_mask)
+                                pthread_cond_wait(&f->tile_thread.icond, &f->tile_thread.lock);
+                            pthread_mutex_unlock(&f->tile_thread.lock);
+                            goto error;
                         }
                     }
 
--- a/src/internal.h
+++ b/src/internal.h
@@ -217,7 +217,7 @@
     CdfContext cdf;
     MsacContext msac;
 
-    atomic_int progress; // in sby units
+    atomic_int progress; // in sby units, TILE_ERROR after a decoding error
     struct {
         pthread_mutex_t lock;
         pthread_cond_t cond;
--- a/src/thread_task.c
+++ b/src/thread_task.c
@@ -71,6 +71,7 @@
             pthread_cond_wait(&fttd->cond, &fttd->lock);
         }
         if (t->tile_thread.die) {
+            pthread_cond_signal(&fttd->icond);
             pthread_mutex_unlock(&fttd->lock);
             break;
         }
@@ -85,18 +86,21 @@
             for (t->by = ts->tiling.row_start; t->by < ts->tiling.row_end;
                  t->by += f->sb_step)
             {
-                dav1d_decode_tile_sbrow(t);
+                int error = dav1d_decode_tile_sbrow(t);
+                int progress = error ? TILE_ERROR : 1 + (t->by >> f->sb_shift);
 
                 // signal progress
                 pthread_mutex_lock(&ts->tile_thread.lock);
-                atomic_store(&ts->progress, 1 + (t->by >> f->sb_shift));
+                atomic_store(&ts->progress, progress);
                 pthread_cond_signal(&ts->tile_thread.cond);
                 pthread_mutex_unlock(&ts->tile_thread.lock);
+                if (error) break;
             }
         } else {
             const int sby = f->tile_thread.task_idx_to_sby_and_tile_idx[task_idx][0];
             const int tile_idx = f->tile_thread.task_idx_to_sby_and_tile_idx[task_idx][1];
             Dav1dTileState *const ts = &f->ts[tile_idx];
+            int progress;
 
             // the interleaved decoding can sometimes cause dependency issues
             // if one part of the frame decodes signifcantly faster than others.
@@ -104,13 +108,14 @@
             // and resume them later as dependencies are met. This also would
             // solve the broadcast() below and allow us to use signal(). However,
             // for now, we use linear dependency tracking because it's simpler.
-            if (atomic_load(&ts->progress) < sby) {
+            if ((progress = atomic_load(&ts->progress)) < sby) {
                 pthread_mutex_lock(&ts->tile_thread.lock);
-                while (atomic_load(&ts->progress) < sby)
+                while ((progress = atomic_load(&ts->progress)) < sby)
                     pthread_cond_wait(&ts->tile_thread.cond,
                                       &ts->tile_thread.lock);
                 pthread_mutex_unlock(&ts->tile_thread.lock);
             }
+            if (progress == TILE_ERROR) continue;
 
             // we need to interleave sbrow decoding for all tile cols in a
             // tile row, since otherwise subsequent threads will be blocked
@@ -117,11 +122,12 @@
             // waiting for the post-filter to complete
             t->ts = ts;
             t->by = sby << f->sb_shift;
-            dav1d_decode_tile_sbrow(t);
+            int error = dav1d_decode_tile_sbrow(t);
+            progress = error ? TILE_ERROR : 1 + sby;
 
             // signal progress
             pthread_mutex_lock(&ts->tile_thread.lock);
-            atomic_store(&ts->progress, 1 + sby);
+            atomic_store(&ts->progress, progress);
             pthread_cond_broadcast(&ts->tile_thread.cond);
             pthread_mutex_unlock(&ts->tile_thread.lock);
         }
--- a/src/thread_task.h
+++ b/src/thread_task.h
@@ -28,7 +28,11 @@
 #ifndef __DAV1D_SRC_THREAD_TASK_H__
 #define __DAV1D_SRC_THREAD_TASK_H__
 
+#include <limits.h>
+
 #include "src/internal.h"
+
+#define TILE_ERROR (INT_MAX - 1)
 
 int dav1d_decode_frame(Dav1dFrameContext *f);
 void *dav1d_frame_task(void *data);