FPMT SIMULATION: Handle frame probabilities in recode path.

Introduce temporary members to track the frame level probabilities
across recodes in each frame. Frame probability calculation for the
parallel frames are done sequentially at postencode process after
all the parallel frames are done.

Change-Id: Ibcead9e29b4ce265a3878bc916a490db6439f7bc
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index a35e801..2cd57e3 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -1262,9 +1262,12 @@
   FeatureFlags *const features = &cm->features;
   MACROBLOCKD *const xd = &x->e_mbd;
   RD_COUNTS *const rdc = &cpi->td.rd_counts;
-  FrameProbInfo *const frame_probs = &cpi->frame_probs;
 #if CONFIG_FRAME_PARALLEL_ENCODE
   FrameProbInfo *const temp_frame_probs = &cpi->ppi->temp_frame_probs;
+  FrameProbInfo *const temp_frame_probs_simulation =
+      &cpi->ppi->temp_frame_probs_simulation;
+#else
+  FrameProbInfo *const frame_probs = &cpi->frame_probs;
 #endif  // CONFIG_FRAME_PARALLEL_ENCODE
   IntraBCHashInfo *const intrabc_hash_info = &x->intrabc_hash_info;
   MultiThreadInfo *const mt_info = &cpi->mt_info;
@@ -1525,6 +1528,26 @@
   assert(oxcf->txfm_cfg.enable_tx64 || tx_search_type != USE_LARGESTALL);
   features->tx_mode = select_tx_mode(cm, tx_search_type);
 
+#if CONFIG_FRAME_PARALLEL_ENCODE
+  // Retain the frame level probability update conditions for parallel frames.
+  // These conditions will be consumed during postencode stage to update the
+  // probability.
+  if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
+    cpi->do_update_frame_probs_txtype[cpi->num_frame_recode] =
+        cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats;
+    cpi->do_update_frame_probs_obmc[cpi->num_frame_recode] =
+        (cpi->sf.inter_sf.prune_obmc_prob_thresh > 0 &&
+         cpi->sf.inter_sf.prune_obmc_prob_thresh < INT_MAX);
+    cpi->do_update_frame_probs_warp[cpi->num_frame_recode] =
+        (features->allow_warped_motion &&
+         cpi->sf.inter_sf.prune_warped_prob_thresh > 0);
+    cpi->do_update_frame_probs_interpfilter[cpi->num_frame_recode] =
+        (cm->current_frame.frame_type != KEY_FRAME &&
+         cpi->sf.interp_sf.adaptive_interp_filter_search == 2 &&
+         features->interp_filter == SWITCHABLE);
+  }
+#endif
+
   if (cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats) {
     const FRAME_UPDATE_TYPE update_type =
         get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
@@ -1540,29 +1563,36 @@
         const int new_prob =
             sum ? 1024 * cpi->td.rd_counts.tx_type_used[i][j] / sum
                 : (j ? 0 : 1024);
+#if CONFIG_FRAME_PARALLEL_ENCODE
+        if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) {
+          int prob =
+              (temp_frame_probs_simulation->tx_type_probs[update_type][i][j] +
+               new_prob) >>
+              1;
+          left -= prob;
+          if (j == 0) prob += left;
+          temp_frame_probs_simulation->tx_type_probs[update_type][i][j] = prob;
+          // Copy temp_frame_probs_simulation to temp_frame_probs
+          for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
+               update_type_idx++) {
+            temp_frame_probs->tx_type_probs[update_type_idx][i][j] =
+                temp_frame_probs_simulation
+                    ->tx_type_probs[update_type_idx][i][j];
+          }
+        }
+        // Track the frame probabilities to update during postencode. The frame
+        // probabilities are updated in ppi->temp_frame_probabilities_simulation
+        // instead of cpi->frame_probs.
+        if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
+          cpi->frame_new_probs[cpi->num_frame_recode]
+              .tx_type_probs[update_type][i][j] = new_prob;
+        }
+#else
         int prob =
             (frame_probs->tx_type_probs[update_type][i][j] + new_prob) >> 1;
         left -= prob;
         if (j == 0) prob += left;
         frame_probs->tx_type_probs[update_type][i][j] = prob;
