drm_hwcomposer: Move HwcDisplayConfigs out of HwcDisplay class

To reduce complexity of HwcDisplay class.

Signed-off-by: Roman Stratiienko <roman.o.stratiienko@globallogic.com>
diff --git a/Android.bp b/Android.bp
index 59aa05f..8e99056 100644
--- a/Android.bp
+++ b/Android.bp
@@ -110,6 +110,7 @@
 
         "hwc2_device/DrmHwcTwo.cpp",
         "hwc2_device/HwcDisplay.cpp",
+        "hwc2_device/HwcDisplayConfigs.cpp",
         "hwc2_device/HwcLayer.cpp",
         "hwc2_device/hwc2_device.cpp",
     ],
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index e0a5823..b2cdfa3 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -190,13 +190,11 @@
 }
 
 HWC2::Error HwcDisplay::ChosePreferredConfig() {
-  // Fetch the number of modes from the display
-  uint32_t num_configs = 0;
-  HWC2::Error err = GetDisplayConfigs(&num_configs, nullptr);
-  if (err != HWC2::Error::None || !num_configs)
+  HWC2::Error err = configs_.Update(*connector_);
+  if (err != HWC2::Error::None)
     return HWC2::Error::BadDisplay;
 
-  return SetActiveConfig(preferred_config_id_);
+  return SetActiveConfig(configs_.preferred_config_id);
 }
 
 HWC2::Error HwcDisplay::AcceptDisplayChanges() {
@@ -221,10 +219,10 @@
 }
 
 HWC2::Error HwcDisplay::GetActiveConfig(hwc2_config_t *config) const {
-  if (hwc_configs_.count(active_config_id_) == 0)
+  if (configs_.hwc_configs.count(configs_.active_config_id) == 0)
     return HWC2::Error::BadConfig;
 
-  *config = active_config_id_;
+  *config = configs_.active_config_id;
   return HWC2::Error::None;
 }
 
