Merge "sdm: Set surfaceDamage numRects for solid-fill layer"
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index 4b62c9c..8b512bf 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -290,11 +290,20 @@
             grallocFormat = HAL_PIXEL_FORMAT_NV21_ZSL; //NV21 ZSL
         else if(usage & GRALLOC_USAGE_HW_CAMERA_READ)
             grallocFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP; //NV21
-        else if(usage & GRALLOC_USAGE_HW_CAMERA_WRITE)
-            grallocFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP; //NV21
-        else if(usage & GRALLOC_USAGE_HW_COMPOSER)
+        else if(usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
+           if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+               grallocFormat = HAL_PIXEL_FORMAT_NV21_ZSL; //NV21
+           } else {
+               grallocFormat = HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS; //NV12 preview
+           }
+        } else if(usage & GRALLOC_USAGE_HW_COMPOSER)
             //XXX: If we still haven't set a format, default to RGBA8888
             grallocFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+        else if(format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+            //If no other usage flags are detected, default the
+            //flexible YUV format to NV21_ZSL
+            grallocFormat = HAL_PIXEL_FORMAT_NV21_ZSL;
+        }
     }
 
     bool useFbMem = false;
diff --git a/libqdutils/display_config.h b/libqdutils/display_config.h
index 8e3fa78..101e230 100644
--- a/libqdutils/display_config.h
+++ b/libqdutils/display_config.h
@@ -49,6 +49,7 @@
 enum {
     DISPLAY_PRIMARY = 0,
     DISPLAY_EXTERNAL,
+    DISPLAY_TERTIARY,
     DISPLAY_VIRTUAL,
 };
 
diff --git a/sdm/include/private/color_params.h b/sdm/include/private/color_params.h
index e36f8e5..a34d84c 100644
--- a/sdm/include/private/color_params.h
+++ b/sdm/include/private/color_params.h
@@ -387,36 +387,10 @@
 
   // Once all features are consumed, destroy/release all TFeatureInfo<T> on the list,
   // then clear dirty_ flag and return the lock to the TFeatureInfo<T> producer.
-  inline void Reset() {
-    for (int i = 0; i < kMaxNumPPFeatures; i++) {
-      if (feature_[i]) {
-        delete feature_[i];
-        feature_[i] = NULL;
-      }
-    }
-    dirty_ = false;
-    next_idx_ = 0;
-  }
+  void Reset();
 
   // Consumer to call this to retrieve all the TFeatureInfo<T> on the list to be programmed.
