Merge "gralloc1: Do not do early validation on Release"
diff --git a/libdrmutils/drm_interface.h b/libdrmutils/drm_interface.h
index ca2f6ff..4ecfcbf 100644
--- a/libdrmutils/drm_interface.h
+++ b/libdrmutils/drm_interface.h
@@ -138,6 +138,12 @@
    */
   PLANE_SET_FB_SECURE_MODE,
   /*
+   * Op: Sets csc config on this plane.
+   * Arg: uint32_t - Plane ID
+   *      uint32_t* - pointer to csc type
+   */
+  PLANE_SET_CSC_CONFIG,
+  /*
    * Op: Activate or deactivate a CRTC
    * Arg: uint32_t - CRTC ID
    *      uint32_t - 1 to enable, 0 to disable
@@ -465,6 +471,15 @@
   void *payload;
 };
 
+enum DRMCscType {
+  kCscYuv2Rgb601L,
+  kCscYuv2Rgb601FR,
+  kCscYuv2Rgb709L,
+  kCscYuv2Rgb2020L,
+  kCscYuv2Rgb2020FR,
+  kCscTypeMax,
+};
+
 struct DRMScalerLUTInfo {
   uint32_t dir_lut_size = 0;
   uint32_t cir_lut_size = 0;
diff --git a/libgralloc1/gr_buf_mgr.cpp b/libgralloc1/gr_buf_mgr.cpp
index bb37da0..d6753d8 100644
--- a/libgralloc1/gr_buf_mgr.cpp
+++ b/libgralloc1/gr_buf_mgr.cpp
@@ -278,13 +278,6 @@
   } else {
     private_handle_t *handle = const_cast<private_handle_t *>(hnd);
     err = ImportHandleLocked(handle);
-    if (err == GRALLOC1_ERROR_NONE) {
-      // TODO(user): See bug 35955598
-      if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
-        return GRALLOC1_ERROR_NONE;  // Don't map secure buffer
-      }
-      err = MapBuffer(hnd);
-    }
   }
   return err;
 }
@@ -709,6 +702,12 @@
         return GRALLOC1_ERROR_BAD_HANDLE;
       }
       *flag = hnd->flags &private_handle_t::PRIV_FLAGS_UBWC_ALIGNED;
+      int linear_format = 0;
+      if (getMetaData(hnd, GET_LINEAR_FORMAT, &linear_format) == 0) {
+        if (!linear_format) {
+         *flag = 0;
+        }
+      }
     } break;
 
     case GRALLOC_MODULE_PERFORM_GET_RGB_DATA_ADDRESS: {
diff --git a/libgralloc1/gr_utils.cpp b/libgralloc1/gr_utils.cpp
index 560bb08..d89b8fe 100644
--- a/libgralloc1/gr_utils.cpp
+++ b/libgralloc1/gr_utils.cpp
@@ -357,29 +357,33 @@
   bool interlaced = false;
 
   memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
-  MetaData_t *metadata = reinterpret_cast<MetaData_t *>(hnd->base_metadata);
 
   // Check if UBWC buffer has been rendered in linear format.
-  if (metadata && (metadata->operation & LINEAR_FORMAT)) {
-    format = INT(metadata->linearFormat);
+  int linear_format = 0;
+  if (getMetaData(const_cast<private_handle_t *>(hnd),
+                  GET_LINEAR_FORMAT, &linear_format) == 0) {
+      format = INT(linear_format);
   }
 
   // Check metadata if the geometry has been updated.
-  if (metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
+  BufferDim_t buffer_dim;
+  if (getMetaData(const_cast<private_handle_t *>(hnd),
+                  GET_BUFFER_GEOMETRY, &buffer_dim) == 0) {
     int usage = 0;
-
     if (hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) {
       usage = GRALLOC1_PRODUCER_USAGE_PRIVATE_ALLOC_UBWC;
     }
 
-    BufferInfo info(metadata->bufferDim.sliceWidth, metadata->bufferDim.sliceHeight, format,
+    BufferInfo info(buffer_dim.sliceWidth, buffer_dim.sliceHeight, format,
                     prod_usage, cons_usage);
     GetAlignedWidthAndHeight(info, &width, &height);
   }
 
   // Check metadata for interlaced content.
-  if (metadata && (metadata->operation & PP_PARAM_INTERLACED)) {
-    interlaced = metadata->interlaced ? true : false;
+  int interlace_flag = 0;
+  if (getMetaData(const_cast<private_handle_t *>(hnd),
+                  GET_PP_PARAM_INTERLACED, &interlace_flag) != 0) {
+    interlaced = interlace_flag;
   }
 
   // Get the chroma offsets from the handle width/height. We take advantage
diff --git a/libgralloc1/gralloc_priv.h b/libgralloc1/gralloc_priv.h
index 87604c6..2abdd84 100644
--- a/libgralloc1/gralloc_priv.h
+++ b/libgralloc1/gralloc_priv.h
@@ -78,6 +78,7 @@
 #define GRALLOC_USAGE_PRIVATE_IOMMU_HEAP GRALLOC1_PRODUCER_USAGE_PRIVATE_IOMMU_HEAP
 #define GRALLOC_USAGE_PRIVATE_WFD GRALLOC1_CONSUMER_USAGE_PRIVATE_WFD
 #define GRALLOC_USAGE_PRIVATE_CAMERA_HEAP GRALLOC1_PRODUCER_USAGE_PRIVATE_CAMERA_HEAP
+#define GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY GRALLOC1_CONSUMER_USAGE_PRIVATE_SECURE_DISPLAY
 #define GRALLOC_USAGE_PRIVATE_MM_HEAP 0x0
 
 
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index 524141e..b8e2a9e 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -135,6 +135,12 @@
   kPortDP,         // Display is connected to DP port.
 };
 
+/*! @brief This enum represents the events received by Display HAL. */
+enum DisplayEvent {
+  kIdleTimeout,    // Event triggered by Idle Timer.
+  kThermalEvent,   // Event triggered by Thermal.
+};
+
 /*! @brief This structure defines configuration for fixed properties of a display device.
 
   @sa DisplayInterface::GetConfig
@@ -245,6 +251,9 @@
   */
   virtual DisplayError CECMessage(char *message) = 0;
 
+  /*! @brief Event handler for events received by Display HAL. */
+  virtual DisplayError HandleEvent(DisplayEvent event) = 0;
+
  protected:
   virtual ~DisplayEventHandler() { }
 };
diff --git a/sdm/include/core/sdm_types.h b/sdm/include/core/sdm_types.h
index ce356bf..72ad6b2 100644
--- a/sdm/include/core/sdm_types.h
+++ b/sdm/include/core/sdm_types.h
@@ -56,6 +56,7 @@
   kErrorPerfValidation,   //!< Bandwidth or Clock requirement validation failure.
   kErrorNoAppLayers,      //!< No App layer(s) in the draw cycle.
   kErrorRotatorValidation,  //!< Rotator configuration validation failure.
+  kErrorNotValidated,     //!< Draw cycle has not been validated.
 };
 
 /*! @brief This structure is defined for client and library compatibility check purpose only. This
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index b76c3d1..538d38e 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -211,6 +211,7 @@
 DisplayError DisplayBase::Prepare(LayerStack *layer_stack) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
   DisplayError error = kErrorNone;
+  needs_validate_ = true;
 
   if (!active_) {
     return kErrorPermission;
@@ -250,7 +251,7 @@
     error = hw_intf_->Validate(&hw_layers_);
     if (error == kErrorNone) {
       // Strategy is successful now, wait for Commit().
-      pending_commit_ = true;
+      needs_validate_ = false;
       break;
     }
     if (error == kErrorShutDown) {
@@ -269,7 +270,7 @@
   DisplayError error = kErrorNone;
 
   if (!active_) {
-    pending_commit_ = false;
+    needs_validate_ = true;
     return kErrorPermission;
   }
 
@@ -277,13 +278,11 @@
     return kErrorParameters;
   }
 
-  if (!pending_commit_) {
+  if (needs_validate_) {
     DLOGE("Commit: Corresponding Prepare() is not called for display = %d", display_type_);
-    return kErrorUndefined;
+    return kErrorNotValidated;
   }
 
-  pending_commit_ = false;
-
   // Layer stack attributes has changed, need to Reconfigure, currently in use for Hybrid Comp
   if (layer_stack->flags.attributes_changed) {
     error = comp_manager_->ReConfigure(display_comp_ctx_, &hw_layers_);
@@ -343,7 +342,7 @@
   error = hw_intf_->Flush();
   if (error == kErrorNone) {
     comp_manager_->Purge(display_comp_ctx_);
-    pending_commit_ = false;
+    needs_validate_ = true;
   } else {
     DLOGW("Unable to flush display = %d", display_type_);
   }
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 4023229..223e5eb 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -153,7 +153,7 @@
   Handle hw_device_ = 0;
   Handle display_comp_ctx_ = 0;
   HWLayers hw_layers_;
-  bool pending_commit_ = false;
+  bool needs_validate_ = true;
   bool vsync_enable_ = false;
   uint32_t max_mixer_stages_ = 0;
   HWInfoInterface *hw_info_intf_ = NULL;
diff --git a/sdm/libs/core/display_primary.cpp b/sdm/libs/core/display_primary.cpp
index 52b71c7..64a0bcc 100644
--- a/sdm/libs/core/display_primary.cpp
+++ b/sdm/libs/core/display_primary.cpp
@@ -283,6 +283,7 @@
   handle_idle_timeout_ = true;
   event_handler_->Refresh();
   comp_manager_->ProcessIdleTimeout(display_comp_ctx_);
+  event_handler_->HandleEvent(kIdleTimeout);
 }
 
 void DisplayPrimary::PingPongTimeout() {
@@ -293,6 +294,7 @@
 void DisplayPrimary::ThermalEvent(int64_t thermal_level) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
   comp_manager_->ProcessThermalEvent(display_comp_ctx_, thermal_level);
+  event_handler_->HandleEvent(kThermalEvent);
 }
 
 void DisplayPrimary::IdlePowerCollapse() {
diff --git a/sdm/libs/core/drm/hw_device_drm.cpp b/sdm/libs/core/drm/hw_device_drm.cpp
index a5ed8a2..fa31a12 100644
--- a/sdm/libs/core/drm/hw_device_drm.cpp
+++ b/sdm/libs/core/drm/hw_device_drm.cpp
@@ -97,6 +97,7 @@
 using sde_drm::DRMPowerMode;
 using sde_drm::DRMSecureMode;
 using sde_drm::DRMSecurityLevel;
+using sde_drm::DRMCscType;
 
 namespace sdm {
 
@@ -328,7 +329,6 @@
                          HWInfoInterface *hw_info_intf)
     : hw_info_intf_(hw_info_intf), buffer_sync_handler_(buffer_sync_handler),
       registry_(buffer_allocator) {
-  device_type_ = kDevicePrimary;
   disp_type_ = DRMDisplayType::PERIPHERAL;
   device_name_ = "Peripheral Display";
   hw_info_intf_ = hw_info_intf;
@@ -343,31 +343,32 @@
     drm_master->GetHandle(&dev_fd_);
     DRMLibLoader::GetInstance()->FuncGetDRMManager()(dev_fd_, &drm_mgr_intf_);
     if (drm_mgr_intf_->RegisterDisplay(disp_type_, &token_)) {
-      DLOGE("RegisterDisplay failed for display %d", disp_type_);
+      DLOGE("RegisterDisplay failed for %s", device_name_);
       return kErrorResources;
     }
     drm_mgr_intf_->CreateAtomicReq(token_, &drm_atomic_intf_);
     drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
-    InitializeConfigs();
-    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &current_mode_);
-
-    drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
     // Commit to setup pipeline with mode, which then tells us the topology etc
-
     if (!deferred_initialize_) {
+      drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id,
+                                &connector_info_.modes[current_mode_index_]);
+      drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
       if (drm_atomic_intf_->Commit(true /* synchronous */)) {
         DRM_LOGI("Setting up CRTC %d, Connector %d for %s failed", token_.crtc_id,
           token_.conn_id, device_name_);
         return kErrorResources;
       }
       // Reload connector info for updated info after 1st commit
