drm_hwcomposer: Deprecate usage of HWC2 setActiveConfig*

Setting a config is currently implemented by queuing a config change to
take effect at the next vsync. Add HwcDisplay::QueueConfig to support
this functionality, which is implemented using the HWC2
setActiveConfigWithConstraints and setActiveConfigInternal as a
reference.

Implement HWC3 setActiveConfig and setActiveConfigWithConstraints in
terms of HwcDisplay::QueueConfig.

Change-Id: I127f569fe889e7370de1987137345b5b75ff04b6
Signed-off-by: Drew Davenport <ddavenport@google.com>
diff --git a/compositor/DisplayInfo.h b/compositor/DisplayInfo.h
index bbcbff8..6ddc66f 100644
--- a/compositor/DisplayInfo.h
+++ b/compositor/DisplayInfo.h
@@ -46,3 +46,12 @@
   kModePanelOrientationLeftUp,
   kModePanelOrientationRightUp
 };
+
+struct QueuedConfigTiming {
+  // In order for the new config to be applied, the client must send a new frame
+  // at this time.
+  int64_t refresh_time_ns;
+
+  // The time when the display will start to refresh at the new vsync period.
+  int64_t new_vsync_time_ns;
+};
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index ec481e1..ffe6b11 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -96,7 +96,7 @@
   Deinit();
 };
 
