Merge "hwc2: Allow commit to go through if flush_ flag is set"
diff --git a/gralloc/QtiMapper.cpp b/gralloc/QtiMapper.cpp
index 3848878..14c788e 100644
--- a/gralloc/QtiMapper.cpp
+++ b/gralloc/QtiMapper.cpp
@@ -52,7 +52,7 @@
 
 bool QtiMapper::ValidDescriptor(const BufferDescriptorInfo_2_1 &bd) {
   if (bd.width == 0 || bd.height == 0 || (static_cast<int32_t>(bd.format) <= 0) ||
-      bd.layerCount != 1) {
+      bd.layerCount <= 0) {
     return false;
   }
 
diff --git a/gralloc/gr_buf_mgr.cpp b/gralloc/gr_buf_mgr.cpp
index 3d4bfac..a569184 100644
--- a/gralloc/gr_buf_mgr.cpp
+++ b/gralloc/gr_buf_mgr.cpp
@@ -335,6 +335,7 @@
 }
 
 Error BufferManager::Dump(std::ostringstream *os) {
+  std::lock_guard<std::mutex> buffer_lock(buffer_lock_);
   for (auto it : handles_map_) {
     auto buf = it.second;
     auto hnd = buf->handle;
diff --git a/include/display_properties.h b/include/display_properties.h
index ddcde64..9af7ddd 100644
--- a/include/display_properties.h
+++ b/include/display_properties.h
@@ -107,6 +107,7 @@
 #define QDCM_DISABLE_TIMEOUT_PROP            PERSIST_DISPLAY_PROP("qdcm.disable_timeout")
 #define QDCM_MODE_COMBINE_PROP               DISPLAY_PROP("qdcm.mode_combine")
 #define PREFER_MULTIRECT_PROP                DISPLAY_PROP("prefer_multirect")
+#define DROP_SKEWED_VSYNC                    DISPLAY_PROP("drop_skewed_vsync");
 
 #define ZERO_SWAP_INTERVAL                   "vendor.debug.egl.swapinterval"
 
diff --git a/sdm/include/utils/locker.h b/sdm/include/utils/locker.h
index dabeb11..e0d91cb 100755
--- a/sdm/include/utils/locker.h
+++ b/sdm/include/utils/locker.h
@@ -127,15 +127,15 @@
 
   Locker() : sequence_wait_(0) {
     pthread_mutex_init(&mutex_, 0);
-    pthread_condattr_init(&cond_attr);
-    pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
-    pthread_cond_init(&condition_, &cond_attr);
+    pthread_condattr_init(&cond_attr_);
+    pthread_condattr_setclock(&cond_attr_, CLOCK_MONOTONIC);
+    pthread_cond_init(&condition_, &cond_attr_);
   }
 
   ~Locker() {
     pthread_mutex_destroy(&mutex_);
     pthread_cond_destroy(&condition_);
-    pthread_condattr_destroy(&cond_attr);
+    pthread_condattr_destroy(&cond_attr_);
   }
 
   void Lock() { pthread_mutex_lock(&mutex_); }
@@ -157,7 +157,7 @@
  private:
   pthread_mutex_t mutex_;
   pthread_cond_t condition_;
-  pthread_condattr_t cond_attr;
+  pthread_condattr_t cond_attr_;
   int sequence_wait_;   // This flag is set to 1 on sequence entry, 0 on exit, and -1 on cancel.
                         // Some routines will wait for sequence of function calls to finish
                         // so that capturing a transitionary snapshot of context is prevented.
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 6d54b4e..bd238a9 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -98,6 +98,7 @@
   int property_value = Debug::GetMaxPipesPerMixer(display_type_);
 
   uint32_t active_index = 0;
+  int drop_vsync = 0;
   hw_intf_->GetActiveConfig(&active_index);
   hw_intf_->GetDisplayAttributes(active_index, &display_attributes_);
   fb_config_ = display_attributes_;
@@ -168,6 +169,9 @@
   Debug::GetProperty(DISABLE_HW_RECOVERY_DUMP_PROP, &disable_hw_recovery_dump_);
   DLOGI("disable_hw_recovery_dump_ set to %d", disable_hw_recovery_dump_);
 
+  Debug::Get()->GetProperty("DROP_SKEWED_VSYNC", &drop_vsync);
+  drop_skewed_vsync_ = (drop_vsync == 1);
+
   return kErrorNone;
 
 CleanupOnError:
@@ -390,7 +394,10 @@
     return error;
   }
 
+  // Stop dropping vsync when first commit is received after idle fallback.
+  drop_hw_vsync_ = false;
   DLOGI_IF(kTagDisplay, "Exiting commit for display: %d-%d", display_id_, display_type_);
+
   return kErrorNone;
 }
 
