Merge "sdm: Avoid looping over event data list when registering events"
diff --git a/config/msmnile.mk b/config/msmnile.mk
old mode 100755
new mode 100644
index 840e8cf..e97dc73
--- a/config/msmnile.mk
+++ b/config/msmnile.mk
@@ -29,10 +29,11 @@
 TARGET_USES_DRM_PP := true
 TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS := true
 MAX_VIRTUAL_DISPLAY_DIMENSION := 4096
-NUM_FRAMEBUFFER_SURFACE_BUFFERS := 2
+NUM_FRAMEBUFFER_SURFACE_BUFFERS := 3
 TARGET_USES_HWC2 := true
 TARGET_USES_QCOM_DISPLAY_BSP := true
 TARGET_USES_COLOR_METADATA := true
+TARGET_HAS_WIDE_COLOR_DISPLAY := true
 
 PRODUCT_PROPERTY_OVERRIDES += \
     persist.demo.hdmirotationlock=false \
@@ -46,8 +47,17 @@
     vendor.gralloc.disable_ubwc=0 \
     vendor.display.disable_scaler=0 \
     vendor.display.disable_inline_rotator=1 \
+    vendor.display.disable_decimation=1 \
     vendor.display.enable_null_display=0 \
     vendor.display.disable_excl_rect=0 \
     vendor.display.comp_mask=0 \
-    vendor.display.disable_hw_recovery=1 \
+    vendor.display.disable_hw_recovery=0 \
     vendor.display.enable_default_color_mode=1
+    vendor.display.disable_hw_recovery=1
+
+# This matrix should be in column major order, per SurfaceFlinger requirement
+#  1.16868   -0.16868    0.00000
+# -0.03155    1.03155    0.00000
+# -0.01473   -0.05899    1.07372
+PRODUCT_PROPERTY_OVERRIDES += \
+    vendor.display.dataspace_saturation_matrix=1.16868,-0.03155,-0.01473,-0.16868,1.03155,-0.05899,0.00000,0.00000,1.07372
diff --git a/include/display_properties.h b/include/display_properties.h
index ef440cd..c321b98 100644
--- a/include/display_properties.h
+++ b/include/display_properties.h
@@ -99,6 +99,7 @@
 #define DISABLE_HDR_LUT_GEN                  DISPLAY_PROP("disable_hdr_lut_gen")
 #define ENABLE_DEFAULT_COLOR_MODE            DISPLAY_PROP("enable_default_color_mode")
 #define DISABLE_HDR                          DISPLAY_PROP("hwc_disable_hdr")
+#define DATASPACE_SATURATION_MATRIX_PROP     DISPLAY_PROP("dataspace_saturation_matrix")
 
 #define HDR_CONFIG_PROP                      RO_DISPLAY_PROP("hdr.config")
 #define QDCM_PCC_TRANS_PROP                  DISPLAY_PROP("qdcm.pcc_for_trans")
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index bbbaf3a..d392e12 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -78,6 +78,7 @@
         SET_COLOR_MODE_BY_ID = 36, // Overrides the QDCM mode using the given mode ID
         GET_COMPOSER_STATUS = 37, // Get composer init status-true if primary display init is done
         SET_QSYNC_MODE = 38, // Set qsync mode. 0 - (none)disable qsync, 1 - continuous mode.
+        SET_COLOR_MODE_WITH_RENDER_INTENT = 39,
         COMMAND_LIST_END = 400,
     };
 
diff --git a/sdm/include/private/color_params.h b/sdm/include/private/color_params.h
index dbe7a97..32f0505 100644
--- a/sdm/include/private/color_params.h
+++ b/sdm/include/private/color_params.h
@@ -84,6 +84,7 @@
 static const std::string kDynamicRangeAttribute = "DynamicRange";
 static const std::string kColorGamutAttribute = "ColorGamut";
 static const std::string kPictureQualityAttribute = "PictureQuality";
+static const std::string kGammaTransferAttribute = "GammaTransfer";
 
 static const std::string kHdr = "hdr";
 static const std::string kSdr = "sdr";
@@ -92,12 +93,18 @@
 static const std::string kDcip3 = "dcip3";
 static const std::string kSrgb = "srgb";
 static const std::string kDisplayP3 = "display_p3";
+static const std::string kBt2020 = "bt2020";
+
+static const std::string kHlg = "hlg";
+static const std::string kSt2084 = "st2084";
+static const std::string kGamma2_2 = "gamma2_2";
 
 static const std::string kVivid = "vivid";
 static const std::string kSharp = "sharp";
 static const std::string kStandard = "standard";
 static const std::string kAmazon = "amazon";
 static const std::string kNetflix = "netflix";
+static const std::string kEnhanced = "enhanced";
 
 // Enum to identify type of dynamic range of color mode.
 enum DynamicRangeType {
diff --git a/sdm/include/private/strategy_interface.h b/sdm/include/private/strategy_interface.h
index 8b5455a..3f1b9ab 100644
--- a/sdm/include/private/strategy_interface.h
+++ b/sdm/include/private/strategy_interface.h
@@ -56,6 +56,7 @@
   virtual DisplayError SetIdleTimeoutMs(uint32_t active_ms) = 0;
   /* Sets the list of color modes supported on a display */
   virtual DisplayError SetColorModesInfo(const std::vector<PrimariesTransfer> &colormodes_cs) = 0;
+  virtual DisplayError SetBlendSpace(const PrimariesTransfer &blend_space) = 0;
 
   virtual ~StrategyInterface() { }
 };
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
index 05c6ba4..838de0c 100644
--- a/sdm/libs/core/comp_manager.cpp
+++ b/sdm/libs/core/comp_manager.cpp
@@ -587,4 +587,13 @@
   return displays_str.c_str();
 }
 
+DisplayError CompManager::SetBlendSpace(Handle display_ctx, const PrimariesTransfer &blend_space) {
+  DisplayCompositionContext *display_comp_ctx =
+      reinterpret_cast<DisplayCompositionContext *>(display_ctx);
+
+  display_comp_ctx->strategy->SetBlendSpace(blend_space);
+
+  return kErrorNone;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/comp_manager.h b/sdm/libs/core/comp_manager.h
index 2a24dc1..5814a67 100644
--- a/sdm/libs/core/comp_manager.h
+++ b/sdm/libs/core/comp_manager.h
@@ -80,6 +80,7 @@
   DisplayError ControlDpps(bool enable);
   DisplayError SetColorModesInfo(Handle display_ctx,
                                  const std::vector<PrimariesTransfer> &colormodes_cs);
+  DisplayError SetBlendSpace(Handle display_ctx, const PrimariesTransfer &blend_space);
 
  private:
   static const int kMaxThermalLevel = 3;
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index cc6c215..5a7a838 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -91,6 +91,11 @@
   DisplayError error = kErrorNone;
   hw_panel_info_ = HWPanelInfo();
   hw_intf_->GetHWPanelInfo(&hw_panel_info_);
+  if (hw_info_intf_) {
+    hw_info_intf_->GetHWResourceInfo(&hw_resource_info_);
+  }
+  auto max_mixer_stages = hw_resource_info_.num_blending_stages;
+  int property_value = Debug::GetMaxPipesPerMixer(display_type_);
 
   uint32_t active_index = 0;
   hw_intf_->GetActiveConfig(&active_index);
@@ -148,15 +153,10 @@
     }
   }
 
-  if (hw_info_intf_) {
-    hw_info_intf_->GetHWResourceInfo(&hw_resource_info_);
-    auto max_mixer_stages = hw_resource_info_.num_blending_stages;
-    int property_value = Debug::GetMaxPipesPerMixer(display_type_);
-    if (property_value >= 0) {
-      max_mixer_stages = std::min(UINT32(property_value), hw_resource_info_.num_blending_stages);
-    }
-    DisplayBase::SetMaxMixerStages(max_mixer_stages);
+  if (property_value >= 0) {
+    max_mixer_stages = std::min(UINT32(property_value), hw_resource_info_.num_blending_stages);
   }
+  DisplayBase::SetMaxMixerStages(max_mixer_stages);
 
   Debug::GetProperty(DISABLE_HDR_LUT_GEN, &disable_hdr_lut_gen_);
   // TODO(user): Temporary changes, to be removed when DRM driver supports
@@ -289,12 +289,6 @@
     return error;
   }
 
-  error = HandleHDR(layer_stack);
-  if (error != kErrorNone) {
-    DLOGW("HandleHDR failed");
-    return error;
-  }
-
   if (color_mgr_ && color_mgr_->NeedsPartialUpdateDisable()) {
     DisablePartialUpdateOneFrame();
   }
@@ -327,16 +321,7 @@
 
   comp_manager_->PostPrepare(display_comp_ctx_, &hw_layers_);
 
-  if (error != kErrorNone) {
-    return error;
-  }
-
-  error = ValidateHDR(layer_stack);
-  if (error != kErrorNone) {
-    DLOGW("ValidateHDR failed");
-  }
-
-  DLOGI_IF(kTagDisplay, "Exiting Prepare for display: %d-%d", display_id_, display_type_);
+  DLOGI_IF(kTagDisplay, "Exiting Prepare for display type : %d error: %d", display_type_, error);
   return error;
 }
 
@@ -841,11 +826,11 @@
   if (!color_mgr_) {
     return kErrorNotSupported;
   }
-
-  for (uint32_t i = 0; i < num_color_modes_; i++) {
-    DLOGV_IF(kTagQDCM, "Color Mode[%d]: Name = %s mode_id = %d", i, color_modes_[i].name,
-             color_modes_[i].id);
-    color_modes->at(i) = color_modes_[i].name;
+  uint32_t i = 0;
+  for (ColorModeAttrMap::iterator it = color_mode_attr_map_.begin();
+       ((i < num_color_modes_) && (it != color_mode_attr_map_.end())); i++, it++) {
+    DLOGI("ColorMode name = %s", it->first.c_str());
+    color_modes->at(i) = it->first.c_str();
   }
 
   return kErrorNone;
@@ -877,59 +862,26 @@
     return kErrorNotSupported;
   }
 
-  DynamicRangeType dynamic_range_type;
-  if (IsSupportColorModeAttribute(color_mode)) {
-    auto it_mode = color_mode_attr_map_.find(color_mode);
-    std::string dynamic_range;
-    GetValueOfModeAttribute(it_mode->second, kDynamicRangeAttribute, &dynamic_range);
-    if (dynamic_range == kHdr) {
-      dynamic_range_type = kHdrType;
-    } else {
-      dynamic_range_type = kSdrType;
-    }
-  } else {
-    if (color_mode.find("hal_hdr") != std::string::npos) {
-      dynamic_range_type = kHdrType;
-    } else {
-      dynamic_range_type = kSdrType;
-    }
-  }
-
   DisplayError error = kErrorNone;
