Merge "sdm: add support to idle timer optimization for DemuraTn"
diff --git a/composer/hwc_session.cpp b/composer/hwc_session.cpp
index a5b1c1b..330cc49 100644
--- a/composer/hwc_session.cpp
+++ b/composer/hwc_session.cpp
@@ -4193,6 +4193,14 @@
 
 int HWCSession::WaitForCommitDoneAsync(hwc2_display_t display, int client_id) {
   std::chrono::milliseconds span(5000);
+  if (commit_done_future_.valid()) {
+    std::future_status status = commit_done_future_.wait_for(std::chrono::milliseconds(0));
+    if (status != std::future_status::ready) {
+      // Previous task is stuck. Bail out early.
+      return -ETIMEDOUT;
+    }
+  }
+
   commit_done_future_ = std::async([](HWCSession* session, hwc2_display_t display, int client_id) {
                                       return session->WaitForCommitDone(display, client_id);
                                      }, this, display, client_id);
diff --git a/sdm/include/core/layer_buffer.h b/sdm/include/core/layer_buffer.h
index ab94535..ac7a6eb 100644
--- a/sdm/include/core/layer_buffer.h
+++ b/sdm/include/core/layer_buffer.h
@@ -370,6 +370,9 @@
   LayerRect cwb_full_rect = {};                      //!< Same as Output buffer Rect (unaligned).
   CwbTapPoint tap_point = CwbTapPoint::kLmTapPoint;  //!< Client specified tap point for CWB.
   void *dither_info = nullptr;                       //!< Pointer to the cwb dither setting.
+  bool avoid_refresh = false;                        //!< Whether to avoid additional refresh for
+                                                     //!< CWB Request, by default refresh occurs
+                                                     //!< for each CWB request to process it.
 };
 
 class LayerBufferObject {
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index ee063c0..2161fed 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -4245,6 +4245,49 @@
   event_handler_->Refresh();
 }
 
+DisplayError DisplayBase::ValidateCwbRoiWithOutputBuffer(const LayerBuffer &output_buffer,
+                                                         CwbConfig &cwb_config) {
+  if (cwb_config.pu_as_cwb_roi) {
+    uint32_t full_frame_width = cwb_config.cwb_full_rect.right - cwb_config.cwb_full_rect.left;
+    uint32_t full_frame_height = cwb_config.cwb_full_rect.bottom - cwb_config.cwb_full_rect.top;
+    if (full_frame_width > output_buffer.width || full_frame_height > output_buffer.height) {
+      // If output buffer is less than full frame when PU as CWB ROI is enabled, then it
+      // may possible in later validation for partial update that it may fallback to full frame
+      // ROI and then it will cause commit failure due to falling of PU ROI out of CWB ROI
+      // bounds. So, to avoid such case, just disable pu_as_cwb_roi to fallback to full
+      // frame update instead of partial update.
+      cwb_config.pu_as_cwb_roi = false;
+    }
+  }
+
+  if (!cwb_config.pu_as_cwb_roi && !IsValid(cwb_config.cwb_roi)) {
+    // Fall to full frame ROI for invalid CWB ROI, when pu_as_cwb_roi is disabled.
+    cwb_config.cwb_roi = cwb_config.cwb_full_rect;
+  }
+
+  // If CWB ROI doesn't fit into provided output buffer, then it limits the right and bottom
+  // bounds of CWB ROI as per provided output buffer to avoid commit failure due to insufficient
+  // buffer detection for CWB ROI.
+  int32_t roi_width = cwb_config.cwb_roi.right - cwb_config.cwb_roi.left;
+  int32_t roi_height = cwb_config.cwb_roi.bottom - cwb_config.cwb_roi.top;
+  if (roi_width > output_buffer.width || roi_height > output_buffer.height) {
+    DLOGW("Insufficient buffer(%dx%d) provided for cwb roi(%f, %f, %f, %f). "
+          "Thus, falling to buffer fit ROI.", output_buffer.width,
+          output_buffer.height, cwb_config.cwb_roi.left, cwb_config.cwb_roi.top,
+          cwb_config.cwb_roi.right, cwb_config.cwb_roi.bottom);
+
+    if (roi_width > output_buffer.width) {
+      cwb_config.cwb_roi.right = FLOAT(output_buffer.width) + cwb_config.cwb_roi.left;
+    }
+
+    if (roi_height > output_buffer.height) {
+      cwb_config.cwb_roi.bottom = FLOAT(output_buffer.height) + cwb_config.cwb_roi.top;
+    }
+  }
+
+  return kErrorNone;
+}
+
 DisplayError DisplayBase::CaptureCwb(const LayerBuffer &output_buffer, const CwbConfig &config) {
   ClientLock lock(disp_mutex_);
 
@@ -4281,6 +4324,12 @@
     return error;
   }
 
