Merge "libgrallocutils: Support defaults in AdrenoMemInfo"
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/libdrmutils/drm_interface.h b/libdrmutils/drm_interface.h
index 35285ee..6e07445 100644
--- a/libdrmutils/drm_interface.h
+++ b/libdrmutils/drm_interface.h
@@ -422,6 +422,7 @@
   bool roi_merge;
   DRMRotation panel_orientation;
   drm_panel_hdr_properties panel_hdr_prop;
+  uint32_t transfer_time_us;
 };
 
 /* Identifier token for a display */
diff --git a/libgralloc1/gr_utils.cpp b/libgralloc1/gr_utils.cpp
index b3056e1..560bb08 100644
--- a/libgralloc1/gr_utils.cpp
+++ b/libgralloc1/gr_utils.cpp
@@ -509,7 +509,9 @@
     // Query GPU for UBWC only if buffer is intended to be used by GPU.
     if ((cons_usage & GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE) ||
         (prod_usage & GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET)) {
-      enable = AdrenoMemInfo::GetInstance()->IsUBWCSupportedByGPU(format);
+      if (AdrenoMemInfo::GetInstance()) {
+        enable = AdrenoMemInfo::GetInstance()->IsUBWCSupportedByGPU(format);
+      }
     }
 
     // Allow UBWC, only if CPU usage flags are not set
@@ -675,8 +677,10 @@
   int tile = ubwc_enabled;
 
   if (IsUncompressedRGBFormat(format)) {
-    AdrenoMemInfo::GetInstance()->AlignUnCompressedRGB(width, height, format, tile, alignedw,
-                                                       alignedh);
+    if (AdrenoMemInfo::GetInstance()) {
+      AdrenoMemInfo::GetInstance()->AlignUnCompressedRGB(width, height, format, tile, alignedw,
+                                                         alignedh);
+    }
     return;
   }
 
@@ -686,7 +690,9 @@
   }
 
   if (IsCompressedRGBFormat(format)) {
-    AdrenoMemInfo::GetInstance()->AlignCompressedRGB(width, height, format, alignedw, alignedh);
+    if (AdrenoMemInfo::GetInstance()) {
+      AdrenoMemInfo::GetInstance()->AlignCompressedRGB(width, height, format, alignedw, alignedh);
+    }
     return;
   }
 