-  if (disable_hdr_lut_gen_) {
-    error = SetColorModeInternal(color_mode);
-    if (error != kErrorNone) {
-      return error;
-    }
-    // Store the new SDR color mode request by client
-    if (dynamic_range_type == kSdrType) {
-      current_color_mode_ = color_mode;
-    }
+  error = SetColorModeInternal(color_mode);
+  if (error != kErrorNone) {
     return error;
   }
 
-  if (hdr_playback_) {
-    // HDR playback on, If incoming mode is SDR mode,
-    // cache the mode and apply it after HDR playback stop.
-    if (dynamic_range_type == kHdrType) {
-      error = SetColorModeInternal(color_mode);
-      if (error != kErrorNone) {
-        return error;
-      }
-    } else if (dynamic_range_type == kSdrType) {
-      current_color_mode_ = color_mode;
-    }
-  } else {
-    // HDR playback off, do not apply HDR mode
-    if (dynamic_range_type == kHdrType) {
-      DLOGE("Failed: Forbid setting HDR Mode : %s when HDR playback off", color_mode.c_str());
-      return kErrorNotSupported;
-    }
-    error = SetColorModeInternal(color_mode);
-    if (error != kErrorNone) {
-      return error;
-    }
-    current_color_mode_ = color_mode;
+  std::string dynamic_range = kSdr;
+  if (IsSupportColorModeAttribute(color_mode)) {
+    auto it_mode = color_mode_attr_map_.find(color_mode);
+    GetValueOfModeAttribute(it_mode->second, kDynamicRangeAttribute, &dynamic_range);
+  }
+
+  comp_manager_->ControlDpps(dynamic_range != kHdr);
+
+  current_color_mode_ = color_mode;
+  PrimariesTransfer blend_space = {};
+  blend_space = GetBlendSpaceFromColorMode();
+  error = comp_manager_->SetBlendSpace(display_comp_ctx_, blend_space);
+  if (error != kErrorNone) {
+    DLOGE("SetBlendSpace failed, error = %d display_type_=%d", error, display_type_);
   }
 
   return error;
@@ -984,25 +936,6 @@
   return true;
 }
 
-DisplayError DisplayBase::GetHdrColorMode(std::string *color_mode, bool *found_hdr) {
-  if (!found_hdr || !color_mode) {
-    return kErrorParameters;
-  }
-  *found_hdr = false;
-  // get the default HDR mode which is value of picture quality equal to "standard"
-  for (auto &it_hdr : color_mode_attr_map_) {
-    std::string dynamic_range, pic_quality;
-    GetValueOfModeAttribute(it_hdr.second, kDynamicRangeAttribute, &dynamic_range);
-    GetValueOfModeAttribute(it_hdr.second, kPictureQualityAttribute, &pic_quality);
-    if (dynamic_range == kHdr && pic_quality == kStandard) {
-      *color_mode = it_hdr.first;
-      *found_hdr = true;
-    }
-  }
-
-  return kErrorNone;
-}
-
 DisplayError DisplayBase::SetColorTransform(const uint32_t length, const double *color_transform) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
   if (!color_mgr_) {
@@ -1554,6 +1487,13 @@
         auto it = color_mode_attr_map_.find(color_modes_[i].name);
         if (it == color_mode_attr_map_.end()) {
           color_mode_attr_map_.insert(std::make_pair(color_modes_[i].name, var));
+          // If target doesn't support SSPP tone maping and color mode is HDR,
+          // add bt2020pq and bt2020hlg color modes.
+          if (hw_resource_info_.src_tone_map.none() && IsHdrMode(var)) {
+            color_mode_map_.insert(std::make_pair(kBt2020Pq, &color_modes_[i]));
+            color_mode_map_.insert(std::make_pair(kBt2020Hlg, &color_modes_[i]));
+            InsertBT2020PqHlgModes();
+          }
         }
         std::vector<PrimariesTransfer> pt_list = {};
         GetColorPrimaryTransferFromAttributes(var, &pt_list);
@@ -1575,110 +1515,6 @@
   return kErrorNone;
 }
 
-DisplayError DisplayBase::SetHDRMode(bool set) {
-  DisplayError error = kErrorNone;
-  std::string color_mode = "";
-
-  if (color_mgr_ && !disable_hdr_lut_gen_) {
-    // Do not apply HDR Mode when hdr lut generation is disabled
-    if (set) {
-      color_mode = "hal_hdr";
-      if (IsSupportColorModeAttribute(current_color_mode_)) {
-        bool found_hdr = false;
-        error = GetHdrColorMode(&color_mode, &found_hdr);
-        if (!found_hdr) {
-          color_mode = "hal_hdr";
-        }
-      }
-    } else {
-      // HDR playback off - set prev mode
-      color_mode = current_color_mode_;
-    }
-    DLOGI("Setting color mode = %s", color_mode.c_str());
-    error = SetColorModeInternal(color_mode);
-  }
-
-  comp_manager_->ControlDpps(!set);
-  hdr_mode_ = set;
-
-  return error;
-}
-
-DisplayError DisplayBase::HandleHDR(LayerStack *layer_stack) {
-  DisplayError error = kErrorNone;
-
-  if (!NeedsHdrHandling()) {
-    return kErrorNone;
-  }
-
-  if (hw_layers_.info.wide_color_primaries.empty()) {
-    //  HDR playback off - set prev mode
-    if (hdr_playback_) {
-      hdr_playback_ = false;
-      if (hdr_mode_) {
-        error = SetHDRMode(false);
-      }
-    }
-  } else {
-    // set HDR mode on legacy targets only
-    if (SetHdrModeAtStart(layer_stack)) {
-      if (!hdr_playback_ && !layer_stack->flags.animating) {
-        // hdr is starting
-        hdr_playback_ = true;
-        error = SetHDRMode(true);
-        if (error != kErrorNone) {
-          DLOGW("Failed to set HDR mode");
-        }
-      } else if (hdr_playback_ && !hdr_mode_) {
-        error = SetHDRMode(true);
-        if (error != kErrorNone) {
-          DLOGW("Failed to set HDR mode");
-        }
-      }
-    }
-  }
-
-  return error;
-}
-
-DisplayError DisplayBase::ValidateHDR(LayerStack *layer_stack) {
-  DisplayError error = kErrorNone;
-
-  if (!NeedsHdrHandling()) {
-    return kErrorNone;
-  }
-
-  bool hdr_mode = false;
-  bool set = false;  // indicates if we need to call SetHDRMode
-  if (hw_resource_info_.src_tone_map.any()) {
-    if (!hw_layers_.info.wide_color_primaries.empty()) {
-      hdr_playback_ = true;
-      // Need to set HDR mode on target with SSPP only when blend cs is BT2020
-      if (layer_stack->blend_cs.primaries == ColorPrimaries_BT2020 && !hdr_mode_) {
-        hdr_mode = true;
-        set = true;
-      }
-    }
-  } else if (hdr_playback_) {  // legacy targets
-    // HDR color mode is set when hdr layer is present in layer_stack.
-    // If client flags HDR layer as skipped, then blending happens
-    // in SDR color space. Hence, need to restore the SDR color mode.
-    if (layer_stack->blend_cs.primaries != ColorPrimaries_BT2020) {
-      hdr_mode = false;
-      set = true;
-    }
-  }
-
-  if (set) {
-    error = SetHDRMode(hdr_mode);
-    if (error != kErrorNone) {
-      DLOGW("Setting HDR Mode %d failed", hdr_mode);
-    }
-  }
-
-  return kErrorNone;
-}
-
 DisplayError DisplayBase::GetClientTargetSupport(uint32_t width, uint32_t height,
                                                  LayerBufferFormat format,
                                                  const ColorMetaData &color_metadata) {
@@ -1911,4 +1747,65 @@
   return (hw_resource_info_.src_tone_map.none() && layer_stack->flags.hdr_present);
 }
 
+PrimariesTransfer DisplayBase::GetBlendSpaceFromColorMode() {
+  PrimariesTransfer pt = {};
+  auto current_color_attr_ = color_mode_attr_map_.find(current_color_mode_);
+  AttrVal attr = current_color_attr_->second;
+  std::string color_gamut = kNative, dynamic_range = kSdr, pic_quality = kStandard;
+  std::string transfer = {};
+
+  for (auto &it : attr) {
+    if (it.first.find(kColorGamutAttribute) != std::string::npos) {
+      color_gamut = it.second;
+    } else if (it.first.find(kDynamicRangeAttribute) != std::string::npos) {
+      dynamic_range = it.second;
+    } else if (it.first.find(kPictureQualityAttribute) != std::string::npos) {
+      pic_quality = it.second;
+    } else if (it.first.find(kGammaTransferAttribute) != std::string::npos) {
+      transfer = it.second;
+    }
+  }
+  // TODO(user): Check is if someone calls with hal_display_p3
+  if (hw_resource_info_.src_tone_map.none() &&
+      (pic_quality == kStandard && color_gamut == kBt2020)) {
+    pt.primaries = GetColorPrimariesFromAttribute(color_gamut);
+    if (transfer == kHlg) {
+      pt.transfer = Transfer_HLG;
+    } else {
+      pt.transfer = Transfer_SMPTE_ST2084;
+    }
+  } else if ((color_gamut == kDcip3 && dynamic_range == kSdr)) {
+    pt.primaries = GetColorPrimariesFromAttribute(color_gamut);
+    pt.transfer = Transfer_Gamma2_2;
+  } else {
+    DLOGE("Invalid color mode: %s", current_color_mode_.c_str());
+  }
+
+  return pt;
+}
+
+void DisplayBase::InsertBT2020PqHlgModes() {
+  AttrVal hdr_var = {};
+  hdr_var.push_back(std::make_pair(kColorGamutAttribute, kBt2020));
+  hdr_var.push_back(std::make_pair(kPictureQualityAttribute, kStandard));
+  hdr_var.push_back(std::make_pair(kGammaTransferAttribute, kSt2084));
+  color_mode_attr_map_.insert(std::make_pair(kBt2020Pq, hdr_var));
+  hdr_var.pop_back();
+  hdr_var.push_back(std::make_pair(kGammaTransferAttribute, kHlg));
+  color_mode_attr_map_.insert(std::make_pair(kBt2020Hlg, hdr_var));
+
+  return;
+}
+
+bool DisplayBase::IsHdrMode(const AttrVal &attr) {
+  std::string color_gamut, dynamic_range;
+  GetValueOfModeAttribute(attr, kColorGamutAttribute, &color_gamut);
+  GetValueOfModeAttribute(attr, kDynamicRangeAttribute, &dynamic_range);
+  if (color_gamut == kDcip3 && dynamic_range == kHdr) {
+    return true;
+  }
+
+  return false;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index ff5c188..d6d5f15 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -129,13 +129,12 @@
   virtual DisplayError InitializeColorModes();
 
  protected:
+  const char *kBt2020Pq = "bt2020_pq";
+  const char *kBt2020Hlg = "bt2020_hlg";
   DisplayError BuildLayerStackStats(LayerStack *layer_stack);
   virtual DisplayError ValidateGPUTargetParams();
   void CommitLayerParams(LayerStack *layer_stack);
   void PostCommitLayerParams(LayerStack *layer_stack);
-  DisplayError HandleHDR(LayerStack *layer_stack);
-  DisplayError ValidateHDR(LayerStack *layer_stack);
-  DisplayError SetHDRMode(bool set);
   DisplayError ValidateScaling(uint32_t width, uint32_t height);
   DisplayError ValidateDataspace(const ColorMetaData &color_metadata);
   void HwRecovery(const HWRecoveryEvent sdm_event_code);
@@ -150,7 +149,6 @@
   DisplayError SetColorModeInternal(const std::string &color_mode);
   DisplayError GetValueOfModeAttribute(const AttrVal &attr, const std::string &type,
                                        std::string *value);
-  DisplayError GetHdrColorMode(std::string *color_mode, bool *found_hdr);
   bool IsSupportColorModeAttribute(const std::string &color_mode);
   DisplayState GetLastPowerMode();
   void SetPUonDestScaler();
@@ -161,6 +159,9 @@
       std::vector<PrimariesTransfer> *supported_pt);
   bool DisplayPowerResetPending();
   bool SetHdrModeAtStart(LayerStack *layer_stack);
+  PrimariesTransfer GetBlendSpaceFromColorMode();
+  bool IsHdrMode(const AttrVal &attr);
+  void InsertBT2020PqHlgModes();
 
   recursive_mutex recursive_mutex_;
   int32_t display_id_ = -1;
@@ -204,8 +205,6 @@
   uint32_t req_mixer_width_ = 0;
   uint32_t req_mixer_height_ = 0;
   std::string current_color_mode_ = "hal_native";
-  bool hdr_playback_ = false;
-  bool hdr_mode_ = false;
   int disable_hdr_lut_gen_ = 0;
   DisplayState last_power_mode_ = kStateOff;
   bool gpu_fallback_ = false;
diff --git a/sdm/libs/core/display_pluggable.cpp b/sdm/libs/core/display_pluggable.cpp
index 524d7c1..fc1a68f 100644
--- a/sdm/libs/core/display_pluggable.cpp
+++ b/sdm/libs/core/display_pluggable.cpp
@@ -327,21 +327,41 @@
 
 DisplayError DisplayPluggable::InitializeColorModes() {
   PrimariesTransfer pt = {};
+  AttrVal var = {};
   color_modes_cs_.push_back(pt);
-
+  var.push_back(std::make_pair(kColorGamutAttribute, kSrgb));
+  var.push_back(std::make_pair(kDynamicRangeAttribute, kSdr));
+  var.push_back(std::make_pair(kPictureQualityAttribute, kStandard));
+  color_mode_attr_map_.insert(std::make_pair(kSrgb, var));
+  pt.primaries = ColorPrimaries_BT2020;
   if (!hw_panel_info_.hdr_enabled) {
+    UpdateColorModes();
     return kErrorNone;
+  } else {
+    pt.transfer = Transfer_Gamma2_2;
+    color_modes_cs_.push_back(pt);
+    var.clear();
+    var.push_back(std::make_pair(kColorGamutAttribute, kBt2020));
+    var.push_back(std::make_pair(kGammaTransferAttribute, kGamma2_2));
+    color_mode_attr_map_.insert(std::make_pair(kBt2020, var));
   }
 
-  pt.primaries = ColorPrimaries_BT2020;
+  var.clear();
+  var.push_back(std::make_pair(kColorGamutAttribute, kBt2020));
   if (hw_panel_info_.hdr_eotf & kHdrEOTFHDR10) {
     pt.transfer = Transfer_SMPTE_ST2084;
+    var.push_back(std::make_pair(kGammaTransferAttribute, kSt2084));
     color_modes_cs_.push_back(pt);
+    color_mode_attr_map_.insert(std::make_pair(kBt2020Pq, var));
   }
   if (hw_panel_info_.hdr_eotf & kHdrEOTFHLG) {
     pt.transfer = Transfer_HLG;
+    var.pop_back();
+    var.push_back(std::make_pair(kGammaTransferAttribute, kHlg));
     color_modes_cs_.push_back(pt);
+    color_mode_attr_map_.insert(std::make_pair(kBt2020Hlg, var));
   }
+  UpdateColorModes();
 
   return kErrorNone;
 }
@@ -357,4 +377,112 @@
   return kErrorNone;
 }
 
