Merge "hwc2: Use floating value refresh rate"
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index dfea4c8..3e0896f 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -34,6 +34,8 @@
 #define __DISPLAY_INTERFACE_H__
 
 #include <stdint.h>
+#include <string>
+#include <vector>
 
 #include "layer_stack.h"
 #include "sdm_types.h"
@@ -412,6 +414,41 @@
                                             PPDisplayAPIPayload *out_payload,
                                             PPPendingParams *pending_action) = 0;
 
+  /*! @brief Method to request the number of color modes supported.
+
+    @param[out] mode_count Number of modes
+
+    @return \link DisplayError \endlink
+  */
+  virtual DisplayError GetColorModeCount(uint32_t *mode_count) = 0;
+
+  /*! @brief Method to request the information of supported color modes.
+
+    @param[inout] mode_count Number of updated modes
+    @param[out] vector of mode strings
+
+    @return \link DisplayError \endlink
+  */
+  virtual DisplayError GetColorModes(uint32_t *mode_count,
+                                     std::vector<std::string> *color_modes) = 0;
+
+  /*! @brief Method to set the color mode
+
+    @param[in] mode_name Mode name which needs to be set
+
+    @return \link DisplayError \endlink
+  */
+  virtual DisplayError SetColorMode(const std::string &color_mode) = 0;
+
+  /*! @brief Method to set the color transform
+
+    @param[in] length Mode name which needs to be set
+    @param[in] color_transform  4x4 Matrix for color transform
+
+    @return \link DisplayError \endlink
+  */
+  virtual DisplayError SetColorTransform(const uint32_t length, const double *color_transform) = 0;
+
   /*! @brief Method to request applying default display mode.
 
     @return \link DisplayError \endlink
diff --git a/sdm/include/private/color_interface.h b/sdm/include/private/color_interface.h
index b84bcab..cc7eac3 100644
--- a/sdm/include/private/color_interface.h
+++ b/sdm/include/private/color_interface.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2015-2016, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -60,6 +60,20 @@
 
   virtual DisplayError ApplyDefaultDisplayMode(PPFeaturesConfig *out_features) = 0;
 
+  virtual DisplayError ColorIntfSetColorTransform(PPFeaturesConfig *out_features,
+                                                uint32_t disp_id, uint32_t length,
+                                                const double *trans_data) = 0;
+
+  virtual DisplayError ColorIntfSetDisplayMode(PPFeaturesConfig *out_features,
+                                             uint32_t disp_id, int32_t mode_id) = 0;
+
+  virtual DisplayError ColorIntfGetNumDisplayModes(PPFeaturesConfig *out_features,
+                                                 uint32_t disp_id, uint32_t *mode_cnt) = 0;
+
+  virtual DisplayError ColorIntfEnumerateDisplayModes(PPFeaturesConfig *out_features,
+                                                uint32_t disp_id, SDEDisplayMode *modes,
+                                                uint32_t *mode_cnt) = 0;
+
  protected:
   virtual ~ColorInterface() {}
 };
diff --git a/sdm/include/private/color_params.h b/sdm/include/private/color_params.h
index 9eb5d79..8bca55f 100644
--- a/sdm/include/private/color_params.h
+++ b/sdm/include/private/color_params.h
@@ -315,6 +315,13 @@
   uint32_t *c2_data = NULL;
 };
 
+struct SDEDisplayMode {
+  static const int kMaxModeNameSize = 256;
+  int32_t id = -1;
+  uint32_t type = 0;
+  char name[kMaxModeNameSize] = {0};
+};
+
 // Wrapper on HW block config data structure to encapsulate the details of allocating
 // and destroying from the caller.
 class SDEGamutCfgWrapper : private SDEGamutCfg {
diff --git a/sdm/libs/core/color_manager.cpp b/sdm/libs/core/color_manager.cpp
index 7b8a1ca..f24a920 100644
--- a/sdm/libs/core/color_manager.cpp
+++ b/sdm/libs/core/color_manager.cpp
@@ -219,4 +219,22 @@
   }
 }
 
+DisplayError ColorManagerProxy::ColorMgrGetNumOfModes(uint32_t *mode_cnt) {
+  return color_intf_->ColorIntfGetNumDisplayModes(&pp_features_, 0, mode_cnt);
+}
+
+DisplayError ColorManagerProxy::ColorMgrGetModes(uint32_t *mode_cnt,
+                                                 SDEDisplayMode *modes) {
+  return color_intf_->ColorIntfEnumerateDisplayModes(&pp_features_, 0, modes, mode_cnt);
+}
+
+DisplayError ColorManagerProxy::ColorMgrSetMode(int32_t color_mode_id) {
+  return color_intf_->ColorIntfSetDisplayMode(&pp_features_, 0, color_mode_id);
+}
+
+DisplayError ColorManagerProxy::ColorMgrSetColorTransform(uint32_t length,
+                                                          const double *trans_data) {
+  return color_intf_->ColorIntfSetColorTransform(&pp_features_, 0, length, trans_data);
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/color_manager.h b/sdm/libs/core/color_manager.h
index fb2bbf5..9f9eb40 100644
--- a/sdm/libs/core/color_manager.h
+++ b/sdm/libs/core/color_manager.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2015-2016, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -65,6 +65,10 @@
                                     PPDisplayAPIPayload *out_payload,
                                     PPPendingParams *pending_action);
   DisplayError ApplyDefaultDisplayMode();
+  DisplayError ColorMgrGetNumOfModes(uint32_t *mode_cnt);
+  DisplayError ColorMgrGetModes(uint32_t *mode_cnt, SDEDisplayMode *modes);
+  DisplayError ColorMgrSetMode(int32_t color_mode_id);
+  DisplayError ColorMgrSetColorTransform(uint32_t length, const double *trans_data);
   bool NeedsPartialUpdateDisable();
   DisplayError Commit();
 
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 5523ff2..361ded8 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -28,6 +28,7 @@
 #include <utils/formats.h>
 #include <utils/rect.h>
 
+#include <string>
 #include <vector>
 
 #include "display_base.h"
@@ -111,6 +112,10 @@
     rotator_intf_->UnregisterDisplay(display_rotator_ctx_);
   }
 
+  if (color_modes_) {
+    delete[] color_modes_;
+  }
+
   if (color_mgr_) {
     delete color_mgr_;
     color_mgr_ = NULL;
@@ -708,6 +713,105 @@
     return kErrorParameters;
 }
 
+DisplayError DisplayBase::GetColorModeCount(uint32_t *mode_count) {
+  if (!mode_count) {
+    return kErrorParameters;
+  }
+
+  if (!color_mgr_) {
+    return kErrorNotSupported;
+  }
+
+  DisplayError error = color_mgr_->ColorMgrGetNumOfModes(&num_color_modes_);
+  if (error != kErrorNone || !num_color_modes_) {
+    return kErrorNotSupported;
+  }
+
+  DLOGI("Number of color modes = %d", num_color_modes_);
+  *mode_count = num_color_modes_;
+
+  return kErrorNone;
+}
+
+DisplayError DisplayBase::GetColorModes(uint32_t *mode_count,
+                                        std::vector<std::string> *color_modes) {
+  if (!mode_count || !color_modes) {
+    return kErrorParameters;
+  }
+
+  if (!color_mgr_) {
+    return kErrorNotSupported;
+  }
+
+  if (color_modes_ == NULL) {
+    color_modes_ = new SDEDisplayMode[num_color_modes_];
+
+    DisplayError error = color_mgr_->ColorMgrGetModes(&num_color_modes_, color_modes_);
+    if (error != kErrorNone) {
+      DLOGE("Failed");
+      return error;
+    }
+    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_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
+    }
+  }
+
+  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;
+  }
+
+  return kErrorNone;
+}
+
+DisplayError DisplayBase::SetColorMode(const std::string &color_mode) {
+  if (!color_mgr_) {
+    return kErrorNotSupported;
+  }
+
+  DLOGV_IF(kTagQDCM, "Color Mode = %s", color_mode.c_str());
+
+  ColorModeMap::iterator it = color_mode_map_.find(color_mode);
+  if (it == color_mode_map_.end()) {
+    DLOGE("Failed: Unknown Mode : %s", color_mode.c_str());
+    return kErrorNotSupported;
+  }
+
+  SDEDisplayMode *sde_display_mode = it->second;
+  if (color_mode_ == sde_display_mode->id) {
+    DLOGV_IF(kTagQDCM, "Same mode requested");
+    return kErrorNone;
+  }
+
+  DLOGV_IF(kTagQDCM, "Color Mode Name = %s corresponding mode_id = %d", sde_display_mode->name,
+           sde_display_mode->id);
+  DisplayError error = kErrorNone;
+  error = color_mgr_->ColorMgrSetMode(sde_display_mode->id);
+  if (error != kErrorNone) {
+    DLOGE("Failed for mode id = %d", sde_display_mode->id);
+    return error;
+  }
+
+  color_mode_ = sde_display_mode->id;
+
+  return error;
+}
+
+DisplayError DisplayBase::SetColorTransform(const uint32_t length, const double *color_transform) {
+  if (!color_mgr_) {
+    return kErrorNotSupported;
+  }
+
+  if (!color_transform) {
+    return kErrorParameters;
+  }
+
+  return color_mgr_->ColorMgrSetColorTransform(length, color_transform);
+}
+
 DisplayError DisplayBase::ApplyDefaultDisplayMode() {
   if (color_mgr_)
     return color_mgr_->ApplyDefaultDisplayMode();
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 0f316fd..d771342 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -31,6 +31,10 @@
 #include <private/color_interface.h>
 #include <utils/locker.h>
 
+#include <map>
+#include <string>
+#include <vector>
+
 #include "hw_interface.h"
 #include "comp_manager.h"
 #include "color_manager.h"
@@ -72,6 +76,10 @@
   virtual DisplayError ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload,
                                             PPDisplayAPIPayload *out_payload,
                                             PPPendingParams *pending_action);
+  virtual DisplayError GetColorModeCount(uint32_t *mode_count);
+  virtual DisplayError GetColorModes(uint32_t *mode_count, std::vector<std::string> *color_modes);
+  virtual DisplayError SetColorMode(const std::string &color_mode);
+  virtual DisplayError SetColorTransform(const uint32_t length, const double *color_transform);
   virtual DisplayError ApplyDefaultDisplayMode(void);
   virtual DisplayError SetCursorPosition(int x, int y);
   virtual DisplayError GetRefreshRateRange(uint32_t *min_refresh_rate, uint32_t *max_refresh_rate);
@@ -122,6 +130,11 @@
   bool partial_update_control_ = true;
   HWEventsInterface *hw_events_intf_ = NULL;
   bool disable_pu_one_frame_ = false;
+  uint32_t num_color_modes_ = 0;
+  SDEDisplayMode *color_modes_ = NULL;
+  int32_t color_mode_ = 0;
+  typedef std::map<std::string, SDEDisplayMode *> ColorModeMap;
+  ColorModeMap color_mode_map_ = {};
 
  private:
   // Unused
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index eb477d0..f687731 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -17,20 +17,23 @@
  * limitations under the License.
  */
 
