Merge "sdm: Add support to pass HDR metadata to HDR External Displays"
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index 6b7d321..34c92df 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -447,6 +447,17 @@
void Reset() { *this = HWLayerConfig(); }
};
+struct HWHDRLayerInfo {
+ enum HDROperation {
+ kNoOp, // No-op.
+ kSet, // Sets the HDR MetaData - Start of HDR
+ kReset, // resets the previously set HDR Metadata, End of HDR
+ };
+
+ int32_t layer_index = -1;
+ HDROperation operation = kNoOp;
+};
+
struct HWLayersInfo {
LayerStack *stack = NULL; // Input layer stack. Set by the caller.
uint32_t app_layer_count = 0; // Total number of app layers. Must not be 0.
@@ -468,6 +479,7 @@
bool use_hw_cursor = false; // Indicates that HWCursor pipe needs to be used for cursor layer
DestScaleInfoMap dest_scale_info_map = {};
+ HWHDRLayerInfo hdr_layer_info = {};
};
struct HWLayers {
diff --git a/sdm/libs/core/fb/hw_hdmi.cpp b/sdm/libs/core/fb/hw_hdmi.cpp
index f8cac1d..334a043 100644
--- a/sdm/libs/core/fb/hw_hdmi.cpp
+++ b/sdm/libs/core/fb/hw_hdmi.cpp
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2015 - 2016, The Linux Foundation. All rights reserved.
+* Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -36,6 +36,8 @@
#include <linux/videodev2.h>
#include <utils/debug.h>
#include <utils/sys.h>
+#include <utils/formats.h>
+
#include <vector>
#include <map>
#include <utility>
@@ -46,6 +48,104 @@
namespace sdm {
+#ifdef MDP_HDR_STREAM
+static int32_t GetEOTF(const GammaTransfer &transfer) {
+ int32_t mdp_transfer = -1;
+
+ switch (transfer) {
+ case Transfer_SMPTE_ST2084:
+ mdp_transfer = MDP_HDR_EOTF_SMTPE_ST2084;
+ break;
+ case Transfer_HLG:
+ mdp_transfer = MDP_HDR_EOTF_HLG;
+ break;
+ default:
+ DLOGW("Unknown Transfer: %d", transfer);
+ }
+
+ return mdp_transfer;
+}
+
+static int32_t GetColoriMetry(const LayerBuffer & layer_buffer) {
+ bool is_yuv = layer_buffer.flags.video;
+ int32_t colorimetry = -1;
+
+ if (is_yuv) {
+ switch (layer_buffer.color_metadata.colorPrimaries) {
+ case ColorPrimaries_BT601_6_525:
+ case ColorPrimaries_BT601_6_625:
+ colorimetry = MDP_COLORIMETRY_YCBCR_ITU_R_BT_601;
+ break;
+ case ColorPrimaries_BT709_5:
+ colorimetry = MDP_COLORIMETRY_YCBCR_ITU_R_BT_709;
+ break;
+ case ColorPrimaries_BT2020:
+ colorimetry = MDP_COLORIMETRY_YCBCR_ITU_R_BT_2020_YCBCR;
+ break;
+ default:
+ DLOGW("Unknown color primary = %d for YUV", layer_buffer.color_metadata.colorPrimaries);
+ }
+ }
+
+ return colorimetry;
+}
+
+static int32_t GetPixelEncoding(const LayerBuffer &layer_buffer) {
+ bool is_yuv = layer_buffer.flags.video;
+ int32_t mdp_pixel_encoding = -1;
+ mdp_pixel_encoding = MDP_PIXEL_ENCODING_RGB; // set RGB as default
+
+ if (is_yuv) {
+ switch (layer_buffer.format) {
+ case kFormatYCbCr420SemiPlanarVenus:
+ case kFormatYCbCr420SPVenusUbwc:
+ case kFormatYCbCr420Planar:
+ case kFormatYCrCb420Planar:
+ case kFormatYCrCb420PlanarStride16:
+ case kFormatYCbCr420SemiPlanar:
+ case kFormatYCrCb420SemiPlanar:
+ case kFormatYCbCr420P010:
+ case kFormatYCbCr420TP10Ubwc:
+ mdp_pixel_encoding = MDP_PIXEL_ENCODING_YCBCR_420;
+ break;
+ case kFormatYCbCr422H2V1Packed:
+ case kFormatYCrCb422H2V1SemiPlanar:
+ case kFormatYCrCb422H1V2SemiPlanar:
+ case kFormatYCbCr422H2V1SemiPlanar:
+ case kFormatYCbCr422H1V2SemiPlanar:
+ mdp_pixel_encoding = MDP_PIXEL_ENCODING_YCBCR_422;
+ break;
+ default: // other yuv formats
+ DLOGW("New YUV format = %d, need to add support", layer_buffer.format);
+ break;
+ }
+ }
+
+ return mdp_pixel_encoding;
+}
+static int32_t GetBitsPerComponent(const LayerBuffer &layer_buffer) {
+ bool is_yuv = layer_buffer.flags.video;
+ bool is_10_bit = Is10BitFormat(layer_buffer.format);
+ int32_t mdp_bpc = -1;
+
+ if (is_yuv) {
+ mdp_bpc = is_10_bit ? MDP_YUV_10_BPC : MDP_YUV_8_BPC;
+ } else {
+ mdp_bpc = is_10_bit ? MDP_RGB_10_BPC : MDP_RGB_8_BPC;
+ }
+
+ return mdp_bpc;
+}
+
+static uint32_t GetRange(const ColorRange &range) {
+ return ((range == Range_Full) ? MDP_DYNAMIC_RANGE_VESA : MDP_DYNAMIC_RANGE_CEA);
+}
+
+static uint32_t GetContentType(const LayerBuffer &layer_buffer) {
+ return (layer_buffer.flags.video ? MDP_CONTENT_TYPE_VIDEO : MDP_CONTENT_TYPE_GRAPHICS);
+}
+#endif
+
static bool MapHDMIDisplayTiming(const msm_hdmi_mode_timing_info *mode,
fb_var_screeninfo *info) {
if (!mode || !info) {
@@ -326,6 +426,15 @@
return HWDevice::Validate(hw_layers);
}
+DisplayError HWHDMI::Commit(HWLayers *hw_layers) {
+ DisplayError error = UpdateHDRMetaData(hw_layers);
+ if (error != kErrorNone) {
+ return error;
+ }
+
+ return HWDevice::Commit(hw_layers);
+}
+
DisplayError HWHDMI::GetHWScanInfo(HWScanInfo *scan_info) {
if (!scan_info) {
return kErrorParameters;
@@ -872,5 +981,84 @@
(display_attributes_.x_pixels / 2) : mixer_attributes_.width;
}
+DisplayError HWHDMI::UpdateHDRMetaData(HWLayers *hw_layers) {
+ const HWHDRLayerInfo &hdr_layer_info = hw_layers->info.hdr_layer_info;
+ if (!hw_panel_info_.hdr_enabled || hdr_layer_info.operation == HWHDRLayerInfo::kNoOp) {
+ return kErrorNone;
+ }
+
+ DisplayError error = kErrorNone;
+
+#ifdef MDP_HDR_STREAM
+ char hdr_stream_path[kMaxStringLength] = {};
+ snprintf(hdr_stream_path, sizeof(hdr_stream_path), "%s%d/hdr_stream", fb_path_, fb_node_index_);
+
+ int fd = Sys::open_(hdr_stream_path, O_WRONLY);
+ if (fd < 0) {
+ DLOGE("Failed to open %s with error %s", hdr_stream_path, strerror(errno));
+ return kErrorFileDescriptor;
+ }
+
+ Layer hdr_layer = {};
+ if (hdr_layer_info.operation == HWHDRLayerInfo::kSet && hdr_layer_info.layer_index > -1) {
+ hdr_layer = *(hw_layers->info.stack->layers.at(UINT32(hdr_layer_info.layer_index)));
+ }
+
+ const LayerBuffer *layer_buffer = &hdr_layer.input_buffer;
+ const MasteringDisplay &mastering_display = layer_buffer->color_metadata.masteringDisplayInfo;
+ const ContentLightLevel &light_level = layer_buffer->color_metadata.contentLightLevel;
+ const Primaries &primaries = mastering_display.primaries;
+
+ mdp_hdr_stream hdr_stream = {};
+ if (hdr_layer_info.operation == HWHDRLayerInfo::kSet) {
+ int32_t eotf = GetEOTF(layer_buffer->color_metadata.transfer);
+ hdr_stream.eotf = (eotf < 0) ? 0 : UINT32(eotf);
+ hdr_stream.white_point_x = primaries.whitePoint[0];
+ hdr_stream.white_point_y = primaries.whitePoint[1];
+ hdr_stream.display_primaries_x[0] = primaries.rgbPrimaries[0][0];
+ hdr_stream.display_primaries_y[0] = primaries.rgbPrimaries[0][1];
+ hdr_stream.display_primaries_x[1] = primaries.rgbPrimaries[1][0];
+ hdr_stream.display_primaries_y[1] = primaries.rgbPrimaries[1][1];
+ hdr_stream.display_primaries_x[2] = primaries.rgbPrimaries[2][0];
+ hdr_stream.display_primaries_y[2] = primaries.rgbPrimaries[2][1];
+ hdr_stream.min_luminance = mastering_display.minDisplayLuminance;
+ hdr_stream.max_luminance = mastering_display.maxDisplayLuminance/10000;
+ hdr_stream.max_content_light_level = light_level.maxContentLightLevel;
+ hdr_stream.max_average_light_level = light_level.minPicAverageLightLevel;
+ // DP related
+ int32_t pixel_encoding = GetPixelEncoding(hdr_layer.input_buffer);
+ hdr_stream.pixel_encoding = (pixel_encoding < 0) ? 0 : UINT32(pixel_encoding);
+ int32_t colorimetry = GetColoriMetry(hdr_layer.input_buffer);
+ hdr_stream.colorimetry = (colorimetry < 0) ? 0 : UINT32(colorimetry);
+ hdr_stream.range = GetRange(hdr_layer.input_buffer.color_metadata.range);
+ int32_t bits_per_component = GetBitsPerComponent(hdr_layer.input_buffer);
+ hdr_stream.bits_per_component = (bits_per_component < 0) ? 0 : UINT32(bits_per_component);
+ hdr_stream.content_type = GetContentType(hdr_layer.input_buffer);
+
+ DLOGV_IF(kTagDriverConfig, "HDR Stream : MaxDisplayLuminance = %d MinDisplayLuminance = %d\n"
+ "MaxContentLightLevel = %d MaxAverageLightLevel = %d Red_x = %d Red_y = %d Green_x = %d\n"
+ "Green_y = %d Blue_x = %d Blue_y = %d WhitePoint_x = %d WhitePoint_y = %d EOTF = %d\n"
+ "PixelEncoding = %d Colorimetry = %d Range = %d BPC = %d ContentType = %d",
+ hdr_stream.max_luminance, hdr_stream.min_luminance, hdr_stream.max_content_light_level,
+ hdr_stream.max_average_light_level, hdr_stream.display_primaries_x[0],
+ hdr_stream.display_primaries_y[0], hdr_stream.display_primaries_x[1],
+ hdr_stream.display_primaries_y[1], hdr_stream.display_primaries_x[2],
+ hdr_stream.display_primaries_y[2], hdr_stream.white_point_x, hdr_stream.white_point_x,
+ hdr_stream.eotf, hdr_stream.pixel_encoding, hdr_stream.colorimetry, hdr_stream.range,
+ hdr_stream.bits_per_component, hdr_stream.content_type);
+ }
+
+ const void *hdr_metadata = reinterpret_cast<const void*>(&hdr_stream);
+ ssize_t len = Sys::pwrite_(fd, hdr_metadata, sizeof(hdr_stream), 0);
+ if (len <= 0) {
+ DLOGE("Failed to write hdr_metadata");
+ error = kErrorUndefined;
+ }
+ Sys::close_(fd);
+#endif
+
+ return error;
+}
+
} // namespace sdm
diff --git a/sdm/libs/core/fb/hw_hdmi.h b/sdm/libs/core/fb/hw_hdmi.h
index ce9e597..625782e 100644
--- a/sdm/libs/core/fb/hw_hdmi.h
+++ b/sdm/libs/core/fb/hw_hdmi.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2015 - 2016, The Linux Foundation. All rights reserved.
+* Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
@@ -85,6 +85,7 @@
virtual DisplayError SetDisplayAttributes(uint32_t index);
virtual DisplayError GetConfigIndex(uint32_t mode, uint32_t *index);
virtual DisplayError Validate(HWLayers *hw_layers);
+ virtual DisplayError Commit(HWLayers *hw_layers);
virtual DisplayError SetS3DMode(HWS3DMode s3d_mode);
virtual DisplayError SetRefreshRate(uint32_t refresh_rate);
@@ -103,6 +104,7 @@
DisplayError GetPanelS3DMode();
bool IsSupportedS3DMode(HWS3DMode s3d_mode);
void UpdateMixerAttributes();
+ DisplayError UpdateHDRMetaData(HWLayers *hw_layers);
DisplayError GetDynamicFrameRateMode(uint32_t refresh_rate, uint32_t*mode,
DynamicFPSData *data, uint32_t *config_index);