display: msm8996: Update display HAL to SU27 + HWC2 specific commits

display_hal:
75f1caf sdm: hwc2: Handle Tranform::None
2857687 hwc2: Ignore empty layer sets
da95cbe hwc2: Always set the retire fence in present()
f50eda4 sdm: hwc2: Set transform correctly
0d4053d sdm: Move HPD enable to Primary device Initialization
a4ebb36 sdm: Reserve one byte for NULL terminating character.
9a3dde8 Promotion of display.lnx.3.0-00027.

Bug: 29463310
Change-Id: I1dfd2b58b7587ee0b2ebc6e1c3d6ed0640405296
diff --git a/msm8996/common.mk b/msm8996/common.mk
index 228f742..6b3e2e9 100644
--- a/msm8996/common.mk
+++ b/msm8996/common.mk
@@ -2,6 +2,9 @@
 display_top := $(call my-dir)
 
 use_hwc2 := false
+ifeq ($(TARGET_USES_HWC2), true)
+    use_hwc2 := true
+endif
 
 common_includes := $(display_top)/libqdutils
 common_includes += $(display_top)/libqservice
diff --git a/msm8996/sdm/libs/core/display_base.cpp b/msm8996/sdm/libs/core/display_base.cpp
index d9583b7..aa50b7a 100644
--- a/msm8996/sdm/libs/core/display_base.cpp
+++ b/msm8996/sdm/libs/core/display_base.cpp
@@ -920,6 +920,10 @@
   return SetMixerResolutionLocked(width, height);
 }
 
+DisplayError DisplayBase::SetMixerResolutionLocked(uint32_t width, uint32_t height) {
+  return ReconfigureMixer(width, height);
+}
+
 DisplayError DisplayBase::GetMixerResolution(uint32_t *width, uint32_t *height) {
   SCOPE_LOCK(locker_);
   return GetMixerResolutionLocked(width, height);
@@ -936,6 +940,89 @@
   return kErrorNone;
 }
 
+DisplayError DisplayBase::ReconfigureMixer(uint32_t width, uint32_t height) {
+  DisplayError error = kErrorNone;
+
+  HWMixerAttributes mixer_attributes;
+  mixer_attributes.width = width;
+  mixer_attributes.height = height;
+
+  error = hw_intf_->SetMixerAttributes(mixer_attributes);
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  return ReconfigureDisplay();
+}
+
+bool DisplayBase::NeedsMixerReconfiguration(LayerStack *layer_stack, uint32_t *new_mixer_width,
+                                            uint32_t *new_mixer_height) {
+  uint32_t layer_count = UINT32(layer_stack->layers.size());
+
+  uint32_t fb_width  = fb_config_.x_pixels;
+  uint32_t fb_height  = fb_config_.y_pixels;
+  uint32_t fb_area = fb_width * fb_height;
+  LayerRect fb_rect = (LayerRect) {0.0f, 0.0f, FLOAT(fb_width), FLOAT(fb_height)};
+  uint32_t mixer_width = mixer_attributes_.width;
+  uint32_t mixer_height = mixer_attributes_.height;
+
+  RectOrientation fb_orientation = GetOrientation(fb_rect);
+  uint32_t max_layer_area = 0;
+  uint32_t max_area_layer_index = 0;
+  std::vector<Layer *> layers = layer_stack->layers;
+
+  for (uint32_t i = 0; i < layer_count; i++) {
+    Layer *layer = layers.at(i);
+    LayerBuffer *layer_buffer = layer->input_buffer;
+
+    if (!layer_buffer->flags.video) {
+      continue;
+    }
+
+    uint32_t layer_width = UINT32(layer->src_rect.right - layer->src_rect.left);
+    uint32_t layer_height = UINT32(layer->src_rect.bottom - layer->src_rect.top);
+    uint32_t layer_area = layer_width * layer_height;
+
+    if (layer_area > max_layer_area) {
+      max_layer_area = layer_area;
+      max_area_layer_index = i;
+    }
+  }
+
+  if (max_layer_area > fb_area) {
+    Layer *layer = layers.at(max_area_layer_index);
+
+    uint32_t layer_width = UINT32(layer->src_rect.right - layer->src_rect.left);
+    uint32_t layer_height = UINT32(layer->src_rect.bottom - layer->src_rect.top);
+    LayerRect layer_rect = (LayerRect){0.0f, 0.0f, FLOAT(layer_width), FLOAT(layer_height)};
+
+    RectOrientation layer_orientation = GetOrientation(layer_rect);
+    if (layer_orientation != kOrientationUnknown &&
+        fb_orientation != kOrientationUnknown) {
+      if (layer_orientation != fb_orientation) {
+        Swap(layer_width, layer_height);
+      }
+    }
+
+    // Align the width and height according to fb's aspect ratio
+    layer_width = UINT32((FLOAT(fb_width) / FLOAT(fb_height)) * layer_height);
+
+    *new_mixer_width = layer_width;
+    *new_mixer_height = layer_height;
+
+    return true;
+  } else {
+    if (fb_width != mixer_width || fb_height != mixer_height) {
+      *new_mixer_width = fb_width;
+      *new_mixer_height = fb_height;
+
+      return true;
+    }
+  }
+
+  return false;
+}
+
 DisplayError DisplayBase::SetFrameBufferConfig(const DisplayConfigVariableInfo &variable_info) {
   SCOPE_LOCK(locker_);
   return SetFrameBufferConfigLocked(variable_info);
@@ -997,4 +1084,15 @@
   return SetDetailEnhancerDataLocked(de_data);
 }
 
+DisplayError DisplayBase::SetDetailEnhancerDataLocked(const DisplayDetailEnhancerData &de_data) {
+  DisplayError error = comp_manager_->SetDetailEnhancerData(display_comp_ctx_, de_data);
+  if (error != kErrorNone) {
+    return error;
+  }
+
+  DisablePartialUpdateOneFrameLocked();
+
+  return kErrorNone;
+}
+
 }  // namespace sdm
diff --git a/msm8996/sdm/libs/core/display_base.h b/msm8996/sdm/libs/core/display_base.h
index 1672351..a9f1c3d 100644
--- a/msm8996/sdm/libs/core/display_base.h
+++ b/msm8996/sdm/libs/core/display_base.h
@@ -103,15 +103,11 @@
   virtual DisplayError DisablePartialUpdateOneFrameLocked() {
     return kErrorNotSupported;
   }
-  virtual DisplayError SetMixerResolutionLocked(uint32_t width, uint32_t height) {
-    return kErrorNotSupported;
-  }
+  virtual DisplayError SetMixerResolutionLocked(uint32_t width, uint32_t height);
   virtual DisplayError GetMixerResolutionLocked(uint32_t *width, uint32_t *height);
   virtual DisplayError SetFrameBufferConfigLocked(const DisplayConfigVariableInfo &variable_info);
   virtual DisplayError GetFrameBufferConfigLocked(DisplayConfigVariableInfo *variable_info);
-  virtual DisplayError SetDetailEnhancerDataLocked(const DisplayDetailEnhancerData &de_data) {
-    return kErrorNotSupported;
-  }
+  virtual DisplayError SetDetailEnhancerDataLocked(const DisplayDetailEnhancerData &de_data);
 
   // DumpImpl method
   void AppendDump(char *buffer, uint32_t length);
@@ -120,6 +116,10 @@
   const char *GetName(const LayerComposition &composition);
   DisplayError ValidateGPUTarget(LayerStack *layer_stack);
   DisplayError ReconfigureDisplay();
+  bool NeedsMixerReconfiguration(LayerStack *layer_stack, uint32_t *new_mixer_width,
+                                 uint32_t *new_mixer_height);
+  DisplayError ReconfigureMixer(uint32_t width, uint32_t height);
+
 
   Locker locker_;
   DisplayType display_type_;
diff --git a/msm8996/sdm/libs/core/display_hdmi.cpp b/msm8996/sdm/libs/core/display_hdmi.cpp
index 11c268a..0eeff0a 100644
--- a/msm8996/sdm/libs/core/display_hdmi.cpp
+++ b/msm8996/sdm/libs/core/display_hdmi.cpp
@@ -107,6 +107,19 @@
 }
 
 DisplayError DisplayHDMI::PrepareLocked(LayerStack *layer_stack) {
+  DisplayError error = kErrorNone;
+  uint32_t new_mixer_width = 0;
+  uint32_t new_mixer_height = 0;
+  uint32_t display_width = display_attributes_.x_pixels;
+  uint32_t display_height = display_attributes_.y_pixels;
+
+  if (NeedsMixerReconfiguration(layer_stack, &new_mixer_width, &new_mixer_height)) {
+    error = ReconfigureMixer(new_mixer_width, new_mixer_height);
+    if (error != kErrorNone) {
+      ReconfigureMixer(display_width, display_height);
+    }
+  }
+
   SetS3DMode(layer_stack);
 
   return DisplayBase::PrepareLocked(layer_stack);
diff --git a/msm8996/sdm/libs/core/display_primary.cpp b/msm8996/sdm/libs/core/display_primary.cpp
index 70b96fe..41e4c29 100644
--- a/msm8996/sdm/libs/core/display_primary.cpp
+++ b/msm8996/sdm/libs/core/display_primary.cpp
@@ -361,103 +361,5 @@
   return kErrorNone;
 }
 
-DisplayError DisplayPrimary::SetMixerResolutionLocked(uint32_t width, uint32_t height) {
-  return ReconfigureMixer(width, height);
-}
-
-DisplayError DisplayPrimary::ReconfigureMixer(uint32_t width, uint32_t height) {
-  DisplayError error = kErrorNone;
-
-  HWMixerAttributes mixer_attributes;
-  mixer_attributes.width = width;
-  mixer_attributes.height = height;
-
-  error = hw_intf_->SetMixerAttributes(mixer_attributes);
-  if (error != kErrorNone) {
-    return error;
-  }
-
-  return DisplayBase::ReconfigureDisplay();
-}
-
-bool DisplayPrimary::NeedsMixerReconfiguration(LayerStack *layer_stack, uint32_t *new_mixer_width,
-                                               uint32_t *new_mixer_height) {
-  uint32_t layer_count = UINT32(layer_stack->layers.size());
-
-  uint32_t fb_width  = fb_config_.x_pixels;
-  uint32_t fb_height  = fb_config_.y_pixels;
-  uint32_t fb_area = fb_width * fb_height;
-  LayerRect fb_rect = (LayerRect) {0.0f, 0.0f, FLOAT(fb_width), FLOAT(fb_height)};
-  uint32_t mixer_width = mixer_attributes_.width;
-  uint32_t mixer_height = mixer_attributes_.height;
-
-  RectOrientation fb_orientation = GetOrientation(fb_rect);
-  uint32_t max_layer_area = 0;
-  uint32_t max_area_layer_index = 0;
-  std::vector<Layer *> layers = layer_stack->layers;
-
-  for (uint32_t i = 0; i < layer_count; i++) {
-    Layer *layer = layers.at(i);
-    LayerBuffer *layer_buffer = layer->input_buffer;
-
-    if (!layer_buffer->flags.video) {
-      continue;
-    }
-
-    uint32_t layer_width = UINT32(layer->src_rect.right - layer->src_rect.left);
-    uint32_t layer_height = UINT32(layer->src_rect.bottom - layer->src_rect.top);
-    uint32_t layer_area = layer_width * layer_height;
-
-    if (layer_area > max_layer_area) {
-      max_layer_area = layer_area;
-      max_area_layer_index = i;
-    }
-  }
-
-  if (max_layer_area > fb_area) {
-    Layer *layer = layers.at(max_area_layer_index);
-
-    uint32_t layer_width = UINT32(layer->src_rect.right - layer->src_rect.left);
-    uint32_t layer_height = UINT32(layer->src_rect.bottom - layer->src_rect.top);
-    LayerRect layer_rect = (LayerRect){0.0f, 0.0f, FLOAT(layer_width), FLOAT(layer_height)};
-
-    RectOrientation layer_orientation = GetOrientation(layer_rect);
-    if (layer_orientation != kOrientationUnknown &&
-        fb_orientation != kOrientationUnknown) {
-      if (layer_orientation != fb_orientation) {
-        Swap(layer_width, layer_height);
-      }
-    }
-
-    // Align the width and height according to fb's aspect ratio
-    layer_width = UINT32((FLOAT(fb_width) / FLOAT(fb_height)) * layer_height);
-
-    *new_mixer_width = layer_width;
-    *new_mixer_height = layer_height;
-
-    return true;
-  } else {
-    if (fb_width != mixer_width || fb_height != mixer_height) {
-      *new_mixer_width = fb_width;
-      *new_mixer_height = fb_height;
-
-      return true;
-    }
-  }
-
-  return false;
-}
-
-DisplayError DisplayPrimary::SetDetailEnhancerDataLocked(const DisplayDetailEnhancerData &de_data) {
-  DisplayError error = comp_manager_->SetDetailEnhancerData(display_comp_ctx_, de_data);
-  if (error != kErrorNone) {
-    return error;
-  }
-
-  DisablePartialUpdateOneFrameLocked();
-
-  return kErrorNone;
-}
-
 }  // namespace sdm
 