-#include <math.h>
+#include <cutils/properties.h>
 #include <errno.h>
-#include <gralloc_priv.h>
 #include <gr.h>
+#include <gralloc_priv.h>
+#include <math.h>
+#include <sync/sync.h>
 #include <utils/constants.h>
+#include <utils/debug.h>
 #include <utils/formats.h>
 #include <utils/rect.h>
-#include <utils/debug.h>
-#include <sync/sync.h>
-#include <cutils/properties.h>
+
+#include <algorithm>
 #include <map>
-#include <string>
 #include <sstream>
+#include <string>
 #include <utility>
+#include <vector>
 
 #include "hwc_display.h"
 #include "hwc_debugger.h"
@@ -53,6 +56,155 @@
   }
 }
 
+HWCColorMode::HWCColorMode(DisplayInterface *display_intf) : display_intf_(display_intf) {}
+
+HWC2::Error HWCColorMode::Init() {
+  PopulateColorModes();
+  return HWC2::Error::None;
+}
+
+HWC2::Error HWCColorMode::DeInit() {
+  color_mode_transform_map_.clear();
+  return HWC2::Error::None;
+}
+
+uint32_t HWCColorMode::GetColorModeCount() {
+  uint32_t count = UINT32(color_mode_transform_map_.size());
+  DLOGI("Supported color mode count = %d", count);
+
+  return std::max(1U, count);
+}
+
+HWC2::Error HWCColorMode::GetColorModes(uint32_t *out_num_modes,
+                                        int32_t /*android_color_mode_t*/ *out_modes) {
+  auto it = color_mode_transform_map_.begin();
+  for (auto i = 0; it != color_mode_transform_map_.end(); it++, i++) {
+    out_modes[i] = it->first;
+    DLOGI("Supports color mode[%d] = %d", i, it->first);
+  }
+  *out_num_modes = UINT32(color_mode_transform_map_.size());
+  return HWC2::Error::None;
+}
+
+HWC2::Error HWCColorMode::SetColorMode(int32_t /*android_color_mode_t*/ mode) {
+  // first mode in 2D matrix is the mode (identity)
+  auto status = HandleColorModeTransform(mode, current_color_transform_, color_matrix_);
+  if (status != HWC2::Error::None) {
+    DLOGE("failed for mode = %d", mode);
+  }
+
+  return status;
+}
+
+HWC2::Error HWCColorMode::SetColorTransform(const float *matrix, android_color_transform_t hint) {
+  if (!matrix) {
+    return HWC2::Error::BadParameter;
+  }
+
+  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);
+  }
+
+  return status;
+}
+
+HWC2::Error HWCColorMode::HandleColorModeTransform(int32_t /*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
+    color_mode_transform = color_mode_transform_map_[mode][hint];
+    if (color_mode_transform.empty()) {
+      transform_hint = HAL_COLOR_TRANSFORM_IDENTITY;
+      use_matrix = true;
+    }
+  } else {
+    use_matrix = true;
+    transform_hint = HAL_COLOR_TRANSFORM_IDENTITY;
+  }
+
+  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);
+    // TODO(user): make use client composition
+    return HWC2::Error::Unsupported;
+  }
+
+  if (use_matrix) {
+    DisplayError error = display_intf_->SetColorTransform(kColorTransformMatrixCount, matrix);
+    if (error != kErrorNone) {
+      DLOGE("Failed to set Color Transform Matrix");
+      // TODO(user): make use client composition
+      return HWC2::Error::Unsupported;
+    }
+  }
+
+  current_color_mode_ = mode;
+  current_color_transform_ = hint;
+  CopyColorTransformMatrix(matrix, color_matrix_);
+  DLOGI("Setting Color Mode = %d Transform Hint = %d Success", mode, hint);
+
+  return HWC2::Error::None;
+}
+
+void HWCColorMode::PopulateColorModes() {
+  uint32_t color_mode_count = 0;
+  // SDM returns modes which is string combination of mode + transform.
+  DisplayError error = display_intf_->GetColorModeCount(&color_mode_count);
+  if (error != kErrorNone || (color_mode_count == 0)) {
+    DLOGW("GetColorModeCount failed, use native color mode");
+    PopulateTransform(0, "native_identity");
+    return;
+  }
+
+  DLOGI("Color Modes supported count = %d", color_mode_count);
+
+  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++) {
+    std::string &mode_string = color_modes.at(i);
+    DLOGI("Color Mode[%d] = %s", i, mode_string.c_str());
+    if (mode_string.find("native") != std::string::npos) {
+      // TODO(user): replace numbers(0,1..) with android_color_mode_t
+      PopulateTransform(0, mode_string);
+    } else if (mode_string.find("srgb") != std::string::npos) {
+      PopulateTransform(1, mode_string);
+    } else if (mode_string.find("adobe") != std::string::npos) {
+      PopulateTransform(2, mode_string);
+    } else if (mode_string.find("dci3") != std::string::npos) {
+      PopulateTransform(3, mode_string);
+    }
+  }
+}
+
+void HWCColorMode::PopulateTransform(const int32_t &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_transform;
+  } else if (color_transform.find("artitrary") != 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_transform;
+  } else if (color_transform.find("grayscale") != std::string::npos) {
+    color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_GRAYSCALE] = color_transform;
+  } else if (color_transform.find("correct_protonopia") != std::string::npos) {
+    color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_CORRECT_PROTANOPIA] = color_transform;
+  } else if (color_transform.find("correct_deuteranopia") != std::string::npos) {
+    color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_CORRECT_DEUTERANOPIA] = color_transform;
+  } else if (color_transform.find("correct_tritanopia") != std::string::npos) {
+    color_mode_transform_map_[mode][HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA] = color_transform;
+  }
+}
+
 HWCDisplay::HWCDisplay(CoreInterface *core_intf, HWCCallbacks *callbacks, DisplayType type,
                        hwc2_display_t id, bool needs_blit, qService::QService *qservice,
                        DisplayClass display_class)
@@ -124,6 +276,11 @@
     blit_engine_ = NULL;
   }
 
+  if (color_mode_) {
+    color_mode_->DeInit();
+    delete color_mode_;
+  }
+
   return 0;
 }
 
@@ -353,6 +510,15 @@
   }
 }
 
+HWC2::Error HWCDisplay::GetColorModes(uint32_t *out_num_modes, int32_t *out_modes) {
+  if (out_modes) {
+    out_modes[0] = 0;  // TODO(user): Change to android_color_mode_t
+  }
+  *out_num_modes = 1;
+
+  return HWC2::Error::None;
+}
+
 HWC2::Error HWCDisplay::GetDisplayConfigs(uint32_t *out_num_configs, hwc2_config_t *out_configs) {
   // TODO(user): Actually handle multiple configs
   if (out_configs == nullptr) {
@@ -361,6 +527,7 @@
     *out_num_configs = 1;
     out_configs[0] = 0;
   }
+
   return HWC2::Error::None;
 }
 
@@ -1260,6 +1427,16 @@
   }
 }
 
+void HWCDisplay::MarkLayersForClientComposition() {
+  // ClientComposition - GPU comp, to acheive this, set skip flag so that
+  // SDM does not handle this layer and hwc_layer composition will be
+  // set correctly at the end of Prepare.
+  for (auto hwc_layer : layer_set_) {
+    Layer *layer = hwc_layer->GetSDMLayer();
+    layer->flags.skip = true;
+  }
+}
+
 void HWCDisplay::ApplyScanAdjustment(hwc_rect_t *display_frame) {
 }
 
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 51e7d13..c3ffcb4 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -20,16 +20,18 @@
 #ifndef __HWC_DISPLAY_H__
 #define __HWC_DISPLAY_H__
 
-#include <hardware/hwcomposer.h>
-#include <core/core_interface.h>
-#include <qdMetaData.h>
 #include <QService.h>
+#include <core/core_interface.h>
+#include <hardware/hwcomposer.h>
 #include <private/color_params.h>
+#include <qdMetaData.h>
 #include <map>
+#include <queue>
 #include <set>
 #include <string>
-#include <queue>
 #include <utility>
+#include <vector>
+
 #include "hwc_callbacks.h"
 #include "hwc_layers.h"
 
@@ -46,6 +48,40 @@
   DISPLAY_CLASS_NULL
 };
 
+class HWCColorMode {
+ public:
+  explicit HWCColorMode(DisplayInterface *display_intf);
+  ~HWCColorMode() {}
+  HWC2::Error Init();
+  HWC2::Error DeInit();
+  uint32_t GetColorModeCount();
+  HWC2::Error GetColorModes(uint32_t *out_num_modes, int32_t /*android_color_mode_t*/ *out_modes);
+  HWC2::Error SetColorMode(int32_t /*android_color_mode_t*/ mode);
+  HWC2::Error SetColorTransform(const float *matrix, android_color_transform_t hint);
+
+ private:
+  static const uint32_t kColorTransformMatrixCount = 16;
+
+  HWC2::Error HandleColorModeTransform(int32_t /*android_color_mode_t*/ mode,
+                                       android_color_transform_t hint, const double *matrix);
+  void PopulateColorModes();
+  void PopulateTransform(const int32_t &mode, const std::string &color_mode);
+  template <class T>
+  void CopyColorTransformMatrix(const T *input_matrix, double *output_matrix) {
+    for (uint32_t i = 0; i < kColorTransformMatrixCount; i++) {
+      output_matrix[i] = static_cast<double>(input_matrix[i]);
+    }
+  }
+
+  DisplayInterface *display_intf_ = NULL;
+  int32_t current_color_mode_ = 0;  // android_color_mode_t
+  android_color_transform_t current_color_transform_ = HAL_COLOR_TRANSFORM_IDENTITY;
+  typedef std::map<android_color_transform_t, std::string> TransformMap;
+  // TODO(user): change int32_t to android_color_mode_t when defined
+  std::map<int32_t, TransformMap> color_mode_transform_map_ = {};
+  double color_matrix_[kColorTransformMatrixCount] = {0};
+};
+
 class HWCDisplay : public DisplayEventHandler {
  public:
   virtual ~HWCDisplay() {}
@@ -101,11 +137,23 @@
   virtual HWC2::Error SetActiveConfig(hwc2_config_t config);
   virtual HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence,
                                       int32_t dataspace);