-
       drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
     }
+    InitializeConfigs();
+  } else {
+    display_attributes_.push_back(HWDisplayAttributes());
+    PopulateDisplayAttributes(current_mode_index_);
   }
-  PopulateDisplayAttributes();
   PopulateHWPanelInfo();
   UpdateMixerAttributes();
+
   hw_info_intf_->GetHWResourceInfo(&hw_resource_);
 
   // TODO(user): In future, remove has_qseed3 member, add version and pass version to constructor
@@ -382,6 +383,7 @@
   PowerOff();
   delete hw_scale_;
   registry_.Clear();
+  display_attributes_ = {};
   drm_mgr_intf_->DestroyAtomicReq(drm_atomic_intf_);
   drm_atomic_intf_ = {};
   drm_mgr_intf_->UnregisterDisplay(token_);
@@ -389,15 +391,27 @@
 }
 
 void HWDeviceDRM::InitializeConfigs() {
-  // TODO(user): Update modes
-  current_mode_ = connector_info_.modes[0];
+  // TODO(user): Choose Best Mode
+  current_mode_index_ = 0;
+  display_attributes_.resize(connector_info_.modes.size());
+
+  uint32_t width = connector_info_.modes[current_mode_index_].hdisplay;
+  uint32_t height = connector_info_.modes[current_mode_index_].vdisplay;
+  for (uint32_t i = 0; i < connector_info_.modes.size(); i++) {
+    auto &mode = connector_info_.modes[i];
+    if (mode.hdisplay != width || mode.vdisplay != height) {
+      resolution_switch_enabled_ = true;
+    }
+    PopulateDisplayAttributes(i);
+  }
 }
 
-DisplayError HWDeviceDRM::PopulateDisplayAttributes() {
+DisplayError HWDeviceDRM::PopulateDisplayAttributes(uint32_t index) {
   drmModeModeInfo mode = {};
   uint32_t mm_width = 0;
   uint32_t mm_height = 0;
   DRMTopology topology = DRMTopology::SINGLE_LM;
+  bool dual_display = false;
 
   if (default_mode_) {
     DRMResMgr *res_mgr = nullptr;
@@ -410,16 +424,17 @@
     res_mgr->GetMode(&mode);
     res_mgr->GetDisplayDimInMM(&mm_width, &mm_height);
   } else {
-    mode = current_mode_;
+    mode = connector_info_.modes[index];
     mm_width = connector_info_.mmWidth;
     mm_height = connector_info_.mmHeight;
     topology = connector_info_.topology;
   }
 
-  display_attributes_.x_pixels = mode.hdisplay;
-  display_attributes_.y_pixels = mode.vdisplay;
-  display_attributes_.fps = mode.vrefresh;
-  display_attributes_.vsync_period_ns = UINT32(1000000000L / display_attributes_.fps);
+  display_attributes_[index].x_pixels = mode.hdisplay;
+  display_attributes_[index].y_pixels = mode.vdisplay;
+  display_attributes_[index].fps = mode.vrefresh;
+  display_attributes_[index].vsync_period_ns =
+    UINT32(1000000000L / display_attributes_[index].fps);
 
   /*
               Active                 Front           Sync           Back
@@ -431,18 +446,19 @@
      <-------------------------------- [hv]total ----------------------------->
    */
 
-  display_attributes_.v_front_porch = mode.vsync_start - mode.vdisplay;
-  display_attributes_.v_pulse_width = mode.vsync_end - mode.vsync_start;
-  display_attributes_.v_back_porch = mode.vtotal - mode.vsync_end;
-  display_attributes_.v_total = mode.vtotal;
-
-  display_attributes_.h_total = mode.htotal;
+  display_attributes_[index].v_front_porch = mode.vsync_start - mode.vdisplay;
+  display_attributes_[index].v_pulse_width = mode.vsync_end - mode.vsync_start;
+  display_attributes_[index].v_back_porch = mode.vtotal - mode.vsync_end;
+  display_attributes_[index].v_total = mode.vtotal;
+  display_attributes_[index].h_total = mode.htotal;
   uint32_t h_blanking = mode.htotal - mode.hdisplay;
-  display_attributes_.is_device_split =
+  display_attributes_[index].is_device_split =
       (topology == DRMTopology::DUAL_LM || topology == DRMTopology::DUAL_LM_MERGE ||
        topology == DRMTopology::DUAL_LM_MERGE_DSC || topology == DRMTopology::DUAL_LM_DSC ||
        topology == DRMTopology::DUAL_LM_DSCMERGE);
-  display_attributes_.h_total += display_attributes_.is_device_split ? h_blanking : 0;
+  dual_display = (topology == DRMTopology::DUAL_LM || topology == DRMTopology::DUAL_LM_DSC ||
+       topology == DRMTopology::PPSPLIT);
+  display_attributes_[index].h_total += dual_display ? h_blanking : 0;
 
   // If driver doesn't return panel width/height information, default to 320 dpi
   if (INT(mm_width) <= 0 || INT(mm_height) <= 0) {
@@ -451,8 +467,17 @@
     DLOGW("Driver doesn't report panel physical width and height - defaulting to 320dpi");
   }
 
-  display_attributes_.x_dpi = (FLOAT(mode.hdisplay) * 25.4f) / FLOAT(mm_width);
-  display_attributes_.y_dpi = (FLOAT(mode.vdisplay) * 25.4f) / FLOAT(mm_height);
+  display_attributes_[index].x_dpi = (FLOAT(mode.hdisplay) * 25.4f) / FLOAT(mm_width);
+  display_attributes_[index].y_dpi = (FLOAT(mode.vdisplay) * 25.4f) / FLOAT(mm_height);
+
+  DLOGI("Display attributes[%d]: WxH: %dx%d, DPI: %fx%f, FPS: %d, LM_SPLIT: %d, V_BACK_PORCH: %d," \
+        " V_FRONT_PORCH: %d, V_PULSE_WIDTH: %d, V_TOTAL: %d, H_TOTAL: %d, TOPOLOGY: %d", index,
+        display_attributes_[index].x_pixels, display_attributes_[index].y_pixels,
+        display_attributes_[index].x_dpi, display_attributes_[index].y_dpi,
+        display_attributes_[index].fps, display_attributes_[index].is_device_split,
+        display_attributes_[index].v_back_porch, display_attributes_[index].v_front_porch,
+        display_attributes_[index].v_pulse_width, display_attributes_[index].v_total,
+        display_attributes_[index].h_total, topology);
 
   return kErrorNone;
 }
@@ -462,11 +487,8 @@
 
   snprintf(hw_panel_info_.panel_name, sizeof(hw_panel_info_.panel_name), "%s",
            connector_info_.panel_name.c_str());
-  hw_panel_info_.split_info.left_split = display_attributes_.x_pixels;
-  if (display_attributes_.is_device_split) {
-    hw_panel_info_.split_info.left_split = hw_panel_info_.split_info.right_split =
-        display_attributes_.x_pixels / 2;
-  }
+
+  UpdatePanelSplitInfo();
 
   hw_panel_info_.partial_update = connector_info_.num_roi;
   hw_panel_info_.left_roi_count = UINT32(connector_info_.num_roi);
@@ -587,18 +609,25 @@
 }
 
 DisplayError HWDeviceDRM::GetActiveConfig(uint32_t *active_config) {
-  *active_config = 0;
+  *active_config = current_mode_index_;
   return kErrorNone;
 }
 
 DisplayError HWDeviceDRM::GetNumDisplayAttributes(uint32_t *count) {
-  *count = 1;
+  *count = UINT32(display_attributes_.size());
+  if (*count <= 0) {
+    return kErrorHardware;
+  }
   return kErrorNone;
 }
 
 DisplayError HWDeviceDRM::GetDisplayAttributes(uint32_t index,
-                                            HWDisplayAttributes *display_attributes) {
-  *display_attributes = display_attributes_;
+                                               HWDisplayAttributes *display_attributes) {
+  if (index >= display_attributes_.size()) {
+    return kErrorParameters;
+  }
+
+  *display_attributes = display_attributes_[index];
   return kErrorNone;
 }
 