diff --git a/msm8996/sdm/libs/core/display_primary.h b/msm8996/sdm/libs/core/display_primary.h
index f029961..92e6c88 100644
--- a/msm8996/sdm/libs/core/display_primary.h
+++ b/msm8996/sdm/libs/core/display_primary.h
@@ -72,12 +72,6 @@
   virtual DisplayError CommitLocked(LayerStack *layer_stack);
   virtual DisplayError ControlPartialUpdateLocked(bool enable, uint32_t *pending);
   virtual DisplayError DisablePartialUpdateOneFrameLocked();
-  virtual DisplayError SetMixerResolutionLocked(uint32_t width, uint32_t height);
-  virtual DisplayError SetDetailEnhancerDataLocked(const DisplayDetailEnhancerData &de_data);
-
-  bool NeedsMixerReconfiguration(LayerStack *layer_stack, uint32_t *new_mixer_width,
-                                 uint32_t *new_mixer_height);
-  DisplayError ReconfigureMixer(uint32_t width, uint32_t height);
 
   uint32_t idle_timeout_ms_ = 0;
   std::vector<const char *> event_list_ = {"vsync_event", "show_blank_event", "idle_notify",
diff --git a/msm8996/sdm/libs/core/display_virtual.h b/msm8996/sdm/libs/core/display_virtual.h
index ba164ae..59334a7 100644
--- a/msm8996/sdm/libs/core/display_virtual.h
+++ b/msm8996/sdm/libs/core/display_virtual.h
@@ -63,6 +63,15 @@
     return kErrorNotSupported;
   }
   virtual DisplayError SetActiveConfigLocked(DisplayConfigVariableInfo *variable_info);
+  virtual DisplayError SetMixerResolutionLocked(uint32_t width, uint32_t height) {
+    return kErrorNotSupported;
+  }
+  virtual DisplayError GetMixerResolutionLocked(uint32_t *width, uint32_t *height) {
+    return kErrorNotSupported;
+  }
+  virtual DisplayError SetDetailEnhancerDataLocked(const DisplayDetailEnhancerData &de_data) {
+    return kErrorNotSupported;
+  }
 };
 
 }  // namespace sdm
diff --git a/msm8996/sdm/libs/core/dump_impl.cpp b/msm8996/sdm/libs/core/dump_impl.cpp
index 0d6c9b2..655b210 100644
--- a/msm8996/sdm/libs/core/dump_impl.cpp
+++ b/msm8996/sdm/libs/core/dump_impl.cpp
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014, 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:
@@ -59,14 +59,15 @@
 
 void DumpImpl::AppendString(char *buffer, uint32_t length, const char *format, ...) {
   uint32_t filled = UINT32(strlen(buffer));
-  if (filled >= length) {
+  // Reserve one byte for null terminating character
+  if ((filled + 1) >= length) {
     return;
   }
   buffer += filled;
 
   va_list list;
   va_start(list, format);
-  vsnprintf(buffer, length - filled, format, list);
+  vsnprintf(buffer, length - filled -1, format, list);
 }
 
 // Every object is created or destroyed through display core only, which itself protects the
diff --git a/msm8996/sdm/libs/core/fb/hw_device.cpp b/msm8996/sdm/libs/core/fb/hw_device.cpp
index 6b7dd2e..641a27e 100644
--- a/msm8996/sdm/libs/core/fb/hw_device.cpp
+++ b/msm8996/sdm/libs/core/fb/hw_device.cpp
@@ -54,7 +54,7 @@
 namespace sdm {
 
 HWDevice::HWDevice(BufferSyncHandler *buffer_sync_handler)
-  : fb_node_index_(-1), fb_path_("/sys/devices/virtual/graphics/fb"), hotplug_enabled_(false),
+  : fb_node_index_(-1), fb_path_("/sys/devices/virtual/graphics/fb"),
     buffer_sync_handler_(buffer_sync_handler), synchronous_commit_(false) {
 }
 
@@ -135,11 +135,6 @@
     return kErrorHardware;
   }
 
-  // Need to turn on HPD
-  if (!hotplug_enabled_) {
-    hotplug_enabled_ = EnableHotPlugDetection(1);
-  }
-
   return kErrorNone;
 }
 
@@ -282,6 +277,40 @@
     DLOGI_IF(kTagDriverConfig, "*****************************************************************");
   }
 
+  uint32_t index = 0;
+  for (uint32_t i = 0; i < hw_resource_.hw_dest_scalar_info.count; i++) {
+    DestScaleInfoMap::iterator it = hw_layer_info.dest_scale_info_map.find(i);
+
+    if (it == hw_layer_info.dest_scale_info_map.end()) {
+      continue;
+    }
+
+    HWDestScaleInfo *dest_scale_info = it->second;
+
+    mdp_destination_scaler_data *dest_scalar_data = &mdp_dest_scalar_data_[index];
+    hw_scale_->SetHWScaleData(dest_scale_info->scale_data, index, &mdp_commit,
+                              kHWDestinationScalar);
+
+    if (dest_scale_info->scale_update) {
+      dest_scalar_data->flags |= MDP_DESTSCALER_SCALE_UPDATE;
+    }
+
+    dest_scalar_data->dest_scaler_ndx = i;
+    dest_scalar_data->lm_width = dest_scale_info->mixer_width;
+    dest_scalar_data->lm_height = dest_scale_info->mixer_height;
+    dest_scalar_data->scale = reinterpret_cast <uint64_t>
+      (hw_scale_->GetScaleDataRef(index, kHWDestinationScalar));
+
+    index++;
+
+    DLOGV_IF(kTagDriverConfig, "************************ DestScalar[%d] **************************",
+             dest_scalar_data->dest_scaler_ndx);
+    DLOGV_IF(kTagDriverConfig, "Mixer WxH %dx%d", dest_scalar_data->lm_width,
+             dest_scalar_data->lm_height);
+    DLOGI_IF(kTagDriverConfig, "*****************************************************************");
+  }
+  mdp_commit.dest_scaler_cnt = UINT32(hw_layer_info.dest_scale_info_map.size());
+
   mdp_commit.flags |= MDP_VALIDATE_LAYER;
   if (Sys::ioctl_(device_fd_, INT(MSMFB_ATOMIC_COMMIT), &mdp_disp_commit_) < 0) {
     if (errno == ESHUTDOWN) {
@@ -947,6 +976,7 @@
 }
 
 void HWDevice::ResetDisplayParams() {
+  uint32_t dst_scalar_cnt = hw_resource_.hw_dest_scalar_info.count;
   memset(&mdp_disp_commit_, 0, sizeof(mdp_disp_commit_));
   memset(&mdp_in_layers_, 0, sizeof(mdp_in_layers_));
   memset(&mdp_out_layer_, 0, sizeof(mdp_out_layer_));
@@ -955,6 +985,10 @@
   memset(&pp_params_, 0, sizeof(pp_params_));
   memset(&igc_lut_data_, 0, sizeof(igc_lut_data_));
 
+  if (mdp_dest_scalar_data_) {
+    memset(mdp_dest_scalar_data_, 0, sizeof(mdp_dest_scalar_data_) * dst_scalar_cnt);
+  }
+
   for (uint32_t i = 0; i < kMaxSDELayers * 2; i++) {
     mdp_in_layers_[i].buffer.fence = -1;
   }
@@ -964,6 +998,7 @@
   mdp_disp_commit_.commit_v1.output_layer = &mdp_out_layer_;
   mdp_disp_commit_.commit_v1.release_fence = -1;
   mdp_disp_commit_.commit_v1.retire_fence = -1;
+  mdp_disp_commit_.commit_v1.dest_scaler = mdp_dest_scalar_data_;
 }
 
 void HWDevice::SetCSC(LayerCSC source, mdp_color_space *color_space) {
@@ -1135,5 +1170,69 @@
   return kErrorNone;
 }
 
+DisplayError HWDevice::SetMixerAttributes(const HWMixerAttributes &mixer_attributes) {
+  if (!hw_resource_.hw_dest_scalar_info.count) {
+    return kErrorNotSupported;
+  }
+
+  if (mixer_attributes.width > display_attributes_.x_pixels ||
+      mixer_attributes.height > display_attributes_.y_pixels) {
+    DLOGW("Input resolution exceeds display resolution! input: res %dx%d display: res %dx%d",
+          mixer_attributes.width, mixer_attributes.height, display_attributes_.x_pixels,
+          display_attributes_.y_pixels);
+    return kErrorNotSupported;
+  }
+
+  uint32_t max_input_width = hw_resource_.hw_dest_scalar_info.max_input_width;
+  if (display_attributes_.is_device_split) {
+    max_input_width *= 2;
+  }
+
+  if (mixer_attributes.width > max_input_width) {
+    DLOGW("Input width exceeds width limit! input_width %d width_limit %d", mixer_attributes.width,
+          max_input_width);
+    return kErrorNotSupported;
+  }
+
+  float mixer_aspect_ratio = FLOAT(mixer_attributes.width) / FLOAT(mixer_attributes.height);
+  float display_aspect_ratio =
+    FLOAT(display_attributes_.x_pixels) / FLOAT(display_attributes_.y_pixels);
+
+  if (display_aspect_ratio != mixer_aspect_ratio) {
+    DLOGW("Aspect ratio mismatch! input: res %dx%d display: res %dx%d", mixer_attributes.width,
+          mixer_attributes.height, display_attributes_.x_pixels, display_attributes_.y_pixels);
+    return kErrorNotSupported;
+  }
+
+  float scale_x = FLOAT(display_attributes_.x_pixels) / FLOAT(mixer_attributes.width);
+  float scale_y = FLOAT(display_attributes_.y_pixels) / FLOAT(mixer_attributes.height);
+  float max_scale_up = hw_resource_.hw_dest_scalar_info.max_scale_up;
+  if (scale_x > max_scale_up || scale_y > max_scale_up) {
+    DLOGW("Up scaling ratio exceeds for destination scalar upscale limit scale_x %f scale_y %f " \
+          "max_scale_up %f", scale_x, scale_y, max_scale_up);
+    return kErrorNotSupported;
+  }
+
+  float mixer_split_ratio = FLOAT(mixer_attributes_.split_left) / FLOAT(mixer_attributes_.width);
+
+  mixer_attributes_ = mixer_attributes;
+  mixer_attributes_.split_left = mixer_attributes_.width;
+  if (display_attributes_.is_device_split) {
+    mixer_attributes_.split_left = UINT32(FLOAT(mixer_attributes.width) * mixer_split_ratio);
+  }
+
+  return kErrorNone;
+}
+
+DisplayError HWDevice::GetMixerAttributes(HWMixerAttributes *mixer_attributes) {
+  if (!mixer_attributes) {
+    return kErrorParameters;
+  }
+
+  *mixer_attributes = mixer_attributes_;
+
+  return kErrorNone;
+}
+
 }  // namespace sdm
 
diff --git a/msm8996/sdm/libs/core/fb/hw_device.h b/msm8996/sdm/libs/core/fb/hw_device.h
index d5b18de..fc473ff 100644
--- a/msm8996/sdm/libs/core/fb/hw_device.h
+++ b/msm8996/sdm/libs/core/fb/hw_device.h
@@ -84,12 +84,8 @@
   virtual DisplayError SetAutoRefresh(bool enable) { return kErrorNone; }
   virtual DisplayError SetS3DMode(HWS3DMode s3d_mode);
   virtual DisplayError SetScaleLutConfig(HWScaleLutInfo *lut_info);
-  virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes) {
-    return kErrorNotSupported;
-  }
-  virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes) {
-    return kErrorNotSupported;
-  }
+  virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes);
+  virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes);
 
   // For HWDevice derivatives
   virtual DisplayError Init();
@@ -135,7 +131,6 @@
   HWInfoInterface *hw_info_intf_;
   int fb_node_index_;
   const char *fb_path_;
-  bool hotplug_enabled_;
   BufferSyncHandler *buffer_sync_handler_;
   int device_fd_;
   HWDeviceType device_type_;
@@ -147,6 +142,9 @@
   mdp_output_layer mdp_out_layer_;
   const char *device_name_;
   bool synchronous_commit_;
+  HWDisplayAttributes display_attributes_ = {};
+  HWMixerAttributes mixer_attributes_ = {};
+  mdp_destination_scaler_data *mdp_dest_scalar_data_ = NULL;
 };
 
 }  // namespace sdm
