Move more features from AV1_COMMON to FeatureFlags

- bool switchable_motion_mode
- TX_MODE tx_mode
- InterpFilter interp_filter
- int primary_ref_frame
- int byte_alignment

BUG=aomedia:2610

Change-Id: I2265d9da62f700953f3b58f8cb9a1444140404e5
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 4b85cf0..c9515cf 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -2093,7 +2093,7 @@
         cpi->lookahead = av1_lookahead_init(
             cpi->oxcf.width, cpi->oxcf.height, subsampling_x, subsampling_y,
             use_highbitdepth, lag_in_frames, cpi->oxcf.border_in_pixels,
-            cpi->common.byte_alignment, ctx->num_lap_buffers);
+            cpi->common.features.byte_alignment, ctx->num_lap_buffers);
       }
       if (!cpi->lookahead)
         aom_internal_error(&cpi->common.error, AOM_CODEC_MEM_ERROR,
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index ef436f1..be38929 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -382,7 +382,7 @@
   BufferPool *const pool = cm->buffer_pool;
 
   cm->cur_frame = NULL;
-  cm->byte_alignment = ctx->byte_alignment;
+  cm->features.byte_alignment = ctx->byte_alignment;
   pbi->skip_loop_filter = ctx->skip_loop_filter;
   pbi->skip_film_grain = ctx->skip_film_grain;
 
@@ -1243,7 +1243,7 @@
   if (ctx->frame_worker) {
     AVxWorker *const worker = ctx->frame_worker;
     FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
-    frame_worker_data->pbi->common.byte_alignment = byte_alignment;
+    frame_worker_data->pbi->common.features.byte_alignment = byte_alignment;
   }
   return AOM_CODEC_OK;
 }
diff --git a/av1/common/av1_common_int.h b/av1/common/av1_common_int.h
index 62a3233..4e8cdb0 100644
--- a/av1/common/av1_common_int.h
+++ b/av1/common/av1_common_int.h
@@ -318,8 +318,7 @@
   int frame_refs_short_signaling;
 } CurrentFrame;
 
-// Struct containing some boolean flags indicating whether some features are
-// allowed/used or not.
+// Struct containing some frame level features.
 typedef struct {
   bool disable_cdf_update;
   bool allow_high_precision_mv;
@@ -333,6 +332,14 @@
   bool all_lossless;    // frame is fully lossless at the upscaled resolution.
   bool reduced_tx_set_used;
   bool error_resilient_mode;
+  bool switchable_motion_mode;
+  TX_MODE tx_mode;
+  InterpFilter interp_filter;
+  int primary_ref_frame;
+  int byte_alignment;
+  // Flag signaling how frame contexts should be updated at the end of
+  // a frame decode
+  REFRESH_FRAME_CONTEXT_MODE refresh_frame_context;
 } FeatureFlags;
 
 // Struct containing params related to tiles.
@@ -525,9 +532,6 @@
   // Params related to MB_MODE_INFO arrays and related info.
   CommonModeInfoParams mi_params;
 
-  /* profile settings */
-  TX_MODE tx_mode;
-
 #if CONFIG_ENTROPY_STATS
   int coef_cdf_category;
 #endif
@@ -562,10 +566,6 @@
 
   uint8_t *last_frame_seg_map;
 
-  InterpFilter interp_filter;
-
-  int switchable_motion_mode;
-
   loop_filter_info_n lf_info;
   RestorationInfo rst_info[MAX_MB_PLANE];
 
@@ -576,10 +576,6 @@
   // Output of loop restoration
   YV12_BUFFER_CONFIG rst_frame;
 
-  // Flag signaling how frame contexts should be updated at the end of
-  // a frame decode
-  REFRESH_FRAME_CONTEXT_MODE refresh_frame_context;
-
   int ref_frame_sign_bias[REF_FRAMES]; /* Two state 0, 1 */
 
   struct loopfilter lf;
@@ -587,13 +583,10 @@
 
   FRAME_CONTEXT *fc; /* this frame entropy */
   FRAME_CONTEXT *default_frame_context;
-  int primary_ref_frame;
 
   // Parameters related to tiling.
   CommonTileParams tiles;
 
-  int byte_alignment;
-
   // External BufferPool passed from outside.
   BufferPool *buffer_pool;
 
@@ -770,8 +763,9 @@
 
 static INLINE RefCntBuffer *get_primary_ref_frame_buf(
     const AV1_COMMON *const cm) {
-  if (cm->primary_ref_frame == PRIMARY_REF_NONE) return NULL;
-  const int map_idx = get_ref_frame_map_idx(cm, cm->primary_ref_frame + 1);
+  const int primary_ref_frame = cm->features.primary_ref_frame;
+  if (primary_ref_frame == PRIMARY_REF_NONE) return NULL;
+  const int map_idx = get_ref_frame_map_idx(cm, primary_ref_frame + 1);
   return (map_idx != INVALID_IDX) ? cm->ref_frame_map[map_idx] : NULL;
 }
 
diff --git a/av1/common/resize.c b/av1/common/resize.c
index ab9a2a0..98f28f7 100644
--- a/av1/common/resize.c
+++ b/av1/common/resize.c
@@ -1371,6 +1371,7 @@
   const int num_planes = av1_num_planes(cm);
   if (!av1_superres_scaled(cm)) return;
   const SequenceHeader *const seq_params = &cm->seq_params;
+  const int byte_alignment = cm->features.byte_alignment;
 
   YV12_BUFFER_CONFIG copy_buffer;
   memset(&copy_buffer, 0, sizeof(copy_buffer));
@@ -1381,7 +1382,7 @@
   if (aom_alloc_frame_buffer(
           &copy_buffer, aligned_width, cm->height, seq_params->subsampling_x,
           seq_params->subsampling_y, seq_params->use_highbitdepth,
-          AOM_BORDER_IN_PIXELS, cm->byte_alignment))
+          AOM_BORDER_IN_PIXELS, byte_alignment))
     aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                        "Failed to allocate copy buffer for superres upscaling");
 
@@ -1413,7 +1414,7 @@
             frame_to_show, cm->superres_upscaled_width,
             cm->superres_upscaled_height, seq_params->subsampling_x,
             seq_params->subsampling_y, seq_params->use_highbitdepth,
-            AOM_BORDER_IN_PIXELS, cm->byte_alignment, fb, cb, cb_priv)) {
+            AOM_BORDER_IN_PIXELS, byte_alignment, fb, cb, cb_priv)) {
       unlock_buffer_pool(pool);
       aom_internal_error(
           &cm->error, AOM_CODEC_MEM_ERROR,
@@ -1430,7 +1431,7 @@
             frame_to_show, cm->superres_upscaled_width,
             cm->superres_upscaled_height, seq_params->subsampling_x,
             seq_params->subsampling_y, seq_params->use_highbitdepth,
-            AOM_BORDER_IN_PIXELS, cm->byte_alignment))
+            AOM_BORDER_IN_PIXELS, byte_alignment))
       aom_internal_error(
           &cm->error, AOM_CODEC_MEM_ERROR,
           "Failed to reallocate current frame buffer for superres upscaling");
diff --git a/av1/common/restoration.c b/av1/common/restoration.c
index 645b92b..a0f37ad 100644
--- a/av1/common/restoration.c
+++ b/av1/common/restoration.c
@@ -1117,7 +1117,7 @@
   if (aom_realloc_frame_buffer(
           lr_ctxt->dst, frame_width, frame_height, seq_params->subsampling_x,
           seq_params->subsampling_y, highbd, AOM_RESTORATION_FRAME_BORDER,
-          cm->byte_alignment, NULL, NULL, NULL) < 0)
+          cm->features.byte_alignment, NULL, NULL, NULL) < 0)
     aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                        "Failed to allocate restoration dst buffer");
 
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 29a758a..1edc98e 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -125,8 +125,9 @@
   return len != 0 && len <= (size_t)(end - start);
 }
 