@@ -608,6 +637,20 @@
 }
 
 DisplayError HWDeviceDRM::SetDisplayAttributes(uint32_t index) {
+  if (index >= display_attributes_.size()) {
+    return kErrorParameters;
+  }
+
+  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &connector_info_.modes[index]);
+  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
+
+  current_mode_index_ = index;
+  UpdatePanelSplitInfo();
+  UpdateMixerAttributes();
+
+  DLOGI("Setting mode index %d for CRTC %d, Connector %d display %s is successful", index,
+         token_.crtc_id, token_.conn_id, device_name_);
+
   return kErrorNone;
 }
 
@@ -630,7 +673,7 @@
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::ON);
   int ret = drm_atomic_intf_->Commit(false /* synchronous */);
   if (ret) {
-    DLOGE("%s failed with error %d", __FUNCTION__, ret);
+    DLOGE("Failed with error: %d", ret);
     return kErrorHardware;
   }
   return kErrorNone;
@@ -646,14 +689,21 @@
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 0);
   int ret = drm_atomic_intf_->Commit(false /* synchronous */);
   if (ret) {
-    DLOGE("%s failed with error %d", __FUNCTION__, ret);
+    DLOGE("Failed with error: %d", ret);
     return kErrorHardware;
   }
   return kErrorNone;
 }
 
 DisplayError HWDeviceDRM::Doze() {
+  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
   drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_POWER_MODE, token_.conn_id, DRMPowerMode::DOZE);
+  int ret = drm_atomic_intf_->Commit(false /* synchronous */);
+  if (ret) {
+    DLOGE("Failed with error: %d", ret);
+    return kErrorHardware;
+  }
+
   return kErrorNone;
 }
 
@@ -676,6 +726,7 @@
   uint32_t hw_layer_count = UINT32(hw_layer_info.hw_layers.size());
   HWQosData &qos_data = hw_layers->qos_data;
   DRMSecurityLevel crtc_security_level = DRMSecurityLevel::SECURE_NON_SECURE;
+  uint32_t index = current_mode_index_;
 
   solid_fills_.clear();
 
@@ -683,8 +734,8 @@
   if (hw_panel_info_.partial_update) {
     const int kNumMaxROIs = 4;
     DRMRect crtc_rects[kNumMaxROIs] = {{0, 0, mixer_attributes_.width, mixer_attributes_.height}};
-    DRMRect conn_rects[kNumMaxROIs] = {{0, 0, display_attributes_.x_pixels,
-                                        display_attributes_.y_pixels}};
+    DRMRect conn_rects[kNumMaxROIs] = {{0, 0, display_attributes_[index].x_pixels,
+                                        display_attributes_[index].y_pixels}};
 
     for (uint32_t i = 0; i < hw_layer_info.left_frame_roi.size(); i++) {
       auto &roi = hw_layer_info.left_frame_roi.at(i);
@@ -781,6 +832,10 @@
                                       reinterpret_cast<uint64_t>(&scaler_output.scaler_v2));
           }
         }
+
+        DRMCscType csc_type = DRMCscType::kCscTypeMax;
+        SelectCscType(layer.input_buffer, &csc_type);
+        drm_atomic_intf_->Perform(DRMOps::PLANE_SET_CSC_CONFIG, pipe_id, &csc_type);
       }
     }
   }
@@ -942,6 +997,12 @@
 }
 
 DisplayError HWDeviceDRM::Flush() {
+  int ret = drm_atomic_intf_->Commit(false /* synchronous */);
+  if (ret) {
+    DLOGE("failed with error %d", ret);
+    return kErrorHardware;
+  }
+
   return kErrorNone;
 }
 
@@ -968,6 +1029,34 @@
   }
 }
 