diff --git a/msm8996/sdm/libs/core/fb/hw_hdmi.cpp b/msm8996/sdm/libs/core/fb/hw_hdmi.cpp
index 3dfac8a..ab4e2ba 100644
--- a/msm8996/sdm/libs/core/fb/hw_hdmi.cpp
+++ b/msm8996/sdm/libs/core/fb/hw_hdmi.cpp
@@ -119,6 +119,11 @@
     return error;
   }
 
+  uint32_t dest_scalar_count = hw_resource_.hw_dest_scalar_info.count;
+  if (dest_scalar_count) {
+    mdp_dest_scalar_data_ = new mdp_destination_scaler_data[dest_scalar_count];
+  }
+
   error = ReadEDIDInfo();
   if (error != kErrorNone) {
     Deinit();
@@ -165,6 +170,8 @@
     delete[] supported_video_modes_;
   }
 
+  delete [] mdp_dest_scalar_data_;
+
   return HWDevice::Deinit();
 }
 
@@ -252,6 +259,7 @@
   display_attributes->y_dpi = 0;
   display_attributes->fps = timing_mode->refresh_rate / 1000;
   display_attributes->vsync_period_ns = UINT32(1000000000L / display_attributes->fps);
+  display_attributes->is_device_split = false;
   if (display_attributes->x_pixels > hw_resource_.max_mixer_width) {
     display_attributes->is_device_split = true;
     display_attributes->h_total += h_blanking;
@@ -318,13 +326,14 @@
 
   frame_rate_ = timing_mode->refresh_rate;
 
-  // Get the supported s3d modes for current active config index
-  HWDisplayAttributes attrib;
-  GetDisplayS3DSupport(index, &attrib);
+  // Get the display attributes for current active config index
+  GetDisplayAttributes(active_config_index_, &display_attributes_);
+  UpdateMixerAttributes();
+
   supported_s3d_modes_.clear();
   supported_s3d_modes_.push_back(kS3DModeNone);
   for (uint32_t mode = kS3DModeNone + 1; mode < kS3DModeMax; mode ++) {
-    if (IS_BIT_SET(attrib.s3d_config, (HWS3DMode)mode)) {
+    if (IS_BIT_SET(display_attributes_.s3d_config, (HWS3DMode)mode)) {
       supported_s3d_modes_.push_back((HWS3DMode)mode);
     }
   }
@@ -748,25 +757,19 @@
     return error;
   }
 
+  GetDisplayAttributes(active_config_index_, &display_attributes_);
+  UpdateMixerAttributes();
+
   frame_rate_ = refresh_rate;
 
   return kErrorNone;
 }
 
-DisplayError HWHDMI::GetMixerAttributes(HWMixerAttributes *mixer_attributes) {
-  if (!mixer_attributes) {
-    return kErrorParameters;
-  }
-
-  HWDisplayAttributes display_attributes;
-  GetDisplayAttributes(active_config_index_, &display_attributes);
-
-  mixer_attributes->width = display_attributes.x_pixels;
-  mixer_attributes->height = display_attributes.y_pixels;
-  mixer_attributes->split_left = display_attributes.is_device_split ?
-      (display_attributes.x_pixels / 2) : mixer_attributes->width;
-
-  return kErrorNone;
+void HWHDMI::UpdateMixerAttributes() {
+  mixer_attributes_.width = display_attributes_.x_pixels;
+  mixer_attributes_.height = display_attributes_.y_pixels;
+  mixer_attributes_.split_left = display_attributes_.is_device_split ?
+      (display_attributes_.x_pixels / 2) : mixer_attributes_.width;
 }
 
 }  // namespace sdm
diff --git a/msm8996/sdm/libs/core/fb/hw_hdmi.h b/msm8996/sdm/libs/core/fb/hw_hdmi.h
index 833b3d3..2845708 100644
--- a/msm8996/sdm/libs/core/fb/hw_hdmi.h
+++ b/msm8996/sdm/libs/core/fb/hw_hdmi.h
@@ -69,7 +69,6 @@
   virtual DisplayError Validate(HWLayers *hw_layers);
   virtual DisplayError SetS3DMode(HWS3DMode s3d_mode);
   virtual DisplayError SetRefreshRate(uint32_t refresh_rate);
-  virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes);
 
  private:
   DisplayError ReadEDIDInfo();
@@ -84,6 +83,7 @@
   DisplayError GetDisplayS3DSupport(uint32_t num_modes,
                                     HWDisplayAttributes *attrib);
   bool IsSupportedS3DMode(HWS3DMode s3d_mode);
+  void UpdateMixerAttributes();
 
   uint32_t hdmi_mode_count_;
   uint32_t hdmi_modes_[256];
diff --git a/msm8996/sdm/libs/core/fb/hw_info.cpp b/msm8996/sdm/libs/core/fb/hw_info.cpp
index 25bb01c..a1a928c 100644
--- a/msm8996/sdm/libs/core/fb/hw_info.cpp
+++ b/msm8996/sdm/libs/core/fb/hw_info.cpp
@@ -554,7 +554,7 @@
   size_t len = kMaxStringLength;
   ssize_t read;
 
-  FILE *fileptr = Sys::fopen_("/sys/class/graphics/fb0/msm_fb_type", "r");
+  FILE *fileptr = Sys::fopen_("/sys/devices/virtual/graphics/fb0/msm_fb_type", "r");
   if (!fileptr) {
     free(stringbuffer);
     return kErrorHardware;
@@ -570,13 +570,13 @@
     }
   } else {
     free(stringbuffer);
-    fclose(fileptr);
+    Sys::fclose_(fileptr);
     return kErrorHardware;
   }
 
-  fclose(fileptr);
+  Sys::fclose_(fileptr);
 
-  fileptr = Sys::fopen_("/sys/class/graphics/fb0/connected", "r");
+  fileptr = Sys::fopen_("/sys/devices/virtual/graphics/fb0/connected", "r");
   if (!fileptr) {
     // If fb0 is for a DSI/connected panel, then connected node will not exist
     hw_disp_info->is_connected = true;
@@ -584,11 +584,11 @@
     if ((read = Sys::getline_(&line, &len, fileptr)) != -1) {
         hw_disp_info->is_connected =  (!strncmp(line, "1", strlen("1")));
     } else {
-        fclose(fileptr);
+        Sys::fclose_(fileptr);
         free(stringbuffer);
         return kErrorHardware;
     }
-    fclose(fileptr);
+    Sys::fclose_(fileptr);
   }
 
   free(stringbuffer);
diff --git a/msm8996/sdm/libs/core/fb/hw_primary.cpp b/msm8996/sdm/libs/core/fb/hw_primary.cpp
index 3d0c776..115a9c8 100644
--- a/msm8996/sdm/libs/core/fb/hw_primary.cpp
+++ b/msm8996/sdm/libs/core/fb/hw_primary.cpp
@@ -112,9 +112,10 @@
 
   UpdateMixerAttributes();
 
-  // Disable HPD at start if HDMI is external, it will be enabled later when the display powers on
+  // Need to enable HPD, but toggle at start when HDMI is external
   // This helps for framework reboot or adb shell stop/start
   EnableHotPlugDetection(0);
+  EnableHotPlugDetection(1);
   InitializeConfigs();
 
   return error;
@@ -390,22 +391,11 @@
   return kErrorNone;
 }
 
-void HWPrimary::ResetDisplayParams() {
-  uint32_t dst_scalar_cnt = hw_resource_.hw_dest_scalar_info.count;
-
-  HWDevice::ResetDisplayParams();
-
-  if (mdp_dest_scalar_data_) {
-    memset(mdp_dest_scalar_data_, 0, sizeof(mdp_dest_scalar_data_) * dst_scalar_cnt);
-    mdp_disp_commit_.commit_v1.dest_scaler = mdp_dest_scalar_data_;
-  }
-}
-
 DisplayError HWPrimary::Validate(HWLayers *hw_layers) {
   HWLayersInfo &hw_layer_info = hw_layers->info;
   LayerStack *stack = hw_layer_info.stack;
 
-  ResetDisplayParams();
+  HWDevice::ResetDisplayParams();
 
   mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1;
 
@@ -445,40 +435,6 @@
     DLOGI_IF(kTagDriverConfig, "****************************************************************");
   }
 
-  uint32_t index = 0;
-  for (uint32_t i = 0; i < hw_resource_.hw_dest_scalar_info.count; i++) {
-    DestScaleInfoMap::iterator it = hw_layer_info.dest_scale_info_map.find(i);
-
-    if (it == hw_layer_info.dest_scale_info_map.end()) {
-      continue;
-    }
-
-    HWDestScaleInfo *dest_scale_info = it->second;
-
-    mdp_destination_scaler_data *dest_scalar_data = &mdp_dest_scalar_data_[index];
-    hw_scale_->SetHWScaleData(dest_scale_info->scale_data, index, &mdp_commit,
-                              kHWDestinationScalar);
-
-    if (dest_scale_info->scale_update) {
-      dest_scalar_data->flags |= MDP_DESTSCALER_SCALE_UPDATE;
-    }
-
-    dest_scalar_data->dest_scaler_ndx = i;
-    dest_scalar_data->lm_width = dest_scale_info->mixer_width;
-    dest_scalar_data->lm_height = dest_scale_info->mixer_height;
-    dest_scalar_data->scale = reinterpret_cast <uint64_t>
-      (hw_scale_->GetScaleDataRef(index, kHWDestinationScalar));
-
-    index++;
-
-    DLOGV_IF(kTagDriverConfig, "************************ DestScalar[%d] **************************",
-             dest_scalar_data->dest_scaler_ndx);
-    DLOGV_IF(kTagDriverConfig, "Mixer WxH %dx%d", dest_scalar_data->lm_width,
-             dest_scalar_data->lm_height);
-    DLOGI_IF(kTagDriverConfig, "*****************************************************************");
-  }
-  mdp_commit.dest_scaler_cnt = UINT32(hw_layer_info.dest_scale_info_map.size());
-
   return HWDevice::Validate(hw_layers);
 }
 
@@ -696,67 +652,11 @@
 }
 
 DisplayError HWPrimary::SetMixerAttributes(const HWMixerAttributes &mixer_attributes) {
-  if (IsResolutionSwitchEnabled() || !hw_resource_.hw_dest_scalar_info.count) {
+  if (IsResolutionSwitchEnabled()) {
     return kErrorNotSupported;
   }
 
-  if (mixer_attributes.width > display_attributes_.x_pixels ||
-      mixer_attributes.height > display_attributes_.y_pixels) {
-    DLOGW("Input resolution exceeds display resolution! input: res %dx%d display: res %dx%d",
-          mixer_attributes.width, mixer_attributes.height, display_attributes_.x_pixels,
-          display_attributes_.y_pixels);
-    return kErrorNotSupported;
-  }
-
-  uint32_t max_input_width = hw_resource_.hw_dest_scalar_info.max_input_width;
-  if (display_attributes_.is_device_split) {
-    max_input_width *= 2;
-  }
-
-  if (mixer_attributes.width > max_input_width) {
-    DLOGW("Input width exceeds width limit! input_width %d width_limit %d", mixer_attributes.width,
-          max_input_width);
-    return kErrorNotSupported;
-  }
-
-  float mixer_aspect_ratio = FLOAT(mixer_attributes.width) / FLOAT(mixer_attributes.height);
-  float display_aspect_ratio =
-    FLOAT(display_attributes_.x_pixels) / FLOAT(display_attributes_.y_pixels);
-
-  if (display_aspect_ratio != mixer_aspect_ratio) {
-    DLOGW("Aspect ratio mismatch! input: res %dx%d display: res %dx%d", mixer_attributes.width,
-          mixer_attributes.height, display_attributes_.x_pixels, display_attributes_.y_pixels);
-    return kErrorNotSupported;
-  }
-
-  float scale_x = FLOAT(display_attributes_.x_pixels) / FLOAT(mixer_attributes.width);
-  float scale_y = FLOAT(display_attributes_.y_pixels) / FLOAT(mixer_attributes.height);
-  float max_scale_up = hw_resource_.hw_dest_scalar_info.max_scale_up;
-  if (scale_x > max_scale_up || scale_y > max_scale_up) {
-    DLOGW("Up scaling ratio exceeds for destination scalar upscale limit scale_x %f scale_y %f " \
-          "max_scale_up %f", scale_x, scale_y, max_scale_up);
-    return kErrorNotSupported;
-  }
-
-  float mixer_split_ratio = FLOAT(mixer_attributes_.split_left) / FLOAT(mixer_attributes_.width);
-
-  mixer_attributes_ = mixer_attributes;
-  mixer_attributes_.split_left = mixer_attributes_.width;
-  if (display_attributes_.is_device_split) {
-    mixer_attributes_.split_left = UINT32(FLOAT(mixer_attributes.width) * mixer_split_ratio);
-  }
-
-  return kErrorNone;
-}
-
-DisplayError HWPrimary::GetMixerAttributes(HWMixerAttributes *mixer_attributes) {
-  if (!mixer_attributes) {
-    return kErrorParameters;
-  }
-
-  *mixer_attributes = mixer_attributes_;
-
-  return kErrorNone;
+  return HWDevice::SetMixerAttributes(mixer_attributes);
 }
 
 void HWPrimary::UpdateMixerAttributes() {
diff --git a/msm8996/sdm/libs/core/fb/hw_primary.h b/msm8996/sdm/libs/core/fb/hw_primary.h
index 36b3f63..18e9d72 100644
--- a/msm8996/sdm/libs/core/fb/hw_primary.h
+++ b/msm8996/sdm/libs/core/fb/hw_primary.h
@@ -66,7 +66,6 @@
   virtual DisplayError GetPanelBrightness(int *level);
   virtual DisplayError SetAutoRefresh(bool enable);
   virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes);
-  virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes);
 
  private:
   // Panel modes for the MSMFB_LPM_ENABLE ioctl
