drm_hwcomposer: Implement getHdrCapabilities and getColorModes

Retrieve color and HDR information from the EDID.

Change-Id: I1aac27644d5c4fd5d5f295ca32b69ed69e94e0c6
Signed-off-by: Sasha McIntosh <sashamcintosh@google.com>
diff --git a/Android.bp b/Android.bp
index fab7a98..796696c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -102,9 +102,9 @@
         "hwc2_device/HwcLayer.cpp",
         "hwc2_device/hwc2_device.cpp",
 
+        "utils/LibdisplayEdidWrapper.cpp",
         "utils/fd.cpp",
         "utils/properties.cpp",
-        "utils/LibdisplayEdidWrapper.cpp",
     ],
 }
 
diff --git a/compositor/DisplayInfo.h b/compositor/DisplayInfo.h
index 6ddc66f..f580d99 100644
--- a/compositor/DisplayInfo.h
+++ b/compositor/DisplayInfo.h
@@ -18,6 +18,31 @@
 
 #include <cstdint>
 
+/*
+ * Display colorimetry enums.
+ */
+// NOLINTBEGIN(readability-identifier-naming)
+enum class Colormode : int32_t {
+  kNative,
+  kBt601_625,
+  kBt601_625Unadjusted,
+  kBt601_525,
+  kBt601_525Unadjusted,
+  kBt709,
+  kDciP3,
+  kSrgb,
+  kAdobeRgb,
+  kDisplayP3,
+  kBt2020,
+  kBt2100Pq,
+  kBt2100Hlg,
+  kDisplayBt2020,
+};
+// NOLINTEND(readability-identifier-naming)
+
+/**
+ * Display panel colorspace property values.
+ */
 enum class Colorspace : int32_t {
   kDefault,
   kSmpte170MYcc,
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 5abbc4d..16d8bac 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -613,11 +613,23 @@
 }
 
 HWC2::Error HwcDisplay::GetColorModes(uint32_t *num_modes, int32_t *modes) {
-  if (!modes)
-    *num_modes = 1;
+  if (!modes) {
+    std::vector<Colormode> temp_modes;
+    GetEdid()->GetColorModes(temp_modes);
+    *num_modes = temp_modes.size();
+    return HWC2::Error::None;
+  }
 
-  if (modes)
-    *modes = HAL_COLOR_MODE_NATIVE;
+  std::vector<Colormode> temp_modes;
+  std::vector<int32_t> out_modes(modes, modes + *num_modes);
+  GetEdid()->GetColorModes(temp_modes);
+  if (temp_modes.empty()) {
+    out_modes.emplace_back(HAL_COLOR_MODE_NATIVE);
+    return HWC2::Error::None;
+  }
+
+  for (auto &c : temp_modes)
+    out_modes.emplace_back(static_cast<int32_t>(c));
 
   return HWC2::Error::None;
 }
@@ -733,12 +745,35 @@
   return HWC2::Error::None;
 }
 
-HWC2::Error HwcDisplay::GetHdrCapabilities(uint32_t *num_types,
-                                           int32_t * /*types*/,
-                                           float * /*max_luminance*/,
-                                           float * /*max_average_luminance*/,
-                                           float * /*min_luminance*/) {
-  *num_types = 0;
+HWC2::Error HwcDisplay::GetHdrCapabilities(uint32_t *num_types, int32_t *types,
+                                           float *max_luminance,
+                                           float *max_average_luminance,
+                                           float *min_luminance) {
+  if (!types) {
+    std::vector<ui::Hdr> temp_types;
+    float lums[3] = {0.F};
+    GetEdid()->GetHdrCapabilities(temp_types, &lums[0], &lums[1], &lums[2]);
+    *num_types = temp_types.size();
+    return HWC2::Error::None;
+  }
+
+  std::vector<ui::Hdr> temp_types;
+  std::vector<int32_t> out_types(types, types + *num_types);
+  GetEdid()->GetHdrCapabilities(temp_types, max_luminance,
+                                max_average_luminance, min_luminance);
+  for (auto &t : temp_types) {
+    switch (t) {
+      case ui::Hdr::HDR10:
+        out_types.emplace_back(HAL_HDR_HDR10);
+        break;
+      case ui::Hdr::HLG:
+        out_types.emplace_back(HAL_HDR_HLG);
+        break;
+      default:
+        // Ignore any other HDR types
+        break;
+    }
+  }
   return HWC2::Error::None;
 }
 
@@ -983,18 +1018,6 @@
   staged_mode_change_time_ = change_time;
   staged_mode_config_id_ = config;
 
-  std::vector<ui::Hdr> hdr_types;
-  GetEdid()->GetSupportedHdrTypes(hdr_types);
-  if (hdr_types.empty()) {
-    hdr_metadata_.reset();
-    colorspace_ = Colorspace::kDefault;
-  } else {
-    auto ret = SetHdrOutputMetadata(hdr_types.front());
-    if (ret != HWC2::Error::None)
-      return ret;
-    colorspace_ = Colorspace::kBt2020Rgb;
-  }
-
   return HWC2::Error::None;
 }
 
