Merge "composer: Implement QsyncCallback API"
diff --git a/composer/Android.mk b/composer/Android.mk
index 306a7dc..cc57203 100644
--- a/composer/Android.mk
+++ b/composer/Android.mk
@@ -46,7 +46,8 @@
                                  vendor.display.config@1.11 \
                                  vendor.display.config@1.12 \
                                  vendor.display.config@1.13 \
-                                 vendor.display.config@1.14
+                                 vendor.display.config@1.14 \
+                                 vendor.display.config@1.15
 
 LOCAL_SRC_FILES               := QtiComposer.cpp QtiComposerClient.cpp service.cpp \
                                  QtiComposerHandleImporter.cpp \
diff --git a/composer/display_null.h b/composer/display_null.h
index bcc8dbb..8c2e8bf 100644
--- a/composer/display_null.h
+++ b/composer/display_null.h
@@ -117,6 +117,7 @@
   MAKE_NO_OP(SetFrameTriggerMode(FrameTriggerMode))
   MAKE_NO_OP(SetPanelLuminanceAttributes(float min_lum, float max_lum))
   MAKE_NO_OP(SetBLScale(uint32_t))
+  MAKE_NO_OP(GetQSyncMode(QSyncMode *))
 
  protected:
   DisplayConfigVariableInfo default_variable_config_ = {};
diff --git a/composer/hwc_display.h b/composer/hwc_display.h
index fa09cfa..7dae1a2 100644
--- a/composer/hwc_display.h
+++ b/composer/hwc_display.h
@@ -377,6 +377,10 @@
     pending_power_mode_ = current_power_mode_;
   }
   virtual void NotifyClientStatus(bool connected) { client_connected_ = connected; }
+  virtual bool IsQsyncCallbackNeeded(bool *qsync_enabled, int32_t *refresh_rate,
+                                     int32_t *qsync_refresh_rate) {
+    return false;
+  }
 
  protected:
   static uint32_t throttling_refresh_rate_;
diff --git a/composer/hwc_display_builtin.cpp b/composer/hwc_display_builtin.cpp
index 439170a..f40bbf4 100644
--- a/composer/hwc_display_builtin.cpp
+++ b/composer/hwc_display_builtin.cpp
@@ -296,6 +296,44 @@
   return HWC2::Error::None;
 }
 
+void HWCDisplayBuiltIn::CacheAvrStatus() {
+  QSyncMode qsync_mode = kQSyncModeNone;
+
+  DisplayError error = display_intf_->GetQSyncMode(&qsync_mode);
+  if (error != kErrorNone) {
+    return;
+  }
+
+  bool qsync_enabled = (qsync_mode != kQSyncModeNone);
+  if (qsync_enabled_ != qsync_enabled) {
+    qsync_reconfigured_ = true;
+    qsync_enabled_ = qsync_enabled;
+  } else {
+    qsync_reconfigured_ = false;
+  }
+}
+
+bool HWCDisplayBuiltIn::IsQsyncCallbackNeeded(bool *qsync_enabled, int32_t *refresh_rate,
+                           int32_t *qsync_refresh_rate) {
+  if (!qsync_reconfigured_) {
+    return false;
+  }
+
+  bool vsync_source = (callbacks_->GetVsyncSource() == id_);
+  // Qsync callback not needed if this display is not the source of vsync
+  if (!vsync_source) {
+    return false;
+  }
+
+  *qsync_enabled = qsync_enabled_;
+  uint32_t current_rate = 0;
+  display_intf_->GetRefreshRate(&current_rate);
+  *refresh_rate = INT32(current_rate);
+  *qsync_refresh_rate = min_refresh_rate_;
+
+  return true;
+}
+
 HWC2::Error HWCDisplayBuiltIn::Present(int32_t *out_retire_fence) {
   auto status = HWC2::Error::None;
 
@@ -310,6 +348,8 @@
       DLOGE("Flush failed. Error = %d", error);
     }
   } else {
+    CacheAvrStatus();
+
     status = CommitStitchLayers();
     if (status != HWC2::Error::None) {
       DLOGE("Stitch failed: %d", status);
diff --git a/composer/hwc_display_builtin.h b/composer/hwc_display_builtin.h
index b1c0421..b6b92ec 100644
--- a/composer/hwc_display_builtin.h
+++ b/composer/hwc_display_builtin.h
@@ -128,6 +128,8 @@
                                       int32_t dataspace, hwc_region_t damage);
   virtual bool IsSmartPanelConfig(uint32_t config_id);
   virtual int Deinit();
+  virtual bool IsQsyncCallbackNeeded(bool *qsync_enabled, int32_t *refresh_rate,
+                                     int32_t *qsync_refresh_rate);
 
  private:
   HWCDisplayBuiltIn(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
@@ -152,6 +154,7 @@
   bool InitLayerStitch();
   void InitStitchTarget();
   bool AllocateStitchBuffer();
+  void CacheAvrStatus();
 
   // SyncTask methods.
   void OnTask(const LayerStitchTaskCode &task_code,
@@ -184,6 +187,9 @@
   GLLayerStitch* gl_layer_stitch_ = nullptr;
   BufferInfo buffer_info_ = {};
   DisplayConfigVariableInfo fb_config_ = {};
+
+  bool qsync_enabled_ = false;
+  bool qsync_reconfigured_ = false;
 };
 
 }  // namespace sdm
diff --git a/composer/hwc_session.cpp b/composer/hwc_session.cpp
index 9b71448..786e359 100644
--- a/composer/hwc_session.cpp
+++ b/composer/hwc_session.cpp
@@ -676,6 +676,19 @@
                              out_fences);
 }
 
