Merge "sdm:hwc2: Add buffer map to tonemap output buffer"
diff --git a/gpu_tonemapper/Tonemapper.cpp b/gpu_tonemapper/Tonemapper.cpp
index 981863d..811e091 100644
--- a/gpu_tonemapper/Tonemapper.cpp
+++ b/gpu_tonemapper/Tonemapper.cpp
@@ -45,7 +45,6 @@
 Tonemapper::~Tonemapper()
 //-----------------------------------------------------------------------------
 {
-  void* caller_context = engine_backup();
   engine_bind(engineContext);
   engine_deleteInputBuffer(tonemapTexture);
   engine_deleteInputBuffer(lutXformTexture);
@@ -58,9 +57,6 @@
   }
 
   engine_shutdown(engineContext);
-  // restore the caller context
-  engine_bind(caller_context);
-  engine_free_backup(caller_context);
 }
 
 //-----------------------------------------------------------------------------
@@ -78,7 +74,6 @@
 
   tonemapper->engineContext = engine_initialize(isSecure);
 
-  void* caller_context = engine_backup();
   engine_bind(tonemapper->engineContext);
 
   // load the 3d lut
@@ -117,10 +112,6 @@
   tonemapper->programID =
       engine_loadProgram(1, &fullscreen_vertex_shader, fragmentShaderCount, fragmentShaders);
 
-  // restore the caller context
-  engine_bind(caller_context);
-  engine_free_backup(caller_context);
-
   return tonemapper;
 }
 
@@ -128,7 +119,6 @@
 int Tonemapper::blit(const void *dst, const void *src, int srcFenceFd)
 //-----------------------------------------------------------------------------
 {
-  void* caller_context = engine_backup();
   // make current
   engine_bind(engineContext);
 
@@ -159,10 +149,5 @@
   // perform
   int fenceFD = engine_blit(srcFenceFd);
 
-  // restore the caller context
-  engine_bind(caller_context);
-  engine_free_backup(caller_context);
-
-
   return fenceFD;
 }
diff --git a/gpu_tonemapper/engine.h b/gpu_tonemapper/engine.h
index e0bf2aa..8fb9452 100644
--- a/gpu_tonemapper/engine.h
+++ b/gpu_tonemapper/engine.h
@@ -22,8 +22,6 @@
 
 void* engine_initialize(bool isSecure);
 void engine_bind(void*);
-void* engine_backup();
-void engine_free_backup(void*);
 void engine_shutdown(void*);
 
 unsigned int engine_loadProgram(int, const char **, int, const char **);
diff --git a/gpu_tonemapper/glengine.cpp b/gpu_tonemapper/glengine.cpp
index 6cfe15f..6c94c23 100644
--- a/gpu_tonemapper/glengine.cpp
+++ b/gpu_tonemapper/glengine.cpp
@@ -47,27 +47,6 @@
 }
 
 //-----------------------------------------------------------------------------
-// store the current context(caller)
-void* engine_backup()
-{
-  EngineContext* callerContext = new EngineContext();
-  // store the previous display/context
-  callerContext->eglDisplay = eglGetCurrentDisplay();
-  callerContext->eglContext = eglGetCurrentContext();
-  callerContext->eglSurface = eglGetCurrentSurface(EGL_DRAW);
-
-  return (void*)callerContext;
-}
-//-----------------------------------------------------------------------------
-// frees the backed up caller context
-void engine_free_backup(void* context)
-{
-  EngineContext* callerContext = (EngineContext*)(context);
-
-  delete callerContext;
-}
-
-//-----------------------------------------------------------------------------
 // initialize GL
 //
 void* engine_initialize(bool isSecure)
diff --git a/libgralloc1/gralloc_priv.h b/libgralloc1/gralloc_priv.h
index d8dfbf3..87604c6 100644
--- a/libgralloc1/gralloc_priv.h
+++ b/libgralloc1/gralloc_priv.h
@@ -65,7 +65,7 @@
 #define GRALLOC1_CONSUMER_USAGE_PRIVATE_WFD            0x00200000
 
 /* This flag is used for SECURE display usecase */
-#define GRALLOC1_CONSUMER_USAGE_PRIVATE_SECURE_DISPLAY 0x00800000
+#define GRALLOC1_CONSUMER_USAGE_PRIVATE_SECURE_DISPLAY 0x01000000
 
 /* Unused flag */
 #define GRALLOC1_USAGE_PRIVATE_UNUSED1  0x04000000
diff --git a/sdm/include/private/color_params.h b/sdm/include/private/color_params.h
index 08895ee..14ec40f 100644
--- a/sdm/include/private/color_params.h
+++ b/sdm/include/private/color_params.h
@@ -157,6 +157,7 @@
   static const uint32_t kSDEPADitherV17 = 16;
   static const uint32_t kSDEIgcV30 = 17;
   static const uint32_t kSDEGamutV4 = 18;
+  static const uint32_t kSDEPccV4 = 19;
 
   uint32_t version[kMaxNumPPFeatures];
   PPFeatureVersion() { memset(version, 0, sizeof(version)); }
@@ -327,6 +328,29 @@
   SDEPccCfg *GetConfig() { return this; }
 };
 
