History

Initial decoder implementation.

With minor contributions from: - Jean-Baptiste Kempf <jb@videolan.org> - Marvin Scholz <epirat07@gmail.com> - Hugo Beauzée-Luyssen <hugo@videolan.org>

Ronald S. Bultje committed 8 years ago

Commit e2892ff1 parent d32eb2d89 files · +30590 −2Browse files

Showing the changes to src/thread_task.c (1 of 89 files). Show all

Unified · Split

src/thread_task.c+137−0
@@ -0,0 +1,137 @@
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 "src/thread_task.h"
31+
32+void *dav1d_frame_task(void *const data) {
33+ Dav1dFrameContext *const f = data;
34+
35+ for (;;) {
36+ pthread_mutex_lock(&f->frame_thread.td.lock);
37+ f->n_tile_data = 0;
38+ int did_signal = 0;
39+ while (!f->n_tile_data && !f->frame_thread.die) {
40+ if (!did_signal) {
41+ did_signal = 1;
42+ pthread_cond_signal(&f->frame_thread.td.cond);
43+ }
44+ pthread_cond_wait(&f->frame_thread.td.cond,
45+ &f->frame_thread.td.lock);
46+ }
47+ if (f->frame_thread.die) {
48+ pthread_mutex_unlock(&f->frame_thread.td.lock);
49+ break;
50+ }
51+ pthread_mutex_unlock(&f->frame_thread.td.lock);
52+
53+ decode_frame(f);
54+ }
55+
56+ pthread_exit(NULL);
57+ return NULL;
58+}
59+
60+void *dav1d_tile_task(void *const data) {
61+ Dav1dTileContext *const t = data;
62+ struct FrameTileThreadData *const fttd = t->tile_thread.fttd;
63+ const Dav1dFrameContext *const f = t->f;
64+ const int tile_thread_idx = t - f->tc;
65+ const uint64_t mask = 1ULL << tile_thread_idx;
66+
67+ for (;;) {
68+ pthread_mutex_lock(&fttd->lock);
69+ fttd->available |= mask;
70+ int did_signal = 0;
71+ while (!fttd->tasks_left && !t->tile_thread.die) {
72+ if (!did_signal) {
73+ did_signal = 1;
74+ pthread_cond_signal(&fttd->icond);
75+ }
76+ pthread_cond_wait(&fttd->cond, &fttd->lock);
77+ }
78+ if (t->tile_thread.die) {
79+ pthread_mutex_unlock(&fttd->lock);
80+ break;
81+ }
82+ fttd->available &= ~mask;
83+ const int task_idx = fttd->num_tasks - fttd->tasks_left--;
84+ pthread_mutex_unlock(&fttd->lock);
85+
86+ if (f->frame_thread.pass == 1 || f->n_tc >= f->frame_hdr.tiling.cols) {
87+ // we can (or in fact, if >, we need to) do full tile decoding.
88+ // loopfilter happens in the main thread
89+ Dav1dTileState *const ts = t->ts = &f->ts[task_idx];
90+ for (t->by = ts->tiling.row_start; t->by < ts->tiling.row_end;
91+ t->by += f->sb_step)
92+ {
93+ decode_tile_sbrow(t);
94+
95+ // signal progress
96+ pthread_mutex_lock(&ts->tile_thread.lock);
97+ atomic_store(&ts->progress, 1 + (t->by >> f->sb_shift));
98+ pthread_cond_signal(&ts->tile_thread.cond);
99+ pthread_mutex_unlock(&ts->tile_thread.lock);
100+ }
101+ } else {
102+ const int sby = f->tile_thread.task_idx_to_sby_and_tile_idx[task_idx][0];
103+ const int tile_idx = f->tile_thread.task_idx_to_sby_and_tile_idx[task_idx][1];
104+ Dav1dTileState *const ts = &f->ts[tile_idx];
105+
106+ // the interleaved decoding can sometimes cause dependency issues
107+ // if one part of the frame decodes signifcantly faster than others.
108+ // Ideally, we'd "skip" tile_sbrows where dependencies are missing,
109+ // and resume them later as dependencies are met. This also would
110+ // solve the broadcast() below and allow us to use signal(). However,
111+ // for now, we use linear dependency tracking because it's simpler.
112+ if (atomic_load(&ts->progress) < sby) {
113+ pthread_mutex_lock(&ts->tile_thread.lock);
114+ while (atomic_load(&ts->progress) < sby)
115+ pthread_cond_wait(&ts->tile_thread.cond,
116+ &ts->tile_thread.lock);
117+ pthread_mutex_unlock(&ts->tile_thread.lock);
118+ }
119+
120+ // we need to interleave sbrow decoding for all tile cols in a
121+ // tile row, since otherwise subsequent threads will be blocked
122+ // waiting for the post-filter to complete
123+ t->ts = ts;
124+ t->by = sby << f->sb_shift;
125+ decode_tile_sbrow(t);
126+
127+ // signal progress
128+ pthread_mutex_lock(&ts->tile_thread.lock);
129+ atomic_store(&ts->progress, 1 + sby);
130+ pthread_cond_broadcast(&ts->tile_thread.cond);
131+ pthread_mutex_unlock(&ts->tile_thread.lock);
132+ }
133+ }
134+
135+ pthread_exit(NULL);
136+ return NULL;
137+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t