drm_hwcomposer: Avoid resetting vsync timestamp

last_timestamp_ tracks the most recent timestamp from a vblank event. Do
not reset it when toggling vsync tracking on/off. This allows for
GetPhasedVSync to calculate a more precise approximation of the next
vsync relative to the current time, even if a vsync hasn't happened for
a while.

Reset last_timestamp_ when the vsync period changes, since the phased
vsync calculation is based on the current vsync.

Also change last_timestamp_ to std::optional type.

Change-Id: I101b36f87d6ba8197c321c83ac0bc230fba9cf7e
Signed-off-by: Drew Davenport <ddavenport@google.com>
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index 5234f6b..5b3071d 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -55,7 +55,6 @@
   {
     const std::lock_guard<std::mutex> lock(mutex_);
     enabled_ = ShouldEnable();
-    last_timestamp_ = -1;
   }
 
   cv_.notify_all();
@@ -64,6 +63,7 @@
 void VSyncWorker::SetVsyncPeriodNs(uint32_t vsync_period_ns) {
   const std::lock_guard<std::mutex> lock(mutex_);
   vsync_period_ns_ = vsync_period_ns;
+  last_timestamp_ = std::nullopt;
 }
 
 void VSyncWorker::SetVsyncTimestampTracking(bool enabled) {
@@ -121,11 +121,11 @@
  *  timestamp.
  */
 int64_t VSyncWorker::GetPhasedVSync(int64_t frame_ns, int64_t current) const {
-  if (last_timestamp_ < 0)
+  if (!last_timestamp_.has_value())
     return current + frame_ns;
 
-  return (frame_ns * ((current - last_timestamp_) / frame_ns + 1)) +
-         last_timestamp_;
+  return (frame_ns * ((current - *last_timestamp_) / frame_ns + 1)) +
+         *last_timestamp_;
 }
 
 static const int64_t kOneSecondNs = 1LL * 1000 * 1000 * 1000;
diff --git a/drm/VSyncWorker.h b/drm/VSyncWorker.h
index 5b97328..784f85d 100644
--- a/drm/VSyncWorker.h
+++ b/drm/VSyncWorker.h
@@ -37,7 +37,8 @@
   auto static CreateInstance(std::shared_ptr<DrmDisplayPipeline> &pipe)
       -> std::unique_ptr<VSyncWorker>;
 
-  // Set the expected vsync period.
+  // Set the expected vsync period. Resets internal timestamp tracking until the
+  // next vsync event is tracked.
   void SetVsyncPeriodNs(uint32_t vsync_period_ns);
 
   // Set or clear a callback to be fired on vsync.
@@ -68,7 +69,7 @@
 
   bool enabled_ GUARDED_BY(mutex_) = false;
   bool thread_exit_ GUARDED_BY(mutex_) = false;
-  int64_t last_timestamp_ GUARDED_BY(mutex_) = -1;
+  std::optional<int64_t> last_timestamp_ GUARDED_BY(mutex_);
 
   // Default to 60Hz refresh rate
   static constexpr uint32_t kDefaultVSPeriodNs = 16666666;
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 121f04f..977ab1a 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -822,7 +822,6 @@
   }
 
   if (new_vsync_period_ns) {
-    vsync_worker_->SetVsyncPeriodNs(new_vsync_period_ns.value());
     staged_mode_config_id_.reset();
 
     vsync_worker_->SetVsyncTimestampTracking(false);
@@ -832,6 +831,7 @@
                                                       last_vsync_ts +
                                                           prev_vperiod_ns);
     }
+    vsync_worker_->SetVsyncPeriodNs(new_vsync_period_ns.value());
   }
 
   return HWC2::Error::None;