summaryrefslogtreecommitdiff
path: root/chromium/third_party/dav1d/libdav1d/src/thread_task.c
diff options
context:
space:
mode:
authorDale Curtis <dalecurtis@chromium.org>2022-12-16 22:37:46 +0000
committerMichael BrĂ¼ning <michael.bruning@qt.io>2023-03-27 08:12:03 +0000
commitc885ec409f9b6ffa25e03851729b1bc2ad2005b3 (patch)
tree0c9f205efc231ede87d2704b2780d1569caf5111 /chromium/third_party/dav1d/libdav1d/src/thread_task.c
parent0d63fc949d16f3e37ed7ab43d335b9d81cc6fdf7 (diff)
downloadqtwebengine-chromium-102-based.tar.gz
[Backport] Security bug 1401571102-based
Manual update of libdav1d to match the version introduced by patch https://chromium-review.googlesource.com/c/chromium/src/+/4114163: Roll src/third_party/dav1d/libdav1d/ 87f9a81cd..ed63a7459 (104 commits) This roll required a few changes to get working: - "properties" => "built in options" crossfile configuration change due to Meson deprecation. - generic config creation never worked, so fixed. - PPC64 configs were never checked in, so switched to generic. - copyright header changes for generate_sources. - Updated readme.chromium with potential issues that can arise. https://chromium.googlesource.com/external/github.com/videolan/dav1d.git/+log/87f9a81cd770..ed63a7459376 $ git log 87f9a81cd..ed63a7459 --date=short --no-merges --format='%ad %ae %s' 2022-12-09 jamrial dav1d: add an option to skip decoding some frame types 2022-12-08 jamrial picture: support creating and freeing refs without tile data 2022-12-07 gramner x86: Add 10bpc 8x32/32x8 itx AVX-512 (Ice Lake) asm 2022-12-07 gramner x86: Add minor DC-only IDCT optimizations 2022-12-13 gramner getbits: Fix assertion failure 2022-12-13 gramner checkasm: Fix integer overflow in refmvs test 2022-01-26 gramner dav1dplay: Update to new libplacebo API 2022-12-09 gramner Add minor getbits improvements 2022-12-09 gramner Add a separate getbits function for getting a single bit 2022-12-09 gramner Remove redundant zeroing in sequence header parsing 2022-12-09 gramner Set the correct default value of initial_display_delay 2022-12-09 jamrial tools: remove the null last entry in inloop_filters_tbl 2022-12-04 lu_zero Do not assume the picture allocation starts as the left edge 2022-11-21 lu_zero ppc: Allocate the correct temp buffer size 2022-11-21 lu_zero ppc: Do not use static const with vec_splats 2022-11-02 charlie.c.hayden Add info to dav1d_send_data docs 2022-10-30 jbeich build: drop -D_DARWIN_C_SOURCE on macOS/iOS after 6b611d36acab 2022-10-30 jbeich build: drop -D_POSIX_C_SOURCE on non-Linux after 6b611d36acab 2022-06-28 victorien threading: Add a pending list for async task insertion 2022-10-26 martin Implement atomic_compare_exchange_strong in the atomic compat headers 2022-10-06 victorien threading: Fix a race around frame completion (frame-mt) 2022-10-07 sebastian Handle host_machine.system() 'ios' and 'tvos' the same way as 'darwin' 2022-09-23 gramner x86: Add 10-bit 8x8/8x16/16x8/16x16 itx AVX-512 (Ice Lake) asm 2022-09-30 gramner Specify hidden visibility for global data symbol declarations 2022-09-28 gramner build: strip() the result of cc.get_define() 2022-09-26 gramner checkasm: Move printf format string to .rodata on x86 2022-09-26 gramner checkasm: Improve 32-bit parameter clobbering on x86-64 2022-09-26 gramner x86: Fix incorrect 32-bit parameter usage in high bit-depth AVX-512 mc 2022-09-09 martin arm: itx: Add clipping to row_clip_min/max in the 10 bpc codepaths 2022-09-15 gramner x86: Fix overflows in 12bpc AVX2 IDCT/IADST 2022-09-15 gramner x86: Fix overflows in 12bpc AVX2 DC-only IDCT 2022-09-15 gramner x86: Fix clipping in high bit-depth AVX2 4x16 IDCT 2022-03-21 martin Don't use gas-preprocessor with clang-cl for arm targets 2022-06-07 david_conrad Fix checking the reference dimesions for the projection process 2022-06-07 david_conrad Fix calculation of OBMC lap dimensions 2022-06-07 david_conrad Support film grain application whose only effect is clipping to video range 2022-06-07 david_conrad Ignore T.35 metadata if the OBU contains no payload 2022-06-07 david_conrad Fix chroma deblock filter size calculation for lossless 2022-06-07 david_conrad Fix rounding in the calculation of initialSubpelX 2022-06-07 david_conrad Fix overflow when saturating dequantized coefficients clipped to 0 2022-06-08 david_conrad Fix overflow in 8-bit NEON ADST 2022-09-14 martin tools: Allocate the priv structs with proper alignment 2022-09-08 gramner x86: Fix clipping in 10bpc SSE4.1 IDCT asm 2022-09-08 gramner build: Improve Windows linking options 2022-09-08 gramner tools: Improve demuxer probing 2022-08-30 code CI: Disable trimming on some tests 2022-08-30 code CI: Remove git 'safe.directory' config 2022-08-30 code gcovr: Ignore parsing errors 2022-08-30 code crossfiles: Update Android toolchains 2022-08-30 code CI: Update images (...) 2022-09-01 victorien checkasm: Add short options 2022-09-01 victorien checkasm: Add pattern matching to --test 2022-09-01 victorien checkasm: Remove pattern matching from --bench 2022-08-29 victorien checkasm: Add a --function option 2022-08-30 victorien threading: Fix copy_lpf_progress initialization 2022-08-19 jamrial data: don't overwrite the Dav1dDataProps size value 2022-07-18 gramner Adjust inlining attributes on some functions 2022-07-19 gramner x86: Remove leftover instruction in loopfilter AVX2 asm 2022-06-07 david_conrad Enable pointer authentication in assembly when building arm64e 2022-06-07 david_conrad Don't trash the return stack buffer in the NEON loop filter 2022-07-03 thresh CI: Removed snap package generation 2022-07-06 gramner Eliminate unused C DSP functions at compile time 2022-07-06 gramner cpu: Inline dav1d_get_cpu_flags() 2022-06-22 gramner x86: Add minor loopfilter asm improvements 2022-06-15 gramner checkasm: Speed up signal handling 2022-06-15 gramner checkasm: Improve seed generation on Windows 2022-06-20 gramner ci: Don't specify a specific MacOS version 2022-06-14 gramner x86: Add high bit-depth loopfilter AVX-512 (Ice Lake) asm 2022-06-13 victorien checkasm/lpf: Use operating dimensions 2022-06-03 gramner checkasm: Print the cpu model and cpuid signature on x86 2022-06-03 gramner checkasm: Add a vzeroupper check on x86 2022-06-02 gramner x86: Add a workaround for quirky AVX-512 hardware behavior 2022-05-31 victorien checkasm: Fix uninitialized variable 2022-05-14 code CI: Update coverage collecting 2022-05-05 code CI: Add a build with the minimum requirements 2022-05-05 code CI: Deactivate git 'safe.directory' 2022-03-24 code CI: Update images 2022-05-25 victorien Fix typo 2022-05-19 gramner x86: Add high bit-depth cdef_filter AVX-512 (Ice Lake) asm 2022-05-20 gramner checkasm: Print --help message to stderr instead of stdout 2022-05-20 gramner checkasm: Split cdef test into separate pri/sec/pri+sec parts 2022-05-20 gramner checkasm: Improve benchmarking of functions that modify their input 2022-05-18 b x86/itx_avx2: fix typo 2022-04-22 code CI: Add gcc12 and clang14 builds with mold linker 2022-04-26 code CI: Trigger documentation rebuild if configuration changes 2022-04-24 code meson/doc: Fix doxygen config 2022-04-28 gramner Use a relaxed memory ordering in dav1d_ref_inc() 2022-04-28 gramner Remove redundant code in dav1d_cdf_thread_unref() 2022-04-28 gramner Inline dav1d_ref_inc() 2022-04-24 code x86/itx: Add 32x8 12bpc AVX2 transforms 2022-04-24 code x86/itx: Add 8x32 12bpc AVX2 transforms 2022-04-24 code x86/itx: Deduplicate dconly code 2022-04-23 code lib: Fix typo in documentation 2022-04-07 jamrial obu: don't output invisible but showable key frames more than once 2022-04-07 jamrial obu: check that the frame referenced by existing_frame_idx is showable 2022-04-07 jamrial obu: check refresh_frame_flags is not equal to allFrames on Intra Only frames 2022-03-29 robux4 remove multipass wait from dav1d_decode_frame 2022-04-07 jamrial picture: ensure the new seq header and op param info flags are attached to the next visible picture in display order 2022-03-31 jamrial lib: add a function to query the decoder frame delay 2022-03-31 jamrial lib: split calculating thread count to its own function Created with: roll-dep src/third_party/dav1d/libdav1d Fixed: 1401571 Change-Id: Ic3cef540a87a2cf411abe6071fd4c9963ea61f75 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4114163 Reviewed-by: Wan-Teh Chang <wtc@google.com> Commit-Queue: Dale Curtis <dalecurtis@chromium.org> Cr-Commit-Position: refs/heads/main@{#1084574} Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/468619 Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/third_party/dav1d/libdav1d/src/thread_task.c')
-rw-r--r--chromium/third_party/dav1d/libdav1d/src/thread_task.c285
1 files changed, 197 insertions, 88 deletions
diff --git a/chromium/third_party/dav1d/libdav1d/src/thread_task.c b/chromium/third_party/dav1d/libdav1d/src/thread_task.c
index 53aa41e5c8a..ab2376c30a4 100644
--- a/chromium/third_party/dav1d/libdav1d/src/thread_task.c
+++ b/chromium/third_party/dav1d/libdav1d/src/thread_task.c
@@ -49,9 +49,13 @@ static inline int reset_task_cur(const Dav1dContext *const c,
unsigned frame_idx)
{
const unsigned first = atomic_load(&ttd->first);
+ unsigned reset_frame_idx = atomic_exchange(&ttd->reset_task_cur, UINT_MAX);
+ if (reset_frame_idx < first) {
+ if (frame_idx == UINT_MAX) return 0;
+ reset_frame_idx = UINT_MAX;
+ }
if (!ttd->cur && c->fc[first].task_thread.task_cur_prev == NULL)
return 0;
- unsigned reset_frame_idx = atomic_exchange(&ttd->reset_task_cur, UINT_MAX);
if (reset_frame_idx != UINT_MAX) {
if (frame_idx == UINT_MAX) {
if (reset_frame_idx > first + ttd->cur)
@@ -78,12 +82,17 @@ cur_found:
static inline void reset_task_cur_async(struct TaskThreadData *const ttd,
unsigned frame_idx, unsigned n_frames)
{
- if (frame_idx < (unsigned)atomic_load(&ttd->first)) frame_idx += n_frames;
+ const unsigned first = atomic_load(&ttd->first);
+ if (frame_idx < first) frame_idx += n_frames;
unsigned last_idx = frame_idx;
do {
frame_idx = last_idx;
last_idx = atomic_exchange(&ttd->reset_task_cur, frame_idx);
} while (last_idx < frame_idx);
+ if (frame_idx == first && atomic_load(&ttd->first) != first) {
+ unsigned expected = frame_idx;
+ atomic_compare_exchange_strong(&ttd->reset_task_cur, &expected, UINT_MAX);
+ }
}
static void insert_tasks_between(Dav1dFrameContext *const f,
@@ -164,6 +173,43 @@ static inline void insert_task(Dav1dFrameContext *const f,
insert_tasks(f, t, t, cond_signal);
}
+static inline void add_pending(Dav1dFrameContext *const f, Dav1dTask *const t) {
+ pthread_mutex_lock(&f->task_thread.pending_tasks.lock);
+ t->next = NULL;
+ if (!f->task_thread.pending_tasks.head)
+ f->task_thread.pending_tasks.head = t;
+ else
+ f->task_thread.pending_tasks.tail->next = t;
+ f->task_thread.pending_tasks.tail = t;
+ atomic_store(&f->task_thread.pending_tasks.merge, 1);
+ pthread_mutex_unlock(&f->task_thread.pending_tasks.lock);
+}
+
+static inline int merge_pending_frame(Dav1dFrameContext *const f) {
+ int const merge = atomic_load(&f->task_thread.pending_tasks.merge);
+ if (merge) {
+ pthread_mutex_lock(&f->task_thread.pending_tasks.lock);
+ Dav1dTask *t = f->task_thread.pending_tasks.head;
+ f->task_thread.pending_tasks.head = NULL;
+ f->task_thread.pending_tasks.tail = NULL;
+ atomic_store(&f->task_thread.pending_tasks.merge, 0);
+ pthread_mutex_unlock(&f->task_thread.pending_tasks.lock);
+ while (t) {
+ Dav1dTask *const tmp = t->next;
+ insert_task(f, t, 0);
+ t = tmp;
+ }
+ }
+ return merge;
+}
+
+static inline int merge_pending(const Dav1dContext *const c) {
+ int res = 0;
+ for (unsigned i = 0; i < c->n_fc; i++)
+ res |= merge_pending_frame(&c->fc[i]);
+ return res;
+}
+
static int create_filter_sbrow(Dav1dFrameContext *const f,
const int pass, Dav1dTask **res_t)
{
@@ -192,13 +238,14 @@ static int create_filter_sbrow(Dav1dFrameContext *const f,
const int prog_sz = ((f->sbh + 31) & ~31) >> 5;
if (prog_sz > f->frame_thread.prog_sz) {
atomic_uint *const prog = realloc(f->frame_thread.frame_progress,
- prog_sz * 2 * sizeof(*prog));
+ 2 * prog_sz * sizeof(*prog));
if (!prog) return -1;
f->frame_thread.frame_progress = prog;
f->frame_thread.copy_lpf_progress = prog + prog_sz;
- f->frame_thread.prog_sz = prog_sz;
}
- memset(f->frame_thread.frame_progress, 0, prog_sz * 2 * sizeof(atomic_uint));
+ f->frame_thread.prog_sz = prog_sz;
+ memset(f->frame_thread.frame_progress, 0, prog_sz * sizeof(atomic_uint));
+ memset(f->frame_thread.copy_lpf_progress, 0, prog_sz * sizeof(atomic_uint));
atomic_store(&f->frame_thread.deblock_progress, 0);
}
f->frame_thread.next_tile_row[pass & 1] = 0;
@@ -224,16 +271,18 @@ int dav1d_task_create_tile_sbrow(Dav1dFrameContext *const f, const int pass,
Dav1dTask *tasks = f->task_thread.tile_tasks[0];
const int uses_2pass = f->c->n_fc > 1;
const int num_tasks = f->frame_hdr->tiling.cols * f->frame_hdr->tiling.rows;
- int alloc_num_tasks = num_tasks * (1 + uses_2pass);
- if (alloc_num_tasks > f->task_thread.num_tile_tasks) {
- const size_t size = sizeof(Dav1dTask) * alloc_num_tasks;
- tasks = realloc(f->task_thread.tile_tasks[0], size);
- if (!tasks) return -1;
- memset(tasks, 0, size);
- f->task_thread.tile_tasks[0] = tasks;
- f->task_thread.num_tile_tasks = alloc_num_tasks;
+ if (pass < 2) {
+ int alloc_num_tasks = num_tasks * (1 + uses_2pass);
+ if (alloc_num_tasks > f->task_thread.num_tile_tasks) {
+ const size_t size = sizeof(Dav1dTask) * alloc_num_tasks;
+ tasks = realloc(f->task_thread.tile_tasks[0], size);
+ if (!tasks) return -1;
+ memset(tasks, 0, size);
+ f->task_thread.tile_tasks[0] = tasks;
+ f->task_thread.num_tile_tasks = alloc_num_tasks;
+ }
+ f->task_thread.tile_tasks[1] = tasks + num_tasks;
}
- f->task_thread.tile_tasks[1] = tasks + num_tasks;
tasks += num_tasks * (pass & 1);
Dav1dTask *pf_t;
@@ -263,8 +312,22 @@ int dav1d_task_create_tile_sbrow(Dav1dFrameContext *const f, const int pass,
prev_t->next = pf_t;
prev_t = pf_t;
}
- insert_tasks(f, &tasks[0], prev_t, cond_signal);
- f->task_thread.done[pass & 1] = 0;
+ prev_t->next = NULL;
+
+ atomic_store(&f->task_thread.done[pass & 1], 0);
+
+ // XXX in theory this could be done locklessly, at this point they are no
+ // tasks in the frameQ, so no other runner should be using this lock, but
+ // we must add both passes at once
+ pthread_mutex_lock(&f->task_thread.pending_tasks.lock);
+ assert(f->task_thread.pending_tasks.head == NULL || pass == 2);
+ if (!f->task_thread.pending_tasks.head)
+ f->task_thread.pending_tasks.head = &tasks[0];
+ else
+ f->task_thread.pending_tasks.tail->next = &tasks[0];
+ f->task_thread.pending_tasks.tail = prev_t;
+ atomic_store(&f->task_thread.pending_tasks.merge, 1);
+ pthread_mutex_unlock(&f->task_thread.pending_tasks.lock);
return 0;
}
@@ -272,7 +335,7 @@ int dav1d_task_create_tile_sbrow(Dav1dFrameContext *const f, const int pass,
void dav1d_task_frame_init(Dav1dFrameContext *const f) {
const Dav1dContext *const c = f->c;
- f->task_thread.init_done = 0;
+ atomic_store(&f->task_thread.init_done, 0);
// schedule init task, which will schedule the remaining tasks
Dav1dTask *const t = &f->task_thread.init_task;
t->type = DAV1D_TASK_TYPE_INIT;
@@ -307,16 +370,12 @@ static inline int ensure_progress(struct TaskThreadData *const ttd,
// so ensure that completed. if not, re-add to task-queue; else, fall-through
int p1 = atomic_load(state);
if (p1 < t->sby) {
+ t->type = type;
+ t->recon_progress = t->deblock_progress = 0;
+ *target = t->sby;
+ add_pending(f, t);
pthread_mutex_lock(&ttd->lock);
- p1 = atomic_load(state);
- if (p1 < t->sby) {
- t->type = type;
- t->recon_progress = t->deblock_progress = 0;
- *target = t->sby;
- insert_task(f, t, 0);
- return 1;
- }
- pthread_mutex_unlock(&ttd->lock);
+ return 1;
}
return 0;
}
@@ -369,11 +428,29 @@ static inline int check_tile(Dav1dTask *const t, Dav1dFrameContext *const f,
return 0;
}
+static inline int get_frame_progress(const Dav1dContext *const c,
+ const Dav1dFrameContext *const f)
+{
+ unsigned frame_prog = c->n_fc > 1 ? atomic_load(&f->sr_cur.progress[1]) : 0;
+ if (frame_prog >= FRAME_ERROR)
+ return f->sbh - 1;
+ int idx = frame_prog >> (f->sb_shift + 7);
+ int prog;
+ do {
+ atomic_uint *state = &f->frame_thread.frame_progress[idx];
+ const unsigned val = ~atomic_load(state);
+ prog = val ? ctz(val) : 32;
+ if (prog != 32) break;
+ prog = 0;
+ } while (++idx < f->frame_thread.prog_sz);
+ return ((idx << 5) | prog) - 1;
+}
+
static inline void abort_frame(Dav1dFrameContext *const f, const int error) {
atomic_store(&f->task_thread.error, error == DAV1D_ERR(EINVAL) ? 1 : -1);
- f->task_thread.task_counter = 0;
- f->task_thread.done[0] = 1;
- f->task_thread.done[1] = 1;
+ atomic_store(&f->task_thread.task_counter, 0);
+ atomic_store(&f->task_thread.done[0], 1);
+ atomic_store(&f->task_thread.done[1], 1);
atomic_store(&f->sr_cur.progress[0], FRAME_ERROR);
atomic_store(&f->sr_cur.progress[1], FRAME_ERROR);
dav1d_decode_frame_exit(f, error);
@@ -478,6 +555,8 @@ void *dav1d_worker_task(void *data) {
for (;;) {
if (tc->task_thread.die) break;
if (atomic_load(c->flush)) goto park;
+
+ merge_pending(c);
if (ttd->delayed_fg.exec) { // run delayed film grain first
delayed_fg_task(c, ttd);
continue;
@@ -488,11 +567,18 @@ void *dav1d_worker_task(void *data) {
for (unsigned i = 0; i < c->n_fc; i++) {
const unsigned first = atomic_load(&ttd->first);
f = &c->fc[(first + i) % c->n_fc];
- if (f->task_thread.init_done) continue;
+ if (atomic_load(&f->task_thread.init_done)) continue;
t = f->task_thread.task_head;
if (!t) continue;
if (t->type == DAV1D_TASK_TYPE_INIT) goto found;
if (t->type == DAV1D_TASK_TYPE_INIT_CDF) {
+ // XXX This can be a simple else, if adding tasks of both
+ // passes at once (in dav1d_task_create_tile_sbrow).
+ // Adding the tasks to the pending Q can result in a
+ // thread merging them before setting init_done.
+ // We will need to set init_done before adding to the
+ // pending Q, so maybe return the tasks, set init_done,
+ // and add to pending Q only then.
const int p1 = f->in_cdf.progress ?
atomic_load(f->in_cdf.progress) : 1;
if (p1) {
@@ -505,6 +591,7 @@ void *dav1d_worker_task(void *data) {
while (ttd->cur < c->n_fc) { // run decoding tasks last
const unsigned first = atomic_load(&ttd->first);
f = &c->fc[(first + ttd->cur) % c->n_fc];
+ merge_pending_frame(f);
prev_t = f->task_thread.task_cur_prev;
t = prev_t ? prev_t->next : f->task_thread.task_head;
while (t) {
@@ -519,11 +606,12 @@ void *dav1d_worker_task(void *data) {
} else if (t->recon_progress) {
const int p = t->type == DAV1D_TASK_TYPE_ENTROPY_PROGRESS;
int error = atomic_load(&f->task_thread.error);
- assert(!f->task_thread.done[p] || error);
+ assert(!atomic_load(&f->task_thread.done[p]) || error);
const int tile_row_base = f->frame_hdr->tiling.cols *
f->frame_thread.next_tile_row[p];
if (p) {
- const int p1 = f->frame_thread.entropy_progress;
+ atomic_int *const prog = &f->frame_thread.entropy_progress;
+ const int p1 = atomic_load(prog);
if (p1 < t->sby) goto next;
atomic_fetch_or(&f->task_thread.error, p1 == TILE_ERROR);
}
@@ -567,6 +655,7 @@ void *dav1d_worker_task(void *data) {
ttd->cur++;
}
if (reset_task_cur(c, ttd, UINT_MAX)) continue;
+ if (merge_pending(c)) continue;
park:
tc->task_thread.flushed = 1;
pthread_cond_signal(&tc->task_thread.td.cond);
@@ -584,6 +673,7 @@ void *dav1d_worker_task(void *data) {
if (!t->next) f->task_thread.task_tail = prev_t;
if (t->type > DAV1D_TASK_TYPE_INIT_CDF && !f->task_thread.task_head)
ttd->cur++;
+ t->next = NULL;
// we don't need to check cond_signaled here, since we found a task
// after the last signal so we want to re-signal the next waiting thread
// and again won't need to signal after that
@@ -605,13 +695,13 @@ void *dav1d_worker_task(void *data) {
if (res || p1 == TILE_ERROR) {
pthread_mutex_lock(&ttd->lock);
abort_frame(f, res ? res : DAV1D_ERR(EINVAL));
- } else if (!res) {
+ reset_task_cur(c, ttd, t->frame_idx);
+ } else {
t->type = DAV1D_TASK_TYPE_INIT_CDF;
if (p1) goto found_unlocked;
+ add_pending(f, t);
pthread_mutex_lock(&ttd->lock);
- insert_task(f, t, 0);
}
- reset_task_cur(c, ttd, t->frame_idx);
continue;
}
case DAV1D_TASK_TYPE_INIT_CDF: {
@@ -619,7 +709,6 @@ void *dav1d_worker_task(void *data) {
int res = DAV1D_ERR(EINVAL);
if (!atomic_load(&f->task_thread.error))
res = dav1d_decode_frame_init_cdf(f);
- pthread_mutex_lock(&ttd->lock);
if (f->frame_hdr->refresh_context && !f->task_thread.update_set) {
atomic_store(f->out_cdf.progress, res < 0 ? TILE_ERROR : 1);
}
@@ -628,23 +717,34 @@ void *dav1d_worker_task(void *data) {
for (int p = 1; p <= 2; p++) {
const int res = dav1d_task_create_tile_sbrow(f, p, 0);
if (res) {
+ pthread_mutex_lock(&ttd->lock);
// memory allocation failed
- f->task_thread.done[2 - p] = 1;
+ atomic_store(&f->task_thread.done[2 - p], 1);
atomic_store(&f->task_thread.error, -1);
- f->task_thread.task_counter -= f->sbh +
- f->frame_hdr->tiling.cols * f->frame_hdr->tiling.rows;
+ atomic_fetch_sub(&f->task_thread.task_counter,
+ f->frame_hdr->tiling.cols *
+ f->frame_hdr->tiling.rows + f->sbh);
atomic_store(&f->sr_cur.progress[p - 1], FRAME_ERROR);
- if (p == 2 && f->task_thread.done[1]) {
- assert(!f->task_thread.task_counter);
+ if (p == 2 && atomic_load(&f->task_thread.done[1])) {
+ assert(!atomic_load(&f->task_thread.task_counter));
dav1d_decode_frame_exit(f, DAV1D_ERR(ENOMEM));
f->n_tile_data = 0;
pthread_cond_signal(&f->task_thread.cond);
+ atomic_store(&f->task_thread.init_done, 1);
+ continue;
+ } else {
+ pthread_mutex_unlock(&ttd->lock);
}
}
}
- } else abort_frame(f, res);
- reset_task_cur(c, ttd, t->frame_idx);
- f->task_thread.init_done = 1;
+ atomic_store(&f->task_thread.init_done, 1);
+ pthread_mutex_lock(&ttd->lock);
+ } else {
+ pthread_mutex_lock(&ttd->lock);
+ abort_frame(f, res);
+ reset_task_cur(c, ttd, t->frame_idx);
+ atomic_store(&f->task_thread.init_done, 1);
+ }
continue;
}
case DAV1D_TASK_TYPE_TILE_ENTROPY:
@@ -673,10 +773,9 @@ void *dav1d_worker_task(void *data) {
pthread_cond_signal(&ttd->cond);
goto found_unlocked;
}
- pthread_mutex_lock(&ttd->lock);
atomic_store(&ts->progress[p], progress);
- reset_task_cur(c, ttd, t->frame_idx);
- insert_task(f, t, 0);
+ add_pending(f, t);
+ pthread_mutex_lock(&ttd->lock);
} else {
pthread_mutex_lock(&ttd->lock);
atomic_store(&ts->progress[p], progress);
@@ -692,15 +791,16 @@ void *dav1d_worker_task(void *data) {
if (c->n_fc > 1)
atomic_store(f->out_cdf.progress, error ? TILE_ERROR : 1);
}
- if (!--f->task_thread.task_counter && f->task_thread.done[0] &&
- (!uses_2pass || f->task_thread.done[1]))
+ if (atomic_fetch_sub(&f->task_thread.task_counter, 1) - 1 == 0 &&
+ atomic_load(&f->task_thread.done[0]) &&
+ (!uses_2pass || atomic_load(&f->task_thread.done[1])))
{
dav1d_decode_frame_exit(f, error == 1 ? DAV1D_ERR(EINVAL) :
error ? DAV1D_ERR(ENOMEM) : 0);
f->n_tile_data = 0;
pthread_cond_signal(&f->task_thread.cond);
}
- assert(f->task_thread.task_counter >= 0);
+ assert(atomic_load(&f->task_thread.task_counter) >= 0);
if (!atomic_fetch_or(&ttd->cond_signaled, 1))
pthread_cond_signal(&ttd->cond);
}
@@ -734,15 +834,11 @@ void *dav1d_worker_task(void *data) {
if (sby) {
int prog = atomic_load(&f->frame_thread.copy_lpf_progress[(sby - 1) >> 5]);
if (~prog & (1U << ((sby - 1) & 31))) {
+ t->type = DAV1D_TASK_TYPE_CDEF;
+ t->recon_progress = t->deblock_progress = 0;
+ add_pending(f, t);
pthread_mutex_lock(&ttd->lock);
- prog = atomic_load(&f->frame_thread.copy_lpf_progress[(sby - 1) >> 5]);
- if (~prog & (1U << ((sby - 1) & 31))) {
- t->type = DAV1D_TASK_TYPE_CDEF;
- t->recon_progress = t->deblock_progress = 0;
- insert_task(f, t, 0);
- continue;
- }
- pthread_mutex_unlock(&ttd->lock);
+ continue;
}
}
}
@@ -776,40 +872,53 @@ void *dav1d_worker_task(void *data) {
const int uses_2pass = c->n_fc > 1;
const int sbh = f->sbh;
const int sbsz = f->sb_step * 4;
- const enum PlaneType progress_plane_type =
- t->type == DAV1D_TASK_TYPE_ENTROPY_PROGRESS ? PLANE_TYPE_BLOCK :
- c->n_fc > 1 ? PLANE_TYPE_Y : PLANE_TYPE_ALL;
- if (t->type != DAV1D_TASK_TYPE_ENTROPY_PROGRESS)
- atomic_fetch_or(&f->frame_thread.frame_progress[sby >> 5],
- 1U << (sby & 31));
- pthread_mutex_lock(&ttd->lock);
- if (t->type != DAV1D_TASK_TYPE_ENTROPY_PROGRESS) {
- unsigned frame_prog = c->n_fc > 1 ? atomic_load(&f->sr_cur.progress[1]) : 0;
- if (frame_prog < FRAME_ERROR) {
- int idx = frame_prog >> (f->sb_shift + 7);
- int prog;
- do {
- atomic_uint *state = &f->frame_thread.frame_progress[idx];
- const unsigned val = ~atomic_load(state);
- prog = val ? ctz(val) : 32;
- if (prog != 32) break;
- prog = 0;
- } while (++idx < f->frame_thread.prog_sz);
- sby = ((idx << 5) | prog) - 1;
- } else sby = sbh - 1;
+ if (t->type == DAV1D_TASK_TYPE_ENTROPY_PROGRESS) {
+ error = atomic_load(&f->task_thread.error);
+ const unsigned y = sby + 1 == sbh ? UINT_MAX : (unsigned)(sby + 1) * sbsz;
+ assert(c->n_fc > 1);
+ if (f->sr_cur.p.data[0] /* upon flush, this can be free'ed already */)
+ atomic_store(&f->sr_cur.progress[0], error ? FRAME_ERROR : y);
+ atomic_store(&f->frame_thread.entropy_progress,
+ error ? TILE_ERROR : sby + 1);
+ if (sby + 1 == sbh)
+ atomic_store(&f->task_thread.done[1], 1);
+ pthread_mutex_lock(&ttd->lock);
+ const int num_tasks = atomic_fetch_sub(&f->task_thread.task_counter, 1) - 1;
+ if (sby + 1 < sbh && num_tasks) {
+ reset_task_cur(c, ttd, t->frame_idx);
+ continue;
+ }
+ if (!num_tasks && atomic_load(&f->task_thread.done[0]) &&
+ atomic_load(&f->task_thread.done[1]))
+ {
+ dav1d_decode_frame_exit(f, error == 1 ? DAV1D_ERR(EINVAL) :
+ error ? DAV1D_ERR(ENOMEM) : 0);
+ f->n_tile_data = 0;
+ pthread_cond_signal(&f->task_thread.cond);
+ }
+ reset_task_cur(c, ttd, t->frame_idx);
+ continue;
}
+ // t->type != DAV1D_TASK_TYPE_ENTROPY_PROGRESS
+ atomic_fetch_or(&f->frame_thread.frame_progress[sby >> 5],
+ 1U << (sby & 31));
+ pthread_mutex_lock(&f->task_thread.lock);
+ sby = get_frame_progress(c, f);
error = atomic_load(&f->task_thread.error);
const unsigned y = sby + 1 == sbh ? UINT_MAX : (unsigned)(sby + 1) * sbsz;
- if (c->n_fc > 1 && f->sr_cur.p.data[0] /* upon flush, this can be free'ed already */) {
- const int idx = t->type != DAV1D_TASK_TYPE_ENTROPY_PROGRESS;
- atomic_store(&f->sr_cur.progress[idx], error ? FRAME_ERROR : y);
- }
- if (progress_plane_type == PLANE_TYPE_BLOCK)
- f->frame_thread.entropy_progress = error ? TILE_ERROR : sby + 1;
+ if (c->n_fc > 1 && f->sr_cur.p.data[0] /* upon flush, this can be free'ed already */)
+ atomic_store(&f->sr_cur.progress[1], error ? FRAME_ERROR : y);
+ pthread_mutex_unlock(&f->task_thread.lock);
if (sby + 1 == sbh)
- f->task_thread.done[progress_plane_type == PLANE_TYPE_BLOCK] = 1;
- if (!--f->task_thread.task_counter &&
- f->task_thread.done[0] && (!uses_2pass || f->task_thread.done[1]))
+ atomic_store(&f->task_thread.done[0], 1);
+ pthread_mutex_lock(&ttd->lock);
+ const int num_tasks = atomic_fetch_sub(&f->task_thread.task_counter, 1) - 1;
+ if (sby + 1 < sbh && num_tasks) {
+ reset_task_cur(c, ttd, t->frame_idx);
+ continue;
+ }
+ if (!num_tasks && atomic_load(&f->task_thread.done[0]) &&
+ (!uses_2pass || atomic_load(&f->task_thread.done[1])))
{
dav1d_decode_frame_exit(f, error == 1 ? DAV1D_ERR(EINVAL) :
error ? DAV1D_ERR(ENOMEM) : 0);