sdm: Add support to defer Fps config

On Builtin display, add support to defer Fps (Transfer time) config
to Comp Manager until number of frames, configured with Vendor properties.

CRs-Fixed: 2472355
Change-Id: Ie314136878b5ec15bfafa629b9a89643cf094d49
diff --git a/include/display_properties.h b/include/display_properties.h
index 5096591..06ab31d 100644
--- a/include/display_properties.h
+++ b/include/display_properties.h
@@ -129,5 +129,6 @@
 #define DISABLE_UI_3D_TONEMAP                DISPLAY_PROP("disable_ui_3d_tonemap")
 #define DISABLE_PARALLEL_CACHE               DISPLAY_PROP("disable_parallel_cache")
 #define ENABLE_FORCE_SPLIT                   DISPLAY_PROP("enable_force_split")
+#define DEFER_FPS_FRAME_COUNT                DISPLAY_PROP("defer_fps_frame_count")
 
 #endif  // __DISPLAY_PROPERTIES_H__
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index d7dabf6..43aa2d8 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -147,6 +147,7 @@
   kIdlePowerCollapse,       // Event triggered by Idle Power Collapse.
   kPanelDeadEvent,          // Event triggered by ESD.
   kDisplayPowerResetEvent,  // Event triggered by Hardware Recovery.
+  kInvalidateDisplay,       // Event triggered to Invalidate display.
 };
 
 /*! @brief This enum represents the secure events received by Display HAL. */
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 8c77e43..9981e77 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -151,6 +151,7 @@
                                                     uint8_t *out_data);
   virtual bool CanSkipValidate();
   virtual DisplayError GetRefreshRate(uint32_t *refresh_rate) { return kErrorNotSupported; }
+  virtual DisplayError ReconfigureDisplay();
 
  protected:
   const char *kBt2020Pq = "bt2020_pq";
@@ -164,7 +165,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 57cf70b..eaed45b 100644
--- a/sdm/libs/core/display_builtin.cpp
+++ b/sdm/libs/core/display_builtin.cpp
@@ -117,9 +117,12 @@
 
   Debug::GetProperty(DISABLE_DEFER_POWER_STATE, &disable_defer_power_state);
   defer_power_state_ = !disable_defer_power_state;
-
   DLOGI("defer_power_state %d", defer_power_state_);
 
+  int value = 0;
+  Debug::Get()->GetProperty(DEFER_FPS_FRAME_COUNT, &value);
+  deferred_config_.frame_count = (value > 0) ? UINT32(value) : 0;
+
   return error;
 }
 
@@ -227,7 +230,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) {
@@ -265,6 +275,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;
@@ -391,8 +406,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) {
@@ -778,4 +794,119 @@
   return kErrorNone;
 }
 
+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 1de4b23..6dd8305 100644
--- a/sdm/libs/core/display_builtin.h
+++ b/sdm/libs/core/display_builtin.h
@@ -34,6 +34,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);
@@ -95,11 +135,16 @@
 
   // Implement the DppsPropIntf
   virtual DisplayError DppsProcessOps(enum DppsOps op, void *payload, size_t size);
+  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);
 
   std::vector<HWEvent> event_list_;
   bool avr_prop_disabled_ = false;
@@ -111,6 +156,7 @@
   LayerRect right_frame_roi_ = {};
   bool first_cycle_ = true;
   int previous_retire_fence_ = -1;
+  DeferFpsConfig deferred_config_ = {};
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 22b9f89..b98bcaf 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -1266,6 +1266,9 @@
               id_);
       }
     } break;
+    case kInvalidateDisplay:
+      validated_ = false;
+      break;
     default:
       DLOGW("Unknown event: %d", event);
       break;