SF: Unify data types for display modes

Remove the RefreshRateConfigs::RefreshRate wrapper around DisplayMode.
Store DisplayModes as a SmallMap, so that RefreshRateConfigs uses the
same data structure for lookup by ID. Use iterators into that map for
all bookkeeping in RefreshRateConfigs.

Bug: 182939859
Bug: 185535769
Test: libsurfaceflinger_unittest
Change-Id: I7708fa997089802c45d906b17b7a073f5c82105e
diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 0ab9605..61a9a08 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayMode.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -18,10 +18,10 @@
 
 #include <cstddef>
 #include <memory>
-#include <vector>
 
 #include <android-base/stringprintf.h>
 #include <android/configuration.h>
+#include <ftl/small_map.h>
 #include <ui/DisplayId.h>
 #include <ui/DisplayMode.h>
 #include <ui/Size.h>
@@ -38,8 +38,17 @@
 
 class DisplayMode;
 using DisplayModePtr = std::shared_ptr<const DisplayMode>;
-using DisplayModes = std::vector<DisplayModePtr>;
-using DisplayModeId = StrongTyping<ui::DisplayModeId, struct DisplayModeIdTag, Compare, Hash>;
+
+// Prevent confusion with fps_approx_ops on the underlying Fps.
+bool operator<(const DisplayModePtr&, const DisplayModePtr&) = delete;
+bool operator>(const DisplayModePtr&, const DisplayModePtr&) = delete;
+bool operator<=(const DisplayModePtr&, const DisplayModePtr&) = delete;
+bool operator>=(const DisplayModePtr&, const DisplayModePtr&) = delete;
+
+using DisplayModeId = StrongTyping<ui::DisplayModeId, struct DisplayModeIdTag, Compare>;
+
+using DisplayModes = ftl::SmallMap<DisplayModeId, DisplayModePtr, 3>;
+using DisplayModeIterator = DisplayModes::const_iterator;
 
 class DisplayMode {
 public:
@@ -61,35 +70,30 @@
             return *this;
         }
 
