hwc2: Add support for HDR and HWC tonemapping

- Identify HDR layer in HWC, and add support to handle
  tonemap requests from  SDM
- Include hwc tonemapper which tonemaps layers using the
  gpu tonemapper
- Add hint in BufferAllocator to specify gfx client

Change-Id: I45a2182fa96e366600d81cdb4cb08bceff3bfcb8
Crs-fixed: 2036626
diff --git a/sdm/include/core/buffer_allocator.h b/sdm/include/core/buffer_allocator.h
index ccb9a1b..6d77bcd 100644
--- a/sdm/include/core/buffer_allocator.h
+++ b/sdm/include/core/buffer_allocator.h
@@ -54,6 +54,7 @@
   bool cache = false;                         //!< Specifies whether the buffer needs to be cache.
   bool secure_camera = false;                 //!< Specifies buffer to be allocated from specific
                                               //!< secure heap and with a specific alignment.
+  bool gfx_client = false;                    //!< Specifies whether buffer is used by gfx.
 };
 
 /*! @brief Holds the information about the allocated buffer.
diff --git a/sdm/libs/hwc2/Android.mk b/sdm/libs/hwc2/Android.mk
index 64f930e..219c19e 100644
--- a/sdm/libs/hwc2/Android.mk
+++ b/sdm/libs/hwc2/Android.mk
@@ -24,7 +24,8 @@
 
 LOCAL_SHARED_LIBRARIES        := libsdmcore libqservice libbinder libhardware libhardware_legacy \
                                  libutils libcutils libsync libqdutils libqdMetaData libdl \
-                                 libpowermanager libsdmutils libc++ liblog libgrallocutils
+                                 libpowermanager libsdmutils libc++ liblog libgrallocutils \
+                                 libui libgpu_tonemapper
 
 ifneq ($(TARGET_USES_GRALLOC1), true)
     LOCAL_SHARED_LIBRARIES += libmemalloc
@@ -41,7 +42,8 @@
                                  hwc_layers.cpp \
                                  hwc_callbacks.cpp \
                                  ../hwc/cpuhint.cpp \
-                                 ../hwc/hwc_socket_handler.cpp
+                                 ../hwc/hwc_socket_handler.cpp \
+                                 hwc_tonemapper.cpp
 
 ifneq ($(TARGET_USES_GRALLOC1), true)
     LOCAL_SRC_FILES += ../hwc/hwc_buffer_allocator.cpp
diff --git a/sdm/libs/hwc2/hwc_buffer_allocator.cpp b/sdm/libs/hwc2/hwc_buffer_allocator.cpp
index bdebc22..195e61e 100644
--- a/sdm/libs/hwc2/hwc_buffer_allocator.cpp
+++ b/sdm/libs/hwc2/hwc_buffer_allocator.cpp
@@ -80,6 +80,11 @@
     // Allocate uncached buffers
     alloc_flags |= GRALLOC_USAGE_PRIVATE_UNCACHED;
   }
+
+  if (buffer_config.gfx_client) {
+    alloc_flags |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
+  }
+
   uint64_t producer_usage = alloc_flags;
   uint64_t consumer_usage = alloc_flags;
   // CreateBuffer
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index cbad3d2..2b33777 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -40,6 +40,8 @@
 #include "hwc_display.h"
 #include "hwc_debugger.h"
 #include "blit_engine_c2d.h"
+#include "hwc_tonemapper.h"
+
 #ifndef USE_GRALLOC1
 #include <gr.h>
 #endif
@@ -366,6 +368,8 @@
     // TODO(user): Add blit engine when needed
   }
 
+  tone_mapper_ = new HWCToneMapper(buffer_allocator_);
+
   display_intf_->GetRefreshRateRange(&min_refresh_rate_, &max_refresh_rate_);
   current_refresh_rate_ = max_refresh_rate_;
   DLOGI("Display created with id: %d", id_);
@@ -386,6 +390,9 @@
     delete color_mode_;
   }
 
+  delete tone_mapper_;
+  tone_mapper_ = nullptr;
+
   return 0;
 }
 
@@ -499,6 +506,13 @@
       }
     }
 
+    if (layer->input_buffer.color_metadata.colorPrimaries == ColorPrimaries_BT2020 &&
+       (layer->input_buffer.color_metadata.transfer == Transfer_SMPTE_ST2084 ||
+       layer->input_buffer.color_metadata.transfer == Transfer_HLG)) {
+      layer->input_buffer.flags.hdr = true;
+      layer_stack_.flags.hdr_present = true;
+    }
+
     // TODO(user): Move to a getter if this is needed at other places
     hwc_rect_t scaled_display_frame = {INT(layer->dst_rect.left), INT(layer->dst_rect.top),
                                        INT(layer->dst_rect.right), INT(layer->dst_rect.bottom)};
@@ -643,6 +657,9 @@
       // Do not flush until a buffer is successfully submitted again.
       flush_on_error = false;
       state = kStateOff;
+      if (tone_mapper_) {
+        tone_mapper_->Terminate();
+      }
       break;
     case HWC2::PowerMode::On:
       state = kStateOn;
@@ -834,6 +851,10 @@
   dump_frame_index_ = 0;
   dump_input_layers_ = ((bit_mask_layer_type & (1 << INPUT_LAYER_DUMP)) != 0);
 
+  if (tone_mapper_) {
+    tone_mapper_->SetFrameDumpConfig(count);
+  }
+
   DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
 }
 
@@ -1050,6 +1071,17 @@
 
   if (!flush_) {
     DisplayError error = kErrorUndefined;
+    int status = 0;
+    if (tone_mapper_) {
+      if (layer_stack_.flags.hdr_present) {
+        status = tone_mapper_->HandleToneMap(&layer_stack_);
+        if (status != 0) {
+          DLOGE("Error handling HDR in ToneMapper");
+        }
+      } else {
+        tone_mapper_->Terminate();
+      }
+    }
     error = display_intf_->Commit(&layer_stack_);
     validated_ = false;
 
@@ -1080,6 +1112,10 @@
     display_intf_->Flush();
   }
 
+  if (tone_mapper_ && tone_mapper_->IsActive()) {
+     tone_mapper_->PostCommit(&layer_stack_);
+  }
+
   // TODO(user): No way to set the client target release fence on SF
   int32_t &client_target_release_fence =
       client_target_->GetSDMLayer()->input_buffer.release_fence_fd;
@@ -1131,6 +1167,8 @@
   geometry_changes_ = GeometryChanges::kNone;
   flush_ = false;
 
+  ClearRequestFlags();
+
   return status;
 }
 
@@ -1761,6 +1799,12 @@
   }
 }
 
+void HWCDisplay::ClearRequestFlags() {
+  for (Layer *layer : layer_stack_.layers) {
+    layer->request.flags = {};
+  }
+}
+
 std::string HWCDisplay::Dump() {
   std::ostringstream os;
   os << "-------------------------------" << std::endl;
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index c428ba2..fa077e5 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -39,6 +39,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
@@ -233,6 +234,7 @@
   bool IsLayerUpdating(const Layer *layer);
   uint32_t SanitizeRefreshRate(uint32_t req_refresh_rate);
   virtual void CloseAcquireFds();
+  virtual void ClearRequestFlags();
 
   enum {
     INPUT_LAYER_DUMP,
@@ -279,6 +281,7 @@
   bool validated_ = false;
   bool color_tranform_failed_ = false;
   HWCColorMode *color_mode_ = NULL;
+  HWCToneMapper *tone_mapper_ = nullptr;
 
  private:
   void DumpInputBuffers(void);
diff --git a/sdm/libs/hwc2/hwc_tonemapper.cpp b/sdm/libs/hwc2/hwc_tonemapper.cpp
new file mode 100644
index 0000000..887c24b
--- /dev/null
+++ b/sdm/libs/hwc2/hwc_tonemapper.cpp
@@ -0,0 +1,340 @@
+/*
+* Copyright (c) 2016 - 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:
+*  * 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 <gralloc_priv.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 <utils/utils.h>
+
+#include <vector>
+
+#include "hwc_debugger.h"
+#include "hwc_tonemapper.h"
+
+#define __CLASS__ "HWCToneMapper"
+
+namespace sdm {
+
+ToneMapSession::ToneMapSession(HWCBufferAllocator *buffer_allocator) :
+                buffer_allocator_(buffer_allocator) {
+  buffer_info_.resize(kNumIntermediateBuffers);
+}
+
+ToneMapSession::~ToneMapSession() {
+  delete gpu_tone_mapper_;
+  gpu_tone_mapper_ = nullptr;
+  FreeIntermediateBuffers();
+  buffer_info_.clear();
+}
+
+DisplayError ToneMapSession::AllocateIntermediateBuffers(const Layer *layer) {
+  DisplayError error = kErrorNone;
+  for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) {
+    BufferInfo &buffer_info = buffer_info_[i];
+    buffer_info.buffer_config.width = layer->request.width;
+    buffer_info.buffer_config.height = layer->request.height;
+    buffer_info.buffer_config.format = layer->request.format;
+    buffer_info.buffer_config.secure = layer->request.flags.secure;
+    buffer_info.buffer_config.gfx_client = true;
+    error = buffer_allocator_->AllocateBuffer(&buffer_info);
+    if (error != kErrorNone) {
+      FreeIntermediateBuffers();
+      return error;
+    }
+  }
+
+  return kErrorNone;
+}
+
+void ToneMapSession::FreeIntermediateBuffers() {
+  for (uint8_t i = 0; i < kNumIntermediateBuffers; i++) {
+    // Free the valid fence
+    if (release_fence_fd_[i] >= 0) {
+      CloseFd(&release_fence_fd_[i]);
+    }
+    BufferInfo &buffer_info = buffer_info_[i];
+    if (buffer_info.private_data) {
+      buffer_allocator_->FreeBuffer(&buffer_info);
+    }
+  }
+}
+
+void ToneMapSession::UpdateBuffer(int acquire_fence, LayerBuffer *buffer) {
+  // Acquire fence will be closed by HWC Display.
+  // Fence returned by GPU will be closed in PostCommit.
+  buffer->acquire_fence_fd = acquire_fence;
+  buffer->size = buffer_info_[current_buffer_index_].alloc_buffer_info.size;
+  buffer->planes[0].fd = buffer_info_[current_buffer_index_].alloc_buffer_info.fd;
+}
+
+void ToneMapSession::SetReleaseFence(int fd) {
+  CloseFd(&release_fence_fd_[current_buffer_index_]);
+  // Used to give to GPU tonemapper along with input layer fd
+  release_fence_fd_[current_buffer_index_] = dup(fd);
+}
+
+void ToneMapSession::SetToneMapConfig(Layer *layer) {
+  // HDR -> SDR is FORWARD and SDR - > HDR is INVERSE
+  tone_map_config_.type = layer->input_buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE;
+  tone_map_config_.colorPrimaries = layer->input_buffer.color_metadata.colorPrimaries;
+  tone_map_config_.transfer = layer->input_buffer.color_metadata.transfer;
+  tone_map_config_.secure = layer->request.flags.secure;
+  tone_map_config_.format = layer->request.format;
+}
+
+bool ToneMapSession::IsSameToneMapConfig(Layer *layer) {
+  LayerBuffer& buffer = layer->input_buffer;
+  private_handle_t *handle = static_cast<private_handle_t *>(buffer_info_[0].private_data);
+  int tonemap_type = buffer.flags.hdr ? TONEMAP_FORWARD : TONEMAP_INVERSE;
+
+  return ((tonemap_type == tone_map_config_.type) &&
+          (buffer.color_metadata.colorPrimaries == tone_map_config_.colorPrimaries) &&
+          (buffer.color_metadata.transfer == tone_map_config_.transfer) &&
+          (layer->request.flags.secure == tone_map_config_.secure) &&
+          (layer->request.format == tone_map_config_.format) &&
+          (layer->request.width == UINT32(handle->unaligned_width)) &&
+          (layer->request.height == UINT32(handle->unaligned_height)));
+}
+
+int HWCToneMapper::HandleToneMap(LayerStack *layer_stack) {
+  uint32_t gpu_count = 0;
+  DisplayError error = kErrorNone;
+
+  for (uint32_t i = 0; i < layer_stack->layers.size(); i++) {
+    uint32_t session_index = 0;
+    Layer *layer = layer_stack->layers.at(i);
+    if (layer->composition == kCompositionGPU) {
+      gpu_count++;
+    }
+
+    if (layer->request.flags.tone_map) {
+      switch (layer->composition) {
+      case kCompositionGPUTarget:
+        if (!gpu_count) {
+          // When all layers are on FrameBuffer and if they do not update in the next draw cycle,
+          // then SDM marks them for SDE Composition because the cached FB layer gets displayed.
+          // GPU count will be 0 in this case. Try to use the existing tone-mapped frame buffer.
+          // No ToneMap/Blit is required. Just update the buffer & acquire fence fd of FB layer.
+          if (!tone_map_sessions_.empty()) {
+            ToneMapSession *fb_tone_map_session = tone_map_sessions_.at(fb_session_index_);
+            fb_tone_map_session->UpdateBuffer(-1 /* acquire_fence */, &layer->input_buffer);
+            fb_tone_map_session->layer_index_ = INT(i);
+            fb_tone_map_session->acquired_ = true;
+            return 0;
+          }
+        }
+        error = AcquireToneMapSession(layer, &session_index);
+        fb_session_index_ = session_index;
+        break;
+      default:
+        error = AcquireToneMapSession(layer, &session_index);
+        break;
+      }
+
+      if (error != kErrorNone) {
+        Terminate();
+        return -1;
+      }
+
+      ToneMapSession *session = tone_map_sessions_.at(session_index);
+      ToneMap(layer, session);
+      session->layer_index_ = INT(i);
+    }
+  }
+
+  return 0;
+}
+
+void HWCToneMapper::ToneMap(Layer* layer, ToneMapSession *session) {
+  int fence_fd = -1;
+  int acquire_fd = -1;
+  int merged_fd = -1;
+
+  uint8_t buffer_index = session->current_buffer_index_;
+  const private_handle_t *dst_hnd = static_cast<private_handle_t *>
+                                    (session->buffer_info_[buffer_index].private_data);
+  const private_handle_t *src_hnd = reinterpret_cast<const private_handle_t *>
+                                    (layer->input_buffer.buffer_id);
+
+  // use and close the layer->input_buffer acquire fence fd.
+  acquire_fd = layer->input_buffer.acquire_fence_fd;
+  buffer_sync_handler_.SyncMerge(session->release_fence_fd_[buffer_index], acquire_fd, &merged_fd);
+
+  if (acquire_fd >= 0) {
+    CloseFd(&acquire_fd);
+  }
+
+  if (session->release_fence_fd_[buffer_index] >= 0) {
+    CloseFd(&session->release_fence_fd_[buffer_index]);
+  }
+
+  DTRACE_BEGIN("GPU_TM_BLIT");
+  fence_fd = session->gpu_tone_mapper_->blit(reinterpret_cast<const void *>(dst_hnd),
+                                             reinterpret_cast<const void *>(src_hnd), merged_fd);
+  DTRACE_END();
+
+  DumpToneMapOutput(session, &fence_fd);
+  session->UpdateBuffer(fence_fd, &layer->input_buffer);
+}
+
+void HWCToneMapper::PostCommit(LayerStack *layer_stack) {
+  auto it = tone_map_sessions_.begin();
+  while (it != tone_map_sessions_.end()) {
+    uint32_t session_index = UINT32(std::distance(tone_map_sessions_.begin(), it));
+    ToneMapSession *session = tone_map_sessions_.at(session_index);
+    if (session->acquired_) {
+      Layer *layer = layer_stack->layers.at(UINT32(session->layer_index_));
+      // Close the fd returned by GPU ToneMapper and set release fence.
+      LayerBuffer &layer_buffer = layer->input_buffer;
+      CloseFd(&layer_buffer.acquire_fence_fd);
+      session->SetReleaseFence(layer_buffer.release_fence_fd);
+      session->acquired_ = false;
+      it++;
+    } else {
+      delete session;
+      it = tone_map_sessions_.erase(it);
+    }
+  }
+}
+
+void HWCToneMapper::Terminate() {
+  if (tone_map_sessions_.size()) {
+    while (!tone_map_sessions_.empty()) {
+      delete tone_map_sessions_.back();
+      tone_map_sessions_.pop_back();
+    }
+    fb_session_index_ = 0;
+  }
+}
+
+void HWCToneMapper::SetFrameDumpConfig(uint32_t count) {
+  DLOGI("Dump FrameConfig count = %d", count);
+  dump_frame_count_ = count;
+  dump_frame_index_ = 0;
+}
+
+void HWCToneMapper::DumpToneMapOutput(ToneMapSession *session, int *acquire_fd) {
+  if (!dump_frame_count_) {
+    return;
+  }
+
+  BufferInfo &buffer_info = session->buffer_info_[session->current_buffer_index_];
+  private_handle_t *target_buffer = static_cast<private_handle_t *>(buffer_info.private_data);
+
+  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;
+    }
+  }
+
+  size_t result = 0;
+  char dump_file_name[PATH_MAX];
+  snprintf(dump_file_name, sizeof(dump_file_name), "/data/misc/display/frame_dump_primary"
+           "/tonemap_%dx%d_frame%d.raw", target_buffer->width, target_buffer->height,
+           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);
+}
+
+DisplayError HWCToneMapper::AcquireToneMapSession(Layer *layer, uint32_t *session_index) {
+  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);
+  }
+
+  // When the property sdm.disable_hdr_lut_gen is set, the lutEntries and gridEntries in
+  // the Lut3d will be NULL, clients needs to allocate the memory and set correct 3D Lut
+  // for Tonemapping.
+  if (!layer->lut_3d.lutEntries || !layer->lut_3d.dim) {
+    // Atleast lutEntries must be valid for GPU Tonemapper.
+    DLOGE("Invalid Lut Entries or lut dimension = %d", layer->lut_3d.dim);
+    return kErrorParameters;
+  }
+
+  // Check if we can re-use an existing tone map session.
+  for (uint32_t i = 0; i < tone_map_sessions_.size(); i++) {
+    ToneMapSession *tonemap_session = tone_map_sessions_.at(i);
+    if (!tonemap_session->acquired_ && tonemap_session->IsSameToneMapConfig(layer)) {
+      tonemap_session->current_buffer_index_ = (tonemap_session->current_buffer_index_ + 1) %
+                                                ToneMapSession::kNumIntermediateBuffers;
+      tonemap_session->acquired_ = true;
+      *session_index = i;
+      return kErrorNone;
+    }
+  }
+
+  ToneMapSession *session = new ToneMapSession(buffer_allocator_);
+
+  session->SetToneMapConfig(layer);
+  session->gpu_tone_mapper_ = TonemapperFactory_GetInstance(session->tone_map_config_.type,
+                                                            layer->lut_3d.lutEntries,
+                                                            layer->lut_3d.dim,
+                                                            grid_entries, grid_size);
+
+  if (session->gpu_tone_mapper_ == NULL) {
+    DLOGE("Get Tonemapper failed!");
+    delete session;
+    return kErrorNotSupported;
+  }
+  DisplayError error = session->AllocateIntermediateBuffers(layer);
+  if (error != kErrorNone) {
+    DLOGE("Allocation of Intermediate Buffers failed!");
+    delete session;
+    return error;
+  }
+
+  session->acquired_ = true;
+  tone_map_sessions_.push_back(session);
+  *session_index = UINT32(tone_map_sessions_.size() - 1);
+
+  return kErrorNone;
+}
+
+}  // namespace sdm
diff --git a/sdm/libs/hwc2/hwc_tonemapper.h b/sdm/libs/hwc2/hwc_tonemapper.h
new file mode 100644
index 0000000..8367c3e
--- /dev/null
+++ b/sdm/libs/hwc2/hwc_tonemapper.h
@@ -0,0 +1,103 @@
+/*
+* Copyright (c) 2016 - 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:
+*  * 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 <vector>
+#include "hwc_buffer_sync_handler.h"
+#include "hwc_buffer_allocator.h"
+
+class Tonemapper;
+
+namespace sdm {
+
+struct ToneMapConfig {
+  int type = 0;
+  ColorPrimaries colorPrimaries = ColorPrimaries_Max;
+  GammaTransfer transfer = Transfer_Max;
+  LayerBufferFormat format = kFormatRGBA8888;
+  bool secure = false;
+};
+
+class ToneMapSession {
+ public:
+  explicit ToneMapSession(HWCBufferAllocator *buffer_allocator);
+  ~ToneMapSession();
+  DisplayError AllocateIntermediateBuffers(const Layer *layer);
+  void FreeIntermediateBuffers();
+  void UpdateBuffer(int acquire_fence, LayerBuffer *buffer);
+  void SetReleaseFence(int fd);
+  void SetToneMapConfig(Layer *layer);
+  bool IsSameToneMapConfig(Layer *layer);
+
+  static const uint8_t kNumIntermediateBuffers = 2;
+  Tonemapper *gpu_tone_mapper_ = nullptr;
+  HWCBufferAllocator *buffer_allocator_ = nullptr;
+  ToneMapConfig tone_map_config_ = {};
+  uint8_t current_buffer_index_ = 0;
+  std::vector<BufferInfo> buffer_info_ = {};
+  int release_fence_fd_[kNumIntermediateBuffers] = {-1, -1};
+  bool acquired_ = false;
+  int layer_index_ = -1;
+};
+
+class HWCToneMapper {
+ public:
+  explicit HWCToneMapper(HWCBufferAllocator *allocator) : buffer_allocator_(allocator) {}
+  ~HWCToneMapper() {}
+
+  int HandleToneMap(LayerStack *layer_stack);
+  bool IsActive() { return !tone_map_sessions_.empty(); }
+  void PostCommit(LayerStack *layer_stack);
+  void SetFrameDumpConfig(uint32_t count);
+  void Terminate();
+
+ private:
+  void ToneMap(Layer *layer, ToneMapSession *session);
+  DisplayError AcquireToneMapSession(Layer *layer, uint32_t *session_index);
+  void DumpToneMapOutput(ToneMapSession *session, int *acquire_fence);
+
+  std::vector<ToneMapSession*> tone_map_sessions_;
+  HWCBufferSyncHandler buffer_sync_handler_ = {};
+  HWCBufferAllocator *buffer_allocator_ = nullptr;
+  uint32_t dump_frame_count_ = 0;
+  uint32_t dump_frame_index_ = 0;
+  uint32_t fb_session_index_ = 0;
+};
+
+}  // namespace sdm
+#endif  // __HWC_TONEMAPPER_H__