-#if CONFIG_FRAME_PARALLEL_ENCODE
-        /* TODO(FPMT): The current update is happening in cpi->frame_probs,
-         * this need to be taken care appropriately in final FPMT implementation
-         * to carry these values to subsequent frames. The frame_probs update is
-         * accumulated across frames, so the values from all individual parallel
-         * frames need to be taken into account after all the parallel frames
-         * are encoded.
-         *
-         * Only for quality simulation purpose - Update the accumulated frame
-         * probabilities in ppi->temp_variable based on the update flag.
-         */
-        if (cpi->do_frame_data_update) {
-          for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
-               update_type_idx++) {
-            temp_frame_probs->tx_type_probs[update_type_idx][i][j] =
-                frame_probs->tx_type_probs[update_type_idx][i][j];
-          }
-        }
 #endif  // CONFIG_FRAME_PARALLEL_ENCODE
       }
     }
@@ -1579,26 +1609,29 @@
 
       const int new_prob =
           sum ? 128 * cpi->td.rd_counts.obmc_used[i][1] / sum : 0;
-      frame_probs->obmc_probs[update_type][i] =
-          (frame_probs->obmc_probs[update_type][i] + new_prob) >> 1;
 #if CONFIG_FRAME_PARALLEL_ENCODE
-      /* TODO(FPMT): The current update is happening in cpi->frame_probs,
-       * this need to be taken care appropriately in final FPMT
-       * implementation to carry these values to subsequent frames.
-       * The frame_probs update is accumulated across frames, so the
-       * values from all individual parallel frames need to be taken
-       * into account after all the parallel frames are encoded.
-       *
-       * Only for quality simulation purpose - Update the accumulated frame
-       * probabilities in ppi->temp_variable based on the update flag.
-       */
-      if (cpi->do_frame_data_update) {
+      if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) {
+        temp_frame_probs_simulation->obmc_probs[update_type][i] =
+            (temp_frame_probs_simulation->obmc_probs[update_type][i] +
+             new_prob) >>
+            1;
+        // Copy temp_frame_probs_simulation to temp_frame_probs
         for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
              update_type_idx++) {
           temp_frame_probs->obmc_probs[update_type_idx][i] =
-              frame_probs->obmc_probs[update_type_idx][i];
+              temp_frame_probs_simulation->obmc_probs[update_type_idx][i];
         }
       }
+      // Track the frame probabilities to update during postencode. The frame
+      // probabilities are updated in ppi->temp_frame_probabilities_simulation
+      // instead of cpi->frame_probs.
+      if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
+        cpi->frame_new_probs[cpi->num_frame_recode].obmc_probs[update_type][i] =
+            new_prob;
+      }
+#else
+      frame_probs->obmc_probs[update_type][i] =
+          (frame_probs->obmc_probs[update_type][i] + new_prob) >> 1;
 #endif  // CONFIG_FRAME_PARALLEL_ENCODE
     }
   }
@@ -1610,26 +1643,28 @@
     int sum = 0;
     for (i = 0; i < 2; i++) sum += cpi->td.rd_counts.warped_used[i];
     const int new_prob = sum ? 128 * cpi->td.rd_counts.warped_used[1] / sum : 0;
-    frame_probs->warped_probs[update_type] =
-        (frame_probs->warped_probs[update_type] + new_prob) >> 1;
 #if CONFIG_FRAME_PARALLEL_ENCODE
-    /* TODO(FPMT): The current update is happening in cpi->frame_probs,
-     * this need to be taken care appropriately in final FPMT
-     * implementation to carry these values to subsequent frames.
-     * The frame_probs update is accumulated across frames, so the
-     * values from all individual parallel frames need to be taken
-     * into account after all the parallel frames are encoded.
-     *
-     * Only for quality simulation purpose - Update the accumulated frame
-     * probabilities in ppi->temp_variable based on the update flag.
-     */
-    if (cpi->do_frame_data_update) {
+    if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) {
+      temp_frame_probs_simulation->warped_probs[update_type] =
+          (temp_frame_probs_simulation->warped_probs[update_type] + new_prob) >>
+          1;
+      // Copy temp_frame_probs_simulation to temp_frame_probs
       for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
            update_type_idx++) {
         temp_frame_probs->warped_probs[update_type_idx] =
-            frame_probs->warped_probs[update_type_idx];
+            temp_frame_probs_simulation->warped_probs[update_type_idx];
       }
     }