-        Builder& setWidth(int32_t width) {
-            mDisplayMode->mWidth = width;
+        Builder& setResolution(ui::Size resolution) {
+            mDisplayMode->mResolution = resolution;
             return *this;
         }
 
-        Builder& setHeight(int32_t height) {
-            mDisplayMode->mHeight = height;
-            return *this;
-        }
-
-        Builder& setVsyncPeriod(int32_t vsyncPeriod) {
+        Builder& setVsyncPeriod(nsecs_t vsyncPeriod) {
             mDisplayMode->mFps = Fps::fromPeriodNsecs(vsyncPeriod);
             return *this;
         }
 
         Builder& setDpiX(int32_t dpiX) {
             if (dpiX == -1) {
-                mDisplayMode->mDpiX = getDefaultDensity();
+                mDisplayMode->mDpi.x = getDefaultDensity();
             } else {
-                mDisplayMode->mDpiX = dpiX / 1000.0f;
+                mDisplayMode->mDpi.x = dpiX / 1000.f;
             }
             return *this;
         }
 
         Builder& setDpiY(int32_t dpiY) {
             if (dpiY == -1) {
-                mDisplayMode->mDpiY = getDefaultDensity();
+                mDisplayMode->mDpi.y = getDefaultDensity();
             } else {
-                mDisplayMode->mDpiY = dpiY / 1000.0f;
+                mDisplayMode->mDpi.y = dpiY / 1000.f;
             }
             return *this;
         }
@@ -107,59 +111,76 @@
             // information to begin with. This is also used for virtual displays and
             // older HWC implementations, so be careful about orientation.
 
-            auto longDimension = std::max(mDisplayMode->mWidth, mDisplayMode->mHeight);
-            if (longDimension >= 1080) {
+            if (std::max(mDisplayMode->getWidth(), mDisplayMode->getHeight()) >= 1080) {
                 return ACONFIGURATION_DENSITY_XHIGH;
             } else {
                 return ACONFIGURATION_DENSITY_TV;
             }
         }
+
         std::shared_ptr<DisplayMode> mDisplayMode;
     };
 
     DisplayModeId getId() const { return mId; }
+
     hal::HWConfigId getHwcId() const { return mHwcId; }
     PhysicalDisplayId getPhysicalDisplayId() const { return mPhysicalDisplayId; }
 
-    int32_t getWidth() const { return mWidth; }
-    int32_t getHeight() const { return mHeight; }
-    ui::Size getSize() const { return {mWidth, mHeight}; }
+    ui::Size getResolution() const { return mResolution; }
+    int32_t getWidth() const { return mResolution.getWidth(); }
+    int32_t getHeight() const { return mResolution.getHeight(); }
+
     Fps getFps() const { return mFps; }
     nsecs_t getVsyncPeriod() const { return mFps.getPeriodNsecs(); }
-    float getDpiX() const { return mDpiX; }
-    float getDpiY() const { return mDpiY; }
+
+    struct Dpi {
+        float x = -1;
+        float y = -1;
+
+        bool operator==(Dpi other) const { return x == other.x && y == other.y; }
+    };
+
+    Dpi getDpi() const { return mDpi; }
 
     // Switches between modes in the same group are seamless, i.e.
     // without visual interruptions such as a black screen.
     int32_t getGroup() const { return mGroup; }
 
-    bool equalsExceptDisplayModeId(const DisplayModePtr& other) const {
-        return mHwcId == other->mHwcId && mWidth == other->mWidth && mHeight == other->mHeight &&
-                getVsyncPeriod() == other->getVsyncPeriod() && mDpiX == other->mDpiX &&
-                mDpiY == other->mDpiY && mGroup == other->mGroup;
-    }
-
 private:
     explicit DisplayMode(hal::HWConfigId id) : mHwcId(id) {}
 
-    hal::HWConfigId mHwcId;
+    const hal::HWConfigId mHwcId;
     DisplayModeId mId;
+
     PhysicalDisplayId mPhysicalDisplayId;
 
-    int32_t mWidth = -1;
-    int32_t mHeight = -1;
+    ui::Size mResolution;
     Fps mFps;
-    float mDpiX = -1;
-    float mDpiY = -1;
+    Dpi mDpi;
     int32_t mGroup = -1;
 };
 
+inline bool equalsExceptDisplayModeId(const DisplayMode& lhs, const DisplayMode& rhs) {
+    return lhs.getHwcId() == rhs.getHwcId() && lhs.getResolution() == rhs.getResolution() &&
+            lhs.getVsyncPeriod() == rhs.getVsyncPeriod() && lhs.getDpi() == rhs.getDpi() &&
+            lhs.getGroup() == rhs.getGroup();
+}
+
 inline std::string to_string(const DisplayMode& mode) {
-    return base::StringPrintf("{id=%d, hwcId=%d, width=%d, height=%d, refreshRate=%s, "
-                              "dpiX=%.2f, dpiY=%.2f, group=%d}",
+    return base::StringPrintf("{id=%d, hwcId=%d, resolution=%dx%d, refreshRate=%s, "
+                              "dpi=%.2fx%.2f, group=%d}",
                               mode.getId().value(), mode.getHwcId(), mode.getWidth(),
-                              mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpiX(),
-                              mode.getDpiY(), mode.getGroup());
+                              mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpi().x,
+                              mode.getDpi().y, mode.getGroup());
+}
+
+template <typename... DisplayModePtrs>
+inline DisplayModes makeModes(const DisplayModePtrs&... modePtrs) {
+    DisplayModes modes;
+    // Note: The omission of std::move(modePtrs) is intentional, because order of evaluation for
+    // arguments is unspecified.
+    (modes.try_emplace(modePtrs->getId(), modePtrs), ...);
+    return modes;
 }
 
 } // namespace android