+  virtual HWC2::Error SetColorMode(int32_t /*android_color_mode_t*/ mode) {
+    return HWC2::Error::Unsupported;
+  }
+  virtual HWC2::Error SetColorTransform(const float *matrix, android_color_transform_t hint) {
+    return HWC2::Error::Unsupported;
+  }
+  virtual HWC2::Error HandleColorModeTransform(int32_t /*android_color_mode_t*/ mode,
+                                               android_color_transform_t hint,
+                                               const double *matrix) {
+    return HWC2::Error::Unsupported;
+  }
   virtual HWC2::Error GetDisplayConfigs(uint32_t *out_num_configs, hwc2_config_t *out_configs);
   virtual HWC2::Error GetDisplayAttribute(hwc2_config_t config, HWC2::Attribute attribute,
                                           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, int32_t *outModes);
   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,
@@ -150,6 +198,7 @@
   const char *GetDisplayString();
   void ScaleDisplayFrame(hwc_rect_t *display_frame);
   void MarkLayersForGPUBypass(void);
+  void MarkLayersForClientComposition(void);
   virtual void ApplyScanAdjustment(hwc_rect_t *display_frame);
   bool NeedsFrameBufferRefresh(void);
   bool SingleLayerUpdating(void);
@@ -197,6 +246,8 @@
   uint32_t solid_fill_color_ = 0;
   LayerRect display_rect_;
   bool validated_ = false;
