Merge "composer: Long term large composition hint"
diff --git a/composer/cpuhint.cpp b/composer/cpuhint.cpp
index bccbe33..d33b470 100644
--- a/composer/cpuhint.cpp
+++ b/composer/cpuhint.cpp
@@ -46,13 +46,16 @@
   }
 
   if (vendor_ext_lib_.Open(path)) {
-    if (!vendor_ext_lib_.Sym("perf_event_offload", reinterpret_cast<void **> \
-        (&fn_perf_event_offload_))) {
+    if (!vendor_ext_lib_.Sym("perf_hint_acq_rel_offload",
+                             reinterpret_cast<void **>(&fn_perf_hint_acq_rel_offload_)) ||
+        !vendor_ext_lib_.Sym("perf_lock_rel_offload",
+                             reinterpret_cast<void **>(&fn_perf_lock_rel_offload_))) {
       DLOGW("Failed to load symbols for Vendor Extension Library");
       return kErrorNotSupported;
     }
     DLOGI("Successfully Loaded Vendor Extension Library symbols");
-    enabled_ = (fn_perf_event_offload_ != NULL);
+    enabled_ = (fn_perf_hint_acq_rel_offload_ != NULL &&
+                fn_perf_lock_rel_offload_ != NULL);
   } else {
     DLOGW("Failed to open %s : %s", path, vendor_ext_lib_.Error());
   }
@@ -60,13 +63,65 @@
   return enabled_ ? kErrorNone : kErrorNotSupported;
 }
 
-void CPUHint::ReqHintsOffload(int hint, int duration) {
+int CPUHint::ReqHintsOffload(int hint, int tid) {
   if(enabled_ && hint > 0) {
-    int args[] = {0, duration};
-    int handle = fn_perf_event_offload_(hint, NULL, 2, args);
-    if (handle < 0) {
-      DLOGW("Failed to send hint 0x%x. handle = %d", hint, handle);
+    if (large_comp_cycle_.status == kActive) {
+      nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+      nsecs_t difference = currentTime-large_comp_cycle_.startTime;
+
+      if (nanoseconds_to_seconds(difference) >= 4) {
+        DLOGV_IF(kTagCpuHint, "Renew large composition hint:%d [start_time:%" PRIu64
+                 " - current_time:%" PRIu64 " = %" PRIu64 "]", large_comp_cycle_.handleId,
+                 large_comp_cycle_.startTime, currentTime, difference);
+
+        large_comp_cycle_.status = kRenew;
+      }
+
+      if (tid != 0 && tid != large_comp_cycle_.tid) {
+        DLOGV_IF(kTagCpuHint, "Renew large composition hint:%d [oldTid:%d newTid:%d]",
+                 large_comp_cycle_.handleId, large_comp_cycle_.tid, tid);
+
+        large_comp_cycle_.status = kRenew;
+      }
+    }
+
+    if (large_comp_cycle_.status == kInactive || large_comp_cycle_.status == kRenew) {
+      PerfHintStatus current_status = large_comp_cycle_.status;
+      int handle = fn_perf_hint_acq_rel_offload_(large_comp_cycle_.handleId, hint, nullptr,
+                                                 tid, 0, 0, nullptr);
+      if (handle < 0) {
+        DLOGW("Failed to request large composition hint ret:%d", handle);
+        return -1;
+      }
+
+      large_comp_cycle_.handleId = handle;
+      large_comp_cycle_.tid = (tid != 0) ? tid : large_comp_cycle_.tid;
+      large_comp_cycle_.startTime = systemTime(SYSTEM_TIME_MONOTONIC);
+      large_comp_cycle_.status = kActive;
+      DLOGV_IF(kTagCpuHint, "Successfully %s large comp hint: handle_id:%d type:0x%x startTime:%"
+               PRIu64 " status:%d", (current_status == kInactive) ? "initialized" : "renewed",
+               large_comp_cycle_.handleId, kLargeComposition, large_comp_cycle_.startTime,
+               large_comp_cycle_.status);
     }
   }
+
+  return 0;
+}
+
+int CPUHint::ReqHintRelease() {
+  if (large_comp_cycle_.status == kActive || large_comp_cycle_.status == kRenew) {
+    int ret = fn_perf_lock_rel_offload_(large_comp_cycle_.handleId);
+    if (ret < 0) {
+      DLOGV_IF(kTagCpuHint, "Failed to release large comp hint ret:%d", ret);
+      return -1;
+    }
+
+    DLOGV_IF(kTagCpuHint, "Release large comp hint ret:%d", ret);
+    large_comp_cycle_.handleId = 0;
+    large_comp_cycle_.tid = 0;
+    large_comp_cycle_.startTime = 0;
+    large_comp_cycle_.status = kInactive;
+  }
+  return 0;
 }
 }  // namespace sdm
diff --git a/composer/cpuhint.h b/composer/cpuhint.h
index 97aad2a..fcc7c95 100644
--- a/composer/cpuhint.h
+++ b/composer/cpuhint.h
@@ -32,20 +32,42 @@
 
 #include <core/sdm_types.h>
 #include <utils/sys.h>
+#include <utils/Timers.h>
 
 namespace sdm {
 
+enum PerfHintStatus {
+  kInactive = 0,
+  kActive,
+  kRenew,
+};
+
+struct LongTermHintInfo {
+  int handleId = 0;
+  int tid = 0;
+  nsecs_t startTime = 0;
+  PerfHintStatus status = kInactive;
+};
+
 class HWCDebugHandler;
 
 class CPUHint {
  public:
   DisplayError Init(HWCDebugHandler *debug_handler);
-  void ReqHintsOffload(int hint, int duration);
+  int ReqHintsOffload(int hint, int tid);
+  int ReqHintRelease();
 
  private:
+  const int kLargeComposition = 0x00001097;
+
   bool enabled_ = false;
   DynLib vendor_ext_lib_;
-  int (*fn_perf_event_offload_)(int hint, const char *pkg, int numArgs, int *) = NULL;
+  int (*fn_perf_hint_acq_rel_offload_)(int handle, int hint, const char *pkg, int duration,
+                                       int type, int numArgs, int list[]) = NULL;
+  int (*fn_perf_lock_rel_offload_)(int handle) = NULL;
+  std::mutex tid_lock_;
+
+  LongTermHintInfo large_comp_cycle_ {};
 };
 
 }  // namespace sdm
diff --git a/composer/hwc_display_builtin.cpp b/composer/hwc_display_builtin.cpp
index d01cff4..1cd02bd 100644
--- a/composer/hwc_display_builtin.cpp
+++ b/composer/hwc_display_builtin.cpp
@@ -1309,24 +1309,23 @@
   return 0;
 }
 
