Merge "sdm: Add support to defer Fps config"
diff --git a/include/display_properties.h b/include/display_properties.h
index e2a5436..59b52f7 100644
--- a/include/display_properties.h
+++ b/include/display_properties.h
@@ -116,6 +116,7 @@
 #define NORMAL_NOC_EFFICIENCY_FACTOR         DISPLAY_PROP("normal_noc_efficiency_factor")
 #define CAMERA_NOC_EFFICIENCY_FACTOR         DISPLAY_PROP("camera_noc_efficiency_factor")
 #define ENABLE_HISTOGRAM_INTR                DISPLAY_PROP("enable_hist_intr")
+#define DEFER_FPS_FRAME_COUNT                DISPLAY_PROP("defer_fps_frame_count")
 
 // Add all vendor.display properties above
 
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 6d0de2b..1aca80d 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -164,6 +164,7 @@
   virtual DisplayError GetQSyncMode(QSyncMode *qsync_mode) { return kErrorNotSupported; }
   virtual DisplayError colorSamplingOn();
   virtual DisplayError colorSamplingOff();
+  virtual DisplayError ReconfigureDisplay();
 
  protected:
   const char *kBt2020Pq = "bt2020_pq";
@@ -178,7 +179,6 @@
   void HwRecovery(const HWRecoveryEvent sdm_event_code);
 
   const char *GetName(const LayerComposition &composition);
-  DisplayError ReconfigureDisplay();
   bool NeedsMixerReconfiguration(LayerStack *layer_stack, uint32_t *new_mixer_width,
                                  uint32_t *new_mixer_height);
   DisplayError ReconfigureMixer(uint32_t width, uint32_t height);
diff --git a/sdm/libs/core/display_builtin.cpp b/sdm/libs/core/display_builtin.cpp
index befdc32..33a244c 100644
--- a/sdm/libs/core/display_builtin.cpp
+++ b/sdm/libs/core/display_builtin.cpp
@@ -116,6 +116,10 @@
 
   initColorSamplingState();
 
+  int value = 0;
+  Debug::Get()->GetProperty(DEFER_FPS_FRAME_COUNT, &value);
+  deferred_config_.frame_count = (value > 0) ? UINT32(value) : 0;
+
   return error;
 }
 
@@ -280,7 +284,14 @@
     dpps_info_.DppsNotifyOps(kDppsCommitEvent, &display_type_, sizeof(display_type_));
   }
 
-  DisplayBase::ReconfigureDisplay();
+  deferred_config_.UpdateDeferCount();
+
+  ReconfigureDisplay();
+
+  if (deferred_config_.CanApplyDeferredState()) {
+    event_handler_->HandleEvent(kInvalidateDisplay);
+    deferred_config_.Clear();
+  }
 
   int idle_time_ms = hw_layers_.info.set_idle_time_ms;
   if (idle_time_ms >= 0) {
@@ -322,6 +333,11 @@
                                              int *release_fence) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
   DisplayError error = kErrorNone;
+
+  if ((state == kStateOn) && deferred_config_.IsDeferredState()) {
+    SetDeferredFpsConfig();
+  }
+
   error = DisplayBase::SetDisplayState(state, teardown, release_fence);
   if (error != kErrorNone) {
     return error;
@@ -496,8 +512,9 @@
   // On success, set current refresh rate to new refresh rate
   current_refresh_rate_ = refresh_rate;
   handle_idle_timeout_ = false;
+  deferred_config_.MarkDirty();
 
-  return DisplayBase::ReconfigureDisplay();
+  return ReconfigureDisplay();
 }
 
 DisplayError DisplayBuiltIn::VSync(int64_t timestamp) {
@@ -1047,4 +1064,119 @@
   return same_roi;
 }
 