+  error = ValidateCwbRoiWithOutputBuffer(output_buffer, cwb_config);
+  if (error != kErrorNone) {
+    DLOGW("Buffer validation failed");
+    return error;
+  }
+
   error = comp_manager_->CaptureCwb(display_comp_ctx_, output_buffer, cwb_config);
   if (error != kErrorNone) {
     DLOGE("CWB config failed");
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 13d7c35..3b54419 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -174,6 +174,8 @@
                                               LayerBufferFormat format,
                                               const ColorMetaData &color_metadata);
   virtual DisplayError HandleSecureEvent(SecureEvent secure_event, bool *needs_refresh);
+  virtual DisplayError ValidateCwbRoiWithOutputBuffer(const LayerBuffer &output_buffer,
+                                                      CwbConfig &cwb_config);
   virtual DisplayError CaptureCwb(const LayerBuffer &output_buffer, const CwbConfig &config);
   virtual DisplayError PostHandleSecureEvent(SecureEvent secure_event) {
     return kErrorNotSupported;
diff --git a/sdm/libs/core/display_builtin.cpp b/sdm/libs/core/display_builtin.cpp
index c10e23a..3a8d6ee 100644
--- a/sdm/libs/core/display_builtin.cpp
+++ b/sdm/libs/core/display_builtin.cpp
@@ -254,6 +254,8 @@
         DLOGE("Unable to DeInit DemuraTn on Display %d", display_id_);
       }
     }
+
+    DeinitCWBBuffer();
   }
   return DisplayBase::Deinit();
 }
@@ -2703,38 +2705,37 @@
     return;
   }
 
