Merge "hwc: Add support to disable animation on WFD(GPU)"
diff --git a/composer/display_null.h b/composer/display_null.h
index a009f02..aa03038 100644
--- a/composer/display_null.h
+++ b/composer/display_null.h
@@ -94,7 +94,7 @@
   MAKE_NO_OP(GetDefaultColorMode(string *))
   MAKE_NO_OP(ApplyDefaultDisplayMode())
   MAKE_NO_OP(SetCursorPosition(int, int))
-  MAKE_NO_OP(SetRefreshRate(uint32_t, bool))
+  MAKE_NO_OP(SetRefreshRate(uint32_t, bool, bool))
   MAKE_NO_OP(GetPanelBrightness(float *))
   MAKE_NO_OP(GetPanelMaxBrightness(uint32_t *))
   MAKE_NO_OP(GetRefreshRate(uint32_t *))
diff --git a/composer/hwc_display_builtin.cpp b/composer/hwc_display_builtin.cpp
index 1435f66..0412c85 100644
--- a/composer/hwc_display_builtin.cpp
+++ b/composer/hwc_display_builtin.cpp
@@ -162,6 +162,10 @@
     }
   }
 
+  value = 0;
+  DebugHandler::Get()->GetProperty(DISABLE_DYNAMIC_FPS, &value);
+  disable_dyn_fps_ = (value == 1);
+
   uint32_t config_index = 0;
   GetActiveDisplayConfig(&config_index);
   DisplayConfigVariableInfo attr = {};
@@ -170,6 +174,11 @@
 
   DLOGI("active_refresh_rate: %d", active_refresh_rate_);
 
+  int enhance_idle_time = 0;
+  HWCDebugHandler::Get()->GetProperty(ENHANCE_IDLE_TIME, &enhance_idle_time);
+  enhance_idle_time_ = (enhance_idle_time == 1);
+  DLOGI("enhance_idle_time: %d", enhance_idle_time);
+
   return status;
 }
 
@@ -230,14 +239,16 @@
   }
 
   uint32_t refresh_rate = GetOptimalRefreshRate(one_updating_layer);
-  error = display_intf_->SetRefreshRate(refresh_rate, force_refresh_rate_);
+  bool idle_screen = GetUpdatingAppLayersCount() == 0;
+  error = display_intf_->SetRefreshRate(refresh_rate, force_refresh_rate_, idle_screen);
 
   // Get the refresh rate set.
   display_intf_->GetRefreshRate(&refresh_rate);
   bool vsync_source = (callbacks_->GetVsyncSource() == id_);
 
   if (error == kErrorNone) {
-    if (vsync_source && (current_refresh_rate_ < refresh_rate)) {
+    if (vsync_source && ((current_refresh_rate_ < refresh_rate) ||
+                         (enhance_idle_time_ && (current_refresh_rate_ != refresh_rate)))) {
       DTRACE_BEGIN("HWC2::Vsync::Enable");
       // Display is ramping up from idle.
       // Client realizes need for resync upon change in config.
@@ -480,6 +491,15 @@
       if (is_cmd_mode_ != command_mode) {
         SetPartialUpdate(fixed_info);
       }
+
+      // For video mode panel with dynamic fps, update the active mode index.
+      // This is needed to report the correct Vsync period when client queries
+      // using GetDisplayVsyncPeriod API.
+      if (!is_cmd_mode_ && !disable_dyn_fps_) {
+        hwc2_config_t active_config = hwc_config_map_.at(0);
+        GetActiveConfig(&active_config);
+        SetActiveConfigIndex(active_config);
+      }
     }
   }
 
@@ -1454,4 +1474,20 @@
   return fixed_info.readback_supported;
 }
 
+uint32_t HWCDisplayBuiltIn::GetUpdatingAppLayersCount() {
+  uint32_t updating_count = 0;
+
+  for (uint i = 0; i < layer_stack_.layers.size(); i++) {
+    auto layer = layer_stack_.layers.at(i);
+    if (layer->composition == kCompositionGPUTarget) {
+      break;
+    }
+    if (layer->flags.updating) {
+      updating_count++;
+    }
+  }
+
+  return updating_count;
+}
+
 }  // namespace sdm