+void HWCSession::PerformQsyncCallback(hwc2_display_t display) {
+  if (qsync_callback_ == nullptr) {
+    return;
+  }
+
+  bool qsync_enabled = 0;
+  int32_t refresh_rate = 0, qsync_refresh_rate = 0;
+  if (hwc_display_[display]->IsQsyncCallbackNeeded(&qsync_enabled,
+      &refresh_rate, &qsync_refresh_rate)) {
+    qsync_callback_->onQsyncReconfigured(qsync_enabled, refresh_rate, qsync_refresh_rate);
+  }
+}
+
 int32_t HWCSession::PresentDisplay(hwc2_display_t display, int32_t *out_retire_fence) {
   auto status = HWC2::Error::BadDisplay;
   DTRACE_SCOPED();
@@ -720,6 +733,9 @@
           callbacks_.ResetRefresh(display);
         }
         status = hwc_display_[target_display]->Present(out_retire_fence);
+        if (status == HWC2::Error::None) {
+          PerformQsyncCallback(target_display);
+        }
       }
     }
   }
diff --git a/composer/hwc_session.h b/composer/hwc_session.h
index 0bfa281..dabd9b9 100644
--- a/composer/hwc_session.h
+++ b/composer/hwc_session.h
@@ -20,7 +20,7 @@
 #ifndef __HWC_SESSION_H__
 #define __HWC_SESSION_H__
 
-#include <vendor/display/config/1.14/IDisplayConfig.h>
+#include <vendor/display/config/1.15/IDisplayConfig.h>
 #include <vendor/qti/hardware/display/composer/2.0/IQtiComposerClient.h>
 
 #include <core/core_interface.h>