-const HwcDisplayConfig *HwcDisplay::GetCurrentConfig() const {
+auto HwcDisplay::GetCurrentConfig() const -> const HwcDisplayConfig * {
   auto config_iter = configs_.hwc_configs.find(configs_.active_config_id);
   if (config_iter == configs_.hwc_configs.end()) {
     return nullptr;
@@ -104,7 +104,7 @@
   return &config_iter->second;
 }
 
-const HwcDisplayConfig *HwcDisplay::GetLastRequestedConfig() const {
+auto HwcDisplay::GetLastRequestedConfig() const -> const HwcDisplayConfig * {
   auto config_iter = configs_.hwc_configs.find(staged_mode_config_id_);
   if (config_iter == configs_.hwc_configs.end()) {
     return nullptr;
@@ -112,6 +112,42 @@
   return &config_iter->second;
 }
 
+auto HwcDisplay::QueueConfig(hwc2_config_t config, int64_t desired_time,
+                             bool seamless, QueuedConfigTiming *out_timing)
+    -> ConfigError {
+  if (configs_.hwc_configs.count(config) == 0) {
+    ALOGE("Could not find active mode for %u", config);
+    return ConfigError::kBadConfig;
+  }
+
+  // TODO: Add support for seamless configuration changes.
+  if (seamless) {
+    return ConfigError::kSeamlessNotAllowed;
+  }
+
+  // Request a refresh from the client one vsync period before the desired
+  // time, or simply at the desired time if there is no active configuration.
+  const HwcDisplayConfig *current_config = GetCurrentConfig();
+  out_timing->refresh_time_ns = desired_time -
+                                (current_config
+                                     ? current_config->mode.GetVSyncPeriodNs()
+                                     : 0);
+  out_timing->new_vsync_time_ns = desired_time;
+
+  // Queue the config change timing to be consistent with the requested
+  // refresh time.
+  staged_mode_ = configs_.hwc_configs[config].mode;
+  staged_mode_change_time_ = out_timing->refresh_time_ns;
+  staged_mode_config_id_ = config;
+
+  // Enable vsync events until the mode has been applied.
+  last_vsync_ts_ = 0;
+  vsync_tracking_en_ = true;
+  vsync_worker_->VSyncControl(true);
+
+  return ConfigError::kNone;
+}
+
 void HwcDisplay::SetPipeline(std::shared_ptr<DrmDisplayPipeline> pipeline) {
   Deinit();
 
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index a315540..91e5df7 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -41,6 +41,13 @@
 // NOLINTNEXTLINE
 class HwcDisplay {
  public:
+  enum ConfigError {
+    kNone,
+    kBadConfig,
+    kSeamlessNotAllowed,
+    kSeamlessNotPossible
+  };
+
   HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwc *hwc);
   HwcDisplay(const HwcDisplay &) = delete;
   ~HwcDisplay();
@@ -60,12 +67,16 @@
   }
 
   // Get the config representing the mode that has been committed to KMS.
-  const HwcDisplayConfig *GetCurrentConfig() const;
+  auto GetCurrentConfig() const -> const HwcDisplayConfig *;
 
   // Get the config that was last requested through SetActiveConfig and similar
   // functions. This may differ from the GetCurrentConfig if the config change
   // is queued up to take effect in the future.
-  const HwcDisplayConfig *GetLastRequestedConfig() const;
+  auto GetLastRequestedConfig() const -> const HwcDisplayConfig *;
+
+  // Queue a configuration change to take effect in the future.
+  auto QueueConfig(hwc2_config_t config, int64_t desired_time, bool seamless,
+                   QueuedConfigTiming *out_timing) -> ConfigError;
 
   // HWC2 Hooks - these should not be used outside of the hwc2 device.
   HWC2::Error AcceptDisplayChanges();
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
index e2d5b21..fe520ed 100644
--- a/hwc3/ComposerClient.cpp
+++ b/hwc3/ComposerClient.cpp
@@ -1051,13 +1051,14 @@
 ndk::ScopedAStatus ComposerClient::setActiveConfig(int64_t display_id,
                                                    int32_t config) {
   DEBUG_FUNC();
-  const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
-  HwcDisplay* display = GetDisplay(display_id);
-  if (display == nullptr) {
-    return ToBinderStatus(hwc3::Error::kBadDisplay);
-  }
 
-  return ToBinderStatus(Hwc2toHwc3Error(display->SetActiveConfig(config)));
+  VsyncPeriodChangeTimeline timeline;
+  VsyncPeriodChangeConstraints constraints = {
+      .desiredTimeNanos = ::android::ResourceManager::GetTimeMonotonicNs(),
+      .seamlessRequired = false,
+  };
+  return setActiveConfigWithConstraints(display_id, config, constraints,
+                                        &timeline);
 }
 
 ndk::ScopedAStatus ComposerClient::setActiveConfigWithConstraints(
@@ -1071,23 +1072,24 @@
     return ToBinderStatus(hwc3::Error::kBadDisplay);
   }
 
-  hwc_vsync_period_change_constraints_t hwc2_constraints;
-  hwc2_constraints.desiredTimeNanos = constraints.desiredTimeNanos;
-  hwc2_constraints.seamlessRequired = static_cast<uint8_t>(
-      constraints.seamlessRequired);
+  ::QueuedConfigTiming timing{};
+  HwcDisplay::ConfigError
+      result = display->QueueConfig(config, constraints.desiredTimeNanos,
+                                    constraints.seamlessRequired, &timing);
+  timeline->newVsyncAppliedTimeNanos = timing.new_vsync_time_ns;
+  timeline->refreshTimeNanos = timing.refresh_time_ns;
+  timeline->refreshRequired = true;
 
-  hwc_vsync_period_change_timeline_t hwc2_timeline{};
-  auto error = Hwc2toHwc3Error(
-      display->SetActiveConfigWithConstraints(config, &hwc2_constraints,
-                                              &hwc2_timeline));
-  if (error != hwc3::Error::kNone) {
-    return ToBinderStatus(error);
+  switch (result) {
+    case HwcDisplay::ConfigError::kBadConfig:
+      return ToBinderStatus(hwc3::Error::kBadConfig);
+    case HwcDisplay::ConfigError::kSeamlessNotAllowed:
+      return ToBinderStatus(hwc3::Error::kSeamlessNotAllowed);
+    case HwcDisplay::ConfigError::kSeamlessNotPossible:
+      return ToBinderStatus(hwc3::Error::kSeamlessNotPossible);
+    case HwcDisplay::ConfigError::kNone:
+      return ndk::ScopedAStatus::ok();
   }
-
-  timeline->refreshTimeNanos = hwc2_timeline.refreshTimeNanos;
-  timeline->newVsyncAppliedTimeNanos = hwc2_timeline.newVsyncAppliedTimeNanos;
-  timeline->refreshRequired = static_cast<bool>(hwc2_timeline.refreshRequired);
-  return ndk::ScopedAStatus::ok();
 }
 
 ndk::ScopedAStatus ComposerClient::setBootDisplayConfig(int64_t /*display_id*/,