-  if (disable_cwb_idle_fallback_) {
+  if (disable_cwb_idle_fallback_ || cwb_buffer_initialized_) {
     return;
   }
 
-  BufferInfo output_buffer_info;
   // Initialize CWB buffer with display resolution to get full size buffer
   // as mixer or fb can init with custom values based on property
-  output_buffer_info.buffer_config.width = display_attributes_.x_pixels;
-  output_buffer_info.buffer_config.height = display_attributes_.y_pixels;
+  output_buffer_info_.buffer_config.width = display_attributes_.x_pixels;
+  output_buffer_info_.buffer_config.height = display_attributes_.y_pixels;
 
-  output_buffer_info.buffer_config.format = kFormatRGBX8888Ubwc;
-  output_buffer_info.buffer_config.buffer_count = 1;
-  if (buffer_allocator_->AllocateBuffer(&output_buffer_info) != 0) {
+  output_buffer_info_.buffer_config.format = kFormatRGBX8888Ubwc;
+  output_buffer_info_.buffer_config.buffer_count = 1;
+  if (buffer_allocator_->AllocateBuffer(&output_buffer_info_) != 0) {
     DLOGE("Buffer allocation failed");
     return;
   }
 
   LayerBuffer buffer = {};
-  buffer.planes[0].fd = output_buffer_info.alloc_buffer_info.fd;
+  buffer.planes[0].fd = output_buffer_info_.alloc_buffer_info.fd;
   buffer.planes[0].offset = 0;
-  buffer.planes[0].stride = output_buffer_info.alloc_buffer_info.stride;
-  buffer.size = output_buffer_info.alloc_buffer_info.size;
-  buffer.handle_id = output_buffer_info.alloc_buffer_info.id;
-  buffer.width = output_buffer_info.alloc_buffer_info.aligned_width;
-  buffer.height = output_buffer_info.alloc_buffer_info.aligned_height;
-  buffer.format = output_buffer_info.alloc_buffer_info.format;
-  buffer.unaligned_width = output_buffer_info.buffer_config.width;
-  buffer.unaligned_height = output_buffer_info.buffer_config.height;
+  buffer.planes[0].stride = output_buffer_info_.alloc_buffer_info.stride;
+  buffer.size = output_buffer_info_.alloc_buffer_info.size;
+  buffer.handle_id = output_buffer_info_.alloc_buffer_info.id;
+  buffer.width = output_buffer_info_.alloc_buffer_info.aligned_width;
+  buffer.height = output_buffer_info_.alloc_buffer_info.aligned_height;
+  buffer.format = output_buffer_info_.alloc_buffer_info.format;
+  buffer.unaligned_width = output_buffer_info_.buffer_config.width;
+  buffer.unaligned_height = output_buffer_info_.buffer_config.height;
 
   cwb_layer_.composition = kCompositionCWBTarget;
   cwb_layer_.input_buffer = buffer;
-  cwb_layer_.input_buffer.buffer_id = reinterpret_cast<uint64_t>(output_buffer_info.private_data);
+  cwb_layer_.input_buffer.buffer_id = reinterpret_cast<uint64_t>(output_buffer_info_.private_data);
   cwb_layer_.src_rect = {0, 0, FLOAT(cwb_layer_.input_buffer.unaligned_width),
                          FLOAT(cwb_layer_.input_buffer.unaligned_height)};
   cwb_layer_.dst_rect = {0, 0, FLOAT(cwb_layer_.input_buffer.unaligned_width),
@@ -2745,7 +2746,26 @@
   return;
 }
 
+void DisplayBuiltIn::DeinitCWBBuffer() {
+  if (!cwb_buffer_initialized_) {
+    return;
+  }
+
+  buffer_allocator_->FreeBuffer(&output_buffer_info_);
+  cwb_layer_ = {};
+  cwb_buffer_initialized_ = false;
+}
+
 void DisplayBuiltIn::AppendCWBLayer(LayerStack *layer_stack) {
+  if (cwb_buffer_initialized_ &&
+      (cwb_layer_.input_buffer.unaligned_width < display_attributes_.x_pixels ||
+      cwb_layer_.input_buffer.unaligned_height < display_attributes_.y_pixels)) {
+    DLOGI("Resetting CWB layer due to insufficient buffer size(%dx%d) compare to output(%dx%d).",
+          cwb_layer_.input_buffer.unaligned_width, cwb_layer_.input_buffer.unaligned_height,
+          display_attributes_.x_pixels, display_attributes_.y_pixels);
+    DeinitCWBBuffer();
+  }
+
   if (!cwb_buffer_initialized_) {
     // If CWB buffer is not initialized, then it must be initialized for video mode
     InitCWBBuffer();
diff --git a/sdm/libs/core/display_builtin.h b/sdm/libs/core/display_builtin.h
index e172547..d4c7e88 100644
--- a/sdm/libs/core/display_builtin.h
+++ b/sdm/libs/core/display_builtin.h
@@ -182,6 +182,7 @@
   DisplayError SetAlternateDisplayConfig(uint32_t *alt_config) override;
   DisplayError PostHandleSecureEvent(SecureEvent secure_event) override;
   void InitCWBBuffer();
+  void DeinitCWBBuffer();
   void AppendCWBLayer(LayerStack *layer_stack);
   uint32_t GetUpdatingAppLayersCount(LayerStack *layer_stack);
   DisplayError ChangeFps();
@@ -307,6 +308,7 @@
   Layer cwb_layer_ = {};
   bool lower_fps_ = false;
   bool cwb_buffer_initialized_ = false;
+  BufferInfo output_buffer_info_ = {};
 };
 
 }  // namespace sdm