@@ -49,8 +49,9 @@
 
 namespace sdm {
 
-using vendor::display::config::V1_14::IDisplayConfig;
+using vendor::display::config::V1_15::IDisplayConfig;
 using vendor::display::config::V1_10::IDisplayCWBCallback;
+using vendor::display::config::V1_15::IDisplayQsyncCallback;
 
 using ::android::hardware::Return;
 using ::android::hardware::hidl_string;
@@ -411,6 +412,7 @@
   Return<int32_t> setQsyncMode(uint32_t disp_id, IDisplayConfig::QsyncMode mode) override;
   Return<bool> isSmartPanelConfig(uint32_t disp_id, uint32_t config_id) override;
   Return<bool> isRotatorSupportedFormat(int hal_format, bool ubwc) override;
+  Return<int32_t> registerQsyncCallback(const sp<IDisplayQsyncCallback> &callback) override;
 
   // QClient methods
   virtual android::status_t notifyCallback(uint32_t command, const android::Parcel *input_parcel,
@@ -460,6 +462,7 @@
   void HandlePendingRefresh();
   void NotifyClientStatus(bool connected);
   int32_t GetVirtualDisplayId();
+  void PerformQsyncCallback(hwc2_display_t display);
 
   CoreInterface *core_intf_ = nullptr;
   HWCDisplay *hwc_display_[HWCCallbacks::kNumDisplays] = {nullptr};
@@ -501,6 +504,7 @@
   float set_min_lum_ = -1.0;
   std::bitset<HWCCallbacks::kNumDisplays> pending_refresh_;
   CWB cwb_;
+  android::sp<IDisplayQsyncCallback> qsync_callback_ = nullptr;
   bool async_powermode_ = false;
   bool async_vds_creation_ = false;
   bool power_state_transition_[HWCCallbacks::kNumDisplays] = {};
diff --git a/composer/hwc_session_services.cpp b/composer/hwc_session_services.cpp
index a9c340a..f538760 100644
--- a/composer/hwc_session_services.cpp
+++ b/composer/hwc_session_services.cpp
@@ -1117,6 +1117,16 @@
   return 0;
 }
 
+Return<int32_t> HWCSession::registerQsyncCallback(const sp<IDisplayQsyncCallback> &callback) {
+  if (qsync_callback_ != nullptr) {
+    DLOGE("Qsync callback already registered, rejecting new request");
+    return -1;
+  }
+  qsync_callback_ = callback;
+
+  return 0;
+}
+
 Return<bool> HWCSession::isAsyncVDSCreationSupported() {
   if (!async_vds_creation_) {
     return false;
diff --git a/composer/vendor.qti.hardware.display.composer-service.xml b/composer/vendor.qti.hardware.display.composer-service.xml
index 0d4ef00..4c8f5cd 100644
--- a/composer/vendor.qti.hardware.display.composer-service.xml
+++ b/composer/vendor.qti.hardware.display.composer-service.xml
@@ -48,7 +48,7 @@
     <hal format="hidl">
         <name>vendor.display.config</name>
         <transport>hwbinder</transport>
-        <version>1.14</version>
+        <version>1.15</version>
         <interface>
             <name>IDisplayConfig</name>
             <instance>default</instance>
diff --git a/config/display-product.mk b/config/display-product.mk
index 761272a..08cf9a2 100644
--- a/config/display-product.mk
+++ b/config/display-product.mk
@@ -30,6 +30,7 @@
     vendor.display.config@1.12.vendor \
     vendor.display.config@1.13.vendor \
     vendor.display.config@1.14.vendor \
+    vendor.display.config@1.15.vendor \
     vendor.qti.hardware.display.mapper@2.0.vendor \
     vendor.qti.hardware.display.mapper@3.0.vendor \
     modetest
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index db9d961..ed2aedf 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -916,6 +916,12 @@
   */
   virtual bool GameEnhanceSupported() = 0;
 
+  /*! @brief Method to get the current qsync mode used.
+
+    @return \link DisplayError \endlink
+  */
+  virtual DisplayError GetQSyncMode(QSyncMode *qsync_mode) = 0;
+
  protected:
   virtual ~DisplayInterface() { }
 };
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 77a2539..6b5ceeb 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -161,6 +161,7 @@
   virtual DisplayError SetBLScale(uint32_t level) { return kErrorNotSupported; }
   virtual bool CheckResourceState();
   virtual bool GameEnhanceSupported();
+  virtual DisplayError GetQSyncMode(QSyncMode *qsync_mode) { return kErrorNotSupported; }
 
  protected:
   const char *kBt2020Pq = "bt2020_pq";
diff --git a/sdm/libs/core/display_builtin.cpp b/sdm/libs/core/display_builtin.cpp
index 7c0fd4e..8d0e1bd 100644
--- a/sdm/libs/core/display_builtin.cpp
+++ b/sdm/libs/core/display_builtin.cpp
@@ -784,6 +784,11 @@
   return kErrorNone;
 }
 
+DisplayError DisplayBuiltIn::GetQSyncMode(QSyncMode *qsync_mode) {
+  *qsync_mode = qsync_mode_;
+  return kErrorNone;
+}
+
 DisplayError DisplayBuiltIn::SetQSyncMode(QSyncMode qsync_mode) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
   if (!hw_panel_info_.qsync_support || qsync_mode_ == qsync_mode || first_cycle_) {
diff --git a/sdm/libs/core/display_builtin.h b/sdm/libs/core/display_builtin.h
index ee55bb4..233f6a0 100644
--- a/sdm/libs/core/display_builtin.h
+++ b/sdm/libs/core/display_builtin.h
@@ -85,6 +85,7 @@
   virtual DisplayError GetSupportedDSIClock(std::vector<uint64_t> *bitclk_rates);
   virtual DisplayError SetFrameTriggerMode(FrameTriggerMode mode);
   virtual DisplayError SetBLScale(uint32_t level);
+  virtual DisplayError GetQSyncMode(QSyncMode *qsync_mode);
 
   // Implement the HWEventHandlers
   virtual DisplayError VSync(int64_t timestamp);