@@ -1056,29 +1079,47 @@
   /* Maps to the Colorspace DRM connector property:
    * https://elixir.bootlin.com/linux/v6.11/source/include/drm/drm_connector.h#L538
    */
-  if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_DISPLAY_P3)
+  if (mode < HAL_COLOR_MODE_NATIVE || mode > HAL_COLOR_MODE_DISPLAY_BT2020)
     return HWC2::Error::BadParameter;
 
   switch (mode) {
     case HAL_COLOR_MODE_NATIVE:
+      hdr_metadata_.reset();
       colorspace_ = Colorspace::kDefault;
       break;
     case HAL_COLOR_MODE_STANDARD_BT601_625:
     case HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED:
     case HAL_COLOR_MODE_STANDARD_BT601_525:
     case HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED:
+      hdr_metadata_.reset();
       // The DP spec does not say whether this is the 525 or the 625 line version.
       colorspace_ = Colorspace::kBt601Ycc;
       break;
     case HAL_COLOR_MODE_STANDARD_BT709:
     case HAL_COLOR_MODE_SRGB:
+      hdr_metadata_.reset();
       colorspace_ = Colorspace::kBt709Ycc;
       break;
     case HAL_COLOR_MODE_DCI_P3:
     case HAL_COLOR_MODE_DISPLAY_P3:
+      hdr_metadata_.reset();
       colorspace_ = Colorspace::kDciP3RgbD65;
       break;
+    case HAL_COLOR_MODE_DISPLAY_BT2020: {
+      std::vector<ui::Hdr> hdr_types;
+      GetEdid()->GetSupportedHdrTypes(hdr_types);
+      if (!hdr_types.empty()) {
+        auto ret = SetHdrOutputMetadata(hdr_types.front());
+        if (ret != HWC2::Error::None)
+          return ret;
+      }
+      colorspace_ = Colorspace::kBt2020Rgb;
+      break;
+    }
     case HAL_COLOR_MODE_ADOBE_RGB:
+    case HAL_COLOR_MODE_BT2020:
+    case HAL_COLOR_MODE_BT2100_PQ:
+    case HAL_COLOR_MODE_BT2100_HLG:
     default:
       return HWC2::Error::Unsupported;
   }
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index 24c7465..7522c8d 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -22,6 +22,8 @@
 #include <optional>
 #include <sstream>
 
+#include <ui/GraphicTypes.h>
+
 #include "HwcDisplayConfigs.h"
 #include "compositor/DisplayInfo.h"
 #include "compositor/FlatteningController.h"
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
index 04beb3a..ff3d42e 100644
--- a/hwc3/ComposerClient.cpp
+++ b/hwc3/ComposerClient.cpp
@@ -941,8 +941,28 @@
     return ToBinderStatus(hwc3::Error::kBadDisplay);
   }
 
-  /* No HDR capabilities */
-  caps->types.clear();
+  uint32_t num_types = 0;
+  hwc3::Error error = Hwc2toHwc3Error(
+      display->GetHdrCapabilities(&num_types, nullptr, nullptr, nullptr,
+                                  nullptr));
+  if (error != hwc3::Error::kNone) {
+    return ToBinderStatus(error);
+  }
+
+  std::vector<int32_t> out_types(num_types);
+  error = Hwc2toHwc3Error(
+      display->GetHdrCapabilities(&num_types, out_types.data(),
+                                  &caps->maxLuminance,
+                                  &caps->maxAverageLuminance,
+                                  &caps->minLuminance));
+  if (error != hwc3::Error::kNone) {
+    return ToBinderStatus(error);
+  }
+
+  caps->types.reserve(num_types);
+  for (const auto type : out_types)
+    caps->types.emplace_back(Hwc2HdrTypeToHwc3(type));
+
   return ndk::ScopedAStatus::ok();
 }
 