-void HWCDisplayBuiltIn::SetCpuPerfHintLargeCompCycle() {
+bool HWCDisplayBuiltIn::NeedsLargeCompPerfHint() {
   if (!cpu_hint_ || !perf_hint_large_comp_cycle_) {
     DLOGV_IF(kTagResources, "cpu_hint_:%d not initialized or property:%d not set",
              !cpu_hint_, !perf_hint_large_comp_cycle_);
-    return;
+
+    return false;
   }
 
   if (active_refresh_rate_ < 120) {
-    return;
+    return false;
   }
 
   // Send hints when the device is in multi-display or when a skip layer is present.
   if (layer_stack_.flags.skip_present || is_multi_display_) {
     DLOGV_IF(kTagResources, "Found skip_layer:%d or is_multidisplay:%d. Set perf hint for large "
              "comp cycle", layer_stack_.flags.skip_present, is_multi_display_);
-    int hwc_tid = gettid();
-    cpu_hint_->ReqHintsOffload(kPerfHintLargeCompCycle, hwc_tid);
-    return;
+    return true;
   }
 
   int gpu_layer_count = 0;
@@ -1339,27 +1338,26 @@
 
   // Return immediately if full MDP comp is in use
   if (!gpu_layer_count) {
-    return;
+    return false;
   }
 
-  auto it = mixed_mode_threshold_.find(active_refresh_rate_);
+  auto it = mixed_mode_threshold_.find(active_refresh_rate_);;
   if (it != mixed_mode_threshold_.end()) {
     if (gpu_layer_count < it->second) {
       DLOGV_IF(kTagResources, "Number of GPU layers :%d does not meet mixed mode perf hints "
                "threshold:%d for %d fps", gpu_layer_count, it->second, active_refresh_rate_);
-      return;
+      return false;
     }
   } else {
     DLOGV_IF(kTagResources, "Mixed mode perf hints is not supported for %d fps",
              active_refresh_rate_);
-    return;
+    return false;
   }
 
   // Send hints when the number of GPU layers reaches the threshold for the active refresh rate.
   DLOGV_IF(kTagResources, "Reached max GPU layers for %dfps. Set perf hint for large comp cycle",
            active_refresh_rate_);
-  int hwc_tid = gettid();
-  cpu_hint_->ReqHintsOffload(kPerfHintLargeCompCycle, hwc_tid);
+  return true;
 }
 
 HWC2::Error HWCDisplayBuiltIn::PostCommitLayerStack(shared_ptr<Fence> *out_retire_fence) {
@@ -1457,7 +1455,8 @@
 
   auto status = HWCDisplay::CommitOrPrepare(validate_only, out_retire_fence, out_num_types,
                                             out_num_requests, needs_commit);
-  SetCpuPerfHintLargeCompCycle();
+  bool needs_hint = NeedsLargeCompPerfHint();
+  HandleLargeCompositionHint(!needs_hint);
   return status;
 }
 
@@ -1536,4 +1535,27 @@
   return HWC2::Error::None;
 }
 
