Merge "hwc2: Teardown CWB in Create Virtual Display"
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index 7ef2f6f..1b4d063 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -797,6 +797,11 @@
   */
   virtual bool IsSupportSsppTonemap() = 0;
 
+  /*! @brief Method to free concurrent writeback resoures for primary display.
+    @return \link DisplayError \endlink
+  */
+  virtual DisplayError TeardownConcurrentWriteback(void) = 0;
+
   /*
    * Returns a string consisting of a dump of SDM's display and layer related state
    * as programmed to driver
diff --git a/sdm/libs/core/display_builtin.cpp b/sdm/libs/core/display_builtin.cpp
index ab6ec16..c8496ac 100644
--- a/sdm/libs/core/display_builtin.cpp
+++ b/sdm/libs/core/display_builtin.cpp
@@ -275,6 +275,12 @@
   return error;
 }
 
+DisplayError DisplayBuiltIn::TeardownConcurrentWriteback(void) {
+  lock_guard<recursive_mutex> obj(recursive_mutex_);
+
+  return hw_intf_->TeardownConcurrentWriteback();
+}
+
 DisplayError DisplayBuiltIn::SetRefreshRate(uint32_t refresh_rate, bool final_rate) {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
 
diff --git a/sdm/libs/core/display_builtin.h b/sdm/libs/core/display_builtin.h
index ffebcb3..a399a67 100644
--- a/sdm/libs/core/display_builtin.h
+++ b/sdm/libs/core/display_builtin.h
@@ -88,6 +88,7 @@
   virtual void PingPongTimeout();
   virtual void PanelDead();
   virtual void HwRecovery(const HWRecoveryEvent sdm_event_code);
+  virtual DisplayError TeardownConcurrentWriteback(void);
 
   // Implement the DppsPropIntf
   virtual DisplayError DppsProcessOps(enum DppsOps op, void *payload, size_t size);
diff --git a/sdm/libs/core/display_pluggable.h b/sdm/libs/core/display_pluggable.h
index d15129c..7716da3 100644
--- a/sdm/libs/core/display_pluggable.h
+++ b/sdm/libs/core/display_pluggable.h
@@ -56,6 +56,7 @@
   virtual DisplayError SetColorTransform(const uint32_t length, const double *color_transform) {
     return kErrorNone;
   }
+  virtual DisplayError TeardownConcurrentWriteback(void) { return kErrorNotSupported; }
 
   // Implement the HWEventHandlers
   virtual DisplayError VSync(int64_t timestamp);
diff --git a/sdm/libs/core/display_virtual.h b/sdm/libs/core/display_virtual.h
index e3daec6..1a672e1 100644
--- a/sdm/libs/core/display_virtual.h
+++ b/sdm/libs/core/display_virtual.h
@@ -69,6 +69,7 @@
   virtual DisplayError SetColorTransform(const uint32_t length, const double *color_transform) {
     return kErrorNone;
   }
+  virtual DisplayError TeardownConcurrentWriteback(void) { return kErrorNotSupported; }
   virtual DisplayError GetColorModeCount(uint32_t *mode_count);
 };
 
diff --git a/sdm/libs/core/drm/hw_device_drm.h b/sdm/libs/core/drm/hw_device_drm.h
index f8ae241..5be5fad 100644
--- a/sdm/libs/core/drm/hw_device_drm.h
+++ b/sdm/libs/core/drm/hw_device_drm.h
@@ -113,6 +113,7 @@
   virtual void PopulateHWPanelInfo();
   virtual DisplayError SetDppsFeature(void *payload, size_t size) { return kErrorNotSupported; }
   virtual DisplayError GetDppsFeatureInfo(void *payload, size_t size) { return kErrorNotSupported; }
+  virtual DisplayError TeardownConcurrentWriteback(void) { return kErrorNotSupported; }
   virtual DisplayError HandleSecureEvent(SecureEvent secure_event, HWLayers *hw_layers) {
     return kErrorNotSupported;
   }
diff --git a/sdm/libs/core/drm/hw_peripheral_drm.cpp b/sdm/libs/core/drm/hw_peripheral_drm.cpp
index ecd0651..0bc95cd 100644
--- a/sdm/libs/core/drm/hw_peripheral_drm.cpp
+++ b/sdm/libs/core/drm/hw_peripheral_drm.cpp
@@ -334,6 +334,16 @@
   }
 }
 
+DisplayError HWPeripheralDRM::TeardownConcurrentWriteback(void) {
+  if (cwb_config_.enabled) {
+    drm_mgr_intf_->UnregisterDisplay(cwb_config_.token);
+    cwb_config_.enabled = false;
+    registry_.Clear();
+  }
+
+  return kErrorNone;
+}
+
 DisplayError HWPeripheralDRM::SetupConcurrentWritebackModes() {
   // To setup Concurrent Writeback topology, get the Connector ID of Virtual display
   if (drm_mgr_intf_->RegisterDisplay(DRMDisplayType::VIRTUAL, &cwb_config_.token)) {
@@ -402,9 +412,7 @@
   bool enabled = hw_resource_.has_concurrent_writeback && output_buffer;
 
   if (!enabled) {
-    drm_mgr_intf_->UnregisterDisplay(cwb_config_.token);
-    cwb_config_.enabled = false;
-    registry_.Clear();
+    TeardownConcurrentWriteback();
   }
 }
 
diff --git a/sdm/libs/core/drm/hw_peripheral_drm.h b/sdm/libs/core/drm/hw_peripheral_drm.h
index 12d2e6c..518657d 100644
--- a/sdm/libs/core/drm/hw_peripheral_drm.h
+++ b/sdm/libs/core/drm/hw_peripheral_drm.h
@@ -60,6 +60,7 @@
   virtual DisplayError SetDynamicDSIClock(uint64_t bit_clk_rate);
   virtual DisplayError GetDynamicDSIClock(uint64_t *bit_clk_rate);
   virtual DisplayError SetDisplayAttributes(uint32_t index);
+  virtual DisplayError TeardownConcurrentWriteback(void);
 
  private:
   void SetDestScalarData(HWLayersInfo hw_layer_info, bool validate);
diff --git a/sdm/libs/core/fb/hw_device.h b/sdm/libs/core/fb/hw_device.h
index dad5fe5..5f451dc 100644
--- a/sdm/libs/core/fb/hw_device.h
+++ b/sdm/libs/core/fb/hw_device.h
@@ -112,6 +112,7 @@
   virtual DisplayError SetDisplayDppsAdROI(void *payload) { return kErrorNotSupported; }
   virtual DisplayError SetDynamicDSIClock(uint64_t bit_clk_rate);
   virtual DisplayError GetDynamicDSIClock(uint64_t *bit_clk_rate);
+  virtual DisplayError TeardownConcurrentWriteback(void) { return kErrorNotSupported; }
 
   enum {
     kHWEventVSync,
diff --git a/sdm/libs/core/hw_interface.h b/sdm/libs/core/hw_interface.h
index 119a95f..240517a 100644
--- a/sdm/libs/core/hw_interface.h
+++ b/sdm/libs/core/hw_interface.h
@@ -123,6 +123,7 @@
   virtual DisplayError SetDisplayDppsAdROI(void *payload) = 0;
   virtual DisplayError SetDynamicDSIClock(uint64_t bit_clk_rate) = 0;
   virtual DisplayError GetDynamicDSIClock(uint64_t *bit_clk_rate) = 0;
+  virtual DisplayError TeardownConcurrentWriteback(void) = 0;
 
  protected:
   virtual ~HWInterface() { }
diff --git a/sdm/libs/hwc2/display_null.h b/sdm/libs/hwc2/display_null.h
index 29f31b0..2dcb9c9 100644
--- a/sdm/libs/hwc2/display_null.h
+++ b/sdm/libs/hwc2/display_null.h
@@ -58,6 +58,7 @@
   virtual std::string Dump() { return ""; }
   virtual bool IsSupportSsppTonemap() { return false; }
 
+  MAKE_NO_OP(TeardownConcurrentWriteback(void))
   MAKE_NO_OP(Commit(LayerStack *))
   MAKE_NO_OP(GetDisplayState(DisplayState *))
   MAKE_NO_OP(SetDisplayState(DisplayState, bool, int*))
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 455f41e..ed0696a 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -157,6 +157,9 @@
   virtual DisplayError GetMixerResolution(uint32_t *width, uint32_t *height);
   virtual void GetPanelResolution(uint32_t *width, uint32_t *height);
   virtual std::string Dump();
+  virtual DisplayError TeardownConcurrentWriteback(void) {
+    return kErrorNotSupported;
+  }
 
   // Captures frame output in the buffer specified by output_buffer_info. The API is
   // non-blocking and the client is expected to check operation status later on.
diff --git a/sdm/libs/hwc2/hwc_display_builtin.cpp b/sdm/libs/hwc2/hwc_display_builtin.cpp
index dbac21a..d565a9b 100644
--- a/sdm/libs/hwc2/hwc_display_builtin.cpp
+++ b/sdm/libs/hwc2/hwc_display_builtin.cpp
@@ -402,6 +402,28 @@
   return status;
 }
 
+DisplayError HWCDisplayBuiltIn::TeardownConcurrentWriteback(void) {
+  DisplayError error = kErrorNotSupported;
+
+  if (output_buffer_.release_fence_fd >= 0) {
+    int32_t release_fence_fd = dup(output_buffer_.release_fence_fd);
+    int ret = sync_wait(output_buffer_.release_fence_fd, 1000);
+    if (ret < 0) {
+      DLOGE("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
+    }
+
+    ::close(release_fence_fd);
+    if (ret)
+      return kErrorResources;
+  }
+
+  if (display_intf_) {
+    error = display_intf_->TeardownConcurrentWriteback();
+  }
+
+  return error;
+}
+
 HWC2::Error HWCDisplayBuiltIn::SetDisplayDppsAdROI(uint32_t h_start, uint32_t h_end,
                                                    uint32_t v_start, uint32_t v_end,
                                                    uint32_t factor_in, uint32_t factor_out) {
diff --git a/sdm/libs/hwc2/hwc_display_builtin.h b/sdm/libs/hwc2/hwc_display_builtin.h
index 682e54f..d4c81e2 100644
--- a/sdm/libs/hwc2/hwc_display_builtin.h
+++ b/sdm/libs/hwc2/hwc_display_builtin.h
@@ -87,6 +87,7 @@
   virtual DisplayError SetDynamicDSIClock(uint64_t bitclk);
   virtual DisplayError GetDynamicDSIClock(uint64_t *bitclk);
   virtual DisplayError GetSupportedDSIClock(std::vector<uint64_t> *bitclk_rates);
+  virtual DisplayError TeardownConcurrentWriteback(void);
 
  private:
   HWCDisplayBuiltIn(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 9c281e2..9c33e7b 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -1156,8 +1156,8 @@
     return HWC2::Error::NoResources;
   }
 
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
   if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
-    SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
     std::bitset<kSecureMax> secure_sessions = 0;
     hwc_display_[HWC_DISPLAY_PRIMARY]->GetActiveSecureSession(&secure_sessions);
     if (secure_sessions.any()) {
@@ -1195,6 +1195,13 @@
         continue;
       }
 
+    if (hwc_display_[HWC_DISPLAY_PRIMARY]) {
+      error = hwc_display_[HWC_DISPLAY_PRIMARY]->TeardownConcurrentWriteback();
+      if (error) {
+        return HWC2::Error::NoResources;
+      }
+    }
+
       status = HWCDisplayVirtual::Create(core_intf_, &buffer_allocator_, &callbacks_, client_id,
                                          info.display_id, width, height, format, &hwc_display);
       // TODO(user): validate width and height support
@@ -1209,11 +1216,10 @@
     }
 
     if (status) {
-      return HWC2::Error::BadDisplay;
+      return HWC2::Error::NoResources;
     }
   }
 
-  SEQUENCE_WAIT_SCOPE_LOCK(locker_[HWC_DISPLAY_PRIMARY]);
   hwc_display_[HWC_DISPLAY_PRIMARY]->ResetValidation();
 
   return HWC2::Error::None;