+    // Track the frame probabilities to update during postencode. The frame
+    // probabilities are updated in ppi->temp_frame_probabilities_simulation
+    // instead of cpi->frame_probs.
+    if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
+      cpi->frame_new_probs[cpi->num_frame_recode].warped_probs[update_type] =
+          new_prob;
+    }
+#else
+    frame_probs->warped_probs[update_type] =
+        (frame_probs->warped_probs[update_type] + new_prob) >> 1;
 #endif  // CONFIG_FRAME_PARALLEL_ENCODE
   }
 
@@ -1652,30 +1687,38 @@
         const int new_prob =
             sum ? 1536 * cpi->td.counts->switchable_interp[i][j] / sum
                 : (j ? 0 : 1536);
+#if CONFIG_FRAME_PARALLEL_ENCODE
+        if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) {
+          int prob = (temp_frame_probs_simulation
+                          ->switchable_interp_probs[update_type][i][j] +
+                      new_prob) >>
+                     1;
+          left -= prob;
+          if (j == 0) prob += left;
+          temp_frame_probs_simulation
+              ->switchable_interp_probs[update_type][i][j] = prob;
+          // Copy temp_frame_probs_simulation to temp_frame_probs
+          for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
+               update_type_idx++) {
+            temp_frame_probs->switchable_interp_probs[update_type_idx][i][j] =
+                temp_frame_probs_simulation
+                    ->switchable_interp_probs[update_type_idx][i][j];
+          }
+        }
+        // Track the frame probabilities to update during postencode. The frame
+        // probabilities are updated in ppi->temp_frame_probabilities_simulation
+        // instead of cpi->frame_probs.
+        if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
+          cpi->frame_new_probs[cpi->num_frame_recode]
+              .switchable_interp_probs[update_type][i][j] = new_prob;
+        }
+#else
         int prob = (frame_probs->switchable_interp_probs[update_type][i][j] +
                     new_prob) >>
                    1;
         left -= prob;
         if (j == 0) prob += left;
         frame_probs->switchable_interp_probs[update_type][i][j] = prob;
-#if CONFIG_FRAME_PARALLEL_ENCODE
-        /* TODO(FPMT): The current update is happening in cpi->frame_probs,
-         * this need to be taken care appropriately in final FPMT
-         * implementation to carry these values to subsequent frames.
-         * The frame_probs update is accumulated across frames, so the
-         * values from all individual parallel frames need to be taken
-         * into account after all the parallel frames are encoded.
-         *
-         * Only for quality simulation purpose - Update the accumulated frame
-         * probabilities in ppi->temp_variable based on the update flag.
-         */
-        if (cpi->do_frame_data_update) {
-          for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
-               update_type_idx++) {
-            temp_frame_probs->switchable_interp_probs[update_type_idx][i][j] =
-                frame_probs->switchable_interp_probs[update_type_idx][i][j];
-          }
-        }
 #endif  // CONFIG_FRAME_PARALLEL_ENCODE
       }
     }
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 38636bc..20cc13e 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2508,6 +2508,9 @@
   int original_q = 0;
 #endif
 
+#if CONFIG_FRAME_PARALLEL_ENCODE
+  cpi->num_frame_recode = 0;
+#endif
   // Loop variables
   int loop = 0;
   int loop_count = 0;
