[CFL] New UV_PREDICTION_MODE for CFL

CfL is now an independent mode.

Results on Subset1 (Compared to 4266a7ed with CFL enabled)

   PSNR | PSNR Cb | PSNR Cr | PSNR HVS |    SSIM | MS SSIM | CIEDE 2000
-0.1645 | -0.4017 |  0.2475 |  -0.1851 | -0.2179 | -0.2338 |    -0.2897

Change-Id: I2e86e7ea7bfc12bb1d763e70a136ca992d57a3c5
diff --git a/av1/common/blockd.h b/av1/common/blockd.h
index 0b428cd..b565d5f 100644
--- a/av1/common/blockd.h
+++ b/av1/common/blockd.h
@@ -518,6 +518,7 @@
 #endif              // CONFIG_SMOOTH_HV
 #endif              // CONFIG_ALT_INTRA
     TM_PRED,        // UV_TM_PRED
+    DC_PRED,        // CFL_PRED
   };
   return uv2y[mode];
 }
diff --git a/av1/common/cfl.h b/av1/common/cfl.h
index f2df4b2..7e031fc 100644
--- a/av1/common/cfl.h
+++ b/av1/common/cfl.h
@@ -69,9 +69,9 @@
 
 static const int cfl_alpha_codes[CFL_ALPHABET_SIZE][CFL_PRED_PLANES] = {
   // barrbrain's simple 1D quant ordered by subset 3 likelihood
-  { 0, 0 }, { 1, 1 }, { 3, 0 }, { 3, 3 }, { 1, 0 }, { 3, 1 },
-  { 5, 5 }, { 0, 1 }, { 5, 3 }, { 5, 0 }, { 3, 5 }, { 1, 3 },
-  { 0, 3 }, { 5, 1 }, { 1, 5 }, { 0, 5 }
+  { 1, 1 }, { 3, 0 }, { 3, 3 }, { 1, 0 }, { 3, 1 },
+  { 5, 5 }, { 0, 1 }, { 5, 3 }, { 5, 0 }, { 3, 5 },
+  { 1, 3 }, { 0, 3 }, { 5, 1 }, { 1, 5 }, { 0, 5 }
 };
 
 static INLINE int get_scaled_luma_q0(int alpha_q3, int y_pix, int avg_q3) {
diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c
index 9faa03e..0a5e13d 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -2613,6 +2613,63 @@
         AOM_ICDF(32768), 0 },
     };
 