@@ -1051,6 +1058,10 @@
   if (vsync_enable_ != enable) {
     error = hw_intf_->SetVSyncState(enable);
     if (error == kErrorNotSupported) {
+      if (drop_skewed_vsync_ && (hw_panel_info_.mode == kModeVideo) &&
+        enable && (current_refresh_rate_ == hw_panel_info_.min_fps)) {
+        drop_hw_vsync_ = true;
+      }
       error = hw_events_intf_->SetEventState(HWEvent::VSYNC, enable);
     }
     if (error == kErrorNone) {
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index e4efb92..27452f4 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -211,6 +211,9 @@
   bool hw_recovery_logs_captured_ = false;
   int disable_hw_recovery_dump_ = 0;
   HWQosData default_qos_data_;
+  bool drop_hw_vsync_ = false;
+  uint32_t current_refresh_rate_ = 0;
+  bool drop_skewed_vsync_ = false;
 
   static Locker display_power_reset_lock_;
   static bool display_power_reset_pending_;
diff --git a/sdm/libs/core/display_builtin.cpp b/sdm/libs/core/display_builtin.cpp
index e4882b8..3b5ca4b 100644
--- a/sdm/libs/core/display_builtin.cpp
+++ b/sdm/libs/core/display_builtin.cpp
@@ -311,7 +311,7 @@
 }
 
 DisplayError DisplayBuiltIn::VSync(int64_t timestamp) {
-  if (vsync_enable_) {
+  if (vsync_enable_ && !drop_hw_vsync_) {
     DisplayEventVSync vsync;
     vsync.timestamp = timestamp;
     event_handler_->VSync(vsync);
@@ -322,7 +322,9 @@
 
 void DisplayBuiltIn::IdleTimeout() {
   if (hw_panel_info_.mode == kModeVideo) {
-    event_handler_->HandleEvent(kIdleTimeout);
+    if (event_handler_->HandleEvent(kIdleTimeout) != kErrorNone) {
+      return;
+    }
     handle_idle_timeout_ = true;
     event_handler_->Refresh();
     lock_guard<recursive_mutex> obj(recursive_mutex_);
diff --git a/sdm/libs/core/display_builtin.h b/sdm/libs/core/display_builtin.h
index d4295fa..599a730 100644
--- a/sdm/libs/core/display_builtin.h
+++ b/sdm/libs/core/display_builtin.h
@@ -95,7 +95,6 @@
   bool avr_prop_disabled_ = false;
   bool switch_to_cmd_ = false;
   bool handle_idle_timeout_ = false;
-  uint32_t current_refresh_rate_ = 0;
   bool reset_panel_ = false;
   bool commit_event_enabled_ = false;
   DppsInfo dpps_info_ = {};
diff --git a/sdm/libs/core/strategy.cpp b/sdm/libs/core/strategy.cpp
index 1281545..5098b01 100644
--- a/sdm/libs/core/strategy.cpp
+++ b/sdm/libs/core/strategy.cpp
@@ -150,6 +150,11 @@
   Layer layer = *gpu_target_layer;
   hw_layers_info_->index.push_back(hw_layers_info_->gpu_target_index);
   hw_layers_info_->roi_index.push_back(0);
+  layer.transform.flip_horizontal ^= hw_panel_info_.panel_orientation.flip_horizontal;
+  layer.transform.flip_vertical ^= hw_panel_info_.panel_orientation.flip_vertical;
+  // Flip rect to match transform.
+  TransformHV(src_domain, layer.dst_rect, layer.transform, &layer.dst_rect);
+  // Scale to mixer resolution.
   MapRect(src_domain, dst_domain, layer.dst_rect, &layer.dst_rect);
   hw_layers_info_->hw_layers.push_back(layer);
 
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 6b722d6..f29bb93 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -554,6 +554,7 @@
       }
     }
 
+    bool is_secure = false;
     const private_handle_t *handle =
         reinterpret_cast<const private_handle_t *>(layer->input_buffer.buffer_id);
     if (handle) {
@@ -561,17 +562,16 @@
         layer_stack_.flags.video_present = true;
       }
       // TZ Protected Buffer - L1
-      if (handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
-        layer_stack_.flags.secure_present = true;
-      }
       // Gralloc Usage Protected Buffer - L3 - which needs to be treated as Secure & avoid fallback
-      if (handle->flags & private_handle_t::PRIV_FLAGS_PROTECTED_BUFFER) {
+      if (handle->flags & private_handle_t::PRIV_FLAGS_PROTECTED_BUFFER ||
+          handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
         layer_stack_.flags.secure_present = true;
+        is_secure = true;
       }
     }
 
-    if (layer->flags.skip) {
-      layer_stack_.flags.skip_present = true;
+    if (layer->input_buffer.flags.secure_display) {
+      is_secure = true;
     }
 
     if (hwc_layer->IsSingleBuffered() &&
@@ -601,6 +601,14 @@
       layer_stack_.flags.hdr_present = true;
     }
 
+    if (hwc_layer->IsNonIntegralSourceCrop() && !is_secure && !hdr_layer) {
+      layer->flags.skip = true;
+    }
+
+    if (layer->flags.skip) {
+      layer_stack_.flags.skip_present = true;
+    }
+
     // TODO(user): Move to a getter if this is needed at other places
     hwc_rect_t scaled_display_frame = {INT(layer->dst_rect.left), INT(layer->dst_rect.top),
                                        INT(layer->dst_rect.right), INT(layer->dst_rect.bottom)};
@@ -624,11 +632,10 @@
       layer->src_rect.bottom = layer_buffer->height;
     }
 
-    if (layer->frame_rate > metadata_refresh_rate_) {
+    if (hwc_layer->HasMetaDataRefreshRate() && layer->frame_rate > metadata_refresh_rate_) {
       metadata_refresh_rate_ = SanitizeRefreshRate(layer->frame_rate);
-    } else {
-      layer->frame_rate = current_refresh_rate_;
     }
+
     display_rect_ = Union(display_rect_, layer->dst_rect);
     geometry_changes_ |= hwc_layer->GetGeometryChanges();
 
@@ -1080,7 +1087,17 @@
 
 DisplayError HWCDisplay::HandleEvent(DisplayEvent event) {
   switch (event) {
-    case kIdleTimeout:
+    case kIdleTimeout: {
+      SCOPE_LOCK(HWCSession::locker_[type_]);
+      if (pending_commit_) {
+        // If idle timeout event comes in between prepare
+        // and commit, drop it since device is not really
+        // idle.
+        return kErrorNotSupported;
+      }
+      validated_ = false;
+      break;
+    }
     case kThermalEvent:
     case kIdlePowerCollapse:
     case kPanelDeadEvent: {
@@ -1118,6 +1135,7 @@
     return ((*out_num_types > 0) ? HWC2::Error::HasChanges : HWC2::Error::None);
   }
 
+  UpdateRefreshRate();
   DisplayError error = display_intf_->Prepare(&layer_stack_);
   if (error != kErrorNone) {
     if (error == kErrorShutDown) {
@@ -1306,6 +1324,10 @@
 
 
 HWC2::Error HWCDisplay::CommitLayerStack(void) {
+  if (flush_) {
+    return HWC2::Error::None;
+  }
+
   if (!validated_) {
     DLOGV_IF(kTagClient, "Display %d is not validated", id_);
     return HWC2::Error::NotValidated;
@@ -1317,37 +1339,35 @@
 
   DumpInputBuffers();
 
-  if (!flush_) {
-    DisplayError error = kErrorUndefined;
-    int status = 0;
-    if (tone_mapper_) {
-      if (NeedsToneMap(layer_stack_)) {
-        status = tone_mapper_->HandleToneMap(&layer_stack_);
-        if (status != 0) {
-          DLOGE("Error handling HDR in ToneMapper");
-        }
-      } else {
-        tone_mapper_->Terminate();
+  DisplayError error = kErrorUndefined;
+  int status = 0;
+  if (tone_mapper_) {
+    if (NeedsToneMap(layer_stack_)) {
+      status = tone_mapper_->HandleToneMap(&layer_stack_);
+      if (status != 0) {
+        DLOGE("Error handling HDR in ToneMapper");
       }
-    }
-    error = display_intf_->Commit(&layer_stack_);
-
-    if (error == kErrorNone) {
-      // A commit is successfully submitted, start flushing on failure now onwards.
-      flush_on_error_ = true;
     } else {
-      if (error == kErrorShutDown) {
-        shutdown_pending_ = true;
-        return HWC2::Error::Unsupported;
-      } else if (error == kErrorNotValidated) {
-        validated_ = false;
-        return HWC2::Error::NotValidated;
-      } else if (error != kErrorPermission) {
-        DLOGE("Commit failed. Error = %d", error);
-        // To prevent surfaceflinger infinite wait, flush the previous frame during Commit()
-        // so that previous buffer and fences are released, and override the error.
-        flush_ = true;
-      }
+      tone_mapper_->Terminate();
+    }
+  }
+  error = display_intf_->Commit(&layer_stack_);
+
+  if (error == kErrorNone) {
+    // A commit is successfully submitted, start flushing on failure now onwards.
+    flush_on_error_ = true;
+  } else {
+    if (error == kErrorShutDown) {
+      shutdown_pending_ = true;
+      return HWC2::Error::Unsupported;
+    } else if (error == kErrorNotValidated) {
+      validated_ = false;
+      return HWC2::Error::NotValidated;
+    } else if (error != kErrorPermission) {
+      DLOGE("Commit failed. Error = %d", error);
+      // To prevent surfaceflinger infinite wait, flush the previous frame during Commit()
+      // so that previous buffer and fences are released, and override the error.
+      flush_ = true;
     }
   }
 
@@ -2138,4 +2158,14 @@
   return skip_prepare;
 }
 
+void HWCDisplay::UpdateRefreshRate() {
+  for (auto hwc_layer : layer_set_) {
+    if (hwc_layer->HasMetaDataRefreshRate()) {
+      continue;
+    }
+    auto layer = hwc_layer->GetSDMLayer();
+    layer->frame_rate = current_refresh_rate_;
+  }
+}
+
 }  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 61e897e..27bed47 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -361,11 +361,12 @@
   int disable_hdr_handling_ = 0;  // disables HDR handling.
   uint32_t display_config_ = 0;
   bool config_pending_ = false;
+  bool pending_commit_ = false;
 
  private:
   void DumpInputBuffers(void);
   bool CanSkipSdmPrepare(uint32_t *num_types, uint32_t *num_requests);
-
+  void UpdateRefreshRate();
   qService::QService *qservice_ = NULL;
   DisplayClass display_class_;
   uint32_t geometry_changes_ = GeometryChanges::kNone;
diff --git a/sdm/libs/hwc2/hwc_display_builtin.cpp b/sdm/libs/hwc2/hwc_display_builtin.cpp
index 7d5b5e1..a11d13e 100644
--- a/sdm/libs/hwc2/hwc_display_builtin.cpp
+++ b/sdm/libs/hwc2/hwc_display_builtin.cpp
@@ -236,6 +236,7 @@
   }
 
   status = PrepareLayerStack(out_num_types, out_num_requests);
+  pending_commit_ = true;
   return status;
 }
 
@@ -257,6 +258,7 @@
   }
 
   CloseFd(&output_buffer_.acquire_fence_fd);
+  pending_commit_ = false;
   return status;
 }
 
diff --git a/sdm/libs/hwc2/hwc_display_pluggable.cpp b/sdm/libs/hwc2/hwc_display_pluggable.cpp
index 7d22642..d97c423 100644
--- a/sdm/libs/hwc2/hwc_display_pluggable.cpp
+++ b/sdm/libs/hwc2/hwc_display_pluggable.cpp
@@ -137,6 +137,7 @@
 
   if (layer_set_.empty()) {
     flush_ = true;
+    validated_ = true;
     return status;
   }
 
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index 13c3f8d..94f1a61 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -455,6 +455,10 @@
 HWC2::Error HWCLayer::SetLayerSourceCrop(hwc_frect_t crop) {
   LayerRect src_rect = {};
   SetRect(crop, &src_rect);
+  non_integral_source_crop_ = ((crop.left != roundf(crop.left)) ||
+                              (crop.top != roundf(crop.top)) ||
+                              (crop.right != roundf(crop.right)) ||
+                              (crop.bottom != roundf(crop.bottom)));
   if (layer_->src_rect != src_rect) {
     geometry_changes_ |= kSourceCrop;
     layer_->src_rect = src_rect;
@@ -801,13 +805,13 @@
   uint32_t frame_rate = layer->frame_rate;
   if (getMetaData(handle, GET_REFRESH_RATE, &fps) == 0) {
     frame_rate = (fps != 0) ? RoundToStandardFPS(fps) : layer->frame_rate;
+    has_metadata_refresh_rate_ = true;
   }
 
   int32_t interlaced = 0;
-  bool interlace = layer_buffer->flags.interlace;
-  if (getMetaData(handle, GET_PP_PARAM_INTERLACED, &interlaced) == 0) {
-    interlace = interlaced ? true : false;
-  }
+  getMetaData(handle, GET_PP_PARAM_INTERLACED, &interlaced);
+  bool interlace = interlaced ? true : false;
+
   if (interlace != layer_buffer->flags.interlace) {
     DLOGI("Layer buffer interlaced metadata has changed. old=%d, new=%d",
           layer_buffer->flags.interlace, interlace);
diff --git a/sdm/libs/hwc2/hwc_layers.h b/sdm/libs/hwc2/hwc_layers.h
index 46e83cb..b5d5eaa 100644
--- a/sdm/libs/hwc2/hwc_layers.h
+++ b/sdm/libs/hwc2/hwc_layers.h
@@ -109,6 +109,8 @@
   static LayerBufferFormat GetSDMFormat(const int32_t &source, const int flags);
   bool IsSurfaceUpdated() { return surface_updated_; }
   void SetPartialUpdate(bool enabled) { partial_update_enabled_ = enabled; }
+  bool IsNonIntegralSourceCrop() { return non_integral_source_crop_; }
+  bool HasMetaDataRefreshRate() { return has_metadata_refresh_rate_; }
 
  private:
   Layer *layer_ = nullptr;
@@ -127,6 +129,8 @@
   bool dataspace_supported_ = false;
   bool partial_update_enabled_ = false;
   bool surface_updated_ = true;
+  bool non_integral_source_crop_ = false;
+  bool has_metadata_refresh_rate_ = false;
 
   // Composition requested by client(SF)
   HWC2::Composition client_requested_ = HWC2::Composition::Device;