drm_hwcomposer: Set HDR metadata on the connector
Implement a function to set HDR metadata on the connector. Support HDR10
and HLG, which are common HDR types.
Change-Id: Id3dbe8eea2ee6b8ba700af23845a43e2070dd14e
Signed-off-by: Sasha McIntosh <sashamcintosh@google.com>
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index a0c200e..5abbc4d 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -24,6 +24,7 @@
#include <xf86drmMode.h>
#include <hardware/gralloc.h>
+#include <ui/ColorSpace.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/GraphicBufferMapper.h>
#include <ui/PixelFormat.h>
@@ -39,6 +40,7 @@
#include "utils/properties.h"
using ::android::DrmDisplayPipeline;
+using ColorGamut = ::android::ColorSpace;
namespace android {
@@ -787,6 +789,7 @@
args.color_matrix = color_matrix_;
args.content_type = content_type_;
args.colorspace = colorspace_;
+ args.hdr_metadata = hdr_metadata_;
std::vector<LayerData> composition_layers;
if (modeset_layer) {
@@ -816,6 +819,7 @@
a_args.color_matrix = color_matrix_;
a_args.content_type = content_type_;
a_args.colorspace = colorspace_;
+ a_args.hdr_metadata = hdr_metadata_;
uint32_t prev_vperiod_ns = 0;
GetDisplayVsyncPeriod(&prev_vperiod_ns);
@@ -979,6 +983,18 @@
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;
}
@@ -1246,6 +1262,61 @@
(int32_t *)(outVsyncPeriod));
}
+// Display primary values are coded as unsigned 16-bit values in units of
+// 0.00002, where 0x0000 represents zero and 0xC350 represents 1.0000.
+static uint64_t ToU16ColorValue(float in) {
+ constexpr float kPrimariesFixedPoint = 50000.F;
+ return static_cast<uint64_t>(kPrimariesFixedPoint * in);
+}
+
+HWC2::Error HwcDisplay::SetHdrOutputMetadata(ui::Hdr type) {
+ hdr_metadata_ = std::make_shared<hdr_output_metadata>();
+ hdr_metadata_->metadata_type = 0;
+ auto *m = &hdr_metadata_->hdmi_metadata_type1;
+ m->metadata_type = 0;
+
+ switch (type) {
+ case ui::Hdr::HDR10:
+ m->eotf = 2; // PQ
+ break;
+ case ui::Hdr::HLG:
+ m->eotf = 3; // HLG
+ break;
+ default:
+ return HWC2::Error::Unsupported;
+ }
+
+ // Most luminance values are coded as an unsigned 16-bit value in units of 1
+ // cd/m2, where 0x0001 represents 1 cd/m2 and 0xFFFF represents 65535 cd/m2.
+ std::vector<ui::Hdr> types;
+ float hdr_luminance[3]{0.F, 0.F, 0.F};
+ GetEdid()->GetHdrCapabilities(types, &hdr_luminance[0], &hdr_luminance[1],
+ &hdr_luminance[2]);
+ m->max_display_mastering_luminance = m->max_cll = static_cast<uint64_t>(
+ hdr_luminance[0]);
+ m->max_fall = static_cast<uint64_t>(hdr_luminance[1]);
+ // The min luminance value is coded as an unsigned 16-bit value in units of
+ // 0.0001 cd/m2, where 0x0001 represents 0.0001 cd/m2 and 0xFFFF
+ // represents 6.5535 cd/m2.
+ m->min_display_mastering_luminance = static_cast<uint64_t>(hdr_luminance[2] *
+ 10000.F);
+
+ auto gamut = ColorGamut::BT2020();
+ auto primaries = gamut.getPrimaries();
+ m->display_primaries[0].x = ToU16ColorValue(primaries[0].x);
+ m->display_primaries[0].y = ToU16ColorValue(primaries[0].y);
+ m->display_primaries[1].x = ToU16ColorValue(primaries[1].x);
+ m->display_primaries[1].y = ToU16ColorValue(primaries[1].y);
+ m->display_primaries[2].x = ToU16ColorValue(primaries[2].x);
+ m->display_primaries[2].y = ToU16ColorValue(primaries[2].y);
+
+ auto whitePoint = gamut.getWhitePoint();
+ m->white_point.x = ToU16ColorValue(whitePoint.x);
+ m->white_point.y = ToU16ColorValue(whitePoint.y);
+
+ return HWC2::Error::None;
+}
+
#if __ANDROID_API__ > 29
HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) {
if (IsInHeadlessMode()) {