+void HWCDisplayBuiltIn::HandleLargeCompositionHint(bool release) {
+  int tid = gettid();
+
+  if (release) {
+    num_basic_frames_++;
+
+    if (num_basic_frames_ >= active_refresh_rate_) {
+      cpu_hint_->ReqHintRelease();
+    }
+    return;
+  }
+
+  if (hwc_tid_ != tid) {
+    DLOGV_IF(kTagResources, "HWC's tid:%d is updated to :%d", hwc_tid_, tid);
+    cpu_hint_->ReqHintsOffload(kPerfHintLargeCompCycle, tid);
+    hwc_tid_ = tid;
+  } else {
+    cpu_hint_->ReqHintsOffload(kPerfHintLargeCompCycle, 0);
+  }
+
+  num_basic_frames_ = 0;
+}
+
 }  // namespace sdm
diff --git a/composer/hwc_display_builtin.h b/composer/hwc_display_builtin.h
index 93d2a7b..87974e1 100644
--- a/composer/hwc_display_builtin.h
+++ b/composer/hwc_display_builtin.h
@@ -166,13 +166,14 @@
   void InitStitchTarget();
   bool AllocateStitchBuffer();
   void PostCommitStitchLayers();
-  void SetCpuPerfHintLargeCompCycle();
+  bool NeedsLargeCompPerfHint();
   void ValidateUiScaling();
   void EnablePartialUpdate();
   uint32_t GetUpdatingAppLayersCount();
   int ValidateFrameCaptureConfig(const BufferInfo &output_buffer_info,
                                  const CwbTapPoint &cwb_tappoint);
   void LoadMixedModePerfHintThreshold();
+  void HandleLargeCompositionHint(bool release);
 
   // SyncTask methods.
   void OnTask(const LayerStitchTaskCode &task_code,
@@ -211,6 +212,10 @@
   shared_ptr<Fence> retire_fence_ = nullptr;
   std::unordered_map<int32_t, int32_t> mixed_mode_threshold_;
   int alternate_config_ = -1;
+
+  // Long term large composition hint
+  int hwc_tid_ = 0;
+  uint32_t num_basic_frames_ = 0;
 };
 
 }  // namespace sdm
diff --git a/sdm/include/core/sdm_types.h b/sdm/include/core/sdm_types.h
index 3618253..ec3f6c9 100644
--- a/sdm/include/core/sdm_types.h
+++ b/sdm/include/core/sdm_types.h
@@ -95,6 +95,7 @@
   kTagClient,           //!< Debug log is tagged for SDM client.
   kTagQOSImpl,          //!< Debug log is tagged for Qos library Implementation.
   kTagStitchBuffer,     //!< Debug log is tagged for Stitch Buffer Implementation.
+  kTagCpuHint,          //!< Debug log is tagged for CPU hint Implementation.
 };
 
 }  // namespace sdm