Set up explicit reference frame maps in GF_GROUP

- Add two arrays ref_frame_disp_idx and ref_frame_gop_idx, holding
gop indices and display order indices of reference frames of frames
in the current gop.
- Rename 'frame_gop_index' as 'frame_disp_idx' because the values
are indices in display order
- If a reference frame, other than the golden frame, is not in the
current gop, the index is set as -1
- TODO: need to figure out how to handle (1) S frame (2) no show
key frame (3) error resilient mode (4) INTNL_OVERLAY_UPDATE frame
with show_existing_frame off.

Change-Id: Ica311c800052784acc8f3aa70405ab66ee7e8ece
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index a6c5336..7897015 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -119,8 +119,10 @@
   unsigned char arf_src_offset[MAX_STATIC_GF_GROUP_LENGTH + 1];
   unsigned char arf_update_idx[MAX_STATIC_GF_GROUP_LENGTH + 1];
   unsigned char arf_pos_in_gf[MAX_STATIC_GF_GROUP_LENGTH + 1];
-  unsigned char frame_gop_index[MAX_STATIC_GF_GROUP_LENGTH + 1];
+  unsigned char frame_disp_idx[MAX_STATIC_GF_GROUP_LENGTH + 1];
   unsigned char pyramid_level[MAX_STATIC_GF_GROUP_LENGTH + 1];
+  int ref_frame_disp_idx[MAX_STATIC_GF_GROUP_LENGTH + 1][REF_FRAMES];
+  int ref_frame_gop_idx[MAX_STATIC_GF_GROUP_LENGTH + 1][REF_FRAMES];
   unsigned char pyramid_height;
   unsigned char pyramid_lvl_nodes[MAX_PYRAMID_LVL];
   int bit_allocation[MAX_STATIC_GF_GROUP_LENGTH + 1];
diff --git a/av1/encoder/gop_structure.c b/av1/encoder/gop_structure.c
index 66f96b3..af9da59 100644
--- a/av1/encoder/gop_structure.c
+++ b/av1/encoder/gop_structure.c
@@ -42,7 +42,7 @@
       gf_group->arf_src_offset[*frame_ind] = 0;
       gf_group->arf_pos_in_gf[*frame_ind] = 0;
       gf_group->arf_update_idx[*frame_ind] = arf_ind;
-      gf_group->frame_gop_index[*frame_ind] = start;
+      gf_group->frame_disp_idx[*frame_ind] = start;
       gf_group->pyramid_level[*frame_ind] = MIN_PYRAMID_LVL;
       ++gf_group->pyramid_lvl_nodes[MIN_PYRAMID_LVL];
       ++(*frame_ind);
@@ -56,7 +56,7 @@
     gf_group->arf_src_offset[*frame_ind] = m - start - 1;
     gf_group->arf_pos_in_gf[*frame_ind] = 0;
     gf_group->arf_update_idx[*frame_ind] = 1;  // mark all internal ARF 1
-    gf_group->frame_gop_index[*frame_ind] = m;
+    gf_group->frame_disp_idx[*frame_ind] = m;
     gf_group->pyramid_level[*frame_ind] = level;
     ++gf_group->pyramid_lvl_nodes[level];
     ++(*frame_ind);
@@ -69,7 +69,7 @@
     gf_group->arf_src_offset[*frame_ind] = 0;
     gf_group->arf_pos_in_gf[*frame_ind] = arf_pos_in_gf;  // For bit allocation.
     gf_group->arf_update_idx[*frame_ind] = 1;
-    gf_group->frame_gop_index[*frame_ind] = m;
+    gf_group->frame_disp_idx[*frame_ind] = m;
     gf_group->pyramid_level[*frame_ind] = MIN_PYRAMID_LVL;
     ++(*frame_ind);
 
@@ -104,7 +104,7 @@
     gf_group->arf_src_offset[frame_index] = gf_interval - 1;
     gf_group->arf_pos_in_gf[frame_index] = 0;
     gf_group->arf_update_idx[frame_index] = 0;
-    gf_group->frame_gop_index[frame_index] = gf_interval;
+    gf_group->frame_disp_idx[frame_index] = gf_interval;
     gf_group->pyramid_level[frame_index] = gf_group->pyramid_height;
     ++frame_index;
   }