diff --git a/hwc3/Utils.h b/hwc3/Utils.h
index b322f5d..642c777 100644
--- a/hwc3/Utils.h
+++ b/hwc3/Utils.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <aidl/android/hardware/graphics/common/Hdr.h>
 #include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
 #include <hardware/hwcomposer2.h>
 #include <log/log.h>
@@ -165,4 +166,12 @@
   return static_cast<int32_t>(dataspace);
 }
 
-};  // namespace aidl::android::hardware::graphics::composer3
\ No newline at end of file
+// Values appear to match.
+// https://cs.android.com/android/platform/superproject/main/+/main:hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Hdr.aidl
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.0.h;l=130;drc=7d940ae4afa450696afa25e07982f3a95e17e9b2
+// https://cs.android.com/android/platform/superproject/main/+/main:system/core/libsystem/include/system/graphics-base-v1.2.h;l=12;drc=af7be7616859f8e9e57710b9c37c66cf880a6643
+inline common::Hdr Hwc2HdrTypeToHwc3(int32_t hdr_type) {
+  return static_cast<common::Hdr>(hdr_type);
+}
+
+};  // namespace aidl::android::hardware::graphics::composer3
diff --git a/utils/EdidWrapper.h b/utils/EdidWrapper.h
index 867d1a0..30124d7 100644
--- a/utils/EdidWrapper.h
+++ b/utils/EdidWrapper.h
@@ -16,8 +16,6 @@
 
 #pragma once
 
-#define LOG_TAG "drmhwc"
-
 #if HAS_LIBDISPLAY_INFO
 extern "C" {
 #include <libdisplay-info/info.h>
@@ -26,8 +24,8 @@
 
 #include <ui/GraphicTypes.h>
 
+#include "compositor/DisplayInfo.h"
 #include "drm/DrmUnique.h"
-#include "utils/log.h"
 
 namespace android {
 
@@ -47,6 +45,9 @@
                                   const float * /*min_luminance*/) {
     GetSupportedHdrTypes(types);
   };
+  virtual void GetColorModes(std::vector<Colormode> &color_modes) {
+    color_modes.clear();
+  };
 };
 
 #if HAS_LIBDISPLAY_INFO
@@ -67,6 +68,8 @@
                           const float *max_average_luminance,
                           const float *min_luminance) override;
 
+  void GetColorModes(std::vector<Colormode> &color_modes) override;
+
  private:
   LibdisplayEdidWrapper(di_info *info) : info_(std::move(info)) {
   }
diff --git a/utils/LibdisplayEdidWrapper.cpp b/utils/LibdisplayEdidWrapper.cpp
index 5a17b93..d2d2a1c 100644
--- a/utils/LibdisplayEdidWrapper.cpp
+++ b/utils/LibdisplayEdidWrapper.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "drmhwc"
 
 #if HAS_LIBDISPLAY_INFO
+
 #include "utils/EdidWrapper.h"
 #include "utils/log.h"
 
@@ -63,5 +64,36 @@
   min_luminance = &hdr_static_meta->desired_content_min_luminance;
 }
 
+void LibdisplayEdidWrapper::GetColorModes(std::vector<Colormode> &color_modes) {
+  color_modes.clear();
+  color_modes.emplace_back(Colormode::kNative);
+
+  const auto *hdr_static_meta = di_info_get_hdr_static_metadata(info_);
+  const auto *colorimetries = di_info_get_supported_signal_colorimetry(info_);
+
+  /* Rec. ITU-R BT.2020 constant luminance YCbCr */
+  /* Rec. ITU-R BT.2020 non-constant luminance YCbCr */
+  if (colorimetries->bt2020_cycc || colorimetries->bt2020_ycc)
+    color_modes.emplace_back(Colormode::kBt2020);
+
+  /* Rec. ITU-R BT.2020 RGB */
+  if (colorimetries->bt2020_rgb)
+    color_modes.emplace_back(Colormode::kDisplayBt2020);
+
+  /* SMPTE ST 2113 RGB: P3D65 and P3DCI */
+  if (colorimetries->st2113_rgb) {
+    color_modes.emplace_back(Colormode::kDciP3);
+    color_modes.emplace_back(Colormode::kDisplayP3);
+  }
+
+  /* Rec. ITU-R BT.2100 ICtCp HDR (with PQ and/or HLG) */
+  if (colorimetries->ictcp) {
+    if (hdr_static_meta->pq)
+      color_modes.emplace_back(Colormode::kBt2100Pq);
+    if (hdr_static_meta->hlg)
+      color_modes.emplace_back(Colormode::kBt2100Hlg);
+  }
+}
+
 }  // namespace android
 #endif