+static PrimariesTransfer GetBlendSpaceFromAttributes(const std::string &color_gamut,
+                                                     const std::string &transfer) {
+  PrimariesTransfer blend_space_ = {};
+  if (color_gamut == kBt2020) {
+    blend_space_.primaries = ColorPrimaries_BT2020;
+    if (transfer == kHlg) {
+      blend_space_.transfer = Transfer_HLG;
+    } else if (transfer == kSt2084) {
+      blend_space_.transfer = Transfer_SMPTE_ST2084;
+    } else if (transfer == kGamma2_2) {
+      blend_space_.transfer = Transfer_Gamma2_2;
+    }
+  } else if (color_gamut == kSrgb) {
+    blend_space_.primaries = ColorPrimaries_BT709_5;
+    blend_space_.transfer = Transfer_sRGB;
+  } else {
+    DLOGW("Failed to Get blend space color_gamut = %s transfer = %s", color_gamut.c_str(),
+          transfer.c_str());
+  }
+  DLOGI("Blend Space Primaries = %d Transfer = %d", blend_space_.primaries, blend_space_.transfer);
+
+  return blend_space_;
+}
+
+DisplayError DisplayPluggable::SetColorMode(const std::string &color_mode) {
+  auto current_color_attr_ = color_mode_attr_map_.find(color_mode);
+  if (current_color_attr_ == color_mode_attr_map_.end()) {
+    DLOGE("Failed to get attribues for color mode = %s", color_mode.c_str());
+    return kErrorNone;
+  }
+  AttrVal attr = current_color_attr_->second;
+  std::string color_gamut = kNative, transfer = {};
+
+  for (auto &it : attr) {
+    if (it.first.find(kColorGamutAttribute) != std::string::npos) {
+      color_gamut = it.second;
+    } else if (it.first.find(kGammaTransferAttribute) != std::string::npos) {
+      transfer = it.second;
+    }
+  }
+
+  DisplayError error = kErrorNone;
+  error = comp_manager_->SetBlendSpace(display_comp_ctx_,
+                                       GetBlendSpaceFromAttributes(color_gamut, transfer));
+  if (error != kErrorNone) {
+    DLOGE("Failed Set blend space, error = %d display_type_=%d", error, display_type_);
+  }
+
+  return kErrorNone;
+}
+
+DisplayError DisplayPluggable::GetColorModeCount(uint32_t *mode_count) {
+  lock_guard<recursive_mutex> obj(recursive_mutex_);
+  if (!mode_count) {
+    return kErrorParameters;
+  }
+
+  DLOGI("Display = %d Number of modes = %d", display_type_, num_color_modes_);
+  *mode_count = num_color_modes_;
+
+  return kErrorNone;
+}
+
+DisplayError DisplayPluggable::GetColorModes(uint32_t *mode_count,
+                                             std::vector<std::string> *color_modes) {
+  lock_guard<recursive_mutex> obj(recursive_mutex_);
+  if (!mode_count || !color_modes) {
+    return kErrorParameters;
+  }
+
+  for (uint32_t i = 0; i < num_color_modes_; i++) {
+    DLOGI_IF(kTagDisplay, "ColorMode[%d] = %s", i, color_modes_[i].name);
+    color_modes->at(i) = color_modes_[i].name;
+  }
+
+  return kErrorNone;
+}
+
+DisplayError DisplayPluggable::GetColorModeAttr(const std::string &color_mode, AttrVal *attr) {
+  lock_guard<recursive_mutex> obj(recursive_mutex_);
+  if (!attr) {
+    return kErrorParameters;
+  }
+
+  auto it = color_mode_attr_map_.find(color_mode);
+  if (it == color_mode_attr_map_.end()) {
+    DLOGI("Mode %s has no attribute", color_mode.c_str());
+    return kErrorNotSupported;
+  }
+  *attr = it->second;
+
+  return kErrorNone;
+}
+
+void DisplayPluggable::UpdateColorModes() {
+  uint32_t i = 0;
+  num_color_modes_ = UINT32(color_mode_attr_map_.size());
+  color_modes_.resize(num_color_modes_);
+  for (ColorModeAttrMap::iterator it = color_mode_attr_map_.begin();
+       ((i < num_color_modes_) && (it != color_mode_attr_map_.end())); i++, it++) {
+    color_modes_[i].id = INT32(i);
+    strncpy(color_modes_[i].name, it->first.c_str(), sizeof(color_modes_[i].name));
+    color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
+    DLOGI("Attr map name = %s", it->first.c_str());
+  }
+  return;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/display_pluggable.h b/sdm/libs/core/display_pluggable.h
index aba1305..f3da05b 100644
--- a/sdm/libs/core/display_pluggable.h
+++ b/sdm/libs/core/display_pluggable.h
@@ -48,6 +48,10 @@
   virtual bool IsUnderscanSupported();
   virtual DisplayError OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level);
   virtual DisplayError InitializeColorModes();
+  virtual DisplayError SetColorMode(const std::string &color_mode);
+  virtual DisplayError GetColorModeCount(uint32_t *mode_count);
+  virtual DisplayError GetColorModes(uint32_t *mode_count, std::vector<std::string> *color_modes);
+  virtual DisplayError GetColorModeAttr(const std::string &color_mode, AttrVal *attr);
   virtual DisplayError SetDisplayState(DisplayState state, int *release_fence);
 
   // Implement the HWEventHandlers
