[CFL] UV_PREDICTION_MODE

A separate prediction mode struct is added to allow
for uv-only modes (like CfL). Note: CfL will be
added as a separate mode in an upcoming commit.

Results on Subset1 (Compared to 4266a7ed with CfL enabled)
  PSNR | PSNR Cb | PSNR Cr | PSNR HVS |   SSIM | MS SSIM | CIEDE 2000
0.0000 |  0.0000 |  0.0000 |   0.0000 | 0.0000 |  0.0000 |     0.0000

Change-Id: Ie80711c641c97f745daac899eadce6201ed97fcc
diff --git a/av1/common/blockd.h b/av1/common/blockd.h
index 4e876ac..4ba0def 100644
--- a/av1/common/blockd.h
+++ b/av1/common/blockd.h
@@ -377,7 +377,7 @@
   int8_t seg_id_predicted;  // valid only when temporal_update is enabled
 
   // Only for INTRA blocks
-  PREDICTION_MODE uv_mode;
+  UV_PREDICTION_MODE uv_mode;
 #if CONFIG_PALETTE
   PALETTE_MODE_INFO palette_mode_info;
 #endif  // CONFIG_PALETTE
@@ -497,6 +497,33 @@
 #endif
 }
 
+#if CONFIG_CFL
+static INLINE PREDICTION_MODE get_uv_mode(UV_PREDICTION_MODE mode) {
+  static const PREDICTION_MODE uv2y[UV_INTRA_MODES] = {
+    DC_PRED,    // UV_DC_PRED
+    V_PRED,     // UV_V_PRED
+    H_PRED,     // UV_H_PRED
+    D45_PRED,   // UV_D45_PRED
+    D135_PRED,  // UV_D135_PRED
+    D117_PRED,  // UV_D117_PRED
+    D153_PRED,  // UV_D153_PRED
+    D207_PRED,  // UV_D207_PRED
+    D63_PRED,   // UV_D63_PRED
+#if CONFIG_ALT_INTRA
+    SMOOTH_PRED,  // UV_SMOOTH_PRED
+#if CONFIG_SMOOTH_HV
+    SMOOTH_V_PRED,  // UV_SMOOTH_V_PRED
+    SMOOTH_H_PRED,  // UV_SMOOTH_H_PRED
+#endif              // CONFIG_SMOOTH_HV
+#endif              // CONFIG_ALT_INTRA
+    TM_PRED,        // UV_TM_PRED
+  };
+  return uv2y[mode];
+}
+#else
+static INLINE PREDICTION_MODE get_uv_mode(PREDICTION_MODE mode) { return mode; }
+#endif  // CONFIG_CFL
+
 static INLINE int is_inter_block(const MB_MODE_INFO *mbmi) {
 #if CONFIG_INTRABC
   if (is_intrabc_block(mbmi)) return 1;
@@ -1191,7 +1218,8 @@
   if (is_inter_block(mbmi)) return mbmi->mode;
 
   int block_raster_idx = av1_block_index_to_raster_order(tx_size, block_idx);
-  return (plane == 0) ? get_y_mode(mi, block_raster_idx) : mbmi->uv_mode;
+  return (plane == PLANE_TYPE_Y) ? get_y_mode(mi, block_raster_idx)
+                                 : get_uv_mode(mbmi->uv_mode);
 }
 #endif
 
@@ -1206,7 +1234,7 @@
 
   return intra_mode_to_tx_type_context[plane_type == PLANE_TYPE_Y
                                            ? get_y_mode(xd->mi[0], block_idx)
-                                           : mbmi->uv_mode];
+                                           : get_uv_mode(mbmi->uv_mode)];
 }
 
 static INLINE TX_TYPE av1_get_tx_type(PLANE_TYPE plane_type,
@@ -1281,7 +1309,7 @@
     return DCT_DCT;
   else
 #endif  // CONFIG_CHROMA_2X2
-    return intra_mode_to_tx_type_context[mbmi->uv_mode];
+    return intra_mode_to_tx_type_context[get_uv_mode(mbmi->uv_mode)];
 #else   // CONFIG_CB4X4
   // Sub8x8-Inter/Intra OR UV-Intra
   if (is_inter_block(mbmi)) {  // Sub8x8-Inter
@@ -1291,7 +1319,7 @@
         av1_block_index_to_raster_order(tx_size, block);
     return intra_mode_to_tx_type_context[plane_type == PLANE_TYPE_Y
                                              ? get_y_mode(mi, block_raster_idx)
-                                             : mbmi->uv_mode];
+                                             : get_uv_mode(mbmi->uv_mode)];
   }
 #endif  // CONFIG_CB4X4
 #else   // CONFIG_EXT_TX
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index 7566e8d..c4d75c5 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -2614,7 +2614,7 @@
     };
 
 static const aom_cdf_prob