@@ -280,12 +278,12 @@
                                             int32_t *value) {
   int conf = static_cast<int>(config);
 
-  if (hwc_configs_.count(conf) == 0) {
+  if (configs_.hwc_configs.count(conf) == 0) {
     ALOGE("Could not find active mode for %d", conf);
     return HWC2::Error::BadConfig;
   }
 
-  auto &hwc_config = hwc_configs_[conf];
+  auto &hwc_config = configs_.hwc_configs[conf];
 
   static const int32_t kUmPerInch = 25400;
   uint32_t mm_width = connector_->mm_width();
@@ -328,7 +326,6 @@
   return HWC2::Error::None;
 }
 
-// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
 HWC2::Error HwcDisplay::GetDisplayConfigs(uint32_t *num_configs,
                                           hwc2_config_t *configs) {
   // Since this callback is normally invoked twice (once to get the count, and
@@ -337,142 +334,11 @@
   // it's possible this will result in stale modes, it'll all come out in the
   // wash when we try to set the active config later.
   if (!configs) {
-    int ret = connector_->UpdateModes();
-    if (ret) {
-      ALOGE("Failed to update display modes %d", ret);
-      return HWC2::Error::BadDisplay;
-    }
-
-    hwc_configs_.clear();
-    preferred_config_id_ = 0;
-    int preferred_config_group_id_ = 0;
-
-    if (connector_->modes().empty()) {
-      ALOGE("No modes reported by KMS");
-      return HWC2::Error::BadDisplay;
-    }
-
-    int last_config_id = 1;
-    int last_group_id = 1;
-
-    /* Group modes */
-    for (const auto &mode : connector_->modes()) {
-      /* Find group for the new mode or create new group */
-      int group_found = 0;
-      for (auto &hwc_config : hwc_configs_) {
-        if (mode.h_display() == hwc_config.second.mode.h_display() &&
-            mode.v_display() == hwc_config.second.mode.v_display()) {
-          group_found = hwc_config.second.group_id;
-        }
-      }
-      if (group_found == 0) {
-        group_found = last_group_id++;
-      }
-
-      bool disabled = false;
-      if (mode.flags() & DRM_MODE_FLAG_3D_MASK) {
-        ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)",
-              mode.name().c_str());
-        disabled = true;
-      }
-
-      /* Add config */
-      hwc_configs_[last_config_id] = {
-          .id = last_config_id,
-          .group_id = group_found,
-          .mode = mode,
-          .disabled = disabled,
-      };
-
-      /* Chwck if the mode is preferred */
-      if ((mode.type() & DRM_MODE_TYPE_PREFERRED) != 0 &&
-          preferred_config_id_ == 0) {
-        preferred_config_id_ = last_config_id;
-        preferred_config_group_id_ = group_found;
-      }
-
-      last_config_id++;
-    }
-
-    /* We must have preferred mode. Set first mode as preferred
-     * in case KMS haven't reported anything. */
-    if (preferred_config_id_ == 0) {
-      preferred_config_id_ = 1;
-      preferred_config_group_id_ = 1;
-    }
-
-    for (int group = 1; group < last_group_id; group++) {
-      bool has_interlaced = false;
-      bool has_progressive = false;
-      for (auto &hwc_config : hwc_configs_) {
-        if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
-          continue;
-        }
-
-        if (hwc_config.second.IsInterlaced()) {
-          has_interlaced = true;
-        } else {
-          has_progressive = true;
-        }
-      }
-
-      bool has_both = has_interlaced && has_progressive;
-      if (!has_both) {
-        continue;
-      }
-
-      bool group_contains_preferred_interlaced = false;
-      if (group == preferred_config_group_id_ &&
-          hwc_configs_[preferred_config_id_].IsInterlaced()) {
-        group_contains_preferred_interlaced = true;
-      }
-
-      for (auto &hwc_config : hwc_configs_) {
-        if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
-          continue;
-        }
-
-        bool disable = group_contains_preferred_interlaced
-                           ? !hwc_config.second.IsInterlaced()
-                           : hwc_config.second.IsInterlaced();
-
-        if (disable) {
-          ALOGI(
-              "Group %i: Disabling display mode %s (This group should consist "
-              "of %s modes)",
-              group, hwc_config.second.mode.name().c_str(),
-              group_contains_preferred_interlaced ? "interlaced"
-                                                  : "progressive");
-
-          hwc_config.second.disabled = true;
-        }
-      }
-    }
-
-    /* Group should not contain 2 modes with FPS delta less than ~1HZ
-     * otherwise android.graphics.cts.SetFrameRateTest CTS will fail
-     */
-    for (int m1 = 1; m1 < last_config_id; m1++) {
-      for (int m2 = 1; m2 < last_config_id; m2++) {
-        if (m1 != m2 &&
-            hwc_configs_[m1].group_id == hwc_configs_[m2].group_id &&
-            !hwc_configs_[m1].disabled && !hwc_configs_[m2].disabled &&
-            fabsf(hwc_configs_[m1].mode.v_refresh() -
-                  hwc_configs_[m2].mode.v_refresh()) < 1.0) {
-          ALOGI(
-              "Group %i: Disabling display mode %s (Refresh rate value is "
-              "too close to existing mode %s)",
-              hwc_configs_[m2].group_id, hwc_configs_[m2].mode.name().c_str(),
-              hwc_configs_[m1].mode.name().c_str());
-
-          hwc_configs_[m2].disabled = true;
-        }
-      }
-    }
+    configs_.Update(*connector_);
   }
 
   uint32_t idx = 0;