+  bool color_tranform_failed_ = false;
+  HWCColorMode *color_mode_ = NULL;
 
  private:
   bool IsFrameBufferScaled();
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index 40ac723..517959e 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -34,6 +34,10 @@
 #include <stdarg.h>
 #include <sys/mman.h>
 
+#include <map>
+#include <string>
+#include <vector>
+
 #include "hwc_display_primary.h"
 #include "hwc_debugger.h"
 
@@ -103,7 +107,13 @@
     use_metadata_refresh_rate_ = false;
   }
 
-  return HWCDisplay::Init();
+  int status = HWCDisplay::Init();
+  if (status) {
+    return status;
+  }
+  color_mode_ = new HWCColorMode(display_intf_);
+
+  return INT(color_mode_->Init());
 }
 
 void HWCDisplayPrimary::ProcessBootAnimCompleted() {
@@ -153,6 +163,11 @@
     return status;
   }
 
+  if (color_tranform_failed_) {
+    // Must fall back to client composition
+    MarkLayersForClientComposition();
+  }
+
   // Fill in the remaining blanks in the layers and add them to the SDM layerstack
   BuildLayerStack();
 
@@ -213,6 +228,48 @@
   return status;
 }
 
+HWC2::Error HWCDisplayPrimary::GetColorModes(uint32_t *out_num_modes,
+                                             int32_t /*android_color_mode_t*/ *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 HWCDisplayPrimary::SetColorMode(int32_t /*android_color_mode_t*/ mode) {
+  auto status = color_mode_->SetColorMode(mode);
+  if (status != HWC2::Error::None) {
+    DLOGE("failed for mode = %d", mode);
+    return status;
+  }
+
+  callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+
+  return status;
+}
+
+HWC2::Error HWCDisplayPrimary::SetColorTransform(const float *matrix,
+                                                 android_color_transform_t hint) {
+  if (!matrix) {
+    return HWC2::Error::BadParameter;
+  }
+
+  auto status = color_mode_->SetColorTransform(matrix, hint);
+  if (status != HWC2::Error::None) {
+    DLOGE("failed for hint = %d", hint);
+    color_tranform_failed_ = true;
+    return status;
+  }
+
+  callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+  color_tranform_failed_ = false;
+
+  return status;
+}
+
 int HWCDisplayPrimary::Perform(uint32_t operation, ...) {
   va_list args;
   va_start(args, operation);
diff --git a/sdm/libs/hwc2/hwc_display_primary.h b/sdm/libs/hwc2/hwc_display_primary.h
index 2779f1b..62b311e 100644
--- a/sdm/libs/hwc2/hwc_display_primary.h
+++ b/sdm/libs/hwc2/hwc_display_primary.h
@@ -30,6 +30,8 @@
 #ifndef __HWC_DISPLAY_PRIMARY_H__
 #define __HWC_DISPLAY_PRIMARY_H__
 
+#include <string>
+
 #include "cpuhint.h"
 #include "hwc_display.h"
 
@@ -52,6 +54,9 @@
   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, int32_t *out_modes);
+  virtual HWC2::Error SetColorMode(int32_t /*android_color_mode_t*/ mode);
+  virtual HWC2::Error SetColorTransform(const float *matrix, android_color_transform_t hint);
   virtual int Perform(uint32_t operation, ...);
   virtual void SetSecureDisplay(bool secure_display_active);
   virtual DisplayError Refresh();
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 66eeb1e..28e0206 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -307,7 +307,11 @@
                                          width, height, format, dataspace);
 }
 