@@ -169,6 +169,136 @@
                 cpi->oxcf.gf_max_pyr_height);
 }
 
+#define REF_IDX(ref) ((ref)-LAST_FRAME)
+
+static INLINE void reset_ref_frame_idx(int *ref_idx, int reset_value) {
+  for (int i = 0; i < REF_FRAMES; ++i) ref_idx[i] = reset_value;
+}
+
+static INLINE void set_ref_frame_disp_idx(GF_GROUP *const gf_group) {
+  for (int i = 0; i <= gf_group->size; ++i) {
+    for (int ref = 0; ref < INTER_REFS_PER_FRAME + 1; ++ref) {
+      int ref_gop_idx = gf_group->ref_frame_gop_idx[i][ref];
+      if (ref_gop_idx == -1) {
+        gf_group->ref_frame_disp_idx[i][ref] = -1;
+      } else {
+        gf_group->ref_frame_disp_idx[i][ref] =
+            gf_group->frame_disp_idx[ref_gop_idx];
+      }
+    }
+  }
+}
+
+static void set_gop_ref_frame_map(GF_GROUP *const gf_group) {
+  // Initialize the reference slots as all -1.
+  for (int frame_idx = 0; frame_idx <= gf_group->size; ++frame_idx)
+    reset_ref_frame_idx(gf_group->ref_frame_gop_idx[frame_idx], -1);
+
+  // Set the map for frames in the current gop
+  for (int frame_idx = 0; frame_idx < gf_group->size; ++frame_idx) {
+    const FRAME_UPDATE_TYPE update_type = gf_group->update_type[frame_idx];
+    // TODO(yuec): need to figure out how to determine
+    // (1) whether a KEY_FRAME has show_frame on
+    // (2) whether a frame with INTNL_OVERLAY_UPDATE type has
+    //     show_existing_frame on
+    const int show_frame =
+        update_type != ARF_UPDATE && update_type != INTNL_ARF_UPDATE;
+    const int show_existing_frame =
+        update_type == OVERLAY_UPDATE || update_type == INTNL_OVERLAY_UPDATE;
+
+    int this_ref_map[INTER_REFS_PER_FRAME + 1];
+    memcpy(this_ref_map, gf_group->ref_frame_gop_idx[frame_idx],
+           sizeof(this_ref_map));
+    int *next_ref_map = &gf_group->ref_frame_gop_idx[frame_idx + 1][0];
+
+    switch (update_type) {
+      case KF_UPDATE:
+        if (show_frame) {
+          reset_ref_frame_idx(this_ref_map, frame_idx);
+        } else {
+          this_ref_map[REF_IDX(LAST3_FRAME)] = frame_idx;
+          this_ref_map[REF_IDX(EXTREF_FRAME)] = frame_idx;
+          this_ref_map[REF_IDX(ALTREF2_FRAME)] = frame_idx;
+          this_ref_map[REF_IDX(GOLDEN_FRAME)] = frame_idx;
+          this_ref_map[REF_IDX(ALTREF_FRAME)] = frame_idx;
+        }
+        break;
+      case LF_UPDATE: this_ref_map[REF_IDX(LAST3_FRAME)] = frame_idx; break;
+      case GF_UPDATE:
+        this_ref_map[REF_IDX(LAST3_FRAME)] = frame_idx;
+        this_ref_map[REF_IDX(GOLDEN_FRAME)] = frame_idx;
+        break;
+      case OVERLAY_UPDATE:
+        this_ref_map[REF_IDX(ALTREF_FRAME)] = frame_idx;
+        break;
+      case ARF_UPDATE: this_ref_map[REF_IDX(ALTREF_FRAME)] = frame_idx; break;
+      case INTNL_OVERLAY_UPDATE:
+        if (!show_existing_frame)
+          this_ref_map[REF_IDX(LAST3_FRAME)] = frame_idx;
+        break;
+      case INTNL_ARF_UPDATE:
+        this_ref_map[REF_IDX(EXTREF_FRAME)] = frame_idx;
+        break;
+      default: assert(0); break;
+    }
+
+    memcpy(next_ref_map, this_ref_map, sizeof(this_ref_map));
+
+    switch (update_type) {
+      case LF_UPDATE:
+      case GF_UPDATE:
+        next_ref_map[REF_IDX(LAST3_FRAME)] = this_ref_map[REF_IDX(LAST2_FRAME)];
+        next_ref_map[REF_IDX(LAST2_FRAME)] = this_ref_map[REF_IDX(LAST_FRAME)];
+        next_ref_map[REF_IDX(LAST_FRAME)] = this_ref_map[REF_IDX(LAST3_FRAME)];
+        break;
+      case INTNL_OVERLAY_UPDATE:
+        if (!show_existing_frame) {
+          next_ref_map[REF_IDX(LAST3_FRAME)] =
+              this_ref_map[REF_IDX(LAST2_FRAME)];
+          next_ref_map[REF_IDX(LAST2_FRAME)] =
+              this_ref_map[REF_IDX(LAST_FRAME)];
+          next_ref_map[REF_IDX(LAST_FRAME)] =
+              this_ref_map[REF_IDX(LAST3_FRAME)];
+        } else {
+          next_ref_map[REF_IDX(LAST_FRAME)] =
+              this_ref_map[REF_IDX(BWDREF_FRAME)];
+          next_ref_map[REF_IDX(LAST2_FRAME)] =
+              this_ref_map[REF_IDX(LAST_FRAME)];
+          next_ref_map[REF_IDX(LAST3_FRAME)] =
+              this_ref_map[REF_IDX(LAST2_FRAME)];
+          next_ref_map[REF_IDX(BWDREF_FRAME)] =
+              this_ref_map[REF_IDX(ALTREF2_FRAME)];
+          next_ref_map[REF_IDX(ALTREF2_FRAME)] =
+              this_ref_map[REF_IDX(EXTREF_FRAME)];
+          next_ref_map[REF_IDX(EXTREF_FRAME)] =
+              this_ref_map[REF_IDX(LAST3_FRAME)];
+        }
+        break;
+      case INTNL_ARF_UPDATE:
+        if (!show_existing_frame) {
+          next_ref_map[REF_IDX(BWDREF_FRAME)] =
+              this_ref_map[REF_IDX(EXTREF_FRAME)];
+          next_ref_map[REF_IDX(ALTREF2_FRAME)] =
+              this_ref_map[REF_IDX(BWDREF_FRAME)];
+          next_ref_map[REF_IDX(EXTREF_FRAME)] =
+              this_ref_map[REF_IDX(ALTREF2_FRAME)];
+        }
+        break;
+      case OVERLAY_UPDATE:
+        next_ref_map[REF_IDX(ALTREF_FRAME)] =
+            this_ref_map[REF_IDX(GOLDEN_FRAME)];
+        next_ref_map[REF_IDX(GOLDEN_FRAME)] =
+            this_ref_map[REF_IDX(ALTREF_FRAME)];
+        break;
+      default: break;
+    }
+  }
+
+  // Set the map in display order index by converting from gop indices in the
+  // above map
+  set_ref_frame_disp_idx(gf_group);
+}
+
 void av1_gop_setup_structure(AV1_COMP *cpi,
                              const EncodeFrameParams *const frame_params) {
   RATE_CONTROL *const rc = &cpi->rc;
@@ -190,6 +320,8 @@
   gf_group->arf_update_idx[gf_group->size] = 0;
   gf_group->arf_pos_in_gf[gf_group->size] = 0;
 
+  set_gop_ref_frame_map(gf_group);
+
 #if CHECK_GF_PARAMETER
   check_frame_params(gf_group, rc->baseline_gf_interval);
 #endif
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 2381a3c..4b2075c 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -517,7 +517,7 @@
   // Initialize P frames
   for (frame_idx = 2; frame_idx < MAX_LAG_BUFFERS; ++frame_idx) {
     struct lookahead_entry *buf;
-    frame_gop_offset = gf_group->frame_gop_index[frame_idx];
+    frame_gop_offset = gf_group->frame_disp_idx[frame_idx];
     buf = av1_lookahead_peek(cpi->lookahead, frame_gop_offset - 1);
 
     if (buf == NULL) break;