-static TX_MODE read_tx_mode(AV1_COMMON *cm, struct aom_read_bit_buffer *rb) {
-  if (cm->features.coded_lossless) return ONLY_4X4;
+static TX_MODE read_tx_mode(struct aom_read_bit_buffer *rb,
+                            int coded_lossless) {
+  if (coded_lossless) return ONLY_4X4;
   return aom_rb_read_bit(rb) ? TX_MODE_SELECT : TX_MODE_LARGEST;
 }
 
@@ -214,12 +215,13 @@
     struct macroblockd_plane *const pd = &xd->plane[plane];
     eob_info *eob_data = pd->eob_data + xd->txb_offset[plane];
     if (eob_data->eob) {
+      const bool reduced_tx_set_used = cm->features.reduced_tx_set_used;
       // tx_type was read out in av1_read_coeffs_txb.
       const TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, row, col, tx_size,
-                                              cm->features.reduced_tx_set_used);
+                                              reduced_tx_set_used);
       uint8_t *dst = &pd->dst.buf[(row * pd->dst.stride + col) << MI_SIZE_LOG2];
       inverse_transform_block(xd, plane, tx_type, tx_size, dst, pd->dst.stride,
-                              cm->features.reduced_tx_set_used);
+                              reduced_tx_set_used);
     }
   }
   if (plane == AOM_PLANE_Y && store_cfl_required(cm, xd)) {
@@ -234,16 +236,15 @@
   (void)r;
   PLANE_TYPE plane_type = get_plane_type(plane);
   const struct macroblockd_plane *const pd = &xd->plane[plane];
-
+  const bool reduced_tx_set_used = cm->features.reduced_tx_set_used;
   // tx_type was read out in av1_read_coeffs_txb.
-  const TX_TYPE tx_type =
-      av1_get_tx_type(xd, plane_type, blk_row, blk_col, tx_size,
-                      cm->features.reduced_tx_set_used);
+  const TX_TYPE tx_type = av1_get_tx_type(xd, plane_type, blk_row, blk_col,
+                                          tx_size, reduced_tx_set_used);
 
   uint8_t *dst =
       &pd->dst.buf[(blk_row * pd->dst.stride + blk_col) << MI_SIZE_LOG2];
   inverse_transform_block(xd, plane, tx_type, tx_size, dst, pd->dst.stride,
-                          cm->features.reduced_tx_set_used);
+                          reduced_tx_set_used);
 #if CONFIG_MISMATCH_DEBUG
   int pixel_c, pixel_r;
   BLOCK_SIZE bsize = txsize_to_bsize[tx_size];
@@ -1344,7 +1345,8 @@
   }
 }
 
