123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- /*
- * Copyright (c) 2017 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 "vp9/encoder/vp9_encoder.h"
- #include "vp9/encoder/vp9_ethread.h"
- #include "vp9/encoder/vp9_multi_thread.h"
- #include "vp9/encoder/vp9_temporal_filter.h"
- void *vp9_enc_grp_get_next_job(MultiThreadHandle *multi_thread_ctxt,
- int tile_id) {
- RowMTInfo *row_mt_info;
- JobQueueHandle *job_queue_hdl = NULL;
- void *next = NULL;
- JobNode *job_info = NULL;
- #if CONFIG_MULTITHREAD
- pthread_mutex_t *mutex_handle = NULL;
- #endif
- row_mt_info = (RowMTInfo *)(&multi_thread_ctxt->row_mt_info[tile_id]);
- job_queue_hdl = (JobQueueHandle *)&row_mt_info->job_queue_hdl;
- #if CONFIG_MULTITHREAD
- mutex_handle = &row_mt_info->job_mutex;
- #endif
- // lock the mutex for queue access
- #if CONFIG_MULTITHREAD
- pthread_mutex_lock(mutex_handle);
- #endif
- next = job_queue_hdl->next;
- if (NULL != next) {
- JobQueue *job_queue = (JobQueue *)next;
- job_info = &job_queue->job_info;
- // Update the next job in the queue
- job_queue_hdl->next = job_queue->next;
- job_queue_hdl->num_jobs_acquired++;
- }
- #if CONFIG_MULTITHREAD
- pthread_mutex_unlock(mutex_handle);
- #endif
- return job_info;
- }
- void vp9_row_mt_alloc_rd_thresh(VP9_COMP *const cpi,
- TileDataEnc *const this_tile) {
- VP9_COMMON *const cm = &cpi->common;
- const int sb_rows =
- (mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2) + 1;
- int i;
- this_tile->row_base_thresh_freq_fact =
- (int *)vpx_calloc(sb_rows * BLOCK_SIZES * MAX_MODES,
- sizeof(*(this_tile->row_base_thresh_freq_fact)));
- for (i = 0; i < sb_rows * BLOCK_SIZES * MAX_MODES; i++)
- this_tile->row_base_thresh_freq_fact[i] = RD_THRESH_INIT_FACT;
- }
- void vp9_row_mt_mem_alloc(VP9_COMP *cpi) {
- struct VP9Common *cm = &cpi->common;
- MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
- int tile_row, tile_col;
- const int tile_cols = 1 << cm->log2_tile_cols;
- const int tile_rows = 1 << cm->log2_tile_rows;
- const int sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
- int jobs_per_tile_col, total_jobs;
- // Allocate memory that is large enough for all row_mt stages. First pass
- // uses 16x16 block size.
- jobs_per_tile_col = VPXMAX(cm->mb_rows, sb_rows);
- // Calculate the total number of jobs
- total_jobs = jobs_per_tile_col * tile_cols;
- multi_thread_ctxt->allocated_tile_cols = tile_cols;
- multi_thread_ctxt->allocated_tile_rows = tile_rows;
- multi_thread_ctxt->allocated_vert_unit_rows = jobs_per_tile_col;
- multi_thread_ctxt->job_queue =
- (JobQueue *)vpx_memalign(32, total_jobs * sizeof(JobQueue));
- #if CONFIG_MULTITHREAD
- // Create mutex for each tile
- for (tile_col = 0; tile_col < tile_cols; tile_col++) {
- RowMTInfo *row_mt_info = &multi_thread_ctxt->row_mt_info[tile_col];
- pthread_mutex_init(&row_mt_info->job_mutex, NULL);
- }
- #endif
- // Allocate memory for row based multi-threading
- for (tile_col = 0; tile_col < tile_cols; tile_col++) {
- TileDataEnc *this_tile = &cpi->tile_data[tile_col];
- vp9_row_mt_sync_mem_alloc(&this_tile->row_mt_sync, cm, jobs_per_tile_col);
- if (cpi->sf.adaptive_rd_thresh_row_mt) {
- if (this_tile->row_base_thresh_freq_fact != NULL) {
- vpx_free(this_tile->row_base_thresh_freq_fact);
- this_tile->row_base_thresh_freq_fact = NULL;
- }
- vp9_row_mt_alloc_rd_thresh(cpi, this_tile);
- }
- }
- // Assign the sync pointer of tile row zero for every tile row > 0
- for (tile_row = 1; tile_row < tile_rows; tile_row++) {
- for (tile_col = 0; tile_col < tile_cols; tile_col++) {
- TileDataEnc *this_tile = &cpi->tile_data[tile_row * tile_cols + tile_col];
- TileDataEnc *this_col_tile = &cpi->tile_data[tile_col];
- this_tile->row_mt_sync = this_col_tile->row_mt_sync;
- }
- }
- // Calculate the number of vertical units in the given tile row
- for (tile_row = 0; tile_row < tile_rows; tile_row++) {
- TileDataEnc *this_tile = &cpi->tile_data[tile_row * tile_cols];
- TileInfo *tile_info = &this_tile->tile_info;
- multi_thread_ctxt->num_tile_vert_sbs[tile_row] =
- get_num_vert_units(*tile_info, MI_BLOCK_SIZE_LOG2);
- }
- }
- void vp9_row_mt_mem_dealloc(VP9_COMP *cpi) {
- MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
- int tile_col;
- #if CONFIG_MULTITHREAD
- int tile_row;
- #endif
- // Deallocate memory for job queue
- if (multi_thread_ctxt->job_queue) vpx_free(multi_thread_ctxt->job_queue);
- #if CONFIG_MULTITHREAD
- // Destroy mutex for each tile
- for (tile_col = 0; tile_col < multi_thread_ctxt->allocated_tile_cols;
- tile_col++) {
- RowMTInfo *row_mt_info = &multi_thread_ctxt->row_mt_info[tile_col];
- if (row_mt_info) pthread_mutex_destroy(&row_mt_info->job_mutex);
- }
- #endif
- // Free row based multi-threading sync memory
- for (tile_col = 0; tile_col < multi_thread_ctxt->allocated_tile_cols;
- tile_col++) {
- TileDataEnc *this_tile = &cpi->tile_data[tile_col];
- vp9_row_mt_sync_mem_dealloc(&this_tile->row_mt_sync);
- }
- #if CONFIG_MULTITHREAD
- for (tile_row = 0; tile_row < multi_thread_ctxt->allocated_tile_rows;
- tile_row++) {
- for (tile_col = 0; tile_col < multi_thread_ctxt->allocated_tile_cols;
- tile_col++) {
- TileDataEnc *this_tile =
- &cpi->tile_data[tile_row * multi_thread_ctxt->allocated_tile_cols +
- tile_col];
- if (this_tile->row_base_thresh_freq_fact != NULL) {
- vpx_free(this_tile->row_base_thresh_freq_fact);
- this_tile->row_base_thresh_freq_fact = NULL;
- }
- }
- }
- #endif
- }
- void vp9_multi_thread_tile_init(VP9_COMP *cpi) {
- VP9_COMMON *const cm = &cpi->common;
- const int tile_cols = 1 << cm->log2_tile_cols;
- const int sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
- int i;
- for (i = 0; i < tile_cols; i++) {
- TileDataEnc *this_tile = &cpi->tile_data[i];
- int jobs_per_tile_col = cpi->oxcf.pass == 1 ? cm->mb_rows : sb_rows;
- // Initialize cur_col to -1 for all rows.
- memset(this_tile->row_mt_sync.cur_col, -1,
- sizeof(*this_tile->row_mt_sync.cur_col) * jobs_per_tile_col);
- vp9_zero(this_tile->fp_data);
- this_tile->fp_data.image_data_start_row = INVALID_ROW;
- }
- }
- void vp9_assign_tile_to_thread(MultiThreadHandle *multi_thread_ctxt,
- int tile_cols, int num_workers) {
- int tile_id = 0;
- int i;
- // Allocating the threads for the tiles
- for (i = 0; i < num_workers; i++) {
- multi_thread_ctxt->thread_id_to_tile_id[i] = tile_id++;
- if (tile_id == tile_cols) tile_id = 0;
- }
- }
- int vp9_get_job_queue_status(MultiThreadHandle *multi_thread_ctxt,
- int cur_tile_id) {
- RowMTInfo *row_mt_info;
- JobQueueHandle *job_queue_hndl;
- #if CONFIG_MULTITHREAD
- pthread_mutex_t *mutex;
- #endif
- int num_jobs_remaining;
- row_mt_info = &multi_thread_ctxt->row_mt_info[cur_tile_id];
- job_queue_hndl = &row_mt_info->job_queue_hdl;
- #if CONFIG_MULTITHREAD
- mutex = &row_mt_info->job_mutex;
- #endif
- #if CONFIG_MULTITHREAD
- pthread_mutex_lock(mutex);
- #endif
- num_jobs_remaining =
- multi_thread_ctxt->jobs_per_tile_col - job_queue_hndl->num_jobs_acquired;
- #if CONFIG_MULTITHREAD
- pthread_mutex_unlock(mutex);
- #endif
- return (num_jobs_remaining);
- }
- void vp9_prepare_job_queue(VP9_COMP *cpi, JOB_TYPE job_type) {
- VP9_COMMON *const cm = &cpi->common;
- MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
- JobQueue *job_queue = multi_thread_ctxt->job_queue;
- const int tile_cols = 1 << cm->log2_tile_cols;
- int job_row_num, jobs_per_tile, jobs_per_tile_col = 0, total_jobs;
- const int sb_rows = mi_cols_aligned_to_sb(cm->mi_rows) >> MI_BLOCK_SIZE_LOG2;
- int tile_col, i;
- switch (job_type) {
- case ENCODE_JOB: jobs_per_tile_col = sb_rows; break;
- case FIRST_PASS_JOB: jobs_per_tile_col = cm->mb_rows; break;
- case ARNR_JOB:
- jobs_per_tile_col = ((cm->mi_rows + TF_ROUND) >> TF_SHIFT);
- break;
- default: assert(0);
- }
- total_jobs = jobs_per_tile_col * tile_cols;
- multi_thread_ctxt->jobs_per_tile_col = jobs_per_tile_col;
- // memset the entire job queue buffer to zero
- memset(job_queue, 0, total_jobs * sizeof(JobQueue));
- // Job queue preparation
- for (tile_col = 0; tile_col < tile_cols; tile_col++) {
- RowMTInfo *tile_ctxt = &multi_thread_ctxt->row_mt_info[tile_col];
- JobQueue *job_queue_curr, *job_queue_temp;
- int tile_row = 0;
- tile_ctxt->job_queue_hdl.next = (void *)job_queue;
- tile_ctxt->job_queue_hdl.num_jobs_acquired = 0;
- job_queue_curr = job_queue;
- job_queue_temp = job_queue;
- // loop over all the vertical rows
- for (job_row_num = 0, jobs_per_tile = 0; job_row_num < jobs_per_tile_col;
- job_row_num++, jobs_per_tile++) {
- job_queue_curr->job_info.vert_unit_row_num = job_row_num;
- job_queue_curr->job_info.tile_col_id = tile_col;
- job_queue_curr->job_info.tile_row_id = tile_row;
- job_queue_curr->next = (void *)(job_queue_temp + 1);
- job_queue_curr = ++job_queue_temp;
- if (ENCODE_JOB == job_type) {
- if (jobs_per_tile >=
- multi_thread_ctxt->num_tile_vert_sbs[tile_row] - 1) {
- tile_row++;
- jobs_per_tile = -1;
- }
- }
- }
- // Set the last pointer to NULL
- job_queue_curr += -1;
- job_queue_curr->next = (void *)NULL;
- // Move to the next tile
- job_queue += jobs_per_tile_col;
- }
- for (i = 0; i < cpi->num_workers; i++) {
- EncWorkerData *thread_data;
- thread_data = &cpi->tile_thr_data[i];
- thread_data->thread_id = i;
- for (tile_col = 0; tile_col < tile_cols; tile_col++)
- thread_data->tile_completion_status[tile_col] = 0;
- }
- }
- int vp9_get_tiles_proc_status(MultiThreadHandle *multi_thread_ctxt,
- int *tile_completion_status, int *cur_tile_id,
- int tile_cols) {
- int tile_col;
- int tile_id = -1; // Stores the tile ID with minimum proc done
- int max_num_jobs_remaining = 0;
- int num_jobs_remaining;
- // Mark the completion to avoid check in the loop
- tile_completion_status[*cur_tile_id] = 1;
- // Check for the status of all the tiles
- for (tile_col = 0; tile_col < tile_cols; tile_col++) {
- if (tile_completion_status[tile_col] == 0) {
- num_jobs_remaining =
- vp9_get_job_queue_status(multi_thread_ctxt, tile_col);
- // Mark the completion to avoid checks during future switches across tiles
- if (num_jobs_remaining == 0) tile_completion_status[tile_col] = 1;
- if (num_jobs_remaining > max_num_jobs_remaining) {
- max_num_jobs_remaining = num_jobs_remaining;
- tile_id = tile_col;
- }
- }
- }
- if (-1 == tile_id) {
- return 1;
- } else {
- // Update the cur ID to the next tile ID that will be processed,
- // which will be the least processed tile
- *cur_tile_id = tile_id;
- return 0;
- }
- }
|