+void HWDeviceDRM::SelectCscType(const LayerBuffer &input_buffer, DRMCscType *type) {
+  if (type == NULL) {
+    return;
+  }
+
+  *type = DRMCscType::kCscTypeMax;
+  if (input_buffer.format < kFormatYCbCr420Planar) {
+    return;
+  }
+
+  switch (input_buffer.color_metadata.colorPrimaries) {
+    case ColorPrimaries_BT601_6_525:
+    case ColorPrimaries_BT601_6_625:
+      *type = ((input_buffer.color_metadata.range == Range_Full) ?
+               DRMCscType::kCscYuv2Rgb601FR : DRMCscType::kCscYuv2Rgb601L);
+      break;
+    case ColorPrimaries_BT709_5:
+      *type = DRMCscType::kCscYuv2Rgb709L;
+      break;
+    case ColorPrimaries_BT2020:
+      *type = ((input_buffer.color_metadata.range == Range_Full) ?
+                DRMCscType::kCscYuv2Rgb2020FR : DRMCscType::kCscYuv2Rgb2020L);
+      break;
+    default:
+      break;
+  }
+}
+
 void HWDeviceDRM::SetRect(const LayerRect &source, DRMRect *target) {
   target->left = UINT32(source.left);
   target->top = UINT32(source.top);
@@ -985,7 +1074,7 @@
 
   // In no rotation case or inline rotation case, plane will handle flips
   // In DRM framework rotation is applied in counter-clockwise direction.
-  if (transform.rotation == 90) {
+  if (mode == kRotatorInline && transform.rotation == 90) {
     // a) rotate 90 clockwise = rotate 270 counter-clockwise in DRM
     // rotate 270 is translated as hflip + vflip + rotate90
     // b) rotate 270 clockwise = rotate 90 counter-clockwise in DRM
@@ -1165,20 +1254,26 @@
 }
 
 DisplayError HWDeviceDRM::SetMixerAttributes(const HWMixerAttributes &mixer_attributes) {
+  if (IsResolutionSwitchEnabled()) {
+    return kErrorNotSupported;
+  }
+
   if (!hw_resource_.hw_dest_scalar_info.count) {
     return kErrorNotSupported;
   }
 
-  if (mixer_attributes.width > display_attributes_.x_pixels ||
-      mixer_attributes.height > display_attributes_.y_pixels) {
+  uint32_t index = current_mode_index_;
+
+  if (mixer_attributes.width > display_attributes_[index].x_pixels ||
+      mixer_attributes.height > display_attributes_[index].y_pixels) {
     DLOGW("Input resolution exceeds display resolution! input: res %dx%d display: res %dx%d",
-          mixer_attributes.width, mixer_attributes.height, display_attributes_.x_pixels,
-          display_attributes_.y_pixels);
+          mixer_attributes.width, mixer_attributes.height, display_attributes_[index].x_pixels,
+          display_attributes_[index].y_pixels);
     return kErrorNotSupported;
   }
 
   uint32_t max_input_width = hw_resource_.hw_dest_scalar_info.max_input_width;
-  if (display_attributes_.is_device_split) {
+  if (display_attributes_[index].is_device_split) {
     max_input_width *= 2;
   }
 
@@ -1190,16 +1285,17 @@
 
   float mixer_aspect_ratio = FLOAT(mixer_attributes.width) / FLOAT(mixer_attributes.height);
   float display_aspect_ratio =
-      FLOAT(display_attributes_.x_pixels) / FLOAT(display_attributes_.y_pixels);
+      FLOAT(display_attributes_[index].x_pixels) / FLOAT(display_attributes_[index].y_pixels);
 
   if (display_aspect_ratio != mixer_aspect_ratio) {
     DLOGW("Aspect ratio mismatch! input: res %dx%d display: res %dx%d", mixer_attributes.width,
-          mixer_attributes.height, display_attributes_.x_pixels, display_attributes_.y_pixels);
+          mixer_attributes.height, display_attributes_[index].x_pixels,
+          display_attributes_[index].y_pixels);
     return kErrorNotSupported;
   }
 
-  float scale_x = FLOAT(display_attributes_.x_pixels) / FLOAT(mixer_attributes.width);
-  float scale_y = FLOAT(display_attributes_.y_pixels) / FLOAT(mixer_attributes.height);
+  float scale_x = FLOAT(display_attributes_[index].x_pixels) / FLOAT(mixer_attributes.width);
+  float scale_y = FLOAT(display_attributes_[index].y_pixels) / FLOAT(mixer_attributes.height);
   float max_scale_up = hw_resource_.hw_dest_scalar_info.max_scale_up;
   if (scale_x > max_scale_up || scale_y > max_scale_up) {
     DLOGW(
@@ -1213,7 +1309,7 @@
 
   mixer_attributes_ = mixer_attributes;
   mixer_attributes_.split_left = mixer_attributes_.width;
-  if (display_attributes_.is_device_split) {
+  if (display_attributes_[index].is_device_split) {
     mixer_attributes_.split_left = UINT32(FLOAT(mixer_attributes.width) * mixer_split_ratio);
   }
 
@@ -1225,9 +1321,10 @@
     return kErrorParameters;
   }
 
-  mixer_attributes_.width = display_attributes_.x_pixels;
-  mixer_attributes_.height = display_attributes_.y_pixels;
-  mixer_attributes_.split_left = display_attributes_.is_device_split
+  uint32_t index = current_mode_index_;
+  mixer_attributes_.width = display_attributes_[index].x_pixels;
+  mixer_attributes_.height = display_attributes_[index].y_pixels;
+  mixer_attributes_.split_left = display_attributes_[index].is_device_split
                                      ? hw_panel_info_.split_info.left_split
                                      : mixer_attributes_.width;
   *mixer_attributes = mixer_attributes_;
@@ -1241,9 +1338,11 @@
 }
 
 void HWDeviceDRM::UpdateMixerAttributes() {
-  mixer_attributes_.width = display_attributes_.x_pixels;
-  mixer_attributes_.height = display_attributes_.y_pixels;
-  mixer_attributes_.split_left = display_attributes_.is_device_split
+  uint32_t index = current_mode_index_;
+
+  mixer_attributes_.width = display_attributes_[index].x_pixels;
+  mixer_attributes_.height = display_attributes_[index].y_pixels;
+  mixer_attributes_.split_left = display_attributes_[index].is_device_split
                                      ? hw_panel_info_.split_info.left_split
                                      : mixer_attributes_.width;
 }
@@ -1274,4 +1373,13 @@
   }
 }
 
+void HWDeviceDRM::UpdatePanelSplitInfo() {
+  uint32_t index = current_mode_index_;
+  hw_panel_info_.split_info.left_split = display_attributes_[index].x_pixels;
+  if (display_attributes_[index].is_device_split) {
+    hw_panel_info_.split_info.left_split = hw_panel_info_.split_info.right_split =
+        display_attributes_[index].x_pixels / 2;
+  }
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index 391e699..883d605 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -112,7 +112,7 @@
   DisplayError SetFormat(const LayerBufferFormat &source, uint32_t *target);
   DisplayError SetStride(HWDeviceType device_type, LayerBufferFormat format, uint32_t width,
                          uint32_t *target);
-  DisplayError PopulateDisplayAttributes();
+  DisplayError PopulateDisplayAttributes(uint32_t index);
   void PopulateHWPanelInfo();
   void GetHWDisplayPortAndMode();
   void GetHWPanelMaxBrightness();
@@ -123,6 +123,7 @@
   void AddSolidfillStage(const HWSolidfillStage &sf, uint32_t plane_alpha);
   void SetBlending(const LayerBlending &source, sde_drm::DRMBlendType *target);
   void SetSrcConfig(const LayerBuffer &input_buffer, uint32_t *config);
+  void SelectCscType(const LayerBuffer &input_buffer, sde_drm::DRMCscType *type);
   void SetRect(const LayerRect &source, sde_drm::DRMRect *target);
   void SetRotation(LayerTransform transform, const HWRotatorMode &mode, uint32_t* rot_bit_mask);
   DisplayError DefaultCommit(HWLayers *hw_layers);
@@ -130,6 +131,8 @@
   void SetupAtomic(HWLayers *hw_layers, bool validate);
   void SetSecureConfig(const LayerBuffer &input_buffer, sde_drm::DRMSecureMode *fb_secure_mode,
                        sde_drm::DRMSecurityLevel *security_level);
+  bool IsResolutionSwitchEnabled() const { return resolution_switch_enabled_; }
+  void UpdatePanelSplitInfo();
 
   class Registry {
    public:
@@ -167,19 +170,19 @@
   sde_drm::DRMDisplayToken token_ = {};
   HWResourceInfo hw_resource_ = {};
   HWPanelInfo hw_panel_info_ = {};
-  HWDeviceType device_type_ = {};
   HWScaleDRM *hw_scale_ = {};
   sde_drm::DRMManagerInterface *drm_mgr_intf_ = {};
   sde_drm::DRMAtomicReqInterface *drm_atomic_intf_ = {};
+  std::vector<HWDisplayAttributes> display_attributes_ = {};
+  uint32_t current_mode_index_ = 0;
   sde_drm::DRMConnectorInfo connector_info_ = {};
-  drmModeModeInfo current_mode_ = {};
-  HWDisplayAttributes display_attributes_ = {};
 
  private:
   bool synchronous_commit_ = false;
   HWMixerAttributes mixer_attributes_ = {};
   std::string interface_str_ = "DSI";
   std::vector<sde_drm::DRMSolidfillStage> solid_fills_ {};
+  bool resolution_switch_enabled_ = false;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_tv_drm.cpp b/sdm/libs/core/drm/hw_tv_drm.cpp
index 67485f1..2659a32 100644
--- a/sdm/libs/core/drm/hw_tv_drm.cpp
+++ b/sdm/libs/core/drm/hw_tv_drm.cpp
@@ -61,7 +61,7 @@
 
 HWTVDRM::HWTVDRM(BufferSyncHandler *buffer_sync_handler, BufferAllocator *buffer_allocator,
                      HWInfoInterface *hw_info_intf)
-  : HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf), active_config_index_(0) {
+  : HWDeviceDRM(buffer_sync_handler, buffer_allocator, hw_info_intf) {
   disp_type_ = DRMDisplayType::TV;
   device_name_ = "TV Display Device";
 }
@@ -96,35 +96,13 @@
     hw_scale_ = new HWScaleDRM(HWScaleDRM::Version::V2);
   }
 
-  if (error != kErrorNone) {
-    return error;
-  }
-
   return error;
 }
-
-DisplayError HWTVDRM::GetNumDisplayAttributes(uint32_t *count) {
-  *count = UINT32(connector_info_.modes.size());
-  if (*count <= 0) {
-    return kErrorHardware;
-  }
-
-  return kErrorNone;
-}
-
-DisplayError HWTVDRM::GetActiveConfig(uint32_t *active_config_index) {
-  *active_config_index = active_config_index_;
-  return kErrorNone;
-}
-
 DisplayError HWTVDRM::SetDisplayAttributes(uint32_t index) {
   if (index >= connector_info_.modes.size()) {
     return kErrorNotSupported;
   }
 
-  active_config_index_ = index;
-  current_mode_ = connector_info_.modes[index];
-
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &connector_info_.modes[index]);
   drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
 
@@ -139,8 +117,8 @@
   drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
   DLOGI("Setup CRTC %d, Connector %d for %s", token_.crtc_id, token_.conn_id, device_name_);
 
-  frame_rate_ = display_attributes_.fps;
-  PopulateDisplayAttributes();
+  current_mode_index_ = index;
+  PopulateDisplayAttributes(index);
   PopulateHWPanelInfo();
   UpdateMixerAttributes();
 
diff --git a/sdm/libs/core/drm/hw_tv_drm.h b/sdm/libs/core/drm/hw_tv_drm.h
index 7991ae3..fa8012a 100644
--- a/sdm/libs/core/drm/hw_tv_drm.h
+++ b/sdm/libs/core/drm/hw_tv_drm.h
@@ -41,18 +41,12 @@
 
  protected:
   virtual DisplayError Init();
-  virtual DisplayError GetNumDisplayAttributes(uint32_t *count);
-  // Requirement to call this only after the first config has been explicitly set by client
-  virtual DisplayError GetActiveConfig(uint32_t *active_config);
   virtual DisplayError SetDisplayAttributes(uint32_t index);
   virtual DisplayError GetConfigIndex(char *mode, uint32_t *index);
 
  private:
   static const int kBitRGB  = 20;
   static const int kBitYUV  = 21;
-
-  uint32_t active_config_index_;
-  uint32_t frame_rate_ = 0;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/drm/hw_virtual_drm.cpp b/sdm/libs/core/drm/hw_virtual_drm.cpp
index 5ea76b0..55f38ac 100644
--- a/sdm/libs/core/drm/hw_virtual_drm.cpp
+++ b/sdm/libs/core/drm/hw_virtual_drm.cpp
@@ -55,6 +55,7 @@
 }
 
 DisplayError HWVirtualDRM::Init() {
+  display_attributes_.push_back(HWDisplayAttributes());
   return kErrorNone;
 }
 
@@ -85,20 +86,19 @@
 }
 
 void HWVirtualDRM::InitializeConfigs() {
-  current_mode_.hdisplay = current_mode_.hsync_start = current_mode_.hsync_end \
-  = current_mode_.htotal = (uint16_t) width_;
-  current_mode_.vdisplay = current_mode_.vsync_start = current_mode_.vsync_end \
-  = current_mode_.vtotal = (uint16_t) height_;
+  drmModeModeInfo mode = {};
+  mode.hdisplay = mode.hsync_start = mode.hsync_end = mode.htotal = (uint16_t) width_;
+  mode.vdisplay = mode.vsync_start = mode.vsync_end = mode.vtotal = (uint16_t) height_;
   // Not sure SF has a way to configure refresh rate. Hardcoding to 60 fps for now.
   // TODO(user): Make this configurable.
-  current_mode_.vrefresh = 60;
-  current_mode_.clock = (current_mode_.htotal * current_mode_.vtotal \
-  * current_mode_.vrefresh) / 1000;
+  mode.vrefresh = 60;
+  mode.clock = (mode.htotal * mode.vtotal * mode.vrefresh) / 1000;
+
   struct sde_drm_wb_cfg wb_cfg;
   wb_cfg.connector_id = token_.conn_id;
   wb_cfg.flags |= SDE_DRM_WB_CFG_FLAGS_CONNECTED;
   wb_cfg.count_modes = 1;
-  wb_cfg.modes = (uint64_t)&current_mode_;
+  wb_cfg.modes = (uint64_t)&mode;
   #ifdef DRM_IOCTL_SDE_WB_CONFIG
   int ret = drmIoctl(dev_fd_, DRM_IOCTL_SDE_WB_CONFIG, &wb_cfg);
   #endif
@@ -106,7 +106,6 @@
     DLOGE("WB config failed\n");
   } else {
     drm_mgr_intf_->GetConnectorInfo(token_.conn_id, &connector_info_);
-    current_mode_ = connector_info_.modes[0];
     DumpConfigs();
   }
 
