ref: 6f979f815bb9256aa4e71f493c71f70dd94ced2f
parent: 82cce09a19199b62fd67a9307b64fd96d7ede33b
author: Janne Grunau <janne-vlc@jannau.net>
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);