Add try_level_down_facade()

Change-Id: I82e12e312e6685c3801b243196af2570d3793aac
diff --git a/av1/encoder/encodetxb.c b/av1/encoder/encodetxb.c
index dc84837..6d82c64 100644
--- a/av1/encoder/encodetxb.c
+++ b/av1/encoder/encodetxb.c
@@ -21,6 +21,8 @@
 #include "av1/encoder/subexp.h"
 #include "av1/encoder/tokenize.h"
 
+#define TEST_OPTIMIZE_TXB 0
+
 void av1_alloc_txb_buf(AV1_COMP *cpi) {
 #if 0
   AV1_COMMON *cm = &cpi->common;
@@ -983,6 +985,12 @@
   }
   return cost_diff;
 }
+
+static INLINE tran_low_t qcoeff_to_dqcoeff(tran_low_t qc, int dqv, int shift) {
+  int sgn = qc < 0 ? -1 : 1;
+  return sgn * ((abs(qc) * dqv) >> shift);
+}
+
 static int get_coeff_cost(tran_low_t qc, int scan_idx, TxbInfo *txb_info,
                           TxbProbs *txb_probs) {
   const TXB_CTX *txb_ctx = txb_info->txb_ctx;
@@ -1026,6 +1034,28 @@
   return cost;
 }
 
+#if TEST_OPTIMIZE_TXB
+static void test_level_down(int coeff_idx, TxbCache *txb_cache,
+                            TxbProbs *txb_probs, TxbInfo *txb_info) {
+  int cost_map[COST_MAP_SIZE][COST_MAP_SIZE];
+  int ref_cost_map[COST_MAP_SIZE][COST_MAP_SIZE];
+  const int cost_diff =
+      try_level_down(coeff_idx, txb_cache, txb_probs, txb_info, cost_map);
+  const int cost_diff_ref = try_level_down_ref(coeff_idx, txb_cache, txb_probs,
+                                               txb_info, ref_cost_map);
+  if (cost_diff != cost_diff_ref) {
+    printf("qc %d cost_diff %d cost_diff_ref %d\n", txb_info->qcoeff[coeff_idx],
+           cost_diff, cost_diff_ref);
+    for (int r = 0; r < COST_MAP_SIZE; ++r) {
+      for (int c = 0; c < COST_MAP_SIZE; ++c) {
+        printf("%d:%d ", cost_map[r][c], ref_cost_map[r][c]);
+      }
+      printf("\n");
+    }
+  }
+}
+#endif
+
 // TODO(angiebird): make this static once it's called
 int get_txb_cost(TxbInfo *txb_info, TxbProbs *txb_probs) {
   int cost = 0;
@@ -1044,6 +1074,64 @@
   return cost;
 }
 
+static INLINE int64_t get_coeff_dist(tran_low_t tcoeff, tran_low_t dqcoeff,
+                                     int shift) {
+  const int64_t diff = (tcoeff - dqcoeff) * (1 << shift);
+  const int64_t error = diff * diff;
+  return error;
+}
+
+typedef struct LevelDownStats {
+  int update;
+  tran_low_t low_qc;
+  tran_low_t low_dqc;
+  int64_t rd_diff;
+  int cost_diff;
+  int64_t dist_diff;
+  int new_eob;
+} LevelDownStats;
+
+void try_level_down_facade(LevelDownStats *stats, int scan_idx,
+                           const TxbCache *txb_cache, const TxbProbs *txb_probs,
+                           TxbInfo *txb_info) {
+  const int16_t *scan = txb_info->scan_order->scan;
+  const int coeff_idx = scan[scan_idx];
+  const tran_low_t qc = txb_info->qcoeff[coeff_idx];
+  stats->new_eob = -1;
+  stats->update = 0;
+  if (qc == 0) {
+    return;
+  }
+
+  const tran_low_t tqc = txb_info->tcoeff[coeff_idx];
+  const int dqv = txb_info->dequant[coeff_idx != 0];
+
+  const tran_low_t dqc = qcoeff_to_dqcoeff(qc, dqv, txb_info->shift);
+  const int64_t dqc_dist = get_coeff_dist(tqc, dqc, txb_info->shift);
+
+  stats->low_qc = get_lower_coeff(qc);
+  stats->low_dqc = qcoeff_to_dqcoeff(stats->low_qc, dqv, txb_info->shift);
+  const int64_t low_dqc_dist =
+      get_coeff_dist(tqc, stats->low_dqc, txb_info->shift);
+
+  stats->dist_diff = -dqc_dist + low_dqc_dist;
+  stats->cost_diff = 0;
+  stats->new_eob = txb_info->eob;
+  if (scan_idx == txb_info->eob - 1 && abs(qc) == 1) {
+    stats->cost_diff = try_change_eob(&stats->new_eob, coeff_idx, txb_cache,
+                                      txb_probs, txb_info);
+  } else {
+    stats->cost_diff =
+        try_level_down(coeff_idx, txb_cache, txb_probs, txb_info, NULL);
+#if TEST_OPTIMIZE_TXB
+    test_level_down(coeff_idx, txb_cache, txb_probs, txb_info);
+#endif
+  }
+  stats->rd_diff = RDCOST(txb_info->rdmult, txb_info->rddiv, stats->cost_diff,
+                          stats->dist_diff);
+  if (stats->rd_diff < 0) stats->update = 1;
+  return;
+}
 int av1_get_txb_entropy_context(const tran_low_t *qcoeff,
                                 const SCAN_ORDER *scan_order, int eob) {
   const int16_t *scan = scan_order->scan;