hwc2: Default handling for dataspaces

CRs-Fixed: 2030917
Bug: 35985399
Change-Id: Idb4aa9914da2f843cf76160afb337365c3c39ea2
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 30a1fee..0344199 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -61,6 +61,24 @@
   }
 }
 
+// This weight function is needed because the color primaries are not sorted by gamut size
+static ColorPrimaries WidestPrimaries(ColorPrimaries p1, ColorPrimaries p2) {
+  int weight = 10;
+  int lp1 = p1, lp2 = p2;
+  // TODO(user) add weight to other wide gamut primaries
+  if (lp1 == ColorPrimaries_BT2020) {
+    lp1 *= weight;
+  }
+  if (lp1 == ColorPrimaries_BT2020) {
+    lp2 *= weight;
+  }
+  if (lp1 >= lp2) {
+    return p1;
+  } else {
+    return p2;
+  }
+}
+
 HWCColorMode::HWCColorMode(DisplayInterface *display_intf) : display_intf_(display_intf) {}
 
 HWC2::Error HWCColorMode::Init() {
@@ -331,10 +349,12 @@
   return HWC2::Error::None;
 }
 
+
 void HWCDisplay::BuildLayerStack() {
   layer_stack_ = LayerStack();
   display_rect_ = LayerRect();
   metadata_refresh_rate_ = 0;
+  auto working_primaries = ColorPrimaries_BT709_5;
 
   // Add one layer for fb target
   // TODO(user): Add blit target layers
@@ -347,6 +367,14 @@
       layer->flags.solid_fill = true;
     }
 
+    if (!hwc_layer->SupportedDataspace()) {
+        layer->flags.skip = true;
+        DLOGW_IF(kTagStrategy, "Unsupported dataspace: 0x%x", hwc_layer->GetLayerDataspace());
+    }
+
+    working_primaries = WidestPrimaries(working_primaries,
+                                        layer->input_buffer.color_metadata.colorPrimaries);
+
     // set default composition as GPU for SDM
     layer->composition = kCompositionGPU;
 
@@ -425,6 +453,19 @@
 
     layer_stack_.layers.push_back(layer);
   }
+
+
+  for (auto hwc_layer : layer_set_) {
+    auto layer = hwc_layer->GetSDMLayer();
+    if (layer->input_buffer.color_metadata.colorPrimaries != working_primaries &&
+        !hwc_layer->SupportLocalConversion(working_primaries)) {
+      layer->flags.skip = true;
+    }
+    if (layer->flags.skip) {
+      layer_stack_.flags.skip_present = true;
+    }
+  }
+
   // TODO(user): Set correctly when SDM supports geometry_changes as bitmask
   layer_stack_.flags.geometry_changed = UINT32(geometry_changes_ > 0);
   // Append client target to the layer stack
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index aec44ad..a710543 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -221,8 +221,10 @@
 }
 
 HWC2::Error HWCLayer::SetLayerDataspace(int32_t dataspace) {
-  // TODO(user): Implement later
-  geometry_changes_ |= kDataspace;
+  if (dataspace_ != dataspace) {
+    geometry_changes_ |= kDataspace;
+    dataspace_ = dataspace;
+  }
   return HWC2::Error::None;
 }
 