-  for (auto &hwc_config : hwc_configs_) {
+  for (auto &hwc_config : configs_.hwc_configs) {
     if (hwc_config.second.disabled) {
       continue;
     }
@@ -666,16 +532,16 @@
 HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) {
   int conf = static_cast<int>(config);
 
-  if (hwc_configs_.count(conf) == 0) {
+  if (configs_.hwc_configs.count(conf) == 0) {
     ALOGE("Could not find active mode for %d", conf);
     return HWC2::Error::BadConfig;
   }
 
-  auto &mode = hwc_configs_[conf].mode;
+  auto &mode = configs_.hwc_configs[conf].mode;
 
   staged_mode = mode;
 
-  active_config_id_ = conf;
+  configs_.active_config_id = conf;
 
   // Setup the client layer's dimensions
   hwc_rect_t display_frame = {.left = 0,
@@ -825,7 +691,8 @@
 
 HWC2::Error HwcDisplay::GetDisplayVsyncPeriod(
     hwc2_vsync_period_t *outVsyncPeriod /* ns */) {
-  return GetDisplayAttribute(active_config_id_, HWC2_ATTRIBUTE_VSYNC_PERIOD,
+  return GetDisplayAttribute(configs_.active_config_id,
+                             HWC2_ATTRIBUTE_VSYNC_PERIOD,
                              (int32_t *)(outVsyncPeriod));
 }
 
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index f69ff18..6f46f5d 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -21,6 +21,7 @@
 
 #include <optional>
 
+#include "HwcDisplayConfigs.h"
 #include "compositor/DrmDisplayCompositor.h"
 #include "drm/ResourceManager.h"
 #include "drm/VSyncWorker.h"
@@ -138,22 +139,6 @@
     uint32_t frames_flattened_ = 0;
   };
 
-  struct HwcDisplayConfig {
-    int id{};
-    int group_id{};
-    DrmMode mode;
-    bool disabled{};
-
-    bool IsInterlaced() const {
-      return (mode.flags() & DRM_MODE_FLAG_INTERLACE) != 0;
-    }
-  };
-
-  std::map<int /*config_id*/, struct HwcDisplayConfig> hwc_configs_;
-
-  int active_config_id_ = 0;
-  int preferred_config_id_ = 0;
-
   const Backend *backend() const;
   void set_backend(std::unique_ptr<Backend> backend);
 
@@ -229,6 +214,8 @@
 
   constexpr static size_t MATRIX_SIZE = 16;
 
+  HwcDisplayConfigs configs_;
+
   DrmHwcTwo *hwc2_;
 
   std::optional<DrmMode> staged_mode;
diff --git a/hwc2_device/HwcDisplayConfigs.cpp b/hwc2_device/HwcDisplayConfigs.cpp
new file mode 100644
index 0000000..d1a8d4c
--- /dev/null
+++ b/hwc2_device/HwcDisplayConfigs.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "hwc-display-configs"
+
+#include "HwcDisplayConfigs.h"
+
+#include <cmath>
+
+#include "drm/DrmConnector.h"
+#include "utils/log.h"
+
+namespace android {
+
+// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
+HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) {
+  int ret = connector.UpdateModes();
+  if (ret != 0) {
+    ALOGE("Failed to update display modes %d", ret);
+    return HWC2::Error::BadDisplay;
+  }
+
+  hwc_configs.clear();
+  preferred_config_id = 0;
+  int preferred_config_group_id = 0;
+
+  if (connector.modes().empty()) {
+    ALOGE("No modes reported by KMS");
+    return HWC2::Error::BadDisplay;
+  }
+
+  int last_config_id = 1;
+  int last_group_id = 1;
+
+  /* Group modes */
+  for (const auto &mode : connector.modes()) {
+    /* Find group for the new mode or create new group */
+    int group_found = 0;
+    for (auto &hwc_config : hwc_configs) {
+      if (mode.h_display() == hwc_config.second.mode.h_display() &&
+          mode.v_display() == hwc_config.second.mode.v_display()) {
+        group_found = hwc_config.second.group_id;
+      }
+    }
+    if (group_found == 0) {
+      group_found = last_group_id++;
+    }
+
+    bool disabled = false;
+    if ((mode.flags() & DRM_MODE_FLAG_3D_MASK) != 0) {
+      ALOGI("Disabling display mode %s (Modes with 3D flag aren't supported)",
+            mode.name().c_str());
+      disabled = true;
+    }
+
+    /* Add config */
+    hwc_configs[last_config_id] = {
+        .id = last_config_id,
+        .group_id = group_found,
+        .mode = mode,
+        .disabled = disabled,
+    };
+
+    /* Chwck if the mode is preferred */
+    if ((mode.type() & DRM_MODE_TYPE_PREFERRED) != 0 &&
+        preferred_config_id == 0) {
+      preferred_config_id = last_config_id;
+      preferred_config_group_id = group_found;
+    }
+
+    last_config_id++;
+  }
+
+  /* We must have preferred mode. Set first mode as preferred
+   * in case KMS haven't reported anything. */
+  if (preferred_config_id == 0) {
+    preferred_config_id = 1;
+    preferred_config_group_id = 1;
+  }
+
+  for (int group = 1; group < last_group_id; group++) {
+    bool has_interlaced = false;
+    bool has_progressive = false;
+    for (auto &hwc_config : hwc_configs) {
+      if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
+        continue;
+      }
+
+      if (hwc_config.second.IsInterlaced()) {
+        has_interlaced = true;
+      } else {
+        has_progressive = true;
+      }
+    }
+
+    bool has_both = has_interlaced && has_progressive;
+    if (!has_both) {
+      continue;
+    }
+
+    bool group_contains_preferred_interlaced = false;
+    if (group == preferred_config_group_id &&
+        hwc_configs[preferred_config_id].IsInterlaced()) {
+      group_contains_preferred_interlaced = true;
+    }
+
+    for (auto &hwc_config : hwc_configs) {
+      if (hwc_config.second.group_id != group || hwc_config.second.disabled) {
+        continue;
+      }
+
+      bool disable = group_contains_preferred_interlaced
+                         ? !hwc_config.second.IsInterlaced()
+                         : hwc_config.second.IsInterlaced();
+
+      if (disable) {
+        ALOGI(
+            "Group %i: Disabling display mode %s (This group should consist "
+            "of %s modes)",
+            group, hwc_config.second.mode.name().c_str(),
+            group_contains_preferred_interlaced ? "interlaced" : "progressive");
+
+        hwc_config.second.disabled = true;
+      }
+    }
+  }
+
+  /* Group should not contain 2 modes with FPS delta less than ~1HZ
+   * otherwise android.graphics.cts.SetFrameRateTest CTS will fail
+   */
+  constexpr float kMinFpsDelta = 1.0;  // FPS
+  for (int m1 = 1; m1 < last_config_id; m1++) {
+    for (int m2 = 1; m2 < last_config_id; m2++) {
+      if (m1 != m2 && hwc_configs[m1].group_id == hwc_configs[m2].group_id &&
+          !hwc_configs[m1].disabled && !hwc_configs[m2].disabled &&
+          fabsf(hwc_configs[m1].mode.v_refresh() -
+                hwc_configs[m2].mode.v_refresh()) < kMinFpsDelta) {
+        ALOGI(
+            "Group %i: Disabling display mode %s (Refresh rate value is "
+            "too close to existing mode %s)",
+            hwc_configs[m2].group_id, hwc_configs[m2].mode.name().c_str(),
+            hwc_configs[m1].mode.name().c_str());
+
+        hwc_configs[m2].disabled = true;
+      }
+    }
+  }
+
+  return HWC2::Error::None;
+}
+
+}  // namespace android
diff --git a/hwc2_device/HwcDisplayConfigs.h b/hwc2_device/HwcDisplayConfigs.h
new file mode 100644
index 0000000..cb38625
--- /dev/null
+++ b/hwc2_device/HwcDisplayConfigs.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWC2_DEVICE_HWC_DISPLAY_CONFIGS_H
+#define ANDROID_HWC2_DEVICE_HWC_DISPLAY_CONFIGS_H
+
+#include <hardware/hwcomposer2.h>
+
+#include <map>
+
+#include "drm/DrmMode.h"
+
+namespace android {
+
+class DrmConnector;
+
+struct HwcDisplayConfig {
+  int id{};
+  int group_id{};
+  DrmMode mode;
+  bool disabled{};
+
+  bool IsInterlaced() const {
+    return (mode.flags() & DRM_MODE_FLAG_INTERLACE) != 0;
+  }
+};
+
+struct HwcDisplayConfigs {
+  HWC2::Error Update(DrmConnector &conn);
+
+  std::map<int /*config_id*/, struct HwcDisplayConfig> hwc_configs;
+
+  int active_config_id = 0;
+  int preferred_config_id = 0;
+};
+
+}  // namespace android
+
+#endif