@@ -80,17 +79,13 @@
   bool IsResolutionSwitchEnabled() { return !display_configs_.empty(); }
   bool GetCurrentModeFromSysfs(size_t *curr_x_pixels, size_t *curr_y_pixels);
   void UpdateMixerAttributes();
-  void ResetDisplayParams();
 
-  HWDisplayAttributes display_attributes_;
   std::vector<DisplayConfigVariableInfo> display_configs_;
   std::vector<std::string> display_config_strings_;
   uint32_t active_config_index_ = 0;
   const char *kBrightnessNode = "/sys/class/leds/lcd-backlight/brightness";
   const char *kAutoRefreshNode = "/sys/devices/virtual/graphics/fb0/msm_cmd_autorefresh_en";
   bool auto_refresh_ = false;
-  HWMixerAttributes mixer_attributes_ = {};
-  mdp_destination_scaler_data *mdp_dest_scalar_data_ = NULL;
 };
 
 }  // namespace sdm
diff --git a/msm8996/sdm/libs/core/fb/hw_virtual.h b/msm8996/sdm/libs/core/fb/hw_virtual.h
index 330a067..5ecec34 100644
--- a/msm8996/sdm/libs/core/fb/hw_virtual.h
+++ b/msm8996/sdm/libs/core/fb/hw_virtual.h
@@ -35,6 +35,12 @@
                              BufferSyncHandler *buffer_sync_handler);
   static DisplayError Destroy(HWInterface *intf);
   virtual DisplayError SetVSyncState(bool enable) { return kErrorNotSupported; }
+  virtual DisplayError SetMixerAttributes(const HWMixerAttributes &mixer_attributes) {
+    return kErrorNotSupported;
+  }
+  virtual DisplayError GetMixerAttributes(HWMixerAttributes *mixer_attributes) {
+    return kErrorNotSupported;
+  }
 
  protected:
   HWVirtual(BufferSyncHandler *buffer_sync_handler, HWInfoInterface *hw_info_intf);
diff --git a/msm8996/sdm/libs/hwc/hwc_session.cpp b/msm8996/sdm/libs/hwc/hwc_session.cpp
index 8d12aee..a31c331 100644
--- a/msm8996/sdm/libs/hwc/hwc_session.cpp
+++ b/msm8996/sdm/libs/hwc/hwc_session.cpp
@@ -487,6 +487,11 @@
   if (hwc_session->hwc_display_[disp]) {
     status = hwc_session->hwc_display_[disp]->SetPowerMode(mode);
   }
+  if (disp == HWC_DISPLAY_PRIMARY && hwc_session->hwc_display_[HWC_DISPLAY_VIRTUAL]) {
+    // Set the power mode for virtual display while setting power mode for primary, as SF
+    // does not invoke SetPowerMode() for virtual display.
+    status = hwc_session->hwc_display_[HWC_DISPLAY_VIRTUAL]->SetPowerMode(mode);
+  }
 
   return status;
 }
diff --git a/msm8996/sdm/libs/hwc2/hwc_color_manager.cpp b/msm8996/sdm/libs/hwc2/hwc_color_manager.cpp
index 0be9724..89b4918 100644
--- a/msm8996/sdm/libs/hwc2/hwc_color_manager.cpp
+++ b/msm8996/sdm/libs/hwc2/hwc_color_manager.cpp
@@ -257,7 +257,7 @@
     uint32_t primary_width = 0;
     uint32_t primary_height = 0;
 
-    hwc_display->GetPanelResolution(&primary_width, &primary_height);
+    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,
diff --git a/msm8996/sdm/libs/hwc2/hwc_display.cpp b/msm8996/sdm/libs/hwc2/hwc_display.cpp
index f687731..d6e6518 100644
--- a/msm8996/sdm/libs/hwc2/hwc_display.cpp
+++ b/msm8996/sdm/libs/hwc2/hwc_display.cpp
@@ -231,12 +231,6 @@
     swap_interval_zero_ = true;
   }
 
-  framebuffer_config_ = new DisplayConfigVariableInfo();
-  if (!framebuffer_config_) {
-    DLOGV("Failed to allocate memory for custom framebuffer config.");
-    core_intf_->DestroyDisplay(display_intf_);
-    return -EINVAL;
-  }
 
   client_target_ = new HWCLayer(id_);
   int blit_enabled = 0;
@@ -267,7 +261,6 @@
     return -EINVAL;
   }
 
