sdm: Add support for HDR

- Add LayerRequests to SDM Layer Interface, which will
  be used in informing any requests from SDM to client.
- Check for color metadata from client and handle
  HDR content.
- Include GPU Tonemapper to tonemap any requests
  coming from SDM

Change-Id: Idd1882ffab77fc3bff296114f36fb30bff4a4530
Crs-fixed: 1092142
diff --git a/sdm/include/core/layer_buffer.h b/sdm/include/core/layer_buffer.h
index 27a4f03..4b42e7b 100644
--- a/sdm/include/core/layer_buffer.h
+++ b/sdm/include/core/layer_buffer.h
@@ -203,6 +203,9 @@
       uint32_t secure_camera : 1;   //!< This flag shall be set by the client to indicate that the
                                     //!< buffer is associated with secure camera session. A secure
                                     //!< camera layer can co-exist with non-secure layer(s).
+
+      uint32_t hdr : 1;             //!< This flag shall be set by the client to indicate that the
+                                    //!< the content is HDR.
     };
 
     uint32_t flags = 0;             //!< For initialization purpose only.
diff --git a/sdm/include/core/layer_stack.h b/sdm/include/core/layer_stack.h
index 096e88f..701e3ca 100644
--- a/sdm/include/core/layer_stack.h
+++ b/sdm/include/core/layer_stack.h
@@ -179,6 +179,36 @@
   };
 };
 
