sdm: Add HDR10+ support for DisplayPort displays

Add HDR10+ i.e., dynamic metadata support for DisplayPort displays.
- Query DRM Connector property.
- Convert dynamic metadata to VSIF packets for DP displays.

Change-Id: I816a7099d61bb8f93fa9b692fdec2a047b3c6110
CRs-fixed: 2450703
diff --git a/sdm/include/core/display_interface.h b/sdm/include/core/display_interface.h
index d55c964..9c19dc2 100644
--- a/sdm/include/core/display_interface.h
+++ b/sdm/include/core/display_interface.h
@@ -191,7 +191,8 @@
   bool underscan = false;              //!< If display support CE underscan.
   bool secure = false;                 //!< If this display is capable of handling secure content.
   bool is_cmdmode = false;             //!< If panel is command mode panel.
-  bool hdr_supported = false;          //!< if HDR is enabled
+  bool hdr_supported = false;          //!< If HDR10 is supported.
+  bool hdr_plus_supported = false;     //!< If HDR10+ is supported.
   bool hdr_metadata_type_one = false;  //!< Metadata type one obtained from HDR sink
   uint32_t hdr_eotf = 0;               //!< Electro optical transfer function
   float max_luminance = 0.0f;          //!< From Panel's peak luminance
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index 666ebec..16b250d 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -30,11 +30,12 @@
 #include <core/core_interface.h>
 #include <utils/locker.h>
 #include <utils/debug.h>
-#include <vector>
-#include <map>
-#include <string>
 #include <bitset>
+#include <map>
 #include <memory>
+#include <set>
+#include <string>
+#include <vector>
 
 namespace sdm {
 using std::string;
@@ -358,6 +359,7 @@
   uint32_t left_roi_count = 1;        // Number if ROI supported on left panel
   uint32_t right_roi_count = 1;       // Number if ROI supported on right panel
   bool hdr_enabled = false;           // HDR feature supported
+  bool hdr_plus_enabled = false;      // HDR10+ feature supported
   bool hdr_metadata_type_one = false;     // Static HDR metadata type one
   uint32_t hdr_eotf = 0;              // Electro optical transfer function
   float peak_luminance = 0.0f;        // Panel's peak luminance level
@@ -614,6 +616,10 @@
 
   int32_t layer_index = -1;
   HDROperation operation = kNoOp;
+  bool in_hdr_mode = false;  // True if already in HDR mode with static metadata.
+  bool blend_space_layer_changed = false;  // True if HDR layer's index changed.
+  std::set<uint32_t> hdr_layers;  // Non-tonemapped HDR layer indices.
+  std::vector<uint8_t> dyn_hdr_vsif_payload;  // Dynamic HDR VSIF data.
 };
 
 struct LayerExt {
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index eddef42..06fc300 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -471,13 +471,23 @@
   HWResourceInfo hw_resource_info = HWResourceInfo();
   hw_info_intf_->GetHWResourceInfo(&hw_resource_info);
   bool hdr_supported = hw_resource_info.has_hdr;
+  bool hdr_plus_supported = false;
   HWDisplayInterfaceInfo hw_disp_info = {};
   hw_info_intf_->GetFirstDisplayInterfaceType(&hw_disp_info);
   if (hw_disp_info.type == kHDMI) {
     hdr_supported = (hdr_supported && hw_panel_info_.hdr_enabled);
   }
 
+  // Built-in displays always support HDR10+ when the target supports HDR. For non-builtins, check
+  // panel capability.
+  if (kBuiltIn == display_type_) {
+    hdr_plus_supported = hdr_supported;
+  } else if (hdr_supported && hw_panel_info_.hdr_plus_enabled) {
+    hdr_plus_supported = true;
+  }
+
   fixed_info->hdr_supported = hdr_supported;
+  fixed_info->hdr_plus_supported = hdr_plus_supported;
   // Populate luminance values only if hdr will be supported on that display
   fixed_info->max_luminance = fixed_info->hdr_supported ? hw_panel_info_.peak_luminance: 0;
   fixed_info->average_luminance = fixed_info->hdr_supported ? hw_panel_info_.average_luminance : 0;
diff --git a/sdm/libs/core/drm/hw_tv_drm.cpp b/sdm/libs/core/drm/hw_tv_drm.cpp
index 4b2dc89..4e76872 100644
--- a/sdm/libs/core/drm/hw_tv_drm.cpp
+++ b/sdm/libs/core/drm/hw_tv_drm.cpp
@@ -220,6 +220,7 @@
 
   HWDeviceDRM::PopulateHWPanelInfo();
   hw_panel_info_.hdr_enabled = connector_info_.ext_hdr_prop.hdr_supported;
+  hw_panel_info_.hdr_plus_enabled = connector_info_.ext_hdr_prop.hdr_plus_supported;
   hw_panel_info_.hdr_metadata_type_one = connector_info_.ext_hdr_prop.hdr_metadata_type_one;
   hw_panel_info_.hdr_eotf = connector_info_.ext_hdr_prop.hdr_eotf;
 
@@ -245,8 +246,9 @@
   }
   hw_panel_info_.average_luminance = average_luminance;
 