@@ -118,6 +117,7 @@
       connector_info_.topology = sde_drm::DRMTopology::DUAL_LM_MERGE;
     }
   }
+  PopulateDisplayAttributes(current_mode_index_);
 }
 
 void HWVirtualDRM::DumpConfigs() {
@@ -160,15 +160,24 @@
     return kErrorParameters;
   }
 
-  display_attributes_ = display_attributes;
+  uint32_t index = current_mode_index_;
+  width_ = display_attributes.x_pixels;
+  height_ = display_attributes.y_pixels;
 
-  if (display_attributes_.x_pixels > hw_resource_.max_mixer_width) {
-    display_attributes_.is_device_split = true;
+  DisplayError error = DeferredInit();
+  if (error != kErrorNone) {
+    width_ = display_attributes_[index].x_pixels;
+    height_ = display_attributes_[index].y_pixels;
+    return error;
   }
+  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_MODE, token_.crtc_id, &connector_info_.modes[index]);
+  drm_atomic_intf_->Perform(DRMOps::CRTC_SET_ACTIVE, token_.crtc_id, 1);
 
-  width_ = display_attributes_.x_pixels;
-  height_ = display_attributes_.y_pixels;
-  DeferredInit();
+  display_attributes_[index] = display_attributes;
+  if (display_attributes_[index].x_pixels > hw_resource_.max_mixer_width) {
+    display_attributes_[index].is_device_split = true;
+  }
+  UpdateMixerAttributes();
 
   return kErrorNone;
 }
diff --git a/sdm/libs/core/fb/hw_device.cpp b/sdm/libs/core/fb/hw_device.cpp
index fa79f75..eb0d17b 100644
--- a/sdm/libs/core/fb/hw_device.cpp
+++ b/sdm/libs/core/fb/hw_device.cpp
@@ -1367,7 +1367,7 @@
   const char* xlog_path = "/data/vendor/display/mdp_xlog";
   DLOGD("Dumping debugfs data to %s", xlog_path);
   std::ostringstream  dst;
-  auto file = open(xlog_path, O_CREAT | O_DSYNC | O_RDWR, "w+");
+  auto file = open(xlog_path, O_CREAT | O_TRUNC | O_DSYNC | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
   if (file < 0) {
     DLOGE("Couldn't open file: err:%d (%s)", errno, strerror(errno));
     return kErrorResources;
diff --git a/sdm/libs/hwc2/hwc_callbacks.cpp b/sdm/libs/hwc2/hwc_callbacks.cpp
index 3be3bf6..48593f1 100644
--- a/sdm/libs/hwc2/hwc_callbacks.cpp
+++ b/sdm/libs/hwc2/hwc_callbacks.cpp
@@ -54,6 +54,7 @@
   if (!vsync_) {
     return HWC2::Error::NoResources;
   }
+  DTRACE_SCOPED();
   vsync_(vsync_data_, display, timestamp);
   return HWC2::Error::None;
 }
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index cf4d1a2..6106baf 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -53,6 +53,8 @@
 
 namespace sdm {
 
+std::bitset<kDisplayMax> HWCDisplay::validated_ = 0;
+
 // This weight function is needed because the color primaries are not sorted by gamut size
 static ColorPrimaries WidestPrimaries(ColorPrimaries p1, ColorPrimaries p2) {
   int weight = 10;
@@ -102,11 +104,16 @@
 }
 
 HWC2::Error HWCColorMode::SetColorMode(android_color_mode_t mode) {
+  DTRACE_SCOPED();
   // first mode in 2D matrix is the mode (identity)
-  if (color_mode_transform_map_.find(mode) == color_mode_transform_map_.end()) {
+  if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_DISPLAY_P3) {
     DLOGE("Could not find mode: %d", mode);
     return HWC2::Error::BadParameter;
   }
+  if (color_mode_transform_map_.find(mode) == color_mode_transform_map_.end()) {
+    return HWC2::Error::Unsupported;
+  }
+
   auto status = HandleColorModeTransform(mode, current_color_transform_, color_matrix_);
   if (status != HWC2::Error::None) {
     DLOGE("failed for mode = %d", mode);
@@ -125,10 +132,12 @@
 }
 
 HWC2::Error HWCColorMode::SetColorTransform(const float *matrix, android_color_transform_t hint) {
-  if (!matrix) {
+  if (!matrix || (hint < HAL_COLOR_TRANSFORM_IDENTITY ||
+      hint > HAL_COLOR_TRANSFORM_CORRECT_TRITANOPIA)) {
     return HWC2::Error::BadParameter;
   }
 
+  DTRACE_SCOPED();
   double color_matrix[kColorTransformMatrixCount] = {0};
   CopyColorTransformMatrix(matrix, color_matrix);
 
@@ -347,6 +356,7 @@
     return -EINVAL;
   }
 
+  validated_.reset();
   HWCDebugHandler::Get()->GetProperty("sys.hwc_disable_hdr", &disable_hdr_handling_);
   if (disable_hdr_handling_) {
     DLOGI("HDR Handling disabled");
@@ -376,6 +386,8 @@
 
   display_intf_->GetRefreshRateRange(&min_refresh_rate_, &max_refresh_rate_);
   current_refresh_rate_ = max_refresh_rate_;
+
+  GetUnderScanConfig();
   DLOGI("Display created with id: %d", id_);
 
   return 0;
@@ -406,8 +418,8 @@
   HWCLayer *layer = *layer_set_.emplace(new HWCLayer(id_, buffer_allocator_));
   layer_map_.emplace(std::make_pair(layer->GetId(), layer));
   *out_layer_id = layer->GetId();
-  validated_ = false;
   geometry_changes_ |= GeometryChanges::kAdded;
+  validated_.reset();
   return HWC2::Error::None;
 }
 
@@ -437,9 +449,9 @@
       break;
     }
   }
-  validated_ = false;
 
   geometry_changes_ |= GeometryChanges::kRemoved;
+  validated_.reset();
   return HWC2::Error::None;
 }
 
@@ -596,7 +608,6 @@
     DLOGE("[%" PRIu64 "] updateLayerZ failed to find layer", id_);
     return HWC2::Error::BadLayer;
   }
-  validated_ = false;
 
   const auto layer = map_layer->second;
   const auto z_range = layer_set_.equal_range(layer);
@@ -625,6 +636,7 @@
 
 HWC2::Error HWCDisplay::SetVsyncEnabled(HWC2::Vsync enabled) {
   DLOGV("Display ID: %d enabled: %s", id_, to_string(enabled).c_str());
+  ATRACE_INT("SetVsyncState ", enabled == HWC2::Vsync::Enable ? 1 : 0);
   DisplayError error = kErrorNone;
 
   if (shutdown_pending_ || !callbacks_->VsyncCallbackRegistered()) {
@@ -688,7 +700,10 @@
       return HWC2::Error::BadParameter;
   }
 
+  ATRACE_INT("SetPowerMode ", state);
   DisplayError error = display_intf_->SetDisplayState(state);
+  validated_.reset();
+
   if (error == kErrorNone) {
     flush_on_error_ = flush_on_error;
   } else {
@@ -743,9 +758,18 @@
 HWC2::Error HWCDisplay::GetDisplayAttribute(hwc2_config_t config, HWC2::Attribute attribute,
                                             int32_t *out_value) {
   DisplayConfigVariableInfo variable_config;
-  if (GetDisplayAttributesForConfig(INT(config), &variable_config) != kErrorNone) {
-    DLOGE("Get variable config failed");
-    return HWC2::Error::BadDisplay;
+  // Get display attributes from config index only if resolution switch is supported.
+  // Otherwise always send mixer attributes. This is to support destination scaler.
+  if (num_configs_ > 1) {
+    if (GetDisplayAttributesForConfig(INT(config), &variable_config) != kErrorNone) {
+      DLOGE("Get variable config failed");
+      return HWC2::Error::BadDisplay;
+    }
+  } else {
+    if (display_intf_->GetFrameBufferConfig(&variable_config) != kErrorNone) {
+      DLOGV("Get variable config failed");
+      return HWC2::Error::BadDisplay;
+    }
   }
 
   switch (attribute) {
@@ -853,6 +877,7 @@
     return HWC2::Error::BadConfig;
   }
 
+  validated_.reset();
   return HWC2::Error::None;
 }
 
@@ -870,6 +895,7 @@
   }
 
   DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
+  validated_.reset();
 }
 
 HWC2::PowerMode HWCDisplay::GetLastPowerMode() {
@@ -895,6 +921,20 @@
   return kErrorNone;
 }
 
+DisplayError HWCDisplay::HandleEvent(DisplayEvent event) {
+  switch (event) {
+    case kIdleTimeout:
+    case kThermalEvent:
+      validated_.reset();
+      break;
+    default:
+      DLOGW("Unknown event: %d", event);
+      break;
+  }
+
+  return kErrorNone;
+}
+
 HWC2::Error HWCDisplay::PrepareLayerStack(uint32_t *out_num_types, uint32_t *out_num_requests) {
   layer_changes_.clear();
   layer_requests_.clear();
@@ -914,6 +954,8 @@
         flush_ = true;
       }
       return HWC2::Error::BadDisplay;
+    } else {
+      validated_.set(type_);
     }
   } else {
     // Skip is not set
@@ -942,10 +984,11 @@
     if (requested_composition != device_composition) {
       layer_changes_[hwc_layer->GetId()] = device_composition;
     }
+    hwc_layer->ResetValidation();
   }
   *out_num_types = UINT32(layer_changes_.size());
   *out_num_requests = UINT32(layer_requests_.size());