-  delete framebuffer_config_;
   delete client_target_;
 
   if (blit_engine_) {
@@ -332,6 +325,8 @@
   // TODO(user): Add blit target layers
   for (auto hwc_layer : layer_set_) {
     Layer *layer = hwc_layer->GetSDMLayer();
+    // set default composition as GPU for SDM
+    layer->composition = kCompositionGPU;
 
     if (swap_interval_zero_) {
       if (layer->input_buffer->acquire_fence_fd >= 0) {
@@ -366,7 +361,6 @@
     // 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)};
-    ScaleDisplayFrame(&scaled_display_frame);
     ApplyScanAdjustment(&scaled_display_frame);
     hwc_layer->SetLayerDisplayFrame(scaled_display_frame);
     ApplyDeInterlaceAdjustment(layer);
@@ -379,12 +373,12 @@
       layer->frame_rate = current_refresh_rate_;
     }
     display_rect_ = Union(display_rect_, layer->dst_rect);
-    // TODO(user): Set correctly when implementing caching
-    layer->flags.updating = true;
     geometry_changes_ |= hwc_layer->GetGeometryChanges();
+    layer->flags.updating = IsLayerUpdating(layer);
 
     layer_stack_.layers.push_back(layer);
   }
+  // 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
   layer_stack_.layers.push_back(client_target_->GetSDMLayer());
@@ -501,9 +495,11 @@
 
 HWC2::Error HWCDisplay::GetClientTargetSupport(uint32_t width, uint32_t height, int32_t format,
                                                int32_t dataspace) {
+  DisplayConfigVariableInfo variable_config;
+  display_intf_->GetFrameBufferConfig(&variable_config);
   // TODO(user): Support scaled configurations, other formats and other dataspaces
   if (format != HAL_PIXEL_FORMAT_RGBA_8888 || dataspace != HAL_DATASPACE_UNKNOWN ||
-      width != framebuffer_config_->x_pixels || height != framebuffer_config_->y_pixels) {
+      width != variable_config.x_pixels || height != variable_config.y_pixels) {
     return HWC2::Error::Unsupported;
   } else {
     return HWC2::Error::None;
@@ -533,7 +529,12 @@
 
 HWC2::Error HWCDisplay::GetDisplayAttribute(hwc2_config_t config, HWC2::Attribute attribute,
                                             int32_t *out_value) {
-  DisplayConfigVariableInfo variable_config = *framebuffer_config_;
+  DisplayConfigVariableInfo variable_config;
+  DisplayError error = display_intf_->GetFrameBufferConfig(&variable_config);
+  if (error != kErrorNone) {
+    DLOGV("Get variable config failed. Error = %d", error);
+    return HWC2::Error::BadDisplay;
+  }
 
   switch (attribute) {
     case HWC2::Attribute::VsyncPeriod:
@@ -609,7 +610,7 @@
 }
 
 HWC2::Error HWCDisplay::SetClientTarget(buffer_handle_t target, int32_t acquire_fence,
-                                        int32_t dataspace) {
+                                        int32_t dataspace, hwc_region_t damage) {
   // TODO(user): SurfaceFlinger gives us a null pointer here when doing full SDE composition
   // The error is problematic for layer caching as it would overwrite our cached client target.
   // Reported bug 28569722 to resolve this.
@@ -617,7 +618,14 @@
   if (target == nullptr) {
     return HWC2::Error::None;
   }
+
+  if (acquire_fence == 0) {
+    DLOGE("acquire_fence is zero");
+    return HWC2::Error::BadParameter;
+  }
+
   client_target_->SetLayerBuffer(target, acquire_fence);
+  client_target_->SetLayerSurfaceDamage(damage);
   // Ignoring dataspace for now
   return HWC2::Error::None;
 }
@@ -627,6 +635,10 @@
   return HWC2::Error::None;
 }
 
+DisplayError HWCDisplay::SetMixerResolution(uint32_t width, uint32_t height) {
+  return kErrorNotSupported;
+}
+
 void HWCDisplay::SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type) {
   dump_frame_count_ = count;
   dump_frame_index_ = 0;
@@ -691,11 +703,6 @@
     flush_ = true;
   }
 
-  // If current draw cycle has different set of layers updating in comparison to previous cycle,
-  // cache content using GPU again.
-  // If set of updating layers remains same, use cached buffer and replace layers marked for GPU
-  // composition with SDE so that SurfaceFlinger does not compose them. Set cache inuse here.
-  bool needs_fb_refresh = NeedsFrameBufferRefresh();
   for (auto hwc_layer : layer_set_) {
     Layer *layer = hwc_layer->GetSDMLayer();
     LayerComposition &composition = layer->composition;
@@ -705,25 +712,28 @@
       layer_requests_[hwc_layer->GetId()] = HWC2::LayerRequest::ClearClientTarget;
     }
 
-    if (!needs_fb_refresh && composition == kCompositionGPU) {
-      composition = kCompositionSDE;
-    }
-    HWC2::Composition current_hwc_composition  = hwc_layer->GetCompositionType();
-    // Convert the SDM layer composition to HWC2 type
+    HWC2::Composition requested_composition = hwc_layer->GetClientRequestedCompositionType();
+    // Set SDM composition to HWC2 type in HWCLayer
     hwc_layer->SetComposition(composition);
-    // Update the changes list only if the HWC2 comp type changed from the previous cycle
-    if (current_hwc_composition != hwc_layer->GetCompositionType()) {
-      layer_changes_[hwc_layer->GetId()] = hwc_layer->GetCompositionType();
+    HWC2::Composition device_composition  = hwc_layer->GetDeviceSelectedCompositionType();
+    // Update the changes list only if the requested composition is different from SDM comp type
+    // TODO(user): Take Care of other comptypes(BLIT)
+    if (requested_composition != device_composition) {
+      layer_changes_[hwc_layer->GetId()] = device_composition;
     }
   }
   *out_num_types = UINT32(layer_changes_.size());
   *out_num_requests = UINT32(layer_requests_.size());
   validated_ = true;
-  return HWC2::Error::None;
+  if (*out_num_types > 0) {
+    return HWC2::Error::HasChanges;
+  } else {
+    return HWC2::Error::None;
+  }
 }
 
 HWC2::Error HWCDisplay::AcceptDisplayChanges() {
-  if (!validated_) {
+  if (!validated_ && !layer_set_.empty()) {
     return HWC2::Error::NotValidated;
   }
   return HWC2::Error::None;
@@ -731,6 +741,14 @@
 
 HWC2::Error HWCDisplay::GetChangedCompositionTypes(uint32_t *out_num_elements,
                                                    hwc2_layer_t *out_layers, int32_t *out_types) {
+  if (layer_set_.empty()) {
+    return HWC2::Error::None;
+  }
+
+  if (!validated_) {
+    DLOGW("Display is not validated");
+    return HWC2::Error::NotValidated;
+  }
   *out_num_elements = UINT32(layer_changes_.size());
   if (out_layers != nullptr && out_types != nullptr) {
     int i = 0;
@@ -764,6 +782,10 @@
   // Use for sharing blit buffers and
   // writing wfd buffer directly to output if there is full GPU composition
   // and no color conversion needed
+  if (layer_set_.empty()) {
+    return HWC2::Error::None;
+  }
+
   if (!validated_) {
     DLOGW("Display is not validated");
     return HWC2::Error::NotValidated;
@@ -782,7 +804,7 @@
 }
 
 HWC2::Error HWCDisplay::CommitLayerStack(void) {
-  if (shutdown_pending_) {
+  if (shutdown_pending_ || layer_set_.empty()) {
     return HWC2::Error::None;
   }
 
@@ -846,6 +868,7 @@
         layer_buffer->release_fence_fd = -1;
       } else if (layer->composition != kCompositionGPU) {
         hwc_layer->PushReleaseFence(layer_buffer->release_fence_fd);
+        layer_buffer->release_fence_fd = -1;
       }
     }
 
@@ -855,19 +878,21 @@
     }
   }
 
+  *out_retire_fence = stored_retire_fence_;
   if (!flush_) {
     // if swapinterval property is set to 0 then close and reset the list retire fence
     if (swap_interval_zero_) {
       close(layer_stack_.retire_fence_fd);
       layer_stack_.retire_fence_fd = -1;
     }
-    *out_retire_fence = stored_retire_fence_;
     stored_retire_fence_ = layer_stack_.retire_fence_fd;
 
     if (dump_frame_count_) {
       dump_frame_count_--;
       dump_frame_index_++;
     }
+  } else {
+    stored_retire_fence_ = -1;
   }
   geometry_changes_ = GeometryChanges::kNone;
   flush_ = false;
@@ -875,31 +900,6 @@
   return status;
 }
 
-bool HWCDisplay::NeedsFrameBufferRefresh(void) {
-  // Frame buffer needs to be refreshed for the following reasons:
-  // 1. Any layer is marked skip in the current layer stack.
-  // 2. Any layer is added/removed/layer properties changes in the current layer stack.
-  // 3. Any layer handle is changed and it is marked for GPU composition
-  // 4. Any layer's current composition is different from previous composition.
-  if (layer_stack_.flags.skip_present || layer_stack_.flags.geometry_changed) {
-    return true;
-  }
-
-  for (auto layer : layer_stack_.layers) {
-    // need FB refresh for s3d case
-    if (layer->input_buffer->s3d_format != kS3dFormatNone) {
-      return true;
-    }
-
-    if (layer->composition == kCompositionGPUTarget ||
-        layer->composition == kCompositionBlitTarget) {
-      continue;
-    }
-  }
-
-  return false;
-}
-
 void HWCDisplay::SetIdleTimeoutMs(uint32_t timeout_ms) {
   return;
 }
@@ -914,16 +914,6 @@
   return error;
 }
 
-DisplayError HWCDisplay::ControlPartialUpdate(bool enable, uint32_t *pending) {
-  DisplayError error = kErrorNone;
-
-  if (display_intf_) {
-    error = display_intf_->ControlPartialUpdate(enable, pending);
-  }
-
-  return error;
-}
-
 LayerBufferFormat HWCDisplay::GetSDMFormat(const int32_t &source, const int flags) {
   LayerBufferFormat format = kFormatInvalid;
   if (flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) {
@@ -1234,45 +1224,29 @@
 
 int HWCDisplay::SetFrameBufferResolution(uint32_t x_pixels, uint32_t y_pixels) {
   if (x_pixels <= 0 || y_pixels <= 0) {
-    DLOGV("Unsupported config: x_pixels=%d, y_pixels=%d", x_pixels, y_pixels);
+    DLOGW("Unsupported config: x_pixels=%d, y_pixels=%d", x_pixels, y_pixels);
     return -EINVAL;
   }
 
-  if (framebuffer_config_->x_pixels == x_pixels && framebuffer_config_->y_pixels == y_pixels) {
-    return 0;
-  }
-
-  DisplayConfigVariableInfo active_config;
-  uint32_t active_config_index = 0;
-  display_intf_->GetActiveConfig(&active_config_index);
-  DisplayError error = display_intf_->GetConfig(active_config_index, &active_config);
+  DisplayConfigVariableInfo fb_config;
+  DisplayError error = display_intf_->GetFrameBufferConfig(&fb_config);
   if (error != kErrorNone) {
-    DLOGV("GetConfig variable info failed. Error = %d", error);
+    DLOGV("Get frame buffer config failed. Error = %d", error);
     return -EINVAL;
   }
 
-  if (active_config.x_pixels <= 0 || active_config.y_pixels <= 0) {
-    DLOGV("Invalid panel resolution (%dx%d)", active_config.x_pixels, active_config.y_pixels);
+  fb_config.x_pixels = x_pixels;
+  fb_config.y_pixels = y_pixels;
+
+  error = display_intf_->SetFrameBufferConfig(fb_config);
+  if (error != kErrorNone) {
+    DLOGV("Set frame buffer config failed. Error = %d", error);
     return -EINVAL;
   }
 
   // Create rects to represent the new source and destination crops
   LayerRect crop = LayerRect(0, 0, FLOAT(x_pixels), FLOAT(y_pixels));
-  LayerRect dst = LayerRect(0, 0, FLOAT(active_config.x_pixels), FLOAT(active_config.y_pixels));
-  // Set rotate90 to false since this is taken care of during regular composition.
-  bool rotate90 = false;
-  error = display_intf_->IsScalingValid(crop, dst, rotate90);
-  if (error != kErrorNone) {
-    DLOGV("Unsupported resolution: (%dx%d)", x_pixels, y_pixels);
-    return -EINVAL;
-  }
-
-  framebuffer_config_->x_pixels = x_pixels;
-  framebuffer_config_->y_pixels = y_pixels;
-  framebuffer_config_->vsync_period_ns = active_config.vsync_period_ns;
-  framebuffer_config_->x_dpi = active_config.x_dpi;
-  framebuffer_config_->y_dpi = active_config.y_dpi;
-
+  LayerRect dst = LayerRect(0, 0, FLOAT(fb_config.x_pixels), FLOAT(fb_config.y_pixels));
   auto client_target_layer = client_target_->GetSDMLayer();
   client_target_layer->src_rect = crop;
   client_target_layer->dst_rect = dst;
@@ -1298,68 +1272,32 @@
   client_target_layer->input_buffer->height = UINT32(aligned_height);
   client_target_layer->plane_alpha = 255;
 
-  DLOGI("New framebuffer resolution (%dx%d)", framebuffer_config_->x_pixels,
-        framebuffer_config_->y_pixels);
+  DLOGI("New framebuffer resolution (%dx%d)", fb_config.x_pixels, fb_config.y_pixels);
 
   return 0;
 }
 
 void HWCDisplay::GetFrameBufferResolution(uint32_t *x_pixels, uint32_t *y_pixels) {
-  *x_pixels = framebuffer_config_->x_pixels;
-  *y_pixels = framebuffer_config_->y_pixels;
+  DisplayConfigVariableInfo fb_config;
+  display_intf_->GetFrameBufferConfig(&fb_config);
+
+  *x_pixels = fb_config.x_pixels;
+  *y_pixels = fb_config.y_pixels;
 }
 
-void HWCDisplay::ScaleDisplayFrame(hwc_rect_t *display_frame) {
-  if (!IsFrameBufferScaled()) {
-    return;
-  }
-
-  uint32_t active_config_index = 0;
-  display_intf_->GetActiveConfig(&active_config_index);
-  DisplayConfigVariableInfo active_config;
-  DisplayError error = display_intf_->GetConfig(active_config_index, &active_config);
-  if (error != kErrorNone) {
-    DLOGE("GetConfig variable info failed. Error = %d", error);
-    return;
-  }
-
-  float custom_x_pixels = FLOAT(framebuffer_config_->x_pixels);
-  float custom_y_pixels = FLOAT(framebuffer_config_->y_pixels);
-  float active_x_pixels = FLOAT(active_config.x_pixels);
-  float active_y_pixels = FLOAT(active_config.y_pixels);
-  float x_pixels_ratio = active_x_pixels / custom_x_pixels;
-  float y_pixels_ratio = active_y_pixels / custom_y_pixels;
-  float layer_width = FLOAT(display_frame->right - display_frame->left);
-  float layer_height = FLOAT(display_frame->bottom - display_frame->top);
-
-  display_frame->left = INT(x_pixels_ratio * FLOAT(display_frame->left));
-  display_frame->top = INT(y_pixels_ratio * FLOAT(display_frame->top));
-  display_frame->right = INT(FLOAT(display_frame->left) + layer_width * x_pixels_ratio);
-  display_frame->bottom = INT(FLOAT(display_frame->top) + layer_height * y_pixels_ratio);
-}
-
-bool HWCDisplay::IsFrameBufferScaled() {
-  if (framebuffer_config_->x_pixels == 0 || framebuffer_config_->y_pixels == 0) {
-    return false;
-  }
-  uint32_t panel_x_pixels = 0;
-  uint32_t panel_y_pixels = 0;
-  GetPanelResolution(&panel_x_pixels, &panel_y_pixels);
-  return (framebuffer_config_->x_pixels != panel_x_pixels) ||
-         (framebuffer_config_->y_pixels != panel_y_pixels);
+DisplayError HWCDisplay::GetMixerResolution(uint32_t *x_pixels, uint32_t *y_pixels) {
+  return display_intf_->GetMixerResolution(x_pixels, y_pixels);
 }
 
 void HWCDisplay::GetPanelResolution(uint32_t *x_pixels, uint32_t *y_pixels) {
-  DisplayConfigVariableInfo active_config;
-  uint32_t active_config_index = 0;
-  display_intf_->GetActiveConfig(&active_config_index);
-  DisplayError error = display_intf_->GetConfig(active_config_index, &active_config);
-  if (error != kErrorNone) {
-    DLOGE("GetConfig variable info failed. Error = %d", error);
-    return;
-  }
-  *x_pixels = active_config.x_pixels;
-  *y_pixels = active_config.y_pixels;
+  DisplayConfigVariableInfo display_config;
+  uint32_t active_index = 0;
+
+  display_intf_->GetActiveConfig(&active_index);
+  display_intf_->GetConfig(active_index, &display_config);
+
+  *x_pixels = display_config.x_pixels;
+  *y_pixels = display_config.y_pixels;
 }
 
 int HWCDisplay::SetDisplayStatus(uint32_t display_status) {
@@ -1505,8 +1443,9 @@
   return display_intf_->GetNumVariableInfoConfigs(count) == kErrorNone ? 0 : -1;
 }
 
-int HWCDisplay::GetDisplayAttributesForConfig(int config, DisplayConfigVariableInfo *attributes) {
-  return display_intf_->GetConfig(UINT32(config), attributes) == kErrorNone ? 0 : -1;
+int HWCDisplay::GetDisplayAttributesForConfig(int config,
+                                            DisplayConfigVariableInfo *display_attributes) {
+  return display_intf_->GetConfig(UINT32(config), display_attributes) == kErrorNone ? 0 : -1;
 }
 
 bool HWCDisplay::SingleLayerUpdating(void) {
@@ -1522,6 +1461,24 @@
   return (updating_count == 1);
 }
 
+bool HWCDisplay::IsLayerUpdating(const Layer *layer) {
+  // Layer should be considered updating if
+  //   a) layer is in single buffer mode, or
+  //   b) valid dirty_regions(android specific hint for updating status), or
+  //   c) layer stack geometry has changed (TODO(user): Remove when SDM accepts
+  //      geometry_changed as bit fields).
+  return (layer->flags.single_buffer || IsSurfaceUpdated(layer->dirty_regions) ||
+          geometry_changes_);
+}
+
+bool HWCDisplay::IsSurfaceUpdated(const std::vector<LayerRect> &dirty_regions) {
+  // based on dirty_regions determine if its updating
+  // dirty_rect count = 0 - whole layer - updating.
+  // dirty_rect count = 1 or more valid rects - updating.
+  // dirty_rect count = 1 with (0,0,0,0) - not updating.
+  return (dirty_regions.empty() || IsValid(dirty_regions.at(0)));
+}
+
 uint32_t HWCDisplay::SanitizeRefreshRate(uint32_t req_refresh_rate) {
   uint32_t refresh_rate = req_refresh_rate;
 
@@ -1565,12 +1522,18 @@
   os << "HWC2 LayerDump:" << std::endl;
   for (auto layer : layer_set_) {
     auto sdm_layer = layer->GetSDMLayer();
+    auto transform = sdm_layer->transform;
     os << "-------------------------------" << std::endl;
     os << "layer_id: " << layer->GetId() << std::endl;
     os << "\tz: " << layer->GetZ() << std::endl;
-    os << "\tcomposition: " << to_string(layer->GetCompositionType()).c_str() << std::endl;
+    os << "\tclient(SF) composition: " <<
+          to_string(layer->GetClientRequestedCompositionType()).c_str() << std::endl;
+    os << "\tdevice(SDM) composition: " <<
+          to_string(layer->GetDeviceSelectedCompositionType()).c_str() << std::endl;
     os << "\tplane_alpha: " << std::to_string(sdm_layer->plane_alpha).c_str() << std::endl;
     os << "\tformat: " << GetFormatString(sdm_layer->input_buffer->format) << std::endl;
+    os << "\ttransform: rot: " << transform.rotation << " flip_h: " << transform.flip_horizontal <<
+          " flip_v: "<< transform.flip_vertical << std::endl;
     os << "\tbuffer_id: " << std::hex << "0x" << sdm_layer->input_buffer->buffer_id << std::dec
        << std::endl;
   }
diff --git a/msm8996/sdm/libs/hwc2/hwc_display.h b/msm8996/sdm/libs/hwc2/hwc_display.h
index c3ffcb4..69a2dea 100644
--- a/msm8996/sdm/libs/hwc2/hwc_display.h
+++ b/msm8996/sdm/libs/hwc2/hwc_display.h
@@ -92,15 +92,19 @@
   virtual void SetIdleTimeoutMs(uint32_t timeout_ms);
   virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
   virtual DisplayError SetMaxMixerStages(uint32_t max_mixer_stages);
-  virtual DisplayError ControlPartialUpdate(bool enable, uint32_t *pending);
+  virtual DisplayError ControlPartialUpdate(bool enable, uint32_t *pending) {
+    return kErrorNotSupported;
+  }
   virtual HWC2::PowerMode GetLastPowerMode();
   virtual int SetFrameBufferResolution(uint32_t x_pixels, uint32_t y_pixels);
   virtual void GetFrameBufferResolution(uint32_t *x_pixels, uint32_t *y_pixels);
-  virtual void GetPanelResolution(uint32_t *x_pixels, uint32_t *y_pixels);
   virtual int SetDisplayStatus(uint32_t display_status);
   virtual int OnMinHdcpEncryptionLevelChange(uint32_t min_enc_level);
   virtual int Perform(uint32_t operation, ...);
   virtual void SetSecureDisplay(bool secure_display_active);
+  virtual DisplayError SetMixerResolution(uint32_t width, uint32_t height);
+  virtual DisplayError GetMixerResolution(uint32_t *width, uint32_t *height);
+  virtual void GetPanelResolution(uint32_t *width, uint32_t *height);
   virtual std::string Dump(void);
 
   // Captures frame output in the buffer specified by output_buffer_info. The API is
@@ -119,7 +123,8 @@
   virtual int SetActiveDisplayConfig(int config);
   virtual int GetActiveDisplayConfig(uint32_t *config);
   virtual int GetDisplayConfigCount(uint32_t *count);
-  virtual int GetDisplayAttributesForConfig(int config, DisplayConfigVariableInfo *attributes);
+  virtual int GetDisplayAttributesForConfig(int config,
+                                            DisplayConfigVariableInfo *display_attributes);
 
   int SetPanelBrightness(int level);
   int GetPanelBrightness(int *level);
@@ -136,7 +141,7 @@
   virtual HWC2::Error GetActiveConfig(hwc2_config_t *out_config);
   virtual HWC2::Error SetActiveConfig(hwc2_config_t config);
   virtual HWC2::Error SetClientTarget(buffer_handle_t target, int32_t acquire_fence,
-                                      int32_t dataspace);
+                                      int32_t dataspace, hwc_region_t damage);
   virtual HWC2::Error SetColorMode(int32_t /*android_color_mode_t*/ mode) {
     return HWC2::Error::Unsupported;
   }
@@ -193,15 +198,18 @@
   virtual HWC2::Error PrepareLayerStack(uint32_t *out_num_types, uint32_t *out_num_requests);
   virtual HWC2::Error CommitLayerStack(void);
   virtual HWC2::Error PostCommitLayerStack(int32_t *out_retire_fence);
+  virtual DisplayError DisablePartialUpdateOneFrame() {
+    return kErrorNotSupported;
+  }
   LayerBufferFormat GetSDMFormat(const int32_t &source, const int flags);
   const char *GetHALPixelFormatString(int format);
   const char *GetDisplayString();
-  void ScaleDisplayFrame(hwc_rect_t *display_frame);
   void MarkLayersForGPUBypass(void);
   void MarkLayersForClientComposition(void);
   virtual void ApplyScanAdjustment(hwc_rect_t *display_frame);
-  bool NeedsFrameBufferRefresh(void);
   bool SingleLayerUpdating(void);
+  bool IsSurfaceUpdated(const std::vector<LayerRect> &dirty_regions);
+  bool IsLayerUpdating(const Layer *layer);
   uint32_t SanitizeRefreshRate(uint32_t req_refresh_rate);
   virtual void CloseAcquireFds();
 
@@ -229,7 +237,6 @@
   bool dump_input_layers_ = false;
   HWC2::PowerMode last_power_mode_;
   bool swap_interval_zero_ = false;
-  DisplayConfigVariableInfo *framebuffer_config_ = NULL;
   bool display_paused_ = false;
   uint32_t min_refresh_rate_ = 0;
   uint32_t max_refresh_rate_ = 0;
@@ -248,14 +255,13 @@
   bool validated_ = false;
   bool color_tranform_failed_ = false;
   HWCColorMode *color_mode_ = NULL;
+  int32_t stored_retire_fence_ = -1;
 
  private:
-  bool IsFrameBufferScaled();
   void DumpInputBuffers(void);
   BlitEngine *blit_engine_ = NULL;
   qService::QService *qservice_ = NULL;
   DisplayClass display_class_;
-  int32_t stored_retire_fence_ = -1;
   uint32_t geometry_changes_ = GeometryChanges::kNone;
 };
 
diff --git a/msm8996/sdm/libs/hwc2/hwc_display_external.cpp b/msm8996/sdm/libs/hwc2/hwc_display_external.cpp
index 73ed0e8..caacb11 100644
--- a/msm8996/sdm/libs/hwc2/hwc_display_external.cpp
+++ b/msm8996/sdm/libs/hwc2/hwc_display_external.cpp
@@ -49,6 +49,7 @@
                                HWCDisplay **hwc_display) {
   uint32_t external_width = 0;
   uint32_t external_height = 0;
+  DisplayError error = kErrorNone;
 
   HWCDisplay *hwc_display_external = new HWCDisplayExternal(core_intf, callbacks, qservice);
   int status = hwc_display_external->Init();
@@ -57,7 +58,10 @@
     return status;
   }
 
-  hwc_display_external->GetPanelResolution(&external_width, &external_height);
+  error = hwc_display_external->GetMixerResolution(&external_width, &external_height);
+  if (error != kErrorNone) {
+    return -EINVAL;
+  }
 
   if (primary_width && primary_height) {
     // use_primary_res means HWCDisplayExternal should directly set framebuffer resolution to the
@@ -144,29 +148,29 @@
     return;
   }
 
-  uint32_t panel_width = 0;
-  uint32_t panel_height = 0;
-  GetPanelResolution(&panel_width, &panel_height);
+  uint32_t mixer_width = 0;
+  uint32_t mixer_height = 0;
+  GetMixerResolution(&mixer_width, &mixer_height);
 
-  if (panel_width == 0 || panel_height == 0) {
-    DLOGV("Invalid panel dimensions (%d, %d)", panel_width, panel_height);
+  if (mixer_width == 0 || mixer_height == 0) {
+    DLOGV("Invalid mixer dimensions (%d, %d)", mixer_width, mixer_height);
     return;
   }
 
-  uint32_t new_panel_width = UINT32(panel_width * FLOAT(1.0f - width_ratio));
-  uint32_t new_panel_height = UINT32(panel_height * FLOAT(1.0f - height_ratio));
+  uint32_t new_mixer_width = UINT32(mixer_width * FLOAT(1.0f - width_ratio));
+  uint32_t new_mixer_height = UINT32(mixer_height * FLOAT(1.0f - height_ratio));
 
-  int x_offset = INT((FLOAT(panel_width) * width_ratio) / 2.0f);
-  int y_offset = INT((FLOAT(panel_height) * height_ratio) / 2.0f);
+  int x_offset = INT((FLOAT(mixer_width) * width_ratio) / 2.0f);
+  int y_offset = INT((FLOAT(mixer_height) * height_ratio) / 2.0f);
 
-  display_frame->left =
-      (display_frame->left * INT32(new_panel_width) / INT32(panel_width)) + x_offset;
-  display_frame->top =
-      (display_frame->top * INT32(new_panel_height) / INT32(panel_height)) + y_offset;
-  display_frame->right =
-      ((display_frame->right * INT32(new_panel_width)) / INT32(panel_width)) + x_offset;
-  display_frame->bottom =
-      ((display_frame->bottom * INT32(new_panel_height)) / INT32(panel_height)) + y_offset;
+  display_frame->left = (display_frame->left * INT32(new_mixer_width) / INT32(mixer_width))
+                        + x_offset;
+  display_frame->top = (display_frame->top * INT32(new_mixer_height) / INT32(mixer_height)) +
+                       y_offset;
+  display_frame->right = ((display_frame->right * INT32(new_mixer_width)) / INT32(mixer_width)) +
+                         x_offset;
+  display_frame->bottom = ((display_frame->bottom * INT32(new_mixer_height)) / INT32(mixer_height))
+                          + y_offset;
 }
 
 void HWCDisplayExternal::SetSecureDisplay(bool secure_display_active) {
diff --git a/msm8996/sdm/libs/hwc2/hwc_display_primary.cpp b/msm8996/sdm/libs/hwc2/hwc_display_primary.cpp
index 517959e..eeb7dbb 100644
--- a/msm8996/sdm/libs/hwc2/hwc_display_primary.cpp
+++ b/msm8996/sdm/libs/hwc2/hwc_display_primary.cpp
@@ -60,7 +60,7 @@
     return status;
   }
 
-  hwc_display_primary->GetPanelResolution(&primary_width, &primary_height);
+  hwc_display_primary->GetMixerResolution(&primary_width, &primary_height);
   int width = 0, height = 0;
   HWCDebugHandler::Get()->GetProperty("sdm.fb_size_width", &width);
   HWCDebugHandler::Get()->GetProperty("sdm.fb_size_height", &height);
@@ -197,7 +197,6 @@
     handle_idle_timeout_ = false;
   }
 
-  // TODO(user): Validate this
   if (layer_set_.empty()) {
     flush_ = true;
     return status;
@@ -412,9 +411,6 @@
   frame_capture_buffer_queued_ = false;
   post_processed_output_ = false;
   output_buffer_ = {};
-
-  uint32_t pending = 0;  // Just a temporary to satisfy the API
-  ControlPartialUpdate(true /* enable */, &pending);
 }
 
 void HWCDisplayPrimary::HandleFrameDump() {
@@ -443,9 +439,6 @@
     output_buffer_ = {};
     output_buffer_info_ = {};
     output_buffer_base_ = nullptr;
-
-    uint32_t pending = 0;  // Just a temporary to satisfy the API
-    ControlPartialUpdate(true /* enable */, &pending);
   }
 }
 
@@ -483,8 +476,7 @@
 
   output_buffer_base_ = buffer;
   post_processed_output_ = true;
-  uint32_t pending = 0;  // Just a temporary to satisfy the API
-  ControlPartialUpdate(false /* enable */, &pending);
+  DisablePartialUpdateOneFrame();
 }
 
 int HWCDisplayPrimary::FrameCaptureAsync(const BufferInfo &output_buffer_info,
@@ -518,11 +510,38 @@
   frame_capture_buffer_queued_ = true;
   // Status is only cleared on a new call to dump and remains valid otherwise
   frame_capture_status_ = -EAGAIN;
-
-  uint32_t pending = 0;  // Just a temporary to satisfy the API
-  ControlPartialUpdate(false /* enable */, &pending);
+  DisablePartialUpdateOneFrame();
 
   return 0;
 }
 
+DisplayError HWCDisplayPrimary::ControlPartialUpdate(bool enable, uint32_t *pending) {
+  DisplayError error = kErrorNone;
+
+  if (display_intf_) {
+    error = display_intf_->ControlPartialUpdate(enable, pending);
+  }
+
+  return error;
+}
+
+DisplayError HWCDisplayPrimary::DisablePartialUpdateOneFrame() {
+  DisplayError error = kErrorNone;
+
+  if (display_intf_) {
+    error = display_intf_->DisablePartialUpdateOneFrame();
+  }
+
+  return error;
+}
+
+
+DisplayError HWCDisplayPrimary::SetMixerResolution(uint32_t width, uint32_t height) {
+  return display_intf_->SetMixerResolution(width, height);
+}
+
+DisplayError HWCDisplayPrimary::GetMixerResolution(uint32_t *width, uint32_t *height) {
+  return display_intf_->GetMixerResolution(width, height);
+}
+
 }  // namespace sdm
diff --git a/msm8996/sdm/libs/hwc2/hwc_display_primary.h b/msm8996/sdm/libs/hwc2/hwc_display_primary.h
index 62b311e..41b0c9f 100644
--- a/msm8996/sdm/libs/hwc2/hwc_display_primary.h
+++ b/msm8996/sdm/libs/hwc2/hwc_display_primary.h
@@ -64,12 +64,14 @@
   virtual void SetFrameDumpConfig(uint32_t count, uint32_t bit_mask_layer_type);
   virtual int FrameCaptureAsync(const BufferInfo &output_buffer_info, bool post_processed);
   virtual int GetFrameCaptureStatus() { return frame_capture_status_; }
+  virtual DisplayError ControlPartialUpdate(bool enable, uint32_t *pending);
 
  private:
   HWCDisplayPrimary(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
                     HWCCallbacks *callbacks, qService::QService *qservice);
   void SetMetaDataRefreshRateFlag(bool enable);
   virtual DisplayError SetDisplayMode(uint32_t mode);
+  virtual DisplayError DisablePartialUpdateOneFrame();
   void ProcessBootAnimCompleted(void);
   void SetQDCMSolidFillInfo(bool enable, uint32_t color);
   void ToggleCPUHint(bool set);
@@ -78,6 +80,8 @@
   void HandleFrameOutput();
   void HandleFrameCapture();
   void HandleFrameDump();
+  DisplayError SetMixerResolution(uint32_t width, uint32_t height);
+  DisplayError GetMixerResolution(uint32_t *width, uint32_t *height);
 
   BufferAllocator *buffer_allocator_ = nullptr;
   CPUHint *cpu_hint_ = nullptr;
diff --git a/msm8996/sdm/libs/hwc2/hwc_display_virtual.cpp b/msm8996/sdm/libs/hwc2/hwc_display_virtual.cpp
index 6c7edfb..89f313a 100644
--- a/msm8996/sdm/libs/hwc2/hwc_display_virtual.cpp
+++ b/msm8996/sdm/libs/hwc2/hwc_display_virtual.cpp
@@ -41,28 +41,32 @@
 namespace sdm {
 
 int HWCDisplayVirtual::Create(CoreInterface *core_intf, HWCCallbacks *callbacks, uint32_t width,
-                              uint32_t height, HWCDisplay **hwc_display) {
+                              uint32_t height, int32_t *format, HWCDisplay **hwc_display) {
   int status = 0;
   HWCDisplayVirtual *hwc_display_virtual = new HWCDisplayVirtual(core_intf, callbacks);
-  uint32_t virtual_width = 0, virtual_height = 0;
+
+  // TODO(user): Populate format correctly
+  DLOGI("Creating virtual display: w: %d h:%d format:0x%x", width, height, *format);
 
   status = hwc_display_virtual->Init();
   if (status) {
+    DLOGW("Failed to initialize virtual display");
     delete hwc_display_virtual;
     return status;
   }
 
   status = INT32(hwc_display_virtual->SetPowerMode(HWC2::PowerMode::On));
   if (status) {
+    DLOGW("Failed to set power mode on virtual display");
     Destroy(hwc_display_virtual);
     return status;
   }
 
-  hwc_display_virtual->GetPanelResolution(&virtual_width, &virtual_height);
-
+  // TODO(user): Validate that we support this width/height
   status = hwc_display_virtual->SetFrameBufferResolution(width, height);
 
   if (status) {
+    DLOGW("Failed to set virtual display FB resolution");
     Destroy(hwc_display_virtual);
     return status;
   }
@@ -83,12 +87,16 @@
 }
 
 int HWCDisplayVirtual::Init() {
+  output_buffer_ = new LayerBuffer();
   return HWCDisplay::Init();
 }
 
 int HWCDisplayVirtual::Deinit() {
   int status = 0;
-
+  if (output_buffer_) {
+    delete output_buffer_;
+    output_buffer_ = nullptr;
+  }
   status = HWCDisplay::Deinit();
 
   return status;
@@ -103,6 +111,7 @@
   }
 
   BuildLayerStack();
+  layer_stack_.output_buffer = output_buffer_;
   status = PrepareLayerStack(out_num_types, out_num_requests);
   return status;
 }
@@ -133,6 +142,13 @@
       }
 
       status = HWCDisplay::PostCommitLayerStack(out_retire_fence);