@@ -61,6 +65,8 @@
   virtual void PanelDead() {}
   virtual void HwRecovery(const HWRecoveryEvent sdm_event_code);
 
+  void UpdateColorModes();
+
  private:
   uint32_t GetBestConfig(HWS3DMode s3d_mode);
   void GetScanSupport();
diff --git a/sdm/libs/core/strategy.cpp b/sdm/libs/core/strategy.cpp
index d96c103..1281545 100644
--- a/sdm/libs/core/strategy.cpp
+++ b/sdm/libs/core/strategy.cpp
@@ -258,4 +258,11 @@
   return kErrorNotSupported;
 }
 
+DisplayError Strategy::SetBlendSpace(const PrimariesTransfer &blend_space) {
+  if (strategy_intf_) {
+    return strategy_intf_->SetBlendSpace(blend_space);
+  }
+  return kErrorNotSupported;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/strategy.h b/sdm/libs/core/strategy.h
index c79dff6..db10f11 100644
--- a/sdm/libs/core/strategy.h
+++ b/sdm/libs/core/strategy.h
@@ -55,6 +55,7 @@
   DisplayError Purge();
   DisplayError SetIdleTimeoutMs(uint32_t active_ms);
   DisplayError SetColorModesInfo(const std::vector<PrimariesTransfer> &colormodes_cs);
+  DisplayError SetBlendSpace(const PrimariesTransfer &blend_space);
 
  private:
   void GenerateROI();
diff --git a/sdm/libs/hwc2/Android.mk b/sdm/libs/hwc2/Android.mk
index e9511f7..d9ffa0b 100644
--- a/sdm/libs/hwc2/Android.mk
+++ b/sdm/libs/hwc2/Android.mk
@@ -24,7 +24,8 @@
                                  vendor.display.config@1.0 \
                                  android.hardware.graphics.mapper@2.0 \
                                  android.hardware.graphics.mapper@2.1 \
-                                 android.hardware.graphics.allocator@2.0
+                                 android.hardware.graphics.allocator@2.0 \
+                                 android.hardware.graphics.composer@2.2 \
 
 ifeq ($(display_config_version), DISPLAY_CONFIG_1_1)
 LOCAL_SHARED_LIBRARIES        += vendor.display.config@1.1
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 7435f3e..ef65057 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -67,47 +67,77 @@
 }
 
 HWC2::Error HWCColorMode::DeInit() {
-  color_mode_transform_map_.clear();
+  color_mode_map_.clear();
   return HWC2::Error::None;
 }
 
 uint32_t HWCColorMode::GetColorModeCount() {
-  uint32_t count = UINT32(color_mode_transform_map_.size());
+  uint32_t count = UINT32(color_mode_map_.size());
   DLOGI("Supported color mode count = %d", count);
-
   return std::max(1U, count);
 }
 