diff --git a/composer/hwc_display_builtin.h b/composer/hwc_display_builtin.h
index a0da3fd..33d3da3 100644
--- a/composer/hwc_display_builtin.h
+++ b/composer/hwc_display_builtin.h
@@ -174,6 +174,7 @@
   int GetBwCode(const DisplayConfigVariableInfo &attr);
   void SetBwLimitHint(bool enable);
   void SetPartialUpdate(DisplayConfigFixedInfo fixed_info);
+  uint32_t GetUpdatingAppLayersCount();
 
   // SyncTask methods.
   void OnTask(const LayerStitchTaskCode &task_code,
@@ -224,6 +225,8 @@
   bool is_smart_panel_ = false;
   const char *kDisplayBwName = "display_bw";
   bool enable_bw_limits_ = false;
+  bool disable_dyn_fps_ = false;
+  bool enhance_idle_time_ = false;
 };
 
 }  // namespace sdm
diff --git a/config/display-product.mk b/config/display-product.mk
index 6d09b8a..fdd2801 100644
--- a/config/display-product.mk
+++ b/config/display-product.mk
@@ -19,6 +19,7 @@
     vendor.qti.hardware.display.mapper@4.0.vendor \
     modetest
 
+ifneq ($(TARGET_HAS_LOW_RAM),true)
 #QDCM calibration xml file for 2k panel
 PRODUCT_COPY_FILES += hardware/qcom/display/config/qdcm_calib_data_nt35597_cmd_mode_dsi_truly_panel_with_DSC.xml:$(TARGET_COPY_OUT_VENDOR)/etc/qdcm_calib_data_nt35597_cmd_mode_dsi_truly_panel_with_DSC.xml
 PRODUCT_COPY_FILES += hardware/qcom/display/config/qdcm_calib_data_nt35597_cmd_mode_dsi_truly_panel_with_DSC.xml:$(TARGET_COPY_OUT_VENDOR)/etc/qdcm_calib_data_nt35597_video_mode_dsi_truly_panel_with_DSC.xml
@@ -32,9 +33,6 @@
 #QDCM calibration xml file for dual panel
 PRODUCT_COPY_FILES += hardware/qcom/display/config/qdcm_calib_data_default.xml:$(TARGET_COPY_OUT_VENDOR)/etc/qdcm_calib_data_sharp_1080p_cmd_mode_dsi_panel.xml
 PRODUCT_COPY_FILES += hardware/qcom/display/config/qdcm_calib_data_default.xml:$(TARGET_COPY_OUT_VENDOR)/etc/qdcm_calib_data_nt35695b_truly_fhd_command_mode_dsi_panel.xml
-#QDCM calibration xml file for td4330 panel
-PRODUCT_COPY_FILES += hardware/qcom/display/config/qdcm_calib_data_bengal_default.xml:$(TARGET_COPY_OUT_VENDOR)/etc/qdcm_calib_data_td4330_v2_cmd_mode_dsi_truly_panel.xml
-PRODUCT_COPY_FILES += hardware/qcom/display/config/qdcm_calib_data_bengal_default.xml:$(TARGET_COPY_OUT_VENDOR)/etc/qdcm_calib_data_td4330_v2_video_mode_dsi_truly_panel.xml
 #QDCM calibration xml file for Sharp fhd panel
 PRODUCT_COPY_FILES += hardware/qcom/display/config/qdcm_calib_data_default.xml:$(TARGET_COPY_OUT_VENDOR)/etc/qdcm_calib_data_Sharp_fhd_cmd_mode_qsync_dsi_panel.xml
 PRODUCT_COPY_FILES += hardware/qcom/display/config/qdcm_calib_data_default.xml:$(TARGET_COPY_OUT_VENDOR)/etc/qdcm_calib_data_Sharp_fhd_video_mode_qsync_dsi_panel.xml
@@ -54,6 +52,10 @@
 PRODUCT_COPY_FILES += hardware/qcom/display/config/qdcm_calib_data_default.xml:$(TARGET_COPY_OUT_VENDOR)/etc/qdcm_calib_data_rm69299_amoled_fhd+_cmd_mode_dsi_visionox_panel.xml
 #QDCM calibration xml file for nt36525 truly panel
 PRODUCT_COPY_FILES += hardware/qcom/display/config/qdcm_calib_data_bengal_default.xml:$(TARGET_COPY_OUT_VENDOR)/etc/qdcm_calib_data_nt36525_video_mode_dsi_truly_panel.xml