+      // On Virtual displays, use the output buffer release fence as the retire fence
+      // Close the layer stack retire fence as it is unused
+      if (layer_stack_.output_buffer) {
+        stored_retire_fence_ = layer_stack_.output_buffer->release_fence_fd;
+        close(layer_stack_.retire_fence_fd);
+        layer_stack_.retire_fence_fd = -1;
+      }
     }
   }
   CloseAcquireFds();
@@ -140,6 +156,9 @@
 }
 
 HWC2::Error HWCDisplayVirtual::SetOutputBuffer(buffer_handle_t buf, int32_t release_fence) {
+  if (buf == nullptr || release_fence == 0) {
+    return HWC2::Error::BadParameter;
+  }
   const private_handle_t *output_handle = static_cast<const private_handle_t *>(buf);
 
   // Fill output buffer parameters (width, height, format, plane information, fence)
@@ -180,7 +199,6 @@
     output_buffer_->planes[0].stride = UINT32(output_handle->width);
   }
 
-  layer_stack_.output_buffer = output_buffer_;
   return HWC2::Error::None;
 }
 
diff --git a/msm8996/sdm/libs/hwc2/hwc_display_virtual.h b/msm8996/sdm/libs/hwc2/hwc_display_virtual.h
index 271d15d..a68ac65 100644
--- a/msm8996/sdm/libs/hwc2/hwc_display_virtual.h
+++ b/msm8996/sdm/libs/hwc2/hwc_display_virtual.h
@@ -38,8 +38,8 @@
 
 class HWCDisplayVirtual : public HWCDisplay {
  public:
-  static int Create(CoreInterface *core_intf, HWCCallbacks *callbacks, uint32_t primary_width,
-                    uint32_t primary_height, HWCDisplay **hwc_display);
+  static int Create(CoreInterface *core_intf, HWCCallbacks *callbacks, uint32_t width,
+                    uint32_t height, int32_t *format, HWCDisplay **hwc_display);
   static void Destroy(HWCDisplay *hwc_display);
   virtual int Init();
   virtual int Deinit();
diff --git a/msm8996/sdm/libs/hwc2/hwc_layers.cpp b/msm8996/sdm/libs/hwc2/hwc_layers.cpp
index 2591898..b9f7a6e 100644
--- a/msm8996/sdm/libs/hwc2/hwc_layers.cpp
+++ b/msm8996/sdm/libs/hwc2/hwc_layers.cpp
@@ -58,6 +58,11 @@
     return HWC2::Error::BadParameter;
   }
 
