Allintra: Skip the application of post-processing filters

This CL generalizes the logic to skip the application of
post-processing filters on the reconstructed frame. The
application of a post-processing filter is disabled if subsequent
post-processing stages are not dependent on the filtered output
from the current stage or subsequent post-processing stages are
disabled. This is a bit-exact change.

Change-Id: Ia1a97042cf09d26d6dc99ae4660b92af68a323d5
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index c87fe9e..39a6999 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2215,7 +2215,8 @@
  */
 static void cdef_restoration_frame(AV1_COMP *cpi, AV1_COMMON *cm,
                                    MACROBLOCKD *xd, int use_restoration,
-                                   int use_cdef) {
+                                   int use_cdef,
+                                   unsigned int skip_apply_postproc_filters) {
 #if !CONFIG_REALTIME_ONLY
   if (use_restoration)
     av1_loop_restoration_save_boundary_lines(&cm->cur_frame->buf, cm, 0);
@@ -2241,7 +2242,8 @@
                     cpi->ppi->rtc_ref.non_reference_frame);
 
     // Apply the filter
-    if (!cpi->ppi->rtc_ref.non_reference_frame) {
+    if (!cpi->ppi->rtc_ref.non_reference_frame &&
+        (skip_apply_postproc_filters & SKIP_APPLY_CDEF) == 0) {
       if (num_workers > 1) {
         // Extension of frame borders is multi-threaded along with cdef.
         const int do_extend_border =
@@ -2259,7 +2261,12 @@
 #endif
   }
 
-  av1_superres_post_encode(cpi);
+  const int use_superres = av1_superres_scaled(cm);
+  if (use_superres) {
+    if ((skip_apply_postproc_filters & SKIP_APPLY_SUPERRES) == 0) {
+      av1_superres_post_encode(cpi);
+    }
+  }
 
 #if !CONFIG_REALTIME_ONLY
 #if CONFIG_COLLECT_COMPONENT_TIMING
@@ -2270,9 +2277,10 @@
     const int num_workers = mt_info->num_mod_workers[MOD_LR];
     av1_loop_restoration_save_boundary_lines(&cm->cur_frame->buf, cm, 1);
     av1_pick_filter_restoration(cpi->source, cpi);
-    if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
-        cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
-        cm->rst_info[2].frame_restoration_type != RESTORE_NONE) {
+    if ((skip_apply_postproc_filters & SKIP_APPLY_RESTORATION) == 0 &&
+        (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
+         cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
+         cm->rst_info[2].frame_restoration_type != RESTORE_NONE)) {
       if (num_workers > 1) {
         // Extension of frame borders is multi-threaded along with loop
         // restoration filter.
@@ -2324,17 +2332,22 @@
   const int use_loopfilter =
       is_loopfilter_used(cm) && !cpi->mt_info.pipeline_lpf_mt_with_enc;
   const int use_cdef = is_cdef_used(cm);
+  const int use_superres = av1_superres_scaled(cm);
   const int use_restoration = is_restoration_used(cm);
 
+  const unsigned int skip_apply_postproc_filters =
+      derive_skip_apply_postproc_filters(cpi, use_loopfilter, use_cdef,
+                                         use_superres, use_restoration);
+
 #if CONFIG_COLLECT_COMPONENT_TIMING
   start_timing(cpi, loop_filter_time);
 #endif
   if (use_loopfilter) {
     av1_pick_filter_level(cpi->source, cpi, cpi->sf.lpf_sf.lpf_pick);
-    if (should_skip_postproc_filtering(cpi, use_cdef, use_restoration)) return;
     struct loopfilter *lf = &cm->lf;
     if ((lf->filter_level[0] || lf->filter_level[1]) &&
-        !cpi->ppi->rtc_ref.non_reference_frame) {
+        !cpi->ppi->rtc_ref.non_reference_frame &&
+        (skip_apply_postproc_filters & SKIP_APPLY_LOOPFILTER) == 0) {
       // lpf_opt_level = 1 : Enables dual/quad loop-filtering.
       // lpf_opt_level is set to 1 if transform size search depth in inter
       // blocks is limited to one as quad loop filtering assumes that all the
@@ -2354,7 +2367,8 @@
   end_timing(cpi, loop_filter_time);
 #endif
 
-  cdef_restoration_frame(cpi, cm, xd, use_restoration, use_cdef);
+  cdef_restoration_frame(cpi, cm, xd, use_restoration, use_cdef,
+                         skip_apply_postproc_filters);
 }
 
 static void update_motion_stat(AV1_COMP *const cpi) {
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 75d45d8..83e634e 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -232,6 +232,17 @@
       3, /*!< Disable loopfilter on frames with low motion. */
 } LOOPFILTER_CONTROL;
 
+/*!\enum SKIP_APPLY_POSTPROC_FILTER
+ * \brief This enum controls the application of post-processing filters on a
+ * reconstructed frame.
+ */
+typedef enum {
+  SKIP_APPLY_RESTORATION = 1 << 0,
+  SKIP_APPLY_SUPERRES = 1 << 1,
+  SKIP_APPLY_CDEF = 1 << 2,
+  SKIP_APPLY_LOOPFILTER = 1 << 3,
+} SKIP_APPLY_POSTPROC_FILTER;
+
 /*!
  * \brief Encoder config related to resize.
  */
@@ -4121,24 +4132,34 @@
 // filters on the reconstructed frame can be skipped at the encoder side.
 // However the computation of different filter parameters that are signaled in
 // the bitstream is still required.
-static INLINE bool should_skip_postproc_filtering(AV1_COMP *cpi, int use_cdef,
-                                                  int use_restoration) {
+static INLINE unsigned int derive_skip_apply_postproc_filters(
+    const AV1_COMP *cpi, int use_loopfilter, int use_cdef, int use_superres,
+    int use_restoration) {
   if (!cpi->oxcf.algo_cfg.skip_postproc_filtering || cpi->ppi->b_calculate_psnr)
-    return false;
+    return 0;
   assert(cpi->oxcf.mode == ALLINTRA);
-  const AV1_COMMON *const cm = &cpi->common;
 
-  // The post-processing filters are applied one after the other. In case of
+  // The post-processing filters are applied one after the other in the
+  // following order: deblocking->cdef->superres->restoration. In case of
   // ALLINTRA encoding, the reconstructed frame is not used as a reference
   // frame. Hence, the application of these filters can be skipped when
   // 1. filter parameters of the subsequent stages are not dependent on the
   // filtered output of the current stage or
   // 2. subsequent filtering stages are disabled
-  // In case of ALLINTRA encode, CDEF is disabled by default and loop
-  // restoration is disabled for speed >= 5. Hence, the application of
-  // deblocking filters is skipped currently if there are no further filtering
-  // stages.
-  return (!use_cdef && !av1_superres_scaled(cm) && !use_restoration);
+  if (use_restoration) return SKIP_APPLY_RESTORATION;
+  if (use_superres) return SKIP_APPLY_SUPERRES;
+  if (use_cdef) {
+    // CDEF parameter selection is not dependent on the deblocked frame if
+    // cdef_pick_method is CDEF_PICK_FROM_Q. Hence the application of deblocking
+    // filters and cdef filters can be skipped in this case.
+    return (cpi->sf.lpf_sf.cdef_pick_method == CDEF_PICK_FROM_Q &&
+            use_loopfilter)
+               ? (SKIP_APPLY_LOOPFILTER | SKIP_APPLY_CDEF)
+               : SKIP_APPLY_CDEF;
+  }
+  if (use_loopfilter) return SKIP_APPLY_LOOPFILTER;
+
+  return 0;  // All post-processing stages disabled.
 }
 
 static INLINE void set_postproc_filter_default_params(AV1_COMMON *cm) {
diff --git a/av1/encoder/ethread.c b/av1/encoder/ethread.c
index 7aadc1d..55bb232 100644
--- a/av1/encoder/ethread.c
+++ b/av1/encoder/ethread.c
@@ -1603,22 +1603,26 @@
   // decides the filter level. Loop-filtering is disabled in case
   // of non-reference frames and for frames with intra block copy tool enabled.
   AV1_COMMON *cm = &cpi->common;
+  const int use_loopfilter = is_loopfilter_used(cm);
+  const int use_superres = av1_superres_scaled(cm);
   const int use_cdef = is_cdef_used(cm);
   const int use_restoration = is_restoration_used(cm);
-  const int skip_postproc_filtering =
-      should_skip_postproc_filtering(cpi, use_cdef, use_restoration);
+
+  const unsigned int skip_apply_postproc_filters =
+      derive_skip_apply_postproc_filters(cpi, use_loopfilter, use_cdef,
+                                         use_superres, use_restoration);
   cpi->mt_info.pipeline_lpf_mt_with_enc =
       (cpi->oxcf.mode == REALTIME) && (cpi->oxcf.speed >= 5) &&
       (cpi->sf.lpf_sf.lpf_pick == LPF_PICK_FROM_Q) &&
       (cpi->oxcf.algo_cfg.loopfilter_control != LOOPFILTER_SELECTIVELY) &&
       !cpi->ppi->rtc_ref.non_reference_frame && !cm->features.allow_intrabc &&
-      !skip_postproc_filtering;
+      ((skip_apply_postproc_filters & SKIP_APPLY_LOOPFILTER) == 0);
 
   if (!cpi->mt_info.pipeline_lpf_mt_with_enc) return;
 
   set_postproc_filter_default_params(cm);
 
-  if (!is_loopfilter_used(cm)) return;
+  if (!use_loopfilter) return;
 
   const LPF_PICK_METHOD method = cpi->sf.lpf_sf.lpf_pick;
   assert(method == LPF_PICK_FROM_Q);
diff --git a/av1/encoder/superres_scale.c b/av1/encoder/superres_scale.c
index 283faab..f439e70 100644
--- a/av1/encoder/superres_scale.c
+++ b/av1/encoder/superres_scale.c
@@ -399,8 +399,6 @@
 void av1_superres_post_encode(AV1_COMP *cpi) {
   AV1_COMMON *cm = &cpi->common;
 
-  if (!av1_superres_scaled(cm)) return;
-
   assert(cpi->oxcf.superres_cfg.enable_superres);
   assert(!is_lossless_requested(&cpi->oxcf.rc_cfg));
   assert(!cm->features.all_lossless);