+endif
+#QDCM calibration xml file for td4330 panel
+PRODUCT_COPY_FILES += hardware/qcom/display/config/qdcm_calib_data_bengal_default.xml:$(TARGET_COPY_OUT_VENDOR)/etc/qdcm_calib_data_td4330_v2_cmd_mode_dsi_truly_panel.xml
+PRODUCT_COPY_FILES += hardware/qcom/display/config/qdcm_calib_data_bengal_default.xml:$(TARGET_COPY_OUT_VENDOR)/etc/qdcm_calib_data_td4330_v2_video_mode_dsi_truly_panel.xml
 
 PRODUCT_PROPERTY_OVERRIDES += \
     persist.demo.hdmirotationlock=false \
diff --git a/include/display_properties.h b/include/display_properties.h
index 9945118..b8a8b49 100644
--- a/include/display_properties.h
+++ b/include/display_properties.h
@@ -122,6 +122,7 @@
 #define DISABLE_INLINE_ROTATOR_UI_PROP       DISPLAY_PROP("disable_inline_rotator_ui")
 #define ENABLE_POMS_DURING_DOZE              DISPLAY_PROP("enable_poms_during_doze")
 #define DISABLE_DYNAMIC_FPS                  DISPLAY_PROP("disable_dynamic_fps")
+#define ENHANCE_IDLE_TIME                    DISPLAY_PROP("enhance_idle_time")
 
 // Add all vendor.display properties above
 