-static TX_SIZE read_selected_tx_size(MACROBLOCKD *xd, aom_reader *r) {
+static TX_SIZE read_selected_tx_size(const MACROBLOCKD *const xd,
+                                     aom_reader *r) {
   // TODO(debargha): Clean up the logic here. This function should only
   // be called for intra.
   const BLOCK_SIZE bsize = xd->mi[0]->sb_type;
@@ -1359,9 +1361,9 @@
   return tx_size;
 }
 
-static TX_SIZE read_tx_size(AV1_COMMON *cm, MACROBLOCKD *xd, int is_inter,
-                            int allow_select_inter, aom_reader *r) {
-  const TX_MODE tx_mode = cm->tx_mode;
+static TX_SIZE read_tx_size(const MACROBLOCKD *const xd, TX_MODE tx_mode,
+                            int is_inter, int allow_select_inter,
+                            aom_reader *r) {
   const BLOCK_SIZE bsize = xd->mi[0]->sb_type;
   if (xd->lossless[xd->mi[0]->segment_id]) return TX_4X4;
 
@@ -1392,7 +1394,7 @@
   const int num_planes = av1_num_planes(cm);
   MB_MODE_INFO *mbmi = xd->mi[0];
   int inter_block_tx = is_inter_block(mbmi) || is_intrabc_block(mbmi);
-  if (cm->tx_mode == TX_MODE_SELECT && block_signals_txsize(bsize) &&
+  if (cm->features.tx_mode == TX_MODE_SELECT && block_signals_txsize(bsize) &&
       !mbmi->skip && inter_block_tx && !xd->lossless[mbmi->segment_id]) {
     const TX_SIZE max_tx_size = max_txsize_rect_lookup[bsize];
     const int bh = tx_size_high_unit[max_tx_size];
@@ -1408,7 +1410,8 @@
 #endif
                            idy, idx, r);
   } else {
-    mbmi->tx_size = read_tx_size(cm, xd, inter_block_tx, !mbmi->skip, r);
+    mbmi->tx_size =
+        read_tx_size(xd, cm->features.tx_mode, inter_block_tx, !mbmi->skip, r);
     if (inter_block_tx)
       memset(mbmi->inter_tx_size, mbmi->tx_size, sizeof(mbmi->inter_tx_size));
     set_txfm_ctxs(mbmi->tx_size, xd->n4_w, xd->n4_h,
@@ -1715,7 +1718,7 @@
     cm->last_frame_seg_map = NULL;
   }
   // Read update flags
-  if (cm->primary_ref_frame == PRIMARY_REF_NONE) {
+  if (cm->features.primary_ref_frame == PRIMARY_REF_NONE) {
     // These frames can't use previous frames, so must signal map + features
     seg->update_map = 1;
     seg->temporal_update = 0;
@@ -1964,6 +1967,7 @@
                                         struct aom_read_bit_buffer *rb) {
   const int num_planes = av1_num_planes(cm);
   struct loopfilter *lf = &cm->lf;
+
   if (cm->features.allow_intrabc || cm->features.coded_lossless) {
     // write default deltas to frame buffer
     av1_set_default_ref_deltas(cm->cur_frame->ref_deltas);
@@ -2195,7 +2199,7 @@
   if (aom_realloc_frame_buffer(
           &cm->cur_frame->buf, cm->width, cm->height, seq_params->subsampling_x,
           seq_params->subsampling_y, seq_params->use_highbitdepth,
-          AOM_DEC_BORDER_IN_PIXELS, cm->byte_alignment,
+          AOM_DEC_BORDER_IN_PIXELS, cm->features.byte_alignment,
           &cm->cur_frame->raw_frame_buffer, pool->get_fb_cb, pool->cb_priv)) {
     unlock_buffer_pool(pool);
     aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
@@ -4620,7 +4624,7 @@
   cm->current_frame_id = cm->ref_frame_id[existing_frame_idx];
   update_ref_frame_id(pbi);
 
-  cm->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED;
+  cm->features.refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED;
 }
 
 static INLINE void reset_frame_buffers(AV1_COMMON *cm) {
@@ -4807,7 +4811,7 @@
 
   int frame_size_override_flag = 0;
   features->allow_intrabc = 0;
-  cm->primary_ref_frame = PRIMARY_REF_NONE;
+  features->primary_ref_frame = PRIMARY_REF_NONE;
 
   if (!seq_params->reduced_still_picture_hdr) {
     if (seq_params->frame_id_numbers_present_flag) {
@@ -4859,7 +4863,7 @@
     current_frame->frame_number = current_frame->order_hint;
 
     if (!features->error_resilient_mode && !frame_is_intra_only(cm)) {
-      cm->primary_ref_frame = aom_rb_read_literal(rb, PRIMARY_REF_BITS);
+      features->primary_ref_frame = aom_rb_read_literal(rb, PRIMARY_REF_BITS);
     }
   }
 
@@ -4949,7 +4953,7 @@
                   &buf->buf, seq_params->max_frame_width,
                   seq_params->max_frame_height, seq_params->subsampling_x,
                   seq_params->subsampling_y, seq_params->use_highbitdepth,
-                  AOM_BORDER_IN_PIXELS, cm->byte_alignment,
+                  AOM_BORDER_IN_PIXELS, features->byte_alignment,
                   &buf->raw_frame_buffer, pool->get_fb_cb, pool->cb_priv)) {
             decrease_ref_count(buf, pool);
             unlock_buffer_pool(pool);
@@ -5081,12 +5085,12 @@
       } else {
         features->allow_high_precision_mv = aom_rb_read_bit(rb);
       }
-      cm->interp_filter = read_frame_interp_filter(rb);
-      cm->switchable_motion_mode = aom_rb_read_bit(rb);
+      features->interp_filter = read_frame_interp_filter(rb);
+      features->switchable_motion_mode = aom_rb_read_bit(rb);
     }
 
     cm->prev_frame = get_primary_ref_frame_buf(cm);
-    if (cm->primary_ref_frame != PRIMARY_REF_NONE &&
+    if (features->primary_ref_frame != PRIMARY_REF_NONE &&
         get_primary_ref_frame_buf(cm) == NULL) {
       aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
                          "Reference frame containing this frame's initial "
@@ -5125,11 +5129,11 @@
   const int might_bwd_adapt = !(seq_params->reduced_still_picture_hdr) &&
                               !(features->disable_cdf_update);
   if (might_bwd_adapt) {
-    cm->refresh_frame_context = aom_rb_read_bit(rb)
-                                    ? REFRESH_FRAME_CONTEXT_DISABLED
-                                    : REFRESH_FRAME_CONTEXT_BACKWARD;
+    features->refresh_frame_context = aom_rb_read_bit(rb)
+                                          ? REFRESH_FRAME_CONTEXT_DISABLED
+                                          : REFRESH_FRAME_CONTEXT_BACKWARD;
   } else {
-    cm->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED;
+    features->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED;
   }
 
   cm->cur_frame->buf.bit_depth = seq_params->bit_depth;
@@ -5182,7 +5186,7 @@
                          "Failed to allocate context buffers");
   }
 
-  if (cm->primary_ref_frame == PRIMARY_REF_NONE) {
+  if (features->primary_ref_frame == PRIMARY_REF_NONE) {
     av1_setup_past_independence(cm);
   }
 
@@ -5241,7 +5245,7 @@
     decode_restoration_mode(cm, rb);
   }
 
-  cm->tx_mode = read_tx_mode(cm, rb);
+  features->tx_mode = read_tx_mode(rb, features->coded_lossless);
   current_frame->reference_mode = read_frame_reference_mode(cm, rb);
 
   av1_setup_skip_mode_allowed(cm);
@@ -5371,7 +5375,7 @@
 
   av1_setup_block_planes(xd, cm->seq_params.subsampling_x,
                          cm->seq_params.subsampling_y, num_planes);
-  if (cm->primary_ref_frame == PRIMARY_REF_NONE) {
+  if (cm->features.primary_ref_frame == PRIMARY_REF_NONE) {
     // use the default frame context values
     *cm->fc = *cm->default_frame_context;
   } else {
@@ -5510,7 +5514,7 @@
 #endif
 
   if (!xd->corrupted) {
-    if (cm->refresh_frame_context == REFRESH_FRAME_CONTEXT_BACKWARD) {
+    if (cm->features.refresh_frame_context == REFRESH_FRAME_CONTEXT_BACKWARD) {
       assert(pbi->context_update_tile_id < pbi->allocated_tiles);
       *cm->fc = pbi->tile_data[pbi->context_update_tile_id].tctx;
       av1_reset_cdf_symbol_counters(cm->fc);
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index d8af601..dc987d1 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -208,7 +208,7 @@
 
 static MOTION_MODE read_motion_mode(AV1_COMMON *cm, MACROBLOCKD *xd,
                                     MB_MODE_INFO *mbmi, aom_reader *r) {
-  if (cm->switchable_motion_mode == 0) return SIMPLE_TRANSLATION;
+  if (cm->features.switchable_motion_mode == 0) return SIMPLE_TRANSLATION;
   if (mbmi->skip_mode) return SIMPLE_TRANSLATION;
 
   const MOTION_MODE last_motion_mode_allowed = motion_mode_allowed(
@@ -1007,26 +1007,27 @@
   }
 }
 
-static INLINE void read_mb_interp_filter(AV1_COMMON *const cm,
-                                         MACROBLOCKD *const xd,
+static INLINE void read_mb_interp_filter(const MACROBLOCKD *const xd,
+                                         InterpFilter interp_filter,
+                                         bool enable_dual_filter,
                                          MB_MODE_INFO *const mbmi,
                                          aom_reader *r) {
   FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
 
   if (!av1_is_interp_needed(xd)) {
-    set_default_interp_filters(mbmi, cm->interp_filter);
+    set_default_interp_filters(mbmi, interp_filter);
     return;
   }
 
-  if (cm->interp_filter != SWITCHABLE) {
-    mbmi->interp_filters = av1_broadcast_interp_filter(cm->interp_filter);
+  if (interp_filter != SWITCHABLE) {
+    mbmi->interp_filters = av1_broadcast_interp_filter(interp_filter);
   } else {
     InterpFilter ref0_filter[2] = { EIGHTTAP_REGULAR, EIGHTTAP_REGULAR };
     for (int dir = 0; dir < 2; ++dir) {
       const int ctx = av1_get_pred_context_switchable_interp(xd, dir);
       ref0_filter[dir] = (InterpFilter)aom_read_symbol(
           r, ec_ctx->switchable_interp_cdf[ctx], SWITCHABLE_FILTERS, ACCT_STR);
-      if (cm->seq_params.enable_dual_filter == 0) {
+      if (!enable_dual_filter) {
         ref0_filter[1] = ref0_filter[0];
         break;
       }
@@ -1450,7 +1451,8 @@
     }
   }
 
-  read_mb_interp_filter(cm, xd, mbmi, r);
+  read_mb_interp_filter(xd, features->interp_filter,
+                        cm->seq_params.enable_dual_filter, mbmi, r);
 
   const int mi_row = xd->mi_row;
   const int mi_col = xd->mi_col;
diff --git a/av1/decoder/obu.c b/av1/decoder/obu.c
index 0b6fb5d..f8f944d 100644
--- a/av1/decoder/obu.c
+++ b/av1/decoder/obu.c
@@ -379,7 +379,7 @@
                              cm->seq_params.subsampling_y,
                              (cm->seq_params.use_highbitdepth &&
                               (cm->seq_params.bit_depth > AOM_BITS_8)),
-                             0, cm->byte_alignment))
+                             0, cm->features.byte_alignment))
     aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                        "Failed to allocate the tile list output buffer");
 }
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 0902bd6..fc8a1de 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -269,7 +269,7 @@
                                          const MB_MODE_INFO *mbmi,
                                          aom_writer *w) {
   MOTION_MODE last_motion_mode_allowed =
-      cm->switchable_motion_mode
+      cm->features.switchable_motion_mode
           ? motion_mode_allowed(cm->global_motion, xd, mbmi,
                                 cm->features.allow_warped_motion)
           : SIMPLE_TRANSLATION;
@@ -603,21 +603,20 @@
                    2 * MAX_ANGLE_DELTA + 1);
 }
 
-static AOM_INLINE void write_mb_interp_filter(AV1_COMP *cpi,
+static AOM_INLINE void write_mb_interp_filter(AV1_COMMON *const cm,
                                               const MACROBLOCKD *xd,
                                               aom_writer *w) {
-  AV1_COMMON *const cm = &cpi->common;
   const MB_MODE_INFO *const mbmi = xd->mi[0];
   FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
 
   if (!av1_is_interp_needed(xd)) {
-    int_interpfilters filters =
-        av1_broadcast_interp_filter(av1_unswitchable_filter(cm->interp_filter));
+    int_interpfilters filters = av1_broadcast_interp_filter(
+        av1_unswitchable_filter(cm->features.interp_filter));
     assert(mbmi->interp_filters.as_int == filters.as_int);
     (void)filters;
     return;
   }
-  if (cm->interp_filter == SWITCHABLE) {
+  if (cm->features.interp_filter == SWITCHABLE) {
     int dir;
     for (dir = 0; dir < 2; ++dir) {
       const int ctx = av1_get_pred_context_switchable_interp(xd, dir);
@@ -1214,7 +1213,7 @@
         }
       }
     }
-    write_mb_interp_filter(cpi, xd, w);
+    write_mb_interp_filter(cm, xd, w);
   }
 }
 
@@ -1514,7 +1513,7 @@
   const int is_inter_tx = is_inter_block(mbmi);
   const int skip = mbmi->skip;
   const int segment_id = mbmi->segment_id;
-  if (cm->tx_mode == TX_MODE_SELECT && block_signals_txsize(bsize) &&
+  if (cm->features.tx_mode == TX_MODE_SELECT && block_signals_txsize(bsize) &&
       !(is_inter_tx && skip) && !xd->lossless[segment_id]) {
     if (is_inter_tx) {  // This implies skip flag is 0.
       const TX_SIZE max_tx_size = get_vartx_max_txsize(xd, bsize, 0);
@@ -2064,7 +2063,7 @@
   if (!seg->enabled) return;
 
   // Write update flags
-  if (cm->primary_ref_frame == PRIMARY_REF_NONE) {
+  if (cm->features.primary_ref_frame == PRIMARY_REF_NONE) {
     assert(seg->update_map == 1);
     seg->temporal_update = 0;
     assert(seg->update_data == 1);
@@ -2923,7 +2922,7 @@
           seq_params->order_hint_info.order_hint_bits_minus_1 + 1);
 
     if (!features->error_resilient_mode && !frame_is_intra_only(cm)) {
-      aom_wb_write_literal(wb, cm->primary_ref_frame, PRIMARY_REF_BITS);
+      aom_wb_write_literal(wb, features->primary_ref_frame, PRIMARY_REF_BITS);
     }
   }
 
@@ -3047,8 +3046,8 @@
 
       if (!features->cur_frame_force_integer_mv)
         aom_wb_write_bit(wb, features->allow_high_precision_mv);
-      write_frame_interp_filter(cm->interp_filter, wb);
-      aom_wb_write_bit(wb, cm->switchable_motion_mode);
+      write_frame_interp_filter(features->interp_filter, wb);
+      aom_wb_write_bit(wb, features->switchable_motion_mode);
       if (frame_might_allow_ref_frame_mvs(cm)) {
         aom_wb_write_bit(wb, features->allow_ref_frame_mvs);
       } else {
@@ -3060,11 +3059,11 @@
   const int might_bwd_adapt = !(seq_params->reduced_still_picture_hdr) &&
                               !(features->disable_cdf_update);
   if (cm->tiles.large_scale)
-    assert(cm->refresh_frame_context == REFRESH_FRAME_CONTEXT_DISABLED);
+    assert(features->refresh_frame_context == REFRESH_FRAME_CONTEXT_DISABLED);
 
   if (might_bwd_adapt) {
     aom_wb_write_bit(
-        wb, cm->refresh_frame_context == REFRESH_FRAME_CONTEXT_DISABLED);
+        wb, features->refresh_frame_context == REFRESH_FRAME_CONTEXT_DISABLED);
   }
 
   write_tile_info(cm, saved_wb, wb);
@@ -3102,9 +3101,9 @@
 
   // Write TX mode
   if (features->coded_lossless)
-    assert(cm->tx_mode == ONLY_4X4);
+    assert(features->tx_mode == ONLY_4X4);
   else
-    aom_wb_write_bit(wb, cm->tx_mode == TX_MODE_SELECT);
+    aom_wb_write_bit(wb, features->tx_mode == TX_MODE_SELECT);
 
   if (!frame_is_intra_only(cm)) {
     const int use_hybrid_pred =
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index d61e787..900c9ae 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -202,7 +202,7 @@
   }
 
   if (cpi->ext_refresh_frame_context_pending) {
-    cm->refresh_frame_context = cpi->ext_refresh_frame_context;
+    cm->features.refresh_frame_context = cpi->ext_refresh_frame_context;
     cpi->ext_refresh_frame_context_pending = 0;
   }
   cm->features.allow_ref_frame_mvs = cpi->ext_use_ref_frame_mvs;
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index d0db89a..4533204 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -648,7 +648,7 @@
       update_global_motion_used(mi_addr->mode, bsize, mi_addr, rdc);
     }
 
-    if (cm->interp_filter == SWITCHABLE &&
+    if (cm->features.interp_filter == SWITCHABLE &&
         mi_addr->motion_mode != WARPED_CAUSAL &&
         !is_nontrans_global_motion(xd, xd->mi[0])) {
       update_filter_type_count(td->counts, xd, mi_addr);
@@ -1342,7 +1342,7 @@
       }
 
       const MOTION_MODE motion_allowed =
-          cm->switchable_motion_mode
+          cm->features.switchable_motion_mode
               ? motion_mode_allowed(xd->global_motion, xd, mbmi,
                                     cm->features.allow_warped_motion)
               : SIMPLE_TRANSLATION;
@@ -1409,7 +1409,7 @@
     }
   }
 
-  if (inter_block && cm->interp_filter == SWITCHABLE &&
+  if (inter_block && cm->features.interp_filter == SWITCHABLE &&
       mbmi->motion_mode != WARPED_CAUSAL &&
       !is_nontrans_global_motion(xd, mbmi)) {
     update_filter_type_cdf(xd, mbmi);
@@ -1657,7 +1657,7 @@
           segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_REF_FRAME);
       if (!seg_ref_active && inter_block) {
         const MOTION_MODE motion_allowed =
-            cm->switchable_motion_mode
+            cm->features.switchable_motion_mode
                 ? motion_mode_allowed(xd->global_motion, xd, mbmi,
                                       cm->features.allow_warped_motion)
                 : SIMPLE_TRANSLATION;
@@ -5900,7 +5900,7 @@
   const TX_SIZE_SEARCH_METHOD tx_search_type =
       cpi->tx_size_search_methods[eval_type];
   assert(cpi->oxcf.enable_tx64 || tx_search_type != USE_LARGESTALL);
-  cm->tx_mode = select_tx_mode(cpi, tx_search_type);
+  features->tx_mode = select_tx_mode(cpi, tx_search_type);
 
   if (cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats) {
     const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group);
@@ -5952,7 +5952,7 @@
 
   if (cm->current_frame.frame_type != KEY_FRAME &&
       cpi->sf.interp_sf.adaptive_interp_filter_search == 2 &&
-      cm->interp_filter == SWITCHABLE) {
+      features->interp_filter == SWITCHABLE) {
     const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group);
 
     for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++) {
@@ -5986,10 +5986,11 @@
 void av1_encode_frame(AV1_COMP *cpi) {
   AV1_COMMON *const cm = &cpi->common;
   CurrentFrame *const current_frame = &cm->current_frame;
+  FeatureFlags *const features = &cm->features;
   const int num_planes = av1_num_planes(cm);
   // Indicates whether or not to use a default reduced set for ext-tx
   // rather than the potential full set of 16 transforms
-  cm->features.reduced_tx_set_used = cpi->oxcf.reduced_tx_type_set;
+  features->reduced_tx_set_used = cpi->oxcf.reduced_tx_type_set;
 
   // Make sure segment_id is no larger than last_active_segid.
   if (cm->seg.enabled && cm->seg.update_map) {
@@ -6061,10 +6062,10 @@
     else
       current_frame->reference_mode = REFERENCE_MODE_SELECT;
 
-    cm->interp_filter = SWITCHABLE;
-    if (cm->tiles.large_scale) cm->interp_filter = EIGHTTAP_REGULAR;
+    features->interp_filter = SWITCHABLE;
+    if (cm->tiles.large_scale) features->interp_filter = EIGHTTAP_REGULAR;
 
-    cm->switchable_motion_mode = 1;
+    features->switchable_motion_mode = 1;
 
     rdc->compound_ref_used_flag = 0;
     rdc->skip_mode_used_flag = 0;
@@ -6092,8 +6093,9 @@
       skip_mode_info->skip_mode_flag = 0;
 
     if (!cm->tiles.large_scale) {
-      if (cm->tx_mode == TX_MODE_SELECT && cpi->td.mb.txb_split_count == 0)
-        cm->tx_mode = TX_MODE_LARGEST;
+      if (features->tx_mode == TX_MODE_SELECT &&
+          cpi->td.mb.txb_split_count == 0)
+        features->tx_mode = TX_MODE_LARGEST;
     }
   } else {
     encode_frame_internal(cpi);
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index c384f33..84e6372 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1053,7 +1053,7 @@
           &cpi->alt_ref_buffer, oxcf->width, oxcf->height,
           seq_params->subsampling_x, seq_params->subsampling_y,
           seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels,
-          cm->byte_alignment, NULL, NULL, NULL))
+          cm->features.byte_alignment, NULL, NULL, NULL))
     aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                        "Failed to allocate altref buffer");
 }
@@ -1061,10 +1061,11 @@
 static void alloc_util_frame_buffers(AV1_COMP *cpi) {
   AV1_COMMON *const cm = &cpi->common;
   const SequenceHeader *const seq_params = &cm->seq_params;
+  const int byte_alignment = cm->features.byte_alignment;
   if (aom_realloc_frame_buffer(
           &cpi->last_frame_uf, cm->width, cm->height, seq_params->subsampling_x,
           seq_params->subsampling_y, seq_params->use_highbitdepth,
-          cpi->oxcf.border_in_pixels, cm->byte_alignment, NULL, NULL, NULL))
+          cpi->oxcf.border_in_pixels, byte_alignment, NULL, NULL, NULL))
     aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                        "Failed to allocate last frame buffer");
 
@@ -1072,14 +1073,14 @@
           &cpi->trial_frame_rst, cm->superres_upscaled_width,
           cm->superres_upscaled_height, seq_params->subsampling_x,
           seq_params->subsampling_y, seq_params->use_highbitdepth,
-          AOM_RESTORATION_FRAME_BORDER, cm->byte_alignment, NULL, NULL, NULL))
+          AOM_RESTORATION_FRAME_BORDER, byte_alignment, NULL, NULL, NULL))
     aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                        "Failed to allocate trial restored frame buffer");
 
   if (aom_realloc_frame_buffer(
           &cpi->scaled_source, cm->width, cm->height, seq_params->subsampling_x,
           seq_params->subsampling_y, seq_params->use_highbitdepth,
-          cpi->oxcf.border_in_pixels, cm->byte_alignment, NULL, NULL, NULL))
+          cpi->oxcf.border_in_pixels, byte_alignment, NULL, NULL, NULL))
     aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                        "Failed to allocate scaled source buffer");
 
