Merge "hwc: cwb: Fix typo causing incorrect variable usage"
diff --git a/sdm/libs/core/display_hdmi.cpp b/sdm/libs/core/display_hdmi.cpp
index e09959f..7d65e26 100644
--- a/sdm/libs/core/display_hdmi.cpp
+++ b/sdm/libs/core/display_hdmi.cpp
@@ -154,7 +154,7 @@
     return error;
   }
 
-  return kErrorNone;
+  return DisplayBase::ReconfigureDisplay();
 }
 
 bool DisplayHDMI::IsUnderscanSupported() {
diff --git a/sdm/libs/core/fb/hw_events.cpp b/sdm/libs/core/fb/hw_events.cpp
index 5ae53a4..4015796 100644
--- a/sdm/libs/core/fb/hw_events.cpp
+++ b/sdm/libs/core/fb/hw_events.cpp
@@ -80,7 +80,7 @@
 pollfd HWEvents::InitializePollFd(HWEventData *event_data) {
   char node_path[kMaxStringLength] = {0};
   char data[kMaxStringLength] = {0};
-  pollfd poll_fd;
+  pollfd poll_fd = {0};
   poll_fd.fd = -1;
 
   if (!strncmp(event_data->event_name, "thread_exit", strlen("thread_exit"))) {
diff --git a/sdm/libs/core/fb/hw_hdmi.cpp b/sdm/libs/core/fb/hw_hdmi.cpp
index d9116e6..1ecb7c2 100644
--- a/sdm/libs/core/fb/hw_hdmi.cpp
+++ b/sdm/libs/core/fb/hw_hdmi.cpp
@@ -695,13 +695,102 @@
   return kErrorNone;
 }
 
+DisplayError HWHDMI::GetDynamicFrameRateMode(uint32_t refresh_rate, uint32_t *mode,
+                                             DynamicFPSData *data, uint32_t *config_index) {
+  msm_hdmi_mode_timing_info *cur = NULL;
+  msm_hdmi_mode_timing_info *dst = NULL;
+  uint32_t i = 0;
+  int pre_refresh_rate_diff = 0;
+  bool pre_unstd_mode = false;
+
+  for (i = 0; i < hdmi_modes_.size(); i++) {
+    msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[i];
+    if (timing_mode->video_format == hdmi_modes_[active_config_index_]) {
+      cur = timing_mode;
+      break;
+    }
+  }
+
+  if (cur == NULL) {
+    DLOGE("can't find timing info for active config index(%d)", active_config_index_);
+    return kErrorUndefined;
+  }
+
+  if (cur->refresh_rate != frame_rate_) {
+    pre_unstd_mode = true;
+  }
+
+  if (i >= hdmi_modes_.size()) {
+    return kErrorNotSupported;
+  }
+
+  dst = cur;
+  pre_refresh_rate_diff = static_cast<int>(dst->refresh_rate) - static_cast<int>(refresh_rate);
+
+  for (i = 0; i < hdmi_modes_.size(); i++) {
+    msm_hdmi_mode_timing_info *timing_mode = &supported_video_modes_[i];
+    if (cur->active_h == timing_mode->active_h &&
+       cur->active_v == timing_mode->active_v &&
+       cur->pixel_formats == timing_mode->pixel_formats ) {
+      int cur_refresh_rate_diff = static_cast<int>(timing_mode->refresh_rate) -
+                                  static_cast<int>(refresh_rate);
+      if (abs(pre_refresh_rate_diff) > abs(cur_refresh_rate_diff)) {
+        pre_refresh_rate_diff = cur_refresh_rate_diff;
+        dst = timing_mode;
+      }
+    }
+  }
+
+  if (pre_refresh_rate_diff > kThresholdRefreshRate) {
+    return kErrorNotSupported;
+  }
+
+  GetConfigIndex(dst->video_format, config_index);
+
+  data->hor_front_porch = dst->front_porch_h;
+  data->hor_back_porch = dst->back_porch_h;
+  data->hor_pulse_width = dst->pulse_width_h;
+  data->clk_rate_hz = dst->pixel_freq;
+  data->fps = refresh_rate;
+
+  if (dst->front_porch_h != cur->front_porch_h) {
+    *mode = kModeHFP;
+  }
+
+  if (dst->refresh_rate != refresh_rate || dst->pixel_freq != cur->pixel_freq) {
+    if (*mode == kModeHFP) {
+      if (dst->refresh_rate != refresh_rate) {
+        *mode = kModeHFPCalcClock;
+      } else {
+        *mode = kModeClockHFP;
+      }
+    } else {
+        *mode = kModeClock;
+    }
+  }
+
+  if (pre_unstd_mode && (*mode == kModeHFP)) {
+    *mode = kModeClockHFP;
+  }
+
+  return kErrorNone;
+}
+
 DisplayError HWHDMI::SetRefreshRate(uint32_t refresh_rate) {
   char mode_path[kMaxStringLength] = {0};
   char node_path[kMaxStringLength] = {0};
-  uint32_t mode = kModeHFP;
+  uint32_t mode = kModeClock;
+  uint32_t config_index = 0;
+  DynamicFPSData data;
+  DisplayError error = kErrorNone;
 
   if (refresh_rate == frame_rate_) {
-    return kErrorNone;
+    return error;
+  }
+
+  error = GetDynamicFrameRateMode(refresh_rate, &mode, &data, &config_index);
+  if (error != kErrorNone) {
+    return error;
   }
 
   snprintf(mode_path, sizeof(mode_path), "%s%d/msm_fb_dfps_mode", fb_path_, fb_node_index_);
@@ -709,7 +798,7 @@
 
   int fd_mode = Sys::open_(mode_path, O_WRONLY);
   if (fd_mode < 0) {
-    DLOGE("Failed to open %s with error %s", node_path, strerror(errno));
+    DLOGE("Failed to open %s with error %s", mode_path, strerror(errno));
     return kErrorFileDescriptor;
   }
 
@@ -731,8 +820,14 @@
   }
 
   char refresh_rate_string[kMaxStringLength];
-  snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d", refresh_rate);
-  DLOGI_IF(kTagDriverConfig, "Setting refresh rate = %d", refresh_rate);
+  if (mode == kModeHFP || mode == kModeClock) {
+    snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d", data.fps);
+    DLOGI_IF(kTagDriverConfig, "Setting refresh rate = %d", data.fps);
+  } else {
+    snprintf(refresh_rate_string, sizeof(refresh_rate_string), "%d %d %d %d %d",
+             data.hor_front_porch, data.hor_back_porch, data.hor_pulse_width,
+             data.clk_rate_hz, data.fps);
+  }
   len = Sys::pwrite_(fd_node, refresh_rate_string, strlen(refresh_rate_string), 0);
   if (len < 0) {
     DLOGE("Failed to write %d with error %s", refresh_rate, strerror(errno));
@@ -741,15 +836,21 @@
   }
   Sys::close_(fd_node);
 
-  DisplayError error = ReadTimingInfo();
+  error = ReadTimingInfo();
   if (error != kErrorNone) {
     return error;
   }
 
-  GetDisplayAttributes(active_config_index_, &display_attributes_);
+  GetDisplayAttributes(config_index, &display_attributes_);
   UpdateMixerAttributes();
 
   frame_rate_ = refresh_rate;
+  active_config_index_ = config_index;
+
+  DLOGI_IF(kTagDriverConfig, "config_index(%d) Mode(%d) frame_rate(%d)",
+           config_index,
+           mode,
+           frame_rate_);
 
   return kErrorNone;
 }
diff --git a/sdm/libs/core/fb/hw_hdmi.h b/sdm/libs/core/fb/hw_hdmi.h
index d2bd658..8cedc93 100644
--- a/sdm/libs/core/fb/hw_hdmi.h
+++ b/sdm/libs/core/fb/hw_hdmi.h
@@ -51,9 +51,29 @@
     kModeVFP,
     // Switch framerate by tuning horizontal front porch
     kModeHFP,
+    // Switch framerate by tuning horizontal front porch and clock
+    kModeClockHFP,
+    // Switch framerate by tuning horizontal front porch and re-caculate clock
+    kModeHFPCalcClock,
     kModeMAX
   };
 