+#if CONFIG_CFL
+static const aom_cdf_prob
+    default_uv_mode_cdf[INTRA_MODES][CDF_SIZE(UV_INTRA_MODES)] = {
+      { AOM_ICDF(18377), AOM_ICDF(18815), AOM_ICDF(19743), AOM_ICDF(20178),
+        AOM_ICDF(20560), AOM_ICDF(20889), AOM_ICDF(21359), AOM_ICDF(22098),
+        AOM_ICDF(22481), AOM_ICDF(24563), AOM_ICDF(25781), AOM_ICDF(26662),
+        AOM_ICDF(28396), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(5350), AOM_ICDF(16837), AOM_ICDF(17066), AOM_ICDF(17360),
+        AOM_ICDF(17692), AOM_ICDF(18778), AOM_ICDF(18969), AOM_ICDF(19206),
+        AOM_ICDF(20291), AOM_ICDF(22367), AOM_ICDF(23212), AOM_ICDF(24670),
+        AOM_ICDF(27912), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(6671), AOM_ICDF(6759), AOM_ICDF(17812), AOM_ICDF(17998),
+        AOM_ICDF(18260), AOM_ICDF(18384), AOM_ICDF(19408), AOM_ICDF(20667),
+        AOM_ICDF(20806), AOM_ICDF(22760), AOM_ICDF(24142), AOM_ICDF(24875),
+        AOM_ICDF(28072), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(7461), AOM_ICDF(8082), AOM_ICDF(8515), AOM_ICDF(15013),
+        AOM_ICDF(15583), AOM_ICDF(16098), AOM_ICDF(16522), AOM_ICDF(18519),
+        AOM_ICDF(20348), AOM_ICDF(22954), AOM_ICDF(24130), AOM_ICDF(25342),
+        AOM_ICDF(26548), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(3694), AOM_ICDF(4403), AOM_ICDF(5370), AOM_ICDF(5854),
+        AOM_ICDF(17841), AOM_ICDF(19639), AOM_ICDF(21625), AOM_ICDF(22224),
+        AOM_ICDF(22651), AOM_ICDF(24613), AOM_ICDF(25399), AOM_ICDF(26143),
+        AOM_ICDF(26599), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(3700), AOM_ICDF(5651), AOM_ICDF(6112), AOM_ICDF(6541),
+        AOM_ICDF(8929), AOM_ICDF(20623), AOM_ICDF(21213), AOM_ICDF(21640),
+        AOM_ICDF(22214), AOM_ICDF(24306), AOM_ICDF(25412), AOM_ICDF(26406),
+        AOM_ICDF(27249), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(4649), AOM_ICDF(4947), AOM_ICDF(7128), AOM_ICDF(7432),
+        AOM_ICDF(9439), AOM_ICDF(9903), AOM_ICDF(21163), AOM_ICDF(21774),
+        AOM_ICDF(22056), AOM_ICDF(24426), AOM_ICDF(25403), AOM_ICDF(26324),
+        AOM_ICDF(27128), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(7208), AOM_ICDF(7375), AOM_ICDF(8779), AOM_ICDF(9683),
+        AOM_ICDF(10072), AOM_ICDF(10284), AOM_ICDF(10796), AOM_ICDF(19786),
+        AOM_ICDF(20152), AOM_ICDF(22955), AOM_ICDF(24246), AOM_ICDF(25165),
+        AOM_ICDF(26589), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(5897), AOM_ICDF(7283), AOM_ICDF(7555), AOM_ICDF(8910),
+        AOM_ICDF(9391), AOM_ICDF(9937), AOM_ICDF(10276), AOM_ICDF(11044),
+        AOM_ICDF(19841), AOM_ICDF(22620), AOM_ICDF(23784), AOM_ICDF(25060),
+        AOM_ICDF(26418), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(12171), AOM_ICDF(12718), AOM_ICDF(13885), AOM_ICDF(14348),
+        AOM_ICDF(14925), AOM_ICDF(15394), AOM_ICDF(16108), AOM_ICDF(17075),
+        AOM_ICDF(17583), AOM_ICDF(21996), AOM_ICDF(23614), AOM_ICDF(25048),
+        AOM_ICDF(27011), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(10192), AOM_ICDF(11222), AOM_ICDF(12318), AOM_ICDF(12877),
+        AOM_ICDF(13533), AOM_ICDF(14184), AOM_ICDF(14866), AOM_ICDF(15879),
+        AOM_ICDF(16650), AOM_ICDF(20419), AOM_ICDF(23265), AOM_ICDF(24295),
+        AOM_ICDF(26596), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(10776), AOM_ICDF(11387), AOM_ICDF(12899), AOM_ICDF(13471),
+        AOM_ICDF(14088), AOM_ICDF(14575), AOM_ICDF(15366), AOM_ICDF(16456),
+        AOM_ICDF(17040), AOM_ICDF(20815), AOM_ICDF(22009), AOM_ICDF(24448),
+        AOM_ICDF(26492), AOM_ICDF(32768), 0 },
+      { AOM_ICDF(4015), AOM_ICDF(6473), AOM_ICDF(9853), AOM_ICDF(10285),
+        AOM_ICDF(10655), AOM_ICDF(11032), AOM_ICDF(11431), AOM_ICDF(12199),
+        AOM_ICDF(12738), AOM_ICDF(14760), AOM_ICDF(16121), AOM_ICDF(17263),
+        AOM_ICDF(28612), AOM_ICDF(32768), 0 },
+    };
+#else
 static const aom_cdf_prob
     default_uv_mode_cdf[INTRA_MODES][CDF_SIZE(UV_INTRA_MODES)] = {
       { AOM_ICDF(23552), AOM_ICDF(23660), AOM_ICDF(26044), AOM_ICDF(28731),
@@ -2668,6 +2725,7 @@
         AOM_ICDF(29907), AOM_ICDF(30600), AOM_ICDF(31515), AOM_ICDF(32049),
         AOM_ICDF(32768), 0 },
     };