@@ -1087,7 +1088,7 @@
           &cpi->scaled_last_source, cm->width, cm->height,
           seq_params->subsampling_x, seq_params->subsampling_y,
           seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels,
-          cm->byte_alignment, NULL, NULL, NULL))
+          byte_alignment, NULL, NULL, NULL))
     aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                        "Failed to allocate scaled last source buffer");
 }
@@ -2841,11 +2842,11 @@
   cpi->refresh_golden_frame = 0;
   cpi->refresh_bwd_ref_frame = 0;
 
-  cm->refresh_frame_context = (oxcf->frame_parallel_decoding_mode)
-                                  ? REFRESH_FRAME_CONTEXT_DISABLED
-                                  : REFRESH_FRAME_CONTEXT_BACKWARD;
+  cm->features.refresh_frame_context = (oxcf->frame_parallel_decoding_mode)
+                                           ? REFRESH_FRAME_CONTEXT_DISABLED
+                                           : REFRESH_FRAME_CONTEXT_BACKWARD;
   if (oxcf->large_scale_tile)
-    cm->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED;
+    cm->features.refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED;
 
   if (x->palette_buffer == NULL) {
     CHECK_MEM_ERROR(cm, x->palette_buffer,
@@ -2889,8 +2890,9 @@
   rc->worst_quality = cpi->oxcf.worst_allowed_q;
   rc->best_quality = cpi->oxcf.best_allowed_q;
 
-  cm->interp_filter = oxcf->large_scale_tile ? EIGHTTAP_REGULAR : SWITCHABLE;
-  cm->switchable_motion_mode = 1;
+  cm->features.interp_filter =
+      oxcf->large_scale_tile ? EIGHTTAP_REGULAR : SWITCHABLE;
+  cm->features.switchable_motion_mode = 1;
 
   if (cpi->oxcf.render_width > 0 && cpi->oxcf.render_height > 0) {
     cm->render_width = cpi->oxcf.render_width;
@@ -2976,11 +2978,11 @@
         aom_calloc(cpi->tpl_stats_buffer[frame].width *
                        cpi->tpl_stats_buffer[frame].height,
                    sizeof(*cpi->tpl_stats_buffer[frame].tpl_stats_ptr)));
-    if (aom_alloc_frame_buffer(&cpi->tpl_rec_pool[frame], cm->width, cm->height,
-                               cm->seq_params.subsampling_x,
-                               cm->seq_params.subsampling_y,
-                               cm->seq_params.use_highbitdepth,
-                               AOM_ENC_NO_SCALE_BORDER, cm->byte_alignment))
+    if (aom_alloc_frame_buffer(
+            &cpi->tpl_rec_pool[frame], cm->width, cm->height,
+            cm->seq_params.subsampling_x, cm->seq_params.subsampling_y,
+            cm->seq_params.use_highbitdepth, AOM_ENC_NO_SCALE_BORDER,
+            cm->features.byte_alignment))
       aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                          "Failed to allocate frame buffer");
   }