-  inline DisplayError RetrieveNextFeature(PPFeatureInfo **feature) {
-    DisplayError ret = kErrorNone;
-    int i(0);
-
-    for (i = next_idx_; i < kMaxNumPPFeatures; i++) {
-      if (feature_[i]) {
-        *feature = feature_[i];
-        next_idx_ = i + 1;
-        break;
-      }
-    }
-    if (i == kMaxNumPPFeatures) {
-      ret = kErrorParameters;
-      next_idx_ = 0;
-    }
-
-    return ret;
-  }
+  DisplayError RetrieveNextFeature(PPFeatureInfo **feature);
 
   inline bool IsDirty() { return dirty_; }
   inline void MarkAsDirty() { dirty_ = true; }
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index 0c1b5f4..37d1f17 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -108,11 +108,9 @@
 struct HWSplitInfo {
   uint32_t left_split = 0;
   uint32_t right_split = 0;
-  bool always_src_split = false;
 
   bool operator !=(const HWSplitInfo &split_info) {
-    return ((left_split != split_info.left_split) || (right_split != split_info.right_split) ||
-            (always_src_split != split_info.always_src_split));
+    return ((left_split != split_info.left_split) || (right_split != split_info.right_split));
   }
 
   bool operator ==(const HWSplitInfo &split_info) {
@@ -166,22 +164,6 @@
   bool secure = false;
   bool cache = false;
   uint32_t frame_rate = 0;
-
-  bool operator != (const HWSessionConfig &input_config) const {
-    if ((src_width != input_config.src_width) || (src_height != input_config.src_height) ||
-        (src_format != input_config.src_format) || (dst_width != input_config.dst_width) ||
-        (dst_height != input_config.dst_height) || (dst_format != input_config.dst_format) ||
-        (buffer_count != input_config.buffer_count) || (secure != input_config.secure) ||
-        (cache != input_config.cache) || (frame_rate != input_config.frame_rate)) {
-      return true;
-    }
-
-    return false;
-  }
-
-  bool operator == (const HWSessionConfig &input_config) const {
-    return !(operator != (input_config));
-  }
 };
 
 struct HWRotateInfo {
@@ -287,7 +269,6 @@
 struct HWDisplayAttributes : DisplayConfigVariableInfo {
   bool is_device_split = false;
   uint32_t split_left = 0;
-  bool always_src_split = false;
   uint32_t v_front_porch = 0;  //!< Vertical front porch of panel
   uint32_t v_back_porch = 0;   //!< Vertical back porch of panel
   uint32_t v_pulse_width = 0;  //!< Vertical pulse width of panel
@@ -298,7 +279,6 @@
   bool operator !=(const HWDisplayAttributes &attributes) {
     return ((is_device_split != attributes.is_device_split) ||
             (split_left != attributes.split_left) ||
-            (always_src_split != attributes.always_src_split) ||
             (x_pixels != attributes.x_pixels) || (y_pixels != attributes.y_pixels) ||
             (x_dpi != attributes.x_dpi) || (y_dpi != attributes.y_dpi) || (fps != attributes.fps) ||
             (vsync_period_ns != attributes.vsync_period_ns) ||
diff --git a/sdm/include/utils/debug.h b/sdm/include/utils/debug.h
index 95efef6..c8a3a98 100644
--- a/sdm/include/utils/debug.h
+++ b/sdm/include/utils/debug.h
@@ -47,6 +47,7 @@
 #define DLOGE(format, ...) DLOGE_IF(kTagNone, format, ##__VA_ARGS__)
 #define DLOGW(format, ...) DLOGW_IF(kTagNone, format, ##__VA_ARGS__)
 #define DLOGI(format, ...) DLOGI_IF(kTagNone, format, ##__VA_ARGS__)
+#define DLOGV(format, ...) DLOGV_IF(kTagNone, format, ##__VA_ARGS__)
 
 #define DTRACE_BEGIN(custom_string) Debug::Get()->BeginTrace(__CLASS__, __FUNCTION__, custom_string)
 #define DTRACE_END() Debug::Get()->EndTrace()
diff --git a/sdm/libs/core/color_manager.cpp b/sdm/libs/core/color_manager.cpp
index 0de2078..aea55b0 100644
--- a/sdm/libs/core/color_manager.cpp
+++ b/sdm/libs/core/color_manager.cpp
@@ -42,6 +42,39 @@
 DestroyColorInterface ColorManagerProxy::destroy_intf_ = NULL;
 HWResourceInfo ColorManagerProxy::hw_res_info_;
 
+// Below two functions are part of concrete implementation for SDM core private
+// color_params.h
+void PPFeaturesConfig::Reset() {
+  for (int i = 0; i < kMaxNumPPFeatures; i++) {
+    if (feature_[i]) {
+      delete feature_[i];
+      feature_[i] = NULL;
+    }
+  }
+  dirty_ = false;
+  next_idx_ = 0;
+}
+
+DisplayError PPFeaturesConfig::RetrieveNextFeature(PPFeatureInfo **feature) {
+  DisplayError ret = kErrorNone;
+  int i(0);
+
+  for (i = next_idx_; i < kMaxNumPPFeatures; i++) {
+    if (feature_[i]) {
+      *feature = feature_[i];
+      next_idx_ = i + 1;
+      break;
+    }
+  }
+
+  if (i == kMaxNumPPFeatures) {
+    ret = kErrorParameters;
+    next_idx_ = 0;
+  }
+
+  return ret;
+}
+
 DisplayError ColorManagerProxy::Init(const HWResourceInfo &hw_res_info) {
   DisplayError error = kErrorNone;
 
diff --git a/sdm/libs/core/display_primary.cpp b/sdm/libs/core/display_primary.cpp
old mode 100644
new mode 100755
index 1a00da4..06bbccb
--- a/sdm/libs/core/display_primary.cpp
+++ b/sdm/libs/core/display_primary.cpp
@@ -148,7 +148,18 @@
 
 DisplayError DisplayPrimary::SetDisplayState(DisplayState state) {
   SCOPE_LOCK(locker_);
-  return DisplayBase::SetDisplayState(state);
+  DisplayError error = kErrorNone;
+  error = DisplayBase::SetDisplayState(state);
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  // Set vsync enable state to false, as driver disables vsync during display power off.
+  if (state == kStateOff) {
+    vsync_enable_ = false;
+  }
+
+  return kErrorNone;
 }
 
 DisplayError DisplayPrimary::SetActiveConfig(DisplayConfigVariableInfo *variable_info) {
diff --git a/sdm/libs/core/fb/hw_device.cpp b/sdm/libs/core/fb/hw_device.cpp
index 3ebd202..50e686a 100644
--- a/sdm/libs/core/fb/hw_device.cpp
+++ b/sdm/libs/core/fb/hw_device.cpp
@@ -595,6 +595,10 @@
     if (layer.transform.flip_horizontal) {
       *mdp_flags |= MDP_LAYER_FLIP_LR;
     }
+
+    if (input_buffer->flags.interlace) {
+      *mdp_flags |= MDP_LAYER_DEINTERLACE;
+    }
   }
 
   if (input_buffer->flags.secure) {
@@ -669,7 +673,6 @@
   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("Source Split Always = %d", hw_panel_info_.split_info.always_src_split);
 }
 
 void HWDevice::GetHWPanelInfoByNode(int device_node, HWPanelInfo *panel_info) {
@@ -820,7 +823,7 @@
 
   // Format "left right" space as delimiter
   read = Sys::getline_(&line, &len, fileptr);
-  if (read != -1) {
+  if (read > 0) {
     if (!ParseLine(line, tokens, max_count, &token_count)) {
       panel_info->split_info.left_split = atoi(tokens[0]);
       panel_info->split_info.right_split = atoi(tokens[1]);
@@ -828,24 +831,6 @@
   }
 
   Sys::fclose_(fileptr);
-
-  // SourceSplit enabled - Get More information
-  snprintf(stringbuffer , sizeof(stringbuffer), "%s%d/msm_fb_src_split_info", fb_path_,
-           device_node);
-  fileptr = Sys::fopen_(stringbuffer, "r");
-  if (!fileptr) {
-    DLOGW("File not found %s", stringbuffer);
-    return;
-  }
-
-  read = Sys::getline_(&line, &len, fileptr);
-  if (read != -1) {
-    if (!strncmp(line, "src_split_always", strlen("src_split_always"))) {
-      panel_info->split_info.always_src_split = true;
-    }
-  }
-
-  Sys::fclose_(fileptr);
 }
 
 int HWDevice::ParseLine(char *input, char *tokens[], const uint32_t max_token, uint32_t *count) {
diff --git a/sdm/libs/core/fb/hw_hdmi.cpp b/sdm/libs/core/fb/hw_hdmi.cpp
index 61d3df8..c47a0bd 100644
--- a/sdm/libs/core/fb/hw_hdmi.cpp
+++ b/sdm/libs/core/fb/hw_hdmi.cpp
@@ -483,6 +483,7 @@
   while (true) {
     char config_buffer[kPageSize] = {0};
     msm_hdmi_mode_timing_info *info = reinterpret_cast<msm_hdmi_mode_timing_info *>(config_buffer);
+    RequestNewPage(page_number);
 
     if (!ReadResolutionFile(config_buffer)) {
       break;
@@ -508,7 +509,6 @@
     // Request HDMI driver to populate res_info with more
     // timing information
     page_number++;
-    RequestNewPage(page_number);
   }
 
   if (page_number == MSM_HDMI_INIT_RES_PAGE || config_index == 0) {
diff --git a/sdm/libs/core/fb/hw_primary.cpp b/sdm/libs/core/fb/hw_primary.cpp
index 3c308d7..c548a26 100644
--- a/sdm/libs/core/fb/hw_primary.cpp
+++ b/sdm/libs/core/fb/hw_primary.cpp
@@ -325,7 +325,6 @@
       (var_screeninfo.xres > hw_resource_.max_mixer_width)) ? true : false;
   display_attributes_.split_left = hw_panel_info_.split_info.left_split ?
       hw_panel_info_.split_info.left_split : display_attributes_.x_pixels / 2;
-  display_attributes_.always_src_split = hw_panel_info_.split_info.always_src_split;
   display_attributes_.h_total += display_attributes_.is_device_split ? h_blanking : 0;
 
   return kErrorNone;
diff --git a/sdm/libs/core/resource_default.cpp b/sdm/libs/core/resource_default.cpp
index e421961..8c67b82 100644
--- a/sdm/libs/core/resource_default.cpp
+++ b/sdm/libs/core/resource_default.cpp
@@ -450,18 +450,13 @@
 DisplayError ResourceDefault::SrcSplitConfig(DisplayResourceContext *display_resource_ctx,
                                         const LayerRect &src_rect, const LayerRect &dst_rect,
                                         HWLayerConfig *layer_config) {
-  HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
   HWPipeInfo *left_pipe = &layer_config->left_pipe;
   HWPipeInfo *right_pipe = &layer_config->right_pipe;
   float src_width = src_rect.right - src_rect.left;
   float dst_width = dst_rect.right - dst_rect.left;
-  float left_mixer_width = FLOAT(display_attributes.split_left);
 
   // Layer cannot qualify for SrcSplit if source or destination width exceeds max pipe width.
-  // For perf/power optimization, even if "always_src_split" is enabled, use 2 pipes only if:
-  // Source width is greater than split_left (left_mixer_width)
-  if ((src_width > hw_res_info_.max_pipe_width) || (dst_width > hw_res_info_.max_pipe_width) ||
-      (display_resource_ctx->display_attributes.always_src_split && src_width > left_mixer_width)) {
+  if ((src_width > hw_res_info_.max_pipe_width) || (dst_width > hw_res_info_.max_pipe_width)) {
     SplitRect(src_rect, dst_rect, &left_pipe->src_roi, &left_pipe->dst_roi, &right_pipe->src_roi,
               &right_pipe->dst_roi);
     left_pipe->valid = true;
diff --git a/sdm/libs/core/strategy.cpp b/sdm/libs/core/strategy.cpp
index 6bd9a9c..0b7bd3c 100644
--- a/sdm/libs/core/strategy.cpp
+++ b/sdm/libs/core/strategy.cpp
@@ -50,9 +50,6 @@
 
     error = extension_intf_->CreatePartialUpdate(display_type_, hw_resource_info_,
                                                  hw_panel_info_, &partial_update_intf_);
-    if (error != kErrorNone) {
-      DLOGW("Partial Update creation failed, Continue without partial update.");
-    }
   }
 
   return kErrorNone;
diff --git a/sdm/libs/hwc/cpuhint.cpp b/sdm/libs/hwc/cpuhint.cpp
index f328268..ccf55bf 100644
--- a/sdm/libs/hwc/cpuhint.cpp
+++ b/sdm/libs/hwc/cpuhint.cpp
@@ -29,6 +29,7 @@
 
 #include <cutils/properties.h>
 #include <dlfcn.h>
+#include <utils/debug.h>
 
 #include "cpuhint.h"
 #include "hwc_debugger.h"
diff --git a/sdm/libs/hwc/cpuhint.h b/sdm/libs/hwc/cpuhint.h
index 14ecd93..a4a7758 100644
--- a/sdm/libs/hwc/cpuhint.h
+++ b/sdm/libs/hwc/cpuhint.h
@@ -44,7 +44,7 @@
   void Reset();
 
  private:
-  enum { HINT =  0x4701 /* 47-display layer hint, 01-Enable */ };
+  enum { HINT =  0x4501 /* 45-display layer hint, 01-Enable */ };
   bool enabled_ = false;
   // frames to wait before setting this hint
   int pre_enable_window_ = 0;
diff --git a/sdm/libs/hwc/hwc_buffer_allocator.cpp b/sdm/libs/hwc/hwc_buffer_allocator.cpp
index 1ea2915..3149718 100644
--- a/sdm/libs/hwc/hwc_buffer_allocator.cpp
+++ b/sdm/libs/hwc/hwc_buffer_allocator.cpp
@@ -32,6 +32,7 @@
 #include <gr.h>
 #include <alloc_controller.h>
 #include <utils/constants.h>
+#include <utils/debug.h>
 #include <core/buffer_allocator.h>
 
 #include "hwc_debugger.h"
diff --git a/sdm/libs/hwc/hwc_buffer_sync_handler.cpp b/sdm/libs/hwc/hwc_buffer_sync_handler.cpp
index 949745e..581bcd6 100644
--- a/sdm/libs/hwc/hwc_buffer_sync_handler.cpp
+++ b/sdm/libs/hwc/hwc_buffer_sync_handler.cpp
@@ -29,6 +29,7 @@
 
 #include <sync/sync.h>
 #include <utils/constants.h>
+#include <utils/debug.h>
 
 #include "hwc_debugger.h"
 #include "hwc_buffer_sync_handler.h"
diff --git a/sdm/libs/hwc/hwc_color_manager.cpp b/sdm/libs/hwc/hwc_color_manager.cpp
index 891d036..fcd2a55 100644
--- a/sdm/libs/hwc/hwc_color_manager.cpp
+++ b/sdm/libs/hwc/hwc_color_manager.cpp
@@ -40,6 +40,7 @@
 
 #include <core/dump_interface.h>
 #include <utils/constants.h>
+#include <utils/debug.h>
 #include <core/buffer_allocator.h>
 #include <private/color_params.h>
 #include "hwc_buffer_allocator.h"
@@ -141,9 +142,16 @@
   return color_mgr;
 }
 
-HWCColorManager::~HWCColorManager() {}
+HWCColorManager::~HWCColorManager() {
+}
 
 void HWCColorManager::DestroyColorManager() {
+  if (qdcm_mode_mgr_) {
+    delete qdcm_mode_mgr_;
+  }
+  if (qdcm_diag_deinit_) {
+    qdcm_diag_deinit_();
+  }
   if (diag_client_lib_) {
     ::dlclose(diag_client_lib_);
   }
@@ -156,24 +164,16 @@
 int HWCColorManager::EnableQDCMMode(bool enable, HWCDisplay *hwc_display) {
   int ret = 0;
 
-  if (enable) {  // entering QDCM mode, disable all active features and acquire Android wakelock
+  if (!qdcm_mode_mgr_) {
     qdcm_mode_mgr_ = HWCQDCMModeManager::CreateQDCMModeMgr();
     if (!qdcm_mode_mgr_) {
-      DLOGE("failing to create QDCM operating mode manager.");
+      DLOGE("Unable to create QDCM operating mode manager.");
       ret = -EFAULT;
-    } else {
-      ret = qdcm_mode_mgr_->EnableQDCMMode(enable, hwc_display);
     }
-  } else {  // exiting QDCM mode, reverse the effect of entering.
-    if (!qdcm_mode_mgr_) {
-      DLOGE("failing to disable QDCM operating mode manager.");
-      ret = -EFAULT;
-    } else {  // once exiting from QDCM operating mode, destroy QDCMModeMgr and release the
-              // resources
-      ret = qdcm_mode_mgr_->EnableQDCMMode(enable, hwc_display);
-      delete qdcm_mode_mgr_;
-      qdcm_mode_mgr_ = NULL;
-    }
+  }
+
+  if (qdcm_mode_mgr_) {
+    ret = qdcm_mode_mgr_->EnableQDCMMode(enable, hwc_display);
   }
 
   return ret;
@@ -407,6 +407,7 @@
                                              const HWCQDCMModeManager::ActiveFeatureCMD &cmds,
                                              bool *was_running) {
   int ret = 0;
+  ssize_t size = 0;
   char response[kSocketCMDMaxLength] = {
       0,
   };
@@ -418,25 +419,31 @@
 
   if (!enable) {  // if client requesting to disable it.
     // query CABL status, if off, no action. keep the status.
-    if (::write(socket_fd_, cmds.cmd_query_status, strlen(cmds.cmd_query_status)) < 0) {
+    size = ::write(socket_fd_, cmds.cmd_query_status, strlen(cmds.cmd_query_status));
+    if (size < 0) {
       DLOGW("Unable to send data over socket %s", ::strerror(errno));
       ret = -EFAULT;
-    } else if (::read(socket_fd_, response, kSocketCMDMaxLength) < 0) {
-      DLOGW("Unable to read data over socket %s", ::strerror(errno));
-      ret = -EFAULT;
-    } else if (!strncmp(response, cmds.running, strlen(cmds.running))) {
-      *was_running = true;
+    } else {
+      size = ::read(socket_fd_, response, kSocketCMDMaxLength);
+      if (size < 0) {
+        DLOGW("Unable to read data over socket %s", ::strerror(errno));
+        ret = -EFAULT;
+      } else if (!strncmp(response, cmds.running, strlen(cmds.running))) {
+        *was_running = true;
+      }
     }
 
     if (*was_running) {  // if was running, it's requested to disable it.
-      if (::write(socket_fd_, cmds.cmd_off, strlen(cmds.cmd_off)) < 0) {
+      size = ::write(socket_fd_, cmds.cmd_off, strlen(cmds.cmd_off));
+      if (size < 0) {
         DLOGW("Unable to send data over socket %s", ::strerror(errno));
         ret = -EFAULT;
       }
     }
   } else {  // if was running, need enable it back.
     if (*was_running) {
-      if (::write(socket_fd_, cmds.cmd_on, strlen(cmds.cmd_on)) < 0) {
+      size = ::write(socket_fd_, cmds.cmd_on, strlen(cmds.cmd_on));
+      if (size < 0) {
         DLOGW("Unable to send data over socket %s", ::strerror(errno));
         ret = -EFAULT;
       }
diff --git a/sdm/libs/hwc/hwc_debugger.h b/sdm/libs/hwc/hwc_debugger.h
index 474e1c5..e4e1ea3 100644
--- a/sdm/libs/hwc/hwc_debugger.h
+++ b/sdm/libs/hwc/hwc_debugger.h
@@ -37,19 +37,6 @@
 #include <cutils/log.h>
 #include <utils/Trace.h>
 
-#define DLOG(Macro, format, ...) Macro(__CLASS__ "::%s: " format, __FUNCTION__, ##__VA_ARGS__)
-
-#define DLOGE(format, ...) DLOG(ALOGE, format, ##__VA_ARGS__)
-#define DLOGW(format, ...) DLOG(ALOGW, format, ##__VA_ARGS__)
-#define DLOGI(format, ...) DLOG(ALOGI, format, ##__VA_ARGS__)
-#define DLOGD(format, ...) DLOG(ALOGI, format, ##__VA_ARGS__)
-#define DLOGV(format, ...) DLOG(ALOGV, format, ##__VA_ARGS__)
-
-#define DTRACE_BEGIN(custom_string) HWCDebugHandler::Get()->BeginTrace(__CLASS__, __FUNCTION__, \
-                                                                       custom_string)
-#define DTRACE_END() HWCDebugHandler::Get()->EndTrace()
-#define DTRACE_SCOPED() ScopeTracer<HWCDebugHandler> scope_tracer(__CLASS__, __FUNCTION__)
-
 namespace sdm {
 
 class HWCDebugHandler : public DebugHandler {
diff --git a/sdm/libs/hwc/hwc_display.cpp b/sdm/libs/hwc/hwc_display.cpp
index 30577a8..7fe8984 100644
--- a/sdm/libs/hwc/hwc_display.cpp
+++ b/sdm/libs/hwc/hwc_display.cpp
@@ -32,6 +32,8 @@
 #include <gralloc_priv.h>
 #include <gr.h>
 #include <utils/constants.h>
+#include <utils/rect.h>
+#include <utils/debug.h>
 #include <sync/sync.h>
 #include <cutils/properties.h>
 
@@ -60,8 +62,6 @@
   if (layer->input_buffer->flags.interlace) {
     float height = (layer->src_rect.bottom - layer->src_rect.top) / 2.0f;
     layer->src_rect.bottom = layer->src_rect.top + floorf(height);
-    layer->input_buffer->height /= 2;
-    layer->input_buffer->width *= 2;
   }
 }
 
@@ -477,6 +477,7 @@
 
   use_blit_comp_ = false;
   metadata_refresh_rate_ = 0;
+  display_rect_ = LayerRect();
 
   // Configure each layer
   for (size_t i = 0; i < num_hw_layers; i++) {
@@ -506,6 +507,11 @@
     }
     SetComposition(hwc_layer.compositionType, &layer.composition);
 
+    if (hwc_layer.compositionType != HWC_FRAMEBUFFER_TARGET) {
+      display_rect_ = Union(display_rect_, layer.dst_rect);
+    }
+
+
     // For dim layers, SurfaceFlinger
     //    - converts planeAlpha to per pixel alpha,
     //    - sets RGB color to 000,
@@ -1308,6 +1314,21 @@
   return ret;
 }
 
+int HWCDisplay::GetVisibleDisplayRect(hwc_rect_t* visible_rect) {
+  if (!IsValid(display_rect_)) {
+    return -EINVAL;
+  }
+
+  visible_rect->left = INT(display_rect_.left);
+  visible_rect->top = INT(display_rect_.top);
+  visible_rect->right = INT(display_rect_.right);
+  visible_rect->bottom = INT(display_rect_.bottom);
+  DLOGI("Dpy = %d Visible Display Rect(%d %d %d %d)", visible_rect->left, visible_rect->top,
+        visible_rect->right, visible_rect->bottom);
+
+  return 0;
+}
+
 void HWCDisplay::ResetLayerCacheStack() {
   uint32_t layer_count = layer_stack_cache_.layer_count;
   for (uint32_t i = 0; i < layer_count; i++) {
diff --git a/sdm/libs/hwc/hwc_display.h b/sdm/libs/hwc/hwc_display.h
index 3714a95..ce624a3 100644
--- a/sdm/libs/hwc/hwc_display.h
+++ b/sdm/libs/hwc/hwc_display.h
@@ -76,6 +76,7 @@
   int ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload,
                            PPDisplayAPIPayload *out_payload,
                            PPPendingParams *pending_action);
+  int GetVisibleDisplayRect(hwc_rect_t* rect);
 
  protected:
   enum DisplayStatus {
@@ -186,7 +187,8 @@
   bool skip_prepare_ = false;
 
   bool solid_fill_enable_ = false;
-  uint32_t solid_fill_color_ = 0;;
+  uint32_t solid_fill_color_ = 0;
+  LayerRect display_rect_;
 
  private:
   bool IsFrameBufferScaled();
diff --git a/sdm/libs/hwc/hwc_display_external.cpp b/sdm/libs/hwc/hwc_display_external.cpp
index 9053b42..a02be81 100644
--- a/sdm/libs/hwc/hwc_display_external.cpp
+++ b/sdm/libs/hwc/hwc_display_external.cpp
@@ -29,6 +29,7 @@
 
 #include <cutils/properties.h>
 #include <utils/constants.h>
+#include <utils/debug.h>
 
 #include "hwc_display_external.h"
 #include "hwc_debugger.h"
@@ -53,7 +54,7 @@
   hwc_display_external->GetPanelResolution(&external_width, &external_height);
 
   int downscale_enabled = 0;
-  HWCDebugHandler::Get()->GetProperty("sdm.debug.sde_downscale_external", &downscale_enabled);
+  HWCDebugHandler::Get()->GetProperty("sdm.debug.downscale_external", &downscale_enabled);
   if (downscale_enabled) {
     GetDownscaleResolution(primary_width, primary_height, &external_width, &external_height);
   }
diff --git a/sdm/libs/hwc/hwc_display_primary.cpp b/sdm/libs/hwc/hwc_display_primary.cpp
index d12bd1d..9842b61 100644
--- a/sdm/libs/hwc/hwc_display_primary.cpp
+++ b/sdm/libs/hwc/hwc_display_primary.cpp
@@ -29,6 +29,7 @@
 
 #include <cutils/properties.h>
 #include <utils/constants.h>
+#include <utils/debug.h>
 #include <stdarg.h>
 #include "hwc_display_primary.h"
 #include "hwc_debugger.h"
diff --git a/sdm/libs/hwc/hwc_display_virtual.cpp b/sdm/libs/hwc/hwc_display_virtual.cpp
index 116c36d..219a81b 100644
--- a/sdm/libs/hwc/hwc_display_virtual.cpp
+++ b/sdm/libs/hwc/hwc_display_virtual.cpp
@@ -28,6 +28,7 @@
 */
 
 #include <utils/constants.h>
+#include <utils/debug.h>
 #include <sync/sync.h>
 #include <stdarg.h>
 #include <gr.h>
@@ -86,7 +87,7 @@
 
   *hwc_display = static_cast<HWCDisplay *>(hwc_display_virtual);
 
-  return status;
+  return 0;
 }
 
 void HWCDisplayVirtual::Destroy(HWCDisplay *hwc_display) {
diff --git a/sdm/libs/hwc/hwc_session.cpp b/sdm/libs/hwc/hwc_session.cpp
index 98444e1..f938f0d 100644
--- a/sdm/libs/hwc/hwc_session.cpp
+++ b/sdm/libs/hwc/hwc_session.cpp
@@ -41,6 +41,7 @@
 #include <gr.h>
 #include <gralloc_priv.h>
 #include <display_config.h>
+#include <utils/debug.h>
 
 #include "hwc_buffer_allocator.h"
 #include "hwc_buffer_sync_handler.h"
@@ -73,6 +74,7 @@
 namespace sdm {
 
 Locker HWCSession::locker_;
+Locker HWCSession::concurrency_locker_;
 bool HWCSession::reset_panel_ = false;
 
 static void Invalidate(const struct hwc_procs *procs) {
@@ -292,22 +294,31 @@
 
   for (size_t dpy = 0; dpy < num_displays; dpy++) {
     hwc_display_contents_1_t *content_list = displays[dpy];
-    if (dpy == HWC_DISPLAY_VIRTUAL) {
-      if (hwc_session->hwc_display_[HWC_DISPLAY_EXTERNAL]) {
-        if (content_list) {
-          for (size_t i = 0; i < content_list->numHwLayers; i++) {
-            if (content_list->hwLayers[i].acquireFenceFd >= 0) {
-              close(content_list->hwLayers[i].acquireFenceFd);
-              content_list->hwLayers[i].acquireFenceFd = -1;
-            }
-          }
-          if (content_list->outbufAcquireFenceFd >= 0) {
-            close(content_list->outbufAcquireFenceFd);
-            content_list->outbufAcquireFenceFd = -1;
-          }
-          content_list->retireFenceFd = -1;
+
+    // Drop virtual display composition if virtual display object could not be created
+    // due to HDMI concurrency.
+    if (dpy == HWC_DISPLAY_VIRTUAL && !hwc_session->hwc_display_[HWC_DISPLAY_VIRTUAL]) {
+      if (!content_list) {
+        continue;
+      }
+
+      for (size_t i = 0; i < content_list->numHwLayers; i++) {
+        int &acquireFenceFd = content_list->hwLayers[i].acquireFenceFd;
+        if (acquireFenceFd >= 0) {
+          close(acquireFenceFd);
+          acquireFenceFd = -1;
         }
       }
+
+      int &outbufAcquireFenceFd = content_list->outbufAcquireFenceFd;
+      if (outbufAcquireFenceFd >= 0) {
+        close(outbufAcquireFenceFd);
+        outbufAcquireFenceFd = -1;
+      }
+
+      content_list->retireFenceFd = -1;
+
+      continue;
     }
 
     if (hwc_session->hwc_display_[dpy]) {
@@ -499,31 +510,35 @@
   return status;
 }
 
-int HWCSession::HandleVirtualDisplayLifeCycle(hwc_display_contents_1_t *content_list) {
-  int status = 0;
+void HWCSession::HandleVirtualDisplayLifeCycle(hwc_display_contents_1_t *content_list) {
+  // Virtual display & HDMI concurrency is not supported.
+  // Acquire concurrency mutex before creating / destroying virtual display.
+  // Signal concurrency condition on virtual display destroy so that HDMI hotplug could
+  // proceed with connection.
+  SCOPE_LOCK(concurrency_locker_);
 
   if (HWCDisplayVirtual::IsValidContentList(content_list)) {
     if (!hwc_display_[HWC_DISPLAY_VIRTUAL]) {
+      DLOGI("Create Virtual Display");
       uint32_t primary_width = 0;
       uint32_t primary_height = 0;
       hwc_display_[HWC_DISPLAY_PRIMARY]->GetFrameBufferResolution(&primary_width, &primary_height);
-      // Create virtual display device
-      status = HWCDisplayVirtual::Create(core_intf_, &hwc_procs_, primary_width, primary_height,
-                                         content_list, &hwc_display_[HWC_DISPLAY_VIRTUAL]);
-      if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
+
+      int status = HWCDisplayVirtual::Create(core_intf_, &hwc_procs_, primary_width,
+                                             primary_height, content_list,
+                                             &hwc_display_[HWC_DISPLAY_VIRTUAL]);
+      if (!status) {
         hwc_display_[HWC_DISPLAY_VIRTUAL]->SetSecureDisplay(secure_display_active_);
       }
     }
   } else {
     if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
+      DLOGI("Destroy Virtual Display");
       HWCDisplayVirtual::Destroy(hwc_display_[HWC_DISPLAY_VIRTUAL]);
-      hwc_display_[HWC_DISPLAY_VIRTUAL] = 0;
-      // Signal the HotPlug thread to continue with the external display connection
-      locker_.Signal();
+      hwc_display_[HWC_DISPLAY_VIRTUAL] = NULL;
+      concurrency_locker_.Signal();
     }
   }
-
-  return status;
 }
 
 android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
@@ -559,8 +574,9 @@
   case qService::IQService::SET_DISPLAY_MODE:
     status = SetDisplayMode(input_parcel);
     break;
+
   case qService::IQService::SET_SECONDARY_DISPLAY_STATUS:
-    status = SetSecondaryDisplayStatus(input_parcel);
+    status = SetSecondaryDisplayStatus(input_parcel, output_parcel);
     break;
 
   case qService::IQService::CONFIGURE_DYN_REFRESH_RATE:
@@ -610,6 +626,10 @@
     status = SetPanelBrightness(input_parcel, output_parcel);
     break;
 
+  case qService::IQService::GET_DISPLAY_VISIBLE_REGION:
+    status = GetVisibleDisplayRect(input_parcel, output_parcel);
+    break;
+
   default:
     DLOGW("QService command = %d is not supported", command);
     return -EINVAL;
@@ -705,11 +725,11 @@
     return ret;
   }
 
+  // Todo(user): Unlock it before sending events to client. It may cause deadlocks in future.
   hwc_procs_->invalidate(hwc_procs_);
 
   // Wait until partial update control is complete
   ret = locker_.WaitFinite(kPartialUpdateControlTimeoutMs);
-  locker_.Unlock();
 
   out->writeInt32(ret);
 
@@ -803,17 +823,28 @@
   return error;
 }
 
-android::status_t HWCSession::SetSecondaryDisplayStatus(const android::Parcel *input_parcel) {
+android::status_t HWCSession::SetSecondaryDisplayStatus(const android::Parcel *input_parcel,
+                                                        android::Parcel *output_parcel) {
+  int ret = -EINVAL;
+
   uint32_t display_id = UINT32(input_parcel->readInt32());
   uint32_t display_status = UINT32(input_parcel->readInt32());
 
-  DLOGI("Display %d Status %d", display_id, display_status);
-  if (display_id < HWC_DISPLAY_EXTERNAL || display_id > HWC_DISPLAY_VIRTUAL) {
-    DLOGW("Not supported for display %d", display_id);
-    return -EINVAL;
+  DLOGI("Display = %d, Status = %d", display_id, display_status);
+
+  if (display_id >= HWC_NUM_DISPLAY_TYPES) {
+    DLOGE("Invalid display_id");
+  } else if (display_id == HWC_DISPLAY_PRIMARY) {
+    DLOGE("Not supported for this display");
+  } else if (!hwc_display_[display_id]) {
+    DLOGW("Display is not connected");
+  } else {
+    ret = hwc_display_[display_id]->SetDisplayStatus(display_status);
   }
 
-  return hwc_display_[display_id]->SetDisplayStatus(display_status);
+  output_parcel->writeInt32(ret);
+
+  return ret;
 }
 
 android::status_t HWCSession::ConfigureRefreshRate(const android::Parcel *input_parcel) {
@@ -1025,10 +1056,13 @@
   uint32_t display_id = UINT32(input_parcel->readInt32());
 
   DLOGI("Display %d", display_id);
-  if (display_id != HWC_DISPLAY_EXTERNAL) {
-    DLOGW("Not supported for display %d", display_id);
+
+  if (display_id >= HWC_NUM_DISPLAY_TYPES) {
+    DLOGE("Invalid display_id");
+  } else if (display_id != HWC_DISPLAY_EXTERNAL) {
+    DLOGE("Not supported for display");
   } else if (!hwc_display_[display_id]) {
-    DLOGE("Display %d is not connected", display_id);
+    DLOGW("Display is not connected");
   } else {
     ret = hwc_display_[display_id]->OnMinHdcpEncryptionLevelChange();
   }
@@ -1126,46 +1160,66 @@
 }
 
 int HWCSession::HotPlugHandler(bool connected) {
-  if (!hwc_procs_) {
-     DLOGW("Ignore hotplug - hwc_proc not registered");
-    return -1;
-  }
+  // To prevent sending events to client while a lock is held, acquire scope locks only within
+  // below scope so that those get automatically unlocked after the scope ends.
+  {
+    // Virtual display & HDMI concurrency is not supported. Acquire concurrency lock
+    // and wait for virtual display to tear down if connected.
+    SCOPE_LOCK(concurrency_locker_);
 
-  if (connected) {
-    SEQUENCE_WAIT_SCOPE_LOCK(locker_);
-    if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
-      // Wait for the virtual display to tear down
-      int status = locker_.WaitFinite(kExternalConnectionTimeoutMs);
-      if (status != 0) {
-        DLOGE("Timed out while waiting for virtual display to tear down.");
+    if (connected) {
+      // Acquire global lock and check if virtual display is connected.
+      // Release global lock before waiting for virtual display to disconnect and signal.
+      bool virtual_display_connected = false;
+      {
+        SCOPE_LOCK(locker_);
+        if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
+          DLOGE("Primay display is not connected");
+          return -1;
+        }
+
+        if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
+          DLOGE("HDMI is already connected");
+          return -1;
+        }
+
+        virtual_display_connected = (hwc_display_[HWC_DISPLAY_VIRTUAL] != NULL);
+        DLOGI("Virtual display connection status = %d", virtual_display_connected);
+      }
+
+      if (virtual_display_connected) {
+        DLOGI("Wait for virtual display to disconnect.");
+        concurrency_locker_.Wait();
+        DLOGI("virtual display is disconnected now.");
+      }
+
+      // Acquire global sequence lock now.
+      SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+      uint32_t primary_width = 0;
+      uint32_t primary_height = 0;
+      hwc_display_[HWC_DISPLAY_PRIMARY]->GetFrameBufferResolution(&primary_width, &primary_height);
+
+      // Create hdmi display
+      int status = HWCDisplayExternal::Create(core_intf_, &hwc_procs_, primary_width,
+                                              primary_height, &hwc_display_[HWC_DISPLAY_EXTERNAL]);
+      if (status) {
+        return status;
+      }
+
+      hwc_display_[HWC_DISPLAY_EXTERNAL]->SetSecureDisplay(secure_display_active_);
+    } else {
+      // Acquire concurrency lock as well as global sequence lock.
+      SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
+      if (!hwc_display_[HWC_DISPLAY_EXTERNAL]) {
+        DLOGE("HDMI not connected");
         return -1;
       }
-    }
-    if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
-     DLOGE("HDMI already connected");
-     return -1;
-    }
 
-    uint32_t primary_width = 0;
-    uint32_t primary_height = 0;
-    hwc_display_[HWC_DISPLAY_PRIMARY]->GetFrameBufferResolution(&primary_width, &primary_height);
-    // Create hdmi display
-    int status = HWCDisplayExternal::Create(core_intf_, &hwc_procs_, primary_width,
-                                            primary_height, &hwc_display_[HWC_DISPLAY_EXTERNAL]);
-    if (status) {
-      return status;
+      HWCDisplayExternal::Destroy(hwc_display_[HWC_DISPLAY_EXTERNAL]);
+      hwc_display_[HWC_DISPLAY_EXTERNAL] = NULL;
     }
-    if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
-      hwc_display_[HWC_DISPLAY_EXTERNAL]->SetSecureDisplay(secure_display_active_);
-    }
-  } else {
-    SEQUENCE_WAIT_SCOPE_LOCK(locker_);
-    if (!hwc_display_[HWC_DISPLAY_EXTERNAL]) {
-     DLOGE("HDMI not connected");
-     return -1;
-    }
-    HWCDisplayExternal::Destroy(hwc_display_[HWC_DISPLAY_EXTERNAL]);
-    hwc_display_[HWC_DISPLAY_EXTERNAL] = 0;
   }
 
   // notify client and trigger a screen refresh
@@ -1204,5 +1258,31 @@
   }
 }
 
+android::status_t HWCSession::GetVisibleDisplayRect(const android::Parcel *input_parcel,
+                                                    android::Parcel *output_parcel) {
+  int dpy = input_parcel->readInt32();
+
+  if (dpy < HWC_DISPLAY_PRIMARY || dpy > HWC_DISPLAY_VIRTUAL) {
+    return android::BAD_VALUE;;
+  }
+
+  if (!hwc_display_[dpy]) {
+    return android::NO_INIT;
+  }
+
+  hwc_rect_t visible_rect = {0, 0, 0, 0};
+  int error = hwc_display_[dpy]->GetVisibleDisplayRect(&visible_rect);
+  if (error < 0) {
+    return error;
+  }
+
+  output_parcel->writeInt32(visible_rect.left);
+  output_parcel->writeInt32(visible_rect.top);
+  output_parcel->writeInt32(visible_rect.right);
+  output_parcel->writeInt32(visible_rect.bottom);
+
+  return android::NO_ERROR;
+}
+
 }  // namespace sdm
 
diff --git a/sdm/libs/hwc/hwc_session.h b/sdm/libs/hwc/hwc_session.h
index 22574dc..1dde96e 100644
--- a/sdm/libs/hwc/hwc_session.h
+++ b/sdm/libs/hwc/hwc_session.h
@@ -80,7 +80,7 @@
   int GetEventValue(const char *uevent_data, int length, const char *event_info);
   int HotPlugHandler(bool connected);
   void ResetPanel();
-  int HandleVirtualDisplayLifeCycle(hwc_display_contents_1_t *content_list);
+  void HandleVirtualDisplayLifeCycle(hwc_display_contents_1_t *content_list);
   void HandleSecureDisplaySession(hwc_display_contents_1_t **displays);
 
   // QClient methods
@@ -90,7 +90,8 @@
   void SetFrameDumpConfig(const android::Parcel *input_parcel);
   android::status_t SetMaxMixerStages(const android::Parcel *input_parcel);
   android::status_t SetDisplayMode(const android::Parcel *input_parcel);
-  android::status_t SetSecondaryDisplayStatus(const android::Parcel *input_parcel);
+  android::status_t SetSecondaryDisplayStatus(const android::Parcel *input_parcel,
+                                              android::Parcel *output_parcel);
   android::status_t ToggleScreenUpdates(const android::Parcel *input_parcel,
                                         android::Parcel *output_parcel);
   android::status_t ConfigureRefreshRate(const android::Parcel *input_parcel);
@@ -112,8 +113,11 @@
                                                 android::Parcel *output_parcel);
   android::status_t HandleGetDisplayAttributesForConfig(const android::Parcel *input_parcel,
                                                         android::Parcel *output_parcel);
+  android::status_t GetVisibleDisplayRect(const android::Parcel *input_parcel,
+                                          android::Parcel *output_parcel);
 
   static Locker locker_;
+  static Locker concurrency_locker_;
   CoreInterface *core_intf_ = NULL;
   hwc_procs_t hwc_procs_default_;
   hwc_procs_t const *hwc_procs_ = &hwc_procs_default_;