-  validated_ = true;
+  skip_validate_ = false;
   if (*out_num_types > 0) {
     return HWC2::Error::HasChanges;
   } else {
@@ -958,7 +1001,7 @@
     return HWC2::Error::None;
   }
 
-  if (!validated_) {
+  if (!validated_.test(type_)) {
     return HWC2::Error::NotValidated;
   }
 
@@ -980,10 +1023,11 @@
     return HWC2::Error::None;
   }
 
-  if (!validated_) {
+  if (!validated_.test(type_)) {
     DLOGW("Display is not validated");
     return HWC2::Error::NotValidated;
   }
+
   *out_num_elements = UINT32(layer_changes_.size());
   if (out_layers != nullptr && out_types != nullptr) {
     int i = 0;
@@ -1013,18 +1057,19 @@
 HWC2::Error HWCDisplay::GetDisplayRequests(int32_t *out_display_requests,
                                            uint32_t *out_num_elements, hwc2_layer_t *out_layers,
                                            int32_t *out_layer_requests) {
-  // No display requests for now
-  // Use for sharing blit buffers and
-  // writing wfd buffer directly to output if there is full GPU composition
-  // and no color conversion needed
   if (layer_set_.empty()) {
     return HWC2::Error::None;
   }
 
-  if (!validated_) {
+  // No display requests for now
+  // Use for sharing blit buffers and
+  // writing wfd buffer directly to output if there is full GPU composition
+  // and no color conversion needed
+  if (!validated_.test(type_)) {
     DLOGW("Display is not validated");
     return HWC2::Error::NotValidated;
   }
+
   *out_display_requests = 0;
   *out_num_elements = UINT32(layer_requests_.size());
   if (out_layers != nullptr && out_layer_requests != nullptr) {
@@ -1079,8 +1124,12 @@
     return HWC2::Error::None;
   }
 
-  if (!validated_) {
-    DLOGW("Display is not validated");
+  if (skip_validate_ && !CanSkipValidate()) {
+    validated_.reset(type_);
+  }
+
+  if (!validated_.test(type_)) {
+    DLOGV_IF(kTagCompManager, "Display %d is not validated", id_);
     return HWC2::Error::NotValidated;
   }
 
@@ -1100,7 +1149,6 @@
       }
     }
     error = display_intf_->Commit(&layer_stack_);
-    validated_ = false;
 
     if (error == kErrorNone) {
       // A commit is successfully submitted, start flushing on failure now onwards.
@@ -1109,6 +1157,9 @@
       if (error == kErrorShutDown) {
         shutdown_pending_ = true;
         return HWC2::Error::Unsupported;
+      } else if (error == kErrorNotValidated) {
+        validated_.reset(type_);
+        return HWC2::Error::NotValidated;
       } else if (error != kErrorPermission) {
         DLOGE("Commit failed. Error = %d", error);
         // To prevent surfaceflinger infinite wait, flush the previous frame during Commit()
@@ -1118,6 +1169,7 @@
     }
   }
 
+  skip_validate_ = true;
   return HWC2::Error::None;
 }
 
@@ -1127,6 +1179,7 @@
   // Do no call flush on errors, if a successful buffer is never submitted.
   if (flush_ && flush_on_error_) {
     display_intf_->Flush();
+    validated_.reset();
   }
 
   if (tone_mapper_ && tone_mapper_->IsActive()) {
@@ -1174,6 +1227,7 @@
       layer_stack_.retire_fence_fd = -1;
     }
     *out_retire_fence = layer_stack_.retire_fence_fd;
+    layer_stack_.retire_fence_fd = -1;
 
     if (dump_frame_count_) {
       dump_frame_count_--;
@@ -1198,6 +1252,7 @@
 
   if (display_intf_) {
     error = display_intf_->SetMaxMixerStages(max_mixer_stages);
+    validated_.reset();
   }
 
   return error;
@@ -1560,6 +1615,7 @@
 
   if (display_status == kDisplayStatusResume || display_status == kDisplayStatusPause) {
     callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+    validated_.reset();
   }
 
   return status;
@@ -1570,9 +1626,18 @@
     return HWC2::Error::None;
   }
 
-  if (GetHWCLayer(layer) == nullptr) {
+  HWCLayer *hwc_layer = GetHWCLayer(layer);
+  if (hwc_layer == nullptr) {
     return HWC2::Error::BadLayer;
   }
+  if (hwc_layer->GetDeviceSelectedCompositionType() != HWC2::Composition::Cursor) {
+    return HWC2::Error::None;
+  }
+  if (!skip_validate_ && validated_.test(type_)) {
+    // the device is currently in the middle of the validate/present sequence,
+    // cannot set the Position(as per HWC2 spec)
+    return HWC2::Error::NotValidated;
+  }
 
   DisplayState state;
   if (display_intf_->GetDisplayState(&state) == kErrorNone) {
@@ -1581,9 +1646,9 @@
     }
   }
 
-  if (!validated_) {
-    return HWC2::Error::NotValidated;
-  }
+  // TODO(user): HWC1.5 was not letting SetCursorPosition before validateDisplay,
+  // but HWC2.0 doesn't let setting cursor position after validate before present.
+  // Need to revisit.
 
   auto error = display_intf_->SetCursorPosition(x, y);
   if (error != kErrorNone) {
@@ -1606,6 +1671,7 @@
     return -1;
   }
 
+  validated_.reset();
   return 0;
 }
 
@@ -1614,7 +1680,7 @@
     auto layer = hwc_layer->GetSDMLayer();
     layer->composition = kCompositionSDE;
   }
-  validated_ = true;
+  validated_.set(type_);
 }
 
 void HWCDisplay::MarkLayersForClientComposition() {
@@ -1632,10 +1698,12 @@
 
 int HWCDisplay::SetPanelBrightness(int level) {
   int ret = 0;
-  if (display_intf_)
+  if (display_intf_) {
     ret = display_intf_->SetPanelBrightness(level);
-  else
+    validated_.reset();
+  } else {
     ret = -EINVAL;
+  }
 
   return ret;
 }
@@ -1647,6 +1715,7 @@
 int HWCDisplay::ToggleScreenUpdates(bool enable) {
   display_paused_ = enable ? false : true;
   callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+  validated_.reset();
   return 0;
 }
 
@@ -1744,7 +1813,9 @@
 }
 
 int HWCDisplay::SetActiveDisplayConfig(uint32_t config) {
-  return display_intf_->SetActiveConfig(config) == kErrorNone ? 0 : -1;
+  int status = (display_intf_->SetActiveConfig(config) == kErrorNone) ? 0 : -1;
+  validated_.reset();
+  return status;
 }
 
 int HWCDisplay::GetActiveDisplayConfig(uint32_t *config) {
@@ -1862,4 +1933,25 @@
   os << "-------------------------------" << std::endl;
   return os.str();
 }