@@ -2727,7 +2730,12 @@
 
     if (loop) {
       ++loop_count;
-
+#if CONFIG_FRAME_PARALLEL_ENCODE
+      cpi->num_frame_recode =
+          (cpi->num_frame_recode < (NUM_RECODES_PER_FRAME - 1))
+              ? ++cpi->num_frame_recode
+              : NUM_RECODES_PER_FRAME - 1;
+#endif
 #if CONFIG_INTERNAL_STATS
       ++cpi->frame_recode_hits;
 #endif
@@ -2796,6 +2804,15 @@
 #if CONFIG_COLLECT_COMPONENT_TIMING
   start_timing(cpi, encode_with_recode_loop_time);
 #endif
+#if CONFIG_FRAME_PARALLEL_ENCODE
+  for (int i = 0; i < NUM_RECODES_PER_FRAME; i++) {
+    cpi->do_update_frame_probs_txtype[i] = 0;
+    cpi->do_update_frame_probs_obmc[i] = 0;
+    cpi->do_update_frame_probs_warp[i] = 0;
+    cpi->do_update_frame_probs_interpfilter[i] = 0;
+  }
+#endif
+
   int err;
 #if CONFIG_REALTIME_ONLY
   err = encode_without_recode(cpi);
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index f38dbc3..67b6591 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -1432,6 +1432,10 @@
  * \brief Max number of frames that can be encoded in a parallel encode set.
  */
 #define MAX_PARALLEL_FRAMES 4
+/*!
+ * \brief Max number of recodes used to track the frame probabilities.
+ */
+#define NUM_RECODES_PER_FRAME 10
 #endif  // CONFIG_FRAME_PARALLEL_ENCODE
 
 /*!
@@ -2228,6 +2232,16 @@
   FrameProbInfo temp_frame_probs;
 
   /*!
+   * TODO(FPMT): Temporary variable holding the updated frame probability across
+   * frames. Copy its value to temp_frame_probs for frame_parallel_level 0
+   * frames or last frame in parallel encode set. In final implementation we can
+   * remove cpi->frame_probs and convert this as main variable across the
+   * encoder by moving this temp variable outside the macro. Currently
+   * cpi->frame_probs is not used in FPMT path.
+   */
+  FrameProbInfo temp_frame_probs_simulation;
+
+  /*!
    * Temporary variable used in simulating the delayed update of
    * avg_frame_qindex.
    */
@@ -2778,6 +2792,19 @@
    */
   FrameProbInfo frame_probs;
 
+#if CONFIG_FRAME_PARALLEL_ENCODE
+  // Number of recodes in the frame.
+  int num_frame_recode;
+
+  // Current frame probability of parallel frames, across recodes.
+  FrameProbInfo frame_new_probs[NUM_RECODES_PER_FRAME];
+
+  // Retain condition for frame_probability calculation
+  int do_update_frame_probs_txtype[NUM_RECODES_PER_FRAME];
+  int do_update_frame_probs_obmc[NUM_RECODES_PER_FRAME];
+  int do_update_frame_probs_warp[NUM_RECODES_PER_FRAME];
+  int do_update_frame_probs_interpfilter[NUM_RECODES_PER_FRAME];
+#endif
   /*!
    * Multi-threading parameters.
    */
diff --git a/av1/encoder/encoder_utils.h b/av1/encoder/encoder_utils.h
index 234b13c..6034929 100644
--- a/av1/encoder/encoder_utils.h
+++ b/av1/encoder/encoder_utils.h
@@ -886,6 +886,23 @@
     av1_copy(temp_frame_probs->switchable_interp_probs,
              default_switchable_interp_probs);
   }
+
+  FrameProbInfo *const temp_frame_probs_simulation =
+      &cpi->ppi->temp_frame_probs_simulation;
+  if (cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats) {
+    av1_copy(temp_frame_probs_simulation->tx_type_probs, default_tx_type_probs);
+  }
+  if (cpi->sf.inter_sf.prune_obmc_prob_thresh > 0 &&
+      cpi->sf.inter_sf.prune_obmc_prob_thresh < INT_MAX) {
+    av1_copy(temp_frame_probs_simulation->obmc_probs, default_obmc_probs);
+  }
+  if (cpi->sf.inter_sf.prune_warped_prob_thresh > 0) {
+    av1_copy(temp_frame_probs_simulation->warped_probs, default_warped_probs);
+  }
+  if (cpi->sf.interp_sf.adaptive_interp_filter_search == 2) {
+    av1_copy(temp_frame_probs_simulation->switchable_interp_probs,
+             default_switchable_interp_probs);
+  }
 #endif
 }
 
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index 1ec9580..a5d1331 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -4137,5 +4137,133 @@
         cpi->ppi->p_rc.temp_active_best_quality[i] = rc->active_best_quality[i];
     }
   }