@@ -698,6 +704,9 @@
   switch (format) {
     case HAL_PIXEL_FORMAT_YCrCb_420_SP:
     case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+      if (AdrenoMemInfo::GetInstance() == nullptr) {
+        return;
+      }
       alignment = AdrenoMemInfo::GetInstance()->GetGpuPixelAlignment();
       aligned_w = ALIGN(width, alignment);
       break;
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/hw_info_types.h b/sdm/include/private/hw_info_types.h
index 752d0c4..763e68d 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -274,6 +274,7 @@
   uint32_t blackness_level = 0;       // Panel's blackness level
   HWColorPrimaries primaries = {};    // WRGB color primaries
   HWPanelOrientation panel_orientation = {};  // Panel Orientation
+  uint32_t transfer_time_us = 0;      // transfer time in micro seconds to panel's active region
 
   bool operator !=(const HWPanelInfo &panel_info) {
     return ((port != panel_info.port) || (mode != panel_info.mode) ||
@@ -289,7 +290,8 @@
             (max_fps != panel_info.max_fps) || (is_primary_panel != panel_info.is_primary_panel) ||
             (split_info != panel_info.split_info) || (s3d_mode != panel_info.s3d_mode) ||
             (left_roi_count != panel_info.left_roi_count) ||
-            (right_roi_count != panel_info.right_roi_count));
+            (right_roi_count != panel_info.right_roi_count) ||
+            (transfer_time_us != panel_info.transfer_time_us));
   }
 
   bool operator ==(const HWPanelInfo &panel_info) {
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/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index 1ed9042..cd036a9 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -494,6 +494,7 @@
   hw_panel_info_.primaries.green[1] = connector_info_.panel_hdr_prop.display_primaries[5];
   hw_panel_info_.primaries.blue[0] = connector_info_.panel_hdr_prop.display_primaries[6];
   hw_panel_info_.primaries.blue[1] = connector_info_.panel_hdr_prop.display_primaries[7];
+  hw_panel_info_.transfer_time_us = connector_info_.transfer_time_us;
 
   // no supprt for 90 rotation only flips or 180 supported
   hw_panel_info_.panel_orientation.rotation = 0;
@@ -519,6 +520,7 @@
   DLOGI("FPS: min = %d, max =%d", hw_panel_info_.min_fps, hw_panel_info_.max_fps);
   DLOGI("Left Split = %d, Right Split = %d", hw_panel_info_.split_info.left_split,
         hw_panel_info_.split_info.right_split);
+  DLOGI("Panel Transfer time = %d us", hw_panel_info_.transfer_time_us);
 }
 
 void HWDeviceDRM::GetHWDisplayPortAndMode() {
diff --git a/sdm/libs/hwc2/hwc_buffer_allocator.cpp b/sdm/libs/hwc2/hwc_buffer_allocator.cpp
index 3c8d460..4865e08 100644
--- a/sdm/libs/hwc2/hwc_buffer_allocator.cpp
+++ b/sdm/libs/hwc2/hwc_buffer_allocator.cpp
@@ -41,23 +41,43 @@
 
 namespace sdm {
 
-HWCBufferAllocator::HWCBufferAllocator() {
+DisplayError HWCBufferAllocator::Init() {
   int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module_);
   if (err != 0) {
-    DLOGE("FATAL: can not open GRALLOC module");
-  } else {
-    gralloc1_open(module_, &gralloc_device_);
+    DLOGE("FATAL: can not get GRALLOC module");
+    return kErrorResources;
   }
+
+  err = gralloc1_open(module_, &gralloc_device_);
+  if (err != 0) {
+    DLOGE("FATAL: can not open GRALLOC device");
+    return kErrorResources;
+  }
+
+  if (gralloc_device_ == nullptr) {
+    DLOGE("FATAL: gralloc device is null");
+    return kErrorResources;
+  }
+
   ReleaseBuffer_ = reinterpret_cast<GRALLOC1_PFN_RELEASE>(
       gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_RELEASE));
   Perform_ = reinterpret_cast<GRALLOC1_PFN_PERFORM>(
       gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_PERFORM));
+  Lock_ = reinterpret_cast<GRALLOC1_PFN_LOCK>(
+      gralloc_device_->getFunction(gralloc_device_, GRALLOC1_FUNCTION_LOCK));
+
+  return kErrorNone;
 }
 