-    default_uv_mode_cdf[INTRA_MODES][CDF_SIZE(INTRA_MODES)] = {
+    default_uv_mode_cdf[INTRA_MODES][CDF_SIZE(UV_INTRA_MODES)] = {
       { AOM_ICDF(23552), AOM_ICDF(23660), AOM_ICDF(26044), AOM_ICDF(28731),
         AOM_ICDF(29093), AOM_ICDF(29590), AOM_ICDF(30000), AOM_ICDF(30465),
         AOM_ICDF(30825), AOM_ICDF(31478), AOM_ICDF(32088), AOM_ICDF(32401),
@@ -2686,7 +2686,7 @@
     };
 
 static const aom_cdf_prob
-    default_uv_mode_cdf[INTRA_MODES][CDF_SIZE(INTRA_MODES)] = {
+    default_uv_mode_cdf[INTRA_MODES][CDF_SIZE(UV_INTRA_MODES)] = {
       { AOM_ICDF(25472), AOM_ICDF(25558), AOM_ICDF(27783), AOM_ICDF(30779),
         AOM_ICDF(30988), AOM_ICDF(31269), AOM_ICDF(31492), AOM_ICDF(31741),
         AOM_ICDF(32014), AOM_ICDF(32420), AOM_ICDF(32768), 0 },
@@ -2740,7 +2740,7 @@
     };
 
 static const aom_cdf_prob
-    default_uv_mode_cdf[INTRA_MODES][CDF_SIZE(INTRA_MODES)] = {
+    default_uv_mode_cdf[INTRA_MODES][CDF_SIZE(UV_INTRA_MODES)] = {
       { AOM_ICDF(15360), AOM_ICDF(15836), AOM_ICDF(20863), AOM_ICDF(27513),
         AOM_ICDF(28269), AOM_ICDF(29048), AOM_ICDF(29455), AOM_ICDF(30154),
         AOM_ICDF(31206), AOM_ICDF(32768), 0 },
diff --git a/av1/common/entropymode.h b/av1/common/entropymode.h
index 61e2fcd..83beb6a 100644
--- a/av1/common/entropymode.h
+++ b/av1/common/entropymode.h
@@ -92,7 +92,7 @@
 
 typedef struct frame_contexts {
   aom_prob y_mode_prob[BLOCK_SIZE_GROUPS][INTRA_MODES - 1];
-  aom_prob uv_mode_prob[INTRA_MODES][INTRA_MODES - 1];
+  aom_prob uv_mode_prob[INTRA_MODES][UV_INTRA_MODES - 1];
 #if CONFIG_EXT_PARTITION_TYPES
   aom_prob partition_prob[PARTITION_CONTEXTS][EXT_PARTITION_TYPES - 1];
 #else
@@ -321,7 +321,7 @@
   aom_prob switchable_restore_prob[RESTORE_SWITCHABLE_TYPES - 1];
 #endif  // CONFIG_LOOP_RESTORATION
   aom_cdf_prob y_mode_cdf[BLOCK_SIZE_GROUPS][CDF_SIZE(INTRA_MODES)];
-  aom_cdf_prob uv_mode_cdf[INTRA_MODES][CDF_SIZE(INTRA_MODES)];
+  aom_cdf_prob uv_mode_cdf[INTRA_MODES][CDF_SIZE(UV_INTRA_MODES)];
 #if CONFIG_EXT_PARTITION_TYPES
   aom_cdf_prob partition_cdf[PARTITION_CONTEXTS][CDF_SIZE(EXT_PARTITION_TYPES)];
 #else
@@ -376,7 +376,7 @@
 #if CONFIG_ENTROPY_STATS
   unsigned int kf_y_mode[INTRA_MODES][INTRA_MODES][INTRA_MODES];
   unsigned int y_mode[BLOCK_SIZE_GROUPS][INTRA_MODES];
-  unsigned int uv_mode[INTRA_MODES][INTRA_MODES];
+  unsigned int uv_mode[INTRA_MODES][UV_INTRA_MODES];
 #endif  // CONFIG_ENTROPY_STATS
 #if CONFIG_EXT_PARTITION_TYPES
   unsigned int partition[PARTITION_CONTEXTS][EXT_PARTITION_TYPES];
diff --git a/av1/common/enums.h b/av1/common/enums.h
index bd9b277..a4dfbf8 100644
--- a/av1/common/enums.h
+++ b/av1/common/enums.h
@@ -415,6 +415,37 @@
   INTRA_INVALID = MB_MODE_COUNT  // For uv_mode in inter blocks
 } PREDICTION_MODE;
 
+#if CONFIG_CFL
+// TODO(ltrudeau) Do we really want to pack this?
+// TODO(ltrudeau) Do we match with PREDICTION_MODE?
+typedef enum ATTRIBUTE_PACKED {
+  UV_DC_PRED,    // Average of above and left pixels
+  UV_V_PRED,     // Vertical
+  UV_H_PRED,     // Horizontal
+  UV_D45_PRED,   // Directional 45  deg = round(arctan(1/1) * 180/pi)
+  UV_D135_PRED,  // Directional 135 deg = 180 - 45
+  UV_D117_PRED,  // Directional 117 deg = 180 - 63
+  UV_D153_PRED,  // Directional 153 deg = 180 - 27
+  UV_D207_PRED,  // Directional 207 deg = 180 + 27
+  UV_D63_PRED,   // Directional 63  deg = round(arctan(2/1) * 180/pi)
+#if CONFIG_ALT_INTRA
+  UV_SMOOTH_PRED,  // Combination of horizontal and vertical interpolation
+#if CONFIG_SMOOTH_HV
+  UV_SMOOTH_V_PRED,  // Vertical interpolation
+  UV_SMOOTH_H_PRED,  // Horizontal interpolation
+#endif               // CONFIG_SMOOTH_HV
+#endif               // CONFIG_ALT_INTRA
+  UV_TM_PRED,        // True-motion
+  UV_INTRA_MODES,
+  UV_MODE_INVALID,  // For uv_mode in inter blocks
+} UV_PREDICTION_MODE;
+#else
+#define UV_INTRA_MODES (INTRA_MODES)
+#define UV_PREDICTION_MODE PREDICTION_MODE
+#define UV_DC_PRED (DC_PRED)
+#define UV_MODE_INVALID (INTRA_INVALID)
+#endif  // CONFIG_CFL
+
 typedef enum {
   SIMPLE_TRANSLATION = 0,
 #if CONFIG_MOTION_VAR
diff --git a/av1/common/reconintra.c b/av1/common/reconintra.c
index 6f62902..13fe11e 100644
--- a/av1/common/reconintra.c
+++ b/av1/common/reconintra.c
@@ -3045,18 +3045,19 @@
 
 void av1_predict_intra_block_facade(MACROBLOCKD *xd, int plane, int block_idx,
                                     int blk_col, int blk_row, TX_SIZE tx_size) {
+  const MODE_INFO *mi = xd->mi[0];
+  const MB_MODE_INFO *const mbmi = &mi->mbmi;
   struct macroblockd_plane *const pd = &xd->plane[plane];
   const int dst_stride = pd->dst.stride;
   uint8_t *dst =
       &pd->dst.buf[(blk_row * dst_stride + blk_col) << tx_size_wide_log2[0]];
-  const MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
   const int block_raster_idx =
       av1_block_index_to_raster_order(tx_size, block_idx);
-  const PREDICTION_MODE mode =
-      (plane == 0) ? get_y_mode(xd->mi[0], block_raster_idx) : mbmi->uv_mode;
-
+  const PREDICTION_MODE mode = (plane == AOM_PLANE_Y)
+                                   ? get_y_mode(mi, block_raster_idx)
+                                   : get_uv_mode(mbmi->uv_mode);
 #if CONFIG_CFL
-  if (plane != AOM_PLANE_Y && mbmi->uv_mode == DC_PRED) {
+  if (plane != AOM_PLANE_Y && mbmi->uv_mode == UV_DC_PRED) {
     if (plane == AOM_PLANE_U && blk_col == 0 && blk_row == 0) {
       // Avoid computing the CfL parameters twice, if they have already been
       // computed in cfl_rd_pick_alpha.
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index 166bb2a..0149688 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -134,10 +134,10 @@
   return y_mode;
 }
 
-static PREDICTION_MODE read_intra_mode_uv(FRAME_CONTEXT *ec_ctx,
-                                          MACROBLOCKD *xd, aom_reader *r,
-                                          PREDICTION_MODE y_mode) {
-  const PREDICTION_MODE uv_mode =
+static UV_PREDICTION_MODE read_intra_mode_uv(FRAME_CONTEXT *ec_ctx,
+                                             MACROBLOCKD *xd, aom_reader *r,
+                                             PREDICTION_MODE y_mode) {
+  const UV_PREDICTION_MODE uv_mode =
       read_intra_mode(r, ec_ctx->uv_mode_cdf[y_mode]);
 #if CONFIG_ENTROPY_STATS
   FRAME_COUNTS *counts = xd->counts;
@@ -825,7 +825,7 @@
     }
   }
 
-  if (mbmi->uv_mode == DC_PRED) {
+  if (mbmi->uv_mode == UV_DC_PRED) {
     const int palette_uv_mode_ctx = (pmi->palette_size[0] > 0);
     if (aom_read(r, av1_default_palette_uv_mode_prob[palette_uv_mode_ctx],
                  ACCT_STR)) {
@@ -886,7 +886,7 @@
   (void)mi_col;
 #endif  // CONFIG_CB4X4
 
-  if (mbmi->uv_mode == DC_PRED
+  if (mbmi->uv_mode == UV_DC_PRED
 #if CONFIG_PALETTE
       && mbmi->palette_mode_info.palette_size[1] == 0
 #endif  // CONFIG_PALETTE
@@ -939,7 +939,7 @@
 #endif  // CONFIG_INTRA_INTERP
   }
 
-  if (av1_is_directional_mode(mbmi->uv_mode, bsize)) {
+  if (av1_is_directional_mode(get_uv_mode(mbmi->uv_mode), bsize)) {
     mbmi->angle_delta[1] =
         av1_read_uniform(r, 2 * MAX_ANGLE_DELTA + 1) - MAX_ANGLE_DELTA;
   }
@@ -1113,7 +1113,7 @@
     mbmi->use_intrabc = aom_read(r, ec_ctx->intrabc_prob, ACCT_STR);
     if (mbmi->use_intrabc) {
       mbmi->tx_size = read_tx_size(cm, xd, 1, !mbmi->skip, r);
-      mbmi->mode = mbmi->uv_mode = DC_PRED;
+      mbmi->mode = mbmi->uv_mode = UV_DC_PRED;
 #if CONFIG_DUAL_FILTER
       for (int idx = 0; idx < 4; ++idx) mbmi->interp_filter[idx] = BILINEAR;
 #else
@@ -1202,7 +1202,7 @@
 
 #if CONFIG_CFL
     // TODO(ltrudeau) support PALETTE
-    if (mbmi->uv_mode == DC_PRED) {
+    if (mbmi->uv_mode == UV_DC_PRED) {
       mbmi->cfl_alpha_idx = read_cfl_alphas(ec_ctx, r, mbmi->cfl_alpha_signs);
     }
 #endif  // CONFIG_CFL
@@ -1210,7 +1210,7 @@
 #if CONFIG_CB4X4
   } else {
     // Avoid decoding angle_info if there is is no chroma prediction
-    mbmi->uv_mode = DC_PRED;
+    mbmi->uv_mode = UV_DC_PRED;
   }
 #endif
 
@@ -1797,7 +1797,7 @@
 
 #if CONFIG_CFL
     // TODO(ltrudeau) support PALETTE
-    if (mbmi->uv_mode == DC_PRED) {
+    if (mbmi->uv_mode == UV_DC_PRED) {
       mbmi->cfl_alpha_idx =
           read_cfl_alphas(xd->tile_ctx, r, mbmi->cfl_alpha_signs);
     }
diff --git a/av1/decoder/inspection.c b/av1/decoder/inspection.c
index 926c77e..4f98f18 100644
--- a/av1/decoder/inspection.c
+++ b/av1/decoder/inspection.c
@@ -78,7 +78,7 @@
       if (mi->mode < INTRA_MODES) {
         mi->uv_mode = mbmi->uv_mode;
       } else {
-        mi->uv_mode = INTRA_INVALID;
+        mi->uv_mode = UV_MODE_INVALID;
       }
       // Block Size
       mi->sb_type = mbmi->sb_type;
@@ -101,7 +101,7 @@
       mi->cdef_strength += mi->cdef_strength == 3;
 #endif
 #if CONFIG_CFL
-      if (mbmi->uv_mode == DC_PRED) {
+      if (mbmi->uv_mode == UV_DC_PRED) {
         mi->cfl_alpha_idx = mbmi->cfl_alpha_idx;
         mi->cfl_alpha_sign = (mbmi->cfl_alpha_signs[CFL_PRED_V] << CFL_PRED_V) +
                              mbmi->cfl_alpha_signs[CFL_PRED_U];
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 3ab937c..2331307 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -1235,7 +1235,7 @@
   (void)mi_col;
 #endif  // CONFIG_CB4X4
 
-  if (mbmi->uv_mode == DC_PRED
+  if (mbmi->uv_mode == UV_DC_PRED
 #if CONFIG_PALETTE
       && mbmi->palette_mode_info.palette_size[1] == 0
 #endif  // CONFIG_PALETTE
@@ -1277,7 +1277,7 @@
 #endif  // CONFIG_INTRA_INTERP
   }
 
-  if (av1_is_directional_mode(mbmi->uv_mode, bsize)) {
+  if (av1_is_directional_mode(get_uv_mode(mbmi->uv_mode), bsize)) {
     write_uniform(w, 2 * MAX_ANGLE_DELTA + 1,
                   MAX_ANGLE_DELTA + mbmi->angle_delta[1]);
   }
@@ -1492,7 +1492,7 @@
     }
   }
 
-  if (mbmi->uv_mode == DC_PRED) {
+  if (mbmi->uv_mode == UV_DC_PRED) {
     const int n = pmi->palette_size[1];
     const int palette_uv_mode_ctx = (pmi->palette_size[0] > 0);
     aom_write(w, n > 0, av1_default_palette_uv_mode_prob[palette_uv_mode_ctx]);
@@ -1612,10 +1612,10 @@
 }
 
 static void write_intra_uv_mode(FRAME_CONTEXT *frame_ctx,
-                                PREDICTION_MODE uv_mode, PREDICTION_MODE y_mode,
-                                aom_writer *w) {
-  aom_write_symbol(w, av1_intra_mode_ind[uv_mode],
-                   frame_ctx->uv_mode_cdf[y_mode], INTRA_MODES);
+                                UV_PREDICTION_MODE uv_mode,
+                                PREDICTION_MODE y_mode, aom_writer *w) {
+  aom_write_symbol(w, av1_intra_mode_ind[get_uv_mode(uv_mode)],
+                   frame_ctx->uv_mode_cdf[y_mode], UV_INTRA_MODES);
 }
 
 #if CONFIG_CFL
@@ -1782,7 +1782,7 @@
 #endif  // CONFIG_CB4X4
 
 #if CONFIG_CFL
-      if (mbmi->uv_mode == DC_PRED) {
+      if (mbmi->uv_mode == UV_DC_PRED) {
         write_cfl_alphas(ec_ctx, mbmi->cfl_alpha_idx, mbmi->cfl_alpha_signs, w);
       }
 #endif
@@ -2149,7 +2149,7 @@
     aom_write(w, use_intrabc, ec_ctx->intrabc_prob);
     if (use_intrabc) {
       assert(mbmi->mode == DC_PRED);
-      assert(mbmi->uv_mode == DC_PRED);
+      assert(mbmi->uv_mode == UV_DC_PRED);
       if (enable_tx_size && !mbmi->skip) write_selected_tx_size(cm, xd, w);
       int_mv dv_ref = mbmi_ext->ref_mvs[INTRA_FRAME][0];
       av1_encode_dv(w, &mbmi->mv[0].as_mv, &dv_ref.as_mv, &ec_ctx->ndvc);
@@ -2191,7 +2191,7 @@
 #endif  // CONFIG_CB4X4
 
 #if CONFIG_CFL
-    if (mbmi->uv_mode == DC_PRED) {
+    if (mbmi->uv_mode == UV_DC_PRED) {
       write_cfl_alphas(ec_ctx, mbmi->cfl_alpha_idx, mbmi->cfl_alpha_signs, w);
     }
 #endif
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index ae19b69..ab1218a 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -5662,8 +5662,8 @@
   const MB_MODE_INFO *const mbmi = &mi->mbmi;
 #if CONFIG_ENTROPY_STATS
   const PREDICTION_MODE y_mode = mbmi->mode;
-  const PREDICTION_MODE uv_mode = mbmi->uv_mode;
-#else
+  const UV_PREDICTION_MODE uv_mode = mbmi->uv_mode;
+#else   // CONFIG_ENTROPY_STATS
   (void)counts;
   (void)above_mi;
   (void)left_mi;
@@ -5710,7 +5710,7 @@
           mbmi->filter_intra_mode_info.use_filter_intra_mode[0];
       ++counts->filter_intra[0][use_filter_intra_mode];
     }
-    if (mbmi->uv_mode == DC_PRED
+    if (mbmi->uv_mode == UV_DC_PRED
 #if CONFIG_CB4X4
         &&
         is_chroma_reference(mi_row, mi_col, bsize, xd->plane[1].subsampling_x,
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index d69a162..9b98975 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -565,7 +565,7 @@
   int ncobmc_mode_cost[ADAPT_OVERLAP_BLOCKS][MAX_NCOBMC_MODES];
 #endif  // CONFIG_MOTION_VAR && CONFIG_NCOBMC_ADAPT_WEIGHT
 #endif  // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION
-  int intra_uv_mode_cost[INTRA_MODES][INTRA_MODES];
+  int intra_uv_mode_cost[INTRA_MODES][UV_INTRA_MODES];
   int y_mode_costs[INTRA_MODES][INTRA_MODES][INTRA_MODES];
   int switchable_interp_costs[SWITCHABLE_FILTER_CONTEXTS][SWITCHABLE_FILTERS];
 #if CONFIG_EXT_PARTITION_TYPES
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index 063b2f5..17d882c 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -524,6 +524,23 @@
   D135_PRED,     D207_PRED,     D153_PRED, D63_PRED, D117_PRED, D45_PRED,
 };
 
+#if CONFIG_CFL
+static const UV_PREDICTION_MODE uv_rd_search_mode_order[UV_INTRA_MODES] = {
+  UV_DC_PRED,       UV_H_PRED,        UV_V_PRED,
+#if CONFIG_ALT_INTRA
+  UV_SMOOTH_PRED,
+#endif  // CONFIG_ALT_INTRA
+  UV_TM_PRED,
+#if CONFIG_ALT_INTRA && CONFIG_SMOOTH_HV
+  UV_SMOOTH_V_PRED, UV_SMOOTH_H_PRED,
+#endif  // CONFIG_ALT_INTRA && CONFIG_SMOOTH_HV
+  UV_D135_PRED,     UV_D207_PRED,     UV_D153_PRED,
+  UV_D63_PRED,      UV_D117_PRED,     UV_D45_PRED,
+};
+#else
+#define uv_rd_search_mode_order intra_rd_search_mode_order
+#endif  // CONFIG_CFL
+
 #if CONFIG_EXT_INTRA || CONFIG_FILTER_INTRA || CONFIG_PALETTE
 static INLINE int write_uniform_cost(int n, int v) {
   const int l = get_unsigned_bits(n);
@@ -1866,11 +1883,12 @@
 #if CONFIG_DPCM_INTRA
     const int block_raster_idx =
         av1_block_index_to_raster_order(tx_size, block);
-    const PREDICTION_MODE mode =
-        (plane == 0) ? get_y_mode(xd->mi[0], block_raster_idx) : mbmi->uv_mode;
+    const PREDICTION_MODE mode = (plane == AOM_PLANE_Y)
+                                     ? get_y_mode(xd->mi[0], block_raster_idx)
+                                     : get_uv_mode(mbmi->uv_mode);
     TX_TYPE tx_type =
-        av1_get_tx_type((plane == 0) ? PLANE_TYPE_Y : PLANE_TYPE_UV, xd,
-                        blk_row, blk_col, block, tx_size);
+        av1_get_tx_type((plane == AOM_PLANE_Y) ? PLANE_TYPE_Y : PLANE_TYPE_UV,
+                        xd, blk_row, blk_col, block, tx_size);
     if (av1_use_dpcm_intra(plane, mode, tx_type, mbmi)) {
       int8_t skip;
       av1_encode_block_intra_dpcm(cm, x, mode, plane, block, blk_row, blk_col,
@@ -5102,7 +5120,7 @@
                            &plane_block_height, &rows, &cols);
   if (rows * cols > PALETTE_MAX_BLOCK_SIZE) return;
 
-  mbmi->uv_mode = DC_PRED;
+  mbmi->uv_mode = UV_DC_PRED;
 #if CONFIG_FILTER_INTRA
   mbmi->filter_intra_mode_info.use_filter_intra_mode[1] = 0;
 #endif  // CONFIG_FILTER_INTRA
@@ -5286,7 +5304,7 @@
 
   av1_zero(filter_intra_mode_info);
   mbmi->filter_intra_mode_info.use_filter_intra_mode[1] = 1;
-  mbmi->uv_mode = DC_PRED;
+  mbmi->uv_mode = UV_DC_PRED;
 #if CONFIG_PALETTE
   mbmi->palette_mode_info.palette_size[1] = 0;
 #endif  // CONFIG_PALETTE
@@ -5313,7 +5331,7 @@
   }
 
   if (filter_intra_selected_flag) {
-    mbmi->uv_mode = DC_PRED;
+    mbmi->uv_mode = UV_DC_PRED;
     mbmi->filter_intra_mode_info.use_filter_intra_mode[1] =
         filter_intra_mode_info.use_filter_intra_mode[1];
     mbmi->filter_intra_mode_info.filter_intra_mode[1] =
@@ -5576,7 +5594,7 @@
 #endif  // CONFIG_CFL
 
 static void init_sbuv_mode(MB_MODE_INFO *const mbmi) {
-  mbmi->uv_mode = DC_PRED;
+  mbmi->uv_mode = UV_DC_PRED;
 #if CONFIG_PALETTE
   mbmi->palette_mode_info.palette_size[1] = 0;
 #endif  // CONFIG_PALETTE
@@ -5602,10 +5620,10 @@
   PALETTE_MODE_INFO *const pmi = &mbmi->palette_mode_info;
 #endif  // CONFIG_PALETTE
 
-  for (int mode_idx = 0; mode_idx < INTRA_MODES; ++mode_idx) {
+  for (int mode_idx = 0; mode_idx < UV_INTRA_MODES; ++mode_idx) {
     int this_rate;
     RD_STATS tokenonly_rd_stats;
-    PREDICTION_MODE mode = intra_rd_search_mode_order[mode_idx];
+    UV_PREDICTION_MODE mode = uv_rd_search_mode_order[mode_idx];
 #if CONFIG_EXT_INTRA
     const int is_directional_mode =
         av1_is_directional_mode(mode, mbmi->sb_type);
@@ -5617,7 +5635,7 @@
     mbmi->uv_mode = mode;
 #if CONFIG_CFL
     int cfl_alpha_rate = 0;
-    if (mode == DC_PRED) {
+    if (mode == UV_DC_PRED) {
       const TX_SIZE uv_tx_size = av1_get_uv_tx_size(mbmi, &xd->plane[1]);
       cfl_alpha_rate = cfl_rd_pick_alpha(x, uv_tx_size);
     }
@@ -5645,7 +5663,7 @@
         tokenonly_rd_stats.rate + cpi->intra_uv_mode_cost[mbmi->mode][mode];
 
 #if CONFIG_CFL
-    if (mode == DC_PRED) {
+    if (mode == UV_DC_PRED) {
       this_rate += cfl_alpha_rate;
     }
 #endif
@@ -5661,7 +5679,7 @@
 #endif  // CONFIG_FILTER_INTRA
 #if CONFIG_PALETTE
     if (cpi->common.allow_screen_content_tools && mbmi->sb_type >= BLOCK_8X8 &&
-        mode == DC_PRED)
+        mode == UV_DC_PRED)
       this_rate += av1_cost_bit(
           av1_default_palette_uv_mode_prob[pmi->palette_size[0] > 0], 0);
 #endif  // CONFIG_PALETTE
@@ -5685,7 +5703,7 @@
   if (cpi->common.allow_screen_content_tools && mbmi->sb_type >= BLOCK_8X8) {
     uint8_t *best_palette_color_map = x->palette_buffer->best_palette_color_map;
     rd_pick_palette_intra_sbuv(cpi, x,
-                               cpi->intra_uv_mode_cost[mbmi->mode][DC_PRED],
+                               cpi->intra_uv_mode_cost[mbmi->mode][UV_DC_PRED],
                                best_palette_color_map, &best_mbmi, &best_rd,
                                rate, rate_tokenonly, distortion, skippable);
   }
@@ -5709,7 +5727,7 @@
                                  PICK_MODE_CONTEXT *ctx, BLOCK_SIZE bsize,
                                  TX_SIZE max_tx_size, int *rate_uv,
                                  int *rate_uv_tokenonly, int64_t *dist_uv,
-                                 int *skip_uv, PREDICTION_MODE *mode_uv) {
+                                 int *skip_uv, UV_PREDICTION_MODE *mode_uv) {
   // Use an estimated rd for uv_intra based on DC_PRED if the
   // appropriate speed flag is set.
   (void)ctx;
@@ -5724,7 +5742,7 @@
     *rate_uv_tokenonly = 0;
     *dist_uv = 0;
     *skip_uv = 1;
-    *mode_uv = DC_PRED;
+    *mode_uv = UV_DC_PRED;
     return;
   }
   BLOCK_SIZE bs = scale_chroma_bsize(bsize, x->e_mbd.plane[1].subsampling_x,
@@ -9337,7 +9355,7 @@
 #endif
     mbmi->use_intrabc = 1;
     mbmi->mode = DC_PRED;
-    mbmi->uv_mode = DC_PRED;
+    mbmi->uv_mode = UV_DC_PRED;
     mbmi->mv[0].as_mv = dv;
 #if CONFIG_DUAL_FILTER
     for (int idx = 0; idx < 4; ++idx) mbmi->interp_filter[idx] = BILINEAR;
@@ -9629,7 +9647,8 @@
     const AV1_COMP *cpi, MACROBLOCK *x, PICK_MODE_CONTEXT *ctx,
     BLOCK_SIZE bsize, int mi_row, int mi_col, int *rate_uv_intra,
     int *rate_uv_tokenonly, int64_t *dist_uv, int *skip_uv,
-    PREDICTION_MODE *mode_uv, FILTER_INTRA_MODE_INFO *filter_intra_mode_info_uv,
+    UV_PREDICTION_MODE *mode_uv,
+    FILTER_INTRA_MODE_INFO *filter_intra_mode_info_uv,
 #if CONFIG_EXT_INTRA
     int8_t *uv_angle_delta,
 #endif  // CONFIG_EXT_INTRA
@@ -9666,7 +9685,7 @@
   // TODO(huisu): use skip_mask for further speedup.
   (void)skip_mask;
   mbmi->mode = DC_PRED;
-  mbmi->uv_mode = DC_PRED;
+  mbmi->uv_mode = UV_DC_PRED;
   mbmi->ref_frame[0] = INTRA_FRAME;
   mbmi->ref_frame[1] = NONE_FRAME;
   if (!rd_pick_filter_intra_sby(cpi, x, &rate_dummy, &rate_y, &distortion_y,
@@ -9873,7 +9892,7 @@
   int rate_uv_intra[TX_SIZES_ALL], rate_uv_tokenonly[TX_SIZES_ALL];
   int64_t dist_uvs[TX_SIZES_ALL];
   int skip_uvs[TX_SIZES_ALL];
-  PREDICTION_MODE mode_uv[TX_SIZES_ALL];
+  UV_PREDICTION_MODE mode_uv[TX_SIZES_ALL];
 #if CONFIG_PALETTE
   PALETTE_MODE_INFO pmi_uv[TX_SIZES_ALL];
 #endif  // CONFIG_PALETTE
@@ -10436,7 +10455,7 @@
     }
 
     mbmi->mode = this_mode;
-    mbmi->uv_mode = DC_PRED;
+    mbmi->uv_mode = UV_DC_PRED;
     mbmi->ref_frame[0] = ref_frame;
     mbmi->ref_frame[1] = second_ref_frame;
 #if CONFIG_PALETTE
@@ -10618,7 +10637,7 @@
               mbmi->filter_intra_mode_info.filter_intra_mode[0]);
         }
       }
-      if (mbmi->uv_mode == DC_PRED) {
+      if (mbmi->uv_mode == UV_DC_PRED) {
         rate2 +=
             av1_cost_bit(cpi->common.fc->filter_intra_probs[1],
                          mbmi->filter_intra_mode_info.use_filter_intra_mode[1]);
@@ -11413,7 +11432,7 @@
     MB_MODE_INFO best_mbmi_palette = best_mbmode;
 
     mbmi->mode = DC_PRED;
-    mbmi->uv_mode = DC_PRED;
+    mbmi->uv_mode = UV_DC_PRED;
     mbmi->ref_frame[0] = INTRA_FRAME;
     mbmi->ref_frame[1] = NONE_FRAME;
     rate_overhead_palette = rd_pick_palette_intra_sby(
@@ -11849,7 +11868,7 @@
 #endif  // CONFIG_FILTER_INTRA
   mbmi->mode = ZEROMV;
   mbmi->motion_mode = SIMPLE_TRANSLATION;
-  mbmi->uv_mode = DC_PRED;
+  mbmi->uv_mode = UV_DC_PRED;
   mbmi->ref_frame[0] = LAST_FRAME;
   mbmi->ref_frame[1] = NONE_FRAME;
 #if CONFIG_GLOBAL_MOTION
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 1094dfc..eeab33a 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -171,12 +171,24 @@
     sf->recode_loop = ALLOW_RECODE_KFARFGF;
 #if CONFIG_TX64X64
     sf->intra_y_mode_mask[TX_64X64] = INTRA_DC_H_V;
+#if CONFIG_CFL
+    sf->intra_uv_mode_mask[TX_64X64] = UV_INTRA_DC_H_V;
+#else
     sf->intra_uv_mode_mask[TX_64X64] = INTRA_DC_H_V;
+#endif  // CONFIG_CFL
 #endif  // CONFIG_TX64X64
     sf->intra_y_mode_mask[TX_32X32] = INTRA_DC_H_V;
+#if CONFIG_CFL
+    sf->intra_uv_mode_mask[TX_32X32] = UV_INTRA_DC_H_V;
+#else
     sf->intra_uv_mode_mask[TX_32X32] = INTRA_DC_H_V;
+#endif
     sf->intra_y_mode_mask[TX_16X16] = INTRA_DC_H_V;
+#if CONFIG_CFL
+    sf->intra_uv_mode_mask[TX_16X16] = UV_INTRA_DC_H_V;
+#else
     sf->intra_uv_mode_mask[TX_16X16] = INTRA_DC_H_V;
+#endif
 
     sf->tx_size_search_breakout = 1;
     sf->partition_search_breakout_rate_thr = 80;
@@ -227,10 +239,18 @@
     sf->mode_skip_start = 6;
 #if CONFIG_TX64X64
     sf->intra_y_mode_mask[TX_64X64] = INTRA_DC;
+#if CONFIG_CFL
+    sf->intra_uv_mode_mask[TX_64X64] = UV_INTRA_DC;
+#else
     sf->intra_uv_mode_mask[TX_64X64] = INTRA_DC;
+#endif  // CONFIG_CFL
 #endif  // CONFIG_TX64X64
     sf->intra_y_mode_mask[TX_32X32] = INTRA_DC;
+#if CONFIG_CFL
+    sf->intra_uv_mode_mask[TX_32X32] = UV_INTRA_DC;
+#else
     sf->intra_uv_mode_mask[TX_32X32] = INTRA_DC;
+#endif  // CONFIG_CFL
     sf->adaptive_interp_filter_search = 1;
   }
 
@@ -255,7 +275,11 @@
     sf->disable_filter_search_var_thresh = 500;
     for (i = 0; i < TX_SIZES; ++i) {
       sf->intra_y_mode_mask[i] = INTRA_DC;
+#if CONFIG_CFL
+      sf->intra_uv_mode_mask[i] = UV_INTRA_DC;
+#else
       sf->intra_uv_mode_mask[i] = INTRA_DC;
+#endif  // CONFIG_CFL
     }
     sf->partition_search_breakout_rate_thr = 500;
     sf->mv.reduce_first_step_size = 1;
@@ -405,7 +429,11 @@
 
   for (i = 0; i < TX_SIZES; i++) {
     sf->intra_y_mode_mask[i] = INTRA_ALL;
+#if CONFIG_CFL
+    sf->intra_uv_mode_mask[i] = UV_INTRA_ALL;
+#else
     sf->intra_uv_mode_mask[i] = INTRA_ALL;
+#endif  // CONFIG_CFL
   }
   sf->use_rd_breakout = 0;
   sf->lpf_pick = LPF_PICK_FROM_FULL_IMAGE;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index 33ceabf..2c89f4e 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -29,6 +29,24 @@
 #endif  // CONFIG_SMOOTH_HV
 #endif  // CONFIG_ALT_INTRA
               (1 << TM_PRED),
+#if CONFIG_CFL
+  UV_INTRA_ALL = (1 << UV_DC_PRED) | (1 << UV_V_PRED) | (1 << UV_H_PRED) |
+                 (1 << UV_D45_PRED) | (1 << UV_D135_PRED) |
+                 (1 << UV_D117_PRED) | (1 << UV_D153_PRED) |
+                 (1 << UV_D207_PRED) | (1 << UV_D63_PRED) |
+#if CONFIG_ALT_INTRA
+                 (1 << UV_SMOOTH_PRED) |
+#if CONFIG_SMOOTH_HV
+                 (1 << UV_SMOOTH_V_PRED) | (1 << UV_SMOOTH_H_PRED) |
+#endif  // CONFIG_SMOOTH_HV
+#endif  // CONFIG_ALT_INTRA
+                 (1 << UV_TM_PRED),
+  UV_INTRA_DC = (1 << UV_DC_PRED),
+  UV_INTRA_DC_TM = (1 << UV_DC_PRED) | (1 << UV_TM_PRED),
+  UV_INTRA_DC_H_V = (1 << UV_DC_PRED) | (1 << UV_V_PRED) | (1 << UV_H_PRED),
+  UV_INTRA_DC_TM_H_V = (1 << UV_DC_PRED) | (1 << UV_TM_PRED) |
+                       (1 << UV_V_PRED) | (1 << UV_H_PRED),
+#endif  // CONFIG_CFL
   INTRA_DC = (1 << DC_PRED),
   INTRA_DC_TM = (1 << DC_PRED) | (1 << TM_PRED),
   INTRA_DC_H_V = (1 << DC_PRED) | (1 << V_PRED) | (1 << H_PRED),
diff --git a/examples/inspect.c b/examples/inspect.c
index 5ad69c1..e5c2871 100644
--- a/examples/inspect.c
+++ b/examples/inspect.c
@@ -219,6 +219,22 @@
                                           ENUM(INTRA_INVALID),
                                           LAST_ENUM };
 
+#if CONFIG_CFL
+const map_entry uv_prediction_mode_map[] = {
+  ENUM(UV_DC_PRED),       ENUM(UV_V_PRED),        ENUM(UV_H_PRED),
+  ENUM(UV_D45_PRED),      ENUM(UV_D135_PRED),     ENUM(UV_D117_PRED),
+  ENUM(UV_D153_PRED),     ENUM(UV_D207_PRED),     ENUM(UV_D63_PRED),
+#if CONFIG_ALT_INTRA
+  ENUM(UV_SMOOTH_PRED),
+#if CONFIG_SMOOTH_HV
+  ENUM(UV_SMOOTH_V_PRED), ENUM(UV_SMOOTH_H_PRED),
+#endif  // CONFIG_SMOOTH_HV
+#endif  // CONFIG_ALT_INTRA
+  ENUM(UV_TM_PRED),       ENUM(UV_MODE_INVALID),  LAST_ENUM
+};
+#else
+#define uv_prediction_mode_map prediction_mode_map
+#endif
 #define NO_SKIP 0
 #define SKIP 1
 
@@ -505,7 +521,7 @@
                           offsetof(insp_mi_data, mode));
   }
   if (layers & UV_MODE_LAYER) {
-    buf += put_block_info(buf, prediction_mode_map, "uv_mode",
+    buf += put_block_info(buf, uv_prediction_mode_map, "uv_mode",
                           offsetof(insp_mi_data, uv_mode));
   }
   if (layers & SKIP_LAYER) {
diff --git a/tools/aom_entropy_optimizer.c b/tools/aom_entropy_optimizer.c
index e0182d1..65b7d29 100644
--- a/tools/aom_entropy_optimizer.c
+++ b/tools/aom_entropy_optimizer.c
@@ -364,14 +364,15 @@
 
   /* Intra mode (chroma) */
   cts_each_dim[0] = INTRA_MODES;
-  cts_each_dim[1] = INTRA_MODES;
+  cts_each_dim[1] = UV_INTRA_MODES;
   optimize_entropy_table(&fc.uv_mode[0][0], probsfile, 2, cts_each_dim,
                          av1_intra_mode_tree, 0,
                          "static const aom_prob default_uv_probs[INTRA_MODES]"
-                         "[INTRA_MODES - 1]");
-  optimize_cdf_table(&fc.uv_mode[0][0], probsfile, 2, cts_each_dim,
-                     "static const aom_cdf_prob\n"
-                     "default_uv_mode_cdf[INTRA_MODES][CDF_SIZE(INTRA_MODES)]");
+                         "[UV_INTRA_MODES - 1]");
+  optimize_cdf_table(
+      &fc.uv_mode[0][0], probsfile, 2, cts_each_dim,
+      "static const aom_cdf_prob\n"
+      "default_uv_mode_cdf[INTRA_MODES][CDF_SIZE(UV_INTRA_MODES)]");
 
   /* Partition */
   cts_each_dim[0] = PARTITION_CONTEXTS;