@@ -491,8 +493,12 @@
 
 DisplayError HWCLayer::SetMetaData(const private_handle_t *pvt_handle, Layer *layer) {
   LayerBuffer *layer_buffer = &layer->input_buffer;
-  if (sdm::SetCSC(pvt_handle, &layer_buffer->color_metadata) != kErrorNone) {
-    return kErrorNotSupported;
+
+  // Only use color metadata if Android framework metadata is not set
+  if (dataspace_ == HAL_DATASPACE_UNKNOWN) {
+    if (sdm::SetCSC(pvt_handle, &layer_buffer->color_metadata) != kErrorNone) {
+      return kErrorNotSupported;
+    }
   }
 
   private_handle_t *handle = const_cast<private_handle_t *>(pvt_handle);
@@ -542,6 +548,121 @@
   return kErrorNone;
 }
 
+
+
+bool HWCLayer::SupportLocalConversion(ColorPrimaries working_primaries) {
+  if (layer_->input_buffer.color_metadata.colorPrimaries <= ColorPrimaries_BT601_6_525 &&
+      working_primaries <= ColorPrimaries_BT601_6_525) {
+    return true;
+  }
+  return false;
+}
+
+bool HWCLayer::SupportedDataspace() {
+  if (dataspace_ == HAL_DATASPACE_UNKNOWN) {
+    // Pick values from metadata
+    return true;
+  }
+
+  // Map deprecated dataspace values to appropriate
+  // new enums
+  if (dataspace_ & 0xffff) {
+    switch (dataspace_ & 0xffff) {
+      case HAL_DATASPACE_SRGB:
+        dataspace_ = HAL_DATASPACE_V0_SRGB;
+        break;
+      case HAL_DATASPACE_JFIF:
+        dataspace_ = HAL_DATASPACE_V0_JFIF;
+        break;
+      case HAL_DATASPACE_SRGB_LINEAR:
+        dataspace_ = HAL_DATASPACE_V0_SRGB_LINEAR;
+        break;
+      case HAL_DATASPACE_BT601_625:
+        dataspace_ = HAL_DATASPACE_V0_BT601_625;
+        break;
+      case HAL_DATASPACE_BT601_525:
+        dataspace_ = HAL_DATASPACE_V0_BT601_525;
+        break;
+      case HAL_DATASPACE_BT709:
+        dataspace_ = HAL_DATASPACE_V0_BT709;
+        break;
+      default:
+        // unknown legacy dataspace
+        DLOGE("Unsupported dataspace type %d", dataspace_);
+        return false;
+    }
+  }
+
+  LayerBuffer *layer_buffer = &layer_->input_buffer;
+
+  GammaTransfer sdm_transfer = {};
+  ColorPrimaries sdm_primaries = {};
+  ColorRange sdm_range = {};
+
+  auto transfer = (dataspace_ & HAL_DATASPACE_TRANSFER_MASK) >> HAL_DATASPACE_TRANSFER_SHIFT;
+  // Handle transfer
+  switch (transfer) {
+    case HAL_DATASPACE_TRANSFER_SRGB:
+      sdm_transfer = Transfer_sRGB;
+      break;
+    case HAL_DATASPACE_TRANSFER_SMPTE_170M:
+      sdm_transfer = Transfer_SMPTE_170M;
+      break;
+    case HAL_DATASPACE_TRANSFER_ST2084:
+      sdm_transfer = Transfer_SMPTE_ST2084;
+      break;
+    case HAL_DATASPACE_TRANSFER_HLG:
+      sdm_transfer = Transfer_HLG;
+      break;
+    default:
+      return false;
+  }
+
+  // Handle standard
+  auto standard = (dataspace_ & HAL_DATASPACE_STANDARD_MASK) >> HAL_DATASPACE_STANDARD_SHIFT;
+  switch (standard) {
+    case  HAL_DATASPACE_STANDARD_BT709:
+      sdm_primaries = ColorPrimaries_BT709_5;
+      break;
+    case HAL_DATASPACE_STANDARD_BT601_525:
+    case HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED:
+      sdm_primaries = ColorPrimaries_BT601_6_525;
+      break;
+    case HAL_DATASPACE_STANDARD_BT601_625:
+    case HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED:
+      sdm_primaries = ColorPrimaries_BT601_6_625;
+      break;
+    case HAL_DATASPACE_STANDARD_DCI_P3:
+      sdm_primaries = ColorPrimaries_DCIP3;
+      break;
+    case HAL_DATASPACE_BT2020:
+      sdm_primaries = ColorPrimaries_BT2020;
+      break;
+    default:
+      return false;
+  }
+  // TODO(user): Check transfer + primary combination
+
+  // Handle range
+  auto range = (dataspace_ & HAL_DATASPACE_RANGE_MASK) >> HAL_DATASPACE_RANGE_SHIFT;
+  switch (range) {
+    case HAL_DATASPACE_RANGE_FULL:
+      sdm_range = Range_Full;
+      break;
+    case HAL_DATASPACE_RANGE_LIMITED:
+    default:
+      sdm_range = Range_Limited;
+      break;
+  }
+
+  // If we got here, the value is supported, update the layer
+  layer_buffer->color_metadata.transfer = sdm_transfer;
+  layer_buffer->color_metadata.colorPrimaries = sdm_primaries;
+  layer_buffer->color_metadata.range = sdm_range;
+  return true;
+}
+
+
 uint32_t HWCLayer::RoundToStandardFPS(float fps) {
   static const uint32_t standard_fps[4] = {24, 30, 48, 60};
   uint32_t frame_rate = (uint32_t)(fps);
diff --git a/sdm/libs/hwc2/hwc_layers.h b/sdm/libs/hwc2/hwc_layers.h
index 58a45ae..bc3d84d 100644
--- a/sdm/libs/hwc2/hwc_layers.h
+++ b/sdm/libs/hwc2/hwc_layers.h
@@ -78,10 +78,13 @@
   HWC2::Composition GetClientRequestedCompositionType() { return client_requested_; }
   void UpdateClientCompositionType(HWC2::Composition type) { client_requested_ = type; }
   HWC2::Composition GetDeviceSelectedCompositionType() { return device_selected_; }
+  int32_t GetLayerDataspace() { return dataspace_; }
   uint32_t GetGeometryChanges() { return geometry_changes_; }
   void ResetGeometryChanges() { geometry_changes_ = GeometryChanges::kNone; }
   void PushReleaseFence(int32_t fence);
   int32_t PopReleaseFence(void);
+  bool SupportedDataspace();
+  bool SupportLocalConversion(ColorPrimaries working_primaries);
 
  private:
   Layer *layer_ = nullptr;
@@ -92,6 +95,7 @@
   std::queue<int32_t> release_fences_;
   int ion_fd_ = -1;
   HWCBufferAllocator *buffer_allocator_ = NULL;
+  int32_t dataspace_ =  HAL_DATASPACE_UNKNOWN;
 
   // Composition requested by client(SF)
   HWC2::Composition client_requested_ = HWC2::Composition::Device;