@@ -3864,8 +3866,8 @@
             ref->border < AOM_BORDER_IN_PIXELS) {
           RefCntBuffer *ref_fb = get_ref_frame_buf(cm, ref_frame);
           if (aom_yv12_realloc_with_new_border(
-                  &ref_fb->buf, AOM_BORDER_IN_PIXELS, cm->byte_alignment,
-                  num_planes) != 0) {
+                  &ref_fb->buf, AOM_BORDER_IN_PIXELS,
+                  cm->features.byte_alignment, num_planes) != 0) {
             aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                                "Failed to allocate frame buffer");
           }
@@ -3888,7 +3890,7 @@
                   &new_fb->buf, cm->width, cm->height,
                   cm->seq_params.subsampling_x, cm->seq_params.subsampling_y,
                   cm->seq_params.use_highbitdepth, AOM_BORDER_IN_PIXELS,
-                  cm->byte_alignment, NULL, NULL, NULL)) {
+                  cm->features.byte_alignment, NULL, NULL, NULL)) {
             if (force_scaling) {
               // Release the reference acquired in the get_free_fb() call above.
               --new_fb->ref_count;
@@ -4031,8 +4033,8 @@
 
   av1_set_speed_features_framesize_independent(cpi, cpi->speed);
   av1_set_rd_speed_thresholds(cpi);
-  cm->interp_filter = SWITCHABLE;
-  cm->switchable_motion_mode = 1;
+  cm->features.interp_filter = SWITCHABLE;
+  cm->features.switchable_motion_mode = 1;
 }
 
 #if !CONFIG_REALTIME_ONLY
@@ -4354,7 +4356,8 @@
   if (aom_realloc_frame_buffer(
           &cm->cur_frame->buf, cm->width, cm->height, seq_params->subsampling_x,
           seq_params->subsampling_y, seq_params->use_highbitdepth,
-          cpi->oxcf.border_in_pixels, cm->byte_alignment, NULL, NULL, NULL))
+          cpi->oxcf.border_in_pixels, cm->features.byte_alignment, NULL, NULL,
+          NULL))
     aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
                        "Failed to allocate frame buffer");
 
@@ -4726,7 +4729,8 @@
             &cpi->scaled_source, cm->superres_upscaled_width,
             cm->superres_upscaled_height, cm->seq_params.subsampling_x,
             cm->seq_params.subsampling_y, cm->seq_params.use_highbitdepth,
-            AOM_BORDER_IN_PIXELS, cm->byte_alignment, NULL, NULL, NULL))
+            AOM_BORDER_IN_PIXELS, cm->features.byte_alignment, NULL, NULL,
+            NULL))
       aom_internal_error(
           &cm->error, AOM_CODEC_MEM_ERROR,
           "Failed to reallocate scaled source buffer for superres");
@@ -4908,7 +4912,7 @@
     }
   }
 