-  DLOGI("TV Panel: %s, type_one = %d, eotf = %d, luminance[max = %f, min = %f, avg = %f]",
-        hw_panel_info_.hdr_enabled ? "HDR" : "Non-HDR", hw_panel_info_.hdr_metadata_type_one,
+  DLOGI("TV Panel: %s%s, type_one = %d, eotf = %d, luminance[max = %f, min = %f, avg = %f]",
+        hw_panel_info_.hdr_enabled ? "HDR" : "Non-HDR",
+        hw_panel_info_.hdr_plus_enabled ? "10+" : "", hw_panel_info_.hdr_metadata_type_one,
         hw_panel_info_.hdr_eotf, hw_panel_info_.peak_luminance, hw_panel_info_.blackness_level,
         hw_panel_info_.average_luminance);
 }
@@ -260,17 +262,16 @@
 }
 
 DisplayError HWTVDRM::UpdateHDRMetaData(HWLayers *hw_layers) {
-  static struct timeval hdr_reset_start, hdr_reset_end;
-  static bool reset_hdr_flag = false;
   const HWHDRLayerInfo &hdr_layer_info = hw_layers->info.hdr_layer_info;
   if (!hw_panel_info_.hdr_enabled) {
     return kErrorNone;
   }
 
   DisplayError error = kErrorNone;
+  HWHDRLayerInfo::HDROperation hdr_op = hdr_layer_info.operation;
 
   Layer hdr_layer = {};
-  if (hdr_layer_info.operation == HWHDRLayerInfo::kSet && hdr_layer_info.layer_index > -1) {
+  if (hdr_op == HWHDRLayerInfo::kSet && hdr_layer_info.layer_index > -1) {
     hdr_layer = *(hw_layers->info.stack->layers.at(UINT32(hdr_layer_info.layer_index)));
   }
 
@@ -279,10 +280,11 @@
   const ContentLightLevel &light_level = layer_buffer->color_metadata.contentLightLevel;
   const Primaries &primaries = mastering_display.primaries;
 
-  if (hdr_layer_info.operation == HWHDRLayerInfo::kSet) {
-    // Reset reset_hdr_flag to handle where there are two consecutive HDR video playbacks with not
+  if (hdr_op == HWHDRLayerInfo::kSet && hdr_layer_info.hdr_layers.size() == 1) {
+    // Reset reset_hdr_flag_ to handle where there are two consecutive HDR video playbacks with not
     // enough non-HDR frames in between to reset the HDR metadata.
-    reset_hdr_flag = false;
+    reset_hdr_flag_ = false;
+    in_multiset_ = false;
 
     int32_t eotf = GetEOTF(layer_buffer->color_metadata.transfer);
     hdr_metadata_.hdr_supported = 1;
@@ -297,36 +299,55 @@
     hdr_metadata_.display_primaries_x[2] = primaries.rgbPrimaries[2][0];
     hdr_metadata_.display_primaries_y[2] = primaries.rgbPrimaries[2][1];
     hdr_metadata_.min_luminance = mastering_display.minDisplayLuminance;
-    hdr_metadata_.max_luminance = mastering_display.maxDisplayLuminance/10000;
+    hdr_metadata_.max_luminance = mastering_display.maxDisplayLuminance;
     hdr_metadata_.max_content_light_level = light_level.maxContentLightLevel;
     hdr_metadata_.max_average_light_level = light_level.minPicAverageLightLevel;
+    if (hw_panel_info_.hdr_plus_enabled && hdr_layer_info.dyn_hdr_vsif_payload.size()) {
+      hdr_metadata_.hdr_plus_payload = reinterpret_cast<uint64_t>
+                                        (hdr_layer_info.dyn_hdr_vsif_payload.data());
+      hdr_metadata_.hdr_plus_payload_size = UINT32(hdr_layer_info.dyn_hdr_vsif_payload.size());
+    } else {
+      hdr_metadata_.hdr_plus_payload = reinterpret_cast<uint64_t>(nullptr);
+      hdr_metadata_.hdr_plus_payload_size = 0;
+    }
 
     drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, &hdr_metadata_);
-    DumpHDRMetaData(hdr_layer_info.operation);
-  } else if (hdr_layer_info.operation == HWHDRLayerInfo::kReset) {
+    DumpHDRMetaData(hdr_op);
+  } else if (hdr_op == HWHDRLayerInfo::kSet && !in_multiset_) {
+    // Special case to handle multiple HDR layers.
+    // If there are multiple HDR layers, then simply drop all metadata (which is optional) since
+    // content going in and out of view (e.g., video start/stop, scrolling video preview thumbnails)
+    // will cause flicker.
+    InitMaxHDRMetaData();
+    in_multiset_ = true;
+    drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, &hdr_metadata_);
+    DumpHDRMetaData(hdr_op);
+  } else if (hdr_op == HWHDRLayerInfo::kReset) {
     memset(&hdr_metadata_, 0, sizeof(hdr_metadata_));
     hdr_metadata_.hdr_supported = 1;
     hdr_metadata_.hdr_state = HDR_ENABLE;
-    reset_hdr_flag = true;
-    gettimeofday(&hdr_reset_start, NULL);
+    reset_hdr_flag_ = true;
+    in_multiset_ = false;
+    gettimeofday(&hdr_reset_start_, NULL);
 
     drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id, &hdr_metadata_);
-    DumpHDRMetaData(hdr_layer_info.operation);
-  } else if (hdr_layer_info.operation == HWHDRLayerInfo::kNoOp) {
+    DumpHDRMetaData(hdr_op);
+  } else if (hdr_op == HWHDRLayerInfo::kNoOp) {
     // TODO(user): This case handles the state transition from HDR_ENABLED to HDR_DISABLED.
     // As per HDMI spec requirement, we need to send zero metadata for atleast 2 sec after end of
     // playback. This timer calculates the 2 sec window after playback stops to stop sending HDR
     // metadata. This will be replaced with an idle timer implementation in the future.
-    if (reset_hdr_flag) {
-      gettimeofday(&hdr_reset_end, NULL);
-      float hdr_reset_time_start = ((hdr_reset_start.tv_sec*1000) + (hdr_reset_start.tv_usec/1000));
-      float hdr_reset_time_end = ((hdr_reset_end.tv_sec*1000) + (hdr_reset_end.tv_usec/1000));
+    if (reset_hdr_flag_) {
+      gettimeofday(&hdr_reset_end_, NULL);
+      float hdr_reset_time_start = ((hdr_reset_start_.tv_sec * 1000) +
+                                    (hdr_reset_start_.tv_usec / 1000));
+      float hdr_reset_time_end = ((hdr_reset_end_.tv_sec * 1000) + (hdr_reset_end_.tv_usec / 1000));
 
-      if (((hdr_reset_time_end-hdr_reset_time_start)/1000) >= MIN_HDR_RESET_WAITTIME) {
+      if (((hdr_reset_time_end - hdr_reset_time_start) / 1000) >= MIN_HDR_RESET_WAITTIME) {
         memset(&hdr_metadata_, 0, sizeof(hdr_metadata_));
         hdr_metadata_.hdr_supported = 1;
         hdr_metadata_.hdr_state = HDR_DISABLE;
-        reset_hdr_flag = false;
+        reset_hdr_flag_ = false;
 
         drm_atomic_intf_->Perform(DRMOps::CONNECTOR_SET_HDR_METADATA, token_.conn_id,
                                   &hdr_metadata_);
@@ -340,13 +361,44 @@
 void HWTVDRM::DumpHDRMetaData(HWHDRLayerInfo::HDROperation operation) {
   DLOGI("Operation = %d, HDR Metadata: 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",
+        "Green_y = %d Blue_x = %d Blue_y = %d WhitePoint_x = %d WhitePoint_y = %d EOTF = %d\n"
+        "HDR10+ payload size = %u\n",
         operation, hdr_metadata_.max_luminance, hdr_metadata_.min_luminance,
         hdr_metadata_.max_content_light_level, hdr_metadata_.max_average_light_level,
         hdr_metadata_.display_primaries_x[0], hdr_metadata_.display_primaries_y[0],
         hdr_metadata_.display_primaries_x[1], hdr_metadata_.display_primaries_y[1],
         hdr_metadata_.display_primaries_x[2], hdr_metadata_.display_primaries_y[2],
-        hdr_metadata_.white_point_x, hdr_metadata_.white_point_y, hdr_metadata_.eotf);
+        hdr_metadata_.white_point_x, hdr_metadata_.white_point_y, hdr_metadata_.eotf,
+        hdr_metadata_.hdr_plus_payload_size);
+}
+
+void HWTVDRM::InitMaxHDRMetaData() {
+  memset(&hdr_metadata_, 0, sizeof(hdr_metadata_));
+  hdr_metadata_.hdr_supported = 1;
+  hdr_metadata_.hdr_state = HDR_ENABLE;
+  hdr_metadata_.eotf = UINT32(GetEOTF(Transfer_SMPTE_ST2084));
+  // Rec. 2020 (ITU-R Recommendation BT.2020) RGB color space parameters
+  // +---------------+-----------------+-----------------------------------------------+
+  // |               |   White point   |                Primary colors                 |
+  // |  Color space  +--------+--------+-------+-------+-------+-------+-------+-------+
+  // |               |   xW   |   yW   |  xR   |  yR   |  xG   |  yG   |  xB   |  yB   |
+  // +---------------+--------+--------+-------+-------+-------+-------+-------+-------+
+  // | ITU-R BT.2020 | 0.3127 | 0.3290 | 0.708 | 0.292 | 0.170 | 0.797 | 0.131 | 0.046 |
+  // +---------------+--------+--------+-------+-------+-------+-------+-------+-------+
+  // Rec. 2020 D65 'CIE Standard Illuminant'.
+  hdr_metadata_.white_point_x = 15635;                // 0.31271 x 50000
+  hdr_metadata_.white_point_y = 16451;                // 0.32902 x 50000
+  // Rec. 2020 primaries.
+  hdr_metadata_.display_primaries_x[0] = 35400;       // 0.708 x 50000
+  hdr_metadata_.display_primaries_y[0] = 14600;       // 0.292 x 50000
+  hdr_metadata_.display_primaries_x[1] = 8500;        // 0.170 x 50000
+  hdr_metadata_.display_primaries_y[1] = 39850;       // 0.797 x 50000
+  hdr_metadata_.display_primaries_x[2] = 6550;        // 0.131 x 50000
+  hdr_metadata_.display_primaries_y[2] = 2300;        // 0.046 x 50000
+  hdr_metadata_.min_luminance = 0;                    // 0 nits
+  hdr_metadata_.max_luminance = 100000000;            // 10000 nits
+  hdr_metadata_.max_content_light_level = 100000000;  // 10000 nits brightest pixel in content
+  hdr_metadata_.max_average_light_level = 100000000;  // 10000 nits brightest frame in content
 }
 
 DisplayError HWTVDRM::PowerOn(const HWQosData &qos_data, int *release_fence) {
diff --git a/sdm/libs/core/drm/hw_tv_drm.h b/sdm/libs/core/drm/hw_tv_drm.h
index 39132ca..635c67a 100644
--- a/sdm/libs/core/drm/hw_tv_drm.h
+++ b/sdm/libs/core/drm/hw_tv_drm.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+* Copyright (c) 2017-2019, 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:
@@ -55,6 +55,7 @@
  private:
   DisplayError UpdateHDRMetaData(HWLayers *hw_layers);
   void DumpHDRMetaData(HWHDRLayerInfo::HDROperation operation);
+  void InitMaxHDRMetaData();
 
   static const int kBitRGB  = 20;
   static const int kBitYUV  = 21;
@@ -63,6 +64,10 @@
   const float kMinPeakLuminance = 300.0f;
   const float kMaxPeakLuminance = 1000.0f;
   drm_msm_ext_hdr_metadata hdr_metadata_ = {};
+  struct timeval hdr_reset_start_ = {};
+  struct timeval hdr_reset_end_ = {};
+  bool reset_hdr_flag_ = false;
+  bool in_multiset_ = false;
 };
 
 }  // namespace sdm