-HWC2::Error HWCColorMode::GetColorModes(uint32_t *out_num_modes,
-                                        android_color_mode_t *out_modes) {
-  auto it = color_mode_transform_map_.begin();
-  *out_num_modes = std::min(*out_num_modes, UINT32(color_mode_transform_map_.size()));
+uint32_t HWCColorMode::GetRenderIntentCount(ColorMode mode) {
+  uint32_t count = UINT32(color_mode_map_[mode].size());
+  DLOGI("mode: %d supported rendering intent count = %d", mode, count);
+  return std::max(1U, count);
+}
+
+HWC2::Error HWCColorMode::GetColorModes(uint32_t *out_num_modes, ColorMode *out_modes) {
+  auto it = color_mode_map_.begin();
+  *out_num_modes = std::min(*out_num_modes, UINT32(color_mode_map_.size()));
   for (uint32_t i = 0; i < *out_num_modes; it++, i++) {
     out_modes[i] = it->first;
-    DLOGI("Supports color mode[%d] = %d", i, it->first);
+    DLOGI("Color mode = %d is supported", out_modes[i]);
   }
-
   return HWC2::Error::None;
 }
 
-HWC2::Error HWCColorMode::SetColorMode(android_color_mode_t mode) {
+HWC2::Error HWCColorMode::GetRenderIntents(ColorMode mode, uint32_t *out_num_intents,
+                                           RenderIntent *out_intents) {
+  if (color_mode_map_.find(mode) == color_mode_map_.end()) {
+    return HWC2::Error::BadParameter;
+  }
+  auto it = color_mode_map_[mode].begin();
+  *out_num_intents = std::min(*out_num_intents, UINT32(color_mode_map_[mode].size()));
+  for (uint32_t i = 0; i < *out_num_intents; it++, i++) {
+    out_intents[i] = it->first;
+    DLOGI("Color mode = %d is supported with render intent = %d", mode, out_intents[i]);
+  }
+  return HWC2::Error::None;
+}
+
+HWC2::Error HWCColorMode::SetColorModeWithRenderIntent(ColorMode mode, RenderIntent intent) {
   DTRACE_SCOPED();
-  // first mode in 2D matrix is the mode (identity)
-  if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_DISPLAY_P3) {
+  if (mode < ColorMode::NATIVE || mode > ColorMode::BT2100_HLG) {
     DLOGE("Could not find mode: %d", mode);
     return HWC2::Error::BadParameter;
   }
-  if (color_mode_transform_map_.find(mode) == color_mode_transform_map_.end()) {
+  if (color_mode_map_.find(mode) == color_mode_map_.end()) {
+    return HWC2::Error::Unsupported;
+  }
+  if (color_mode_map_[mode].find(intent) == color_mode_map_[mode].end()) {
     return HWC2::Error::Unsupported;
   }
 
-  auto status = HandleColorModeTransform(mode, current_color_transform_, color_matrix_);
-  if (status != HWC2::Error::None) {
-    DLOGE("failed for mode = %d", mode);
+  if (current_color_mode_ == mode && current_render_intent_ == intent) {
+    return HWC2::Error::None;
   }
 
-  DLOGV_IF(kTagClient, "Color mode %d successfully set.", mode);
-  return status;
+  auto mode_string = color_mode_map_[mode][intent];
+  DisplayError error = display_intf_->SetColorMode(mode_string);
+  if (error != kErrorNone) {
+    DLOGE("failed for mode = %d intent = %d name = %s", mode, intent, mode_string.c_str());
+    return HWC2::Error::Unsupported;
+  }
+  // The mode does not have the PCC configured, restore the transform
+  RestoreColorTransform();
+
+  current_color_mode_ = mode;
+  current_render_intent_ = intent;
+  DLOGV_IF(kTagClient, "Successfully applied mode = %d intent = %d name = %s", mode, intent,
+           mode_string.c_str());
+  return HWC2::Error::None;
 }
 
 HWC2::Error HWCColorMode::SetColorModeById(int32_t color_mode_id) {
@@ -130,80 +160,42 @@
   return HWC2::Error::None;
 }
 
-HWC2::Error HWCColorMode::SetColorTransform(const float *matrix, android_color_transform_t hint) {
+HWC2::Error HWCColorMode::SetColorTransform(const float *matrix,
+                                            android_color_transform_t /*hint*/) {
   DTRACE_SCOPED();
+  auto status = HWC2::Error::None;
   double color_matrix[kColorTransformMatrixCount] = {0};
   CopyColorTransformMatrix(matrix, color_matrix);
 
-  auto status = HandleColorModeTransform(current_color_mode_, hint, color_matrix);
-  if (status != HWC2::Error::None) {
-    DLOGE("failed for hint = %d", hint);
+  DisplayError error = display_intf_->SetColorTransform(kColorTransformMatrixCount, color_matrix);
+  if (error != kErrorNone) {
+    DLOGE("Failed to set Color Transform Matrix");
+    status = HWC2::Error::Unsupported;
   }
-
+  CopyColorTransformMatrix(matrix, color_matrix_);
   return status;
 }
 
-HWC2::Error HWCColorMode::HandleColorModeTransform(android_color_mode_t mode,
-                                                   android_color_transform_t hint,
-                                                   const double *matrix) {
-  android_color_transform_t transform_hint = hint;
-  std::string color_mode_transform;
-  bool use_matrix = false;
-  if (hint != HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX) {
-    // if the mode + transfrom request from HWC matches one mode in SDM, set that
-    if (color_mode_transform.empty()) {
-      transform_hint = HAL_COLOR_TRANSFORM_IDENTITY;
-      use_matrix = true;
-    } else {
-      color_mode_transform = color_mode_transform_map_[mode][hint];
-    }
-  } else {
-    use_matrix = true;
-    transform_hint = HAL_COLOR_TRANSFORM_IDENTITY;
+void HWCColorMode::FindRenderIntent(const ColorMode &mode, const std::string &mode_string) {
+  auto intent = RenderIntent::COLORIMETRIC;
+  if (mode_string.find("enhanced") != std::string::npos) {
+    intent = RenderIntent::ENHANCE;
   }
-
-  // if the mode count is 1, then only native mode is supported, so just apply matrix w/o
-  // setting mode
-  if (color_mode_transform_map_.size() > 1U && current_color_mode_ != mode) {
-    color_mode_transform = color_mode_transform_map_[mode][transform_hint];
-    DisplayError error = display_intf_->SetColorMode(color_mode_transform);
-    if (error != kErrorNone) {
-      DLOGE("Failed to set color_mode  = %d transform_hint = %d", mode, hint);
-      // failure to force client composition
-      return HWC2::Error::Unsupported;
-    }
-    DLOGI("Setting Color Mode = %d Transform Hint = %d Success", mode, hint);
-  }
-
-  if (use_matrix) {
-    DisplayError error = display_intf_->SetColorTransform(kColorTransformMatrixCount, matrix);
-    if (error != kErrorNone) {
-      DLOGE("Failed to set Color Transform Matrix");
-      // failure to force client composition
-      return HWC2::Error::Unsupported;
-    }
-  }
-
-  current_color_mode_ = mode;
-  current_color_transform_ = hint;
-  CopyColorTransformMatrix(matrix, color_matrix_);
-
-  return HWC2::Error::None;
+  color_mode_map_[mode][intent] = mode_string;
 }
 
 void HWCColorMode::PopulateColorModes() {
   uint32_t color_mode_count = 0;
-  // SDM returns modes which is string combination of mode + transform.
+  // SDM returns modes which have attributes defining mode and rendering intent
   DisplayError error = display_intf_->GetColorModeCount(&color_mode_count);
   if (error != kErrorNone || (color_mode_count == 0)) {
     DLOGW("GetColorModeCount failed, use native color mode");
-    PopulateTransform(HAL_COLOR_MODE_NATIVE, "native", "identity");
+    color_mode_map_[ColorMode::NATIVE][RenderIntent::COLORIMETRIC] = "hal_native_identity";
     return;
   }
 
   DLOGV_IF(kTagClient, "Color Modes supported count = %d", color_mode_count);
 
-  const std::string color_transform = "identity";
   std::vector<std::string> color_modes(color_mode_count);
   error = display_intf_->GetColorModes(&color_mode_count, &color_modes);
   for (uint32_t i = 0; i < color_mode_count; i++) {
@@ -211,7 +203,7 @@
     DLOGV_IF(kTagClient, "Color Mode[%d] = %s", i, mode_string.c_str());
     AttrVal attr;
     error = display_intf_->GetColorModeAttr(mode_string, &attr);
-    std::string color_gamut, dynamic_range, pic_quality;
+    std::string color_gamut = kNative, dynamic_range = kSdr, pic_quality = kStandard, transfer;
     if (!attr.empty()) {
       for (auto &it : attr) {
         if (it.first.find(kColorGamutAttribute) != std::string::npos) {
@@ -220,81 +212,66 @@
           dynamic_range = it.second;
         } else if (it.first.find(kPictureQualityAttribute) != std::string::npos) {
           pic_quality = it.second;
+        } else if (it.first.find(kGammaTransferAttribute) != std::string::npos) {
+          transfer = it.second;
         }
       }
 
       DLOGV_IF(kTagClient, "color_gamut : %s, dynamic_range : %s, pic_quality : %s",
                color_gamut.c_str(), dynamic_range.c_str(), pic_quality.c_str());
-
-      if (dynamic_range == kHdr) {
-        continue;
+      if (color_gamut == kNative) {
+        color_mode_map_[ColorMode::NATIVE][RenderIntent::COLORIMETRIC] = mode_string;
       }
-      if ((color_gamut == kNative) &&
-          (pic_quality.empty() || pic_quality == kStandard)) {
-        PopulateTransform(HAL_COLOR_MODE_NATIVE, mode_string, color_transform);
-      } else if ((color_gamut == kSrgb) &&
-                 (pic_quality.empty() || pic_quality == kStandard)) {
-        PopulateTransform(HAL_COLOR_MODE_SRGB, mode_string, color_transform);
-      } else if ((color_gamut == kDcip3) &&
-                 (pic_quality.empty() || pic_quality == kStandard)) {
-        PopulateTransform(HAL_COLOR_MODE_DISPLAY_P3, mode_string, color_transform);
-      } else if ((color_gamut == kDisplayP3) &&
-                 (pic_quality.empty() || pic_quality == kStandard)) {
-        PopulateTransform(HAL_COLOR_MODE_DISPLAY_P3, mode_string, color_transform);
-      }
-    }
 
-    // Look at the mode name, if no color gamut is found
-    if (color_gamut.empty()) {
+      if (color_gamut == kSrgb && dynamic_range == kSdr) {
+        if (pic_quality == kStandard) {
+          color_mode_map_[ColorMode::SRGB][RenderIntent::COLORIMETRIC] = mode_string;
+        }
+        if (pic_quality == kEnhanced) {
+          color_mode_map_[ColorMode::SRGB][RenderIntent::ENHANCE] = mode_string;
+        }
+      }
+
+      if (color_gamut == kDcip3 && dynamic_range == kSdr) {
+        if (pic_quality == kStandard) {
+          color_mode_map_[ColorMode::DISPLAY_P3][RenderIntent::COLORIMETRIC] = mode_string;
+        }
+        if (pic_quality == kEnhanced) {
+          color_mode_map_[ColorMode::DISPLAY_P3][RenderIntent::ENHANCE] = mode_string;
+        }
+      }
+      if (color_gamut == kDcip3 && pic_quality == kStandard && dynamic_range == kHdr) {
+        color_mode_map_[ColorMode::BT2100_PQ][RenderIntent::TONE_MAP_COLORIMETRIC] = mode_string;
+        color_mode_map_[ColorMode::BT2100_HLG][RenderIntent::TONE_MAP_COLORIMETRIC] = mode_string;
+      } else if (color_gamut == kBt2020) {
+        if (transfer == kSt2084) {
+          color_mode_map_[ColorMode::BT2100_PQ][RenderIntent::COLORIMETRIC] = mode_string;
+        } else if (transfer == kHlg) {
+          color_mode_map_[ColorMode::BT2100_HLG][RenderIntent::COLORIMETRIC] = mode_string;
+        } else if (transfer == kGamma2_2) {
+          color_mode_map_[ColorMode::BT2020][RenderIntent::COLORIMETRIC] = mode_string;
+        }
+      }
+    } else {
+      // Look at the mode names, if no attributes are found
       if (mode_string.find("hal_native") != std::string::npos) {
-        PopulateTransform(HAL_COLOR_MODE_NATIVE, mode_string, mode_string);
-      } else if (mode_string.find("hal_srgb") != std::string::npos) {
-        PopulateTransform(HAL_COLOR_MODE_SRGB, mode_string, mode_string);
-      } else if (mode_string.find("hal_adobe") != std::string::npos) {
-        PopulateTransform(HAL_COLOR_MODE_ADOBE_RGB, mode_string, mode_string);
-      } else if (mode_string.find("hal_dci_p3") != std::string::npos) {
-        PopulateTransform(HAL_COLOR_MODE_DCI_P3, mode_string, mode_string);
-      } else if (mode_string.find("hal_display_p3") != std::string::npos) {
-        PopulateTransform(HAL_COLOR_MODE_DISPLAY_P3, mode_string, mode_string);
+        color_mode_map_[ColorMode::NATIVE][RenderIntent::COLORIMETRIC] = mode_string;
       }
     }
   }
 }
 
-void HWCColorMode::PopulateTransform(const android_color_mode_t &mode,
-                                     const std::string &color_mode,
-                                     const std::string &color_transform) {
-  // TODO(user): Check the substring from QDCM
-  if (color_transform.find("identity") != std::string::npos) {
-    color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_IDENTITY] = color_mode;
-  } else if (color_transform.find("arbitrary") != std::string::npos) {
-    // no color mode for arbitrary
-  } else if (color_transform.find("inverse") != std::string::npos) {
-    color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_VALUE_INVERSE] = color_mode;
-  } else if (color_transform.find("grayscale") != std::string::npos) {
-    color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_GRAYSCALE] = color_mode;
-  } else if (color_transform.find("correct_protonopia") != std::string::npos) {
-    color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA] = color_mode;
-  } else if (color_transform.find("correct_deuteranopia") != std::string::npos) {
-    color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA] = color_mode;
-  } else if (color_transform.find("correct_tritanopia") != std::string::npos) {
-    color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA] = color_mode;
-  } else {
-    color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_IDENTITY] = color_mode;
-  }
-}
-
 HWC2::Error HWCColorMode::ApplyDefaultColorMode() {
-  android_color_mode_t color_mode = HAL_COLOR_MODE_NATIVE;
-  if (color_mode_transform_map_.size() == 1U) {
-    color_mode = color_mode_transform_map_.begin()->first;
-  } else if (color_mode_transform_map_.size() > 1U) {
+  auto color_mode = ColorMode::NATIVE;
+  if (color_mode_map_.size() == 1U) {
+    color_mode = color_mode_map_.begin()->first;
+  } else if (color_mode_map_.size() > 1U) {
     std::string default_color_mode;
     bool found = false;
     DisplayError error = display_intf_->GetDefaultColorMode(&default_color_mode);
     if (error == kErrorNone) {
       // get the default mode corresponding android_color_mode_t
-      for (auto &it_mode : color_mode_transform_map_) {
+      for (auto &it_mode : color_mode_map_) {
         for (auto &it : it_mode.second) {
           if (it.second == default_color_mode) {
             found = true;
@@ -308,20 +285,25 @@
       }
     }
 
-    // return the first andrid_color_mode_t when we encouter if not found
+    // return the first color mode we encounter if not found
     if (!found) {
-      color_mode = color_mode_transform_map_.begin()->first;
+      color_mode = color_mode_map_.begin()->first;
     }
   }
-  return SetColorMode(color_mode);
+  return SetColorModeWithRenderIntent(color_mode, RenderIntent::COLORIMETRIC);
 }
 
 void HWCColorMode::Dump(std::ostringstream* os) {
-  *os << "color modes supported: ";
-  for (auto it : color_mode_transform_map_) {
-    *os << it.first <<" ";
+  *os << "color modes supported: \n";
+  for (auto it : color_mode_map_) {
+    *os << "mode: " << static_cast<int32_t>(it.first) << " RIs { ";
+    for (auto rit : color_mode_map_[it.first]) {
+      *os << static_cast<int32_t>(rit.first) << " ";
+    }
+    *os << "} \n";
   }
-  *os << "current mode: " << current_color_mode_ << std::endl;
+  *os << "current mode: " << static_cast<uint32_t>(current_color_mode_) << std::endl;
+  *os << "current render_intent: " << static_cast<uint32_t>(current_render_intent_) << std::endl;
   *os << "current transform: ";
   for (uint32_t i = 0; i < kColorTransformMatrixCount; i++) {
     if (i % 4 == 0) {
@@ -553,8 +535,12 @@
     bool hdr_layer = layer->input_buffer.color_metadata.colorPrimaries == ColorPrimaries_BT2020 &&
                      (layer->input_buffer.color_metadata.transfer == Transfer_SMPTE_ST2084 ||
                      layer->input_buffer.color_metadata.transfer == Transfer_HLG);
-    if (hdr_layer && !disable_hdr_handling_) {
-      // dont honor HDR when its handling is disabled
+    if (hdr_layer && !disable_hdr_handling_  &&
+        (color_mode_->GetCurrentColorMode()) != ColorMode::NATIVE) {
+      // Dont honor HDR when its handling is disabled
+      // Also, when the color mode is native, it implies that
+      // SF has not correctly set the mode to BT2100_PQ in the presence of an HDR layer
+      // In such cases, we should not handle HDR as the HDR mode isn't applied
       layer->input_buffer.flags.hdr = true;
       layer_stack_.flags.hdr_present = true;
     }
@@ -778,14 +764,27 @@
   return HWC2::Error::None;
 }
 
-HWC2::Error HWCDisplay::GetColorModes(uint32_t *out_num_modes, android_color_mode_t *out_modes) {
+HWC2::Error HWCDisplay::GetColorModes(uint32_t *out_num_modes, ColorMode *out_modes) {
   if (out_modes == nullptr) {
     *out_num_modes = 1;
   } else if (out_modes && *out_num_modes > 0) {
     *out_num_modes = 1;
-    out_modes[0] = HAL_COLOR_MODE_NATIVE;
+    out_modes[0] = ColorMode::NATIVE;
   }
+  return HWC2::Error::None;
+}
 
+HWC2::Error HWCDisplay::GetRenderIntents(ColorMode mode, uint32_t *out_num_intents,
+                                         RenderIntent *out_intents) {
+  if (mode != ColorMode::NATIVE) {
+    return HWC2::Error::Unsupported;
+  }
+  if (out_intents == nullptr) {
+    *out_num_intents = 1;
+  } else if (out_intents && *out_num_intents > 0) {
+    *out_num_intents = 1;
+    out_intents[0] = RenderIntent::COLORIMETRIC;
+  }
   return HWC2::Error::None;
 }
 
@@ -899,6 +898,29 @@
   }
 }
 
+HWC2::Error HWCDisplay::GetPerFrameMetadataKeys(uint32_t *out_num_keys,
+                                                PerFrameMetadataKey *out_keys) {
+  if (out_num_keys == nullptr) {
+    return HWC2::Error::BadParameter;
+  }
+  *out_num_keys = UINT32(PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL) + 1;
+  if (out_keys != nullptr) {
+    out_keys[0] = PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X;
+    out_keys[1] = PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y;
+    out_keys[2] = PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X;
+    out_keys[3] = PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y;
+    out_keys[4] = PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X;
+    out_keys[5] = PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y;
+    out_keys[6] = PerFrameMetadataKey::WHITE_POINT_X;
+    out_keys[7] = PerFrameMetadataKey::WHITE_POINT_Y;
+    out_keys[8] = PerFrameMetadataKey::MAX_LUMINANCE;
+    out_keys[9] = PerFrameMetadataKey::MIN_LUMINANCE;
+    out_keys[10] = PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL;
+    out_keys[11] = PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL;
+  }
+  return HWC2::Error::None;
+}
+
 HWC2::Error HWCDisplay::GetActiveConfig(hwc2_config_t *out_config) {
   if (out_config == nullptr) {
     return HWC2::Error::BadDisplay;
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index d35ea23..b4bb554 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -20,12 +20,13 @@
 #ifndef __HWC_DISPLAY_H__
 #define __HWC_DISPLAY_H__
 
-#include <sys/stat.h>
 #include <QService.h>
+#include <android/hardware/graphics/common/1.1/types.h>
 #include <core/core_interface.h>
 #include <hardware/hwcomposer.h>
 #include <private/color_params.h>
 #include <qdMetaData.h>
+#include <sys/stat.h>
 #include <map>
 #include <queue>
 #include <set>
@@ -40,6 +41,10 @@
 #include "display_null.h"
 #include "hwc_display_event_handler.h"
 
+using android::hardware::graphics::common::V1_1::ColorMode;
+using android::hardware::graphics::common::V1_1::Dataspace;
+using android::hardware::graphics::common::V1_1::RenderIntent;
+
 namespace sdm {
 
 class BlitEngine;
@@ -68,20 +73,19 @@
   HWC2::Error DeInit();
   void Dump(std::ostringstream* os);
   uint32_t GetColorModeCount();
-  HWC2::Error GetColorModes(uint32_t *out_num_modes, android_color_mode_t *out_modes);
-  HWC2::Error SetColorMode(android_color_mode_t mode);
+  uint32_t GetRenderIntentCount(ColorMode mode);
+  HWC2::Error GetColorModes(uint32_t *out_num_modes, ColorMode *out_modes);
+  HWC2::Error GetRenderIntents(ColorMode mode, uint32_t *out_num_intents, RenderIntent *out_modes);
+  HWC2::Error SetColorModeWithRenderIntent(ColorMode mode, RenderIntent intent);
   HWC2::Error SetColorModeById(int32_t color_mode_id);
   HWC2::Error SetColorTransform(const float *matrix, android_color_transform_t hint);
   HWC2::Error RestoreColorTransform();
+  ColorMode GetCurrentColorMode() { return current_color_mode_; }
 
  private:
   static const uint32_t kColorTransformMatrixCount = 16;
-
-  HWC2::Error HandleColorModeTransform(android_color_mode_t mode,
-                                       android_color_transform_t hint, const double *matrix);
   void PopulateColorModes();
-  void PopulateTransform(const android_color_mode_t &mode,
-                         const std::string &color_mode, const std::string &color_transform);
+  void FindRenderIntent(const ColorMode &mode, const std::string &mode_string);
   template <class T>
   void CopyColorTransformMatrix(const T *input_matrix, double *output_matrix) {
     for (uint32_t i = 0; i < kColorTransformMatrixCount; i++) {
@@ -91,10 +95,12 @@
   HWC2::Error ApplyDefaultColorMode();
 
   DisplayInterface *display_intf_ = NULL;
-  android_color_mode_t current_color_mode_ = HAL_COLOR_MODE_NATIVE;
-  android_color_transform_t current_color_transform_ = HAL_COLOR_TRANSFORM_IDENTITY;
-  typedef std::map<android_color_transform_t, std::string> TransformMap;
-  std::map<android_color_mode_t, TransformMap> color_mode_transform_map_ = {};
+
+  ColorMode current_color_mode_ = ColorMode::NATIVE;
+  RenderIntent current_render_intent_ = RenderIntent::COLORIMETRIC;
+  typedef std::map<RenderIntent, std::string> RenderIntentMap;
+  // Initialize supported mode/render intent combination
+  std::map<ColorMode, RenderIntentMap> color_mode_map_ = {};
   double color_matrix_[kColorTransformMatrixCount] = { 1.0, 0.0, 0.0, 0.0, \
                                                        0.0, 1.0, 0.0, 0.0, \
                                                        0.0, 0.0, 1.0, 0.0, \
@@ -203,7 +209,8 @@
   virtual HWC2::Error SetActiveConfig(hwc2_config_t config);
   virtual HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence,
                                       int32_t dataspace, hwc_region_t damage);
-  virtual HWC2::Error SetColorMode(android_color_mode_t mode) {
+  virtual HWC2::Error SetColorMode(ColorMode mode) { return HWC2::Error::Unsupported; }
+  virtual HWC2::Error SetColorModeWithRenderIntent(ColorMode mode, RenderIntent intent) {
     return HWC2::Error::Unsupported;
   }
   virtual HWC2::Error SetColorModeById(int32_t color_mode_id) {
@@ -225,7 +232,9 @@
                                           int32_t *out_value);
   virtual HWC2::Error GetClientTargetSupport(uint32_t width, uint32_t height, int32_t format,
                                              int32_t dataspace);
-  virtual HWC2::Error GetColorModes(uint32_t *outNumModes, android_color_mode_t *outModes);
+  virtual HWC2::Error GetColorModes(uint32_t *outNumModes, ColorMode *outModes);
+  virtual HWC2::Error GetRenderIntents(ColorMode mode, uint32_t *out_num_intents,
+                                       RenderIntent *out_intents);
   virtual HWC2::Error GetChangedCompositionTypes(uint32_t *out_num_elements,
                                                  hwc2_layer_t *out_layers, int32_t *out_types);
   virtual HWC2::Error GetDisplayRequests(int32_t *out_display_requests, uint32_t *out_num_elements,
@@ -246,6 +255,8 @@
                                          float* out_max_luminance,
                                          float* out_max_average_luminance,
                                          float* out_min_luminance);
+  virtual HWC2::Error GetPerFrameMetadataKeys(uint32_t *out_num_keys,
+                                              PerFrameMetadataKey *out_keys);
   virtual HWC2::Error SetDisplayAnimating(bool animating) {
     animating_ = animating;
     validated_ = false;
diff --git a/sdm/libs/hwc2/hwc_display_external.cpp b/sdm/libs/hwc2/hwc_display_external.cpp
index 70d7528..ad18868 100644
--- a/sdm/libs/hwc2/hwc_display_external.cpp
+++ b/sdm/libs/hwc2/hwc_display_external.cpp
@@ -95,6 +95,17 @@
   return status;
 }
 
+int HWCDisplayExternal::Init() {
+  int status = HWCDisplay::Init();
+  if (status) {
+    return status;
+  }
+  color_mode_ = new HWCColorMode(display_intf_);
+  color_mode_->Init();
+
+  return status;
+}
+
 void HWCDisplayExternal::Destroy(HWCDisplay *hwc_display) {
   hwc_display->Deinit();
   delete hwc_display;
@@ -284,4 +295,40 @@
   return display_intf_->Flush();
 }
 
+HWC2::Error HWCDisplayExternal::GetColorModes(uint32_t *out_num_modes, ColorMode *out_modes) {
+  if (out_modes == nullptr) {
+    *out_num_modes = color_mode_->GetColorModeCount();
+  } else {
+    color_mode_->GetColorModes(out_num_modes, out_modes);
+  }
+  return HWC2::Error::None;
+}
+
+HWC2::Error HWCDisplayExternal::GetRenderIntents(ColorMode mode, uint32_t *out_num_intents,
+                                                 RenderIntent *out_intents) {
+  if (out_intents == nullptr) {
+    *out_num_intents = color_mode_->GetRenderIntentCount(mode);
+  } else {
+    color_mode_->GetRenderIntents(mode, out_num_intents, out_intents);
+  }
+  return HWC2::Error::None;
+}
+
+HWC2::Error HWCDisplayExternal::SetColorMode(ColorMode mode) {
+  return SetColorModeWithRenderIntent(mode, RenderIntent::COLORIMETRIC);
+}
+
+HWC2::Error HWCDisplayExternal::SetColorModeWithRenderIntent(ColorMode mode, RenderIntent intent) {
+  auto status = color_mode_->SetColorModeWithRenderIntent(mode, intent);
+  if (status != HWC2::Error::None) {
+    DLOGE("failed for mode = %d intent = %d", mode, intent);
+    return status;
+  }
+
+  callbacks_->Refresh(HWC_DISPLAY_EXTERNAL);
+  validated_ = false;
+
+  return status;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_external.h b/sdm/libs/hwc2/hwc_display_external.h
index 88b10e4..89ac87e 100644
--- a/sdm/libs/hwc2/hwc_display_external.h
+++ b/sdm/libs/hwc2/hwc_display_external.h
@@ -46,10 +46,16 @@
                     HWCCallbacks *callbacks, HWCDisplayEventHandler *event_handler,
                     qService::QService *qservice, HWCDisplay **hwc_display);
   static void Destroy(HWCDisplay *hwc_display);
+  virtual int Init();
   virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
   virtual HWC2::Error Present(int32_t *out_retire_fence);
   virtual int SetState(bool connected);
   virtual DisplayError Flush();
+  virtual HWC2::Error GetColorModes(uint32_t *out_num_modes, ColorMode *out_modes);
+  virtual HWC2::Error GetRenderIntents(ColorMode mode, uint32_t *out_num_intents,
+                                       RenderIntent *out_intents);
+  virtual HWC2::Error SetColorMode(ColorMode mode);
+  virtual HWC2::Error SetColorModeWithRenderIntent(ColorMode mode, RenderIntent intent);
 
  private:
   HWCDisplayExternal(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index 36050d2..e285c04 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -250,8 +250,7 @@
   return status;
 }
 
-HWC2::Error HWCDisplayPrimary::GetColorModes(uint32_t *out_num_modes,
-                                             android_color_mode_t *out_modes) {
+HWC2::Error HWCDisplayPrimary::GetColorModes(uint32_t *out_num_modes, ColorMode *out_modes) {
   if (out_modes == nullptr) {
     *out_num_modes = color_mode_->GetColorModeCount();
   } else {
@@ -261,16 +260,28 @@
   return HWC2::Error::None;
 }
 
-HWC2::Error HWCDisplayPrimary::SetColorMode(android_color_mode_t mode) {
-  auto status = color_mode_->SetColorMode(mode);
+HWC2::Error HWCDisplayPrimary::GetRenderIntents(ColorMode mode, uint32_t *out_num_intents,
+                                                RenderIntent *out_intents) {
+  if (out_intents == nullptr) {
+    *out_num_intents = color_mode_->GetRenderIntentCount(mode);
+  } else {
+    color_mode_->GetRenderIntents(mode, out_num_intents, out_intents);
+  }
+  return HWC2::Error::None;
+}
+
+HWC2::Error HWCDisplayPrimary::SetColorMode(ColorMode mode) {
+  return SetColorModeWithRenderIntent(mode, RenderIntent::COLORIMETRIC);
+}
+
+HWC2::Error HWCDisplayPrimary::SetColorModeWithRenderIntent(ColorMode mode, RenderIntent intent) {
+  auto status = color_mode_->SetColorModeWithRenderIntent(mode, intent);
   if (status != HWC2::Error::None) {
-    DLOGE("failed for mode = %d", mode);
+    DLOGE("failed for mode = %d intent = %d", mode, intent);
     return status;
   }
-
   callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
   validated_ = false;
-
   return status;
 }
 
diff --git a/sdm/libs/hwc2/hwc_display_primary.h b/sdm/libs/hwc2/hwc_display_primary.h
index c561f4c..8957855 100644
--- a/sdm/libs/hwc2/hwc_display_primary.h
+++ b/sdm/libs/hwc2/hwc_display_primary.h
@@ -55,8 +55,11 @@
   virtual int Init();
   virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
   virtual HWC2::Error Present(int32_t *out_retire_fence);
-  virtual HWC2::Error GetColorModes(uint32_t *out_num_modes, android_color_mode_t *out_modes);
-  virtual HWC2::Error SetColorMode(android_color_mode_t mode);
+  virtual HWC2::Error GetColorModes(uint32_t *out_num_modes, ColorMode *out_modes);
+  virtual HWC2::Error SetColorMode(ColorMode mode);
+  virtual HWC2::Error GetRenderIntents(ColorMode mode, uint32_t *out_num_intents,
+                                       RenderIntent *out_intents);
+  virtual HWC2::Error SetColorModeWithRenderIntent(ColorMode mode, RenderIntent intent);
   virtual HWC2::Error SetColorModeById(int32_t color_mode_id);
   virtual HWC2::Error SetColorTransform(const float *matrix, android_color_transform_t hint);
   virtual HWC2::Error RestoreColorTransform();
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index 7aac16f..840119e 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -517,6 +517,56 @@
   return HWC2::Error::None;
 }
 
+HWC2::Error HWCLayer::SetLayerPerFrameMetadata(uint32_t num_elements,
+                                               const PerFrameMetadataKey *keys,
+                                               const float *metadata) {
+  auto &mastering_display = layer_->input_buffer.color_metadata.masteringDisplayInfo;
+  auto &content_light = layer_->input_buffer.color_metadata.contentLightLevel;
+  for (uint32_t i = 0; i < num_elements; i++) {
+    switch (keys[i]) {
+      case PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X:
+        mastering_display.colorVolumeSEIEnabled = true;
+        mastering_display.primaries.rgbPrimaries[0][0] = UINT32(metadata[i] * 50000);
+        break;
+      case PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y:
+        mastering_display.primaries.rgbPrimaries[0][1] = UINT32(metadata[i] * 50000);
+        break;
+      case PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X:
+        mastering_display.primaries.rgbPrimaries[1][0] = UINT32(metadata[i] * 50000);
+        break;
+      case PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y:
+        mastering_display.primaries.rgbPrimaries[1][1] = UINT32(metadata[i] * 50000);
+        break;
+      case PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X:
+        mastering_display.primaries.rgbPrimaries[2][0] = UINT32(metadata[i] * 50000);
+        break;
+      case PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y:
+        mastering_display.primaries.rgbPrimaries[2][1] = UINT32(metadata[i] * 50000);
+        break;
+      case PerFrameMetadataKey::WHITE_POINT_X:
+        mastering_display.primaries.whitePoint[0] = UINT32(metadata[i] * 50000);
+        break;
+      case PerFrameMetadataKey::WHITE_POINT_Y:
+        mastering_display.primaries.whitePoint[1] = UINT32(metadata[i] * 50000);
+        break;
+      case PerFrameMetadataKey::MAX_LUMINANCE:
+        mastering_display.maxDisplayLuminance = UINT32(metadata[i]);
+        break;
+      case PerFrameMetadataKey::MIN_LUMINANCE:
+        mastering_display.minDisplayLuminance = UINT32(metadata[i] * 10000);
+        break;
+      case PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL:
+        content_light.lightLevelSEIEnabled = true;
+        content_light.maxContentLightLevel = UINT32(metadata[i]);
+        break;
+      case PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL:
+        content_light.minPicAverageLightLevel = UINT32(metadata[i] * 10000);
+        break;
+    }
+  }
+  return HWC2::Error::None;
+}
+
 void HWCLayer::SetRect(const hwc_rect_t &source, LayerRect *target) {
   target->left = FLOAT(source.left);
   target->top = FLOAT(source.top);
diff --git a/sdm/libs/hwc2/hwc_layers.h b/sdm/libs/hwc2/hwc_layers.h
index 0b08bb5..d72f07f 100644
--- a/sdm/libs/hwc2/hwc_layers.h
+++ b/sdm/libs/hwc2/hwc_layers.h
@@ -32,12 +32,16 @@
 #include <hardware/hwcomposer2.h>
 #undef HWC2_INCLUDE_STRINGIFICATION
 #undef HWC2_USE_CPP11
-#include <map>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
 #include <deque>
+#include <map>
 #include <set>
 #include "core/buffer_allocator.h"
 #include "hwc_buffer_allocator.h"
 
+using PerFrameMetadataKey =
+    android::hardware::graphics::composer::V2_2::IComposerClient::PerFrameMetadataKey;
+
 namespace sdm {
 
 DisplayError SetCSC(const private_handle_t *pvt_handle, ColorMetaData *color_metadata);
@@ -83,6 +87,8 @@
   HWC2::Error SetLayerSurfaceDamage(hwc_region_t damage);
   HWC2::Error SetLayerTransform(HWC2::Transform transform);
   HWC2::Error SetLayerVisibleRegion(hwc_region_t visible);
+  HWC2::Error SetLayerPerFrameMetadata(uint32_t num_elements, const PerFrameMetadataKey *keys,
+                                       const float *metadata);
   HWC2::Error SetLayerZOrder(uint32_t z);
   void SetComposition(const LayerComposition &sdm_composition);
   HWC2::Composition GetClientRequestedCompositionType() { return client_requested_; }
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 237343f..10482ae 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -17,26 +17,27 @@
  * limitations under the License.
  */
 
-#include <core/buffer_allocator.h>
-#include <private/color_params.h>
-#include <utils/constants.h>
-#include <utils/String16.h>
-#include <cutils/properties.h>
-#include <hardware_legacy/uevent.h>
-#include <sys/resource.h>
-#include <sys/prctl.h>
-#include <binder/Parcel.h>
 #include <QService.h>
+#include <binder/Parcel.h>
+#include <core/buffer_allocator.h>
+#include <cutils/properties.h>
 #include <display_config.h>
-#include <utils/debug.h>
-#include <sync/sync.h>
+#include <hardware_legacy/uevent.h>
+#include <private/color_params.h>
 #include <qd_utils.h>
+#include <sync/sync.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <utils/String16.h>
+#include <utils/constants.h>
+#include <utils/debug.h>
 #include <utils/utils.h>
 #include <algorithm>
-#include <string>
 #include <bitset>
-#include <thread>
 #include <memory>
+#include <string>
+#include <thread>
+#include <vector>
 
 #include "hwc_buffer_allocator.h"
 #include "hwc_buffer_sync_handler.h"
@@ -440,8 +441,8 @@
 }
 
 static int32_t GetColorModes(hwc2_device_t *device, hwc2_display_t display, uint32_t *out_num_modes,
-                             int32_t /*android_color_mode_t*/ *int_out_modes) {
-  auto out_modes = reinterpret_cast<android_color_mode_t *>(int_out_modes);
+                             int32_t /*ColorMode*/ *int_out_modes) {
+  auto out_modes = reinterpret_cast<ColorMode *>(int_out_modes);
   if (out_num_modes == nullptr) {
     return HWC2_ERROR_BAD_PARAMETER;
   }
@@ -449,6 +450,80 @@
                                          out_modes);
 }
 
+static int32_t GetRenderIntents(hwc2_device_t *device, hwc2_display_t display,
+                                int32_t /*ColorMode*/ int_mode, uint32_t *out_num_intents,
+                                int32_t /*RenderIntent*/ *int_out_intents) {
+  auto mode = static_cast<ColorMode>(int_mode);
+  auto out_intents = reinterpret_cast<RenderIntent *>(int_out_intents);
+  if (out_num_intents == nullptr) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+  return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetRenderIntents, mode,
+                                         out_num_intents, out_intents);
+}
+
+static int32_t GetDataspaceSaturationMatrix(hwc2_device_t *device,
+                                            int32_t /*Dataspace*/ int_dataspace,
+                                            float *out_matrix) {
+  auto dataspace = static_cast<Dataspace>(int_dataspace);
+  if (device == nullptr || out_matrix == nullptr || dataspace != Dataspace::SRGB_LINEAR) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+  // We only have the matrix for sRGB
+  float saturation_matrix[kDataspaceSaturationMatrixCount] = { 1.0, 0.0, 0.0, 0.0, \
+                                                               0.0, 1.0, 0.0, 0.0, \
+                                                               0.0, 0.0, 1.0, 0.0, \
+                                                               0.0, 0.0, 0.0, 1.0 };
+
+  // TODO(user): This value should ideally be retrieved from a QDCM configuration file
+  char value[kPropertyMax] = {};
+  if (Debug::Get()->GetProperty(DATASPACE_SATURATION_MATRIX_PROP, value) != kErrorNone) {
+    DLOGW("Undefined saturation matrix");
+    return HWC2_ERROR_BAD_CONFIG;
+  }
+  std::string value_string(value);
+  std::size_t start = 0, end = 0;
+  int index = 0;
+  while ((end = value_string.find(",", start)) != std::string::npos) {
+    saturation_matrix[index] = std::stof(value_string.substr(start, end - start));
+    start = end + 1;
+    index++;
+    // We expect a 3x3, SF needs 4x4, keep the last row/column identity
+    if ((index + 1) % 4 == 0) {
+      index++;
+    }
+  }
+  saturation_matrix[index] = std::stof(value_string.substr(start, end - start));
+  if (index < kDataspaceSaturationPropertyElements - 1) {
+    // The property must have kDataspaceSaturationPropertyElements delimited by commas
+    DLOGW("Invalid saturation matrix defined");
+    return HWC2_ERROR_BAD_CONFIG;
+  }
+  for (int32_t i = 0; i < kDataspaceSaturationMatrixCount; i += 4) {
+    DLOGD("%f %f %f %f", saturation_matrix[i], saturation_matrix[i + 1], saturation_matrix[i + 2],
+          saturation_matrix[i + 3]);
+  }
+  for (uint32_t i = 0; i < kDataspaceSaturationMatrixCount; i++) {
+    out_matrix[i] = saturation_matrix[i];
+  }
+  return HWC2_ERROR_NONE;
+}
+
+static int32_t GetPerFrameMetadataKeys(hwc2_device_t *device, hwc2_display_t display,
+                                       uint32_t *out_num_keys, int32_t *int_out_keys) {
+  auto out_keys = reinterpret_cast<PerFrameMetadataKey *>(int_out_keys);
+  return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetPerFrameMetadataKeys,
+                                         out_num_keys, out_keys);
+}
+
+static int32_t SetLayerPerFrameMetadata(hwc2_device_t *device, hwc2_display_t display,
+                                        hwc2_layer_t layer, uint32_t num_elements,
+                                        const int32_t *int_keys, const float *metadata) {
+  auto keys = reinterpret_cast<const PerFrameMetadataKey *>(int_keys);
+  return HWCSession::CallLayerFunction(device, display, layer, &HWCLayer::SetLayerPerFrameMetadata,
+                                       num_elements, keys, metadata);
+}
+
 static int32_t GetDisplayAttribute(hwc2_device_t *device, hwc2_display_t display,
                                    hwc2_config_t config, int32_t int_attribute,
                                    int32_t *out_value) {
@@ -598,14 +673,26 @@
 }
 
 int32_t HWCSession::SetColorMode(hwc2_device_t *device, hwc2_display_t display,
-                                 int32_t /*android_color_mode_t*/ int_mode) {
-  if (int_mode < HAL_COLOR_MODE_NATIVE || int_mode > HAL_COLOR_MODE_DISPLAY_P3) {
+                                 int32_t /*ColorMode*/ int_mode) {
+  auto mode = static_cast<ColorMode>(int_mode);
+  if (mode < ColorMode::NATIVE || mode > ColorMode::BT2100_HLG) {
     return HWC2_ERROR_BAD_PARAMETER;
   }
-  auto mode = static_cast<android_color_mode_t>(int_mode);
   return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetColorMode, mode);
 }
 
+int32_t HWCSession::SetColorModeWithRenderIntent(hwc2_device_t *device, hwc2_display_t display,
+                                                 int32_t /*ColorMode*/ int_mode,
+                                                 int32_t /*RenderIntent*/ int_render_intent) {
+  auto mode = static_cast<ColorMode>(int_mode);
+  if (mode < ColorMode::NATIVE || mode > ColorMode::BT2100_HLG) {
+    return HWC2_ERROR_BAD_PARAMETER;
+  }
+  auto render_intent = static_cast<RenderIntent>(int_render_intent);
+  return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetColorModeWithRenderIntent,
+                                         mode, render_intent);
+}
+
 int32_t HWCSession::SetColorTransform(hwc2_device_t *device, hwc2_display_t display,
                                       const float *matrix,
                                       int32_t /*android_color_transform_t*/ hint) {
@@ -892,6 +979,17 @@
       return AsFP<HWC2_PFN_GET_READBACK_BUFFER_ATTRIBUTES>(HWCSession::GetReadbackBufferAttributes);
     case HWC2::FunctionDescriptor::GetReadbackBufferFence:
       return AsFP<HWC2_PFN_GET_READBACK_BUFFER_FENCE>(HWCSession::GetReadbackBufferFence);
+    case HWC2::FunctionDescriptor::GetRenderIntents:
+      return AsFP<HWC2_PFN_GET_RENDER_INTENTS>(GetRenderIntents);
+    case HWC2::FunctionDescriptor::SetColorModeWithRenderIntent:
+      return AsFP<HWC2_PFN_SET_COLOR_MODE_WITH_RENDER_INTENT>(
+          HWCSession::SetColorModeWithRenderIntent);
+    case HWC2::FunctionDescriptor::GetDataspaceSaturationMatrix:
+      return AsFP<HWC2_PFN_GET_DATASPACE_SATURATION_MATRIX>(GetDataspaceSaturationMatrix);
+    case HWC2::FunctionDescriptor::GetPerFrameMetadataKeys:
+      return AsFP<HWC2_PFN_GET_PER_FRAME_METADATA_KEYS>(GetPerFrameMetadataKeys);
+    case HWC2::FunctionDescriptor::SetLayerPerFrameMetadata:
+      return AsFP<HWC2_PFN_SET_LAYER_PER_FRAME_METADATA>(SetLayerPerFrameMetadata);
     default:
       DLOGD("Unknown/Unimplemented function descriptor: %d (%s)", int_descriptor,
             to_string(descriptor).c_str());
@@ -1202,6 +1300,14 @@
       status = SetColorModeOverride(input_parcel);
       break;
 
+    case qService::IQService::SET_COLOR_MODE_WITH_RENDER_INTENT:
+      if (!input_parcel) {
+        DLOGE("QService command = %d: input_parcel needed.", command);
+        break;
+      }
+      status = SetColorModeWithRenderIntentOverride(input_parcel);
+      break;
+
     case qService::IQService::SET_COLOR_MODE_BY_ID:
       if (!input_parcel) {
         DLOGE("QService command = %d: input_parcel needed.", command);
@@ -1394,7 +1500,7 @@
 
 android::status_t HWCSession::SetColorModeOverride(const android::Parcel *input_parcel) {
   auto display = static_cast<hwc2_display_t >(input_parcel->readInt32());
-  auto mode = static_cast<android_color_mode_t>(input_parcel->readInt32());
+  auto mode = static_cast<ColorMode>(input_parcel->readInt32());
   auto device = static_cast<hwc2_device_t *>(this);
 
   auto err = CallDisplayFunction(device, display, &HWCDisplay::SetColorMode, mode);
@@ -1404,6 +1510,20 @@
   return 0;
 }
 
+android::status_t HWCSession::SetColorModeWithRenderIntentOverride(
+    const android::Parcel *input_parcel) {
+  auto display = static_cast<hwc2_display_t>(input_parcel->readInt32());
+  auto mode = static_cast<ColorMode>(input_parcel->readInt32());
+  auto intent = static_cast<RenderIntent>(input_parcel->readInt32());
+  auto device = static_cast<hwc2_device_t *>(this);
+
+  auto err =
+      CallDisplayFunction(device, display, &HWCDisplay::SetColorModeWithRenderIntent, mode, intent);
+  if (err != HWC2_ERROR_NONE)
+    return -EINVAL;
+
+  return 0;
+}
 android::status_t HWCSession::SetColorModeById(const android::Parcel *input_parcel) {
   auto display = static_cast<hwc2_display_t >(input_parcel->readInt32());
   auto mode = input_parcel->readInt32();
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index f74179b..119c931 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -73,6 +73,10 @@
   bool init_done_ = false;
 };
 
+constexpr int32_t kDataspaceSaturationMatrixCount = 16;
+constexpr int32_t kDataspaceSaturationPropertyElements = 9;
+constexpr int32_t kPropertyMax = 256;
+
 class HWCSession : hwc2_device_t, HWCUEventListener, IDisplayConfig, public qClient::BnQClient,
                    public HWCDisplayEventHandler {
  public:
@@ -161,7 +165,10 @@
   static int32_t ValidateDisplay(hwc2_device_t *device, hwc2_display_t display,
                                  uint32_t *out_num_types, uint32_t *out_num_requests);
   static int32_t SetColorMode(hwc2_device_t *device, hwc2_display_t display,
-                              int32_t /*android_color_mode_t*/ int_mode);
+                              int32_t /*ColorMode*/ int_mode);
+  static int32_t SetColorModeWithRenderIntent(hwc2_device_t *device, hwc2_display_t display,
+                                              int32_t /*ColorMode*/ int_mode,
+                                              int32_t /*RenderIntent*/ int_render_intent);
   static int32_t SetColorTransform(hwc2_device_t *device, hwc2_display_t display,
                                    const float *matrix, int32_t /*android_color_transform_t*/ hint);
   static int32_t GetReadbackBufferAttributes(hwc2_device_t *device, hwc2_display_t display,
@@ -258,6 +265,7 @@
                                           android::Parcel *output_parcel);
   android::status_t SetMixerResolution(const android::Parcel *input_parcel);
   android::status_t SetColorModeOverride(const android::Parcel *input_parcel);
+  android::status_t SetColorModeWithRenderIntentOverride(const android::Parcel *input_parcel);
 
   android::status_t SetColorModeById(const android::Parcel *input_parcel);
   android::status_t getComposerStatus();