+DisplayError DisplayBuiltIn::SetActiveConfig(uint32_t index) {
+  deferred_config_.MarkDirty();
+  return DisplayBase::SetActiveConfig(index);
+}
+
+DisplayError DisplayBuiltIn::ReconfigureDisplay() {
+  lock_guard<recursive_mutex> obj(recursive_mutex_);
+  DisplayError error = kErrorNone;
+  HWDisplayAttributes display_attributes;
+  HWMixerAttributes mixer_attributes;
+  HWPanelInfo hw_panel_info;
+  uint32_t active_index = 0;
+
+  DTRACE_SCOPED();
+
+  error = hw_intf_->GetActiveConfig(&active_index);
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  error = hw_intf_->GetDisplayAttributes(active_index, &display_attributes);
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  error = hw_intf_->GetMixerAttributes(&mixer_attributes);
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  error = hw_intf_->GetHWPanelInfo(&hw_panel_info);
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  const bool dirty = deferred_config_.IsDirty();
+  if (deferred_config_.IsDeferredState()) {
+    if (dirty) {
+      SetDeferredFpsConfig();
+    } else {
+      // In Deferred state, use current config for comparison.
+      GetFpsConfig(&display_attributes, &hw_panel_info);
+    }
+  }
+
+  const bool display_unchanged = (display_attributes == display_attributes_);
+  const bool mixer_unchanged = (mixer_attributes == mixer_attributes_);
+  const bool panel_unchanged = (hw_panel_info == hw_panel_info_);
+  if (!dirty && display_unchanged && mixer_unchanged && panel_unchanged) {
+    return kErrorNone;
+  }
+
+  if (CanDeferFpsConfig(display_attributes.fps)) {
+    deferred_config_.Init(display_attributes.fps, display_attributes.vsync_period_ns,
+                          hw_panel_info.transfer_time_us);
+
+    // Apply current config until new Fps is deferred.
+    GetFpsConfig(&display_attributes, &hw_panel_info);
+  }
+
+  error = comp_manager_->ReconfigureDisplay(display_comp_ctx_, display_attributes, hw_panel_info,
+                                            mixer_attributes, fb_config_,
+                                            &(default_qos_data_.clock_hz));
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  bool disble_pu = true;
+  if (mixer_unchanged && panel_unchanged) {
+    // Do not disable Partial Update for one frame, if only FPS has changed.
+    // Because if first frame after transition, has a partial Frame-ROI and
+    // is followed by Skip Validate frames, then it can benefit those frames.
+    disble_pu = !display_attributes_.OnlyFpsChanged(display_attributes);
+  }
+
+  if (disble_pu) {
+    DisablePartialUpdateOneFrame();
+  }
+
+  display_attributes_ = display_attributes;
+  mixer_attributes_ = mixer_attributes;
+  hw_panel_info_ = hw_panel_info;
+
+  // TODO(user): Temporary changes, to be removed when DRM driver supports
+  // Partial update with Destination scaler enabled.
+  SetPUonDestScaler();
+
+  return kErrorNone;
+}
+
+bool DisplayBuiltIn::CanDeferFpsConfig(uint32_t fps) {
+  if (deferred_config_.CanApplyDeferredState()) {
+    // Deferred Fps Config needs to be applied.
+    return false;
+  }
+
+  // In case of higher to lower Fps transition on a Builtin display, defer the Fps
+  // (Transfer time) configuration, for the number of frames based on frame_count.
+  return ((deferred_config_.frame_count != 0) && (display_attributes_.fps > fps));
+}
+
+void DisplayBuiltIn::SetDeferredFpsConfig() {
+  // Update with the deferred Fps Config.
+  display_attributes_.fps = deferred_config_.fps;
+  display_attributes_.vsync_period_ns = deferred_config_.vsync_period_ns;
+  hw_panel_info_.transfer_time_us = deferred_config_.transfer_time_us;
+  deferred_config_.Clear();
+}
+
+void DisplayBuiltIn::GetFpsConfig(HWDisplayAttributes *display_attr, HWPanelInfo *panel_info) {
+  display_attr->fps = display_attributes_.fps;
+  display_attr->vsync_period_ns = display_attributes_.vsync_period_ns;
+  panel_info->transfer_time_us = hw_panel_info_.transfer_time_us;
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/core/display_builtin.h b/sdm/libs/core/display_builtin.h
index 7fe6c6c..abc8a9a 100644
--- a/sdm/libs/core/display_builtin.h
+++ b/sdm/libs/core/display_builtin.h
@@ -35,6 +35,46 @@
 
 namespace sdm {
 
+struct DeferFpsConfig {
+  uint32_t frame_count = 0;
+  uint32_t frames_to_defer = 0;
+  uint32_t fps = 0;
+  uint32_t vsync_period_ns = 0;
+  uint32_t transfer_time_us = 0;
+  bool dirty = false;
+  bool apply = false;
+
+  void Init(uint32_t refresh_rate, uint32_t vsync_period, uint32_t transfer_time) {
+    fps = refresh_rate;
+    vsync_period_ns = vsync_period;
+    transfer_time_us = transfer_time;
+    frames_to_defer = frame_count;
+    dirty = false;
+    apply = false;
+  }
+
+  bool IsDeferredState() { return (frames_to_defer != 0); }
+
+  bool CanApplyDeferredState() { return apply; }
+
+  bool IsDirty() { return dirty; }
+
+  void MarkDirty() { dirty = IsDeferredState(); }
+
+  void UpdateDeferCount() {
+    if (frames_to_defer > 0) {
+      frames_to_defer--;
+      apply = (frames_to_defer == 0);
+    }
+  }
+
+  void Clear() {
+    frames_to_defer = 0;
+    dirty = false;
+    apply = false;
+  }
+};
+
 class DppsInfo {
  public:
   void Init(DppsPropIntf *intf, const std::string &panel_name);
@@ -106,11 +146,16 @@
   // Implement the DppsPropIntf
   virtual DisplayError DppsProcessOps(enum DppsOps op, void *payload, size_t size);
   void ResetPanel();
+  virtual DisplayError SetActiveConfig(uint32_t index);
+  virtual DisplayError ReconfigureDisplay();
 
  private:
   bool CanCompareFrameROI(LayerStack *layer_stack);
   bool CanSkipDisplayPrepare(LayerStack *layer_stack);
   HWAVRModes GetAvrMode(QSyncMode mode);
+  bool CanDeferFpsConfig(uint32_t fps);
+  void SetDeferredFpsConfig();
+  void GetFpsConfig(HWDisplayAttributes *display_attributes, HWPanelInfo *panel_info);
 
   const uint32_t kPuTimeOutMs = 1000;
   std::vector<HWEvent> event_list_;
@@ -138,6 +183,7 @@
   sde_drm::DppsFeaturePayload histogramCtrl;
   sde_drm::DppsFeaturePayload histogramIRQ;
   void initColorSamplingState();
+  DeferFpsConfig deferred_config_ = {};
 };
 
 }  // namespace sdm