diff --git a/libhistogram/histogram_collector.cpp b/libhistogram/histogram_collector.cpp
index f7da3b4..f52e241 100644
--- a/libhistogram/histogram_collector.cpp
+++ b/libhistogram/histogram_collector.cpp
@@ -67,7 +67,7 @@
 }  // namespace
 
 std::string histogram::HistogramCollector::Dump() const {
-  uint64_t num_frames;
+  uint64_t num_frames = 0;
   std::array<uint64_t, HIST_V_SIZE> all_sample_buckets;
   std::tie(num_frames, all_sample_buckets) = histogram->collect_cumulative();
   std::array<uint64_t, numBuckets> samples = rebucketTo8Buckets(all_sample_buckets);
@@ -101,7 +101,7 @@
   out_samples_size[2] = numBuckets;
   out_samples_size[3] = 0;
 
-  uint64_t num_frames;
+  uint64_t num_frames = 0;
   std::array<uint64_t, HIST_V_SIZE> samples;
 
   if (max_frames == 0 && timestamp == 0) {
@@ -194,7 +194,7 @@
     lk.unlock();
 
     drmModePropertyBlobPtr blob = drmModeGetPropertyBlob(work.fd, work.id);
-    if (!blob) {
+    if (!blob || !blob->data) {
       lk.lock();
       continue;
     }
diff --git a/libhistogram/ringbuffer.cpp b/libhistogram/ringbuffer.cpp
index b19682f..1c06f76 100644
--- a/libhistogram/ringbuffer.cpp
+++ b/libhistogram/ringbuffer.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2018, 2020 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -125,7 +125,8 @@
     return {0, {}};
   std::array<uint64_t, HIST_V_SIZE> bins;
   bins.fill(0);
-  for (auto it = ringbuffer.begin(); it != ringbuffer.begin() + collect_first; it++) {
+  for (auto it = ringbuffer.begin(); it != ringbuffer.end() &&
+    it != ringbuffer.begin() + collect_first; it++) {
     nsecs_t end_timestamp = it->end_timestamp;
     if (it == ringbuffer.begin()) {
       end_timestamp = timekeeper->current_time();
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index c8d1cf6..2f087cf 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -544,9 +544,12 @@
 
     @param[in] final_rate indicates whether refresh rate is final rate or can be changed by sdm
 
+    @param[in] idle_screen indicates whether screen is idle.
+
     @return \link DisplayError \endlink
   */
-  virtual DisplayError SetRefreshRate(uint32_t refresh_rate, bool final_rate) = 0;
+  virtual DisplayError SetRefreshRate(uint32_t refresh_rate, bool final_rate,
+                                      bool idle_screen = false) = 0;
 
   /*! @brief Method to get the refresh rate of a display.
 
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
index 8f35daa..aad32d7 100644
--- a/sdm/libs/core/comp_manager.cpp
+++ b/sdm/libs/core/comp_manager.cpp
@@ -451,6 +451,7 @@
 }
 
 void CompManager::ProcessIdleTimeout(Handle display_ctx) {
+  DTRACE_SCOPED();
   SCOPE_LOCK(locker_);
 
   DisplayCompositionContext *display_comp_ctx =
diff --git a/sdm/libs/core/display_builtin.cpp b/sdm/libs/core/display_builtin.cpp
index a73bf2f..9e889fb 100644
--- a/sdm/libs/core/display_builtin.cpp
+++ b/sdm/libs/core/display_builtin.cpp
@@ -57,6 +57,10 @@
 DisplayBuiltIn::~DisplayBuiltIn() {
 }
 
+static uint64_t GetTimeInMs(struct timespec ts) {
+  return (ts.tv_sec * 1000 + (ts.tv_nsec + 500000) / 1000000);
+}
+
 DisplayError DisplayBuiltIn::Init() {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
 
@@ -121,6 +125,10 @@
   DebugHandler::Get()->GetProperty(DISABLE_DYNAMIC_FPS, &value);
   disable_dyn_fps_ = (value == 1);
 
+  value = 0;
+  DebugHandler::Get()->GetProperty(ENHANCE_IDLE_TIME, &value);
+  enhance_idle_time_ = (value == 1);
+
   return error;
 }
 
@@ -295,9 +303,11 @@
     deferred_config_.Clear();
   }
 
+  clock_gettime(CLOCK_MONOTONIC, &idle_timer_start_);
   int idle_time_ms = hw_layers_.info.set_idle_time_ms;
   if (idle_time_ms >= 0) {
     hw_intf_->SetIdleTimeoutMs(UINT32(idle_time_ms));
+    idle_time_ms_ = idle_time_ms;
   }
 
   if (switch_to_cmd_) {
@@ -499,7 +509,8 @@
   return hw_intf_->TeardownConcurrentWriteback();
 }
 
-DisplayError DisplayBuiltIn::SetRefreshRate(uint32_t refresh_rate, bool final_rate) {
+DisplayError DisplayBuiltIn::SetRefreshRate(uint32_t refresh_rate, bool final_rate,
+                                            bool idle_screen) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
 
   if (!active_ || !hw_panel_info_.dynamic_fps || qsync_mode_ != kQSyncModeNone ||
@@ -512,11 +523,11 @@
     return kErrorParameters;
   }
 
-  if (handle_idle_timeout_ && !final_rate) {
+  if (CanLowerFps(idle_screen) && !final_rate) {
     refresh_rate = hw_panel_info_.min_fps;
   }
 
-  if ((current_refresh_rate_ != refresh_rate) || handle_idle_timeout_) {
+  if (current_refresh_rate_ != refresh_rate) {
     DisplayError error = hw_intf_->SetRefreshRate(refresh_rate);
     if (error != kErrorNone) {
       // Attempt to update refresh rate can fail if rf interfenence is detected.
@@ -531,6 +542,11 @@
     }
   }
 
+  // Set safe mode upon success.
+  if (enhance_idle_time_ && handle_idle_timeout_ && (refresh_rate == hw_panel_info_.min_fps)) {
+    comp_manager_->ProcessIdleTimeout(display_comp_ctx_);
+  }
+
   // On success, set current refresh rate to new refresh rate
   current_refresh_rate_ = refresh_rate;
   handle_idle_timeout_ = false;
@@ -539,6 +555,24 @@
   return ReconfigureDisplay();
 }
 
+bool DisplayBuiltIn::CanLowerFps(bool idle_screen) {
+  if (!enhance_idle_time_) {
+    return handle_idle_timeout_;
+  }
+
+  if (!handle_idle_timeout_ || !idle_screen) {
+    return false;
+  }
+
+  struct timespec now;
+  clock_gettime(CLOCK_MONOTONIC, &now);
+  uint64_t elapsed_time_ms = GetTimeInMs(now) - GetTimeInMs(idle_timer_start_);
+  bool can_lower = elapsed_time_ms >= UINT32(idle_time_ms_);
+  DLOGV_IF(kTagDisplay, "lower fps: %d", can_lower);
+
+  return can_lower;
+}
+
 DisplayError DisplayBuiltIn::VSync(int64_t timestamp) {
   if (vsync_enable_ && !drop_hw_vsync_) {
     DisplayEventVSync vsync;
@@ -556,8 +590,10 @@
     }
     handle_idle_timeout_ = true;
     event_handler_->Refresh();
-    lock_guard<recursive_mutex> obj(recursive_mutex_);
-    comp_manager_->ProcessIdleTimeout(display_comp_ctx_);
+    if (!enhance_idle_time_) {
+      lock_guard<recursive_mutex> obj(recursive_mutex_);
+      comp_manager_->ProcessIdleTimeout(display_comp_ctx_);
+    }
   }
 }
 
diff --git a/sdm/libs/core/display_builtin.h b/sdm/libs/core/display_builtin.h
index ddc4bb1..9cf8a5f 100644
--- a/sdm/libs/core/display_builtin.h
+++ b/sdm/libs/core/display_builtin.h
@@ -25,6 +25,8 @@
 #ifndef __DISPLAY_BUILTIN_H__
 #define __DISPLAY_BUILTIN_H__
 
+#include <sys/time.h>
+
 #include <core/dpps_interface.h>
 #include <string>
 #include <vector>
@@ -111,7 +113,7 @@
   virtual void SetIdleTimeoutMs(uint32_t active_ms);
   virtual DisplayError SetDisplayMode(uint32_t mode);
   virtual DisplayError GetRefreshRateRange(uint32_t *min_refresh_rate, uint32_t *max_refresh_rate);
-  virtual DisplayError SetRefreshRate(uint32_t refresh_rate, bool final_rate);
+  virtual DisplayError SetRefreshRate(uint32_t refresh_rate, bool final_rate, bool idle_screen);
   virtual DisplayError SetPanelBrightness(float brightness);
   virtual DisplayError GetPanelBrightness(float *brightness);
   virtual DisplayError GetPanelMaxBrightness(uint32_t *max_brightness_level);
@@ -156,6 +158,7 @@
   void SetDeferredFpsConfig();
   void GetFpsConfig(HWDisplayAttributes *display_attributes, HWPanelInfo *panel_info);
   void UpdateDisplayModeParams();
+  bool CanLowerFps(bool idle_screen);
 
   const uint32_t kPuTimeOutMs = 1000;
   std::vector<HWEvent> event_list_;
@@ -185,6 +188,9 @@
   sde_drm::DppsFeaturePayload histogramIRQ;
   void initColorSamplingState();
   DeferFpsConfig deferred_config_ = {};
+  bool enhance_idle_time_ = false;
+  int idle_time_ms_ = 0;
+  struct timespec idle_timer_start_;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/display_pluggable.cpp b/sdm/libs/core/display_pluggable.cpp
index 4ac1f01..4254348 100644
--- a/sdm/libs/core/display_pluggable.cpp
+++ b/sdm/libs/core/display_pluggable.cpp
@@ -156,7 +156,8 @@
   return error;
 }
 
-DisplayError DisplayPluggable::SetRefreshRate(uint32_t refresh_rate, bool final_rate) {
+DisplayError DisplayPluggable::SetRefreshRate(uint32_t refresh_rate, bool final_rate,
+                                              bool idle_screen) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
 
   if (!active_) {
diff --git a/sdm/libs/core/display_pluggable.h b/sdm/libs/core/display_pluggable.h
index e2b5c3a..18d6610 100644
--- a/sdm/libs/core/display_pluggable.h
+++ b/sdm/libs/core/display_pluggable.h
@@ -44,7 +44,7 @@
   virtual DisplayError Init();
   virtual DisplayError Prepare(LayerStack *layer_stack);
   virtual DisplayError GetRefreshRateRange(uint32_t *min_refresh_rate, uint32_t *max_refresh_rate);
-  virtual DisplayError SetRefreshRate(uint32_t refresh_rate, bool final_rate);
+  virtual DisplayError SetRefreshRate(uint32_t refresh_rate, bool final_rate, bool idle_screen);
   virtual bool IsUnderscanSupported();
   virtual DisplayError InitializeColorModes();
   virtual DisplayError SetColorMode(const std::string &color_mode);
diff --git a/sdm/libs/core/display_virtual.h b/sdm/libs/core/display_virtual.h
index 9cadf60..0ff0180 100644
--- a/sdm/libs/core/display_virtual.h
+++ b/sdm/libs/core/display_virtual.h
@@ -55,7 +55,7 @@
   virtual DisplayError SetVSyncState(bool enable) {
     return kErrorNotSupported;
   }
-  virtual DisplayError SetRefreshRate(uint32_t refresh_rate, bool final_rate) {
+  virtual DisplayError SetRefreshRate(uint32_t refresh_rate, bool final_rate, bool idle_screen) {
     return kErrorNotSupported;
   }
   virtual DisplayError SetDetailEnhancerData(const DisplayDetailEnhancerData &de_data) {