+struct SDEPccV4Coeff {
+  uint32_t c = 0;
+  uint32_t r = 0;
+  uint32_t g = 0;
+  uint32_t b = 0;
+  uint32_t rg = 0;
+  uint32_t gb = 0;
+  uint32_t rb = 0;
+  uint32_t rgb = 0;
+  uint32_t rr = 0;
+  uint32_t gg = 0;
+  uint32_t bb = 0;
+};
+
+struct SDEPccV4Cfg {
+  SDEPccV4Coeff red;
+  SDEPccV4Coeff green;
+  SDEPccV4Coeff blue;
+
+  static SDEPccV4Cfg *Init(uint32_t arg __attribute__((__unused__)));
+  SDEPccV4Cfg *GetConfig() { return this; }
+};
+
 struct SDEDitherCfg {
   uint32_t g_y_depth;
   uint32_t r_cr_depth;
diff --git a/sdm/include/utils/debug.h b/sdm/include/utils/debug.h
index 0b40e7b..d5974d9 100644
--- a/sdm/include/utils/debug.h
+++ b/sdm/include/utils/debug.h
@@ -78,6 +78,7 @@
   static bool IsAVRDisabled();
   static bool IsExtAnimDisabled();
   static bool IsPartialSplitDisabled();
+  static bool IsSrcSplitPreferred();
   static DisplayError GetMixerResolution(uint32_t *width, uint32_t *height);
   static DisplayError GetReducedConfig(uint32_t *num_vig_pipes, uint32_t *num_dma_pipes);
   static int GetExtMaxlayers();
diff --git a/sdm/libs/core/Android.mk b/sdm/libs/core/Android.mk
index 14df125..cf3543c 100644
--- a/sdm/libs/core/Android.mk
+++ b/sdm/libs/core/Android.mk
@@ -13,7 +13,7 @@
 LOCAL_SHARED_LIBRARIES        := libdl libsdmutils
 
 ifneq ($(TARGET_IS_HEADLESS), true)
-    LOCAL_CFLAGS              += -DCOMPILE_DRM -isystem external/libdrm
+    LOCAL_CFLAGS              += -isystem external/libdrm
     LOCAL_SHARED_LIBRARIES    += libdrm libdrmutils
     LOCAL_HW_INTF_PATH_2      := drm
 endif
diff --git a/sdm/libs/core/drm/hw_color_manager_drm.cpp b/sdm/libs/core/drm/hw_color_manager_drm.cpp
index 67478c9..2000f9a 100644
--- a/sdm/libs/core/drm/hw_color_manager_drm.cpp
+++ b/sdm/libs/core/drm/hw_color_manager_drm.cpp
@@ -77,6 +77,11 @@
 
   switch (feature.id) {
     case kFeaturePcc:
+      if (feature.version == 1) {
+        version = PPFeatureVersion::kSDEPccV17;
+      } else if (feature.version == 4) {
+        version = PPFeatureVersion::kSDEPccV4;
+      }
       break;
     case kFeatureIgc:
       if (feature.version == 3)
@@ -87,10 +92,13 @@
         version = PPFeatureVersion::kSDEPgcV17;
       break;
     case kFeatureMixerGc:
+        version = PPFeatureVersion::kSDEPgcV17;
       break;
     case kFeaturePaV2:
+        version = PPFeatureVersion::kSDEPaV17;
       break;
     case kFeatureDither:
+        version = PPFeatureVersion::kSDEDitherV17;
       break;
     case kFeatureGamut:
       if (feature.version == 1)
@@ -99,6 +107,7 @@
         version = PPFeatureVersion::kSDEGamutV4;
       break;
     case kFeaturePADither:
+        version = PPFeatureVersion::kSDEPADitherV17;
       break;
     default:
       break;
@@ -143,6 +152,84 @@
 DisplayError HWColorManagerDrm::GetDrmPCC(const PPFeatureInfo &in_data,
                                           DRMPPFeatureInfo *out_data) {
   DisplayError ret = kErrorNone;
+#ifdef PP_DRM_ENABLE
+  struct SDEPccV4Cfg *sde_pcc = NULL;
+  struct SDEPccV4Coeff *sde_pcc_coeffs = NULL;
+  struct drm_msm_pcc *mdp_pcc = NULL;
+  struct drm_msm_pcc_coeff *mdp_pcc_coeffs = NULL;
+  uint32_t i = 0;
+
+  if (!out_data) {
+    DLOGE("Invalid input parameter for pcc");
+    return kErrorParameters;
+  }
+
+  switch (in_data.feature_version_) {
+  case PPFeatureVersion::kSDEPccV4:
+    sde_pcc = (struct SDEPccV4Cfg *) in_data.GetConfigData();
+    break;
+  default:
+    DLOGE("Unsupported pcc feature version: %d", in_data.feature_version_);
+    return kErrorParameters;
+  }
+
+  out_data->id = kFeaturePcc;
+  out_data->type = sde_drm::kPropBlob;
+  out_data->version = in_data.feature_version_;
+  out_data->payload_size = sizeof(struct drm_msm_pcc);
+
+  if (in_data.enable_flags_ & kOpsDisable) {
+    /* feature disable case */
+    out_data->payload = NULL;
+    return ret;
+  } else if (!(in_data.enable_flags_ & kOpsEnable)) {
+    out_data->payload = NULL;
+    return kErrorParameters;
+  }
+
+  mdp_pcc = new drm_msm_pcc();
+  if (!mdp_pcc) {
+    DLOGE("Failed to allocate memory for pcc");
+    return kErrorMemory;
+  }
+
+  mdp_pcc->flags = 0;
+
+  for (i = 0; i < kMaxPCCChanel; i++) {
+    switch (i) {
+    case 0:
+      sde_pcc_coeffs = &sde_pcc->red;
+      mdp_pcc_coeffs = &mdp_pcc->r;
+      mdp_pcc->r_rr = sde_pcc_coeffs->rr;
+      mdp_pcc->r_gg = sde_pcc_coeffs->gg;
+      mdp_pcc->r_bb = sde_pcc_coeffs->bb;
+      break;
+    case 1:
+        sde_pcc_coeffs = &sde_pcc->green;
+        mdp_pcc_coeffs = &mdp_pcc->g;
+        mdp_pcc->g_rr = sde_pcc_coeffs->rr;
+        mdp_pcc->g_gg = sde_pcc_coeffs->gg;
+        mdp_pcc->g_bb = sde_pcc_coeffs->bb;
+      break;
+    case 2:
+        sde_pcc_coeffs = &sde_pcc->blue;
+        mdp_pcc_coeffs = &mdp_pcc->b;
+        mdp_pcc->b_rr = sde_pcc_coeffs->rr;
+        mdp_pcc->b_gg = sde_pcc_coeffs->gg;
+        mdp_pcc->b_bb = sde_pcc_coeffs->bb;
+      break;
+    }
+    mdp_pcc_coeffs->c = sde_pcc_coeffs->c;
+    mdp_pcc_coeffs->r = sde_pcc_coeffs->r;
+    mdp_pcc_coeffs->g = sde_pcc_coeffs->g;
+    mdp_pcc_coeffs->b = sde_pcc_coeffs->b;
+    mdp_pcc_coeffs->rg = sde_pcc_coeffs->rg;
+    mdp_pcc_coeffs->gb = sde_pcc_coeffs->gb;
+    mdp_pcc_coeffs->rb = sde_pcc_coeffs->rb;
+    mdp_pcc_coeffs->rgb = sde_pcc_coeffs->rgb;
+  }
+  out_data->payload = mdp_pcc;
+#endif
   return ret;
 }
 
@@ -266,18 +353,49 @@
 DisplayError HWColorManagerDrm::GetDrmMixerGC(const PPFeatureInfo &in_data,
                                               DRMPPFeatureInfo *out_data) {
   DisplayError ret = kErrorNone;
+#ifdef PP_DRM_ENABLE
+  if (!out_data) {
+    DLOGE("Invalid input parameter for Mixer GC");
+    return kErrorParameters;
+  }
+
+  out_data->id = kPPFeaturesMax;
+  out_data->type = sde_drm::kPropBlob;
+  out_data->version = in_data.feature_version_;
+#endif
   return ret;
 }
 
 DisplayError HWColorManagerDrm::GetDrmPAV2(const PPFeatureInfo &in_data,
                                            DRMPPFeatureInfo *out_data) {
   DisplayError ret = kErrorNone;
+#ifdef PP_DRM_ENABLE
+  if (!out_data) {
+    DLOGE("Invalid input parameter for PA V2");
+    return kErrorParameters;
+  }
+
+  out_data->id = kPPFeaturesMax;
+  out_data->type = sde_drm::kPropBlob;
+  out_data->version = in_data.feature_version_;
+
+#endif
   return ret;
 }
 
 DisplayError HWColorManagerDrm::GetDrmDither(const PPFeatureInfo &in_data,
                                              DRMPPFeatureInfo *out_data) {
   DisplayError ret = kErrorNone;
+#ifdef PP_DRM_ENABLE
+  if (!out_data) {
+    DLOGE("Invalid input parameter for dither");
+    return kErrorParameters;
+  }
+
+  out_data->id = kPPFeaturesMax;
+  out_data->type = sde_drm::kPropBlob;
+  out_data->version = in_data.feature_version_;
+#endif
   return ret;
 }
 
@@ -360,6 +478,16 @@
 DisplayError HWColorManagerDrm::GetDrmPADither(const PPFeatureInfo &in_data,
                                                DRMPPFeatureInfo *out_data) {
   DisplayError ret = kErrorNone;
+#ifdef PP_DRM_ENABLE
+  if (!out_data) {
+    DLOGE("Invalid input parameter for PA dither");
+    return kErrorParameters;
+  }
+
+  out_data->id = kPPFeaturesMax;
+  out_data->type = sde_drm::kPropBlob;
+  out_data->version = in_data.feature_version_;
+#endif
   return ret;
 }
 
diff --git a/sdm/libs/core/drm/hw_color_manager_drm.h b/sdm/libs/core/drm/hw_color_manager_drm.h
index a10d00b..290c606 100644
--- a/sdm/libs/core/drm/hw_color_manager_drm.h
+++ b/sdm/libs/core/drm/hw_color_manager_drm.h
@@ -38,6 +38,8 @@
 
 namespace sdm {
 
+static const uint32_t kMaxPCCChanel = 3;
+
 class HWColorManagerDrm {
  public:
   static DisplayError (*GetDrmFeature[kMaxNumPPFeatures])(const PPFeatureInfo &in_data,
diff --git a/sdm/libs/core/hw_events_interface.cpp b/sdm/libs/core/hw_events_interface.cpp
index 5817cdb..84a7dab 100644
--- a/sdm/libs/core/hw_events_interface.cpp
+++ b/sdm/libs/core/hw_events_interface.cpp
@@ -32,9 +32,7 @@
 
 #include "hw_events_interface.h"
 #include "fb/hw_events.h"
-#ifdef COMPILE_DRM
 #include "drm/hw_events_drm.h"
-#endif
 
 #define __CLASS__ "HWEventsInterface"
 
@@ -48,9 +46,7 @@
   if (GetDriverType() == DriverType::FB) {
     hw_events = new HWEvents();
   } else {
-#ifdef COMPILE_DRM
     hw_events = new HWEventsDRM();
-#endif
   }
 
   error = hw_events->Init(display_type, event_handler, event_list, hw_intf);
diff --git a/sdm/libs/core/hw_info_interface.cpp b/sdm/libs/core/hw_info_interface.cpp
index 1773fe5..79bc79a 100644
--- a/sdm/libs/core/hw_info_interface.cpp
+++ b/sdm/libs/core/hw_info_interface.cpp
@@ -31,9 +31,7 @@
 
 #include "hw_info_interface.h"
 #include "fb/hw_info.h"
-#ifdef COMPILE_DRM
 #include "drm/hw_info_drm.h"
-#endif
 
 #define __CLASS__ "HWInfoInterface"
 
@@ -43,9 +41,7 @@
   if (GetDriverType() == DriverType::FB) {
     *intf = new HWInfo();
   } else {
-#ifdef COMPILE_DRM
     *intf = new HWInfoDRM();
-#endif
   }
 
   return kErrorNone;
diff --git a/sdm/libs/core/hw_interface.cpp b/sdm/libs/core/hw_interface.cpp
index cfaf72b..2d8d41e 100644
--- a/sdm/libs/core/hw_interface.cpp
+++ b/sdm/libs/core/hw_interface.cpp
@@ -35,11 +35,9 @@
 #include "fb/hw_primary.h"
 #include "fb/hw_hdmi.h"
 #include "fb/hw_virtual.h"
-#ifdef COMPILE_DRM
 #include "drm/hw_device_drm.h"
 #include "drm/hw_virtual_drm.h"
 #include "drm/hw_tv_drm.h"
-#endif
 
 #define __CLASS__ "HWInterface"
 
@@ -57,27 +55,21 @@
       if (driver_type == DriverType::FB) {
         hw = new HWPrimary(buffer_sync_handler, hw_info_intf);
       } else {
-#ifdef COMPILE_DRM
         hw = new HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf);
-#endif
       }
       break;
     case kHDMI:
       if (driver_type == DriverType::FB) {
         hw = new HWHDMI(buffer_sync_handler, hw_info_intf);
       } else {
-#ifdef COMPILE_DRM
         hw = new HWTVDRM(buffer_sync_handler, buffer_allocator, hw_info_intf);
-#endif
       }
       break;
     case kVirtual:
       if (driver_type == DriverType::FB) {
         hw = new HWVirtual(buffer_sync_handler, hw_info_intf);
       } else {
-#ifdef COMPILE_DRM
         hw = new HWVirtualDRM(buffer_sync_handler, buffer_allocator, hw_info_intf);
-#endif
       }
       break;
     default:
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 91879ae..f7a9dec 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -363,11 +363,18 @@
     // TODO(user): Add blit engine when needed
   }
 
+  error = display_intf_->GetNumVariableInfoConfigs(&num_configs_);
+  if (error != kErrorNone) {
+    DLOGE("Getting config count failed. Error = %d", error);
+    return -EINVAL;
+  }
+
   tone_mapper_ = new HWCToneMapper(buffer_allocator_);
 
   display_intf_->GetRefreshRateRange(&min_refresh_rate_, &max_refresh_rate_);
   current_refresh_rate_ = max_refresh_rate_;
   DLOGI("Display created with id: %d", id_);
+
   return 0;
 }
 
@@ -454,12 +461,11 @@
       layer->flags.solid_fill = true;
     }
 
+    if (!hwc_layer->ValidateAndSetCSC()) {
 #ifdef FEATURE_WIDE_COLOR
-    if (!hwc_layer->SupportedDataspace()) {
-        layer->flags.skip = true;
-        DLOGW_IF(kTagStrategy, "Unsupported dataspace: 0x%x", hwc_layer->GetLayerDataspace());
-    }
+      layer->flags.skip = true;
 #endif
+    }
 
     working_primaries = WidestPrimaries(working_primaries,
                                         layer->input_buffer.color_metadata.colorPrimaries);
@@ -717,12 +723,15 @@
 }
 
 HWC2::Error HWCDisplay::GetDisplayConfigs(uint32_t *out_num_configs, hwc2_config_t *out_configs) {
-  // TODO(user): Actually handle multiple configs
   if (out_configs == nullptr) {
-    *out_num_configs = 1;
-  } else {
-    *out_num_configs = 1;
-    out_configs[0] = 0;
+    *out_num_configs = num_configs_;
+    return HWC2::Error::None;
+  }
+
+  *out_num_configs = num_configs_;
+
+  for (uint32_t i = 0; i < num_configs_; i++) {
+    out_configs[i] = i;
   }
 
   return HWC2::Error::None;
@@ -731,16 +740,11 @@
 HWC2::Error HWCDisplay::GetDisplayAttribute(hwc2_config_t config, HWC2::Attribute attribute,
                                             int32_t *out_value) {
   DisplayConfigVariableInfo variable_config;
-  DisplayError error = display_intf_->GetFrameBufferConfig(&variable_config);
-  if (error != kErrorNone) {
-    DLOGV("Get variable config failed. Error = %d", error);
+  if (GetDisplayAttributesForConfig(INT(config), &variable_config) != kErrorNone) {
+    DLOGE("Get variable config failed");
     return HWC2::Error::BadDisplay;
   }
 
-  if (config != 0) {  // We only use config[0] - see TODO above
-      return HWC2::Error::BadConfig;
-  }
-
   switch (attribute) {
     case HWC2::Attribute::VsyncPeriod:
       *out_value = INT32(variable_config.vsync_period_ns);
@@ -805,14 +809,19 @@
   }
 }
 
-// TODO(user): Store configurations and hook them up here
 HWC2::Error HWCDisplay::GetActiveConfig(hwc2_config_t *out_config) {
-  if (out_config != nullptr) {
-    *out_config = 0;
-    return HWC2::Error::None;
-  } else {
-    return HWC2::Error::BadParameter;
+  if (out_config == nullptr) {
+    return HWC2::Error::BadDisplay;
   }
+
+  uint32_t active_index = 0;
+  if (GetActiveDisplayConfig(&active_index) != kErrorNone) {
+    return HWC2::Error::BadConfig;
+  }
+
+  *out_config = active_index;
+
+  return HWC2::Error::None;
 }
 
 HWC2::Error HWCDisplay::SetClientTarget(buffer_handle_t target, int32_t acquire_fence,
@@ -837,10 +846,10 @@
 }
 
 HWC2::Error HWCDisplay::SetActiveConfig(hwc2_config_t config) {
-  if (config != 0) {
+  if (SetActiveDisplayConfig(config) != kErrorNone) {
     return HWC2::Error::BadConfig;
   }
-  // We have only one config right now - do nothing
+
   return HWC2::Error::None;
 }
 
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index b70f160..e773e91 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -299,6 +299,7 @@
   bool color_tranform_failed_ = false;
   HWCColorMode *color_mode_ = NULL;
   HWCToneMapper *tone_mapper_ = nullptr;
+  uint32_t num_configs_ = 0;
   int disable_hdr_handling_ = 0;  // disables HDR handling.
 
  private:
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index f485ac6..6b5d470 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -255,6 +255,7 @@
     }
   }
 
+  // cache the dataspace, to be used later to update SDM ColorMetaData
   if (dataspace_ != dataspace) {
     geometry_changes_ |= kDataspace;
     dataspace_ = dataspace;
@@ -573,19 +574,6 @@
 
 DisplayError HWCLayer::SetMetaData(const private_handle_t *pvt_handle, Layer *layer) {
   LayerBuffer *layer_buffer = &layer->input_buffer;
-  bool use_color_metadata = true;
-
-#ifdef FEATURE_WIDE_COLOR
-  // Only use color metadata if Android framework metadata is not set
-  use_color_metadata = (dataspace_ == HAL_DATASPACE_UNKNOWN);
-#endif
-
-  if (use_color_metadata) {
-    if (sdm::SetCSC(pvt_handle, &layer_buffer->color_metadata) != kErrorNone) {
-      return kErrorNotSupported;
-    }
-  }
-
   private_handle_t *handle = const_cast<private_handle_t *>(pvt_handle);
   IGC_t igc = {};
   if (getMetaData(handle, GET_IGC, &igc) == 0) {
@@ -655,84 +643,106 @@
   return false;
 }
 
-bool HWCLayer::SupportedDataspace() {
-  if (dataspace_ == HAL_DATASPACE_UNKNOWN) {
-    // Pick values from metadata
+bool HWCLayer::ValidateAndSetCSC() {
+  if (client_requested_ != HWC2::Composition::Device &&
+      client_requested_ != HWC2::Composition::Cursor) {
+    // Check the layers which are configured to Device
     return true;
   }
 
+  // Retrieve ColorMetaData from android_data_space_t (STANDARD|TRANSFER|RANGE)
   LayerBuffer *layer_buffer = &layer_->input_buffer;
+  bool use_color_metadata = true;
 
+#ifdef FEATURE_WIDE_COLOR
   GammaTransfer sdm_transfer = {};
   ColorPrimaries sdm_primaries = {};
   ColorRange sdm_range = {};
+  if (dataspace_ != HAL_DATASPACE_UNKNOWN) {
+    use_color_metadata = false;  // avoid using color_metadata
+    auto transfer = dataspace_ & HAL_DATASPACE_TRANSFER_MASK;
+    // Handle transfer
+    switch (transfer) {
+      case HAL_DATASPACE_TRANSFER_SRGB:
+        sdm_transfer = Transfer_sRGB;
+        break;
+      case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+        sdm_transfer = Transfer_SMPTE_170M;
+        break;
+      case HAL_DATASPACE_TRANSFER_ST2084:
+        sdm_transfer = Transfer_SMPTE_ST2084;
+        break;
+      case HAL_DATASPACE_TRANSFER_HLG:
+        sdm_transfer = Transfer_HLG;
+        break;
+      case HAL_DATASPACE_TRANSFER_LINEAR:
+        sdm_transfer = Transfer_Linear;
+        break;
+      case HAL_DATASPACE_TRANSFER_GAMMA2_2:
+        sdm_transfer = Transfer_Gamma2_2;
+        break;
+      default:
+        DLOGV_IF(kTagStrategy, "Unsupported Transfer Request = %d", transfer);
+        return false;
+    }
 
-  auto transfer = dataspace_ & HAL_DATASPACE_TRANSFER_MASK;
-  // Handle transfer
-  switch (transfer) {
-    case HAL_DATASPACE_TRANSFER_SRGB:
-      sdm_transfer = Transfer_sRGB;
-      break;
-    case HAL_DATASPACE_TRANSFER_SMPTE_170M:
-      sdm_transfer = Transfer_SMPTE_170M;
-      break;
-    case HAL_DATASPACE_TRANSFER_ST2084:
-      sdm_transfer = Transfer_SMPTE_ST2084;
-      break;
-    case HAL_DATASPACE_TRANSFER_HLG:
-      sdm_transfer = Transfer_HLG;
-      break;
-    case HAL_DATASPACE_TRANSFER_LINEAR:
-      sdm_transfer = Transfer_Linear;
-      break;
-    case HAL_DATASPACE_TRANSFER_GAMMA2_2:
-      sdm_transfer = Transfer_Gamma2_2;
-      break;
-    default:
+    // Handle standard
+    auto standard = dataspace_ & HAL_DATASPACE_STANDARD_MASK;
+    switch (standard) {
+      case  HAL_DATASPACE_STANDARD_BT709:
+        sdm_primaries = ColorPrimaries_BT709_5;
+        break;
+      case HAL_DATASPACE_STANDARD_BT601_525:
+      case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+        sdm_primaries = ColorPrimaries_BT601_6_525;
+        break;
+      case HAL_DATASPACE_STANDARD_BT601_625:
+      case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+        sdm_primaries = ColorPrimaries_BT601_6_625;
+        break;
+      case HAL_DATASPACE_STANDARD_DCI_P3:
+        sdm_primaries = ColorPrimaries_DCIP3;
+        break;
+      case HAL_DATASPACE_STANDARD_BT2020:
+        sdm_primaries = ColorPrimaries_BT2020;
+        // android_dataspace_t doesnt support mastering display and light levels
+        // so retrieve it from metadata
+        use_color_metadata = true;
+        break;
+      default:
+        DLOGV_IF(kTagStrategy, "Unsupported Standard Request = %d", standard);
+        return false;
+    }
+    // TODO(user): Check transfer + primary combination
+
+    // Handle range
+    auto range = dataspace_ & HAL_DATASPACE_RANGE_MASK;
+    switch (range) {
+      case HAL_DATASPACE_RANGE_FULL:
+        sdm_range = Range_Full;
+        break;
+      case HAL_DATASPACE_RANGE_LIMITED:
+        sdm_range = Range_Limited;
+        break;
+      default:
+        DLOGV_IF(kTagStrategy, "Unsupported Range Request = %d", range);
+        break;
+    }
+    // If we got here, the value is supported, update the layer
+    layer_buffer->color_metadata.transfer = sdm_transfer;
+    layer_buffer->color_metadata.colorPrimaries = sdm_primaries;
+    layer_buffer->color_metadata.range = sdm_range;
+  }
+#endif
+
+  if (use_color_metadata) {
+    const private_handle_t *handle =
+      reinterpret_cast<const private_handle_t *>(layer_buffer->buffer_id);
+    if (sdm::SetCSC(handle, &layer_buffer->color_metadata) != kErrorNone) {
       return false;
+    }
   }
 
-  // Handle standard
-  auto standard = dataspace_ & HAL_DATASPACE_STANDARD_MASK;
-  switch (standard) {
-    case  HAL_DATASPACE_STANDARD_BT709:
-      sdm_primaries = ColorPrimaries_BT709_5;
-      break;
-    case HAL_DATASPACE_STANDARD_BT601_525:
-    case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
-      sdm_primaries = ColorPrimaries_BT601_6_525;
-      break;
-    case HAL_DATASPACE_STANDARD_BT601_625:
-    case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
-      sdm_primaries = ColorPrimaries_BT601_6_625;
-      break;
-    case HAL_DATASPACE_STANDARD_DCI_P3:
-      sdm_primaries = ColorPrimaries_DCIP3;
-      break;
-    case HAL_DATASPACE_STANDARD_BT2020:
-      sdm_primaries = ColorPrimaries_BT2020;
-      break;
-    default:
-      return false;
-  }
-  // TODO(user): Check transfer + primary combination
-
-  // Handle range
-  auto range = dataspace_ & HAL_DATASPACE_RANGE_MASK;
-  switch (range) {
-    case HAL_DATASPACE_RANGE_FULL:
-      sdm_range = Range_Full;
-      break;
-    case HAL_DATASPACE_RANGE_LIMITED:
-    default:
-      sdm_range = Range_Limited;
-      break;
-  }
-
-  // If we got here, the value is supported, update the layer
-  layer_buffer->color_metadata.transfer = sdm_transfer;
-  layer_buffer->color_metadata.colorPrimaries = sdm_primaries;
-  layer_buffer->color_metadata.range = sdm_range;
   return true;
 }
 
diff --git a/sdm/libs/hwc2/hwc_layers.h b/sdm/libs/hwc2/hwc_layers.h
index c566655..30fc362 100644
--- a/sdm/libs/hwc2/hwc_layers.h
+++ b/sdm/libs/hwc2/hwc_layers.h
@@ -85,7 +85,7 @@
   void ResetGeometryChanges() { geometry_changes_ = GeometryChanges::kNone; }
   void PushReleaseFence(int32_t fence);
   int32_t PopReleaseFence(void);
-  bool SupportedDataspace();
+  bool ValidateAndSetCSC();
   bool SupportLocalConversion(ColorPrimaries working_primaries);
 
  private:
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index a135be2..df15404 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -35,6 +35,8 @@
 #include <algorithm>
 #include <string>
 #include <bitset>
+#include <thread>
+#include <memory>
 
 #include "hwc_buffer_allocator.h"
 #include "hwc_buffer_sync_handler.h"
@@ -66,8 +68,63 @@
 };
 
 namespace sdm {
+
+static HWCUEvent g_hwc_uevent_;
 Locker HWCSession::locker_;
 
+void HWCUEvent::UEventThread(HWCUEvent *hwc_uevent) {
+  const char *uevent_thread_name = "HWC_UeventThread";
+
+  prctl(PR_SET_NAME, uevent_thread_name, 0, 0, 0);
+  setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+
+  int status = uevent_init();
+  if (!status) {
+    std::unique_lock<std::mutex> caller_lock(hwc_uevent->mutex_);
+    hwc_uevent->caller_cv_.notify_one();
+    DLOGE("Failed to init uevent with err %d", status);
+    return;
+  }
+
+  {
+    // Signal caller thread that worker thread is ready to listen to events.
+    std::unique_lock<std::mutex> caller_lock(hwc_uevent->mutex_);
+    hwc_uevent->init_done_ = true;
+    hwc_uevent->caller_cv_.notify_one();
+  }
+
+  while (1) {
+    char uevent_data[PAGE_SIZE] = {};
+
+    // keep last 2 zeroes to ensure double 0 termination
+    int length = uevent_next_event(uevent_data, INT32(sizeof(uevent_data)) - 2);
+
+    // scope of lock to this block only, so that caller is free to set event handler to nullptr;
+    {
+      std::lock_guard<std::mutex> guard(hwc_uevent->mutex_);
+      if (hwc_uevent->uevent_listener_) {
+        hwc_uevent->uevent_listener_->UEventHandler(uevent_data, length);
+      } else {
+        DLOGW("UEvent dropped. No uevent listener.");
+      }
+    }
+  }
+}
+
+HWCUEvent::HWCUEvent() {
+  std::unique_lock<std::mutex> caller_lock(mutex_);
+  std::thread thread(HWCUEvent::UEventThread, this);
+  thread.detach();
+  caller_cv_.wait(caller_lock);
+}
+
+void HWCUEvent::Register(HWCUEventListener *uevent_listener) {
+  DLOGI("Set uevent listener = %p", uevent_listener);
+
+  std::lock_guard<std::mutex> obj(mutex_);
+  uevent_listener_ = uevent_listener;
+}
+
 HWCSession::HWCSession(const hw_module_t *module) {
   hwc2_device_t::common.tag = HARDWARE_DEVICE_TAG;
   hwc2_device_t::common.version = HWC_DEVICE_API_VERSION_2_0;
@@ -81,6 +138,10 @@
   int status = -EINVAL;
   const char *qservice_name = "display.qservice";
 
+  if (!g_hwc_uevent_.InitDone()) {
+    return status;
+  }
+
   // Start QService and connect to it.
   qService::QService::init();
   android::sp<qService::IQService> iqservice = android::interface_cast<qService::IQService>(
@@ -104,10 +165,13 @@
     return -EINVAL;
   }
 
+  g_hwc_uevent_.Register(this);
+
   // If HDMI display is primary display, defer display creation until hotplug event is received.
   HWDisplayInterfaceInfo hw_disp_info = {};
   error = core_intf_->GetFirstDisplayInterfaceType(&hw_disp_info);
   if (error != kErrorNone) {
+    g_hwc_uevent_.Register(nullptr);
     CoreInterface::DestroyCore();
     DLOGE("Primary display type not recognized. Error = %d", error);
     return -EINVAL;
@@ -132,6 +196,7 @@
   }
 
   if (status) {
+    g_hwc_uevent_.Register(nullptr);
     CoreInterface::DestroyCore();
     return status;
   }
@@ -146,9 +211,6 @@
     }
   }
 
-  std::thread uevent_thread(HWCUeventThread, this);
-  uevent_thread_.swap(uevent_thread);
-
   return 0;
 }
 
@@ -167,10 +229,7 @@
     color_mgr_->DestroyColorManager();
   }
 
-  DLOGD("Terminating uevent thread");
-  uevent_thread_exit_ = true;
-  // todo(user): add a local event to interrupt thread execution and join.
-  uevent_thread_.detach();
+  g_hwc_uevent_.Register(nullptr);
 
   DisplayError error = CoreInterface::DestroyCore();
   if (error != kErrorNone) {
@@ -1081,8 +1140,6 @@
 }
 
 android::status_t HWCSession::SetColorModeOverride(const android::Parcel *input_parcel) {
-  SCOPE_LOCK(locker_);
-
   auto display = static_cast<hwc2_display_t >(input_parcel->readInt32());
   auto mode = static_cast<android_color_mode_t>(input_parcel->readInt32());
   auto device = static_cast<hwc2_device_t *>(this);
@@ -1149,8 +1206,6 @@
 
 android::status_t HWCSession::QdcmCMDHandler(const android::Parcel *input_parcel,
                                              android::Parcel *output_parcel) {
-  SCOPE_LOCK(locker_);
-
   int ret = 0;
   int32_t *brightness_value = NULL;
   uint32_t display_id(0);
@@ -1242,52 +1297,26 @@
   return (ret ? -EINVAL : 0);
 }
 
-void *HWCSession::HWCUeventThread(void *context) {
-  if (context) {
-    return reinterpret_cast<HWCSession *>(context)->HWCUeventThreadHandler();
-  }
-
-  return NULL;
-}
-
-void *HWCSession::HWCUeventThreadHandler() {
-  static char uevent_data[PAGE_SIZE];
-  int length = 0;
-  prctl(PR_SET_NAME, uevent_thread_name_, 0, 0, 0);
-  setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
-  if (!uevent_init()) {
-    DLOGE("Failed to init uevent");
-    pthread_exit(0);
-    return NULL;
-  }
-
-  while (!uevent_thread_exit_) {
-    // keep last 2 zeroes to ensure double 0 termination
-    length = uevent_next_event(uevent_data, INT32(sizeof(uevent_data)) - 2);
-
-    if (strcasestr(HWC_UEVENT_SWITCH_HDMI, uevent_data)) {
-      DLOGI("Uevent HDMI = %s", uevent_data);
-      int connected = GetEventValue(uevent_data, length, "SWITCH_STATE=");
-      if (connected >= 0) {
-        DLOGI("HDMI = %s", connected ? "connected" : "disconnected");
-        if (HotPlugHandler(connected) == -1) {
-          DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected");
-        }
+void HWCSession::UEventHandler(const char *uevent_data, int length) {
+  if (strcasestr(uevent_data, HWC_UEVENT_SWITCH_HDMI)) {
+    DLOGI("Uevent HDMI = %s", uevent_data);
+    int connected = GetEventValue(uevent_data, length, "SWITCH_STATE=");
+    if (connected >= 0) {
+      DLOGI("HDMI = %s", connected ? "connected" : "disconnected");
+      if (HotPlugHandler(connected) == -1) {
+        DLOGE("Failed handling Hotplug = %s", connected ? "connected" : "disconnected");
       }
-    } else if (strcasestr(HWC_UEVENT_GRAPHICS_FB0, uevent_data)) {
-      DLOGI("Uevent FB0 = %s", uevent_data);
-      int panel_reset = GetEventValue(uevent_data, length, "PANEL_ALIVE=");
-      if (panel_reset == 0) {
-        callbacks_.Refresh(0);
-        reset_panel_ = true;
-      }
-    } else if (strcasestr(uevent_data, HWC_UEVENT_DRM_EXT_HOTPLUG)) {
-      HandleExtHPD(uevent_data, length);
     }
+  } else if (strcasestr(uevent_data, HWC_UEVENT_GRAPHICS_FB0)) {
+    DLOGI("Uevent FB0 = %s", uevent_data);
+    int panel_reset = GetEventValue(uevent_data, length, "PANEL_ALIVE=");
+    if (panel_reset == 0) {
+      callbacks_.Refresh(0);
+      reset_panel_ = true;
+    }
+  } else if (strcasestr(uevent_data, HWC_UEVENT_DRM_EXT_HOTPLUG)) {
+    HandleExtHPD(uevent_data, length);
   }
-  pthread_exit(0);
-
-  return NULL;
 }
 
 void HWCSession::HandleExtHPD(const char *uevent_data, int length) {
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index cd9831d..7d2a30c 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -23,7 +23,6 @@
 #include <vendor/display/config/1.0/IDisplayConfig.h>
 #include <core/core_interface.h>
 #include <utils/locker.h>
-#include <thread>
 
 #include "hwc_callbacks.h"
 #include "hwc_layers.h"
@@ -39,7 +38,32 @@
 using ::vendor::display::config::V1_0::IDisplayConfig;
 using ::android::hardware::Return;
 
-class HWCSession : hwc2_device_t, public IDisplayConfig, public qClient::BnQClient {
+// Create a singleton uevent listener thread valid for life of hardware composer process.
+// This thread blocks on uevents poll inside uevent library implementation. This poll exits
+// only when there is a valid uevent, it can not be interrupted otherwise. Tieing life cycle
+// of this thread with HWC session cause HWC deinitialization to wait infinitely for the
+// thread to exit.
+class HWCUEventListener {
+ public:
+  virtual ~HWCUEventListener() {}
+  virtual void UEventHandler(const char *uevent_data, int length) = 0;
+};
+
+class HWCUEvent {
+ public:
+  HWCUEvent();
+  static void UEventThread(HWCUEvent *hwc_event);
+  void Register(HWCUEventListener *uevent_listener);
+  inline bool InitDone() { return init_done_; }
+
+ private:
+  std::mutex mutex_;
+  std::condition_variable caller_cv_;
+  HWCUEventListener *uevent_listener_ = nullptr;
+  bool init_done_ = false;
+};
+
+class HWCSession : hwc2_device_t, HWCUEventListener, IDisplayConfig, public qClient::BnQClient {
  public:
   struct HWCModuleMethods : public hw_module_methods_t {
     HWCModuleMethods() { hw_module_methods_t::open = HWCSession::Open; }
@@ -120,9 +144,8 @@
                               int32_t *outCapabilities);
   static hwc2_function_pointer_t GetFunction(struct hwc2_device *device, int32_t descriptor);
 
-  // Uevent thread
-  static void *HWCUeventThread(void *context);
-  void *HWCUeventThreadHandler();
+  // Uevent handler
+  virtual void UEventHandler(const char *uevent_data, int length);
   int GetEventValue(const char *uevent_data, int length, const char *event_info);
   void HandleExtHPD(const char *uevent_data, int length);
   int HotPlugHandler(bool connected);
@@ -192,9 +215,6 @@
   CoreInterface *core_intf_ = nullptr;
   HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {nullptr};
   HWCCallbacks callbacks_;
-  std::thread uevent_thread_;
-  bool uevent_thread_exit_ = false;
-  const char *uevent_thread_name_ = "HWC_UeventThread";
   HWCBufferAllocator buffer_allocator_;
   HWCBufferSyncHandler buffer_sync_handler_;
   HWCColorManager *color_mgr_ = nullptr;
diff --git a/sdm/libs/hwc2/hwc_tonemapper.cpp b/sdm/libs/hwc2/hwc_tonemapper.cpp
index 257296b..a224e8d 100644
--- a/sdm/libs/hwc2/hwc_tonemapper.cpp
+++ b/sdm/libs/hwc2/hwc_tonemapper.cpp
@@ -188,8 +188,8 @@
           // then SDM marks them for SDE Composition because the cached FB layer gets displayed.
           // GPU count will be 0 in this case. Try to use the existing tone-mapped frame buffer.
           // No ToneMap/Blit is required. Just update the buffer & acquire fence fd of FB layer.
-          if (!tone_map_sessions_.empty()) {
-            ToneMapSession *fb_tone_map_session = tone_map_sessions_.at(fb_session_index_);
+          if (!tone_map_sessions_.empty() && (fb_session_index_ >= 0)) {
+            ToneMapSession *fb_tone_map_session = tone_map_sessions_.at(UINT32(fb_session_index_));
             fb_tone_map_session->UpdateBuffer(-1 /* acquire_fence */, &layer->input_buffer);
             fb_tone_map_session->layer_index_ = INT(i);
             fb_tone_map_session->acquired_ = true;
@@ -197,7 +197,7 @@
           }
         }
         error = AcquireToneMapSession(layer, &session_index);
-        fb_session_index_ = session_index;
+        fb_session_index_ = INT(session_index);
         break;
       default:
         error = AcquireToneMapSession(layer, &session_index);
@@ -261,6 +261,13 @@
     } else {
       delete session;
       it = tone_map_sessions_.erase(it);
+      int deleted_session = INT(session_index);
+      // If FB tonemap session gets deleted, reset fb_session_index_, else update it.
+      if (deleted_session == fb_session_index_) {
+        fb_session_index_ = -1;
+      } else if (deleted_session < fb_session_index_) {
+        fb_session_index_--;
+      }
     }
   }
 }
@@ -271,7 +278,7 @@
       delete tone_map_sessions_.back();
       tone_map_sessions_.pop_back();
     }
-    fb_session_index_ = 0;
+    fb_session_index_ = -1;
   }
 }
 
diff --git a/sdm/libs/hwc2/hwc_tonemapper.h b/sdm/libs/hwc2/hwc_tonemapper.h
index e2c8ef4..8bef3b1 100644
--- a/sdm/libs/hwc2/hwc_tonemapper.h
+++ b/sdm/libs/hwc2/hwc_tonemapper.h
@@ -118,7 +118,7 @@
   HWCBufferAllocator *buffer_allocator_ = nullptr;
   uint32_t dump_frame_count_ = 0;
   uint32_t dump_frame_index_ = 0;
-  uint32_t fb_session_index_ = 0;
+  int fb_session_index_ = -1;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/utils/debug.cpp b/sdm/libs/utils/debug.cpp
index 60ce0ac..ee881ef 100644
--- a/sdm/libs/utils/debug.cpp
+++ b/sdm/libs/utils/debug.cpp
@@ -177,6 +177,13 @@
   return (value == 1);
 }
 
+bool Debug::IsSrcSplitPreferred() {
+  int value = 0;
+  debug_.debug_handler_->GetProperty("sdm.debug.prefersplit", &value);
+
+  return (value == 1);
+}
+
 DisplayError Debug::GetMixerResolution(uint32_t *width, uint32_t *height) {
   char value[64] = {};