-HWCBufferAllocator::~HWCBufferAllocator() {
+DisplayError HWCBufferAllocator::Deinit() {
   if (gralloc_device_ != nullptr) {
-    gralloc1_close(gralloc_device_);
+    int err = gralloc1_close(gralloc_device_);
+    if (err != 0) {
+      DLOGE("FATAL: can not close GRALLOC device");
+      return kErrorResources;
+    }
   }
+  return kErrorNone;
 }
 
 DisplayError HWCBufferAllocator::AllocateBuffer(BufferInfo *buffer_info) {
@@ -354,4 +374,21 @@
   return kErrorNone;
 }
 
+DisplayError HWCBufferAllocator::MapBuffer(const private_handle_t *handle, int acquire_fence) {
+  void* buffer_ptr = NULL;
+  const gralloc1_rect_t accessRegion = {
+        .left = 0,
+        .top = 0,
+        .width = 0,
+        .height = 0
+  };
+  Lock_(gralloc_device_, handle, GRALLOC1_PRODUCER_USAGE_CPU_READ, GRALLOC1_CONSUMER_USAGE_NONE,
+        &accessRegion, &buffer_ptr, acquire_fence);
+  if (!buffer_ptr) {
+    return kErrorUndefined;
+  }
+
+  return kErrorNone;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_buffer_allocator.h b/sdm/libs/hwc2/hwc_buffer_allocator.h
index d574401..8101d85 100644
--- a/sdm/libs/hwc2/hwc_buffer_allocator.h
+++ b/sdm/libs/hwc2/hwc_buffer_allocator.h
@@ -45,9 +45,8 @@
 
 class HWCBufferAllocator : public BufferAllocator {
  public:
-  HWCBufferAllocator();
-  ~HWCBufferAllocator();
-
+  DisplayError Init();
+  DisplayError Deinit();
   DisplayError AllocateBuffer(BufferInfo *buffer_info);
   DisplayError FreeBuffer(BufferInfo *buffer_info);
   uint32_t GetBufferSize(BufferInfo *buffer_info);
@@ -61,12 +60,14 @@
                                uint32_t stride[4], uint32_t offset[4],
                                uint32_t *num_planes);
   int SetBufferInfo(LayerBufferFormat format, int *target, uint64_t *flags);
+  DisplayError MapBuffer(const private_handle_t *handle, int acquire_fence);
 
  private:
   gralloc1_device_t *gralloc_device_ = nullptr;
   const hw_module_t *module_;
   GRALLOC1_PFN_RELEASE ReleaseBuffer_ = nullptr;
   GRALLOC1_PFN_PERFORM Perform_ = nullptr;
+  GRALLOC1_PFN_LOCK Lock_ = nullptr;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 34ff7e3..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;
 }
 
@@ -716,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;
@@ -730,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);
@@ -804,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,
@@ -836,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_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 7f39d7f..293ffce 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>(
@@ -96,19 +157,29 @@
 
   StartServices();
 
-  DisplayError error = CoreInterface::CreateCore(HWCDebugHandler::Get(), &buffer_allocator_,
-                                                 &buffer_sync_handler_, &socket_handler_,
-                                                 &core_intf_);
+  DisplayError error = buffer_allocator_.Init();
   if (error != kErrorNone) {
+    DLOGE("Buffer allocaor initialization failed. Error = %d", error);
+    return -EINVAL;
+  }
+
+  error = CoreInterface::CreateCore(HWCDebugHandler::Get(), &buffer_allocator_,
+                                    &buffer_sync_handler_, &socket_handler_, &core_intf_);
+  if (error != kErrorNone) {
+    buffer_allocator_.Deinit();
     DLOGE("Display core initialization failed. Error = %d", error);
     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();
+    buffer_allocator_.Deinit();
     DLOGE("Primary display type not recognized. Error = %d", error);
     return -EINVAL;
   }
@@ -132,7 +203,9 @@
   }
 
   if (status) {
+    g_hwc_uevent_.Register(nullptr);
     CoreInterface::DestroyCore();
+    buffer_allocator_.Deinit();
     return status;
   }
 
@@ -146,9 +219,6 @@
     }
   }
 
-  std::thread uevent_thread(HWCUeventThread, this);
-  uevent_thread_.swap(uevent_thread);
-
   return 0;
 }
 
@@ -167,10 +237,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) {
@@ -1238,52 +1305,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 3086fb4..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;
   }
 }
 
@@ -282,6 +289,7 @@
 }
 
 void HWCToneMapper::DumpToneMapOutput(ToneMapSession *session, int *acquire_fd) {
+  DisplayError error = kErrorNone;
   if (!dump_frame_count_) {
     return;
   }
@@ -297,6 +305,12 @@
     }
   }
 
+  error = buffer_allocator_->MapBuffer(target_buffer, *acquire_fd);
+  if (error != kErrorNone) {
+    DLOGE("MapBuffer failed, base addr = %x", target_buffer->base);
+    return;
+  }
+
   size_t result = 0;
   char dump_file_name[PATH_MAX];
   snprintf(dump_file_name, sizeof(dump_file_name), "%s/frame_dump_primary"
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] = {};