+#endif  // CONFIG_CFL
 #else   // !CONFIG_SMOOTH_HV
 static const aom_cdf_prob
     default_if_y_mode_cdf[BLOCK_SIZE_GROUPS][CDF_SIZE(INTRA_MODES)] = {
@@ -3499,10 +3557,10 @@
 
 #if CONFIG_CFL
 static const aom_cdf_prob default_cfl_alpha_cdf[CDF_SIZE(CFL_ALPHABET_SIZE)] = {
-  AOM_ICDF(20492), AOM_ICDF(24094), AOM_ICDF(25679), AOM_ICDF(27242),
-  AOM_ICDF(28286), AOM_ICDF(29153), AOM_ICDF(29807), AOM_ICDF(30352),
-  AOM_ICDF(30866), AOM_ICDF(31295), AOM_ICDF(31703), AOM_ICDF(32046),
-  AOM_ICDF(32317), AOM_ICDF(32534), AOM_ICDF(32663), AOM_ICDF(32768)
+  AOM_ICDF(4646),  AOM_ICDF(8045),  AOM_ICDF(11243), AOM_ICDF(17092),
+  AOM_ICDF(22690), AOM_ICDF(24193), AOM_ICDF(26118), AOM_ICDF(27310),
+  AOM_ICDF(28206), AOM_ICDF(29118), AOM_ICDF(30997), AOM_ICDF(31439),
+  AOM_ICDF(32189), AOM_ICDF(32601), AOM_ICDF(32768), 0
 };
 #endif
 
diff --git a/av1/common/enums.h b/av1/common/enums.h
index 2b18d32..14b0309 100644
--- a/av1/common/enums.h
+++ b/av1/common/enums.h
@@ -334,10 +334,7 @@
 typedef enum { PLANE_TYPE_Y = 0, PLANE_TYPE_UV = 1, PLANE_TYPES } PLANE_TYPE;
 
 #if CONFIG_CFL
-// TODO(ltrudeau) this should change based on QP size
-#define CB_ALPHABET_SIZE 4
-#define CR_ALPHABET_SIZE 4
-#define CFL_ALPHABET_SIZE (CB_ALPHABET_SIZE * CR_ALPHABET_SIZE)
+#define CFL_ALPHABET_SIZE 15
 #define CFL_MAGS_SIZE 7
 
 typedef enum { CFL_PRED_U = 0, CFL_PRED_V = 1, CFL_PRED_PLANES } CFL_PRED_TYPE;
@@ -438,6 +435,7 @@
 #endif               // CONFIG_SMOOTH_HV
 #endif               // CONFIG_ALT_INTRA
   UV_TM_PRED,        // True-motion
+  UV_CFL_PRED,       // Chroma-from-Luma
   UV_INTRA_MODES,
   UV_MODE_INVALID,  // For uv_mode in inter blocks
 } UV_PREDICTION_MODE;
diff --git a/av1/common/reconintra.c b/av1/common/reconintra.c
index 13fe11e..5de444d 100644
--- a/av1/common/reconintra.c
+++ b/av1/common/reconintra.c
@@ -2912,16 +2912,8 @@
 
   // predict
   if (mode == DC_PRED) {
-#if CONFIG_CFL
-    // CFL predict its own DC_PRED for Chromatic planes
-    if (plane == AOM_PLANE_Y) {
-#endif
-      dc_pred[n_left_px > 0][n_top_px > 0][tx_size](dst, dst_stride, above_row,
-                                                    left_col);
-#if CONFIG_CFL
-    }
-#endif
-
+    dc_pred[n_left_px > 0][n_top_px > 0][tx_size](dst, dst_stride, above_row,
+                                                  left_col);
   } else {
     pred[mode][tx_size](dst, dst_stride, above_row, left_col);
   }