+
+bool HWCDisplay::CanSkipValidate() {
+  // Layer Stack checks
+  if (layer_stack_.flags.hdr_present && (tone_mapper_ && tone_mapper_->IsActive())) {
+    return false;
+  }
+
+  for (auto hwc_layer : layer_set_) {
+    if (hwc_layer->NeedsValidation()) {
+      return false;
+    }
+
+    // Do not allow Skip Validate, if any layer needs GPU Composition.
+    if (hwc_layer->GetDeviceSelectedCompositionType() == HWC2::Composition::Client) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index e773e91..273b760 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -146,19 +146,6 @@
   virtual int GetDisplayConfigCount(uint32_t *count);
   virtual int GetDisplayAttributesForConfig(int config,
                                             DisplayConfigVariableInfo *display_attributes);
-  template <typename... Args>
-  int32_t CallLayerFunction(hwc2_layer_t layer, HWC2::Error (HWCLayer::*member)(Args... ),
-                            Args... args) {
-    auto status = HWC2::Error::BadLayer;
-    validated_ = false;
-    auto hwc_layer = GetHWCLayer(layer);
-    if (hwc_layer != nullptr) {
-      status = (hwc_layer->*member)(std::forward<Args>(args)...);
-    }
-
-    return INT32(status);
-  }
-
   virtual int SetState(bool connected) {
     return kErrorNotSupported;
   }
@@ -174,6 +161,8 @@
   void BuildLayerStack(void);
   void BuildSolidFillStack(void);
   HWCLayer *GetHWCLayer(hwc2_layer_t layer);
+  void ResetValidation() { validated_.reset(); }
+  uint32_t GetGeometryChanges() { return geometry_changes_; }
 
   // HWC2 APIs
   virtual HWC2::Error AcceptDisplayChanges(void);
@@ -234,6 +223,7 @@
   virtual DisplayError VSync(const DisplayEventVSync &vsync);
   virtual DisplayError Refresh();
   virtual DisplayError CECMessage(char *message);
+  virtual DisplayError HandleEvent(DisplayEvent event);
   virtual void DumpOutputBuffer(const BufferInfo &buffer_info, void *base, int fence);
   virtual HWC2::Error PrepareLayerStack(uint32_t *out_num_types, uint32_t *out_num_requests);
   virtual HWC2::Error CommitLayerStack(void);
@@ -252,12 +242,14 @@
   uint32_t SanitizeRefreshRate(uint32_t req_refresh_rate);
   virtual void CloseAcquireFds();
   virtual void ClearRequestFlags();
+  virtual void GetUnderScanConfig() { }
 
   enum {
     INPUT_LAYER_DUMP,
     OUTPUT_LAYER_DUMP,
   };
 
+  static std::bitset<kDisplayMax> validated_;
   CoreInterface *core_intf_ = nullptr;
   HWCCallbacks *callbacks_  = nullptr;
   HWCBufferAllocator *buffer_allocator_ = NULL;
@@ -295,7 +287,6 @@
   LayerRect solid_fill_rect_ = {};
   uint32_t solid_fill_color_ = 0;
   LayerRect display_rect_;
-  bool validated_ = false;
   bool color_tranform_failed_ = false;
   HWCColorMode *color_mode_ = NULL;
   HWCToneMapper *tone_mapper_ = nullptr;
@@ -304,9 +295,11 @@
 
  private:
   void DumpInputBuffers(void);
+  bool CanSkipValidate();
   qService::QService *qservice_ = NULL;
   DisplayClass display_class_;
   uint32_t geometry_changes_ = GeometryChanges::kNone;
+  bool skip_validate_ = false;
 };
 
 inline int HWCDisplay::Perform(uint32_t operation, ...) {
diff --git a/sdm/libs/hwc2/hwc_display_external.cpp b/sdm/libs/hwc2/hwc_display_external.cpp
index e89451d..97507ee 100644
--- a/sdm/libs/hwc2/hwc_display_external.cpp
+++ b/sdm/libs/hwc2/hwc_display_external.cpp
@@ -142,20 +142,12 @@
 }
 
 void HWCDisplayExternal::ApplyScanAdjustment(hwc_rect_t *display_frame) {
-  if (display_intf_->IsUnderscanSupported()) {
+  if ((underscan_width_ <= 0) || (underscan_height_ <= 0)) {
     return;
   }
 
-  // Read user defined width and height ratio
-  int width = 0, height = 0;
-  HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_width", &width);
-  float width_ratio = FLOAT(width) / 100.0f;
-  HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_height", &height);
-  float height_ratio = FLOAT(height) / 100.0f;
-
-  if (width_ratio == 0.0f || height_ratio == 0.0f) {
-    return;
-  }
+  float width_ratio = FLOAT(underscan_width_) / 100.0f;
+  float height_ratio = FLOAT(underscan_height_) / 100.0f;
 
   uint32_t mixer_width = 0;
   uint32_t mixer_height = 0;
@@ -188,6 +180,7 @@
 
     if (secure_display_active_) {
       DisplayError error = display_intf_->Flush();
+      validated_.reset();
       if (error != kErrorNone) {
         DLOGE("Flush failed. Error = %d", error);
       }
@@ -241,6 +234,7 @@
 
       display_null_.GetDisplayState(&state);
       display_intf_->SetDisplayState(state);
+      validated_.reset();
 
       SetVsyncEnabled(HWC2::Vsync::Enable);
 
@@ -277,4 +271,12 @@
   return 0;
 }
 
+void HWCDisplayExternal::GetUnderScanConfig() {
+  if (!display_intf_->IsUnderscanSupported()) {
+    // Read user defined underscan width and height
+    HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_width", &underscan_width_);
+    HWCDebugHandler::Get()->GetProperty("sdm.external_action_safe_height", &underscan_height_);
+  }
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_external.h b/sdm/libs/hwc2/hwc_display_external.h
index 7aa84b2..fbee6a3 100644
--- a/sdm/libs/hwc2/hwc_display_external.h
+++ b/sdm/libs/hwc2/hwc_display_external.h
@@ -54,10 +54,13 @@
   HWCDisplayExternal(CoreInterface *core_intf, HWCBufferAllocator *buffer_allocator,
                      HWCCallbacks *callbacks, qService::QService *qservice);
   void ApplyScanAdjustment(hwc_rect_t *display_frame);
+  void GetUnderScanConfig();
   static void GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height,
                                      uint32_t *virtual_width, uint32_t *virtual_height);
 
   DisplayNull display_null_;
+  int underscan_width_ = 0;
+  int underscan_height_ = 0;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index 1094100..4079cbc 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -217,6 +217,7 @@
     // If we do not handle the frame set retireFenceFd to outbufAcquireFenceFd
     // Revisit this when validating display_paused
     DisplayError error = display_intf_->Flush();
+    validated_.reset();
     if (error != kErrorNone) {
       DLOGE("Flush failed. Error = %d", error);
     }
@@ -252,6 +253,7 @@
   }
 
   callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+  validated_.reset();
 
   return status;
 }
@@ -264,6 +266,7 @@
   }
 
   callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
+  validated_.reset();
 
   return status;
 }
@@ -283,6 +286,7 @@
 
   callbacks_->Refresh(HWC_DISPLAY_PRIMARY);
   color_tranform_failed_ = false;
+  validated_.reset();
 
   return status;
 }
@@ -324,6 +328,7 @@
       return -EINVAL;
   }
   va_end(args);
+  validated_.reset();
 
   return 0;
 }
@@ -410,6 +415,7 @@
 
 void HWCDisplayPrimary::SetIdleTimeoutMs(uint32_t timeout_ms) {
   display_intf_->SetIdleTimeoutMs(timeout_ms);
+  validated_.reset();
 }
 
 static void SetLayerBuffer(const BufferInfo &output_buffer_info, LayerBuffer *output_buffer) {
@@ -509,6 +515,7 @@
   output_buffer_base_ = buffer;
   post_processed_output_ = true;
   DisablePartialUpdateOneFrame();
+  validated_.reset();
 }
 
 int HWCDisplayPrimary::FrameCaptureAsync(const BufferInfo &output_buffer_info,
@@ -553,6 +560,7 @@
 
   if (display_intf_) {
     error = display_intf_->SetDetailEnhancerData(de_data);
+    validated_.reset();
   }
   return error;
 }
@@ -562,6 +570,7 @@
 
   if (display_intf_) {
     error = display_intf_->ControlPartialUpdate(enable, pending);
+    validated_.reset();
   }
 
   return error;
@@ -572,6 +581,7 @@
 
   if (display_intf_) {
     error = display_intf_->DisablePartialUpdateOneFrame();
+    validated_.reset();
   }
 
   return error;