+
+  // Update the frame probabilities obtained from parallel encode frames
+  FrameProbInfo *const temp_frame_probs_simulation =
+      &cpi->ppi->temp_frame_probs_simulation;
+  FrameProbInfo *const temp_frame_probs = &cpi->ppi->temp_frame_probs;
+  int i, j, loop;
+  AV1_COMMON *const cm = &cpi->common;
+  FeatureFlags *const features = &cm->features;
+  // Sequentially do average on temp_frame_probs_simulation which holds
+  // probabilities of last frame before parallel encode
+  for (loop = 0; loop <= cpi->num_frame_recode; loop++) {
+    // Sequentially update tx_type_probs
+    if (cpi->do_update_frame_probs_txtype[loop] &&
+        (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0)) {
+      const FRAME_UPDATE_TYPE update_type =
+          get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
+      for (i = 0; i < TX_SIZES_ALL; i++) {
+        int j;
+        int left = 1024;
+
+        for (j = TX_TYPES - 1; j >= 0; j--) {
+          const int new_prob =
+              cpi->frame_new_probs[loop].tx_type_probs[update_type][i][j];
+          int prob =
+              (temp_frame_probs_simulation->tx_type_probs[update_type][i][j] +
+               new_prob) >>
+              1;
+          left -= prob;
+          if (j == 0) prob += left;
+          temp_frame_probs_simulation->tx_type_probs[update_type][i][j] = prob;
+
+          if (cpi->do_frame_data_update) {
+            // Copying temp_frame_probs_simulation to temp_frame_probs based on
+            // the flag
+            for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
+                 update_type_idx++) {
+              temp_frame_probs->tx_type_probs[update_type_idx][i][j] =
+                  temp_frame_probs_simulation
+                      ->tx_type_probs[update_type_idx][i][j];
+            }
+          }
+        }
+      }
+    }
+
+    // Sequentially update obmc_probs
+    if (cpi->do_update_frame_probs_obmc[loop] &&
+        cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
+      const FRAME_UPDATE_TYPE update_type =
+          get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
+
+      for (i = 0; i < BLOCK_SIZES_ALL; i++) {
+        const int new_prob =
+            cpi->frame_new_probs[loop].obmc_probs[update_type][i];
+        temp_frame_probs_simulation->obmc_probs[update_type][i] =
+            (temp_frame_probs_simulation->obmc_probs[update_type][i] +
+             new_prob) >>
+            1;
+
+        if (cpi->do_frame_data_update) {
+          // Copying temp_frame_probs_simulation to temp_frame_probs based on
+          // the flag
+          for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
+               update_type_idx++) {
+            temp_frame_probs->obmc_probs[update_type_idx][i] =
+                temp_frame_probs_simulation->obmc_probs[update_type_idx][i];
+          }
+        }
+      }
+    }
+
+    // Sequentially update warped_probs
+    if (cpi->do_update_frame_probs_warp[loop] &&
+        cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
+      const FRAME_UPDATE_TYPE update_type =
+          get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
+      const int new_prob = cpi->frame_new_probs[loop].warped_probs[update_type];
+      temp_frame_probs_simulation->warped_probs[update_type] =
+          (temp_frame_probs_simulation->warped_probs[update_type] + new_prob) >>
+          1;
+
+      if (cpi->do_frame_data_update) {
+        // Copying temp_frame_probs_simulation to temp_frame_probs based on the
+        // flag
+        for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
+             update_type_idx++) {
+          temp_frame_probs->warped_probs[update_type_idx] =
+              temp_frame_probs_simulation->warped_probs[update_type_idx];
+        }
+      }
+    }
+
+    // Sequentially update switchable_interp_probs
+    if (cpi->do_update_frame_probs_interpfilter[loop] &&
+        cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
+      const FRAME_UPDATE_TYPE update_type =
+          get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
+
+      for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++) {
+        int j;
+        int left = 1536;
+
+        for (j = SWITCHABLE_FILTERS - 1; j >= 0; j--) {
+          const int new_prob = cpi->frame_new_probs[loop]
+                                   .switchable_interp_probs[update_type][i][j];
+          int prob = (temp_frame_probs_simulation
+                          ->switchable_interp_probs[update_type][i][j] +
+                      new_prob) >>
+                     1;
+          left -= prob;
+          if (j == 0) prob += left;
+          temp_frame_probs_simulation
+              ->switchable_interp_probs[update_type][i][j] = prob;
+
+          if (cpi->do_frame_data_update) {
+            // Copying temp_frame_probs_simulation to temp_frame_probs based on
+            // the flag
+            for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
+                 update_type_idx++) {
+              temp_frame_probs->switchable_interp_probs[update_type_idx][i][j] =
+                  temp_frame_probs_simulation
+                      ->switchable_interp_probs[update_type_idx][i][j];
+            }
+          }
+        }
+      }
+    }
+  }
 #endif
 }