333 lines · 11.0 KB · C
RawDownload
/* *  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;  }}

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