@@ -3057,7 +3049,7 @@
                                    ? get_y_mode(mi, block_raster_idx)
                                    : get_uv_mode(mbmi->uv_mode);
 #if CONFIG_CFL
-  if (plane != AOM_PLANE_Y && mbmi->uv_mode == UV_DC_PRED) {
+  if (plane != AOM_PLANE_Y && mbmi->uv_mode == UV_CFL_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 7c85442..ceb54e2 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -138,7 +138,12 @@
                                              MACROBLOCKD *xd, aom_reader *r,
                                              PREDICTION_MODE y_mode) {
   const UV_PREDICTION_MODE uv_mode =
+#if CONFIG_CFL
+      aom_read_symbol(r, ec_ctx->uv_mode_cdf[y_mode], UV_INTRA_MODES, ACCT_STR);
+#else
       read_intra_mode(r, ec_ctx->uv_mode_cdf[y_mode]);
+#endif  // CONFIG_CFL
+
 #if CONFIG_ENTROPY_STATS
   FRAME_COUNTS *counts = xd->counts;
   if (counts) ++counts->uv_mode[y_mode][uv_mode];
@@ -1208,7 +1213,7 @@
 
 #if CONFIG_CFL
     // TODO(ltrudeau) support PALETTE
-    if (mbmi->uv_mode == UV_DC_PRED) {
+    if (mbmi->uv_mode == UV_CFL_PRED) {
       mbmi->cfl_alpha_idx = read_cfl_alphas(ec_ctx, r, mbmi->cfl_alpha_signs);
     }
 #endif  // CONFIG_CFL
@@ -1802,8 +1807,7 @@
 #endif
 
 #if CONFIG_CFL
-    // TODO(ltrudeau) support PALETTE
-    if (mbmi->uv_mode == UV_DC_PRED) {
+    if (mbmi->uv_mode == UV_CFL_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 4f98f18..c243e06 100644
--- a/av1/decoder/inspection.c
+++ b/av1/decoder/inspection.c
@@ -101,7 +101,7 @@
       mi->cdef_strength += mi->cdef_strength == 3;
 #endif
 #if CONFIG_CFL
-      if (mbmi->uv_mode == UV_DC_PRED) {
+      if (mbmi->uv_mode == UV_CFL_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 2e0abc1..43b2521 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -1635,8 +1635,10 @@
 static void write_intra_uv_mode(FRAME_CONTEXT *frame_ctx,
                                 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
+  uv_mode = av1_intra_mode_ind[get_uv_mode(uv_mode)];
+#endif
+  aom_write_symbol(w, uv_mode, frame_ctx->uv_mode_cdf[y_mode], UV_INTRA_MODES);
 }
 
 #if CONFIG_CFL
@@ -1812,7 +1814,7 @@
 #endif  // CONFIG_CB4X4
 
 #if CONFIG_CFL
-      if (mbmi->uv_mode == UV_DC_PRED) {
+      if (mbmi->uv_mode == UV_CFL_PRED) {
         write_cfl_alphas(ec_ctx, mbmi->cfl_alpha_idx, mbmi->cfl_alpha_signs, w);
       }
 #endif
@@ -2221,7 +2223,7 @@
 #endif  // CONFIG_CB4X4
 
 #if CONFIG_CFL
-    if (mbmi->uv_mode == UV_DC_PRED) {
+    if (mbmi->uv_mode == UV_CFL_PRED) {
       write_cfl_alphas(ec_ctx, mbmi->cfl_alpha_idx, mbmi->cfl_alpha_signs, w);
     }
 #endif
diff --git a/av1/encoder/rd.c b/av1/encoder/rd.c
index da3b6e2..4c59d9d 100644
--- a/av1/encoder/rd.c
+++ b/av1/encoder/rd.c
@@ -73,10 +73,16 @@
   for (i = 0; i < BLOCK_SIZE_GROUPS; ++i)
     av1_cost_tokens_from_cdf(cpi->mbmode_cost[i], fc->y_mode_cdf[i],
                              av1_intra_mode_inv);
-
+  const int *uv_mode_inv_map =
+#if CONFIG_CFL
+      // CfL codes the uv_mode without reordering it
+      NULL;
+#else
+      av1_intra_mode_inv;
+#endif
   for (i = 0; i < INTRA_MODES; ++i)
     av1_cost_tokens_from_cdf(cpi->intra_uv_mode_cost[i], fc->uv_mode_cdf[i],
-                             av1_intra_mode_inv);
+                             uv_mode_inv_map);
 
   for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; ++i)
     av1_cost_tokens(cpi->switchable_interp_costs[i],
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index 44bdd95..00d3c0e 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -526,7 +526,7 @@
 
 #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,
+  UV_DC_PRED,       UV_CFL_PRED,      UV_H_PRED,    UV_V_PRED,
 #if CONFIG_ALT_INTRA
   UV_SMOOTH_PRED,
 #endif  // CONFIG_ALT_INTRA
@@ -534,8 +534,8 @@
 #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,
+  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
@@ -5732,16 +5732,12 @@
   int64_t best_cost;
 
   // Compute least squares parameter of the entire block
-  // IMPORTANT: We assume that the first code is 0,0
   int ind = 0;
   signs[CFL_PRED_U] = CFL_SIGN_POS;
   signs[CFL_PRED_V] = CFL_SIGN_POS;
+  best_cost = INT64_MAX;
 
-  dist = sse[CFL_PRED_U][0] + sse[CFL_PRED_V][0];
-  dist *= 16;
-  best_cost = RDCOST(x->rdmult, cfl->costs[0], dist);
-
-  for (int c = 1; c < CFL_ALPHABET_SIZE; c++) {
+  for (int c = 0; c < CFL_ALPHABET_SIZE; c++) {
     const int idx_u = cfl_alpha_codes[c][CFL_PRED_U];
     const int idx_v = cfl_alpha_codes[c][CFL_PRED_V];
     for (CFL_SIGN_TYPE sign_u = idx_u == 0; sign_u < CFL_SIGNS; sign_u++) {
@@ -5798,7 +5794,7 @@
     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);
+        av1_is_directional_mode(get_uv_mode(mode), mbmi->sb_type);
 #endif  // CONFIG_EXT_INTRA
     if (!(cpi->sf.intra_uv_mode_mask[txsize_sqr_up_map[max_tx_size]] &
           (1 << mode)))
@@ -5807,7 +5803,8 @@
     mbmi->uv_mode = mode;
 #if CONFIG_CFL
     int cfl_alpha_rate = 0;
-    if (mode == UV_DC_PRED) {
+    if (mode == UV_CFL_PRED) {
+      assert(!is_directional_mode);
       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);
     }
@@ -5835,7 +5832,7 @@
         tokenonly_rd_stats.rate + cpi->intra_uv_mode_cost[mbmi->mode][mode];
 
 #if CONFIG_CFL
-    if (mode == UV_DC_PRED) {
+    if (mode == UV_CFL_PRED) {
       this_rate += cfl_alpha_rate;
     }
 #endif
@@ -9642,14 +9639,14 @@
     x->cfl_store_y = !x->skip_chroma_rd;
 #else
     x->cfl_store_y = 1;
-#endif
+#endif  // CONFIG_CB4X4
 
     txfm_rd_in_plane(x, cpi, &this_rd_stats, INT64_MAX, AOM_PLANE_Y,
                      mbmi->sb_type, mbmi->tx_size,
                      cpi->sf.use_fast_coef_costing);
 
     x->cfl_store_y = 0;
-#endif
+#endif  // CONFIG_CFL
     max_uv_tx_size = uv_txsize_lookup[bsize][mbmi->tx_size][pd[1].subsampling_x]
                                      [pd[1].subsampling_y];
     init_sbuv_mode(mbmi);
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index eeab33a..bf82b19 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -172,20 +172,20 @@
 #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;
+    sf->intra_uv_mode_mask[TX_64X64] = UV_INTRA_DC_H_V_CFL;
 #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;
+    sf->intra_uv_mode_mask[TX_32X32] = UV_INTRA_DC_H_V_CFL;
 #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;
+    sf->intra_uv_mode_mask[TX_16X16] = UV_INTRA_DC_H_V_CFL;
 #else
     sf->intra_uv_mode_mask[TX_16X16] = INTRA_DC_H_V;
 #endif
@@ -240,14 +240,14 @@
 #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;
+    sf->intra_uv_mode_mask[TX_64X64] = UV_INTRA_DC_CFL;
 #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;
+    sf->intra_uv_mode_mask[TX_32X32] = UV_INTRA_DC_CFL;
 #else
     sf->intra_uv_mode_mask[TX_32X32] = INTRA_DC;
 #endif  // CONFIG_CFL
@@ -276,7 +276,7 @@
     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;
+      sf->intra_uv_mode_mask[i] = UV_INTRA_DC_CFL;
 #else
       sf->intra_uv_mode_mask[i] = INTRA_DC;
 #endif  // CONFIG_CFL
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index 2c89f4e..ecfc310 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -40,12 +40,20 @@
                  (1 << UV_SMOOTH_V_PRED) | (1 << UV_SMOOTH_H_PRED) |
 #endif  // CONFIG_SMOOTH_HV
 #endif  // CONFIG_ALT_INTRA
-                 (1 << UV_TM_PRED),
+                 (1 << UV_TM_PRED) | (1 << UV_CFL_PRED),
   UV_INTRA_DC = (1 << UV_DC_PRED),
+  UV_INTRA_DC_CFL = (1 << UV_DC_PRED) | (1 << UV_CFL_PRED),
   UV_INTRA_DC_TM = (1 << UV_DC_PRED) | (1 << UV_TM_PRED),
+  UV_INTRA_DC_TM_CFL =
+      (1 << UV_DC_PRED) | (1 << UV_TM_PRED) | (1 << UV_CFL_PRED),
   UV_INTRA_DC_H_V = (1 << UV_DC_PRED) | (1 << UV_V_PRED) | (1 << UV_H_PRED),
+  UV_INTRA_DC_H_V_CFL = (1 << UV_DC_PRED) | (1 << UV_V_PRED) |
+                        (1 << UV_H_PRED) | (1 << UV_CFL_PRED),
   UV_INTRA_DC_TM_H_V = (1 << UV_DC_PRED) | (1 << UV_TM_PRED) |
                        (1 << UV_V_PRED) | (1 << UV_H_PRED),
+  UV_INTRA_DC_TM_H_V_CFL = (1 << UV_DC_PRED) | (1 << UV_TM_PRED) |
+                           (1 << UV_V_PRED) | (1 << UV_H_PRED) |
+                           (1 << UV_CFL_PRED),
 #endif  // CONFIG_CFL
   INTRA_DC = (1 << DC_PRED),
   INTRA_DC_TM = (1 << DC_PRED) | (1 << TM_PRED),
diff --git a/configure b/configure
index a884014..a739934 100755
--- a/configure
+++ b/configure
@@ -557,6 +557,7 @@
     enabled ext_comp_refs && disable_feature one_sided_compound
     enabled altref2 && enable_feature ext_refs
     enabled rect_tx_ext && enable_feature rect_tx
+    enabled cfl && enable_feature smooth_hv
 
     if ! enabled delta_q && enabled ext_delta_q; then
       log_echo "ext_delta_q requires delta_q, so disabling ext_delta_q"
diff --git a/examples/inspect.c b/examples/inspect.c
index e5c2871..1056af2 100644
--- a/examples/inspect.c
+++ b/examples/inspect.c
@@ -221,16 +221,22 @@
 
 #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),
+  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
+  ENUM(UV_TM_PRED),
+#if CONFIG_CFL
+  ENUM(UV_CFL_PRED),
+#endif
+  ENUM(UV_MODE_INVALID),  LAST_ENUM
 };
 #else
 #define uv_prediction_mode_map prediction_mode_map