FPMT: Recompute frame parallel contexts

Disabled FPMT when unsupported configurations are set through control
calls. Recomputed maximum number of frame contexts at the beginning of
each sub-gop to account for updates to supported configurations.
Cleanup in is_fpmt_config function.

Change-Id: I1c343110e0b8cebc1584895cd43ff1ba1779768e
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index a396fb9..972b563 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -1505,6 +1505,9 @@
   if (res == AOM_CODEC_OK) {
     ctx->extra_cfg = *extra_cfg;
     set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
+#if CONFIG_FRAME_PARALLEL_ENCODE
+    av1_check_fpmt_config(ctx->ppi, &ctx->oxcf);
+#endif
     bool is_sb_size_changed = false;
     av1_change_config_seq(ctx->ppi, &ctx->oxcf, &is_sb_size_changed);
 #if CONFIG_FRAME_PARALLEL_ENCODE
@@ -2605,7 +2608,7 @@
   if (ctx->ppi) {
     AV1_PRIMARY *ppi = ctx->ppi;
 #if CONFIG_FRAME_PARALLEL_ENCODE
-    for (int i = 0; i < ppi->num_fp_contexts - 1; i++) {
+    for (int i = 0; i < MAX_PARALLEL_FRAMES - 1; i++) {
       if (ppi->parallel_frames_data[i].cx_data) {
         free(ppi->parallel_frames_data[i].cx_data);
       }
@@ -2619,7 +2622,7 @@
 #endif
 #if CONFIG_FRAME_PARALLEL_ENCODE
     int i;
-    for (i = 0; i < ppi->num_fp_contexts; i++) {
+    for (i = 0; i < MAX_PARALLEL_FRAMES; i++) {
       destroy_context_and_bufferpool(ppi->parallel_cpi[i], &ctx->buffer_pool);
     }
     ppi->cpi = NULL;
@@ -2909,6 +2912,15 @@
       av1_post_encode_updates(cpi_lap, &cpi_lap_data);
     }
 
+#if CONFIG_FRAME_PARALLEL_ENCODE
+    // Recalculate the maximum number of frames that can be encoded in
+    // parallel at the beginning of sub gop.
+    if (is_stat_consumption_stage(cpi) && ppi->gf_group.size > 0 &&
+        cpi->gf_frame_index == ppi->gf_group.size) {
+      ppi->num_fp_contexts = av1_compute_num_fp_contexts(ppi, &cpi->oxcf);
+    }
+#endif  // CONFIG_FRAME_PARALLEL_ENCODE
+
     // Get the next visible frame. Invisible frames get packed with the next
     // visible frame.
     while (cpi_data.cx_data_sz >= ctx->cx_data_sz / 2 && !is_frame_visible) {
@@ -3238,6 +3250,9 @@
     const int res = av1_set_internal_size(
         &ctx->ppi->cpi->oxcf, &ctx->ppi->cpi->resize_pending_params,
         (AOM_SCALING)mode->h_scaling_mode, (AOM_SCALING)mode->v_scaling_mode);
+#if CONFIG_FRAME_PARALLEL_ENCODE
+    av1_check_fpmt_config(ctx->ppi, &ctx->ppi->cpi->oxcf);
+#endif
     return (res == 0) ? AOM_CODEC_OK : AOM_CODEC_INVALID_PARAM;
   } else {
     return AOM_CODEC_INVALID_PARAM;
@@ -3311,6 +3326,9 @@
     }
     av1_update_layer_context_change_config(cpi, target_bandwidth);
   }
+#if CONFIG_FRAME_PARALLEL_ENCODE
+  av1_check_fpmt_config(ctx->ppi, &ctx->ppi->cpi->oxcf);
+#endif  // CONFIG_FRAME_PARALLEL_ENCODE
   return AOM_CODEC_OK;
 }
 
diff --git a/av1/encoder/ethread.c b/av1/encoder/ethread.c
index 0506170..c140c13 100644
--- a/av1/encoder/ethread.c
+++ b/av1/encoder/ethread.c
@@ -838,7 +838,7 @@
 // the current configuration. Returns 0 otherwise.
 static AOM_INLINE int is_fpmt_config(AV1_PRIMARY *ppi, AV1EncoderConfig *oxcf) {
   // FPMT is enabled for AOM_Q and AOM_VBR.
-  // TODO(Mufaddal, Aasaipriya): Test and enable multi-tile and resize config.
+  // TODO(Tarun): Test and enable resize config.
   if (oxcf->rc_cfg.mode == AOM_CBR || oxcf->rc_cfg.mode == AOM_CQ) {
     return 0;
   }
@@ -860,13 +860,47 @@
   if (oxcf->resize_cfg.resize_mode) {
     return 0;
   }
-  if (oxcf->passes == 1) {
+  if (oxcf->pass != AOM_RC_SECOND_PASS) {
+    return 0;
+  }
+  if (oxcf->max_threads < 2) {
     return 0;
   }
 
   return 1;
 }
 
+int av1_check_fpmt_config(AV1_PRIMARY *const ppi,
+                          AV1EncoderConfig *const oxcf) {
+  if (is_fpmt_config(ppi, oxcf)) return 1;
+  // Reset frame parallel configuration for unsupported config
+  if (ppi->num_fp_contexts > 1) {
+    for (int i = 1; i < ppi->num_fp_contexts; i++) {
+      // Release the previously-used frame-buffer
+      if (ppi->parallel_cpi[i]->common.cur_frame != NULL) {
+        --ppi->parallel_cpi[i]->common.cur_frame->ref_count;
+        ppi->parallel_cpi[i]->common.cur_frame = NULL;
+      }
+    }
+
+    int cur_gf_index = ppi->cpi->gf_frame_index;
+    int reset_size = AOMMAX(0, ppi->gf_group.size - cur_gf_index);
+    av1_zero_array(&ppi->gf_group.frame_parallel_level[cur_gf_index],
+                   reset_size);
+    av1_zero_array(&ppi->gf_group.is_frame_non_ref[cur_gf_index], reset_size);
+    av1_zero_array(&ppi->gf_group.src_offset[cur_gf_index], reset_size);
+#if CONFIG_FRAME_PARALLEL_ENCODE_2
+    memset(&ppi->gf_group.skip_frame_refresh[cur_gf_index][0], INVALID_IDX,
+           sizeof(ppi->gf_group.skip_frame_refresh[cur_gf_index][0]) *
+               reset_size * REF_FRAMES);
+    memset(&ppi->gf_group.skip_frame_as_ref[cur_gf_index], INVALID_IDX,
+           sizeof(ppi->gf_group.skip_frame_as_ref[cur_gf_index]) * reset_size);
+#endif
+    ppi->num_fp_contexts = 1;
+  }
+  return 0;
+}
+
 // A large value for threads used to compute the max num_enc_workers
 // possible for each resolution.
 #define MAX_THREADS 100
@@ -875,7 +909,7 @@
 // based on the number of max_enc_workers.
 int av1_compute_num_fp_contexts(AV1_PRIMARY *ppi, AV1EncoderConfig *oxcf) {
   ppi->p_mt_info.num_mod_workers[MOD_FRAME_ENC] = 0;
-  if (!is_fpmt_config(ppi, oxcf)) {
+  if (!av1_check_fpmt_config(ppi, oxcf)) {
     return 1;
   }
   int max_num_enc_workers =
@@ -888,8 +922,11 @@
   int num_fp_contexts = max_threads / workers_per_frame;
 
   num_fp_contexts = AOMMAX(1, AOMMIN(num_fp_contexts, MAX_PARALLEL_FRAMES));
+  // Limit recalculated num_fp_contexts to ppi->num_fp_contexts.
+  num_fp_contexts = (ppi->num_fp_contexts == 1)
+                        ? num_fp_contexts
+                        : AOMMIN(num_fp_contexts, ppi->num_fp_contexts);
   if (num_fp_contexts > 1) {
-    assert(max_threads >= 2);
     ppi->p_mt_info.num_mod_workers[MOD_FRAME_ENC] =
         AOMMIN(max_num_enc_workers * num_fp_contexts, oxcf->max_threads);
   }
diff --git a/av1/encoder/ethread.h b/av1/encoder/ethread.h
index bd75664..f56dcc0 100644
--- a/av1/encoder/ethread.h
+++ b/av1/encoder/ethread.h
@@ -117,6 +117,8 @@
 #if CONFIG_FRAME_PARALLEL_ENCODE
 int av1_compute_num_fp_contexts(AV1_PRIMARY *ppi, AV1EncoderConfig *oxcf);
 
+int av1_check_fpmt_config(AV1_PRIMARY *const ppi, AV1EncoderConfig *const oxcf);
+
 int av1_compress_parallel_frames(AV1_PRIMARY *const ppi,
                                  AV1_COMP_DATA *const first_cpi_data);
 #endif