+  if (acquire_fence == 0) {
+    DLOGE("acquire_fence is zero");
+    return HWC2::Error::BadParameter;
+  }
+
   const private_handle_t *handle = static_cast<const private_handle_t *>(buffer);
   LayerBuffer *layer_buffer = layer_->input_buffer;
   layer_buffer->width = UINT32(handle->width);
@@ -89,6 +94,7 @@
 
 HWC2::Error HWCLayer::SetLayerSurfaceDamage(hwc_region_t damage) {
   auto num_dirty_rects = damage.numRects;
+  layer_->dirty_regions.clear();
   if (num_dirty_rects > 0) {
     for (uint32_t i = 0; i <= damage.numRects; i++) {
       LayerRect rect;
@@ -100,20 +106,25 @@
 }
 
 HWC2::Error HWCLayer::SetLayerBlendMode(HWC2::BlendMode mode) {
+  LayerBlending blending = kBlendingPremultiplied;
   switch (mode) {
     case HWC2::BlendMode::Coverage:
-      layer_->blending = kBlendingCoverage;
+      blending = kBlendingCoverage;
       break;
     case HWC2::BlendMode::Premultiplied:
-      layer_->blending = kBlendingPremultiplied;
+      blending = kBlendingPremultiplied;
       break;
     case HWC2::BlendMode::None:
-      layer_->blending = kBlendingOpaque;
+      blending = kBlendingOpaque;
       break;
     default:
       return HWC2::Error::BadParameter;
   }
-  geometry_changes_ |= kBlendMode;
+
+  if (layer_->blending != blending) {
+    geometry_changes_ |= kBlendMode;
+    layer_->blending = blending;
+  }
   return HWC2::Error::None;
 }
 
@@ -128,7 +139,7 @@
 
 HWC2::Error HWCLayer::SetLayerCompositionType(HWC2::Composition type) {
   layer_->flags = {};   // Reset earlier flags
-  composition_ = type;  // Used to compute changes
+  client_requested_ = type;
   switch (type) {
     case HWC2::Composition::Client:
       layer_->flags.skip = true;
@@ -147,8 +158,7 @@
     default:
       return HWC2::Error::Unsupported;
   }
-  // TODO(user): Check if this should be set here or somewhere else
-  layer_->flags.updating = true;
+
   return HWC2::Error::None;
 }
 
@@ -159,60 +169,81 @@
 }
 
 HWC2::Error HWCLayer::SetLayerDisplayFrame(hwc_rect_t frame) {
-  SetRect(frame, &layer_->dst_rect);
-  geometry_changes_ |= kDisplayFrame;
+  LayerRect dst_rect = {};
+  SetRect(frame, &dst_rect);
+  if (layer_->dst_rect != dst_rect) {
+    geometry_changes_ |= kDisplayFrame;
+    layer_->dst_rect = dst_rect;
+  }
   return HWC2::Error::None;
 }
 
 HWC2::Error HWCLayer::SetLayerPlaneAlpha(float alpha) {
   // Conversion of float alpha in range 0.0 to 1.0 similar to the HWC Adapter
-  layer_->plane_alpha = static_cast<uint8_t>(std::round(255.0f * alpha));
-  geometry_changes_ |= kPlaneAlpha;
+  uint8_t plane_alpha = static_cast<uint8_t>(std::round(255.0f * alpha));
+  if (layer_->plane_alpha != plane_alpha) {
+    geometry_changes_ |= kPlaneAlpha;
+    layer_->plane_alpha = plane_alpha;
+  }
+
   return HWC2::Error::None;
 }
 
 HWC2::Error HWCLayer::SetLayerSourceCrop(hwc_frect_t crop) {
-  SetRect(crop, &layer_->src_rect);
-  geometry_changes_ |= kSourceCrop;
+  LayerRect src_rect = {};
+  SetRect(crop, &src_rect);
+  if (layer_->src_rect != src_rect) {
+    geometry_changes_ |= kSourceCrop;
+    layer_->src_rect = src_rect;
+  }
+
   return HWC2::Error::None;
 }
 
 HWC2::Error HWCLayer::SetLayerTransform(HWC2::Transform transform) {
+  LayerTransform layer_transform = {};
   switch (transform) {
     case HWC2::Transform::FlipH:
-      layer_->transform.flip_horizontal = true;
+      layer_transform.flip_horizontal = true;
       break;
     case HWC2::Transform::FlipV:
-      layer_->transform.flip_vertical = true;
+      layer_transform.flip_vertical = true;
       break;
     case HWC2::Transform::Rotate90:
-      layer_->transform.rotation = 90.0f;
+      layer_transform.rotation = 90.0f;
       break;
     case HWC2::Transform::Rotate180:
-      layer_->transform.rotation = 180.0f;
+      layer_transform.flip_horizontal = true;
+      layer_transform.flip_vertical = true;
       break;
     case HWC2::Transform::Rotate270:
-      layer_->transform.rotation = 270.0f;
+      layer_transform.rotation = 90.0f;
+      layer_transform.flip_horizontal = true;
+      layer_transform.flip_vertical = true;
       break;
     case HWC2::Transform::FlipHRotate90:
-      layer_->transform.rotation = 90.0f;
-      layer_->transform.flip_horizontal = true;
+      layer_transform.rotation = 90.0f;
+      layer_transform.flip_horizontal = true;
       break;
     case HWC2::Transform::FlipVRotate90:
-      layer_->transform.rotation = 90.0f;
-      layer_->transform.flip_vertical = true;
+      layer_transform.rotation = 90.0f;
+      layer_transform.flip_vertical = true;
       break;
-    default:
-      layer_->transform.rotation = 0.0f;
-      layer_->transform.flip_horizontal = false;
-      layer_->transform.flip_vertical = false;
+    case HWC2::Transform::None:
+      // do nothing
+      break;
   }
-  geometry_changes_ |= kTransform;
+
+  if (layer_->transform != layer_transform) {
+    geometry_changes_ |= kTransform;
+    layer_->transform = layer_transform;
+  }
   return HWC2::Error::None;
 }
 
 HWC2::Error HWCLayer::SetLayerVisibleRegion(hwc_region_t visible) {
   auto num_dirty_rects = visible.numRects;
+  layer_->visible_regions.clear();
   if (num_dirty_rects > 0) {
     for (uint32_t i = 0; i <= visible.numRects; i++) {
       LayerRect rect;
@@ -225,8 +256,10 @@
 }
 
 HWC2::Error HWCLayer::SetLayerZOrder(uint32_t z) {
-  z_ = z;
-  geometry_changes_ |= kZOrder;
+  if (z_ != z) {
+    geometry_changes_ |= kZOrder;
+    z_ = z;
+  }
   return HWC2::Error::None;
 }
 
@@ -490,24 +523,26 @@
   return frame_rate;
 }
 
-void HWCLayer::SetComposition(const LayerComposition &source) {
-  auto composition = HWC2::Composition::Invalid;
-  switch (source) {
+void HWCLayer::SetComposition(const LayerComposition &sdm_composition) {
+  auto hwc_composition = HWC2::Composition::Invalid;
+  switch (sdm_composition) {
     case kCompositionGPU:
-      composition = HWC2::Composition::Client;
+      hwc_composition = HWC2::Composition::Client;
       break;
     case kCompositionHWCursor:
-      composition = HWC2::Composition::Cursor;
+      hwc_composition = HWC2::Composition::Cursor;
       break;
     default:
-      composition = HWC2::Composition::Device;
+      hwc_composition = HWC2::Composition::Device;
       break;
   }
   // Update solid fill composition
-  if (layer_->composition == kCompositionSDE && layer_->flags.solid_fill != 0) {
-    composition = HWC2::Composition::SolidColor;
+  if (sdm_composition == kCompositionSDE && layer_->flags.solid_fill != 0) {
+    hwc_composition = HWC2::Composition::SolidColor;
   }
-  composition_ = composition;
+  device_selected_ = hwc_composition;
+
+  return;
 }
 void HWCLayer::PushReleaseFence(int32_t fence) {
   release_fences_.push(fence);
diff --git a/msm8996/sdm/libs/hwc2/hwc_layers.h b/msm8996/sdm/libs/hwc2/hwc_layers.h
index 1026ff2..56e0336 100644
--- a/msm8996/sdm/libs/hwc2/hwc_layers.h
+++ b/msm8996/sdm/libs/hwc2/hwc_layers.h
@@ -70,8 +70,9 @@
   HWC2::Error SetLayerTransform(HWC2::Transform transform);
   HWC2::Error SetLayerVisibleRegion(hwc_region_t visible);
   HWC2::Error SetLayerZOrder(uint32_t z);
-  void SetComposition(const LayerComposition &source);
-  HWC2::Composition GetCompositionType() { return composition_; }
+  void SetComposition(const LayerComposition &sdm_composition);
+  HWC2::Composition GetClientRequestedCompositionType() { return client_requested_; }
+  HWC2::Composition GetDeviceSelectedCompositionType() { return device_selected_; }
   uint32_t GetGeometryChanges() { return geometry_changes_; }
   void ResetGeometryChanges() { geometry_changes_ = GeometryChanges::kNone; }
   void PushReleaseFence(int32_t fence);
@@ -85,7 +86,10 @@
   static std::atomic<hwc2_layer_t> next_id_;
   std::queue<int32_t> release_fences_;
 
-  HWC2::Composition composition_ = HWC2::Composition::Device;
+  // Composition requested by client(SF)
+  HWC2::Composition client_requested_ = HWC2::Composition::Device;
+  // Composition selected by SDM
+  HWC2::Composition device_selected_ = HWC2::Composition::Device;
   uint32_t geometry_changes_ = GeometryChanges::kNone;
 
   void SetRect(const hwc_rect_t &source, LayerRect *target);
diff --git a/msm8996/sdm/libs/hwc2/hwc_session.cpp b/msm8996/sdm/libs/hwc2/hwc_session.cpp
index 28e0206..f75e6b8 100644
--- a/msm8996/sdm/libs/hwc2/hwc_session.cpp
+++ b/msm8996/sdm/libs/hwc2/hwc_session.cpp
@@ -236,15 +236,18 @@
 }
 
 int32_t HWCSession::CreateVirtualDisplay(hwc2_device_t *device, uint32_t width, uint32_t height,
-                                         hwc2_display_t *out_display_id) {
+                                         int32_t *format, hwc2_display_t *out_display_id) {
+  // TODO(user): Handle concurrency with HDMI
+  SCOPE_LOCK(locker_);
   if (!device) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
 
   HWCSession *hwc_session = static_cast<HWCSession *>(device);
-  auto status = hwc_session->CreateVirtualDisplayObject(width, height);
+  auto status = hwc_session->CreateVirtualDisplayObject(width, height, format);
   if (status == HWC2::Error::None)
     *out_display_id = HWC_DISPLAY_VIRTUAL;
+  DLOGI("Created virtual display id:% " PRIu64 " with res: %dx%d", *out_display_id, width, height);
   return INT32(status);
 }
 
@@ -255,10 +258,12 @@
 }
 
 int32_t HWCSession::DestroyVirtualDisplay(hwc2_device_t *device, hwc2_display_t display) {
+  SCOPE_LOCK(locker_);
   if (!device) {
     return HWC2_ERROR_BAD_DISPLAY;
   }
 
+  DLOGI("Destroying virtual display id:%" PRIu64, display);
   auto *hwc_session = static_cast<HWCSession *>(device);
 
   if (hwc_session->hwc_display_[display]) {
@@ -417,9 +422,10 @@
 }
 
 static int32_t SetClientTarget(hwc2_device_t *device, hwc2_display_t display,
-                               buffer_handle_t target, int32_t acquire_fence, int32_t dataspace) {
+                               buffer_handle_t target, int32_t acquire_fence,
+                               int32_t dataspace, hwc_region_t damage) {
   return HWCSession::CallDisplayFunction(device, display, &HWCDisplay::SetClientTarget, target,
-                                         acquire_fence, dataspace);
+                                         acquire_fence, dataspace, damage);
 }
 
 int32_t HWCSession::SetColorMode(hwc2_device_t *device, hwc2_display_t display,
@@ -571,7 +577,7 @@
   }
   // If validate fails, cancel the sequence lock so that other operations
   // (such as Dump or SetPowerMode) may succeed without blocking on the condition
-  if (status != HWC2::Error::None) {
+  if (status == HWC2::Error::BadDisplay) {
     SEQUENCE_CANCEL_SCOPE_LOCK(locker_);
   }
   return INT32(status);
@@ -678,11 +684,12 @@
 
 // TODO(user): handle locking
 
-HWC2::Error HWCSession::CreateVirtualDisplayObject(uint32_t width, uint32_t height) {
+HWC2::Error HWCSession::CreateVirtualDisplayObject(uint32_t width, uint32_t height,
+                                                   int32_t *format) {
   if (hwc_display_[HWC_DISPLAY_VIRTUAL]) {
     return HWC2::Error::NoResources;
   }
-  auto status = HWCDisplayVirtual::Create(core_intf_, &callbacks_, width, height,
+  auto status = HWCDisplayVirtual::Create(core_intf_, &callbacks_, width, height, format,
                                           &hwc_display_[HWC_DISPLAY_VIRTUAL]);
   // TODO(user): validate width and height support
   if (status)
@@ -830,6 +837,10 @@
       status = GetBWTransactionStatus(input_parcel, output_parcel);
       break;
 
+  case qService::IQService::SET_LAYER_MIXER_RESOLUTION:
+    status = SetMixerResolution(input_parcel);
+    break;
+
     default:
       DLOGW("QService command = %d is not supported", command);
       return -EINVAL;
@@ -996,25 +1007,26 @@
   return error;
 }
 
-android::status_t HWCSession::HandleGetDisplayAttributesForConfig(
-    const android::Parcel *input_parcel, android::Parcel *output_parcel) {
+android::status_t HWCSession::HandleGetDisplayAttributesForConfig(const android::Parcel
+                                                                  *input_parcel,
+                                                                  android::Parcel *output_parcel) {
   int config = input_parcel->readInt32();
   int dpy = input_parcel->readInt32();
   int error = android::BAD_VALUE;
-  DisplayConfigVariableInfo attributes;
+  DisplayConfigVariableInfo display_attributes;
 
   if (dpy > HWC_DISPLAY_VIRTUAL) {
     return android::BAD_VALUE;
   }
 
   if (hwc_display_[dpy]) {
-    error = hwc_display_[dpy]->GetDisplayAttributesForConfig(config, &attributes);
+    error = hwc_display_[dpy]->GetDisplayAttributesForConfig(config, &display_attributes);
     if (error == 0) {
-      output_parcel->writeInt32(INT(attributes.vsync_period_ns));
-      output_parcel->writeInt32(INT(attributes.x_pixels));
-      output_parcel->writeInt32(INT(attributes.y_pixels));
-      output_parcel->writeFloat(attributes.x_dpi);
-      output_parcel->writeFloat(attributes.y_dpi);
+      output_parcel->writeInt32(INT(display_attributes.vsync_period_ns));
+      output_parcel->writeInt32(INT(display_attributes.x_pixels));
+      output_parcel->writeInt32(INT(display_attributes.y_pixels));
+      output_parcel->writeFloat(display_attributes.x_dpi);
+      output_parcel->writeFloat(display_attributes.y_dpi);
       output_parcel->writeInt32(0);  // Panel type, unsupported.
     }
   }
@@ -1167,6 +1179,31 @@
   }
 }
 
+android::status_t HWCSession::SetMixerResolution(const android::Parcel *input_parcel) {
+  DisplayError error = kErrorNone;
+  uint32_t dpy = UINT32(input_parcel->readInt32());
+
+  if (dpy != HWC_DISPLAY_PRIMARY) {
+    DLOGI("Resoulution change not supported for this display %d", dpy);
+    return -EINVAL;
+  }
+
+  if (!hwc_display_[HWC_DISPLAY_PRIMARY]) {
+    DLOGI("Primary display is not initialized");
+    return -EINVAL;
+  }
+
+  uint32_t width = UINT32(input_parcel->readInt32());
+  uint32_t height = UINT32(input_parcel->readInt32());
+
+  error = hwc_display_[HWC_DISPLAY_PRIMARY]->SetMixerResolution(width, height);
+  if (error != kErrorNone) {
+    return -EINVAL;
+  }
+
+  return 0;
+}
+
 void HWCSession::DynamicDebug(const android::Parcel *input_parcel) {
   int type = input_parcel->readInt32();
   bool enable = (input_parcel->readInt32() > 0);
diff --git a/msm8996/sdm/libs/hwc2/hwc_session.h b/msm8996/sdm/libs/hwc2/hwc_session.h
index a713ab0..63cce84 100644
--- a/msm8996/sdm/libs/hwc2/hwc_session.h
+++ b/msm8996/sdm/libs/hwc2/hwc_session.h
@@ -42,7 +42,7 @@
   explicit HWCSession(const hw_module_t *module);
   int Init();
   int Deinit();
-  HWC2::Error CreateVirtualDisplayObject(uint32_t width, uint32_t height);
+  HWC2::Error CreateVirtualDisplayObject(uint32_t width, uint32_t height, int32_t *format);
 
   template <typename... Args>
   static int32_t CallDisplayFunction(hwc2_device_t *device, hwc2_display_t display,
@@ -85,7 +85,7 @@
   static int32_t CreateLayer(hwc2_device_t *device, hwc2_display_t display,
                              hwc2_layer_t *out_layer_id);
   static int32_t CreateVirtualDisplay(hwc2_device_t *device, uint32_t width, uint32_t height,
-                                      hwc2_display_t *out_display_id);
+                                      int32_t *format, hwc2_display_t *out_display_id);
   static int32_t DestroyLayer(hwc2_device_t *device, hwc2_display_t display, hwc2_layer_t layer);
   static int32_t DestroyVirtualDisplay(hwc2_device_t *device, hwc2_display_t display);
   static void Dump(hwc2_device_t *device, uint32_t *out_size, char *out_buffer);
@@ -164,6 +164,8 @@
                                           android::Parcel *output_parcel);
   android::status_t GetBWTransactionStatus(const android::Parcel *input_parcel,
                                            android::Parcel *output_parcel);
+  android::status_t SetMixerResolution(const android::Parcel *input_parcel);
+
   static Locker locker_;
   CoreInterface *core_intf_ = NULL;
   HWCDisplay *hwc_display_[HWC_NUM_DISPLAY_TYPES] = {NULL};