-  fix_interp_filter(&cm->interp_filter, cpi->td.counts);
+  fix_interp_filter(&cm->features.interp_filter, cpi->td.counts);
 }
 
 static int get_regulated_q_overshoot(AV1_COMP *const cpi, int q_low, int q_high,
@@ -5725,7 +5729,7 @@
                              ybf->y_crop_height, ybf->subsampling_x,
                              ybf->subsampling_y,
                              ybf->flags & YV12_FLAG_HIGHBITDEPTH, ybf->border,
-                             cm->byte_alignment) != AOM_CODEC_OK) {
+                             cm->features.byte_alignment) != AOM_CODEC_OK) {
     aom_internal_error(
         &cm->error, AOM_CODEC_MEM_ERROR,
         "Failed to allocate copy buffer for saving coding context");
@@ -6429,7 +6433,7 @@
   av1_accumulate_frame_counts(&aggregate_fc, &cpi->counts);
 #endif  // CONFIG_ENTROPY_STATS
 
-  if (cm->refresh_frame_context == REFRESH_FRAME_CONTEXT_BACKWARD) {
+  if (features->refresh_frame_context == REFRESH_FRAME_CONTEXT_BACKWARD) {
     *cm->fc = cpi->tile_data[largest_tile_id].tctx;
     av1_reset_cdf_symbol_counters(cm->fc);
   }
@@ -6502,7 +6506,7 @@
 
   current_frame->refresh_frame_flags = frame_params->refresh_frame_flags;
   cm->features.error_resilient_mode = frame_params->error_resilient_mode;
-  cm->primary_ref_frame = frame_params->primary_ref_frame;
+  cm->features.primary_ref_frame = frame_params->primary_ref_frame;
   cm->current_frame.frame_type = frame_params->frame_type;
   cm->show_frame = frame_params->show_frame;
   cpi->ref_frame_flags = frame_params->ref_frame_flags;
@@ -6773,11 +6777,11 @@
   av1_set_high_precision_mv(cpi, 1, 0);
 
   // Normal defaults
-  cm->refresh_frame_context = oxcf->frame_parallel_decoding_mode
-                                  ? REFRESH_FRAME_CONTEXT_DISABLED
-                                  : REFRESH_FRAME_CONTEXT_BACKWARD;
+  cm->features.refresh_frame_context = oxcf->frame_parallel_decoding_mode
+                                           ? REFRESH_FRAME_CONTEXT_DISABLED
+                                           : REFRESH_FRAME_CONTEXT_BACKWARD;
   if (oxcf->large_scale_tile)
-    cm->refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED;
+    cm->features.refresh_frame_context = REFRESH_FRAME_CONTEXT_DISABLED;
 
   // Initialize fields related to forward keyframes
   cpi->no_show_kf = 0;
diff --git a/av1/encoder/interp_search.c b/av1/encoder/interp_search.c
index 1b94651..7fc2672 100644
--- a/av1/encoder/interp_search.c
+++ b/av1/encoder/interp_search.c
@@ -612,7 +612,7 @@
   av1_init_rd_stats(&rd_stats);
 
   int match_found_idx = -1;
-  const InterpFilter assign_filter = cm->interp_filter;
+  const InterpFilter assign_filter = cm->features.interp_filter;
 
   match_found_idx = av1_find_interp_filter_match(
       mbmi, cpi, assign_filter, need_search, args->interp_filter_stats,
diff --git a/av1/encoder/nonrd_pickmode.c b/av1/encoder/nonrd_pickmode.c
index 902420d..d0eb08b 100644
--- a/av1/encoder/nonrd_pickmode.c
+++ b/av1/encoder/nonrd_pickmode.c
@@ -917,7 +917,7 @@
   mbmi->motion_mode = SIMPLE_TRANSLATION;
   mbmi->num_proj_ref = 1;
   mbmi->interintra_mode = 0;
-  set_default_interp_filters(mbmi, cm->interp_filter);
+  set_default_interp_filters(mbmi, cm->features.interp_filter);
 }
 
 #if CONFIG_INTERNAL_STATS
@@ -1333,7 +1333,7 @@
     else
       model_rd_for_sb_y(cpi, bsize, x, xd, &pf_rate[i], &pf_dist[i],
                         &skip_txfm[i], NULL, &pf_var[i], &pf_sse[i], 1);
-    pf_rate[i] += av1_get_switchable_rate(cm, x, xd);
+    pf_rate[i] += av1_get_switchable_rate(x, xd, cm->features.interp_filter);
     cost = RDCOST(x->rdmult, pf_rate[i], pf_dist[i]);
     pf_tx_size[i] = mi->tx_size;
     if (cost < best_cost) {
@@ -1592,7 +1592,7 @@
   // filter_ref, we use a less strict condition on assigning filter_ref.
   // This is to reduce the probabily of entering the flow of not assigning
   // filter_ref and then skip filter search.
-  filter_ref = cm->interp_filter;
+  filter_ref = cm->features.interp_filter;
 
   // initialize mode decisions
   av1_invalid_rd_stats(&best_rdc);
diff --git a/av1/encoder/picklpf.c b/av1/encoder/picklpf.c
index 2b4addb..78cb1c8 100644
--- a/av1/encoder/picklpf.c
+++ b/av1/encoder/picklpf.c
@@ -147,7 +147,7 @@
       bias = (bias * cpi->twopass.section_intra_rating) / 20;
 
     // yx, bias less for large block size
-    if (cm->tx_mode != ONLY_4X4) bias >>= 1;
+    if (cm->features.tx_mode != ONLY_4X4) bias >>= 1;
 
     if (filt_direction <= 0 && filt_low != filt_mid) {
       // Get Low filter error score
diff --git a/av1/encoder/rd.c b/av1/encoder/rd.c
index b7b0cd9..20e2ab2 100644
--- a/av1/encoder/rd.c
+++ b/av1/encoder/rd.c
@@ -1065,9 +1065,9 @@
                                                        : NULL;
 }
 
-int av1_get_switchable_rate(const AV1_COMMON *const cm, MACROBLOCK *x,
-                            const MACROBLOCKD *xd) {
-  if (cm->interp_filter == SWITCHABLE) {
+int av1_get_switchable_rate(const MACROBLOCK *x, const MACROBLOCKD *xd,
+                            InterpFilter interp_filter) {
+  if (interp_filter == SWITCHABLE) {
     const MB_MODE_INFO *const mbmi = xd->mi[0];
     int inter_filter_cost = 0;
     int dir;
diff --git a/av1/encoder/rd.h b/av1/encoder/rd.h
index e1d5bd9..cac8c5b 100644
--- a/av1/encoder/rd.h
+++ b/av1/encoder/rd.h
@@ -230,8 +230,8 @@
 void av1_model_rd_surffit(BLOCK_SIZE bsize, double sse_norm, double xm,
                           double yl, double *rate_f, double *distbysse_f);
 
-int av1_get_switchable_rate(const AV1_COMMON *const cm, MACROBLOCK *x,
-                            const MACROBLOCKD *xd);
+int av1_get_switchable_rate(const MACROBLOCK *x, const MACROBLOCKD *xd,
+                            InterpFilter interp_filter);
 
 YV12_BUFFER_CONFIG *av1_get_scaled_ref_frame(const struct AV1_COMP *cpi,
                                              int ref_frame);
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index 8022137..268f08f 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -1229,6 +1229,7 @@
     const BUFFER_SET *orig_dst, int64_t *best_est_rd, int do_tx_search,
     InterModesInfo *inter_modes_info, int eval_motion_mode) {
   const AV1_COMMON *const cm = &cpi->common;
+  const FeatureFlags *const features = &cm->features;
   const int num_planes = av1_num_planes(cm);
   MACROBLOCKD *xd = &x->e_mbd;
   MB_MODE_INFO *mbmi = xd->mi[0];
@@ -1252,9 +1253,9 @@
   aom_clear_system_state();
   mbmi->num_proj_ref = 1;  // assume num_proj_ref >=1
   MOTION_MODE last_motion_mode_allowed = SIMPLE_TRANSLATION;
-  if (cm->switchable_motion_mode) {
+  if (features->switchable_motion_mode) {
     last_motion_mode_allowed = motion_mode_allowed(
-        xd->global_motion, xd, mbmi, cm->features.allow_warped_motion);
+        xd->global_motion, xd, mbmi, features->allow_warped_motion);
   }
 
   if (last_motion_mode_allowed == WARPED_CAUSAL) {
@@ -1268,8 +1269,10 @@
   const MB_MODE_INFO base_mbmi = *mbmi;
   MB_MODE_INFO best_mbmi;
   SimpleRDState *const simple_states = &args->simple_rd_state[mbmi->ref_mv_idx];
+  const int interp_filter = features->interp_filter;
   const int switchable_rate =
-      av1_is_interp_needed(xd) ? av1_get_switchable_rate(cm, x, xd) : 0;
+      av1_is_interp_needed(xd) ? av1_get_switchable_rate(x, xd, interp_filter)
+                               : 0;
   int64_t best_rd = INT64_MAX;
   int best_rate_mv = rate_mv0;
   const int mi_row = xd->mi_row;
@@ -1351,8 +1354,8 @@
       int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE];
       mbmi->motion_mode = WARPED_CAUSAL;
       mbmi->wm_params.wmtype = DEFAULT_WMTYPE;
-      mbmi->interp_filters = av1_broadcast_interp_filter(
-          av1_unswitchable_filter(cm->interp_filter));
+      mbmi->interp_filters =
+          av1_broadcast_interp_filter(av1_unswitchable_filter(interp_filter));
 
       memcpy(pts, pts0, total_samples * 2 * sizeof(*pts0));
       memcpy(pts_inref, pts_inref0, total_samples * 2 * sizeof(*pts_inref0));
@@ -1569,8 +1572,8 @@
 
     if (this_mode == GLOBALMV || this_mode == GLOBAL_GLOBALMV) {
       if (is_nontrans_global_motion(xd, xd->mi[0])) {
-        mbmi->interp_filters = av1_broadcast_interp_filter(
-            av1_unswitchable_filter(cm->interp_filter));
+        mbmi->interp_filters =
+            av1_broadcast_interp_filter(av1_unswitchable_filter(interp_filter));
       }
     }
 
@@ -1944,7 +1947,7 @@
     mbmi->comp_group_idx = 0;
     mbmi->compound_idx = 1;
   }
-  set_default_interp_filters(mbmi, cm->interp_filter);
+  set_default_interp_filters(mbmi, cm->features.interp_filter);
 
   const int mi_row = xd->mi_row;
   const int mi_col = xd->mi_col;
@@ -2485,7 +2488,7 @@
     if (is_comp_pred) {
       // Find matching interp filter or set to default interp filter
       const int need_search = av1_is_interp_needed(xd);
-      const InterpFilter assign_filter = cm->interp_filter;
+      const InterpFilter assign_filter = cm->features.interp_filter;
       int is_luma_interp_done = 0;
       av1_find_interp_filter_match(mbmi, cpi, assign_filter, need_search,
                                    args->interp_filter_stats,
@@ -2961,7 +2964,7 @@
   mbmi->ref_mv_idx = 0;
   mbmi->skip_mode = mbmi->skip = 1;
 
-  set_default_interp_filters(mbmi, cm->interp_filter);
+  set_default_interp_filters(mbmi, cm->features.interp_filter);
 
   set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
   for (int i = 0; i < num_planes; i++) {
@@ -3029,7 +3032,8 @@
         (INTERINTRA_MODE)(II_DC_PRED - 1);
     search_state->best_mbmode.filter_intra_mode_info.use_filter_intra = 0;
 
-    set_default_interp_filters(&search_state->best_mbmode, cm->interp_filter);
+    set_default_interp_filters(&search_state->best_mbmode,
+                               cm->features.interp_filter);
 
     search_state->best_mode_index = mode_index;
 
@@ -3793,7 +3797,7 @@
   mbmi->mv[0].as_int = mbmi->mv[1].as_int = 0;
   mbmi->motion_mode = SIMPLE_TRANSLATION;
   mbmi->interintra_mode = (INTERINTRA_MODE)(II_DC_PRED - 1);
-  set_default_interp_filters(mbmi, cm->interp_filter);
+  set_default_interp_filters(mbmi, cm->features.interp_filter);
 }
 
 static AOM_INLINE void collect_single_states(MACROBLOCK *x,
@@ -4188,6 +4192,7 @@
                                const BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx,
                                int64_t best_rd_so_far) {
   AV1_COMMON *const cm = &cpi->common;
+  const FeatureFlags *const features = &cm->features;
   const int num_planes = av1_num_planes(cm);
   const SPEED_FEATURES *const sf = &cpi->sf;
   MACROBLOCKD *const xd = &x->e_mbd;
@@ -4707,20 +4712,20 @@
       const NN_CONFIG *nn_config = (AOMMIN(cm->width, cm->height) <= 480)
                                        ? &av1_intrap_nn_config
                                        : &av1_intrap_hd_nn_config;
-      float features[6];
+      float nn_features[6];
       float scores[2] = { 0.0f };
       float probs[2] = { 0.0f };
 
-      features[0] = (float)search_state.best_mbmode.skip;
-      features[1] = (float)mi_size_wide_log2[bsize];
-      features[2] = (float)mi_size_high_log2[bsize];
-      features[3] = (float)intra_cost;
-      features[4] = (float)inter_cost;
+      nn_features[0] = (float)search_state.best_mbmode.skip;
+      nn_features[1] = (float)mi_size_wide_log2[bsize];
+      nn_features[2] = (float)mi_size_high_log2[bsize];
+      nn_features[3] = (float)intra_cost;
+      nn_features[4] = (float)inter_cost;
       const int ac_q = av1_ac_quant_QTX(x->qindex, 0, xd->bd);
       const int ac_q_max = av1_ac_quant_QTX(255, 0, xd->bd);
-      features[5] = (float)(ac_q_max / ac_q);
+      nn_features[5] = (float)(ac_q_max / ac_q);
 
-      av1_nn_predict(features, nn_config, 1, scores);
+      av1_nn_predict(nn_features, nn_config, 1, scores);
       aom_clear_system_state();
       av1_nn_softmax(scores, probs, 2);
 
@@ -4799,8 +4804,7 @@
   // Only try palette mode when the best mode so far is an intra mode.
   const int try_palette =
       cpi->oxcf.enable_palette &&
-      av1_allow_palette(cm->features.allow_screen_content_tools,
-                        mbmi->sb_type) &&
+      av1_allow_palette(features->allow_screen_content_tools, mbmi->sb_type) &&
       !is_inter_mode(search_state.best_mbmode.mode);
   PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info;
   RD_STATS this_rd_cost;
@@ -4851,12 +4855,13 @@
     return;
   }
 
-  assert((cm->interp_filter == SWITCHABLE) ||
-         (cm->interp_filter ==
+  const InterpFilter interp_filter = features->interp_filter;
+  assert((interp_filter == SWITCHABLE) ||
+         (interp_filter ==
           search_state.best_mbmode.interp_filters.as_filters.y_filter) ||
          !is_inter_block(&search_state.best_mbmode));
-  assert((cm->interp_filter == SWITCHABLE) ||
-         (cm->interp_filter ==
+  assert((interp_filter == SWITCHABLE) ||
+         (interp_filter ==
           search_state.best_mbmode.interp_filters.as_filters.x_filter) ||
          !is_inter_block(&search_state.best_mbmode));
 
@@ -4875,8 +4880,8 @@
   if (mbmi->mode == GLOBALMV || mbmi->mode == GLOBAL_GLOBALMV) {
     // Correct the interp filters for GLOBALMV
     if (is_nontrans_global_motion(xd, xd->mi[0])) {
-      int_interpfilters filters = av1_broadcast_interp_filter(
-          av1_unswitchable_filter(cm->interp_filter));
+      int_interpfilters filters =
+          av1_broadcast_interp_filter(av1_unswitchable_filter(interp_filter));
       assert(mbmi->interp_filters.as_int == filters.as_int);
       (void)filters;
     }
@@ -4918,6 +4923,7 @@
                                         PICK_MODE_CONTEXT *ctx,
                                         int64_t best_rd_so_far) {
   const AV1_COMMON *const cm = &cpi->common;
+  const FeatureFlags *const features = &cm->features;
   MACROBLOCKD *const xd = &x->e_mbd;
   MB_MODE_INFO *const mbmi = xd->mi[0];
   unsigned char segment_id = mbmi->segment_id;
@@ -4960,8 +4966,8 @@
   mbmi->ref_frame[1] = NONE_FRAME;
   mbmi->mv[0].as_int =
       gm_get_motion_vector(&cm->global_motion[mbmi->ref_frame[0]],
-                           cm->features.allow_high_precision_mv, bsize, mi_col,
-                           mi_row, cm->features.cur_frame_force_integer_mv)
+                           features->allow_high_precision_mv, bsize, mi_col,
+                           mi_row, features->cur_frame_force_integer_mv)
           .as_int;
   mbmi->tx_size = max_txsize_lookup[bsize];
   x->force_skip = 1;
@@ -4979,10 +4985,11 @@
                                              mbmi->num_proj_ref, bsize);
   }
 
-  set_default_interp_filters(mbmi, cm->interp_filter);
+  const InterpFilter interp_filter = features->interp_filter;
+  set_default_interp_filters(mbmi, interp_filter);
 
-  if (cm->interp_filter != SWITCHABLE) {
-    best_filter = cm->interp_filter;
+  if (interp_filter != SWITCHABLE) {
+    best_filter = interp_filter;
   } else {
     best_filter = EIGHTTAP_REGULAR;
     if (av1_is_interp_needed(xd) &&
@@ -4992,7 +4999,7 @@
       int best_rs = INT_MAX;
       for (i = 0; i < SWITCHABLE_FILTERS; ++i) {
         mbmi->interp_filters = av1_broadcast_interp_filter(i);
-        rs = av1_get_switchable_rate(cm, x, xd);
+        rs = av1_get_switchable_rate(x, xd, interp_filter);
         if (rs < best_rs) {
           best_rs = rs;
           best_filter = mbmi->interp_filters.as_filters.y_filter;
@@ -5002,7 +5009,7 @@
   }
   // Set the appropriate filter
   mbmi->interp_filters = av1_broadcast_interp_filter(best_filter);
-  rate2 += av1_get_switchable_rate(cm, x, xd);
+  rate2 += av1_get_switchable_rate(x, xd, interp_filter);
 
   if (cm->current_frame.reference_mode == REFERENCE_MODE_SELECT)
     rate2 += comp_inter_cost[comp_pred];
@@ -5022,8 +5029,8 @@
     return;
   }
 
-  assert((cm->interp_filter == SWITCHABLE) ||
-         (cm->interp_filter == mbmi->interp_filters.as_filters.y_filter));
+  assert((interp_filter == SWITCHABLE) ||
+         (interp_filter == mbmi->interp_filters.as_filters.y_filter));
 
   if (cpi->sf.inter_sf.adaptive_rd_thresh) {
     av1_update_rd_thresh_fact(cm, x->thresh_freq_fact,
diff --git a/av1/encoder/segmentation.c b/av1/encoder/segmentation.c
index c34c3fc..0c029c0 100644
--- a/av1/encoder/segmentation.c
+++ b/av1/encoder/segmentation.c
@@ -216,7 +216,7 @@
     no_pred_cost += no_pred_segcounts[i] * seg_id_cost[i];
 
   // Frames without past dependency cannot use temporal prediction
-  if (cm->primary_ref_frame != PRIMARY_REF_NONE) {
+  if (cm->features.primary_ref_frame != PRIMARY_REF_NONE) {
     int pred_flag_cost[SEG_TEMPORAL_PRED_CTXS][2];
     for (int i = 0; i < SEG_TEMPORAL_PRED_CTXS; ++i)
       av1_cost_tokens_from_cdf(pred_flag_cost[i], segp->pred_cdf[i], NULL);
diff --git a/av1/encoder/tune_vmaf.c b/av1/encoder/tune_vmaf.c
index 72fd846..997f78e 100644
--- a/av1/encoder/tune_vmaf.c
+++ b/av1/encoder/tune_vmaf.c
@@ -200,9 +200,9 @@
 
   YV12_BUFFER_CONFIG sharpened;
   memset(&sharpened, 0, sizeof(sharpened));
-  aom_alloc_frame_buffer(&sharpened, width, height, 1, 1,
-                         cm->seq_params.use_highbitdepth,
-                         cpi->oxcf.border_in_pixels, cm->byte_alignment);
+  aom_alloc_frame_buffer(
+      &sharpened, width, height, 1, 1, cm->seq_params.use_highbitdepth,
+      cpi->oxcf.border_in_pixels, cm->features.byte_alignment);
 
   const double baseline_variance = frame_average_variance(cpi, source);
   double unsharp_amount;
@@ -245,12 +245,12 @@
   YV12_BUFFER_CONFIG source_extended, blurred;
   memset(&source_extended, 0, sizeof(source_extended));
   memset(&blurred, 0, sizeof(blurred));
-  aom_alloc_frame_buffer(&source_extended, width, height, 1, 1,
-                         cm->seq_params.use_highbitdepth,
-                         cpi->oxcf.border_in_pixels, cm->byte_alignment);
-  aom_alloc_frame_buffer(&blurred, width, height, 1, 1,
-                         cm->seq_params.use_highbitdepth,
-                         cpi->oxcf.border_in_pixels, cm->byte_alignment);
+  aom_alloc_frame_buffer(
+      &source_extended, width, height, 1, 1, cm->seq_params.use_highbitdepth,
+      cpi->oxcf.border_in_pixels, cm->features.byte_alignment);
+  aom_alloc_frame_buffer(
+      &blurred, width, height, 1, 1, cm->seq_params.use_highbitdepth,
+      cpi->oxcf.border_in_pixels, cm->features.byte_alignment);
 
   av1_copy_and_extend_frame(source, &source_extended);
   gaussian_blur(bit_depth, &source_extended, &blurred);
@@ -276,12 +276,12 @@
   YV12_BUFFER_CONFIG source_extended, blurred;
   memset(&blurred, 0, sizeof(blurred));
   memset(&source_extended, 0, sizeof(source_extended));
-  aom_alloc_frame_buffer(&blurred, width, height, 1, 1,
-                         cm->seq_params.use_highbitdepth,
-                         cpi->oxcf.border_in_pixels, cm->byte_alignment);
-  aom_alloc_frame_buffer(&source_extended, width, height, 1, 1,
-                         cm->seq_params.use_highbitdepth,
-                         cpi->oxcf.border_in_pixels, cm->byte_alignment);
+  aom_alloc_frame_buffer(
+      &blurred, width, height, 1, 1, cm->seq_params.use_highbitdepth,
+      cpi->oxcf.border_in_pixels, cm->features.byte_alignment);
+  aom_alloc_frame_buffer(
+      &source_extended, width, height, 1, 1, cm->seq_params.use_highbitdepth,
+      cpi->oxcf.border_in_pixels, cm->features.byte_alignment);
 
   av1_copy_and_extend_frame(source, &source_extended);
   gaussian_blur(bit_depth, &source_extended, &blurred);
@@ -304,12 +304,12 @@
   YV12_BUFFER_CONFIG source_block, blurred_block;
   memset(&source_block, 0, sizeof(source_block));
   memset(&blurred_block, 0, sizeof(blurred_block));
-  aom_alloc_frame_buffer(&source_block, block_w, block_h, 1, 1,
-                         cm->seq_params.use_highbitdepth,
-                         cpi->oxcf.border_in_pixels, cm->byte_alignment);
-  aom_alloc_frame_buffer(&blurred_block, block_w, block_h, 1, 1,
-                         cm->seq_params.use_highbitdepth,
-                         cpi->oxcf.border_in_pixels, cm->byte_alignment);
+  aom_alloc_frame_buffer(
+      &source_block, block_w, block_h, 1, 1, cm->seq_params.use_highbitdepth,
+      cpi->oxcf.border_in_pixels, cm->features.byte_alignment);
+  aom_alloc_frame_buffer(
+      &blurred_block, block_w, block_h, 1, 1, cm->seq_params.use_highbitdepth,
+      cpi->oxcf.border_in_pixels, cm->features.byte_alignment);
 
   for (int row = 0; row < num_rows; ++row) {
     for (int col = 0; col < num_cols; ++col) {
@@ -510,10 +510,10 @@
   aom_clear_system_state();
   YV12_BUFFER_CONFIG resized_source;
   memset(&resized_source, 0, sizeof(resized_source));
-  aom_alloc_frame_buffer(&resized_source, y_width / resize_factor,
-                         y_height / resize_factor, 1, 1,
-                         cm->seq_params.use_highbitdepth,
-                         cpi->oxcf.border_in_pixels, cm->byte_alignment);
+  aom_alloc_frame_buffer(
+      &resized_source, y_width / resize_factor, y_height / resize_factor, 1, 1,
+      cm->seq_params.use_highbitdepth, cpi->oxcf.border_in_pixels,
+      cm->features.byte_alignment);
   av1_resize_and_extend_frame(cpi->source, &resized_source, bit_depth,
                               av1_num_planes(cm));
 
@@ -530,7 +530,8 @@
   memset(&blurred, 0, sizeof(blurred));
   aom_alloc_frame_buffer(&blurred, resized_y_width, resized_y_height, 1, 1,
                          cm->seq_params.use_highbitdepth,
-                         cpi->oxcf.border_in_pixels, cm->byte_alignment);
+                         cpi->oxcf.border_in_pixels,
+                         cm->features.byte_alignment);
   gaussian_blur(bit_depth, &resized_source, &blurred);
 
   double *scores = aom_malloc(sizeof(*scores) * (num_rows * num_cols));
@@ -674,15 +675,15 @@
   memset(&blurred_last, 0, sizeof(blurred_last));
   memset(&blurred_next, 0, sizeof(blurred_next));
 
-  aom_alloc_frame_buffer(&blurred_cur, y_width, y_height, 1, 1,
-                         cm->seq_params.use_highbitdepth,
-                         cpi->oxcf.border_in_pixels, cm->byte_alignment);
-  aom_alloc_frame_buffer(&blurred_last, y_width, y_height, 1, 1,
-                         cm->seq_params.use_highbitdepth,
-                         cpi->oxcf.border_in_pixels, cm->byte_alignment);
-  aom_alloc_frame_buffer(&blurred_next, y_width, y_height, 1, 1,
-                         cm->seq_params.use_highbitdepth,
-                         cpi->oxcf.border_in_pixels, cm->byte_alignment);
+  aom_alloc_frame_buffer(
+      &blurred_cur, y_width, y_height, 1, 1, cm->seq_params.use_highbitdepth,
+      cpi->oxcf.border_in_pixels, cm->features.byte_alignment);
+  aom_alloc_frame_buffer(
+      &blurred_last, y_width, y_height, 1, 1, cm->seq_params.use_highbitdepth,
+      cpi->oxcf.border_in_pixels, cm->features.byte_alignment);
+  aom_alloc_frame_buffer(
+      &blurred_next, y_width, y_height, 1, 1, cm->seq_params.use_highbitdepth,
+      cpi->oxcf.border_in_pixels, cm->features.byte_alignment);
 
   gaussian_blur(bit_depth, cur, &blurred_cur);
   gaussian_blur(bit_depth, last, &blurred_last);