drm_hwcomposer: Implement getDisplayPhysicalOrientation()

Implement ComposerClient::getDisplayPhysicalOrientation() by querying
the DRM display panel orientation property and translating the result to
the correct common::Transform enum value.

The result is used by SurfaceFlinger to correctly rotate the image
before displaying it to the user.

Signed-off-by: Tim Van Patten <timvp@google.com>
diff --git a/drm/DrmAtomicStateManager.h b/drm/DrmAtomicStateManager.h
index c8736f2..20896ed 100644
--- a/drm/DrmAtomicStateManager.h
+++ b/drm/DrmAtomicStateManager.h
@@ -21,7 +21,7 @@
 #include <memory>
 #include <optional>
 
-#include "compositor/ColorInfo.h"
+#include "compositor/DisplayInfo.h"
 #include "compositor/DrmKmsPlan.h"
 #include "compositor/LayerData.h"
 #include "drm/DrmPlane.h"
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index 5371513..c46effa 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -27,6 +27,7 @@
 #include <sstream>
 
 #include "DrmDevice.h"
+#include "compositor/DisplayInfo.h"
 #include "utils/log.h"
 
 #ifndef DRM_MODE_CONNECTOR_SPI
@@ -136,6 +137,26 @@
   GetConnectorProperty("content type", &content_type_property_,
                        /*is_optional=*/true);
 
+  if (GetConnectorProperty("panel orientation", &panel_orientation_,
+                           /*is_optional=*/true)) {
+    panel_orientation_
+        .AddEnumToMapReverse("Normal",
+                             PanelOrientation::kModePanelOrientationNormal,
+                             panel_orientation_enum_map_);
+    panel_orientation_
+        .AddEnumToMapReverse("Upside Down",
+                             PanelOrientation::kModePanelOrientationBottomUp,
+                             panel_orientation_enum_map_);
+    panel_orientation_
+        .AddEnumToMapReverse("Left Side Up",
+                             PanelOrientation::kModePanelOrientationLeftUp,
+                             panel_orientation_enum_map_);
+    panel_orientation_
+        .AddEnumToMapReverse("Right Side Up",
+                             PanelOrientation::kModePanelOrientationRightUp,
+                             panel_orientation_enum_map_);
+  }
+
   return true;
 }
 
@@ -241,4 +262,26 @@
 
   return true;
 }
+
+std::optional<PanelOrientation> DrmConnector::GetPanelOrientation() {
+  if (!panel_orientation_.GetValue().has_value()) {
+    ALOGW("No panel orientation property available.");
+    return {};
+  }
+
+  /* The value_or(0) satisfies the compiler warning. However,
+   * panel_orientation_.GetValue() is guaranteed to have a value since we check
+   * has_value() and return early otherwise.
+   */
+  uint64_t panel_orientation_value = panel_orientation_.GetValue().value_or(0);
+
+  if (panel_orientation_enum_map_.count(panel_orientation_value) == 1) {
+    return panel_orientation_enum_map_[panel_orientation_value];
+  }
+
+  ALOGE("Unknown panel orientation: panel_orientation = %lu",
+        panel_orientation_value);
+  return {};
+}
+
 }  // namespace android
diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h
index 9186f07..be84ae3 100644
--- a/drm/DrmConnector.h
+++ b/drm/DrmConnector.h
@@ -26,8 +26,7 @@
 #include "DrmMode.h"
 #include "DrmProperty.h"
 #include "DrmUnique.h"
-
-#include "compositor/ColorInfo.h"
+#include "compositor/DisplayInfo.h"
 
 namespace android {
 
@@ -118,6 +117,10 @@
     return writeback_out_fence_;
   }
 
+  auto &GetPanelOrientationProperty() const {
+    return panel_orientation_;
+  }
+
   auto IsConnected() const {
     return connector_->connection == DRM_MODE_CONNECTED;
   }
@@ -130,11 +133,13 @@
     return connector_->mmHeight;
   };
 
+  auto GetPanelOrientation() -> std::optional<PanelOrientation>;
+
  private:
   DrmConnector(DrmModeConnectorUnique connector, DrmDevice *drm, uint32_t index)
       : connector_(std::move(connector)),
         drm_(drm),
-        index_in_res_array_(index){};
+        index_in_res_array_(index) {};
 
   DrmModeConnectorUnique connector_;
   DrmDevice *const drm_;
@@ -157,7 +162,9 @@
   DrmProperty writeback_pixel_formats_;
   DrmProperty writeback_fb_id_;
   DrmProperty writeback_out_fence_;
+  DrmProperty panel_orientation_;
 
   std::map<Colorspace, uint64_t> colorspace_enum_map_;
+  std::map<uint64_t, PanelOrientation> panel_orientation_enum_map_;
 };
 }  // namespace android
diff --git a/drm/DrmProperty.cpp b/drm/DrmProperty.cpp
index 031918a..0ea9143 100644
--- a/drm/DrmProperty.cpp
+++ b/drm/DrmProperty.cpp
@@ -125,4 +125,22 @@
   return true;
 }
 
+std::optional<std::string> DrmProperty::GetEnumNameFromValue(
+    uint64_t value) const {
+  if (enums_.empty()) {
+    ALOGE("No enum values for property: %s", name_.c_str());
+    return {};
+  }
+
+  for (const auto &it : enums_) {
+    if (it.value == value) {
+      return it.name;
+    }
+  }
+
+  ALOGE("Property '%s' has no matching enum for value: %lu", name_.c_str(),
+        value);
+  return {};
+}
+
 }  // namespace android
diff --git a/drm/DrmProperty.h b/drm/DrmProperty.h
index 516518b..2683ad8 100644
--- a/drm/DrmProperty.h
+++ b/drm/DrmProperty.h
@@ -64,10 +64,16 @@
   auto AddEnumToMap(const std::string &name, E key, std::map<E, uint64_t> &map)
       -> bool;
 
+  template <class E>
+  auto AddEnumToMapReverse(const std::string &name, E value,
+                           std::map<uint64_t, E> &map) -> bool;
+
   explicit operator bool() const {
     return id_ != 0;
   }
 
+  auto GetEnumNameFromValue(uint64_t value) const -> std::optional<std::string>;
+
  private:
   class DrmPropertyEnum {
    public:
@@ -104,4 +110,18 @@
   return false;
 }
 
+template <class E>
+auto DrmProperty::AddEnumToMapReverse(const std::string &name, E value,
+                                      std::map<uint64_t, E> &map) -> bool {
+  uint64_t enum_value = UINT64_MAX;
+  int err = 0;
+  std::tie(enum_value, err) = GetEnumValueWithName(name);
+  if (err == 0) {
+    map[enum_value] = value;
+    return true;
+  }
+
+  return false;
+}
+
 }  // namespace android