+/*! @brief This structure defines flags associated with the layer requests. The 1-bit flag can be
+    set to ON(1) or OFF(0).
+
+  @sa Layer
+*/
+struct LayerRequestFlags {
+  union {
+    struct {
+      uint32_t tone_map : 1;  //!< This flag will be set by SDM when the layer needs tone map
+      uint32_t secure: 1;  //!< This flag will be set by SDM when the layer must be secure
+    };
+    uint32_t request_flags = 0;  //!< For initialization purpose only.
+                                 //!< Shall not be refered directly.
+  };
+};
+
+/*! @brief This structure defines LayerRequest.
+   Includes width/height/format of the LayerRequest.
+
+   SDM shall set the properties of LayerRequest to be used by the client
+
+  @sa LayerRequest
+*/
+struct LayerRequest {
+  LayerRequestFlags flags;  // Flags associated with this request
+  LayerBufferFormat format = kFormatRGBA8888;  // Requested format
+  uint32_t width = 0;
+  uint32_t height = 0;
+};
+
 /*! @brief This structure defines flags associated with a layer stack. The 1-bit flag can be set to
   ON(1) or OFF(0).
 
@@ -219,6 +249,8 @@
 
       uint32_t post_processed_output : 1;  // If output_buffer should contain post processed output
                                            // This applies only to primary displays currently
+
+      uint32_t hdr_present : 1;  //!< Set if stack has HDR content
     };
 
     uint32_t flags = 0;               //!< For initialization purpose only.
@@ -322,6 +354,11 @@
                                                    //!< no content is associated with the layer.
 
   LayerFlags flags;                                //!< Flags associated with this layer.
+
+  LayerRequest request = {};                       //!< o/p - request on this Layer by SDM.
+
+  Lut3d lut_3d = {};                               //!< o/p - Populated by SDM when tone mapping is
+                                                   //!< needed on this layer.
 };
 
 /*! @brief This structure defines a layer stack that contains layers which need to be composed and
diff --git a/sdm/include/private/strategy_interface.h b/sdm/include/private/strategy_interface.h
index 122a3c6..90e1064 100644
--- a/sdm/include/private/strategy_interface.h
+++ b/sdm/include/private/strategy_interface.h
@@ -53,6 +53,7 @@
                                    const HWMixerAttributes &mixer_attributes,
                                    const DisplayConfigVariableInfo &fb_config) = 0;
   virtual DisplayError SetCompositionState(LayerComposition composition_type, bool enable) = 0;
+  virtual DisplayError Purge() = 0;
 
  protected:
   virtual ~StrategyInterface() { }
diff --git a/sdm/include/utils/constants.h b/sdm/include/utils/constants.h
index 31129c1..72b1bed 100644
--- a/sdm/include/utils/constants.h
+++ b/sdm/include/utils/constants.h
@@ -71,6 +71,8 @@
   const int kMaxRotatePerLayer = 2;
   const uint32_t kMaxBlitTargetLayers = 2;
   const int kPageSize = 4096;
+  const uint32_t kGridSize = 129;  // size used for non-linear transformation before Tone-mapping
+  const uint32_t kLutDim = 17;  // Dim of the 3d LUT for tone-mapping.
 
   typedef void * Handle;
 
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
index 9fc44e0..199be86 100644
--- a/sdm/libs/core/comp_manager.cpp
+++ b/sdm/libs/core/comp_manager.cpp
@@ -382,6 +382,8 @@
                              reinterpret_cast<DisplayCompositionContext *>(display_ctx);
 
   resource_intf_->Purge(display_comp_ctx->display_resource_ctx);
+
+  display_comp_ctx->strategy->Purge();
 }
 
 void CompManager::ProcessIdleTimeout(Handle display_ctx) {
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 98513c4..77b6edc 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -104,6 +104,8 @@
                                display_attributes_, hw_panel_info_);
   if (!color_mgr_) {
     DLOGW("Unable to create ColorManagerProxy for display = %d", display_type_);
+  } else if (InitializeColorModes() != kErrorNone) {
+    DLOGW("InitColorModes failed for display = %d", display_type_);
   }
 
   return kErrorNone;
@@ -119,6 +121,9 @@
 DisplayError DisplayBase::Deinit() {
   lock_guard<recursive_mutex> obj(recursive_mutex_);
 
+  color_modes_.clear();
+  color_mode_map_.clear();
+
   if (color_mgr_) {
     delete color_mgr_;
     color_mgr_ = NULL;
@@ -216,6 +221,12 @@
     return error;
   }
 
+  error = HandleHDR(layer_stack);
+  if (error != kErrorNone) {
+    DLOGW("HandleHDR failed");
+    return error;
+  }
+
   if (color_mgr_ && color_mgr_->NeedsPartialUpdateDisable()) {
     DisablePartialUpdateOneFrame();
   }
@@ -659,11 +670,6 @@
     return kErrorNotSupported;
   }
 
-  DisplayError error = color_mgr_->ColorMgrGetNumOfModes(&num_color_modes_);
-  if (error != kErrorNone || !num_color_modes_) {
-    return kErrorNotSupported;
-  }
-
   DLOGV_IF(kTagQDCM, "Number of modes from color manager = %d", num_color_modes_);
   *mode_count = num_color_modes_;
 
@@ -681,30 +687,6 @@
     return kErrorNotSupported;
   }
 
-  if (!color_modes_.size()) {
-    color_modes_.resize(num_color_modes_);
-
-    DisplayError error = color_mgr_->ColorMgrGetModes(&num_color_modes_, color_modes_.data());
-    if (error != kErrorNone) {
-      DLOGE("Failed");
-      return error;
-    }
-
-    for (uint32_t i = 0; i < num_color_modes_; i++) {
-      DLOGV_IF(kTagQDCM, "Color Mode[%d]: Name = %s mode_id = %d", i, color_modes_[i].name,
-               color_modes_[i].id);
-      auto it = color_mode_map_.find(color_modes_[i].name);
-      if (it != color_mode_map_.end()) {
-        if (it->second->id < color_modes_[i].id) {
-          color_mode_map_.erase(it);
-          color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
-        }
-      } else {
-        color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
-      }
-    }
-  }
-
   for (uint32_t i = 0; i < num_color_modes_; i++) {
     DLOGV_IF(kTagQDCM, "Color Mode[%d]: Name = %s mode_id = %d", i, color_modes_[i].name,
              color_modes_[i].id);
@@ -720,6 +702,21 @@
     return kErrorNotSupported;
   }
 
+  DisplayError error = kErrorNone;
+  // Set client requests when not in HDR Mode.
+  if (!hdr_playback_mode_) {
+    error = SetColorModeInternal(color_mode);
+    if (error != kErrorNone) {
+      return error;
+    }
+  }
+  // Store the new color mode request by client
+  current_color_mode_ = color_mode;
+
+  return error;
+}
+
+DisplayError DisplayBase::SetColorModeInternal(const std::string &color_mode) {
   DLOGV_IF(kTagQDCM, "Color Mode = %s", color_mode.c_str());
 
   ColorModeMap::iterator it = color_mode_map_.find(color_mode);
@@ -730,7 +727,7 @@
 
   SDEDisplayMode *sde_display_mode = it->second;
 
-  DLOGD("Color Mode Name = %s corresponding mode_id = %d", sde_display_mode->name,
+  DLOGV_IF(kTagQDCM, "Color Mode Name = %s corresponding mode_id = %d", sde_display_mode->name,
            sde_display_mode->id);
   DisplayError error = kErrorNone;
   error = color_mgr_->ColorMgrSetMode(sde_display_mode->id);
@@ -1145,5 +1142,74 @@
   return;
 }
 
+DisplayError DisplayBase::InitializeColorModes() {
+  if (!color_mgr_) {
+    return kErrorNotSupported;
+  }
+
+  DisplayError error = color_mgr_->ColorMgrGetNumOfModes(&num_color_modes_);
+  if (error != kErrorNone || !num_color_modes_) {
+    DLOGV_IF(kTagQDCM, "GetNumModes failed = %d count = %d", error, num_color_modes_);
+    return kErrorNotSupported;
+  }
+  DLOGI("Number of Color Modes = %d", num_color_modes_);
+
+  if (!color_modes_.size()) {
+    color_modes_.resize(num_color_modes_);
+
+    DisplayError error = color_mgr_->ColorMgrGetModes(&num_color_modes_, color_modes_.data());
+    if (error != kErrorNone) {
+      color_modes_.clear();
+      DLOGE("Failed");
+      return error;
+    }
+
+    for (uint32_t i = 0; i < num_color_modes_; i++) {
+      DLOGV_IF(kTagQDCM, "Color Mode[%d]: Name = %s mode_id = %d", i, color_modes_[i].name,
+               color_modes_[i].id);
+      auto it = color_mode_map_.find(color_modes_[i].name);
+      if (it != color_mode_map_.end()) {
+        if (it->second->id < color_modes_[i].id) {
+          color_mode_map_.erase(it);
+          color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
+        }
+      } else {
+        color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
+      }
+    }
+  }
+
+  return kErrorNone;
+}
+
+DisplayError DisplayBase::HandleHDR(LayerStack *layer_stack) {
+  DisplayError error = kErrorNone;
+
+  if (!color_mgr_) {
+    // TODO(user): Handle the case where color_mgr is not present
+    return kErrorNone;
+  }
+
+  if (!layer_stack->flags.hdr_present) {
+    //  HDR playback off - set prev mode
+    if (hdr_playback_mode_) {
+      hdr_playback_mode_ = false;
+      DLOGI("Setting color mode = %s", current_color_mode_.c_str());
+      error = SetColorModeInternal(current_color_mode_);
+    // TODO(user): Enable DPPS
+    }
+  } else {
+    // hdr is present
+    if (!hdr_playback_mode_ && !layer_stack->flags.animating) {
+      // hdr is starting
+      hdr_playback_mode_ = true;
+      DLOGI("Setting HDR color mode = %s", hdr_color_mode_.c_str());
+      error = SetColorModeInternal(hdr_color_mode_);
+    }
+    // TODO(user): Disable DPPS
+  }
+
+  return error;
+}
 
 }  // namespace sdm
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index 4ea108e..85a1bc2 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -114,6 +114,7 @@
   virtual DisplayError ValidateGPUTargetParams();
   void CommitLayerParams(LayerStack *layer_stack);
   void PostCommitLayerParams(LayerStack *layer_stack);
+  DisplayError HandleHDR(LayerStack *layer_stack);
 
   // DumpImpl method
   void AppendDump(char *buffer, uint32_t length);
@@ -124,6 +125,8 @@
                                  uint32_t *new_mixer_height);
   DisplayError ReconfigureMixer(uint32_t width, uint32_t height);
   bool NeedsDownScale(const LayerRect &src_rect, const LayerRect &dst_rect, bool needs_rotation);
+  DisplayError InitializeColorModes();
+  DisplayError SetColorModeInternal(const std::string &color_mode);
 
   recursive_mutex recursive_mutex_;
   DisplayType display_type_;
@@ -155,6 +158,9 @@
   DisplayConfigVariableInfo fb_config_ = {};
   uint32_t req_mixer_width_ = 0;
   uint32_t req_mixer_height_ = 0;
+  std::string current_color_mode_ = "hal_native";
+  std::string hdr_color_mode_ = "hal_hdr";
+  bool hdr_playback_mode_ = false;
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/core/strategy.cpp b/sdm/libs/core/strategy.cpp
index f4a5088..c987fd0 100644
--- a/sdm/libs/core/strategy.cpp
+++ b/sdm/libs/core/strategy.cpp
@@ -137,6 +137,7 @@
   LayerStack *layer_stack = hw_layers_info_->stack;
   for (uint32_t i = 0; i < hw_layers_info_->app_layer_count; i++) {
     layer_stack->layers.at(i)->composition = kCompositionGPU;
+    layer_stack->layers.at(i)->request.flags.request_flags = 0;  // Reset layer request
   }
 
   if (!extn_start_success_) {
@@ -244,4 +245,13 @@
   return kErrorNone;
 }
 
+DisplayError Strategy::Purge() {
+  if (strategy_intf_) {
+    return strategy_intf_->Purge();
+  }
+
+  return kErrorNone;
+}
+
+
 }  // namespace sdm
diff --git a/sdm/libs/core/strategy.h b/sdm/libs/core/strategy.h
index 3fadd0d..a84d139 100644
--- a/sdm/libs/core/strategy.h
+++ b/sdm/libs/core/strategy.h
@@ -49,6 +49,7 @@
                            const HWMixerAttributes &mixer_attributes,
                            const DisplayConfigVariableInfo &fb_config);
   DisplayError SetCompositionState(LayerComposition composition_type, bool enable);
+  DisplayError Purge();
 
  private:
   void GenerateROI();
diff --git a/sdm/libs/hwc/Android.mk b/sdm/libs/hwc/Android.mk
index 259a727..d2828b4 100644
--- a/sdm/libs/hwc/Android.mk
+++ b/sdm/libs/hwc/Android.mk
@@ -15,7 +15,7 @@
 
 LOCAL_SHARED_LIBRARIES        := libsdmcore libqservice libbinder libhardware libhardware_legacy \
                                  libutils libcutils libsync libmemalloc libqdutils libdl \
-                                 libpowermanager libsdmutils libc++
+                                 libpowermanager libsdmutils libgpu_tonemapper  libc++
 
 LOCAL_SRC_FILES               := hwc_session.cpp \
                                  hwc_display.cpp \
@@ -28,7 +28,8 @@
                                  hwc_buffer_sync_handler.cpp \
                                  hwc_color_manager.cpp \
                                  blit_engine_c2d.cpp \
-                                 cpuhint.cpp
+                                 cpuhint.cpp \
+                                 hwc_tonemapper.cpp
 
 include $(BUILD_SHARED_LIBRARY)
 endif
diff --git a/sdm/libs/hwc/hwc_display.cpp b/sdm/libs/hwc/hwc_display.cpp
index 1108c39..305ed66 100644
--- a/sdm/libs/hwc/hwc_display.cpp
+++ b/sdm/libs/hwc/hwc_display.cpp
@@ -41,9 +41,10 @@
 #include <utility>
 #include <vector>
 
-#include "hwc_display.h"
-#include "hwc_debugger.h"
 #include "blit_engine_c2d.h"
+#include "hwc_debugger.h"
+#include "hwc_display.h"
+#include "hwc_tonemapper.h"
 
 #ifdef QTI_BSP
 #include <hardware/display_defs.h>
@@ -98,6 +99,9 @@
     }
   }
 
+  tone_mapper_ = new HWCToneMapper();
+  tone_mapper_->Init();
+
   display_intf_->GetRefreshRateRange(&min_refresh_rate_, &max_refresh_rate_);
   current_refresh_rate_ = max_refresh_rate_;
 
@@ -127,6 +131,9 @@
     blit_engine_ = NULL;
   }
 
+  delete tone_mapper_;
+  tone_mapper_ = NULL;
+
   return 0;
 }
 
@@ -172,6 +179,7 @@
     // Do not flush until a buffer is successfully submitted again.
     flush_on_error = false;
     state = kStateOff;
+    tone_mapper_->Terminate();
     break;
 
   case HWC_POWER_MODE_NORMAL:
@@ -273,6 +281,10 @@
     blit_engine_->SetFrameDumpConfig(count);
   }
 
+  if (tone_mapper_) {
+    tone_mapper_->SetFrameDumpConfig(count);
+  }
+
   DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
 }
 
@@ -702,6 +714,15 @@
       }
     }
 
+    if (layer_stack_.flags.hdr_present) {
+      status = tone_mapper_->HandleToneMap(content_list, &layer_stack_);
+      if (status != 0) {
+        DLOGE("Error handling HDR in ToneMapper");
+      }
+    } else {
+      tone_mapper_->Terminate();
+    }
+
     DisplayError error = kErrorUndefined;
     if (status == 0) {
       error = display_intf_->Commit(&layer_stack_);
@@ -738,6 +759,11 @@
     display_intf_->Flush();
   }
 
+
+  if (tone_mapper_ && tone_mapper_->IsActive()) {
+     tone_mapper_->PostCommit(&layer_stack_);
+  }
+
   // Set the release fence fd to the blit engine
   if (use_blit_comp_ && blit_engine_->BlitActive()) {
     blit_engine_->PostCommit(&layer_stack_);
@@ -1282,6 +1308,13 @@
     return kErrorNotSupported;
   }
 
+  if (layer_buffer.color_metadata.colorPrimaries == ColorPrimaries_BT2020 &&
+     (layer_buffer.color_metadata.transfer == Transfer_SMPTE_ST2084 ||
+      layer_buffer.color_metadata.transfer == Transfer_HLG)) {
+    layer_buffer.flags.hdr = true;
+    layer_stack_.flags.hdr_present = true;
+  }
+
   if (meta_data->operation & SET_IGC) {
     if (SetIGC(meta_data->igc, &layer_buffer.igc) != kErrorNone) {
       return kErrorNotSupported;
diff --git a/sdm/libs/hwc/hwc_display.h b/sdm/libs/hwc/hwc_display.h
index bf51222..dad78b6 100644
--- a/sdm/libs/hwc/hwc_display.h
+++ b/sdm/libs/hwc/hwc_display.h
@@ -36,6 +36,7 @@
 namespace sdm {
 
 class BlitEngine;
+class HWCToneMapper;
 
 // Subclasses set this to their type. This has to be different from DisplayType.
 // This is to avoid RTTI and dynamic_cast
@@ -217,6 +218,7 @@
   LayerRect display_rect_;
   std::map<int, LayerBufferS3DFormat> s3d_format_hwc_to_sdm_;
   bool animating_ = false;
+  HWCToneMapper *tone_mapper_ = NULL;
 
  private:
   void DumpInputBuffers(hwc_display_contents_1_t *content_list);
diff --git a/sdm/libs/hwc/hwc_tonemapper.cpp b/sdm/libs/hwc/hwc_tonemapper.cpp
new file mode 100644
index 0000000..694acc0
--- /dev/null
+++ b/sdm/libs/hwc/hwc_tonemapper.cpp
@@ -0,0 +1,290 @@
+/*
+* Copyright (c) 2016, 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:
+*  * Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+*  * Redistributions in binary form must reproduce the above
+*    copyright notice, this list of conditions and the following
+*    disclaimer in the documentation and/or other materials provided
+*    with the distribution.
+*  * Neither the name of The Linux Foundation nor the names of its
+*    contributors may be used to endorse or promote products derived
+*    from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <alloc_controller.h>
+#include <gr.h>
+#include <gralloc_priv.h>
+#include <memalloc.h>
+#include <sync/sync.h>
+
+#include <TonemapFactory.h>
+
+#include <core/buffer_allocator.h>
+
+#include <utils/constants.h>
+#include <utils/debug.h>
+#include <utils/formats.h>
+#include <utils/rect.h>
+
+#include <vector>
+
+#include "hwc_debugger.h"
+#include "hwc_tonemapper.h"
+
+#define __CLASS__ "HWCToneMapper"
+
+namespace sdm {
+
+int HWCToneMapper::Init() {
+  for (uint32_t i = 0; i < kNumIntermediateBuffers; i++) {
+    intermediate_buffer_[i] = NULL;
+    release_fence_fd_[i] = -1;
+  }
+  return 0;
+}
+
+void HWCToneMapper::DeInit() {
+  return;
+}
+
+int HWCToneMapper::HandleToneMap(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) {
+  uint32_t layer_count = UINT32(layer_stack->layers.size());
+  std::vector<uint32_t> tonemap_layer_index = {};
+  Layer *layer = NULL;
+  uint32_t i = 0;
+  uint32_t gpu_count = 0;
+  int fence_fd = -1;
+  int acquire_fd = -1;
+  int merged_fd = -1;
+  hwc_layer_1_t *hwc_layer = NULL;
+  const private_handle_t *dst_hnd = NULL;
+  const private_handle_t *src_hnd = NULL;
+
+  for (; i < layer_count; i++) {
+    layer = layer_stack->layers.at(i);
+    if (layer->request.flags.tone_map) {
+      tonemap_layer_index.push_back(i);
+      break;
+    }
+    if (layer->composition == kCompositionGPU) {
+      gpu_count++;
+    }
+  }
+
+  if (tonemap_layer_index.empty()) {
+    return 0;
+  }
+  // gpu count can be 0 when a layer is on FB and in next cycle it doesn't update and SDM marks
+  // it as SDE comp
+  if (gpu_count == 0) {
+    // TODO(akumarkr): Remove goto when added multiple instance support
+    // intermediate buffer can be null
+    goto update_fd;
+  }
+
+  if (intermediate_buffer_[0] == NULL) {
+    DLOGI("format = %d width = %d height = %d", layer->request.format, layer->request.width,
+         layer->request.height);
+     // TODO(akumarkr): use flags from LayerRequestFlags for format change etc.,
+     uint32_t usage = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | GRALLOC_USAGE_HW_TEXTURE |
+                      GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
+     AllocateIntermediateBuffers(layer->input_buffer.width, layer->input_buffer.height,
+                                 HAL_PIXEL_FORMAT_RGBA_8888, usage);
+  }
+  current_intermediate_buffer_index_ =
+    (current_intermediate_buffer_index_ + 1) % kNumIntermediateBuffers;
+
+  if (!gpu_tone_mapper_) {
+    Color10Bit *grid_entries = NULL;
+    int grid_size = 0;
+    if (layer->lut_3d.validGridEntries) {
+      grid_entries = layer->lut_3d.gridEntries;
+      grid_size = INT(layer->lut_3d.gridSize);
+    }
+    gpu_tone_mapper_ = TonemapperFactory_GetInstance(TONEMAP_INVERSE, layer->lut_3d.lutEntries,
+                                                     layer->lut_3d.dim, grid_entries, grid_size);
+    if (gpu_tone_mapper_ == NULL) {
+      DLOGE("Get Tonemapper failed");
+      return -1;
+    }
+  }
+
+  hwc_layer = &content_list->hwLayers[i];
+  dst_hnd = intermediate_buffer_[current_intermediate_buffer_index_];
+  src_hnd = static_cast<const private_handle_t *>(hwc_layer->handle);
+  acquire_fd = dup(layer->input_buffer.acquire_fence_fd);
+  buffer_sync_handler_.SyncMerge(acquire_fd, release_fence_fd_[current_intermediate_buffer_index_],
+                                 &merged_fd);
+  if (acquire_fd >= 0) {
+    CloseFd(&acquire_fd);
+  }
+
+  if (release_fence_fd_[current_intermediate_buffer_index_] >= 0) {
+    CloseFd(&release_fence_fd_[current_intermediate_buffer_index_]);
+  }
+  DTRACE_BEGIN("GPU_TM_BLIT");
+  fence_fd = gpu_tone_mapper_->blit(reinterpret_cast<const void *>(dst_hnd),
+                                    reinterpret_cast<const void *>(src_hnd), merged_fd);
+  DTRACE_END();
+
+
+  DumpToneMapOutput(&fence_fd);
+
+update_fd:
+  // Acquire fence will be closed by HWC Display
+  // Fence returned by GPU will be closed in PostCommit
+  layer->input_buffer.acquire_fence_fd = fence_fd;
+  layer->input_buffer.planes[0].fd = intermediate_buffer_[current_intermediate_buffer_index_]->fd;
+
+  active_ = true;
+
+  tonemap_layer_index.clear();
+
+  return 0;
+}
+
+int HWCToneMapper::AllocateIntermediateBuffers(uint32_t width, uint32_t height, uint32_t format,
+                                               uint32_t usage) {
+  int status = 0;
+  if (width <= 0 || height <= 0) {
+    return false;
+  }
+
+  for (uint32_t i = 0; i < kNumIntermediateBuffers; i++) {
+    status = alloc_buffer(&intermediate_buffer_[i], INT(width), INT(height), INT(format),
+                          INT(usage));
+    if (status < 0) {
+      DLOGE("Allocation of Intermediate Buffer failed");
+      FreeIntermediateBuffers();
+      break;
+    }
+  }
+
+  return status;
+}
+void HWCToneMapper::FreeIntermediateBuffers() {
+  if (!intermediate_buffer_[0]) {
+    return;
+  }
+  for (uint32_t i = 0; i < kNumIntermediateBuffers; i++) {
+    private_handle_t *buffer = intermediate_buffer_[i];
+    if (buffer) {
+      // Free the valid fence
+      if (release_fence_fd_[i] >= 0) {
+        CloseFd(&release_fence_fd_[i]);
+      }
+      free_buffer(buffer);
+      intermediate_buffer_[i] = NULL;
+    }
+  }
+}
+
+void HWCToneMapper::PostCommit(LayerStack *layer_stack) {
+  uint32_t layer_count = UINT32(layer_stack->layers.size());
+  std::vector<uint32_t> tonemap_layer_index = {};
+  Layer *layer = NULL;
+  int rel_fence_fd = -1;
+  bool has_tonemap = false;
+  uint32_t i;
+
+  for (i = 0; i < layer_count; i++) {
+    layer = layer_stack->layers.at(i);
+    if (layer->request.flags.tone_map) {
+      tonemap_layer_index.push_back(i);
+      has_tonemap = true;
+      break;
+    }
+  }
+
+  if (has_tonemap) {
+    LayerBuffer &layer_buffer = layer->input_buffer;
+
+    rel_fence_fd = layer_buffer.release_fence_fd;
+    // close the fd returned by GPU Tonemapper
+    CloseFd(&layer_buffer.acquire_fence_fd);
+
+    SetReleaseFence(rel_fence_fd);
+  }
+
+  active_ = false;
+}
+
+void HWCToneMapper::SetReleaseFence(int fd) {
+  CloseFd(&release_fence_fd_[current_intermediate_buffer_index_]);
+  // used to give to GPU tonemapper along with input layer fd
+  release_fence_fd_[current_intermediate_buffer_index_] = dup(fd);
+}
+
+void HWCToneMapper::CloseFd(int *fd) {
+  if (*fd >= 0) {
+    close(*fd);
+    *fd = -1;
+  }
+}
+
+void HWCToneMapper::Terminate() {
+  if (!gpu_tone_mapper_) {
+    return;
+  }
+  // fix this on multiple instance: only delete obj and call ToneMapperDestroy on deInit.
+  delete gpu_tone_mapper_;
+  gpu_tone_mapper_ = NULL;
+
+  TonemapperFactory_Destroy();
+  FreeIntermediateBuffers();
+  active_ = false;
+}
+
+void HWCToneMapper::SetFrameDumpConfig(uint32_t count) {
+  DLOGI("Dump FrameConfig count = %d", count);
+  dump_frame_count_ = count;
+  dump_frame_index_ = 0;
+}
+
+void HWCToneMapper::DumpToneMapOutput(int *acquire_fd) {
+  if (!dump_frame_count_) {
+    return;
+  }
+
+  private_handle_t *target_buffer = intermediate_buffer_[current_intermediate_buffer_index_];
+
+  if (*acquire_fd >= 0) {
+    int error = sync_wait(*acquire_fd, 1000);
+    if (error < 0) {
+      DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
+      return;
+    }
+  }
+
+  char dump_file_name[PATH_MAX];
+  size_t result = 0;
+  snprintf(dump_file_name, sizeof(dump_file_name), "/data/misc/display/frame_dump_primary"
+           "/tonemap_%d.raw", (dump_frame_index_));
+  FILE* fp = fopen(dump_file_name, "w+");
+  if (fp) {
+    DLOGI("base addr = %x", target_buffer->base);
+    result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp);
+    fclose(fp);
+  }
+  dump_frame_count_--;
+  dump_frame_index_++;
+  CloseFd(acquire_fd);
+}
+
+}  // namespace sdm
diff --git a/sdm/libs/hwc/hwc_tonemapper.h b/sdm/libs/hwc/hwc_tonemapper.h
new file mode 100644
index 0000000..7ed5373
--- /dev/null
+++ b/sdm/libs/hwc/hwc_tonemapper.h
@@ -0,0 +1,81 @@
+/*
+* Copyright (c) 2016, 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:
+*  * Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+*  * Redistributions in binary form must reproduce the above
+*    copyright notice, this list of conditions and the following
+*    disclaimer in the documentation and/or other materials provided
+*    with the distribution.
+*  * Neither the name of The Linux Foundation nor the names of its
+*    contributors may be used to endorse or promote products derived
+*    from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HWC_TONEMAPPER_H__
+#define __HWC_TONEMAPPER_H__
+
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <hardware/hwcomposer.h>
+
+#include <core/layer_stack.h>
+#include <utils/sys.h>
+
+#include "hwc_buffer_sync_handler.h"
+
+class Tonemapper;
+
+namespace sdm {
+
+class HWCToneMapper {
+ public:
+  HWCToneMapper() {}
+  ~HWCToneMapper() {}
+
+  int Init();
+  void DeInit();
+  int HandleToneMap(hwc_display_contents_1_t *content_list, LayerStack *layer_stack);
+  void Terminate();
+  void PostCommit(LayerStack *layer_stack);
+  bool IsActive() { return active_; }
+  void SetFrameDumpConfig(uint32_t count);
+
+ private:
+  int AllocateIntermediateBuffers(uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
+  void FreeIntermediateBuffers();
+  void SetReleaseFence(int fence_fd);
+  void CloseFd(int *fd);
+  void DumpToneMapOutput(int *acquire_fence);
+
+  static const uint32_t kNumIntermediateBuffers = 2;
+  bool active_ = false;
+
+  private_handle_t *intermediate_buffer_[kNumIntermediateBuffers] = {NULL, NULL};
+  uint32_t current_intermediate_buffer_index_ = 0;
+  int release_fence_fd_[kNumIntermediateBuffers];
+
+  HWCBufferSyncHandler buffer_sync_handler_ = {};
+  Tonemapper *gpu_tone_mapper_ = NULL;
+  uint32_t dump_frame_count_ = 0;
+  uint32_t dump_frame_index_ = 0;
+};
+
+}  // namespace sdm
+#endif  // __HWC_TONEMAPPER_H__
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 14d7014..f603f18 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -363,6 +363,13 @@
       }
     }
 
+    if (layer->color_metadata.colorPrimaries == ColorPrimaries_BT2020 &&
+       (layer->color_metadata.transfer == Transfer_SMPTE_ST2084 ||
+        layer->color_metadata.transfer == Transfer_HLG)) {
+      layer->flags.hdr = true;
+      layer_stack_.flags.hdr_present = true;
+    }
+
     if (layer->flags.skip) {
       layer_stack_.flags.skip_present = true;
     }