-// TODO(user): GetColorModes
+static int32_t GetColorModes(hwc2_device_t *device, hwc2_display_t display, uint32_t *out_num_modes,
+                             int32_t /*android_color_mode_t*/ *out_modes) {
+  return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::GetColorModes, out_num_modes,
+                                         out_modes);
+}
 
 static int32_t GetDisplayAttribute(hwc2_device_t *device, hwc2_display_t display,
                                    hwc2_config_t config, int32_t int_attribute,
@@ -418,7 +422,20 @@
                                          acquire_fence, dataspace);
 }
 
-// TODO(user): SetColorMode, SetColorTransform
+int32_t HWCSession::SetColorMode(hwc2_device_t *device, hwc2_display_t display,
+                                 int32_t /*android_color_mode_t*/ mode) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+  return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetColorMode, mode);
+}
+
+int32_t HWCSession::SetColorTransform(hwc2_device_t *device, hwc2_display_t display,
+                                      const float *matrix,
+                                      int32_t /*android_color_transform_t*/ hint) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+  android_color_transform_t transform_hint = static_cast<android_color_transform_t>(hint);
+  return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetColorTransform, matrix,
+                                         transform_hint);
+}
 
 static int32_t SetCursorPosition(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer,
                                  int32_t x, int32_t y) {
@@ -583,8 +600,8 @@
       return AsFP<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(GetChangedCompositionTypes);
     case HWC2::FunctionDescriptor::GetClientTargetSupport:
       return AsFP<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(GetClientTargetSupport);
-    // case HWC2::FunctionDescriptor::GetColorModes:
-    // TODO(user): Support later
+    case HWC2::FunctionDescriptor::GetColorModes:
+      return AsFP<HWC2_PFN_GET_COLOR_MODES>(GetColorModes);
     case HWC2::FunctionDescriptor::GetDisplayAttribute:
       return AsFP<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(GetDisplayAttribute);
     case HWC2::FunctionDescriptor::GetDisplayConfigs:
@@ -611,10 +628,10 @@
       return AsFP<HWC2_PFN_SET_ACTIVE_CONFIG>(SetActiveConfig);
     case HWC2::FunctionDescriptor::SetClientTarget:
       return AsFP<HWC2_PFN_SET_CLIENT_TARGET>(SetClientTarget);
-    // TODO(user): Support later
-    // case HWC2::FunctionDescriptor::SetColorMode:
-    // case HWC2::FunctionDescriptor::SetColorTransform:
-    // break;
+    case HWC2::FunctionDescriptor::SetColorMode:
+      return AsFP<HWC2_PFN_SET_COLOR_MODE>(SetColorMode);
+    case HWC2::FunctionDescriptor::SetColorTransform:
+      return AsFP<HWC2_PFN_SET_COLOR_TRANSFORM>(SetColorTransform);
     case HWC2::FunctionDescriptor::SetCursorPosition:
       return AsFP<HWC2_PFN_SET_CURSOR_POSITION>(SetCursorPosition);
     case HWC2::FunctionDescriptor::SetLayerBlendMode:
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 679619c..a713ab0 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -101,6 +101,10 @@
   static int32_t SetPowerMode(hwc2_device_t *device, hwc2_display_t display, int32_t int_mode);
   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*/ mode);
+  static int32_t SetColorTransform(hwc2_device_t *device, hwc2_display_t display,
+                                   const float *matrix, int32_t /*android_color_transform_t*/ hint);
 
  private:
   static const int kExternalConnectionTimeoutMs = 500;