ref: 06983668cf41f66765528db044419f954e5a5d64
parent: 6aa308abfb681b532c67cda0070c98d830db3549
author: James Zern <jzern@google.com>
date: Sat Dec 22 04:26:29 EST 2018
Revert "Add Tile-SB-Row based Multi-threading in Decoder" This reverts commit 02b3ef7faee5be5ee519856fbb3523d3ab49f6e7. Reason for revert: fails to build under visual studio Original change's description: > Add Tile-SB-Row based Multi-threading in Decoder > > Add the multi-thread function that decodes a video row by row instead > of a tile at a time. Create a job queue for queueing all parse and recon jobs. > Each SB row of a tile is a job. > > Performance Improvement: > > Platform Resolution 3 Threads 4 Threads > ARM 720p 36.81% 18.37% > 1080p 32.27% 14.76% > > ARM Improvement measured on Nexus 6 Snapdragon 805 Quad-core @ 2.65 GHz > > Change-Id: I3d4dd7a932fc2904c90d9546b2de99c809afd29e BUG=webm:1587 Change-Id: Ia4c8f5128922a205cd9fd83aaef8a2e73764d4a7
--- a/vp9/common/vp9_enums.h
+++ b/vp9/common/vp9_enums.h
@@ -41,8 +41,6 @@
MAX_PROFILES
} BITSTREAM_PROFILE;
-typedef enum PARSE_RECON_FLAG { PARSE = 1, RECON = 2 } PARSE_RECON_FLAG;
-
#define BLOCK_4X4 0
#define BLOCK_4X8 1
#define BLOCK_8X4 2
--- a/vp9/common/vp9_thread_common.c
+++ b/vp9/common/vp9_thread_common.c
@@ -475,12 +475,6 @@
#endif // CONFIG_MULTITHREAD
}
-void vp9_loopfilter_job(LFWorkerData *lf_data, VP9LfSync *lf_sync) {
- thread_loop_filter_rows(lf_data->frame_buffer, lf_data->cm, lf_data->planes,
- lf_data->start, lf_data->stop, lf_data->y_only,
- lf_sync);
-}
-
// Accumulate frame counts.
void vp9_accumulate_frame_counts(FRAME_COUNTS *accum,
const FRAME_COUNTS *counts, int is_dec) {
--- a/vp9/common/vp9_thread_common.h
+++ b/vp9/common/vp9_thread_common.h
@@ -70,7 +70,7 @@
void vp9_set_row(VP9LfSync *lf_sync, int num_tiles, int row, int is_last_row,
int corrupted);
-void vp9_loopfilter_job(LFWorkerData *lf_data, VP9LfSync *lf_sync);
+void vp9_set_last_decoded_row(struct VP9Common *cm, int tile_col, int mi_row);
void vp9_accumulate_frame_counts(struct FRAME_COUNTS *accum,
const struct FRAME_COUNTS *counts, int is_dec);
--- a/vp9/decoder/vp9_decodeframe.c
+++ b/vp9/decoder/vp9_decodeframe.c
@@ -42,7 +42,6 @@
#include "vp9/decoder/vp9_decodemv.h"
#include "vp9/decoder/vp9_decoder.h"
#include "vp9/decoder/vp9_dsubexp.h"
-#include "vp9/decoder/vp9_job_queue.h"
#define MAX_VP9_HEADER_SIZE 80
@@ -1028,6 +1027,7 @@
static void parse_block(TileWorkerData *twd, VP9Decoder *const pbi, int mi_row,
int mi_col, BLOCK_SIZE bsize, int bwl, int bhl) {
VP9_COMMON *const cm = &pbi->common;
+ const int less8x8 = bsize < BLOCK_8X8;
const int bw = 1 << (bwl - 1);
const int bh = 1 << (bhl - 1);
const int x_mis = VPXMIN(bw, cm->mi_cols - mi_col);
@@ -1059,7 +1059,7 @@
const int eobtotal =
predict_recon_inter(xd, mi, twd, parse_inter_block_row_mt);
- if (bsize >= BLOCK_8X8 && eobtotal == 0) mi->skip = 1; // skip loopfilter
+ if (!less8x8 && eobtotal == 0) mi->skip = 1; // skip loopfilter
}
}
@@ -1172,10 +1172,9 @@
dec_update_partition_context(twd, mi_row, mi_col, subsize, num_8x8_wh);
}
-static void process_partition(TileWorkerData *twd, VP9Decoder *const pbi,
- int mi_row, int mi_col, BLOCK_SIZE bsize,
- int n4x4_l2, int parse_recon_flag,
- process_block_fn_t process_block) {
+static void recon_partition(TileWorkerData *twd, VP9Decoder *const pbi,
+ int mi_row, int mi_col, BLOCK_SIZE bsize,
+ int n4x4_l2) {
VP9_COMMON *const cm = &pbi->common;
const int n8x8_l2 = n4x4_l2 - 1;
const int num_8x8_wh = 1 << n8x8_l2;
@@ -1188,11 +1187,61 @@
if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
- if (parse_recon_flag & PARSE) {
- *xd->partition =
- read_partition(twd, mi_row, mi_col, has_rows, has_cols, n8x8_l2);
+ partition = *xd->partition;
+ xd->partition++;
+
+ subsize = get_subsize(bsize, partition);
+ if (!hbs) {
+ // calculate bmode block dimensions (log 2)
+ xd->bmode_blocks_wl = 1 >> !!(partition & PARTITION_VERT);
+ xd->bmode_blocks_hl = 1 >> !!(partition & PARTITION_HORZ);
+ recon_block(twd, pbi, mi_row, mi_col, subsize, 1, 1);
+ } else {
+ switch (partition) {
+ case PARTITION_NONE:
+ recon_block(twd, pbi, mi_row, mi_col, subsize, n4x4_l2, n4x4_l2);
+ break;
+ case PARTITION_HORZ:
+ recon_block(twd, pbi, mi_row, mi_col, subsize, n4x4_l2, n8x8_l2);
+ if (has_rows)
+ recon_block(twd, pbi, mi_row + hbs, mi_col, subsize, n4x4_l2,
+ n8x8_l2);
+ break;
+ case PARTITION_VERT:
+ recon_block(twd, pbi, mi_row, mi_col, subsize, n8x8_l2, n4x4_l2);
+ if (has_cols)
+ recon_block(twd, pbi, mi_row, mi_col + hbs, subsize, n8x8_l2,
+ n4x4_l2);
+ break;
+ case PARTITION_SPLIT:
+ recon_partition(twd, pbi, mi_row, mi_col, subsize, n8x8_l2);
+ recon_partition(twd, pbi, mi_row, mi_col + hbs, subsize, n8x8_l2);
+ recon_partition(twd, pbi, mi_row + hbs, mi_col, subsize, n8x8_l2);
+ recon_partition(twd, pbi, mi_row + hbs, mi_col + hbs, subsize, n8x8_l2);
+ break;
+ default: assert(0 && "Invalid partition type");
+ }
}
+}
+static void parse_partition(TileWorkerData *twd, VP9Decoder *const pbi,
+ int mi_row, int mi_col, BLOCK_SIZE bsize,
+ int n4x4_l2) {
+ VP9_COMMON *const cm = &pbi->common;
+ const int n8x8_l2 = n4x4_l2 - 1;
+ const int num_8x8_wh = 1 << n8x8_l2;
+ const int hbs = num_8x8_wh >> 1;
+ PARTITION_TYPE partition;
+ BLOCK_SIZE subsize;
+ const int has_rows = (mi_row + hbs) < cm->mi_rows;
+ const int has_cols = (mi_col + hbs) < cm->mi_cols;
+ MACROBLOCKD *const xd = &twd->xd;
+
+ if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
+
+ *xd->partition =
+ read_partition(twd, mi_row, mi_col, has_rows, has_cols, n8x8_l2);
+
partition = *xd->partition;
xd->partition++;
@@ -1201,44 +1250,38 @@
// calculate bmode block dimensions (log 2)
xd->bmode_blocks_wl = 1 >> !!(partition & PARTITION_VERT);
xd->bmode_blocks_hl = 1 >> !!(partition & PARTITION_HORZ);
- process_block(twd, pbi, mi_row, mi_col, subsize, 1, 1);
+ parse_block(twd, pbi, mi_row, mi_col, subsize, 1, 1);
} else {
switch (partition) {
case PARTITION_NONE:
- process_block(twd, pbi, mi_row, mi_col, subsize, n4x4_l2, n4x4_l2);
+ parse_block(twd, pbi, mi_row, mi_col, subsize, n4x4_l2, n4x4_l2);
break;
case PARTITION_HORZ:
- process_block(twd, pbi, mi_row, mi_col, subsize, n4x4_l2, n8x8_l2);
+ parse_block(twd, pbi, mi_row, mi_col, subsize, n4x4_l2, n8x8_l2);
if (has_rows)
- process_block(twd, pbi, mi_row + hbs, mi_col, subsize, n4x4_l2,
- n8x8_l2);
+ parse_block(twd, pbi, mi_row + hbs, mi_col, subsize, n4x4_l2,
+ n8x8_l2);
break;
case PARTITION_VERT:
- process_block(twd, pbi, mi_row, mi_col, subsize, n8x8_l2, n4x4_l2);
+ parse_block(twd, pbi, mi_row, mi_col, subsize, n8x8_l2, n4x4_l2);
if (has_cols)
- process_block(twd, pbi, mi_row, mi_col + hbs, subsize, n8x8_l2,
- n4x4_l2);
+ parse_block(twd, pbi, mi_row, mi_col + hbs, subsize, n8x8_l2,
+ n4x4_l2);
break;
case PARTITION_SPLIT:
- process_partition(twd, pbi, mi_row, mi_col, subsize, n8x8_l2,
- parse_recon_flag, process_block);
- process_partition(twd, pbi, mi_row, mi_col + hbs, subsize, n8x8_l2,
- parse_recon_flag, process_block);
- process_partition(twd, pbi, mi_row + hbs, mi_col, subsize, n8x8_l2,
- parse_recon_flag, process_block);
- process_partition(twd, pbi, mi_row + hbs, mi_col + hbs, subsize,
- n8x8_l2, parse_recon_flag, process_block);
+ parse_partition(twd, pbi, mi_row, mi_col, subsize, n8x8_l2);
+ parse_partition(twd, pbi, mi_row, mi_col + hbs, subsize, n8x8_l2);
+ parse_partition(twd, pbi, mi_row + hbs, mi_col, subsize, n8x8_l2);
+ parse_partition(twd, pbi, mi_row + hbs, mi_col + hbs, subsize, n8x8_l2);
break;
default: assert(0 && "Invalid partition type");
}
}
- if (parse_recon_flag & PARSE) {
- // update partition context
- if ((bsize == BLOCK_8X8 || partition != PARTITION_SPLIT) &&
- bsize >= BLOCK_8X8)
- dec_update_partition_context(twd, mi_row, mi_col, subsize, num_8x8_wh);
- }
+ // update partition context
+ if (bsize >= BLOCK_8X8 &&
+ (bsize == BLOCK_8X8 || partition != PARTITION_SPLIT))
+ dec_update_partition_context(twd, mi_row, mi_col, subsize, num_8x8_wh);
}
static void setup_token_decoder(const uint8_t *data, const uint8_t *data_end,
@@ -1645,306 +1688,6 @@
}
}
-static void map_write(RowMTWorkerData *row_mt_worker_data, int idx) {
-#if CONFIG_MULTITHREAD
- pthread_mutex_lock(&row_mt_worker_data->map_mutex);
- row_mt_worker_data->recon_map[idx] = 1;
- pthread_mutex_unlock(&row_mt_worker_data->map_mutex);
-#else
- (void)row_mt_worker_data;
- (void)idx;
-#endif
-}
-
-static void map_read(RowMTWorkerData *row_mt_worker_data, int idx) {
-#if CONFIG_MULTITHREAD
- volatile int8_t *map = row_mt_worker_data->recon_map + idx;
- pthread_mutex_lock(&row_mt_worker_data->map_mutex);
- while (!*map) {
- pthread_mutex_unlock(&row_mt_worker_data->map_mutex);
- sched_yield();
- pthread_mutex_lock(&row_mt_worker_data->map_mutex);
- }
- pthread_mutex_unlock(&row_mt_worker_data->map_mutex);
-#else
- (void)row_mt_worker_data;
- (void)idx;
-#endif
-}
-
-static int lpf_map_write_check(VP9LfSync *lf_sync, int row, int num_tile_cols) {
- int return_val = 0;
-#if CONFIG_MULTITHREAD
- int corrupted;
- pthread_mutex_lock(&lf_sync->lf_mutex);
- corrupted = lf_sync->corrupted;
- pthread_mutex_unlock(&lf_sync->lf_mutex);
- if (!corrupted) {
- pthread_mutex_lock(&lf_sync->recon_done_mutex[row]);
- lf_sync->num_tiles_done[row] += 1;
- if (num_tile_cols == lf_sync->num_tiles_done[row]) return_val = 1;
- pthread_mutex_unlock(&lf_sync->recon_done_mutex[row]);
- }
-#else
- (void)lf_sync;
- (void)row;
- (void)num_tile_cols;
-#endif
- return return_val;
-}
-
-static void vp9_tile_done(VP9Decoder *pbi) {
-#if CONFIG_MULTITHREAD
- int terminate;
- RowMTWorkerData *const row_mt_worker_data = pbi->row_mt_worker_data;
- const int all_parse_done = 1 << pbi->common.log2_tile_cols;
- pthread_mutex_lock(&row_mt_worker_data->recon_mutex);
- row_mt_worker_data->num_tiles_done++;
- terminate = all_parse_done == row_mt_worker_data->num_tiles_done;
- pthread_mutex_unlock(&row_mt_worker_data->recon_mutex);
- if (terminate) {
- vp9_jobq_terminate(&row_mt_worker_data->jobq);
- }
-#else
- (void)pbi;
-#endif
-}
-
-static void vp9_jobq_alloc(VP9Decoder *pbi) {
- VP9_COMMON *const cm = &pbi->common;
- RowMTWorkerData *const row_mt_worker_data = pbi->row_mt_worker_data;
- const int aligned_rows = mi_cols_aligned_to_sb(cm->mi_rows);
- const int sb_rows = aligned_rows >> MI_BLOCK_SIZE_LOG2;
- const int tile_cols = 1 << cm->log2_tile_cols;
- const size_t jobq_size = (tile_cols * sb_rows * 2 + sb_rows) * sizeof(Job);
-
- if (jobq_size > row_mt_worker_data->jobq_size) {
- vpx_free(row_mt_worker_data->jobq_buf);
- CHECK_MEM_ERROR(cm, row_mt_worker_data->jobq_buf, vpx_calloc(1, jobq_size));
- vp9_jobq_init(&row_mt_worker_data->jobq, row_mt_worker_data->jobq_buf,
- jobq_size);
- row_mt_worker_data->jobq_size = jobq_size;
- }
-}
-
-static void recon_tile_row(TileWorkerData *tile_data, VP9Decoder *pbi,
- int mi_row, int is_last_row, VP9LfSync *lf_sync) {
- VP9_COMMON *const cm = &pbi->common;
- RowMTWorkerData *const row_mt_worker_data = pbi->row_mt_worker_data;
- const int tile_cols = 1 << cm->log2_tile_cols;
- const int aligned_cols = mi_cols_aligned_to_sb(cm->mi_cols);
- const int sb_cols = aligned_cols >> MI_BLOCK_SIZE_LOG2;
- const int cur_sb_row = mi_row >> MI_BLOCK_SIZE_LOG2;
- int mi_col_start = tile_data->xd.tile.mi_col_start;
- int mi_col_end = tile_data->xd.tile.mi_col_end;
- int mi_col;
-
- vp9_zero(tile_data->xd.left_context);
- vp9_zero(tile_data->xd.left_seg_context);
- for (mi_col = mi_col_start; mi_col < mi_col_end; mi_col += MI_BLOCK_SIZE) {
- const int c = mi_col >> MI_BLOCK_SIZE_LOG2;
- int plane;
- const int sb_num = (cur_sb_row * (aligned_cols >> MI_BLOCK_SIZE_LOG2) + c);
-
- // Top Dependency
- if (cur_sb_row) {
- map_read(row_mt_worker_data, ((cur_sb_row - 1) * sb_cols) + c);
- }
-
- for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
- tile_data->xd.plane[plane].eob =
- row_mt_worker_data->eob[plane] + (sb_num << EOBS_PER_SB_LOG2);
- tile_data->xd.plane[plane].dqcoeff =
- row_mt_worker_data->dqcoeff[plane] + (sb_num << DQCOEFFS_PER_SB_LOG2);
- }
- tile_data->xd.partition =
- row_mt_worker_data->partition + (sb_num * PARTITIONS_PER_SB);
- process_partition(tile_data, pbi, mi_row, mi_col, BLOCK_64X64, 4, RECON,
- recon_block);
- if (cm->lf.filter_level && !cm->skip_loop_filter) {
- // Queue LPF_JOB
- int is_lpf_job_ready = 0;
-
- if (mi_col + MI_BLOCK_SIZE >= mi_col_end) {
- // Checks if this row has been decoded in all tiles
- is_lpf_job_ready = lpf_map_write_check(lf_sync, cur_sb_row, tile_cols);
-
- if (is_lpf_job_ready) {
- Job lpf_job;
- lpf_job.job_type = LPF_JOB;
- if (cur_sb_row > 0) {
- lpf_job.row_num = mi_row - MI_BLOCK_SIZE;
- vp9_jobq_queue(&row_mt_worker_data->jobq, &lpf_job,
- sizeof(lpf_job));
- }
- if (is_last_row) {
- lpf_job.row_num = mi_row;
- vp9_jobq_queue(&row_mt_worker_data->jobq, &lpf_job,
- sizeof(lpf_job));
- }
- }
- }
- }
- map_write(row_mt_worker_data, (cur_sb_row * sb_cols) + c);
- }
-}
-
-static void parse_tile_row(TileWorkerData *tile_data, VP9Decoder *pbi,
- int mi_row, int cur_tile_col, uint8_t **data_end) {
- int mi_col;
- VP9_COMMON *const cm = &pbi->common;
- RowMTWorkerData *const row_mt_worker_data = pbi->row_mt_worker_data;
- TileInfo *tile = &tile_data->xd.tile;
- TileBuffer *const buf = &pbi->tile_buffers[cur_tile_col];
- const int aligned_cols = mi_cols_aligned_to_sb(cm->mi_cols);
-
- vp9_zero(tile_data->dqcoeff);
- vp9_tile_init(tile, cm, 0, cur_tile_col);
-
- /* Update reader only at the beginning of each row in a tile */
- if (mi_row == 0) {
- setup_token_decoder(buf->data, *data_end, buf->size, &tile_data->error_info,
- &tile_data->bit_reader, pbi->decrypt_cb,
- pbi->decrypt_state);
- }
- vp9_init_macroblockd(cm, &tile_data->xd, tile_data->dqcoeff);
- tile_data->xd.error_info = &tile_data->error_info;
-
- vp9_zero(tile_data->xd.left_context);
- vp9_zero(tile_data->xd.left_seg_context);
- for (mi_col = tile->mi_col_start; mi_col < tile->mi_col_end;
- mi_col += MI_BLOCK_SIZE) {
- const int r = mi_row >> MI_BLOCK_SIZE_LOG2;
- const int c = mi_col >> MI_BLOCK_SIZE_LOG2;
- int plane;
- const int sb_num = (r * (aligned_cols >> MI_BLOCK_SIZE_LOG2) + c);
- for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
- tile_data->xd.plane[plane].eob =
- row_mt_worker_data->eob[plane] + (sb_num << EOBS_PER_SB_LOG2);
- tile_data->xd.plane[plane].dqcoeff =
- row_mt_worker_data->dqcoeff[plane] + (sb_num << DQCOEFFS_PER_SB_LOG2);
- }
- tile_data->xd.partition =
- row_mt_worker_data->partition + sb_num * PARTITIONS_PER_SB;
- process_partition(tile_data, pbi, mi_row, mi_col, BLOCK_64X64, 4, PARSE,
- parse_block);
- }
-}
-
-static int row_decode_worker_hook(ThreadData *const thread_data,
- uint8_t **data_end) {
- VP9Decoder *const pbi = thread_data->pbi;
- VP9_COMMON *const cm = &pbi->common;
- RowMTWorkerData *const row_mt_worker_data = pbi->row_mt_worker_data;
- const int aligned_cols = mi_cols_aligned_to_sb(cm->mi_cols);
- const int aligned_rows = mi_cols_aligned_to_sb(cm->mi_rows);
- const int sb_rows = aligned_rows >> MI_BLOCK_SIZE_LOG2;
- Job job;
- LFWorkerData *lf_data = thread_data->lf_data;
- VP9LfSync *lf_sync = thread_data->lf_sync;
- volatile int corrupted = 0;
-
- while (!vp9_jobq_dequeue(&row_mt_worker_data->jobq, &job, sizeof(job), 1)) {
- int mi_col;
- const int mi_row = job.row_num;
-
- if (job.job_type == LPF_JOB) {
- lf_data->start = mi_row;
- lf_data->stop = lf_data->start + MI_BLOCK_SIZE;
-
- if (cm->lf.filter_level && !cm->skip_loop_filter &&
- mi_row < cm->mi_rows) {
- vp9_loopfilter_job(lf_data, lf_sync);
- }
- } else if (job.job_type == RECON_JOB) {
- const int cur_sb_row = mi_row >> MI_BLOCK_SIZE_LOG2;
- const int is_last_row = sb_rows - 1 == cur_sb_row;
- TileWorkerData twd_recon;
- TileWorkerData *const tile_data_recon = &twd_recon;
- int mi_col_start, mi_col_end;
-
- tile_data_recon->xd = pbi->mb;
- vp9_tile_init(&tile_data_recon->xd.tile, cm, 0, job.tile_col);
- vp9_init_macroblockd(cm, &tile_data_recon->xd, tile_data_recon->dqcoeff);
- mi_col_start = tile_data_recon->xd.tile.mi_col_start;
- mi_col_end = tile_data_recon->xd.tile.mi_col_end;
-
- if (setjmp(tile_data_recon->error_info.jmp)) {
- const int sb_cols = aligned_cols >> MI_BLOCK_SIZE_LOG2;
- tile_data_recon->error_info.setjmp = 0;
- corrupted = 1;
- for (mi_col = mi_col_start; mi_col < mi_col_end;
- mi_col += MI_BLOCK_SIZE) {
- const int c = mi_col >> MI_BLOCK_SIZE_LOG2;
- map_write(row_mt_worker_data, (cur_sb_row * sb_cols) + c);
- }
- if (is_last_row) {
- vp9_tile_done(pbi);
- }
- continue;
- }
-
- tile_data_recon->error_info.setjmp = 1;
- tile_data_recon->xd.error_info = &tile_data_recon->error_info;
-
- recon_tile_row(tile_data_recon, pbi, mi_row, is_last_row, lf_sync);
-
- if (corrupted)
- vpx_internal_error(&tile_data_recon->error_info,
- VPX_CODEC_CORRUPT_FRAME,
- "Failed to decode tile data");
-
- if (is_last_row) {
- vp9_tile_done(pbi);
- }
- } else if (job.job_type == PARSE_JOB) {
- TileWorkerData *const tile_data = &pbi->tile_worker_data[job.tile_col];
-
- if (setjmp(tile_data->error_info.jmp)) {
- tile_data->error_info.setjmp = 0;
- corrupted = 1;
- vp9_tile_done(pbi);
- continue;
- }
-
- tile_data->xd = pbi->mb;
- tile_data->xd.counts =
- cm->frame_parallel_decoding_mode ? 0 : &tile_data->counts;
-
- tile_data->error_info.setjmp = 1;
-
- parse_tile_row(tile_data, pbi, mi_row, job.tile_col, data_end);
-
- corrupted |= tile_data->xd.corrupted;
- if (corrupted)
- vpx_internal_error(&tile_data->error_info, VPX_CODEC_CORRUPT_FRAME,
- "Failed to decode tile data");
-
- /* Queue in the recon_job for this row */
- {
- Job recon_job;
- recon_job.row_num = mi_row;
- recon_job.tile_col = job.tile_col;
- recon_job.job_type = RECON_JOB;
- vp9_jobq_queue(&row_mt_worker_data->jobq, &recon_job,
- sizeof(recon_job));
- }
-
- /* Queue next parse job */
- if (mi_row + MI_BLOCK_SIZE < cm->mi_rows) {
- Job parse_job;
- parse_job.row_num = mi_row + MI_BLOCK_SIZE;
- parse_job.tile_col = job.tile_col;
- parse_job.job_type = PARSE_JOB;
- vp9_jobq_queue(&row_mt_worker_data->jobq, &parse_job,
- sizeof(parse_job));
- }
- }
- }
-
- return !corrupted;
-}
-
static const uint8_t *decode_tiles(VP9Decoder *pbi, const uint8_t *data,
const uint8_t *data_end) {
VP9_COMMON *const cm = &pbi->common;
@@ -2032,8 +1775,7 @@
row_mt_worker_data->dqcoeff[plane];
}
tile_data->xd.partition = row_mt_worker_data->partition;
- process_partition(tile_data, pbi, mi_row, mi_col, BLOCK_64X64, 4,
- PARSE, parse_block);
+ parse_partition(tile_data, pbi, mi_row, mi_col, BLOCK_64X64, 4);
for (plane = 0; plane < MAX_MB_PLANE; ++plane) {
tile_data->xd.plane[plane].eob = row_mt_worker_data->eob[plane];
@@ -2041,8 +1783,7 @@
row_mt_worker_data->dqcoeff[plane];
}
tile_data->xd.partition = row_mt_worker_data->partition;
- process_partition(tile_data, pbi, mi_row, mi_col, BLOCK_64X64, 4,
- RECON, recon_block);
+ recon_partition(tile_data, pbi, mi_row, mi_col, BLOCK_64X64, 4);
} else {
decode_partition(tile_data, pbi, mi_row, mi_col, BLOCK_64X64, 4);
}
@@ -2210,13 +1951,23 @@
return (buf_a->size < buf_b->size) - (buf_a->size > buf_b->size);
}
-static INLINE void init_mt(VP9Decoder *pbi) {
- int n;
+static const uint8_t *decode_tiles_mt(VP9Decoder *pbi, const uint8_t *data,
+ const uint8_t *data_end) {
VP9_COMMON *const cm = &pbi->common;
+ const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
+ const uint8_t *bit_reader_end = NULL;
VP9LfSync *lf_row_sync = &pbi->lf_row_sync;
+ YV12_BUFFER_CONFIG *const new_fb = get_frame_new_buffer(cm);
const int aligned_mi_cols = mi_cols_aligned_to_sb(cm->mi_cols);
- const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
+ const int tile_cols = 1 << cm->log2_tile_cols;
+ const int tile_rows = 1 << cm->log2_tile_rows;
+ const int num_workers = VPXMIN(pbi->max_threads, tile_cols);
+ int n;
+ assert(tile_cols <= (1 << 6));
+ assert(tile_rows == 1);
+ (void)tile_rows;
+
if (pbi->num_tile_workers == 0) {
const int num_threads = pbi->max_threads;
CHECK_MEM_ERROR(cm, pbi->tile_workers,
@@ -2234,163 +1985,14 @@
}
// Initialize LPF
- if ((pbi->lpf_mt_opt || pbi->row_mt) && cm->lf.filter_level &&
- !cm->skip_loop_filter) {
+ if (pbi->lpf_mt_opt && cm->lf.filter_level && !cm->skip_loop_filter) {
vp9_lpf_mt_init(lf_row_sync, cm, cm->lf.filter_level,
pbi->num_tile_workers);
}
- // Note: this memset assumes above_context[0], [1] and [2]
- // are allocated as part of the same buffer.
- memset(cm->above_context, 0,
- sizeof(*cm->above_context) * MAX_MB_PLANE * 2 * aligned_mi_cols);
-
- memset(cm->above_seg_context, 0,
- sizeof(*cm->above_seg_context) * aligned_mi_cols);
-
- vp9_reset_lfm(cm);
-}
-
-static const uint8_t *decode_tiles_row_wise_mt(VP9Decoder *pbi,
- const uint8_t *data,
- const uint8_t *data_end) {
- VP9_COMMON *const cm = &pbi->common;
- RowMTWorkerData *const row_mt_worker_data = pbi->row_mt_worker_data;
- const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
- const int tile_cols = 1 << cm->log2_tile_cols;
- const int tile_rows = 1 << cm->log2_tile_rows;
- const int num_workers = pbi->max_threads;
- int i, n;
- int col;
- int corrupted = 0;
- const int sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
- const int sb_cols = mi_cols_aligned_to_sb(cm->mi_cols) >> MI_BLOCK_SIZE_LOG2;
- VP9LfSync *lf_row_sync = &pbi->lf_row_sync;
- YV12_BUFFER_CONFIG *const new_fb = get_frame_new_buffer(cm);
-
- assert(tile_cols <= (1 << 6));
- assert(tile_rows == 1);
- (void)tile_rows;
-
- memset(row_mt_worker_data->recon_map, 0,
- sb_rows * sb_cols * sizeof(*row_mt_worker_data->recon_map));
-
- init_mt(pbi);
-
// Reset tile decoding hook
for (n = 0; n < num_workers; ++n) {
VPxWorker *const worker = &pbi->tile_workers[n];
- ThreadData *const thread_data = &pbi->row_mt_worker_data->thread_data[n];
- winterface->sync(worker);
-
- if (cm->lf.filter_level && !cm->skip_loop_filter) {
- thread_data->lf_sync = lf_row_sync;
- thread_data->lf_data = &thread_data->lf_sync->lfdata[n];
- vp9_loop_filter_data_reset(thread_data->lf_data, new_fb, cm,
- pbi->mb.plane);
- }
-
- thread_data->pbi = pbi;
-
- worker->hook = (VPxWorkerHook)row_decode_worker_hook;
- worker->data1 = thread_data;
- worker->data2 = &row_mt_worker_data->data_end;
- }
-
- for (col = 0; col < tile_cols; ++col) {
- TileWorkerData *const tile_data = &pbi->tile_worker_data[col];
- tile_data->xd = pbi->mb;
- tile_data->xd.counts =
- cm->frame_parallel_decoding_mode ? NULL : &tile_data->counts;
- }
-
- /* Reset the jobq to start of the jobq buffer */
- vp9_jobq_reset(&row_mt_worker_data->jobq);
- row_mt_worker_data->num_tiles_done = 0;
- row_mt_worker_data->data_end = NULL;
-
- // Load tile data into tile_buffers
- get_tile_buffers(pbi, data, data_end, tile_cols, tile_rows,
- &pbi->tile_buffers);
-
- // Initialize thread frame counts.
- if (!cm->frame_parallel_decoding_mode) {
- for (col = 0; col < tile_cols; ++col) {
- TileWorkerData *const tile_data =
- (TileWorkerData *)&pbi->tile_worker_data[col];
- vp9_zero(tile_data->counts);
- }
- }
-
- // queue parse jobs for 0th row of every tile
- for (col = 0; col < tile_cols; ++col) {
- Job parse_job;
- parse_job.row_num = 0;
- parse_job.tile_col = col;
- parse_job.job_type = PARSE_JOB;
- vp9_jobq_queue(&row_mt_worker_data->jobq, &parse_job, sizeof(parse_job));
- }
-
- for (i = 0; i < num_workers; ++i) {
- VPxWorker *const worker = &pbi->tile_workers[i];
- worker->had_error = 0;
- if (i == num_workers - 1) {
- winterface->execute(worker);
- } else {
- winterface->launch(worker);
- }
- }
-
- for (; n > 0; --n) {
- VPxWorker *const worker = &pbi->tile_workers[n - 1];
- // TODO(jzern): The tile may have specific error data associated with
- // its vpx_internal_error_info which could be propagated to the main info
- // in cm. Additionally once the threads have been synced and an error is
- // detected, there's no point in continuing to decode tiles.
- corrupted |= !winterface->sync(worker);
- }
-
- pbi->mb.corrupted = corrupted;
-
- {
- /* Set data end */
- TileWorkerData *const tile_data = &pbi->tile_worker_data[tile_cols - 1];
- row_mt_worker_data->data_end = vpx_reader_find_end(&tile_data->bit_reader);
- }
-
- // Accumulate thread frame counts.
- if (!cm->frame_parallel_decoding_mode) {
- for (i = 0; i < tile_cols; ++i) {
- TileWorkerData *const tile_data =
- (TileWorkerData *)&pbi->tile_worker_data[i];
- vp9_accumulate_frame_counts(&cm->counts, &tile_data->counts, 1);
- }
- }
-
- return row_mt_worker_data->data_end;
-}
-
-static const uint8_t *decode_tiles_mt(VP9Decoder *pbi, const uint8_t *data,
- const uint8_t *data_end) {
- VP9_COMMON *const cm = &pbi->common;
- const VPxWorkerInterface *const winterface = vpx_get_worker_interface();
- const uint8_t *bit_reader_end = NULL;
- VP9LfSync *lf_row_sync = &pbi->lf_row_sync;
- YV12_BUFFER_CONFIG *const new_fb = get_frame_new_buffer(cm);
- const int tile_cols = 1 << cm->log2_tile_cols;
- const int tile_rows = 1 << cm->log2_tile_rows;
- const int num_workers = VPXMIN(pbi->max_threads, tile_cols);
- int n;
-
- assert(tile_cols <= (1 << 6));
- assert(tile_rows == 1);
- (void)tile_rows;
-
- init_mt(pbi);
-
- // Reset tile decoding hook
- for (n = 0; n < num_workers; ++n) {
- VPxWorker *const worker = &pbi->tile_workers[n];
TileWorkerData *const tile_data =
&pbi->tile_worker_data[n + pbi->total_tiles];
winterface->sync(worker);
@@ -2410,6 +2012,15 @@
worker->data2 = pbi;
}
+ // Note: this memset assumes above_context[0], [1] and [2]
+ // are allocated as part of the same buffer.
+ memset(cm->above_context, 0,
+ sizeof(*cm->above_context) * MAX_MB_PLANE * 2 * aligned_mi_cols);
+ memset(cm->above_seg_context, 0,
+ sizeof(*cm->above_seg_context) * aligned_mi_cols);
+
+ vp9_reset_lfm(cm);
+
// Load tile data into tile_buffers
get_tile_buffers(pbi, data, data_end, tile_cols, tile_rows,
&pbi->tile_buffers);
@@ -2759,10 +2370,6 @@
if (pbi->row_mt_worker_data == NULL) {
CHECK_MEM_ERROR(cm, pbi->row_mt_worker_data,
vpx_calloc(1, sizeof(*pbi->row_mt_worker_data)));
-#if CONFIG_MULTITHREAD
- pthread_mutex_init(&pbi->row_mt_worker_data->recon_mutex, NULL);
- pthread_mutex_init(&pbi->row_mt_worker_data->map_mutex, NULL);
-#endif
}
if (pbi->max_threads > 1) {
@@ -2776,10 +2383,8 @@
if (num_sbs > pbi->row_mt_worker_data->num_sbs) {
vp9_dec_free_row_mt_mem(pbi->row_mt_worker_data);
- vp9_dec_alloc_row_mt_mem(pbi->row_mt_worker_data, cm, num_sbs,
- pbi->max_threads);
+ vp9_dec_alloc_row_mt_mem(pbi->row_mt_worker_data, cm, num_sbs);
}
- vp9_jobq_alloc(pbi);
}
sz = vpx_rb_read_literal(rb, 16);
@@ -2939,27 +2544,21 @@
pbi->total_tiles = tile_rows * tile_cols;
}
- if (pbi->max_threads > 1 && tile_rows == 1 &&
- (tile_cols > 1 || pbi->row_mt == 1)) {
- if (pbi->row_mt == 1) {
- *p_data_end =
- decode_tiles_row_wise_mt(pbi, data + first_partition_size, data_end);
- } else {
- // Multi-threaded tile decoder
- *p_data_end = decode_tiles_mt(pbi, data + first_partition_size, data_end);
- if (!pbi->lpf_mt_opt) {
- if (!xd->corrupted) {
- if (!cm->skip_loop_filter) {
- // If multiple threads are used to decode tiles, then we use those
- // threads to do parallel loopfiltering.
- vp9_loop_filter_frame_mt(
- new_fb, cm, pbi->mb.plane, cm->lf.filter_level, 0, 0,
- pbi->tile_workers, pbi->num_tile_workers, &pbi->lf_row_sync);
- }
- } else {
- vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME,
- "Decode failed. Frame data is corrupted.");
+ if (pbi->max_threads > 1 && tile_rows == 1 && tile_cols > 1) {
+ // Multi-threaded tile decoder
+ *p_data_end = decode_tiles_mt(pbi, data + first_partition_size, data_end);
+ if (!pbi->lpf_mt_opt) {
+ if (!xd->corrupted) {
+ if (!cm->skip_loop_filter) {
+ // If multiple threads are used to decode tiles, then we use those
+ // threads to do parallel loopfiltering.
+ vp9_loop_filter_frame_mt(new_fb, cm, pbi->mb.plane,
+ cm->lf.filter_level, 0, 0, pbi->tile_workers,
+ pbi->num_tile_workers, &pbi->lf_row_sync);
}
+ } else {
+ vpx_internal_error(&cm->error, VPX_CODEC_CORRUPT_FRAME,
+ "Decode failed. Frame data is corrupted.");
}
}
} else {
--- a/vp9/decoder/vp9_decoder.c
+++ b/vp9/decoder/vp9_decoder.c
@@ -56,7 +56,7 @@
}
void vp9_dec_alloc_row_mt_mem(RowMTWorkerData *row_mt_worker_data,
- VP9_COMMON *cm, int num_sbs, int max_threads) {
+ VP9_COMMON *cm, int num_sbs) {
int plane;
const size_t dqcoeff_size = (num_sbs << DQCOEFFS_PER_SB_LOG2) *
sizeof(*row_mt_worker_data->dqcoeff[0]);
@@ -74,14 +74,6 @@
sizeof(*row_mt_worker_data->partition)));
CHECK_MEM_ERROR(cm, row_mt_worker_data->recon_map,
vpx_calloc(num_sbs, sizeof(*row_mt_worker_data->recon_map)));
-
- // allocate memory for thread_data
- if (row_mt_worker_data->thread_data == NULL) {
- const size_t thread_size =
- max_threads * sizeof(*row_mt_worker_data->thread_data);
- CHECK_MEM_ERROR(cm, row_mt_worker_data->thread_data,
- vpx_memalign(32, thread_size));
- }
}
void vp9_dec_free_row_mt_mem(RowMTWorkerData *row_mt_worker_data) {
@@ -97,8 +89,6 @@
row_mt_worker_data->partition = NULL;
vpx_free(row_mt_worker_data->recon_map);
row_mt_worker_data->recon_map = NULL;
- vpx_free(row_mt_worker_data->thread_data);
- row_mt_worker_data->thread_data = NULL;
}
}
@@ -189,17 +179,8 @@
if (pbi->row_mt == 1) {
vp9_dec_free_row_mt_mem(pbi->row_mt_worker_data);
- if (pbi->row_mt_worker_data != NULL) {
- vp9_jobq_deinit(&pbi->row_mt_worker_data->jobq);
- vpx_free(pbi->row_mt_worker_data->jobq_buf);
-#if CONFIG_MULTITHREAD
- pthread_mutex_destroy(&pbi->row_mt_worker_data->recon_mutex);
- pthread_mutex_destroy(&pbi->row_mt_worker_data->map_mutex);
-#endif
- }
vpx_free(pbi->row_mt_worker_data);
}
-
vp9_remove_common(&pbi->common);
vpx_free(pbi);
}
--- a/vp9/decoder/vp9_decoder.h
+++ b/vp9/decoder/vp9_decoder.h
@@ -21,7 +21,6 @@
#include "vp9/common/vp9_thread_common.h"
#include "vp9/common/vp9_onyxc_int.h"
#include "vp9/common/vp9_ppflags.h"
-#include "./vp9_job_queue.h"
#ifdef __cplusplus
extern "C" {
@@ -31,14 +30,6 @@
#define DQCOEFFS_PER_SB_LOG2 12
#define PARTITIONS_PER_SB 85
-typedef enum JobType { PARSE_JOB, RECON_JOB, LPF_JOB } JobType;
-
-typedef struct ThreadData {
- struct VP9Decoder *pbi;
- LFWorkerData *lf_data;
- VP9LfSync *lf_sync;
-} ThreadData;
-
typedef struct TileBuffer {
const uint8_t *data;
size_t size;
@@ -58,11 +49,6 @@
struct vpx_internal_error_info error_info;
} TileWorkerData;
-typedef void (*process_block_fn_t)(TileWorkerData *twd,
- struct VP9Decoder *const pbi, int mi_row,
- int mi_col, BLOCK_SIZE bsize, int bwl,
- int bhl);
-
typedef struct RowMTWorkerData {
int num_sbs;
int *eob[MAX_MB_PLANE];
@@ -69,25 +55,8 @@
PARTITION_TYPE *partition;
tran_low_t *dqcoeff[MAX_MB_PLANE];
int8_t *recon_map;
- const uint8_t *data_end;
- uint8_t *jobq_buf;
- JobQueueRowMt jobq;
- size_t jobq_size;
- int num_tiles_done;
-#if CONFIG_MULTITHREAD
- pthread_mutex_t recon_mutex;
- pthread_mutex_t map_mutex;
-#endif
- ThreadData *thread_data;
} RowMTWorkerData;
-/* Structure to queue and dequeue row decode jobs */
-typedef struct Job {
- int row_num;
- int tile_col;
- JobType job_type;
-} Job;
-
typedef struct VP9Decoder {
DECLARE_ALIGNED(16, MACROBLOCKD, mb);
@@ -159,7 +128,7 @@
void vp9_decoder_remove(struct VP9Decoder *pbi);
void vp9_dec_alloc_row_mt_mem(RowMTWorkerData *row_mt_worker_data,
- VP9_COMMON *cm, int num_sbs, int max_threads);
+ VP9_COMMON *cm, int num_sbs);
void vp9_dec_free_row_mt_mem(RowMTWorkerData *row_mt_worker_data);
static INLINE void decrease_ref_count(int idx, RefCntBuffer *const frame_bufs,
--- a/vp9/decoder/vp9_job_queue.c
+++ /dev/null
@@ -1,124 +1,0 @@
-/*
- * Copyright (c) 2018 The WebM project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include <assert.h>
-#include <string.h>
-
-#include "vpx/vpx_integer.h"
-
-#include "vp9/decoder/vp9_job_queue.h"
-
-void vp9_jobq_init(JobQueueRowMt *jobq, uint8_t *buf, size_t buf_size) {
-#if CONFIG_MULTITHREAD
- pthread_mutex_init(&jobq->mutex, NULL);
- pthread_cond_init(&jobq->cond, NULL);
-#endif
- jobq->buf_base = buf;
- jobq->buf_wr = buf;
- jobq->buf_rd = buf;
- jobq->buf_end = buf + buf_size;
- jobq->terminate = 0;
-}
-
-void vp9_jobq_reset(JobQueueRowMt *jobq) {
-#if CONFIG_MULTITHREAD
- pthread_mutex_lock(&jobq->mutex);
-#endif
- jobq->buf_wr = jobq->buf_base;
- jobq->buf_rd = jobq->buf_base;
- jobq->terminate = 0;
-#if CONFIG_MULTITHREAD
- pthread_mutex_unlock(&jobq->mutex);
-#endif
-}
-
-void vp9_jobq_deinit(JobQueueRowMt *jobq) {
- vp9_jobq_reset(jobq);
-#if CONFIG_MULTITHREAD
- pthread_mutex_destroy(&jobq->mutex);
- pthread_cond_destroy(&jobq->cond);
-#endif
-}
-
-void vp9_jobq_terminate(JobQueueRowMt *jobq) {
-#if CONFIG_MULTITHREAD
- pthread_mutex_lock(&jobq->mutex);
-#endif
- jobq->terminate = 1;
-#if CONFIG_MULTITHREAD
- pthread_cond_broadcast(&jobq->cond);
- pthread_mutex_unlock(&jobq->mutex);
-#endif
-}
-
-int vp9_jobq_queue(JobQueueRowMt *jobq, void *job, size_t job_size) {
- int ret = 0;
-#if CONFIG_MULTITHREAD
- pthread_mutex_lock(&jobq->mutex);
-#endif
- if (jobq->buf_end >= jobq->buf_wr + job_size) {
- memcpy(jobq->buf_wr, job, job_size);
- jobq->buf_wr = jobq->buf_wr + job_size;
-#if CONFIG_MULTITHREAD
- pthread_cond_signal(&jobq->cond);
-#endif
- ret = 0;
- } else {
- /* Wrap around case is not supported */
- assert(0);
- ret = 1;
- }
-#if CONFIG_MULTITHREAD
- pthread_mutex_unlock(&jobq->mutex);
-#endif
- return ret;
-}
-
-int vp9_jobq_dequeue(JobQueueRowMt *jobq, void *job, size_t job_size,
- int blocking) {
- int ret = 0;
-#if CONFIG_MULTITHREAD
- pthread_mutex_lock(&jobq->mutex);
-#endif
- if (jobq->buf_end >= jobq->buf_rd + job_size) {
- while (1) {
- if (jobq->buf_wr >= jobq->buf_rd + job_size) {
- memcpy(job, jobq->buf_rd, job_size);
- jobq->buf_rd = jobq->buf_rd + job_size;
- ret = 0;
- break;
- } else {
- /* If all the entries have been dequeued, then break and return */
- if (jobq->terminate == 1) {
- ret = 1;
- break;
- }
- if (blocking == 1) {
-#if CONFIG_MULTITHREAD
- pthread_cond_wait(&jobq->cond, &jobq->mutex);
-#endif
- } else {
- /* If there is no job available,
- * and this is non blocking call then return fail */
- ret = 1;
- break;
- }
- }
- }
- } else {
- /* Wrap around case is not supported */
- ret = 1;
- }
-#if CONFIG_MULTITHREAD
- pthread_mutex_unlock(&jobq->mutex);
-#endif
-
- return ret;
-}
--- a/vp9/decoder/vp9_job_queue.h
+++ /dev/null
@@ -1,45 +1,0 @@
-/*
- * Copyright (c) 2018 The WebM project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef VPX_VP9_DECODER_VP9_JOB_QUEUE_H_
-#define VPX_VP9_DECODER_VP9_JOB_QUEUE_H_
-
-#include "vpx_util/vpx_thread.h"
-
-typedef struct {
- // Pointer to buffer base which contains the jobs
- uint8_t *buf_base;
-
- // Pointer to current address where new job can be added
- uint8_t *volatile buf_wr;
-
- // Pointer to current address from where next job can be obtained
- uint8_t *volatile buf_rd;
-
- // Pointer to end of job buffer
- uint8_t *buf_end;
-
- int terminate;
-
-#if CONFIG_MULTITHREAD
- pthread_mutex_t mutex;
- pthread_cond_t cond;
-#endif
-} JobQueueRowMt;
-
-void vp9_jobq_init(JobQueueRowMt *jobq, uint8_t *buf, size_t buf_size);
-void vp9_jobq_reset(JobQueueRowMt *jobq);
-void vp9_jobq_deinit(JobQueueRowMt *jobq);
-void vp9_jobq_terminate(JobQueueRowMt *jobq);
-int vp9_jobq_queue(JobQueueRowMt *jobq, void *job, size_t job_size);
-int vp9_jobq_dequeue(JobQueueRowMt *jobq, void *job, size_t job_size,
- int blocking);
-
-#endif // VPX_VP9_DECODER_VP9_JOB_QUEUE_H_
--- a/vp9/vp9dx.mk
+++ b/vp9/vp9dx.mk
@@ -28,7 +28,5 @@
VP9_DX_SRCS-yes += decoder/vp9_decoder.h
VP9_DX_SRCS-yes += decoder/vp9_dsubexp.c
VP9_DX_SRCS-yes += decoder/vp9_dsubexp.h
-VP9_DX_SRCS-yes += decoder/vp9_job_queue.c
-VP9_DX_SRCS-yes += decoder/vp9_job_queue.h
VP9_DX_SRCS-yes := $(filter-out $(VP9_DX_SRCS_REMOVE-yes),$(VP9_DX_SRCS-yes))