@@ -579,7 +589,9 @@
 
 
 DisplayError HWCDisplayPrimary::SetMixerResolution(uint32_t width, uint32_t height) {
-  return display_intf_->SetMixerResolution(width, height);
+  DisplayError error = display_intf_->SetMixerResolution(width, height);
+  validated_.reset();
+  return error;
 }
 
 DisplayError HWCDisplayPrimary::GetMixerResolution(uint32_t *width, uint32_t *height) {
diff --git a/sdm/libs/hwc2/hwc_display_virtual.cpp b/sdm/libs/hwc2/hwc_display_virtual.cpp
index 8ac9be6..8837ad0 100644
--- a/sdm/libs/hwc2/hwc_display_virtual.cpp
+++ b/sdm/libs/hwc2/hwc_display_virtual.cpp
@@ -131,6 +131,7 @@
   auto status = HWC2::Error::None;
   if (display_paused_) {
     DisplayError error = display_intf_->Flush();
+    validated_.reset();
     if (error != kErrorNone) {
       DLOGE("Flush failed. Error = %d", error);
     }
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index a45fb1f..a717305 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -84,7 +84,6 @@
     close(release_fences_.front());
     release_fences_.pop();
   }
-  close(ion_fd_);
   if (layer_) {
     delete layer_;
   }
@@ -108,13 +107,8 @@
 
   const private_handle_t *handle = static_cast<const private_handle_t *>(buffer);
 
-  // Validate and dup ion fd from surfaceflinger
-  // This works around bug 30281222
   if (handle->fd < 0) {
     return HWC2::Error::BadParameter;
-  } else {
-    close(ion_fd_);
-    ion_fd_ = dup(handle->fd);
   }
 
   LayerBuffer *layer_buffer = &layer_->input_buffer;
@@ -125,36 +119,40 @@
   AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(handle, aligned_width, aligned_height);
 #endif
 
+  LayerBufferFormat format = GetSDMFormat(handle->format, handle->flags);
+  if ((format != layer_buffer->format) || (UINT32(aligned_width) != layer_buffer->width) ||
+      (UINT32(aligned_height) != layer_buffer->height)) {
+    // Layer buffer geometry has changed.
+    geometry_changes_ |= kBufferGeometry;
+  }
+
+  layer_buffer->format = format;
   layer_buffer->width = UINT32(aligned_width);
   layer_buffer->height = UINT32(aligned_height);
   layer_buffer->unaligned_width = UINT32(handle->unaligned_width);
   layer_buffer->unaligned_height = UINT32(handle->unaligned_height);
 
-  layer_buffer->format = GetSDMFormat(handle->format, handle->flags);
   if (SetMetaData(const_cast<private_handle_t *>(handle), layer_) != kErrorNone) {
     return HWC2::Error::BadLayer;
   }
 
-#ifdef USE_GRALLOC1
-  // TODO(user): Clean this up
-  if (handle->buffer_type == BUFFER_TYPE_VIDEO) {
-#else
-    if (handle->bufferType == BUFFER_TYPE_VIDEO) {
-#endif
-    layer_buffer->flags.video = true;
-  }
+  layer_buffer->flags.video = (handle->buffer_type == BUFFER_TYPE_VIDEO) ? true : false;
+
   // TZ Protected Buffer - L1
-  if (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
-    layer_buffer->flags.secure = true;
-    if (handle->flags & private_handle_t::PRIV_FLAGS_CAMERA_WRITE) {
-      layer_buffer->flags.secure_camera = true;
-    }
-  }
-  if (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY) {
-    layer_buffer->flags.secure_display = true;
+  bool secure = (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER);
+  bool secure_camera = secure && (handle->flags & private_handle_t::PRIV_FLAGS_CAMERA_WRITE);
+  bool secure_display = (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY);
+  if (secure != layer_buffer->flags.secure || secure_camera != layer_buffer->flags.secure_camera ||
+      secure_display != layer_buffer->flags.secure_display) {
+    // Secure attribute of layer buffer has changed.
+    needs_validate_ = true;
   }
 
-  layer_buffer->planes[0].fd = ion_fd_;
+  layer_buffer->flags.secure = secure;
+  layer_buffer->flags.secure_camera = secure_camera;
+  layer_buffer->flags.secure_display = secure_display;
+
+  layer_buffer->planes[0].fd = handle->fd;
   layer_buffer->planes[0].offset = handle->offset;
   layer_buffer->planes[0].stride = UINT32(handle->width);
   layer_buffer->acquire_fence_fd = acquire_fence;
@@ -165,6 +163,20 @@
 }
 
 HWC2::Error HWCLayer::SetLayerSurfaceDamage(hwc_region_t damage) {
+  // Check if there is an update in SurfaceDamage rects
+  if (layer_->dirty_regions.size() != damage.numRects) {
+    needs_validate_ = true;
+  } else {
+    for (uint32_t j = 0; j < damage.numRects; j++) {
+      LayerRect damage_rect;
+      SetRect(damage.rects[j], &damage_rect);
+      if (damage_rect != layer_->dirty_regions.at(j)) {
+        needs_validate_ = true;
+        break;
+      }
+    }
+  }
+
   layer_->dirty_regions.clear();
   for (uint32_t i = 0; i < damage.numRects; i++) {
     LayerRect rect;
@@ -198,6 +210,9 @@
 }
 
 HWC2::Error HWCLayer::SetLayerColor(hwc_color_t color) {
+  if (client_requested_ != HWC2::Composition::SolidColor) {
+    return HWC2::Error::None;
+  }
   layer_->solid_fill_color = GetUint32Color(color);
   layer_->input_buffer.format = kFormatARGB8888;
   DLOGV_IF(kTagCompManager, "[%" PRIu64 "][%" PRIu64 "] Layer color set to %x", display_id_, id_,
@@ -576,20 +591,23 @@
   LayerBuffer *layer_buffer = &layer->input_buffer;
   private_handle_t *handle = const_cast<private_handle_t *>(pvt_handle);
   IGC_t igc = {};
+  LayerIGC layer_igc = layer_buffer->igc;
   if (getMetaData(handle, GET_IGC, &igc) == 0) {
-    if (SetIGC(igc, &layer_buffer->igc) != kErrorNone) {
+    if (SetIGC(igc, &layer_igc) != kErrorNone) {
       return kErrorNotSupported;
     }
   }
 
   float fps = 0;
-  if (getMetaData(handle, GET_REFRESH_RATE  , &fps) == 0) {
-    layer->frame_rate = RoundToStandardFPS(fps);
+  uint32_t frame_rate = layer->frame_rate;
+  if (getMetaData(handle, GET_REFRESH_RATE, &fps) == 0) {
+    frame_rate = RoundToStandardFPS(fps);
   }
 
   int32_t interlaced = 0;
+  bool interlace = layer_buffer->flags.interlace;
   if (getMetaData(handle, GET_PP_PARAM_INTERLACED, &interlaced) == 0) {
-    layer_buffer->flags.interlace = interlaced ? true : false;
+    interlace = interlaced ? true : false;
   }
 
   uint32_t linear_format = 0;
@@ -598,8 +616,19 @@
   }
 
   uint32_t s3d = 0;
+  LayerBufferS3DFormat s3d_format = layer_buffer->s3d_format;
   if (getMetaData(handle, GET_S3D_FORMAT, &s3d) == 0) {
-    layer_buffer->s3d_format = GetS3DFormat(s3d);
+    s3d_format = GetS3DFormat(s3d);
+  }
+
+  if ((layer_igc != layer_buffer->igc) || (interlace != layer_buffer->flags.interlace) ||
+      (frame_rate != layer->frame_rate) || (s3d_format != layer_buffer->s3d_format)) {
+    // Layer buffer metadata has changed.
+    needs_validate_ = true;
+    layer_buffer->igc = layer_igc;
+    layer->frame_rate = frame_rate;
+    layer_buffer->s3d_format = s3d_format;
+    layer_buffer->flags.interlace = interlace;
   }
 
   // Check if metadata is set
diff --git a/sdm/libs/hwc2/hwc_layers.h b/sdm/libs/hwc2/hwc_layers.h
index 25ec4dc..e8e6e59 100644
--- a/sdm/libs/hwc2/hwc_layers.h
+++ b/sdm/libs/hwc2/hwc_layers.h
@@ -52,6 +52,7 @@
   kZOrder       = 0x040,
   kAdded        = 0x080,
   kRemoved      = 0x100,
+  kBufferGeometry = 0x200,
 };
 
 class HWCLayer {
@@ -87,6 +88,8 @@
   int32_t PopReleaseFence(void);
   bool ValidateAndSetCSC();
   bool SupportLocalConversion(ColorPrimaries working_primaries);
+  void ResetValidation() { needs_validate_ = false; }
+  bool NeedsValidation() { return (needs_validate_ || geometry_changes_); }
 
  private:
   Layer *layer_ = nullptr;
@@ -95,11 +98,11 @@
   const hwc2_display_t display_id_;
   static std::atomic<hwc2_layer_t> next_id_;
   std::queue<int32_t> release_fences_;
-  int ion_fd_ = -1;
   HWCBufferAllocator *buffer_allocator_ = NULL;
   int32_t dataspace_ =  HAL_DATASPACE_UNKNOWN;
   LayerTransform layer_transform_ = {};
   LayerRect dst_rect_ = {};
+  bool needs_validate_ = true;
 
   // Composition requested by client(SF)
   HWC2::Composition client_requested_ = HWC2::Composition::Device;
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index f7462d1..272b2f6 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -290,10 +290,20 @@
 
 void HWCSession::GetCapabilities(struct hwc2_device *device, uint32_t *outCount,
                                  int32_t *outCapabilities) {
-  if (outCapabilities != nullptr && *outCount >= 1) {
-    outCapabilities[0] = HWC2_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
+  int value = 0;
+  bool disable_skip_validate = false;
+  if (Debug::Get()->GetProperty("sdm.debug.disable_skip_validate", &value) == kErrorNone) {
+    disable_skip_validate = (value == 1);
   }
-  *outCount = 1;
+  uint32_t count = 1 + (disable_skip_validate ? 0 : 1);
+
+  if (outCapabilities != nullptr && (*outCount >= count)) {
+    outCapabilities[0] = HWC2_CAPABILITY_SKIP_CLIENT_COLOR_TRANSFORM;
+    if (!disable_skip_validate) {
+      outCapabilities[1] = HWC2_CAPABILITY_SKIP_VALIDATE;
+    }
+  }
+  *outCount = count;
 }
 
 template <typename PFN, typename T>
@@ -344,7 +354,7 @@
 
 int32_t HWCSession::DestroyVirtualDisplay(hwc2_device_t *device, hwc2_display_t display) {
   SCOPE_LOCK(locker_);
-  if (!device) {
+  if (!device || display != HWC_DISPLAY_VIRTUAL) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
 
@@ -633,8 +643,12 @@
     return HWC2_ERROR_BAD_DISPLAY;
   }
 
+  if (display != HWC_DISPLAY_VIRTUAL) {
+    return HWC2_ERROR_UNSUPPORTED;
+  }
+
   auto *hwc_session = static_cast<HWCSession *>(device);
-  if (display == HWC_DISPLAY_VIRTUAL && hwc_session->hwc_display_[display]) {
+  if (hwc_session->hwc_display_[display]) {
     auto vds = reinterpret_cast<HWCDisplayVirtual *>(hwc_session->hwc_display_[display]);
     auto status = vds->SetOutputBuffer(buffer, releaseFence);
     return INT32(status);
@@ -1306,6 +1320,7 @@
   HWCColorManager::MarshallStructIntoParcel(resp_payload, output_parcel);
   req_payload.DestroyPayload();
   resp_payload.DestroyPayload();
+  hwc_display_[display_id]->ResetValidation();
 
   return (ret ? -EINVAL : 0);
 }
diff --git a/sdm/libs/hwc2/hwc_session.h b/sdm/libs/hwc2/hwc_session.h
index 288bbba..f09ed0e 100644
--- a/sdm/libs/hwc2/hwc_session.h
+++ b/sdm/libs/hwc2/hwc_session.h
@@ -99,11 +99,18 @@
     }
 
     HWCSession *hwc_session = static_cast<HWCSession *>(device);
-    int32_t status = INT32(HWC2::Error::BadDisplay);
+    auto status = HWC2::Error::BadDisplay;
     if (hwc_session->hwc_display_[display]) {
-      status = hwc_session->hwc_display_[display]->CallLayerFunction(layer, member, args...);
+      status = HWC2::Error::BadLayer;
+      auto hwc_layer = hwc_session->hwc_display_[display]->GetHWCLayer(layer);
+      if (hwc_layer != nullptr) {
+        status = (hwc_layer->*member)(std::forward<Args>(args)...);
+        if (hwc_session->hwc_display_[display]->GetGeometryChanges()) {
+          hwc_session->hwc_display_[display]->ResetValidation();
+        }
+      }
     }
-    return status;
+    return INT32(status);
   }
 
   // HWC2 Functions that require a concrete implementation in hwc session
diff --git a/sdm/libs/hwc2/hwc_session_services.cpp b/sdm/libs/hwc2/hwc_session_services.cpp
index 383ec3b..425ffbe 100644
--- a/sdm/libs/hwc2/hwc_session_services.cpp
+++ b/sdm/libs/hwc2/hwc_session_services.cpp
@@ -451,6 +451,7 @@
 
   new_bw_mode_ = true;
   need_invalidate_ = true;
+  hwc_display_[HWC_DISPLAY_PRIMARY]->ResetValidation();
 
   return 0;
 }