| File: | root/firefox-clang/third_party/dav1d/src/thread_task.c |
| Warning: | line 320, column 22 Access to field 'next' results in a dereference of a null pointer (loaded from variable 'prev_t') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright © 2018, VideoLAN and dav1d authors | |||
| 3 | * Copyright © 2018, Two Orioles, LLC | |||
| 4 | * All rights reserved. | |||
| 5 | * | |||
| 6 | * Redistribution and use in source and binary forms, with or without | |||
| 7 | * modification, are permitted provided that the following conditions are met: | |||
| 8 | * | |||
| 9 | * 1. Redistributions of source code must retain the above copyright notice, this | |||
| 10 | * list of conditions and the following disclaimer. | |||
| 11 | * | |||
| 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, | |||
| 13 | * this list of conditions and the following disclaimer in the documentation | |||
| 14 | * and/or other materials provided with the distribution. | |||
| 15 | * | |||
| 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
| 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
| 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
| 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | |||
| 20 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
| 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
| 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
| 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
| 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| 26 | */ | |||
| 27 | ||||
| 28 | #include "config.h" | |||
| 29 | ||||
| 30 | #include "common/frame.h" | |||
| 31 | ||||
| 32 | #include "src/thread_task.h" | |||
| 33 | #include "src/fg_apply.h" | |||
| 34 | ||||
| 35 | // This function resets the cur pointer to the first frame theoretically | |||
| 36 | // executable after a task completed (ie. each time we update some progress or | |||
| 37 | // insert some tasks in the queue). | |||
| 38 | // When frame_idx is set, it can be either from a completed task, or from tasks | |||
| 39 | // inserted in the queue, in which case we have to make sure the cur pointer | |||
| 40 | // isn't past this insert. | |||
| 41 | // The special case where frame_idx is UINT_MAX is to handle the reset after | |||
| 42 | // completing a task and locklessly signaling progress. In this case we don't | |||
| 43 | // enter a critical section, which is needed for this function, so we set an | |||
| 44 | // atomic for a delayed handling, happening here. Meaning we can call this | |||
| 45 | // function without any actual update other than what's in the atomic, hence | |||
| 46 | // this special case. | |||
| 47 | static inline int reset_task_cur(const Dav1dContext *const c, | |||
| 48 | struct TaskThreadData *const ttd, | |||
| 49 | unsigned frame_idx) | |||
| 50 | { | |||
| 51 | const unsigned first = atomic_load(&ttd->first)__c11_atomic_load(&ttd->first, 5); | |||
| 52 | unsigned reset_frame_idx = atomic_exchange(&ttd->reset_task_cur, UINT_MAX)__c11_atomic_exchange(&ttd->reset_task_cur, (2147483647 *2U +1U), 5); | |||
| 53 | if (reset_frame_idx < first) { | |||
| 54 | if (frame_idx == UINT_MAX(2147483647 *2U +1U)) return 0; | |||
| 55 | reset_frame_idx = UINT_MAX(2147483647 *2U +1U); | |||
| 56 | } | |||
| 57 | if (!ttd->cur && c->fc[first].task_thread.task_cur_prev == NULL((void*)0)) | |||
| 58 | return 0; | |||
| 59 | if (reset_frame_idx != UINT_MAX(2147483647 *2U +1U)) { | |||
| 60 | if (frame_idx == UINT_MAX(2147483647 *2U +1U)) { | |||
| 61 | if (reset_frame_idx > first + ttd->cur) | |||
| 62 | return 0; | |||
| 63 | ttd->cur = reset_frame_idx - first; | |||
| 64 | goto cur_found; | |||
| 65 | } | |||
| 66 | } else if (frame_idx == UINT_MAX(2147483647 *2U +1U)) | |||
| 67 | return 0; | |||
| 68 | if (frame_idx < first) frame_idx += c->n_fc; | |||
| 69 | const unsigned min_frame_idx = umin(reset_frame_idx, frame_idx); | |||
| 70 | const unsigned cur_frame_idx = first + ttd->cur; | |||
| 71 | if (ttd->cur < c->n_fc && cur_frame_idx < min_frame_idx) | |||
| 72 | return 0; | |||
| 73 | for (ttd->cur = min_frame_idx - first; ttd->cur < c->n_fc; ttd->cur++) | |||
| 74 | if (c->fc[(first + ttd->cur) % c->n_fc].task_thread.task_head) | |||
| 75 | break; | |||
| 76 | cur_found: | |||
| 77 | for (unsigned i = ttd->cur; i < c->n_fc; i++) | |||
| 78 | c->fc[(first + i) % c->n_fc].task_thread.task_cur_prev = NULL((void*)0); | |||
| 79 | return 1; | |||
| 80 | } | |||
| 81 | ||||
| 82 | static inline void reset_task_cur_async(struct TaskThreadData *const ttd, | |||
| 83 | unsigned frame_idx, unsigned n_frames) | |||
| 84 | { | |||
| 85 | const unsigned first = atomic_load(&ttd->first)__c11_atomic_load(&ttd->first, 5); | |||
| 86 | if (frame_idx < first) frame_idx += n_frames; | |||
| 87 | unsigned last_idx = frame_idx; | |||
| 88 | do { | |||
| 89 | frame_idx = last_idx; | |||
| 90 | last_idx = atomic_exchange(&ttd->reset_task_cur, frame_idx)__c11_atomic_exchange(&ttd->reset_task_cur, frame_idx, 5); | |||
| 91 | } while (last_idx < frame_idx); | |||
| 92 | if (frame_idx == first && atomic_load(&ttd->first)__c11_atomic_load(&ttd->first, 5) != first) { | |||
| 93 | unsigned expected = frame_idx; | |||
| 94 | atomic_compare_exchange_strong(&ttd->reset_task_cur, &expected, UINT_MAX)__c11_atomic_compare_exchange_strong(&ttd->reset_task_cur , &expected, (2147483647 *2U +1U), 5, 5); | |||
| 95 | } | |||
| 96 | } | |||
| 97 | ||||
| 98 | static void insert_tasks_between(Dav1dFrameContext *const f, | |||
| 99 | Dav1dTask *const first, Dav1dTask *const last, | |||
| 100 | Dav1dTask *const a, Dav1dTask *const b, | |||
| 101 | const int cond_signal) | |||
| 102 | { | |||
| 103 | struct TaskThreadData *const ttd = f->task_thread.ttd; | |||
| 104 | if (atomic_load(f->c->flush)__c11_atomic_load(f->c->flush, 5)) return; | |||
| 105 | assert(!a || a->next == b)((void) sizeof ((!a || a->next == b) ? 1 : 0), __extension__ ({ if (!a || a->next == b) ; else __assert_fail ("!a || a->next == b" , "/root/firefox-clang/third_party/dav1d/src/thread_task.c", 105 , __extension__ __PRETTY_FUNCTION__); })); | |||
| 106 | if (!a) f->task_thread.task_head = first; | |||
| 107 | else a->next = first; | |||
| 108 | if (!b) f->task_thread.task_tail = last; | |||
| 109 | last->next = b; | |||
| 110 | reset_task_cur(f->c, ttd, first->frame_idx); | |||
| 111 | if (cond_signal && !atomic_fetch_or(&ttd->cond_signaled, 1)__c11_atomic_fetch_or(&ttd->cond_signaled, 1, 5)) | |||
| 112 | pthread_cond_signal(&ttd->cond); | |||
| 113 | } | |||
| 114 | ||||
| 115 | static void insert_tasks(Dav1dFrameContext *const f, | |||
| 116 | Dav1dTask *const first, Dav1dTask *const last, | |||
| 117 | const int cond_signal) | |||
| 118 | { | |||
| 119 | // insert task back into task queue | |||
| 120 | Dav1dTask *t_ptr, *prev_t = NULL((void*)0); | |||
| 121 | for (t_ptr = f->task_thread.task_head; | |||
| 122 | t_ptr; prev_t = t_ptr, t_ptr = t_ptr->next) | |||
| 123 | { | |||
| 124 | // entropy coding precedes other steps | |||
| 125 | if (t_ptr->type == DAV1D_TASK_TYPE_TILE_ENTROPY) { | |||
| 126 | if (first->type > DAV1D_TASK_TYPE_TILE_ENTROPY) continue; | |||
| 127 | // both are entropy | |||
| 128 | if (first->sby > t_ptr->sby) continue; | |||
| 129 | if (first->sby < t_ptr->sby) { | |||
| 130 | insert_tasks_between(f, first, last, prev_t, t_ptr, cond_signal); | |||
| 131 | return; | |||
| 132 | } | |||
| 133 | // same sby | |||
| 134 | } else { | |||
| 135 | if (first->type == DAV1D_TASK_TYPE_TILE_ENTROPY) { | |||
| 136 | insert_tasks_between(f, first, last, prev_t, t_ptr, cond_signal); | |||
| 137 | return; | |||
| 138 | } | |||
| 139 | if (first->sby > t_ptr->sby) continue; | |||
| 140 | if (first->sby < t_ptr->sby) { | |||
| 141 | insert_tasks_between(f, first, last, prev_t, t_ptr, cond_signal); | |||
| 142 | return; | |||
| 143 | } | |||
| 144 | // same sby | |||
| 145 | if (first->type > t_ptr->type) continue; | |||
| 146 | if (first->type < t_ptr->type) { | |||
| 147 | insert_tasks_between(f, first, last, prev_t, t_ptr, cond_signal); | |||
| 148 | return; | |||
| 149 | } | |||
| 150 | // same task type | |||
| 151 | } | |||
| 152 | ||||
| 153 | // sort by tile-id | |||
| 154 | assert(first->type == DAV1D_TASK_TYPE_TILE_RECONSTRUCTION ||((void) sizeof ((first->type == DAV1D_TASK_TYPE_TILE_RECONSTRUCTION || first->type == DAV1D_TASK_TYPE_TILE_ENTROPY) ? 1 : 0), __extension__ ({ if (first->type == DAV1D_TASK_TYPE_TILE_RECONSTRUCTION || first->type == DAV1D_TASK_TYPE_TILE_ENTROPY) ; else __assert_fail ("first->type == DAV1D_TASK_TYPE_TILE_RECONSTRUCTION || first->type == DAV1D_TASK_TYPE_TILE_ENTROPY" , "/root/firefox-clang/third_party/dav1d/src/thread_task.c", 155 , __extension__ __PRETTY_FUNCTION__); })) | |||
| 155 | first->type == DAV1D_TASK_TYPE_TILE_ENTROPY)((void) sizeof ((first->type == DAV1D_TASK_TYPE_TILE_RECONSTRUCTION || first->type == DAV1D_TASK_TYPE_TILE_ENTROPY) ? 1 : 0), __extension__ ({ if (first->type == DAV1D_TASK_TYPE_TILE_RECONSTRUCTION || first->type == DAV1D_TASK_TYPE_TILE_ENTROPY) ; else __assert_fail ("first->type == DAV1D_TASK_TYPE_TILE_RECONSTRUCTION || first->type == DAV1D_TASK_TYPE_TILE_ENTROPY" , "/root/firefox-clang/third_party/dav1d/src/thread_task.c", 155 , __extension__ __PRETTY_FUNCTION__); })); | |||
| 156 | assert(first->type == t_ptr->type)((void) sizeof ((first->type == t_ptr->type) ? 1 : 0), __extension__ ({ if (first->type == t_ptr->type) ; else __assert_fail ("first->type == t_ptr->type", "/root/firefox-clang/third_party/dav1d/src/thread_task.c" , 156, __extension__ __PRETTY_FUNCTION__); })); | |||
| 157 | assert(t_ptr->sby == first->sby)((void) sizeof ((t_ptr->sby == first->sby) ? 1 : 0), __extension__ ({ if (t_ptr->sby == first->sby) ; else __assert_fail ( "t_ptr->sby == first->sby", "/root/firefox-clang/third_party/dav1d/src/thread_task.c" , 157, __extension__ __PRETTY_FUNCTION__); })); | |||
| 158 | const int p = first->type == DAV1D_TASK_TYPE_TILE_ENTROPY; | |||
| 159 | const int t_tile_idx = (int) (first - f->task_thread.tile_tasks[p]); | |||
| 160 | const int p_tile_idx = (int) (t_ptr - f->task_thread.tile_tasks[p]); | |||
| 161 | assert(t_tile_idx != p_tile_idx)((void) sizeof ((t_tile_idx != p_tile_idx) ? 1 : 0), __extension__ ({ if (t_tile_idx != p_tile_idx) ; else __assert_fail ("t_tile_idx != p_tile_idx" , "/root/firefox-clang/third_party/dav1d/src/thread_task.c", 161 , __extension__ __PRETTY_FUNCTION__); })); | |||
| 162 | if (t_tile_idx > p_tile_idx) continue; | |||
| 163 | insert_tasks_between(f, first, last, prev_t, t_ptr, cond_signal); | |||
| 164 | return; | |||
| 165 | } | |||
| 166 | // append at the end | |||
| 167 | insert_tasks_between(f, first, last, prev_t, NULL((void*)0), cond_signal); | |||
| 168 | } | |||
| 169 | ||||
| 170 | static inline void insert_task(Dav1dFrameContext *const f, | |||
| 171 | Dav1dTask *const t, const int cond_signal) | |||
| 172 | { | |||
| 173 | insert_tasks(f, t, t, cond_signal); | |||
| 174 | } | |||
| 175 | ||||
| 176 | static inline void add_pending(Dav1dFrameContext *const f, Dav1dTask *const t) { | |||
| 177 | pthread_mutex_lock(&f->task_thread.pending_tasks.lock); | |||
| 178 | t->next = NULL((void*)0); | |||
| 179 | if (!f->task_thread.pending_tasks.head) | |||
| 180 | f->task_thread.pending_tasks.head = t; | |||
| 181 | else | |||
| 182 | f->task_thread.pending_tasks.tail->next = t; | |||
| 183 | f->task_thread.pending_tasks.tail = t; | |||
| 184 | atomic_store(&f->task_thread.pending_tasks.merge, 1)__c11_atomic_store(&f->task_thread.pending_tasks.merge , 1, 5); | |||
| 185 | pthread_mutex_unlock(&f->task_thread.pending_tasks.lock); | |||
| 186 | } | |||
| 187 | ||||
| 188 | static inline int merge_pending_frame(Dav1dFrameContext *const f) { | |||
| 189 | int const merge = atomic_load(&f->task_thread.pending_tasks.merge)__c11_atomic_load(&f->task_thread.pending_tasks.merge, 5); | |||
| 190 | if (merge) { | |||
| 191 | pthread_mutex_lock(&f->task_thread.pending_tasks.lock); | |||
| 192 | Dav1dTask *t = f->task_thread.pending_tasks.head; | |||
| 193 | f->task_thread.pending_tasks.head = NULL((void*)0); | |||
| 194 | f->task_thread.pending_tasks.tail = NULL((void*)0); | |||
| 195 | atomic_store(&f->task_thread.pending_tasks.merge, 0)__c11_atomic_store(&f->task_thread.pending_tasks.merge , 0, 5); | |||
| 196 | pthread_mutex_unlock(&f->task_thread.pending_tasks.lock); | |||
| 197 | while (t) { | |||
| 198 | Dav1dTask *const tmp = t->next; | |||
| 199 | insert_task(f, t, 0); | |||
| 200 | t = tmp; | |||
| 201 | } | |||
| 202 | } | |||
| 203 | return merge; | |||
| 204 | } | |||
| 205 | ||||
| 206 | static inline int merge_pending(const Dav1dContext *const c) { | |||
| 207 | int res = 0; | |||
| 208 | for (unsigned i = 0; i < c->n_fc; i++) | |||
| 209 | res |= merge_pending_frame(&c->fc[i]); | |||
| 210 | return res; | |||
| 211 | } | |||
| 212 | ||||
| 213 | static int create_filter_sbrow(Dav1dFrameContext *const f, | |||
| 214 | const int pass, Dav1dTask **res_t) | |||
| 215 | { | |||
| 216 | const int has_deblock = f->frame_hdr->loopfilter.level_y[0] || | |||
| 217 | f->frame_hdr->loopfilter.level_y[1]; | |||
| 218 | const int has_cdef = f->seq_hdr->cdef; | |||
| 219 | const int has_resize = f->frame_hdr->width[0] != f->frame_hdr->width[1]; | |||
| 220 | const int has_lr = f->lf.restore_planes; | |||
| 221 | ||||
| 222 | Dav1dTask *tasks = f->task_thread.tasks; | |||
| 223 | const int uses_2pass = f->c->n_fc
| |||
| 224 | int num_tasks = f->sbh * (1 + uses_2pass); | |||
| 225 | if (num_tasks > f->task_thread.num_tasks) { | |||
| 226 | const size_t size = sizeof(Dav1dTask) * num_tasks; | |||
| 227 | tasks = dav1d_realloc(ALLOC_COMMON_CTX, f->task_thread.tasks, size)realloc(f->task_thread.tasks, size); | |||
| 228 | if (!tasks) return -1; | |||
| 229 | memset(tasks, 0, size); | |||
| 230 | f->task_thread.tasks = tasks; | |||
| 231 | f->task_thread.num_tasks = num_tasks; | |||
| 232 | } | |||
| 233 | tasks += f->sbh * (pass & 1); | |||
| 234 | ||||
| 235 | if (pass & 1) { | |||
| 236 | f->frame_thread.entropy_progress = 0; | |||
| 237 | } else { | |||
| 238 | const int prog_sz = ((f->sbh + 31) & ~31) >> 5; | |||
| 239 | if (prog_sz > f->frame_thread.prog_sz) { | |||
| 240 | atomic_uint *const prog = dav1d_realloc(ALLOC_COMMON_CTX, f->frame_thread.frame_progress,realloc(f->frame_thread.frame_progress, 2 * prog_sz * sizeof (*prog)) | |||
| 241 | 2 * prog_sz * sizeof(*prog))realloc(f->frame_thread.frame_progress, 2 * prog_sz * sizeof (*prog)); | |||
| 242 | if (!prog) return -1; | |||
| 243 | f->frame_thread.frame_progress = prog; | |||
| 244 | f->frame_thread.copy_lpf_progress = prog + prog_sz; | |||
| 245 | } | |||
| 246 | f->frame_thread.prog_sz = prog_sz; | |||
| 247 | memset(f->frame_thread.frame_progress, 0, prog_sz * sizeof(atomic_uint)); | |||
| 248 | memset(f->frame_thread.copy_lpf_progress, 0, prog_sz * sizeof(atomic_uint)); | |||
| 249 | atomic_store(&f->frame_thread.deblock_progress, 0)__c11_atomic_store(&f->frame_thread.deblock_progress, 0 , 5); | |||
| 250 | } | |||
| 251 | f->frame_thread.next_tile_row[pass & 1] = 0; | |||
| 252 | ||||
| 253 | Dav1dTask *t = &tasks[0]; | |||
| 254 | t->sby = 0; | |||
| 255 | t->recon_progress = 1; | |||
| 256 | t->deblock_progress = 0; | |||
| 257 | t->type = pass
| |||
| 258 | has_deblock
| |||
| 259 | has_cdef || has_lr /* i.e. LR backup */ ? DAV1D_TASK_TYPE_DEBLOCK_ROWS : | |||
| 260 | has_resize ? DAV1D_TASK_TYPE_SUPER_RESOLUTION : | |||
| 261 | DAV1D_TASK_TYPE_RECONSTRUCTION_PROGRESS; | |||
| 262 | t->frame_idx = (int)(f - f->c->fc); | |||
| 263 | ||||
| 264 | *res_t = t; | |||
| 265 | return 0; | |||
| 266 | } | |||
| 267 | ||||
| 268 | int dav1d_task_create_tile_sbrow(Dav1dFrameContext *const f, const int pass, | |||
| 269 | const int cond_signal) | |||
| 270 | { | |||
| 271 | Dav1dTask *tasks = f->task_thread.tile_tasks[0]; | |||
| 272 | const int uses_2pass = f->c->n_fc > 1; | |||
| ||||
| 273 | const int n_tasks_per_pass = f->frame_hdr->tiling.cols * f->frame_hdr->tiling.rows; | |||
| 274 | const int n_tasks = n_tasks_per_pass * (1 + uses_2pass); | |||
| 275 | if (pass < 2) { | |||
| 276 | if (n_tasks > f->task_thread.num_tile_tasks) { | |||
| 277 | const size_t size = sizeof(Dav1dTask) * n_tasks; | |||
| 278 | tasks = dav1d_realloc(ALLOC_COMMON_CTX, f->task_thread.tile_tasks[0], size)realloc(f->task_thread.tile_tasks[0], size); | |||
| 279 | if (!tasks) return -1; | |||
| 280 | memset(tasks, 0, size); | |||
| 281 | f->task_thread.tile_tasks[0] = tasks; | |||
| 282 | f->task_thread.num_tile_tasks = n_tasks; | |||
| 283 | } | |||
| 284 | f->task_thread.tile_tasks[1] = tasks + n_tasks_per_pass; | |||
| 285 | } | |||
| 286 | assert(n_tasks <= f->task_thread.num_tile_tasks)((void) sizeof ((n_tasks <= f->task_thread.num_tile_tasks ) ? 1 : 0), __extension__ ({ if (n_tasks <= f->task_thread .num_tile_tasks) ; else __assert_fail ("n_tasks <= f->task_thread.num_tile_tasks" , "/root/firefox-clang/third_party/dav1d/src/thread_task.c", 286 , __extension__ __PRETTY_FUNCTION__); })); | |||
| 287 | ||||
| 288 | Dav1dTask *pf_t; | |||
| 289 | if (create_filter_sbrow(f, pass, &pf_t)) | |||
| 290 | return -1; | |||
| 291 | ||||
| 292 | Dav1dTask *const p1_tasks = f->task_thread.tile_tasks[1]; | |||
| 293 | Dav1dTask *prev_t = NULL((void*)0); | |||
| 294 | if (pass == 2) { | |||
| 295 | prev_t = &p1_tasks[n_tasks_per_pass - 1]; | |||
| 296 | // PF task is scheduled after the last sby=0 TILE task | |||
| 297 | if (f->frame_hdr->tiling.rows == 1) | |||
| 298 | prev_t = prev_t->next; | |||
| 299 | } | |||
| 300 | tasks += (pass & 1) * n_tasks_per_pass; | |||
| 301 | for (int tile_idx = 0; tile_idx < n_tasks_per_pass; tile_idx++) { | |||
| 302 | Dav1dTileState *const ts = &f->ts[tile_idx]; | |||
| 303 | Dav1dTask *t = &tasks[tile_idx]; | |||
| 304 | t->sby = ts->tiling.row_start >> f->sb_shift; | |||
| 305 | if (pf_t && t->sby) { | |||
| 306 | prev_t->next = pf_t; | |||
| 307 | prev_t = pf_t; | |||
| 308 | pf_t = NULL((void*)0); | |||
| 309 | } | |||
| 310 | t->recon_progress = 0; | |||
| 311 | t->deblock_progress = 0; | |||
| 312 | t->deps_skip = 0; | |||
| 313 | t->type = pass != 1 ? DAV1D_TASK_TYPE_TILE_RECONSTRUCTION : | |||
| 314 | DAV1D_TASK_TYPE_TILE_ENTROPY; | |||
| 315 | t->frame_idx = (int)(f - f->c->fc); | |||
| 316 | if (prev_t) prev_t->next = t; | |||
| 317 | prev_t = t; | |||
| 318 | } | |||
| 319 | if (pf_t
| |||
| 320 | prev_t->next = pf_t; | |||
| ||||
| 321 | prev_t = pf_t; | |||
| 322 | } | |||
| 323 | prev_t->next = NULL((void*)0); | |||
| 324 | ||||
| 325 | atomic_store(&f->task_thread.done[pass & 1], 0)__c11_atomic_store(&f->task_thread.done[pass & 1], 0, 5); | |||
| 326 | ||||
| 327 | // XXX in theory this could be done locklessly, at this point they are no | |||
| 328 | // tasks in the frameQ, so no other runner should be using this lock, but | |||
| 329 | // we must add both passes at once | |||
| 330 | if (!(pass & 1)) { | |||
| 331 | pthread_mutex_lock(&f->task_thread.pending_tasks.lock); | |||
| 332 | assert(f->task_thread.pending_tasks.head == NULL)((void) sizeof ((f->task_thread.pending_tasks.head == ((void *)0)) ? 1 : 0), __extension__ ({ if (f->task_thread.pending_tasks .head == ((void*)0)) ; else __assert_fail ("f->task_thread.pending_tasks.head == NULL" , "/root/firefox-clang/third_party/dav1d/src/thread_task.c", 332 , __extension__ __PRETTY_FUNCTION__); })); | |||
| 333 | f->task_thread.pending_tasks.head = f->task_thread.tile_tasks[pass == 2]; | |||
| 334 | f->task_thread.pending_tasks.tail = prev_t; | |||
| 335 | atomic_store(&f->task_thread.pending_tasks.merge, 1)__c11_atomic_store(&f->task_thread.pending_tasks.merge , 1, 5); | |||
| 336 | atomic_store(&f->task_thread.init_done, 1)__c11_atomic_store(&f->task_thread.init_done, 1, 5); | |||
| 337 | pthread_mutex_unlock(&f->task_thread.pending_tasks.lock); | |||
| 338 | } | |||
| 339 | return 0; | |||
| 340 | } | |||
| 341 | ||||
| 342 | void dav1d_task_frame_init(Dav1dFrameContext *const f) { | |||
| 343 | const Dav1dContext *const c = f->c; | |||
| 344 | ||||
| 345 | atomic_store(&f->task_thread.init_done, 0)__c11_atomic_store(&f->task_thread.init_done, 0, 5); | |||
| 346 | // schedule init task, which will schedule the remaining tasks | |||
| 347 | Dav1dTask *const t = &f->task_thread.init_task; | |||
| 348 | t->type = DAV1D_TASK_TYPE_INIT; | |||
| 349 | t->frame_idx = (int)(f - c->fc); | |||
| 350 | t->sby = 0; | |||
| 351 | t->recon_progress = t->deblock_progress = 0; | |||
| 352 | insert_task(f, t, 1); | |||
| 353 | } | |||
| 354 | ||||
| 355 | void dav1d_task_delayed_fg(Dav1dContext *const c, Dav1dPicture *const out, | |||
| 356 | const Dav1dPicture *const in) | |||
| 357 | { | |||
| 358 | struct TaskThreadData *const ttd = &c->task_thread; | |||
| 359 | ttd->delayed_fg.in = in; | |||
| 360 | ttd->delayed_fg.out = out; | |||
| 361 | ttd->delayed_fg.type = DAV1D_TASK_TYPE_FG_PREP; | |||
| 362 | atomic_init__c11_atomic_init(&ttd->delayed_fg.progress[0], 0); | |||
| 363 | atomic_init__c11_atomic_init(&ttd->delayed_fg.progress[1], 0); | |||
| 364 | pthread_mutex_lock(&ttd->lock); | |||
| 365 | ttd->delayed_fg.exec = 1; | |||
| 366 | ttd->delayed_fg.finished = 0; | |||
| 367 | pthread_cond_signal(&ttd->cond); | |||
| 368 | do { | |||
| 369 | pthread_cond_wait(&ttd->delayed_fg.cond, &ttd->lock); | |||
| 370 | } while (!ttd->delayed_fg.finished); | |||
| 371 | pthread_mutex_unlock(&ttd->lock); | |||
| 372 | } | |||
| 373 | ||||
| 374 | static inline int ensure_progress(struct TaskThreadData *const ttd, | |||
| 375 | Dav1dFrameContext *const f, | |||
| 376 | Dav1dTask *const t, const enum TaskType type, | |||
| 377 | atomic_int *const state, int *const target) | |||
| 378 | { | |||
| 379 | // deblock_rows (non-LR portion) depends on deblock of previous sbrow, | |||
| 380 | // so ensure that completed. if not, re-add to task-queue; else, fall-through | |||
| 381 | int p1 = atomic_load(state)__c11_atomic_load(state, 5); | |||
| 382 | if (p1 < t->sby) { | |||
| 383 | t->type = type; | |||
| 384 | t->recon_progress = t->deblock_progress = 0; | |||
| 385 | *target = t->sby; | |||
| 386 | add_pending(f, t); | |||
| 387 | pthread_mutex_lock(&ttd->lock); | |||
| 388 | return 1; | |||
| 389 | } | |||
| 390 | return 0; | |||
| 391 | } | |||
| 392 | ||||
| 393 | static inline int check_tile(Dav1dTask *const t, Dav1dFrameContext *const f, | |||
| 394 | const int frame_mt) | |||
| 395 | { | |||
| 396 | const int tp = t->type == DAV1D_TASK_TYPE_TILE_ENTROPY; | |||
| 397 | const int tile_idx = (int)(t - f->task_thread.tile_tasks[tp]); | |||
| 398 | Dav1dTileState *const ts = &f->ts[tile_idx]; | |||
| 399 | const int p1 = atomic_load(&ts->progress[tp])__c11_atomic_load(&ts->progress[tp], 5); | |||
| 400 | if (p1 < t->sby) return 1; | |||
| 401 | int error = p1 == TILE_ERROR(2147483647 - 1); | |||
| 402 | error |= atomic_fetch_or(&f->task_thread.error, error)__c11_atomic_fetch_or(&f->task_thread.error, error, 5); | |||
| 403 | if (!error && frame_mt && !tp) { | |||
| 404 | const int p2 = atomic_load(&ts->progress[1])__c11_atomic_load(&ts->progress[1], 5); | |||
| 405 | if (p2 <= t->sby) return 1; | |||
| 406 | error = p2 == TILE_ERROR(2147483647 - 1); | |||
| 407 | error |= atomic_fetch_or(&f->task_thread.error, error)__c11_atomic_fetch_or(&f->task_thread.error, error, 5); | |||
| 408 | } | |||
| 409 | if (!error && frame_mt && !IS_KEY_OR_INTRA(f->frame_hdr)(!((f->frame_hdr)->frame_type & 1))) { | |||
| 410 | // check reference state | |||
| 411 | const Dav1dThreadPicture *p = &f->sr_cur; | |||
| 412 | const int ss_ver = p->p.p.layout == DAV1D_PIXEL_LAYOUT_I420; | |||
| 413 | const unsigned p_b = (t->sby + 1) << (f->sb_shift + 2); | |||
| 414 | const int tile_sby = t->sby - (ts->tiling.row_start >> f->sb_shift); | |||
| 415 | const int (*const lowest_px)[2] = ts->lowest_pixel[tile_sby]; | |||
| 416 | for (int n = t->deps_skip; n < 7; n++, t->deps_skip++) { | |||
| 417 | unsigned lowest; | |||
| 418 | if (tp) { | |||
| 419 | // if temporal mv refs are disabled, we only need this | |||
| 420 | // for the primary ref; if segmentation is disabled, we | |||
| 421 | // don't even need that | |||
| 422 | lowest = p_b; | |||
| 423 | } else { | |||
| 424 | // +8 is postfilter-induced delay | |||
| 425 | const int y = lowest_px[n][0] == INT_MIN(-2147483647 -1) ? INT_MIN(-2147483647 -1) : | |||
| 426 | lowest_px[n][0] + 8; | |||
| 427 | const int uv = lowest_px[n][1] == INT_MIN(-2147483647 -1) ? INT_MIN(-2147483647 -1) : | |||
| 428 | lowest_px[n][1] * (1 << ss_ver) + 8; | |||
| 429 | const int max = imax(y, uv); | |||
| 430 | if (max == INT_MIN(-2147483647 -1)) continue; | |||
| 431 | lowest = iclip(max, 1, f->refp[n].p.p.h); | |||
| 432 | } | |||
| 433 | const unsigned p3 = atomic_load(&f->refp[n].progress[!tp])__c11_atomic_load(&f->refp[n].progress[!tp], 5); | |||
| 434 | if (p3 < lowest) return 1; | |||
| 435 | atomic_fetch_or(&f->task_thread.error, p3 == FRAME_ERROR)__c11_atomic_fetch_or(&f->task_thread.error, p3 == ((2147483647 *2U +1U) - 1), 5); | |||
| 436 | } | |||
| 437 | } | |||
| 438 | return 0; | |||
| 439 | } | |||
| 440 | ||||
| 441 | static inline int get_frame_progress(const Dav1dContext *const c, | |||
| 442 | const Dav1dFrameContext *const f) | |||
| 443 | { | |||
| 444 | unsigned frame_prog = c->n_fc > 1 ? atomic_load(&f->sr_cur.progress[1])__c11_atomic_load(&f->sr_cur.progress[1], 5) : 0; | |||
| 445 | if (frame_prog >= FRAME_ERROR((2147483647 *2U +1U) - 1)) | |||
| 446 | return f->sbh - 1; | |||
| 447 | int idx = frame_prog >> (f->sb_shift + 7); | |||
| 448 | int prog; | |||
| 449 | do { | |||
| 450 | atomic_uint *state = &f->frame_thread.frame_progress[idx]; | |||
| 451 | const unsigned val = ~atomic_load(state)__c11_atomic_load(state, 5); | |||
| 452 | prog = val ? ctz(val) : 32; | |||
| 453 | if (prog != 32) break; | |||
| 454 | prog = 0; | |||
| 455 | } while (++idx < f->frame_thread.prog_sz); | |||
| 456 | return ((idx << 5) | prog) - 1; | |||
| 457 | } | |||
| 458 | ||||
| 459 | static inline void abort_frame(Dav1dFrameContext *const f, const int error) { | |||
| 460 | atomic_store(&f->task_thread.error, error == DAV1D_ERR(EINVAL) ? 1 : -1)__c11_atomic_store(&f->task_thread.error, error == (-( 22)) ? 1 : -1, 5); | |||
| 461 | atomic_store(&f->task_thread.task_counter, 0)__c11_atomic_store(&f->task_thread.task_counter, 0, 5); | |||
| 462 | atomic_store(&f->task_thread.done[0], 1)__c11_atomic_store(&f->task_thread.done[0], 1, 5); | |||
| 463 | atomic_store(&f->task_thread.done[1], 1)__c11_atomic_store(&f->task_thread.done[1], 1, 5); | |||
| 464 | atomic_store(&f->sr_cur.progress[0], FRAME_ERROR)__c11_atomic_store(&f->sr_cur.progress[0], ((2147483647 *2U +1U) - 1), 5); | |||
| 465 | atomic_store(&f->sr_cur.progress[1], FRAME_ERROR)__c11_atomic_store(&f->sr_cur.progress[1], ((2147483647 *2U +1U) - 1), 5); | |||
| 466 | dav1d_decode_frame_exit(f, error); | |||
| 467 | f->n_tile_data = 0; | |||
| 468 | pthread_cond_signal(&f->task_thread.cond); | |||
| 469 | } | |||
| 470 | ||||
| 471 | static inline void delayed_fg_task(const Dav1dContext *const c, | |||
| 472 | struct TaskThreadData *const ttd) | |||
| 473 | { | |||
| 474 | const Dav1dPicture *const in = ttd->delayed_fg.in; | |||
| 475 | Dav1dPicture *const out = ttd->delayed_fg.out; | |||
| 476 | #if CONFIG_16BPC1 | |||
| 477 | int off; | |||
| 478 | if (out->p.bpc != 8) | |||
| 479 | off = (out->p.bpc >> 1) - 4; | |||
| 480 | #endif | |||
| 481 | switch (ttd->delayed_fg.type) { | |||
| 482 | case DAV1D_TASK_TYPE_FG_PREP: | |||
| 483 | ttd->delayed_fg.exec = 0; | |||
| 484 | if (atomic_load(&ttd->cond_signaled)__c11_atomic_load(&ttd->cond_signaled, 5)) | |||
| 485 | pthread_cond_signal(&ttd->cond); | |||
| 486 | pthread_mutex_unlock(&ttd->lock); | |||
| 487 | switch (out->p.bpc) { | |||
| 488 | #if CONFIG_8BPC1 | |||
| 489 | case 8: | |||
| 490 | dav1d_prep_grain_8bpc(&c->dsp[0].fg, out, in, | |||
| 491 | ttd->delayed_fg.scaling_8bpc, | |||
| 492 | ttd->delayed_fg.grain_lut_8bpc); | |||
| 493 | break; | |||
| 494 | #endif | |||
| 495 | #if CONFIG_16BPC1 | |||
| 496 | case 10: | |||
| 497 | case 12: | |||
| 498 | dav1d_prep_grain_16bpc(&c->dsp[off].fg, out, in, | |||
| 499 | ttd->delayed_fg.scaling_16bpc, | |||
| 500 | ttd->delayed_fg.grain_lut_16bpc); | |||
| 501 | break; | |||
| 502 | #endif | |||
| 503 | default: abort(); | |||
| 504 | } | |||
| 505 | ttd->delayed_fg.type = DAV1D_TASK_TYPE_FG_APPLY; | |||
| 506 | pthread_mutex_lock(&ttd->lock); | |||
| 507 | ttd->delayed_fg.exec = 1; | |||
| 508 | // fall-through | |||
| 509 | case DAV1D_TASK_TYPE_FG_APPLY:; | |||
| 510 | int row = atomic_fetch_add(&ttd->delayed_fg.progress[0], 1)__c11_atomic_fetch_add(&ttd->delayed_fg.progress[0], 1 , 5); | |||
| 511 | pthread_mutex_unlock(&ttd->lock); | |||
| 512 | int progmax = (out->p.h + FG_BLOCK_SIZE32 - 1) / FG_BLOCK_SIZE32; | |||
| 513 | while (row < progmax) { | |||
| 514 | if (row + 1 < progmax) | |||
| 515 | pthread_cond_signal(&ttd->cond); | |||
| 516 | else { | |||
| 517 | pthread_mutex_lock(&ttd->lock); | |||
| 518 | ttd->delayed_fg.exec = 0; | |||
| 519 | pthread_mutex_unlock(&ttd->lock); | |||
| 520 | } | |||
| 521 | switch (out->p.bpc) { | |||
| 522 | #if CONFIG_8BPC1 | |||
| 523 | case 8: | |||
| 524 | dav1d_apply_grain_row_8bpc(&c->dsp[0].fg, out, in, | |||
| 525 | ttd->delayed_fg.scaling_8bpc, | |||
| 526 | ttd->delayed_fg.grain_lut_8bpc, row); | |||
| 527 | break; | |||
| 528 | #endif | |||
| 529 | #if CONFIG_16BPC1 | |||
| 530 | case 10: | |||
| 531 | case 12: | |||
| 532 | dav1d_apply_grain_row_16bpc(&c->dsp[off].fg, out, in, | |||
| 533 | ttd->delayed_fg.scaling_16bpc, | |||
| 534 | ttd->delayed_fg.grain_lut_16bpc, row); | |||
| 535 | break; | |||
| 536 | #endif | |||
| 537 | default: abort(); | |||
| 538 | } | |||
| 539 | row = atomic_fetch_add(&ttd->delayed_fg.progress[0], 1)__c11_atomic_fetch_add(&ttd->delayed_fg.progress[0], 1 , 5); | |||
| 540 | atomic_fetch_add(&ttd->delayed_fg.progress[1], 1)__c11_atomic_fetch_add(&ttd->delayed_fg.progress[1], 1 , 5); | |||
| 541 | } | |||
| 542 | pthread_mutex_lock(&ttd->lock); | |||
| 543 | ttd->delayed_fg.exec = 0; | |||
| 544 | int done = atomic_fetch_add(&ttd->delayed_fg.progress[1], 1)__c11_atomic_fetch_add(&ttd->delayed_fg.progress[1], 1 , 5) + 1; | |||
| 545 | progmax = atomic_load(&ttd->delayed_fg.progress[0])__c11_atomic_load(&ttd->delayed_fg.progress[0], 5); | |||
| 546 | // signal for completion only once the last runner reaches this | |||
| 547 | if (done >= progmax) { | |||
| 548 | ttd->delayed_fg.finished = 1; | |||
| 549 | pthread_cond_signal(&ttd->delayed_fg.cond); | |||
| 550 | } | |||
| 551 | break; | |||
| 552 | default: abort(); | |||
| 553 | } | |||
| 554 | } | |||
| 555 | ||||
| 556 | void *dav1d_worker_task(void *data) { | |||
| 557 | Dav1dTaskContext *const tc = data; | |||
| 558 | const Dav1dContext *const c = tc->c; | |||
| 559 | struct TaskThreadData *const ttd = tc->task_thread.ttd; | |||
| 560 | ||||
| 561 | dav1d_set_thread_name("dav1d-worker"); | |||
| 562 | ||||
| 563 | pthread_mutex_lock(&ttd->lock); | |||
| 564 | for (;;) { | |||
| 565 | if (tc->task_thread.die) break; | |||
| 566 | if (atomic_load(c->flush)__c11_atomic_load(c->flush, 5)) goto park; | |||
| 567 | ||||
| 568 | merge_pending(c); | |||
| 569 | if (ttd->delayed_fg.exec) { // run delayed film grain first | |||
| 570 | delayed_fg_task(c, ttd); | |||
| 571 | continue; | |||
| 572 | } | |||
| 573 | Dav1dFrameContext *f; | |||
| 574 | Dav1dTask *t, *prev_t = NULL((void*)0); | |||
| 575 | if (c->n_fc > 1) { // run init tasks second | |||
| 576 | for (unsigned i = 0; i < c->n_fc; i++) { | |||
| 577 | const unsigned first = atomic_load(&ttd->first)__c11_atomic_load(&ttd->first, 5); | |||
| 578 | f = &c->fc[(first + i) % c->n_fc]; | |||
| 579 | if (atomic_load(&f->task_thread.init_done)__c11_atomic_load(&f->task_thread.init_done, 5)) continue; | |||
| 580 | t = f->task_thread.task_head; | |||
| 581 | if (!t) continue; | |||
| 582 | if (t->type == DAV1D_TASK_TYPE_INIT) goto found; | |||
| 583 | if (t->type == DAV1D_TASK_TYPE_INIT_CDF) { | |||
| 584 | // XXX This can be a simple else, if adding tasks of both | |||
| 585 | // passes at once (in dav1d_task_create_tile_sbrow). | |||
| 586 | // Adding the tasks to the pending Q can result in a | |||
| 587 | // thread merging them before setting init_done. | |||
| 588 | // We will need to set init_done before adding to the | |||
| 589 | // pending Q, so maybe return the tasks, set init_done, | |||
| 590 | // and add to pending Q only then. | |||
| 591 | const int p1 = f->in_cdf.progress ? | |||
| 592 | atomic_load(f->in_cdf.progress)__c11_atomic_load(f->in_cdf.progress, 5) : 1; | |||
| 593 | if (p1) { | |||
| 594 | atomic_fetch_or(&f->task_thread.error, p1 == TILE_ERROR)__c11_atomic_fetch_or(&f->task_thread.error, p1 == (2147483647 - 1), 5); | |||
| 595 | goto found; | |||
| 596 | } | |||
| 597 | } | |||
| 598 | } | |||
| 599 | } | |||
| 600 | while (ttd->cur < c->n_fc) { // run decoding tasks last | |||
| 601 | const unsigned first = atomic_load(&ttd->first)__c11_atomic_load(&ttd->first, 5); | |||
| 602 | f = &c->fc[(first + ttd->cur) % c->n_fc]; | |||
| 603 | merge_pending_frame(f); | |||
| 604 | prev_t = f->task_thread.task_cur_prev; | |||
| 605 | t = prev_t ? prev_t->next : f->task_thread.task_head; | |||
| 606 | while (t) { | |||
| 607 | if (t->type == DAV1D_TASK_TYPE_INIT_CDF) goto next; | |||
| 608 | else if (t->type == DAV1D_TASK_TYPE_TILE_ENTROPY || | |||
| 609 | t->type == DAV1D_TASK_TYPE_TILE_RECONSTRUCTION) | |||
| 610 | { | |||
| 611 | // if not bottom sbrow of tile, this task will be re-added | |||
| 612 | // after it's finished | |||
| 613 | if (!check_tile(t, f, c->n_fc > 1)) | |||
| 614 | goto found; | |||
| 615 | } else if (t->recon_progress) { | |||
| 616 | const int p = t->type == DAV1D_TASK_TYPE_ENTROPY_PROGRESS; | |||
| 617 | int error = atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5); | |||
| 618 | assert(!atomic_load(&f->task_thread.done[p]) || error)((void) sizeof ((!__c11_atomic_load(&f->task_thread.done [p], 5) || error) ? 1 : 0), __extension__ ({ if (!__c11_atomic_load (&f->task_thread.done[p], 5) || error) ; else __assert_fail ("!atomic_load(&f->task_thread.done[p]) || error", "/root/firefox-clang/third_party/dav1d/src/thread_task.c" , 618, __extension__ __PRETTY_FUNCTION__); })); | |||
| 619 | const int tile_row_base = f->frame_hdr->tiling.cols * | |||
| 620 | f->frame_thread.next_tile_row[p]; | |||
| 621 | if (p) { | |||
| 622 | atomic_int *const prog = &f->frame_thread.entropy_progress; | |||
| 623 | const int p1 = atomic_load(prog)__c11_atomic_load(prog, 5); | |||
| 624 | if (p1 < t->sby) goto next; | |||
| 625 | atomic_fetch_or(&f->task_thread.error, p1 == TILE_ERROR)__c11_atomic_fetch_or(&f->task_thread.error, p1 == (2147483647 - 1), 5); | |||
| 626 | } | |||
| 627 | for (int tc = 0; tc < f->frame_hdr->tiling.cols; tc++) { | |||
| 628 | Dav1dTileState *const ts = &f->ts[tile_row_base + tc]; | |||
| 629 | const int p2 = atomic_load(&ts->progress[p])__c11_atomic_load(&ts->progress[p], 5); | |||
| 630 | if (p2 < t->recon_progress) goto next; | |||
| 631 | atomic_fetch_or(&f->task_thread.error, p2 == TILE_ERROR)__c11_atomic_fetch_or(&f->task_thread.error, p2 == (2147483647 - 1), 5); | |||
| 632 | } | |||
| 633 | if (t->sby + 1 < f->sbh) { | |||
| 634 | // add sby+1 to list to replace this one | |||
| 635 | Dav1dTask *next_t = &t[1]; | |||
| 636 | *next_t = *t; | |||
| 637 | next_t->sby++; | |||
| 638 | const int ntr = f->frame_thread.next_tile_row[p] + 1; | |||
| 639 | const int start = f->frame_hdr->tiling.row_start_sb[ntr]; | |||
| 640 | if (next_t->sby == start) | |||
| 641 | f->frame_thread.next_tile_row[p] = ntr; | |||
| 642 | next_t->recon_progress = next_t->sby + 1; | |||
| 643 | insert_task(f, next_t, 0); | |||
| 644 | } | |||
| 645 | goto found; | |||
| 646 | } else if (t->type == DAV1D_TASK_TYPE_CDEF) { | |||
| 647 | atomic_uint *prog = f->frame_thread.copy_lpf_progress; | |||
| 648 | const int p1 = atomic_load(&prog[(t->sby - 1) >> 5])__c11_atomic_load(&prog[(t->sby - 1) >> 5], 5); | |||
| 649 | if (p1 & (1U << ((t->sby - 1) & 31))) | |||
| 650 | goto found; | |||
| 651 | } else { | |||
| 652 | assert(t->deblock_progress)((void) sizeof ((t->deblock_progress) ? 1 : 0), __extension__ ({ if (t->deblock_progress) ; else __assert_fail ("t->deblock_progress" , "/root/firefox-clang/third_party/dav1d/src/thread_task.c", 652 , __extension__ __PRETTY_FUNCTION__); })); | |||
| 653 | const int p1 = atomic_load(&f->frame_thread.deblock_progress)__c11_atomic_load(&f->frame_thread.deblock_progress, 5 ); | |||
| 654 | if (p1 >= t->deblock_progress) { | |||
| 655 | atomic_fetch_or(&f->task_thread.error, p1 == TILE_ERROR)__c11_atomic_fetch_or(&f->task_thread.error, p1 == (2147483647 - 1), 5); | |||
| 656 | goto found; | |||
| 657 | } | |||
| 658 | } | |||
| 659 | next: | |||
| 660 | prev_t = t; | |||
| 661 | t = t->next; | |||
| 662 | f->task_thread.task_cur_prev = prev_t; | |||
| 663 | } | |||
| 664 | ttd->cur++; | |||
| 665 | } | |||
| 666 | if (reset_task_cur(c, ttd, UINT_MAX(2147483647 *2U +1U))) continue; | |||
| 667 | if (merge_pending(c)) continue; | |||
| 668 | park: | |||
| 669 | tc->task_thread.flushed = 1; | |||
| 670 | pthread_cond_signal(&tc->task_thread.td.cond); | |||
| 671 | // we want to be woken up next time progress is signaled | |||
| 672 | atomic_store(&ttd->cond_signaled, 0)__c11_atomic_store(&ttd->cond_signaled, 0, 5); | |||
| 673 | pthread_cond_wait(&ttd->cond, &ttd->lock); | |||
| 674 | tc->task_thread.flushed = 0; | |||
| 675 | reset_task_cur(c, ttd, UINT_MAX(2147483647 *2U +1U)); | |||
| 676 | continue; | |||
| 677 | ||||
| 678 | found: | |||
| 679 | // remove t from list | |||
| 680 | if (prev_t) prev_t->next = t->next; | |||
| 681 | else f->task_thread.task_head = t->next; | |||
| 682 | if (!t->next) f->task_thread.task_tail = prev_t; | |||
| 683 | if (t->type > DAV1D_TASK_TYPE_INIT_CDF && !f->task_thread.task_head) | |||
| 684 | ttd->cur++; | |||
| 685 | t->next = NULL((void*)0); | |||
| 686 | // we don't need to check cond_signaled here, since we found a task | |||
| 687 | // after the last signal so we want to re-signal the next waiting thread | |||
| 688 | // and again won't need to signal after that | |||
| 689 | atomic_store(&ttd->cond_signaled, 1)__c11_atomic_store(&ttd->cond_signaled, 1, 5); | |||
| 690 | pthread_cond_signal(&ttd->cond); | |||
| 691 | pthread_mutex_unlock(&ttd->lock); | |||
| 692 | found_unlocked:; | |||
| 693 | const int flush = atomic_load(c->flush)__c11_atomic_load(c->flush, 5); | |||
| 694 | int error = atomic_fetch_or(&f->task_thread.error, flush)__c11_atomic_fetch_or(&f->task_thread.error, flush, 5) | flush; | |||
| 695 | ||||
| 696 | // run it | |||
| 697 | tc->f = f; | |||
| 698 | int sby = t->sby; | |||
| 699 | switch (t->type) { | |||
| 700 | case DAV1D_TASK_TYPE_INIT: { | |||
| 701 | assert(c->n_fc > 1)((void) sizeof ((c->n_fc > 1) ? 1 : 0), __extension__ ( { if (c->n_fc > 1) ; else __assert_fail ("c->n_fc > 1" , "/root/firefox-clang/third_party/dav1d/src/thread_task.c", 701 , __extension__ __PRETTY_FUNCTION__); })); | |||
| 702 | int res = dav1d_decode_frame_init(f); | |||
| 703 | int p1 = f->in_cdf.progress ? atomic_load(f->in_cdf.progress)__c11_atomic_load(f->in_cdf.progress, 5) : 1; | |||
| 704 | if (res || p1 == TILE_ERROR(2147483647 - 1)) { | |||
| 705 | pthread_mutex_lock(&ttd->lock); | |||
| 706 | abort_frame(f, res ? res : DAV1D_ERR(EINVAL)(-(22))); | |||
| 707 | reset_task_cur(c, ttd, t->frame_idx); | |||
| 708 | } else { | |||
| 709 | t->type = DAV1D_TASK_TYPE_INIT_CDF; | |||
| 710 | if (p1) goto found_unlocked; | |||
| 711 | add_pending(f, t); | |||
| 712 | pthread_mutex_lock(&ttd->lock); | |||
| 713 | } | |||
| 714 | continue; | |||
| 715 | } | |||
| 716 | case DAV1D_TASK_TYPE_INIT_CDF: { | |||
| 717 | assert(c->n_fc > 1)((void) sizeof ((c->n_fc > 1) ? 1 : 0), __extension__ ( { if (c->n_fc > 1) ; else __assert_fail ("c->n_fc > 1" , "/root/firefox-clang/third_party/dav1d/src/thread_task.c", 717 , __extension__ __PRETTY_FUNCTION__); })); | |||
| 718 | int res = DAV1D_ERR(EINVAL)(-(22)); | |||
| 719 | if (!atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5)) | |||
| 720 | res = dav1d_decode_frame_init_cdf(f); | |||
| 721 | if (f->frame_hdr->refresh_context && !f->task_thread.update_set) | |||
| 722 | atomic_store(f->out_cdf.progress, res < 0 ? TILE_ERROR : 1)__c11_atomic_store(f->out_cdf.progress, res < 0 ? (2147483647 - 1) : 1, 5); | |||
| 723 | for (int p = 1; p <= 2 && !res; p++) | |||
| 724 | res = dav1d_task_create_tile_sbrow(f, p, 0); | |||
| 725 | pthread_mutex_lock(&ttd->lock); | |||
| 726 | if (res) { | |||
| 727 | abort_frame(f, DAV1D_ERR(ENOMEM)(-(12))); | |||
| 728 | reset_task_cur(c, ttd, t->frame_idx); | |||
| 729 | atomic_store(&f->task_thread.init_done, 1)__c11_atomic_store(&f->task_thread.init_done, 1, 5); | |||
| 730 | } | |||
| 731 | continue; | |||
| 732 | } | |||
| 733 | case DAV1D_TASK_TYPE_TILE_ENTROPY: | |||
| 734 | case DAV1D_TASK_TYPE_TILE_RECONSTRUCTION: { | |||
| 735 | const int p = t->type == DAV1D_TASK_TYPE_TILE_ENTROPY; | |||
| 736 | const int tile_idx = (int)(t - f->task_thread.tile_tasks[p]); | |||
| 737 | Dav1dTileState *const ts = &f->ts[tile_idx]; | |||
| 738 | ||||
| 739 | tc->ts = ts; | |||
| 740 | tc->by = sby << f->sb_shift; | |||
| 741 | const int uses_2pass = c->n_fc > 1; | |||
| 742 | tc->frame_thread.pass = !uses_2pass ? 0 : | |||
| 743 | 1 + (t->type == DAV1D_TASK_TYPE_TILE_RECONSTRUCTION); | |||
| 744 | if (!error) error = dav1d_decode_tile_sbrow(tc); | |||
| 745 | const int progress = error ? TILE_ERROR(2147483647 - 1) : 1 + sby; | |||
| 746 | ||||
| 747 | // signal progress | |||
| 748 | atomic_fetch_or(&f->task_thread.error, error)__c11_atomic_fetch_or(&f->task_thread.error, error, 5); | |||
| 749 | if (((sby + 1) << f->sb_shift) < ts->tiling.row_end) { | |||
| 750 | t->sby++; | |||
| 751 | t->deps_skip = 0; | |||
| 752 | if (!check_tile(t, f, uses_2pass)) { | |||
| 753 | atomic_store(&ts->progress[p], progress)__c11_atomic_store(&ts->progress[p], progress, 5); | |||
| 754 | reset_task_cur_async(ttd, t->frame_idx, c->n_fc); | |||
| 755 | if (!atomic_fetch_or(&ttd->cond_signaled, 1)__c11_atomic_fetch_or(&ttd->cond_signaled, 1, 5)) | |||
| 756 | pthread_cond_signal(&ttd->cond); | |||
| 757 | goto found_unlocked; | |||
| 758 | } | |||
| 759 | atomic_store(&ts->progress[p], progress)__c11_atomic_store(&ts->progress[p], progress, 5); | |||
| 760 | add_pending(f, t); | |||
| 761 | pthread_mutex_lock(&ttd->lock); | |||
| 762 | } else { | |||
| 763 | pthread_mutex_lock(&ttd->lock); | |||
| 764 | atomic_store(&ts->progress[p], progress)__c11_atomic_store(&ts->progress[p], progress, 5); | |||
| 765 | reset_task_cur(c, ttd, t->frame_idx); | |||
| 766 | error = atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5); | |||
| 767 | if (f->frame_hdr->refresh_context && | |||
| 768 | tc->frame_thread.pass <= 1 && f->task_thread.update_set && | |||
| 769 | f->frame_hdr->tiling.update == tile_idx) | |||
| 770 | { | |||
| 771 | if (!error) | |||
| 772 | dav1d_cdf_thread_update(f->frame_hdr, f->out_cdf.data.cdf, | |||
| 773 | &f->ts[f->frame_hdr->tiling.update].cdf); | |||
| 774 | if (c->n_fc > 1) | |||
| 775 | atomic_store(f->out_cdf.progress, error ? TILE_ERROR : 1)__c11_atomic_store(f->out_cdf.progress, error ? (2147483647 - 1) : 1, 5); | |||
| 776 | } | |||
| 777 | if (atomic_fetch_sub(&f->task_thread.task_counter, 1)__c11_atomic_fetch_sub(&f->task_thread.task_counter, 1 , 5) - 1 == 0 && | |||
| 778 | atomic_load(&f->task_thread.done[0])__c11_atomic_load(&f->task_thread.done[0], 5) && | |||
| 779 | (!uses_2pass || atomic_load(&f->task_thread.done[1])__c11_atomic_load(&f->task_thread.done[1], 5))) | |||
| 780 | { | |||
| 781 | error = atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5); | |||
| 782 | dav1d_decode_frame_exit(f, error == 1 ? DAV1D_ERR(EINVAL)(-(22)) : | |||
| 783 | error ? DAV1D_ERR(ENOMEM)(-(12)) : 0); | |||
| 784 | f->n_tile_data = 0; | |||
| 785 | pthread_cond_signal(&f->task_thread.cond); | |||
| 786 | } | |||
| 787 | assert(atomic_load(&f->task_thread.task_counter) >= 0)((void) sizeof ((__c11_atomic_load(&f->task_thread.task_counter , 5) >= 0) ? 1 : 0), __extension__ ({ if (__c11_atomic_load (&f->task_thread.task_counter, 5) >= 0) ; else __assert_fail ("atomic_load(&f->task_thread.task_counter) >= 0", "/root/firefox-clang/third_party/dav1d/src/thread_task.c", 787 , __extension__ __PRETTY_FUNCTION__); })); | |||
| 788 | if (!atomic_fetch_or(&ttd->cond_signaled, 1)__c11_atomic_fetch_or(&ttd->cond_signaled, 1, 5)) | |||
| 789 | pthread_cond_signal(&ttd->cond); | |||
| 790 | } | |||
| 791 | continue; | |||
| 792 | } | |||
| 793 | case DAV1D_TASK_TYPE_DEBLOCK_COLS: | |||
| 794 | if (!atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5)) | |||
| 795 | f->bd_fn.filter_sbrow_deblock_cols(f, sby); | |||
| 796 | if (ensure_progress(ttd, f, t, DAV1D_TASK_TYPE_DEBLOCK_ROWS, | |||
| 797 | &f->frame_thread.deblock_progress, | |||
| 798 | &t->deblock_progress)) continue; | |||
| 799 | // fall-through | |||
| 800 | case DAV1D_TASK_TYPE_DEBLOCK_ROWS: | |||
| 801 | if (!atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5)) | |||
| 802 | f->bd_fn.filter_sbrow_deblock_rows(f, sby); | |||
| 803 | // signal deblock progress | |||
| 804 | if (f->frame_hdr->loopfilter.level_y[0] || | |||
| 805 | f->frame_hdr->loopfilter.level_y[1]) | |||
| 806 | { | |||
| 807 | error = atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5); | |||
| 808 | atomic_store(&f->frame_thread.deblock_progress,__c11_atomic_store(&f->frame_thread.deblock_progress, error ? (2147483647 - 1) : sby + 1, 5) | |||
| 809 | error ? TILE_ERROR : sby + 1)__c11_atomic_store(&f->frame_thread.deblock_progress, error ? (2147483647 - 1) : sby + 1, 5); | |||
| 810 | reset_task_cur_async(ttd, t->frame_idx, c->n_fc); | |||
| 811 | if (!atomic_fetch_or(&ttd->cond_signaled, 1)__c11_atomic_fetch_or(&ttd->cond_signaled, 1, 5)) | |||
| 812 | pthread_cond_signal(&ttd->cond); | |||
| 813 | } else if (f->seq_hdr->cdef || f->lf.restore_planes) { | |||
| 814 | atomic_fetch_or(&f->frame_thread.copy_lpf_progress[sby >> 5],__c11_atomic_fetch_or(&f->frame_thread.copy_lpf_progress [sby >> 5], 1U << (sby & 31), 5) | |||
| 815 | 1U << (sby & 31))__c11_atomic_fetch_or(&f->frame_thread.copy_lpf_progress [sby >> 5], 1U << (sby & 31), 5); | |||
| 816 | // CDEF needs the top buffer to be saved by lr_copy_lpf of the | |||
| 817 | // previous sbrow | |||
| 818 | if (sby) { | |||
| 819 | int prog = atomic_load(&f->frame_thread.copy_lpf_progress[(sby - 1) >> 5])__c11_atomic_load(&f->frame_thread.copy_lpf_progress[( sby - 1) >> 5], 5); | |||
| 820 | if (~prog & (1U << ((sby - 1) & 31))) { | |||
| 821 | t->type = DAV1D_TASK_TYPE_CDEF; | |||
| 822 | t->recon_progress = t->deblock_progress = 0; | |||
| 823 | add_pending(f, t); | |||
| 824 | pthread_mutex_lock(&ttd->lock); | |||
| 825 | continue; | |||
| 826 | } | |||
| 827 | } | |||
| 828 | } | |||
| 829 | // fall-through | |||
| 830 | case DAV1D_TASK_TYPE_CDEF: | |||
| 831 | if (f->seq_hdr->cdef) { | |||
| 832 | if (!atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5)) | |||
| 833 | f->bd_fn.filter_sbrow_cdef(tc, sby); | |||
| 834 | reset_task_cur_async(ttd, t->frame_idx, c->n_fc); | |||
| 835 | if (!atomic_fetch_or(&ttd->cond_signaled, 1)__c11_atomic_fetch_or(&ttd->cond_signaled, 1, 5)) | |||
| 836 | pthread_cond_signal(&ttd->cond); | |||
| 837 | } | |||
| 838 | // fall-through | |||
| 839 | case DAV1D_TASK_TYPE_SUPER_RESOLUTION: | |||
| 840 | if (f->frame_hdr->width[0] != f->frame_hdr->width[1]) | |||
| 841 | if (!atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5)) | |||
| 842 | f->bd_fn.filter_sbrow_resize(f, sby); | |||
| 843 | // fall-through | |||
| 844 | case DAV1D_TASK_TYPE_LOOP_RESTORATION: | |||
| 845 | if (!atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5) && f->lf.restore_planes) | |||
| 846 | f->bd_fn.filter_sbrow_lr(f, sby); | |||
| 847 | // fall-through | |||
| 848 | case DAV1D_TASK_TYPE_RECONSTRUCTION_PROGRESS: | |||
| 849 | // dummy to cover for no post-filters | |||
| 850 | case DAV1D_TASK_TYPE_ENTROPY_PROGRESS: | |||
| 851 | // dummy to convert tile progress to frame | |||
| 852 | break; | |||
| 853 | default: abort(); | |||
| 854 | } | |||
| 855 | // if task completed [typically LR], signal picture progress as per below | |||
| 856 | const int uses_2pass = c->n_fc > 1; | |||
| 857 | const int sbh = f->sbh; | |||
| 858 | const int sbsz = f->sb_step * 4; | |||
| 859 | if (t->type == DAV1D_TASK_TYPE_ENTROPY_PROGRESS) { | |||
| 860 | error = atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5); | |||
| 861 | const unsigned y = sby + 1 == sbh ? UINT_MAX(2147483647 *2U +1U) : (unsigned)(sby + 1) * sbsz; | |||
| 862 | assert(c->n_fc > 1)((void) sizeof ((c->n_fc > 1) ? 1 : 0), __extension__ ( { if (c->n_fc > 1) ; else __assert_fail ("c->n_fc > 1" , "/root/firefox-clang/third_party/dav1d/src/thread_task.c", 862 , __extension__ __PRETTY_FUNCTION__); })); | |||
| 863 | if (f->sr_cur.p.data[0] /* upon flush, this can be free'ed already */) | |||
| 864 | atomic_store(&f->sr_cur.progress[0], error ? FRAME_ERROR : y)__c11_atomic_store(&f->sr_cur.progress[0], error ? ((2147483647 *2U +1U) - 1) : y, 5); | |||
| 865 | atomic_store(&f->frame_thread.entropy_progress,__c11_atomic_store(&f->frame_thread.entropy_progress, error ? (2147483647 - 1) : sby + 1, 5) | |||
| 866 | error ? TILE_ERROR : sby + 1)__c11_atomic_store(&f->frame_thread.entropy_progress, error ? (2147483647 - 1) : sby + 1, 5); | |||
| 867 | if (sby + 1 == sbh) | |||
| 868 | atomic_store(&f->task_thread.done[1], 1)__c11_atomic_store(&f->task_thread.done[1], 1, 5); | |||
| 869 | pthread_mutex_lock(&ttd->lock); | |||
| 870 | const int num_tasks = atomic_fetch_sub(&f->task_thread.task_counter, 1)__c11_atomic_fetch_sub(&f->task_thread.task_counter, 1 , 5) - 1; | |||
| 871 | if (sby + 1 < sbh && num_tasks) { | |||
| 872 | reset_task_cur(c, ttd, t->frame_idx); | |||
| 873 | continue; | |||
| 874 | } | |||
| 875 | if (!num_tasks && atomic_load(&f->task_thread.done[0])__c11_atomic_load(&f->task_thread.done[0], 5) && | |||
| 876 | atomic_load(&f->task_thread.done[1])__c11_atomic_load(&f->task_thread.done[1], 5)) | |||
| 877 | { | |||
| 878 | error = atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5); | |||
| 879 | dav1d_decode_frame_exit(f, error == 1 ? DAV1D_ERR(EINVAL)(-(22)) : | |||
| 880 | error ? DAV1D_ERR(ENOMEM)(-(12)) : 0); | |||
| 881 | f->n_tile_data = 0; | |||
| 882 | pthread_cond_signal(&f->task_thread.cond); | |||
| 883 | } | |||
| 884 | reset_task_cur(c, ttd, t->frame_idx); | |||
| 885 | continue; | |||
| 886 | } | |||
| 887 | // t->type != DAV1D_TASK_TYPE_ENTROPY_PROGRESS | |||
| 888 | atomic_fetch_or(&f->frame_thread.frame_progress[sby >> 5],__c11_atomic_fetch_or(&f->frame_thread.frame_progress[ sby >> 5], 1U << (sby & 31), 5) | |||
| 889 | 1U << (sby & 31))__c11_atomic_fetch_or(&f->frame_thread.frame_progress[ sby >> 5], 1U << (sby & 31), 5); | |||
| 890 | pthread_mutex_lock(&f->task_thread.lock); | |||
| 891 | sby = get_frame_progress(c, f); | |||
| 892 | error = atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5); | |||
| 893 | const unsigned y = sby + 1 == sbh ? UINT_MAX(2147483647 *2U +1U) : (unsigned)(sby + 1) * sbsz; | |||
| 894 | if (c->n_fc > 1 && f->sr_cur.p.data[0] /* upon flush, this can be free'ed already */) | |||
| 895 | atomic_store(&f->sr_cur.progress[1], error ? FRAME_ERROR : y)__c11_atomic_store(&f->sr_cur.progress[1], error ? ((2147483647 *2U +1U) - 1) : y, 5); | |||
| 896 | pthread_mutex_unlock(&f->task_thread.lock); | |||
| 897 | if (sby + 1 == sbh) | |||
| 898 | atomic_store(&f->task_thread.done[0], 1)__c11_atomic_store(&f->task_thread.done[0], 1, 5); | |||
| 899 | pthread_mutex_lock(&ttd->lock); | |||
| 900 | const int num_tasks = atomic_fetch_sub(&f->task_thread.task_counter, 1)__c11_atomic_fetch_sub(&f->task_thread.task_counter, 1 , 5) - 1; | |||
| 901 | if (sby + 1 < sbh && num_tasks) { | |||
| 902 | reset_task_cur(c, ttd, t->frame_idx); | |||
| 903 | continue; | |||
| 904 | } | |||
| 905 | if (!num_tasks && atomic_load(&f->task_thread.done[0])__c11_atomic_load(&f->task_thread.done[0], 5) && | |||
| 906 | (!uses_2pass || atomic_load(&f->task_thread.done[1])__c11_atomic_load(&f->task_thread.done[1], 5))) | |||
| 907 | { | |||
| 908 | error = atomic_load(&f->task_thread.error)__c11_atomic_load(&f->task_thread.error, 5); | |||
| 909 | dav1d_decode_frame_exit(f, error == 1 ? DAV1D_ERR(EINVAL)(-(22)) : | |||
| 910 | error ? DAV1D_ERR(ENOMEM)(-(12)) : 0); | |||
| 911 | f->n_tile_data = 0; | |||
| 912 | pthread_cond_signal(&f->task_thread.cond); | |||
| 913 | } | |||
| 914 | reset_task_cur(c, ttd, t->frame_idx); | |||
| 915 | } | |||
| 916 | pthread_mutex_unlock(&ttd->lock); | |||
| 917 | ||||
| 918 | return NULL((void*)0); | |||
| 919 | } |