+  /**
+   * struct DynamicFPSData - defines dynamic fps related data
+   * @hor_front_porch: horizontal front porch
+   * @hor_back_porch: horizontal back porch
+   * @hor_pulse_width: horizontal pulse width
+   * @clk_rate_hz: panel clock rate in HZ
+   * @fps: frames per second
+   */
+  struct DynamicFPSData {
+    uint32_t hor_front_porch;
+    uint32_t hor_back_porch;
+    uint32_t hor_pulse_width;
+    uint32_t clk_rate_hz;
+    uint32_t fps;
+  };
+
   HWHDMI(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf);
   virtual DisplayError Init();
   virtual DisplayError Deinit();
@@ -87,6 +107,9 @@
   bool IsSupportedS3DMode(HWS3DMode s3d_mode);
   void UpdateMixerAttributes();
 
+  DisplayError GetDynamicFrameRateMode(uint32_t refresh_rate, uint32_t*mode,
+                                       DynamicFPSData *data, uint32_t *config_index);
+  static const int kThresholdRefreshRate = 1000;
   vector<uint32_t> hdmi_modes_;
   // Holds the hdmi timing information. Ex: resolution, fps etc.,
   vector<msm_hdmi_mode_timing_info> supported_video_modes_;
diff --git a/sdm/libs/hwc/hwc_display.cpp b/sdm/libs/hwc/hwc_display.cpp
index dd6f83a..883f2df 100644
--- a/sdm/libs/hwc/hwc_display.cpp
+++ b/sdm/libs/hwc/hwc_display.cpp
@@ -1321,7 +1321,12 @@
 
   for (uint i = 0; i < app_layer_count; i++) {
     Layer *layer = layer_stack_.layers[i];
-    if (layer->flags.updating && (layer->input_buffer->flags.video == true)) {
+    // TODO(user):disable DRC feature in S3D playbacl case.S3D video
+    // need play in dedicate resolution and fps, if DRC switch the
+    // mode to an non S3D supported mode, it would break S3D playback.
+    // Need figure out a way to make S3D and DRC co-exist.
+    if (layer->flags.updating && (layer->input_buffer->flags.video == true) &&
+       (layer->input_buffer->s3d_format == kS3dFormatNone)) {
       updating_count++;
     }
   }
diff --git a/sdm/libs/hwc/hwc_display.h b/sdm/libs/hwc/hwc_display.h
index 1dfface..df9056e 100644
--- a/sdm/libs/hwc/hwc_display.h
+++ b/sdm/libs/hwc/hwc_display.h
@@ -49,6 +49,14 @@
 
 class HWCDisplay : public DisplayEventHandler {
  public:
+  enum {
+    SET_METADATA_DYN_REFRESH_RATE,
+    SET_BINDER_DYN_REFRESH_RATE,
+    SET_DISPLAY_MODE,
+    SET_QDCM_SOLID_FILL_INFO,
+    UNSET_QDCM_SOLID_FILL_INFO,
+  };
+
   virtual ~HWCDisplay() { }
   virtual int Init();
   virtual int Deinit();
diff --git a/sdm/libs/hwc/hwc_display_external.cpp b/sdm/libs/hwc/hwc_display_external.cpp
index a1ad661..ed916d4 100644
--- a/sdm/libs/hwc/hwc_display_external.cpp
+++ b/sdm/libs/hwc/hwc_display_external.cpp
@@ -51,6 +51,7 @@
   uint32_t external_width = 0;
   uint32_t external_height = 0;
   int drc_enabled = 0;
+  int drc_reset_fps_enabled = 0;
   DisplayError error = kErrorNone;
 
   HWCDisplay *hwc_display_external = new HWCDisplayExternal(core_intf, hwc_procs, qservice);
@@ -89,6 +90,10 @@
   HWCDebugHandler::Get()->GetProperty("sdm.hdmi.drc_enabled", &(drc_enabled));
   reinterpret_cast<HWCDisplayExternal *>(hwc_display_external)->drc_enabled_ = drc_enabled;
 
+  HWCDebugHandler::Get()->GetProperty("sdm.hdmi.drc_reset_fps", &(drc_reset_fps_enabled));
+  reinterpret_cast<HWCDisplayExternal *>(hwc_display_external)->drc_reset_fps_enabled_ =
+                                                                drc_reset_fps_enabled;
+
   *hwc_display = hwc_display_external;
 
   return status;
@@ -131,16 +136,15 @@
 
   bool one_video_updating_layer = SingleVideoLayerUpdating(UINT32(content_list->numHwLayers - 1));
 
-  if (current_refresh_rate_ != metadata_refresh_rate_ && one_video_updating_layer && drc_enabled_) {
-    error = display_intf_->SetRefreshRate(metadata_refresh_rate_);
+  uint32_t refresh_rate = GetOptimalRefreshRate(one_video_updating_layer);
+  if (current_refresh_rate_ != refresh_rate) {
+    error = display_intf_->SetRefreshRate(refresh_rate);
+    if (error == kErrorNone) {
+      // On success, set current refresh rate to new refresh rate
+      current_refresh_rate_ = refresh_rate;
+    }
   }
 
-  if (error == kErrorNone) {
-    // On success, set current refresh rate to new refresh rate
-    current_refresh_rate_ = metadata_refresh_rate_;
-  }
-
-
   status = PrepareLayerStack(content_list);
   if (status) {
     return status;
@@ -248,6 +252,11 @@
   static const uint32_t mapping_fps[] = {59940, 60000, 60000, 59940, 60000, 50000, 59940, 60000};
   uint32_t frame_rate = (uint32_t)(fps * 1000);
 
+  // process non valid
+  if (frame_rate == 0) {
+    return current_refresh_rate_;
+  }
+
   int count = INT(sizeof(standard_fps) / sizeof(standard_fps[0]));
   for (int i = 0; i < count; i++) {
     // Most likely used for video, the fps for frames should be stable from video side.
@@ -269,10 +278,57 @@
 
 void HWCDisplayExternal::PrepareDynamicRefreshRate(Layer *layer) {
   if (layer->input_buffer->flags.video) {
-    metadata_refresh_rate_ = SanitizeRefreshRate(layer->frame_rate);
+    if (layer->frame_rate != 0) {
+      metadata_refresh_rate_ = SanitizeRefreshRate(layer->frame_rate);
+    } else {
+      metadata_refresh_rate_ = current_refresh_rate_;
+    }
     layer->frame_rate = current_refresh_rate_;
   }
 }
 
+void HWCDisplayExternal::ForceRefreshRate(uint32_t refresh_rate) {
+  if ((refresh_rate && (refresh_rate < min_refresh_rate_ || refresh_rate > max_refresh_rate_)) ||
+       force_refresh_rate_ == refresh_rate) {
+    // Cannot honor force refresh rate, as its beyond the range or new request is same
+    return;
+  }
+
+  force_refresh_rate_ = refresh_rate;
+}
+
+uint32_t HWCDisplayExternal::GetOptimalRefreshRate(bool one_updating_layer) {
+  if (force_refresh_rate_) {
+    return force_refresh_rate_;
+  } else if (one_updating_layer && drc_enabled_) {
+    return metadata_refresh_rate_;
+  }
+
+  if (drc_reset_fps_enabled_) {
+    DisplayConfigVariableInfo fb_config;
+    display_intf_->GetFrameBufferConfig(&fb_config);
+    return (fb_config.fps * 1000);
+  }
+
+  return current_refresh_rate_;
+}
+
+int HWCDisplayExternal::Perform(uint32_t operation, ...) {
+  va_list args;
+  va_start(args, operation);
+  int val = va_arg(args, int32_t);
+  va_end(args);
+  switch (operation) {
+    case SET_BINDER_DYN_REFRESH_RATE:
+      ForceRefreshRate(UINT32(val));
+      break;
+    default:
+      DLOGW("Invalid operation %d", operation);
+      return -EINVAL;
+  }
+
+  return 0;
+}
+
 }  // namespace sdm
 
diff --git a/sdm/libs/hwc/hwc_display_external.h b/sdm/libs/hwc/hwc_display_external.h
index c54f738..ac70489 100644
--- a/sdm/libs/hwc/hwc_display_external.h
+++ b/sdm/libs/hwc/hwc_display_external.h
@@ -40,11 +40,13 @@
   virtual int Prepare(hwc_display_contents_1_t *content_list);
   virtual int Commit(hwc_display_contents_1_t *content_list);
   virtual void SetSecureDisplay(bool secure_display_active);
+  virtual int Perform(uint32_t operation, ...);
 
  protected:
   virtual uint32_t RoundToStandardFPS(float fps);
   virtual void PrepareDynamicRefreshRate(Layer *layer);
   int drc_enabled_ = 0;
+  int drc_reset_fps_enabled_ = 0;
 
  private:
   HWCDisplayExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs,
@@ -52,6 +54,8 @@
   void ApplyScanAdjustment(hwc_rect_t *display_frame);
   static void GetDownscaleResolution(uint32_t primary_width, uint32_t primary_height,
                                      uint32_t *virtual_width, uint32_t *virtual_height);
+  void ForceRefreshRate(uint32_t refresh_rate);
+  uint32_t GetOptimalRefreshRate(bool one_updating_layer);
 };
 
 }  // namespace sdm
diff --git a/sdm/libs/hwc/hwc_display_primary.h b/sdm/libs/hwc/hwc_display_primary.h
index f25a877..7ae5b53 100644
--- a/sdm/libs/hwc/hwc_display_primary.h
+++ b/sdm/libs/hwc/hwc_display_primary.h
@@ -32,14 +32,6 @@
 
 class HWCDisplayPrimary : public HWCDisplay {
  public:
-  enum {
-    SET_METADATA_DYN_REFRESH_RATE,
-    SET_BINDER_DYN_REFRESH_RATE,
-    SET_DISPLAY_MODE,
-    SET_QDCM_SOLID_FILL_INFO,
-    UNSET_QDCM_SOLID_FILL_INFO,
-  };
-
   static int Create(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
                     hwc_procs_t const **hwc_procs, qService::QService *qservice,
                     HWCDisplay **hwc_display);
diff --git a/sdm/libs/hwc/hwc_session.cpp b/sdm/libs/hwc/hwc_session.cpp
index 95da143..b00968c 100644
--- a/sdm/libs/hwc/hwc_session.cpp
+++ b/sdm/libs/hwc/hwc_session.cpp
@@ -278,7 +278,7 @@
 
     if (hwc_session->color_mgr_) {
       HWCDisplay *primary_display = hwc_session->hwc_display_[HWC_DISPLAY_PRIMARY];
-      if (primary_display) {
+      if (primary_display && !hwc_session->is_hdmi_primary_) {
         int ret = hwc_session->color_mgr_->SolidFillLayersPrepare(displays, primary_display);
         if (ret)
           return 0;
@@ -1380,6 +1380,7 @@
 int HWCSession::HotPlugHandler(bool connected) {
   int status = 0;
   bool notify_hotplug = false;
+  bool refresh_screen = false;
 
   // To prevent sending events to client while a lock is held, acquire scope locks only within
   // below scope so that those get automatically unlocked after the scope ends.
@@ -1423,6 +1424,11 @@
           return -1;
         }
 
+        status = hwc_display_[HWC_DISPLAY_PRIMARY]->SetPowerMode(HWC_POWER_MODE_NORMAL);
+        if (status) {
+          DLOGE("power-on on primary failed with error = %d", status);
+        }
+
         is_hdmi_yuv_ = IsDisplayYUV(HWC_DISPLAY_PRIMARY);
 
         // Next, go ahead and enable vsync on external display. This is expliclity required
@@ -1435,6 +1441,7 @@
         }
         // Don't do hotplug notification for HDMI as primary case for now
         notify_hotplug = false;
+        refresh_screen = true;
       } else {
         if (hwc_display_[HWC_DISPLAY_EXTERNAL]) {
           DLOGE("HDMI is already connected");
@@ -1493,7 +1500,7 @@
     }
   }
 
-  if (connected && notify_hotplug) {
+  if (connected && (notify_hotplug || refresh_screen)) {
     // trigger screen refresh to ensure sufficient resources are available to process new
     // new display connection.
     hwc_procs_->invalidate(hwc_procs_);
diff --git a/sdm/libs/hwc2/hwc_color_manager.cpp b/sdm/libs/hwc2/hwc_color_manager.cpp
index 3075cbb..c40ec4b 100644
--- a/sdm/libs/hwc2/hwc_color_manager.cpp
+++ b/sdm/libs/hwc2/hwc_color_manager.cpp
@@ -166,158 +166,8 @@
   return ret;
 }
 
-bool HWCColorManager::SolidFillLayersPrepare(hwc_display_contents_1_t **displays,
-                                             HWCDisplay *hwc_display) {
-  SCOPE_LOCK(locker_);
-
-  // Query HWCColorManager if QDCM tool requesting SOLID_FILL mode.
-  uint32_t solid_fill_color = Get8BitsARGBColorValue(solid_fill_params_);
-  hwc_display_contents_1_t *layer_list = displays[HWC_DISPLAY_PRIMARY];
-
-  if (solid_fill_enable_ && solid_fill_layers_ && layer_list) {
-    // 1. shallow copy HWC_FRAMEBUFFER_TARGET layer info solid fill layer list.
-    solid_fill_layers_->hwLayers[1] = layer_list->hwLayers[layer_list->numHwLayers - 1];
-
-    // 2. continue the prepare<> on solid_fill_layers.
-    hwc_display->Perform(HWCDisplayPrimary::SET_QDCM_SOLID_FILL_INFO, solid_fill_color);
-    // TODO(user): Remove the display_contents generated here and
-    // use the solid fill layer support in HWC2 to set this up
-    // hwc_display->Prepare(solid_fill_layers_);  // RECT info included.
-
-    // 3. Set HWC_OVERLAY to all SF layers before returning to framework.
-    for (size_t i = 0; i < (layer_list->numHwLayers - 1); i++) {
-      hwc_layer_1_t *layer = &layer_list->hwLayers[i];
-      layer->compositionType = HWC_OVERLAY;
-    }
-
-    return true;
-  } else if (!solid_fill_enable_) {
-    hwc_display->Perform(HWCDisplayPrimary::UNSET_QDCM_SOLID_FILL_INFO, 0);
-  }
-
-  return false;
-}
-
-bool HWCColorManager::SolidFillLayersSet(hwc_display_contents_1_t **displays,
-                                         HWCDisplay *hwc_display) {
-  // Query HWCColorManager if QDCM tool requesting SOLID_FILL mode.
-  SCOPE_LOCK(locker_);
-  hwc_display_contents_1_t *layer_list = displays[HWC_DISPLAY_PRIMARY];
-  if (solid_fill_enable_ && solid_fill_layers_ && layer_list) {
-    // TODO(user): Present solid fill
-    // hwc_display->Commit(solid_fill_layers_);
-
-    // SurfaceFlinger layer stack is dropped in solid fill case and replaced with local layer stack
-    // Close acquire fence fds associated with SF layer stack
-    // Close release/retire fence fds returned along with local layer stack
-    for (size_t i = 0; i < (layer_list->numHwLayers - 1); i++) {
-      int &fence_fd = layer_list->hwLayers[i].acquireFenceFd;
-      if (fence_fd >= 0) {
-        close(fence_fd);
-        fence_fd = -1;
-      }
-    }
-
-    for (size_t i = 0; i < (solid_fill_layers_->numHwLayers - 1); i++) {
-      int &fence_fd = solid_fill_layers_->hwLayers[i].releaseFenceFd;
-      if (fence_fd >= 0) {
-        close(fence_fd);
-        fence_fd = -1;
-      }
-    }
-    if (solid_fill_layers_->retireFenceFd >= 0) {
-      close(solid_fill_layers_->retireFenceFd);
-      solid_fill_layers_->retireFenceFd = -1;
-    }
-
-    return true;
-  }
-
-  return false;
-}
-
-int HWCColorManager::CreateSolidFillLayers(HWCDisplay *hwc_display) {
-  int ret = 0;
-
-  if (!solid_fill_layers_) {
-    uint32_t size = sizeof(hwc_display_contents_1) + kNumSolidFillLayers * sizeof(hwc_layer_1_t);
-    uint32_t primary_width = 0;
-    uint32_t primary_height = 0;
-
-    hwc_display->GetMixerResolution(&primary_width, &primary_height);
-    uint8_t *buf = new uint8_t[size]();
-    // handle for solid fill layer with fd = -1.
-    private_handle_t *handle = new private_handle_t(-1, 0, private_handle_t::PRIV_FLAGS_FRAMEBUFFER,
-                                                    BUFFER_TYPE_UI, HAL_PIXEL_FORMAT_RGBA_8888,
-                                                    INT32(primary_width), INT32(primary_height));
-
-    if (!buf || !handle) {
-      DLOGE("Failed to allocate memory.");
-      if (buf)
-        delete[] buf;
-      if (handle)
-        delete handle;
-
-      return -ENOMEM;
-    }
-
-    solid_fill_layers_ = reinterpret_cast<hwc_display_contents_1 *>(buf);
-    hwc_layer_1_t &layer = solid_fill_layers_->hwLayers[0];
-    layer.handle = handle;
-  }
-
-  solid_fill_layers_->flags = HWC_GEOMETRY_CHANGED;
-  solid_fill_layers_->numHwLayers = kNumSolidFillLayers;
-  solid_fill_layers_->retireFenceFd = -1;
-  solid_fill_layers_->outbuf = NULL;
-  solid_fill_layers_->outbufAcquireFenceFd = -1;
-
-  hwc_layer_1_t &layer = solid_fill_layers_->hwLayers[0];
-  hwc_rect_t solid_fill_rect = {
-      INT(solid_fill_params_.rect.x), INT(solid_fill_params_.rect.y),
-      solid_fill_params_.rect.x + INT(solid_fill_params_.rect.width),
-      solid_fill_params_.rect.y + INT(solid_fill_params_.rect.height),
-  };
-
-  layer.compositionType = HWC_FRAMEBUFFER;
-  layer.blending = HWC_BLENDING_PREMULT;
-  layer.sourceCropf.left = solid_fill_params_.rect.x;
-  layer.sourceCropf.top = solid_fill_params_.rect.y;
-  layer.sourceCropf.right = UINT32(solid_fill_params_.rect.x) + solid_fill_params_.rect.width;
-  layer.sourceCropf.bottom = UINT32(solid_fill_params_.rect.y) + solid_fill_params_.rect.height;
-  layer.acquireFenceFd = -1;
-  layer.releaseFenceFd = -1;
-  layer.flags = 0;
-  layer.transform = 0;
-  layer.hints = 0;
-  layer.planeAlpha = 0xff;
-  layer.displayFrame = solid_fill_rect;
-  layer.visibleRegionScreen.numRects = 1;
-  layer.visibleRegionScreen.rects = &layer.displayFrame;
-  layer.surfaceDamage.numRects = 0;
-
-  return ret;
-}
-
-void HWCColorManager::DestroySolidFillLayers() {
-  if (solid_fill_layers_) {
-    hwc_layer_1_t &layer = solid_fill_layers_->hwLayers[0];
-    uint8_t *buf = reinterpret_cast<uint8_t *>(solid_fill_layers_);
-    private_handle_t const *hnd = reinterpret_cast<private_handle_t const *>(layer.handle);
-
-    if (hnd)
-      delete hnd;
-
-    if (buf)
-      delete[] buf;
-
-    solid_fill_layers_ = NULL;
-  }
-}
-
 int HWCColorManager::SetSolidFill(const void *params, bool enable, HWCDisplay *hwc_display) {
   SCOPE_LOCK(locker_);
-  int ret = 0;
 
   if (params) {
     solid_fill_params_ = *reinterpret_cast<const PPColorFillParams *>(params);
@@ -325,15 +175,21 @@
     solid_fill_params_ = PPColorFillParams();
   }
 
+  uint32_t solid_fill_color = Get8BitsARGBColorValue(solid_fill_params_);
   if (enable) {
-    // will create solid fill layers for rendering if not present.
-    ret = CreateSolidFillLayers(hwc_display);
-  } else {
-    DestroySolidFillLayers();
-  }
-  solid_fill_enable_ = enable;
+    LayerRect solid_fill_rect = {
+      FLOAT(solid_fill_params_.rect.x), FLOAT(solid_fill_params_.rect.y),
+      FLOAT(solid_fill_params_.rect.x) + FLOAT(solid_fill_params_.rect.width),
+      FLOAT(solid_fill_params_.rect.y) + FLOAT(solid_fill_params_.rect.height),
+    };
 
-  return ret;
+    hwc_display->Perform(HWCDisplayPrimary::SET_QDCM_SOLID_FILL_INFO, solid_fill_color);
+    hwc_display->Perform(HWCDisplayPrimary::SET_QDCM_SOLID_FILL_RECT, &solid_fill_rect);
+  } else {
+    hwc_display->Perform(HWCDisplayPrimary::UNSET_QDCM_SOLID_FILL_INFO, 0);
+  }
+
+  return 0;
 }
 
 int HWCColorManager::SetFrameCapture(void *params, bool enable, HWCDisplay *hwc_display) {
diff --git a/sdm/libs/hwc2/hwc_color_manager.h b/sdm/libs/hwc2/hwc_color_manager.h
new file mode 100644
index 0000000..130dca9
--- /dev/null
+++ b/sdm/libs/hwc2/hwc_color_manager.h
@@ -0,0 +1,141 @@
+/* Copyright (c) 2015-2016, The Linux Foundataion. 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_COLOR_MANAGER_H__
+#define __HWC_COLOR_MANAGER_H__
+
+#include <stdlib.h>
+#include <binder/Parcel.h>
+#include <powermanager/IPowerManager.h>
+#include <binder/BinderService.h>
+#include <core/sdm_types.h>
+#include <utils/locker.h>
+
+namespace sdm {
+
+// This macro defines name for display APIs interface wrapper library.
+// This macro shall be used to load library using dlopen().
+#define DISPLAY_API_INTERFACE_LIBRARY_NAME "libsdm-disp-apis.so"
+
+// This macro defines variable name of display color APIs function tables
+// This macro shall be used to specify name of the variable in dlsym().
+#define DISPLAY_API_FUNC_TABLES "display_color_apis_ftables"
+#define QDCM_DIAG_CLIENT_LIBRARY_NAME "libsdm-diag.so"
+#define INIT_QDCM_DIAG_CLIENT_NAME "QDCMDiagInit"
+#define DEINIT_QDCM_DIAG_CLIENT_NAME "QDCMDiagDeInit"
+
+typedef int (*QDCMDiagInit)(void *ftables);
+
+typedef int (*QDCMDiagDeInit)(void);
+
+// Class to encapsulte all details of managing QDCM operating mode.
+class HWCQDCMModeManager {
+ public:
+  static const uint32_t kSocketCMDMaxLength = 4096;
+  static const uint32_t kFullWakeLock = 0x0000001a;
+  static const uint32_t kAcquireCauseWakeup = 0x10000000;
+  static const uint32_t kONAfterRelease = 0x20000000;
+  enum ActiveFeatureID {
+    kCABLFeature,
+    kADFeature,
+    kSVIFeature,
+    kMaxNumActiveFeature,
+  };
+
+  struct ActiveFeatureCMD {
+    const char *cmd_on = NULL;
+    const char *cmd_off = NULL;
+    const char *cmd_query_status = NULL;
+    const char *running = NULL;
+    ActiveFeatureCMD(const char *arg1, const char *arg2, const char *arg3, const char *arg4)
+        : cmd_on(arg1), cmd_off(arg2), cmd_query_status(arg3), running(arg4) {}
+  };
+
+  static const ActiveFeatureCMD kActiveFeatureCMD[kMaxNumActiveFeature];
+
+ public:
+  static HWCQDCMModeManager *CreateQDCMModeMgr();
+  ~HWCQDCMModeManager();
+  int EnableQDCMMode(bool enable, HWCDisplay *hwc_display);
+
+ protected:
+  bool SendSocketCmd();
+  int AcquireAndroidWakeLock(bool enable);
+  int EnableActiveFeatures(bool enable);
+  int EnableActiveFeatures(bool enable, const ActiveFeatureCMD &cmds, bool *was_running);
+
+ private:
+  bool cabl_was_running_ = false;
+  int socket_fd_ = -1;
+  android::sp<android::IBinder> wakelock_token_ = NULL;
+  android::sp<android::IPowerManager> power_mgr_ = NULL;
+  uint32_t entry_timeout_ = 0;
+  static const char *const kSocketName;
+  static const char *const kTagName;
+  static const char *const kPackageName;
+};
+
+// Class to encapsulte all HWC/OS specific behaviours for ColorManager.
+class HWCColorManager {
+ public:
+  static const int kNumSolidFillLayers = 2;
+  static HWCColorManager *CreateColorManager();
+  static int CreatePayloadFromParcel(const android::Parcel &in, uint32_t *disp_id,
+                                     PPDisplayAPIPayload *sink);
+  static void MarshallStructIntoParcel(const PPDisplayAPIPayload &data,
+                                       android::Parcel *out_parcel);
+
+  ~HWCColorManager();
+  void DestroyColorManager();
+  int EnableQDCMMode(bool enable, HWCDisplay *hwc_display);
+  int SetSolidFill(const void *params, bool enable, HWCDisplay *hwc_display);
+  int SetFrameCapture(void *params, bool enable, HWCDisplay *hwc_display);
+
+ protected:
+  int CreateSolidFillLayers(HWCDisplay *hwc_display);
+  void DestroySolidFillLayers();
+  static uint32_t Get8BitsARGBColorValue(const PPColorFillParams &params);
+
+ private:
+  DynLib color_apis_lib_;
+  DynLib diag_client_lib_;
+  void *color_apis_ = NULL;
+  QDCMDiagInit qdcm_diag_init_ = NULL;
+  QDCMDiagDeInit qdcm_diag_deinit_ = NULL;
+  HWCQDCMModeManager *qdcm_mode_mgr_ = NULL;
+
+  PPColorFillParams solid_fill_params_;
+  HWCBufferAllocator *buffer_allocator_ = NULL;
+  BufferInfo buffer_info;
+  Locker locker_;
+};
+
+}  // namespace sdm
+
+#endif  // __HWC_COLOR_MANAGER_H__
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 1f0bd55..868b0f7 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -389,6 +389,16 @@
   layer_stack_.layers.push_back(client_target_->GetSDMLayer());
 }
 
+void HWCDisplay::BuildSolidFillStack() {
+  layer_stack_ = LayerStack();
+  display_rect_ = LayerRect();
+
+  layer_stack_.layers.push_back(solid_fill_layer_);
+  layer_stack_.flags.geometry_changed = 1U;
+  // Append client target to the layer stack
+  layer_stack_.layers.push_back(client_target_->GetSDMLayer());
+}
+
 HWC2::Error HWCDisplay::SetLayerZOrder(hwc2_layer_t layer_id, uint32_t z) {
   const auto map_layer = layer_map_.find(layer_id);
   if (map_layer == layer_map_.end()) {
@@ -1416,6 +1426,68 @@
   return ret;
 }
 
+void HWCDisplay::SolidFillPrepare() {
+  if (solid_fill_enable_) {
+    if (solid_fill_layer_ == NULL) {
+      // Create a dummy layer here
+      solid_fill_layer_ = new Layer();
+      solid_fill_layer_->input_buffer = new LayerBuffer();
+    }
+    uint32_t primary_width = 0, primary_height = 0;
+    GetMixerResolution(&primary_width, &primary_height);
+
+    LayerBuffer *layer_buffer = solid_fill_layer_->input_buffer;
+    layer_buffer->width = primary_width;
+    layer_buffer->height = primary_height;
+    layer_buffer->acquire_fence_fd = -1;
+    layer_buffer->release_fence_fd = -1;
+
+    LayerRect rect;
+    rect.top = 0; rect.left = 0;
+    rect.right = primary_width;
+    rect.bottom = primary_height;
+
+    solid_fill_layer_->composition = kCompositionGPU;
+    solid_fill_layer_->src_rect = rect;
+    solid_fill_layer_->dst_rect = rect;
+
+    solid_fill_layer_->blending = kBlendingPremultiplied;
+    solid_fill_layer_->solid_fill_color = solid_fill_color_;
+    solid_fill_layer_->frame_rate = 60;
+    solid_fill_layer_->visible_regions.push_back(solid_fill_layer_->dst_rect);
+    solid_fill_layer_->flags.updating = 1;
+    solid_fill_layer_->flags.solid_fill = true;
+  } else {
+    // delete the dummy layer
+    if (solid_fill_layer_) {
+      delete solid_fill_layer_->input_buffer;
+    }
+    delete solid_fill_layer_;
+    solid_fill_layer_ = NULL;
+  }
+
+  if (solid_fill_enable_ && solid_fill_layer_) {
+    BuildSolidFillStack();
+    MarkLayersForGPUBypass();
+  }
+
+  return;
+}
+
+void HWCDisplay::SolidFillCommit() {
+  if (solid_fill_enable_ && solid_fill_layer_) {
+    LayerBuffer *layer_buffer = solid_fill_layer_->input_buffer;
+    if (layer_buffer->release_fence_fd > 0) {
+      close(layer_buffer->release_fence_fd);
+      layer_buffer->release_fence_fd = -1;
+    }
+    if (layer_stack_.retire_fence_fd > 0) {
+      close(layer_stack_.retire_fence_fd);
+      layer_stack_.retire_fence_fd = -1;
+    }
+  }
+}
+
 int HWCDisplay::GetVisibleDisplayRect(hwc_rect_t *visible_rect) {
   if (!IsValid(display_rect_)) {
     return -EINVAL;
@@ -1456,7 +1528,7 @@
 bool HWCDisplay::SingleLayerUpdating(void) {
   uint32_t updating_count = 0;
 
-  for (uint i = 0; i < layer_set_.size(); i++) {
+  for (uint i = 0; i < layer_stack_.layers.size(); i++) {
     auto layer = layer_stack_.layers.at(i);
     if (layer->flags.updating) {
       updating_count++;
diff --git a/sdm/libs/hwc2/hwc_display.h b/sdm/libs/hwc2/hwc_display.h
index 277514d..880fca2 100644
--- a/sdm/libs/hwc2/hwc_display.h
+++ b/sdm/libs/hwc2/hwc_display.h
@@ -130,9 +130,12 @@
   int ToggleScreenUpdates(bool enable);
   int ColorSVCRequestRoute(const PPDisplayAPIPayload &in_payload, PPDisplayAPIPayload *out_payload,
                            PPPendingParams *pending_action);
+  void SolidFillPrepare();
+  void SolidFillCommit();
   DisplayClass GetDisplayClass();
   int GetVisibleDisplayRect(hwc_rect_t *rect);
   void BuildLayerStack(void);
+  void BuildSolidFillStack(void);
   HWCLayer *GetHWCLayer(hwc2_layer_t layer);
 
   // HWC2 APIs
@@ -249,6 +252,8 @@
   bool secure_display_active_ = false;
   bool skip_prepare_ = false;
   bool solid_fill_enable_ = false;
+  Layer *solid_fill_layer_ = NULL;
+  LayerRect solid_fill_rect_ = {};
   uint32_t solid_fill_color_ = 0;
   LayerRect display_rect_;
   bool validated_ = false;
diff --git a/sdm/libs/hwc2/hwc_display_primary.cpp b/sdm/libs/hwc2/hwc_display_primary.cpp
index 56ff335..7dac376 100644
--- a/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -174,6 +174,8 @@
 
   // Fill in the remaining blanks in the layers and add them to the SDM layerstack
   BuildLayerStack();
+  // Checks and replaces layer stack for solid fill
+  SolidFillPrepare();
 
   bool pending_output_dump = dump_frame_count_ && dump_output_to_file_;
 
@@ -224,9 +226,11 @@
     status = HWCDisplay::CommitLayerStack();
     if (status == HWC2::Error::None) {
       HandleFrameOutput();
+      SolidFillCommit();
       status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
     }
   }
+
   CloseAcquireFds();
   return status;
 }
@@ -276,28 +280,40 @@
 int HWCDisplayPrimary::Perform(uint32_t operation, ...) {
   va_list args;
   va_start(args, operation);
-  int val = va_arg(args, int32_t);
-  va_end(args);
+  int val = 0;
+  LayerRect *rect = NULL;
+
   switch (operation) {
     case SET_METADATA_DYN_REFRESH_RATE:
+      val = va_arg(args, int32_t);
       SetMetaDataRefreshRateFlag(val);
       break;
     case SET_BINDER_DYN_REFRESH_RATE:
+      val = va_arg(args, int32_t);
       ForceRefreshRate(UINT32(val));
       break;
     case SET_DISPLAY_MODE:
+      val = va_arg(args, int32_t);
       SetDisplayMode(UINT32(val));
       break;
     case SET_QDCM_SOLID_FILL_INFO:
+      val = va_arg(args, int32_t);
       SetQDCMSolidFillInfo(true, UINT32(val));
       break;
     case UNSET_QDCM_SOLID_FILL_INFO:
+      val = va_arg(args, int32_t);
       SetQDCMSolidFillInfo(false, UINT32(val));
       break;
+    case SET_QDCM_SOLID_FILL_RECT:
+      rect = va_arg(args, LayerRect*);
+      solid_fill_rect_ = *rect;
+      break;
     default:
       DLOGW("Invalid operation %d", operation);
+      va_end(args);
       return -EINVAL;
   }
+  va_end(args);
 
   return 0;
 }
diff --git a/sdm/libs/hwc2/hwc_display_primary.h b/sdm/libs/hwc2/hwc_display_primary.h
index 32d265e..ab46cde 100644
--- a/sdm/libs/hwc2/hwc_display_primary.h
+++ b/sdm/libs/hwc2/hwc_display_primary.h
@@ -45,6 +45,7 @@
     SET_DISPLAY_MODE,
     SET_QDCM_SOLID_FILL_INFO,
     UNSET_QDCM_SOLID_FILL_INFO,
+    SET_QDCM_SOLID_FILL_RECT,
   };
 
   static int Create(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
diff --git a/sdm/libs/hwc2/hwc_session.cpp b/sdm/libs/hwc2/hwc_session.cpp
index 9344ed6..30bc11c 100644
--- a/sdm/libs/hwc2/hwc_session.cpp
+++ b/sdm/libs/hwc2/hwc_session.cpp
@@ -382,10 +382,9 @@
   if (!device) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
-  // TODO(user): Handle solid fill layers
+
   auto status = HWC2::Error::BadDisplay;
   // TODO(user): Handle virtual display/HDMI concurrency
-
   if (hwc_session->hwc_display_[display]) {
     status = hwc_session->hwc_display_[display]->Present(out_retire_fence);
     // This is only indicative of how many times SurfaceFlinger posts