Merge "sde: resource config: rectangle alignment for video and rotator"
diff --git a/displayengine/libs/core/comp_manager.cpp b/displayengine/libs/core/comp_manager.cpp
index 7e888ee..06028a2 100644
--- a/displayengine/libs/core/comp_manager.cpp
+++ b/displayengine/libs/core/comp_manager.cpp
@@ -144,6 +144,10 @@
   DisplayCompositionContext *display_comp_ctx =
                              reinterpret_cast<DisplayCompositionContext *>(comp_handle);
 
+  if (!display_comp_ctx) {
+    return kErrorParameters;
+  }
+
   res_mgr_.UnregisterDisplay(display_comp_ctx->display_resource_ctx);
   destroy_strategy_intf_(display_comp_ctx->strategy_intf);
 
@@ -154,11 +158,8 @@
            "display type %d", registered_displays_, configured_displays_,
            display_comp_ctx->display_type);
 
-  if (display_comp_ctx) {
-    delete display_comp_ctx;
-    display_comp_ctx = NULL;
-  }
-
+  delete display_comp_ctx;
+  display_comp_ctx = NULL;
   return kErrorNone;
 }
 
diff --git a/displayengine/libs/core/display_base.cpp b/displayengine/libs/core/display_base.cpp
index 058bacc..dac17fd 100644
--- a/displayengine/libs/core/display_base.cpp
+++ b/displayengine/libs/core/display_base.cpp
@@ -298,7 +298,7 @@
 
   DisplayError error = kErrorNone;
 
-  DLOGI("Set state = %d", state);
+  DLOGI("Set state = %d, display %d", state, display_type_);
 
   if (state == state_) {
     DLOGI("Same state transition is requested.");
@@ -307,13 +307,12 @@
 
   switch (state) {
   case kStateOff:
-    // Invoke flush during suspend for HDMI and virtual displays. StateOff is handled
-    // separately for primary in DisplayPrimary::SetDisplayState() function.
+    hw_layers_.info.count = 0;
     error = hw_intf_->Flush(hw_device_);
     if (error == kErrorNone) {
       comp_manager_->Purge(display_comp_ctx_);
-      state_ = state;
-      hw_layers_.info.count = 0;
+
+      error = hw_intf_->PowerOff(hw_device_);
     }
     break;
 
diff --git a/displayengine/libs/core/display_primary.cpp b/displayengine/libs/core/display_primary.cpp
index ac44fe3..8eed8ee 100644
--- a/displayengine/libs/core/display_primary.cpp
+++ b/displayengine/libs/core/display_primary.cpp
@@ -35,29 +35,5 @@
                                CompManager *comp_manager, OfflineCtrl *offline_ctrl)
   : DisplayBase(kPrimary, event_handler, kDevicePrimary, hw_intf, comp_manager, offline_ctrl) { }
 
-DisplayError DisplayPrimary::SetDisplayState(DisplayState state) {
-  DisplayError error = kErrorNone;
-
-  DLOGI("Set state = %d", state);
-
-  if (state == kStateOff) {
-    SCOPE_LOCK(locker_);
-    if (state == state_) {
-      DLOGI("Same state transition is requested.");
-      return kErrorNone;
-    }
-    error = hw_intf_->PowerOff(hw_device_);
-    if (error == kErrorNone) {
-      comp_manager_->Purge(display_comp_ctx_);
-      state_ = state;
-      hw_layers_.info.count = 0;
-    }
-  } else {
-    error = DisplayBase::SetDisplayState(state);
-  }
-
-  return error;
-}
-
 }  // namespace sde
 
diff --git a/displayengine/libs/core/display_primary.h b/displayengine/libs/core/display_primary.h
index 79fbddf..ea4cf2b 100644
--- a/displayengine/libs/core/display_primary.h
+++ b/displayengine/libs/core/display_primary.h
@@ -33,7 +33,6 @@
  public:
   DisplayPrimary(DisplayEventHandler *event_handler, HWInterface *hw_intf,
                  CompManager *comp_manager, OfflineCtrl *offline_ctrl);
-  virtual DisplayError SetDisplayState(DisplayState state);
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp
index 4a361da..69d1efa 100644
--- a/displayengine/libs/core/hw_framebuffer.cpp
+++ b/displayengine/libs/core/hw_framebuffer.cpp
@@ -542,49 +542,33 @@
   return kErrorNone;
 }
 
-DisplayError HWFrameBuffer::OpenRotatorSession(Handle device, HWLayers *hw_layers) {
+DisplayError HWFrameBuffer::OpenRotatorSession(Handle device, HWRotateInfo *rotate_info) {
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
   HWRotator *hw_rotator = &hw_context->hw_rotator;
+  LayerBuffer *input_buffer = rotate_info->input_buffer;
+  HWBufferInfo *rot_buf_info = &rotate_info->hw_buffer_info;
 
   hw_rotator->Reset();
 
-  HWLayersInfo &hw_layer_info = hw_layers->info;
+  STRUCT_VAR(mdp_rotation_config, mdp_rot_config);
+  mdp_rot_config.version = MDP_ROTATION_REQUEST_VERSION_1_0;
+  mdp_rot_config.input.width = input_buffer->width;
+  mdp_rot_config.input.height = input_buffer->height;
+  SetFormat(input_buffer->format, &mdp_rot_config.input.format);
+  mdp_rot_config.output.width = rot_buf_info->output_buffer.width;
+  mdp_rot_config.output.height = rot_buf_info->output_buffer.height;
+  SetFormat(rot_buf_info->output_buffer.format, &mdp_rot_config.output.format);
+  mdp_rot_config.frame_rate = rotate_info->frame_rate;
 
-  for (uint32_t i = 0; i < hw_layer_info.count; i++) {
-    Layer& layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
-    LayerBuffer *input_buffer = layer.input_buffer;
-    bool rot90 = (layer.transform.rotation == 90.0f);
-
-    for (uint32_t count = 0; count < 2; count++) {
-      HWRotateInfo *rotate_info = &hw_layers->config[i].rotates[count];
-
-      if (rotate_info->valid) {
-        HWBufferInfo *rot_buf_info = &rotate_info->hw_buffer_info;
-
-        if (rot_buf_info->session_id < 0) {
-          STRUCT_VAR(mdp_rotation_config, mdp_rot_config);
-          mdp_rot_config.version = MDP_ROTATION_REQUEST_VERSION_1_0;
-          mdp_rot_config.input.width = input_buffer->width;
-          mdp_rot_config.input.height = input_buffer->height;
-          SetFormat(input_buffer->format, &mdp_rot_config.input.format);
-          mdp_rot_config.output.width = rot_buf_info->output_buffer.width;
-          mdp_rot_config.output.height = rot_buf_info->output_buffer.height;
-          SetFormat(rot_buf_info->output_buffer.format, &mdp_rot_config.output.format);
-          mdp_rot_config.frame_rate = layer.frame_rate;
-
-          if (ioctl_(hw_context->device_fd, MDSS_ROTATION_OPEN, &mdp_rot_config) < 0) {
-            IOCTL_LOGE(MDSS_ROTATION_OPEN, hw_context->type);
-            return kErrorHardware;
-          }
-
-          rot_buf_info->session_id = mdp_rot_config.session_id;
-
-          DLOGV_IF(kTagDriverConfig, "session_id %d", rot_buf_info->session_id);
-        }
-      }
-    }
+  if (ioctl_(hw_context->device_fd, MDSS_ROTATION_OPEN, &mdp_rot_config) < 0) {
+    IOCTL_LOGE(MDSS_ROTATION_OPEN, hw_context->type);
+    return kErrorHardware;
   }
 
+  rot_buf_info->session_id = mdp_rot_config.session_id;
+
+  DLOGV_IF(kTagDriverConfig, "session_id %d", rot_buf_info->session_id);
+
   return kErrorNone;
 }
 
@@ -911,7 +895,7 @@
   return kErrorNone;
 }
 
-DisplayError HWFrameBuffer::RotatorValidate(HWContext *hw_context, HWLayers *hw_layers) {
+void HWFrameBuffer::SetRotatorCtrlParams(HWContext *hw_context, HWLayers *hw_layers) {
   HWRotator *hw_rotator = &hw_context->hw_rotator;
   DLOGV_IF(kTagDriverConfig, "************************* %s Validate Input ************************",
            GetDeviceString(hw_context->type));
@@ -978,17 +962,9 @@
       }
     }
   }
-
-  mdp_rot_request->flags = MDSS_ROTATION_REQUEST_VALIDATE;
-  if (ioctl_(hw_context->device_fd, MDSS_ROTATION_REQUEST, mdp_rot_request) < 0) {
-    IOCTL_LOGE(MDSS_ROTATION_REQUEST, hw_context->type);
-    return kErrorHardware;
-  }
-
-  return kErrorNone;
 }
 
-DisplayError HWFrameBuffer::RotatorCommit(HWContext *hw_context, HWLayers *hw_layers) {
+void HWFrameBuffer::SetRotatorBufferParams(HWContext *hw_context, HWLayers *hw_layers) {
   HWRotator *hw_rotator = &hw_context->hw_rotator;
   mdp_rotation_request *mdp_rot_request = &hw_rotator->mdp_rot_req;
   HWLayersInfo &hw_layer_info = hw_layers->info;
@@ -1041,14 +1017,36 @@
       }
     }
   }
+}
 
-  mdp_rot_request->flags &= ~MDSS_ROTATION_REQUEST_VALIDATE;
-  if (ioctl_(hw_context->device_fd, MDSS_ROTATION_REQUEST, mdp_rot_request) < 0) {
+DisplayError HWFrameBuffer::RotatorValidate(HWContext *hw_context, HWLayers *hw_layers) {
+  HWRotator *hw_rotator = &hw_context->hw_rotator;
+  SetRotatorCtrlParams(hw_context, hw_layers);
+
+  hw_rotator->mdp_rot_req.flags = MDSS_ROTATION_REQUEST_VALIDATE;
+  if (ioctl_(hw_context->device_fd, MDSS_ROTATION_REQUEST, &hw_rotator->mdp_rot_req) < 0) {
     IOCTL_LOGE(MDSS_ROTATION_REQUEST, hw_context->type);
     return kErrorHardware;
   }
 
-  rot_count = 0;
+  return kErrorNone;
+}
+
+DisplayError HWFrameBuffer::RotatorCommit(HWContext *hw_context, HWLayers *hw_layers) {
+  HWRotator *hw_rotator = &hw_context->hw_rotator;
+  HWLayersInfo &hw_layer_info = hw_layers->info;
+  uint32_t rot_count = 0;
+
+  SetRotatorCtrlParams(hw_context, hw_layers);
+
+  SetRotatorBufferParams(hw_context, hw_layers);
+
+  hw_rotator->mdp_rot_req.flags &= ~MDSS_ROTATION_REQUEST_VALIDATE;
+  if (ioctl_(hw_context->device_fd, MDSS_ROTATION_REQUEST, &hw_rotator->mdp_rot_req) < 0) {
+    IOCTL_LOGE(MDSS_ROTATION_REQUEST, hw_context->type);
+    return kErrorHardware;
+  }
+
   for (uint32_t i = 0; i < hw_layer_info.count; i++) {
     Layer& layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
 
@@ -1059,7 +1057,7 @@
 
       if (rotate_info->valid) {
         HWBufferInfo *rot_buf_info = &rotate_info->hw_buffer_info;
-        mdp_rotation_item *mdp_rot_item = &mdp_rot_request->list[rot_count];
+        mdp_rotation_item *mdp_rot_item = &hw_rotator->mdp_rot_req.list[rot_count];
 
         SyncMerge(layer.input_buffer->release_fence_fd, dup(mdp_rot_item->output.fence),
                   &layer.input_buffer->release_fence_fd);
@@ -1079,14 +1077,26 @@
   HWContext *hw_context = reinterpret_cast<HWContext *>(device);
   HWDisplay *hw_display = &hw_context->hw_display;
 
-  hw_display->Reset();
-  mdp_layer_commit_v1 &mdp_commit = hw_display->mdp_disp_commit.commit_v1;
-  mdp_commit.input_layer_cnt = 0;
-  mdp_commit.flags &= ~MDP_VALIDATE_LAYER;
+  switch (hw_context->type) {
+  case kDevicePrimary:
+  case kDeviceHDMI:
+  case kDeviceVirtual:
+    {
+      hw_display->Reset();
+      mdp_layer_commit_v1 &mdp_commit = hw_display->mdp_disp_commit.commit_v1;
+      mdp_commit.input_layer_cnt = 0;
+      mdp_commit.output_layer = NULL;
 
-  if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_display->mdp_disp_commit) == -1) {
-    IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
-    return kErrorHardware;
+      mdp_commit.flags &= ~MDP_VALIDATE_LAYER;
+      if (ioctl_(hw_context->device_fd, MSMFB_ATOMIC_COMMIT, &hw_display->mdp_disp_commit) < 0) {
+        IOCTL_LOGE(MSMFB_ATOMIC_COMMIT, hw_context->type);
+        return kErrorHardware;
+      }
+    }
+    break;
+  default:
+    DLOGE("Flush is not supported for the device %s", GetDeviceString(hw_context->type));
+    return kErrorNotSupported;
   }
 
   return kErrorNone;
diff --git a/displayengine/libs/core/hw_framebuffer.h b/displayengine/libs/core/hw_framebuffer.h
index 5c01e5f..68a0674 100644
--- a/displayengine/libs/core/hw_framebuffer.h
+++ b/displayengine/libs/core/hw_framebuffer.h
@@ -56,7 +56,7 @@
   virtual DisplayError Doze(Handle device);
   virtual DisplayError SetVSyncState(Handle device, bool enable);
   virtual DisplayError Standby(Handle device);
-  virtual DisplayError OpenRotatorSession(Handle device, HWLayers *hw_layers);
+  virtual DisplayError OpenRotatorSession(Handle device, HWRotateInfo *rotate_info);
   virtual DisplayError CloseRotatorSession(Handle device, int32_t session_id);
   virtual DisplayError Validate(Handle device, HWLayers *hw_layers);
   virtual DisplayError Commit(Handle device, HWLayers *hw_layers);
@@ -86,6 +86,7 @@
       mdp_disp_commit.commit_v1.input_layers = mdp_in_layers;
       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_scale_data* GetScaleRef(uint32_t index) { return &scale_data[index]; }
@@ -192,6 +193,9 @@
   DisplayError DisplayValidate(HWContext *device_ctx, HWLayers *hw_layers);
   DisplayError DisplayCommit(HWContext *device_ctx, HWLayers *hw_layers);
 
+  void SetRotatorCtrlParams(HWContext *device_ctx, HWLayers *hw_layers);
+  void SetRotatorBufferParams(HWContext *device_ctx, HWLayers *hw_layers);
+
   DisplayError RotatorValidate(HWContext *device_ctx, HWLayers *hw_layers);
   DisplayError RotatorCommit(HWContext *device_ctx, HWLayers *hw_layers);
 
diff --git a/displayengine/libs/core/hw_interface.h b/displayengine/libs/core/hw_interface.h
index 084768e..9e003bb 100644
--- a/displayengine/libs/core/hw_interface.h
+++ b/displayengine/libs/core/hw_interface.h
@@ -107,6 +107,7 @@
 };
 
 struct HWRotateInfo {
+  LayerBuffer *input_buffer;
   uint32_t pipe_id;
   LayerRect src_roi;
   LayerRect dst_roi;
@@ -116,9 +117,11 @@
   float downscale_ratio_y;
   HWBufferInfo hw_buffer_info;
   bool valid;
+  uint32_t frame_rate;
 
-  HWRotateInfo() : pipe_id(0), dst_format(kFormatInvalid), writeback_id(kHWWriteback0),
-                   downscale_ratio_x(1.0f), downscale_ratio_y(1.0f), valid(false) { }
+  HWRotateInfo() : input_buffer(NULL), pipe_id(0), dst_format(kFormatInvalid),
+                   writeback_id(kHWWriteback0), downscale_ratio_x(1.0f), downscale_ratio_y(1.0f),
+                   valid(false), frame_rate(0) { }
 
   void Reset() { *this = HWRotateInfo(); }
 };
@@ -195,7 +198,7 @@
   virtual DisplayError Doze(Handle device) = 0;
   virtual DisplayError SetVSyncState(Handle device, bool enable) = 0;
   virtual DisplayError Standby(Handle device) = 0;
-  virtual DisplayError OpenRotatorSession(Handle device, HWLayers *hw_layers) = 0;
+  virtual DisplayError OpenRotatorSession(Handle device, HWRotateInfo *rotate_info) = 0;
   virtual DisplayError CloseRotatorSession(Handle device, int32_t session_id) = 0;
   virtual DisplayError Validate(Handle device, HWLayers *hw_layers) = 0;
   virtual DisplayError Commit(Handle device, HWLayers *hw_layers) = 0;
diff --git a/displayengine/libs/core/offline_ctrl.cpp b/displayengine/libs/core/offline_ctrl.cpp
index 5ffaf22..8794074 100644
--- a/displayengine/libs/core/offline_ctrl.cpp
+++ b/displayengine/libs/core/offline_ctrl.cpp
@@ -85,34 +85,30 @@
 
   DisplayOfflineContext *disp_offline_ctx = reinterpret_cast<DisplayOfflineContext *>(display_ctx);
 
+  disp_offline_ctx->pending_rot_commit = false;
+
   if (!hw_rotator_device_ && IsRotationRequired(hw_layers)) {
     DLOGV_IF(kTagOfflineCtrl, "No Rotator device found");
     return kErrorHardware;
   }
 
-  disp_offline_ctx->pending_rot_commit = false;
-
-  uint32_t i = 0;
-  while (hw_layers->closed_session_ids[i] >= 0) {
-    error = hw_intf_->CloseRotatorSession(hw_rotator_device_, hw_layers->closed_session_ids[i]);
-    if (LIKELY(error != kErrorNone)) {
-      DLOGE("Rotator close session failed");
-      return error;
-    }
-    hw_layers->closed_session_ids[i++] = -1;
+  error = CloseRotatorSession(hw_layers);
+  if (LIKELY(error != kErrorNone)) {
+    DLOGE("Close rotator session failed for display %d", disp_offline_ctx->display_type);
+    return error;
   }
 
 
   if (IsRotationRequired(hw_layers)) {
-    error = hw_intf_->OpenRotatorSession(hw_rotator_device_, hw_layers);
+    error = OpenRotatorSession(hw_layers);
     if (LIKELY(error != kErrorNone)) {
-      DLOGE("Rotator open session failed");
+      DLOGE("Open rotator session failed for display %d", disp_offline_ctx->display_type);
       return error;
     }
 
     error = hw_intf_->Validate(hw_rotator_device_, hw_layers);
     if (LIKELY(error != kErrorNone)) {
-      DLOGE("Rotator validation failed");
+      DLOGE("Rotator validation failed for display %d", disp_offline_ctx->display_type);
       return error;
     }
     disp_offline_ctx->pending_rot_commit = true;
@@ -129,7 +125,7 @@
   if (disp_offline_ctx->pending_rot_commit) {
     error = hw_intf_->Commit(hw_rotator_device_, hw_layers);
     if (error != kErrorNone) {
-      DLOGE("Rotator commit failed");
+      DLOGE("Rotator commit failed for display %d", disp_offline_ctx->display_type);
       return error;
     }
     disp_offline_ctx->pending_rot_commit = false;
@@ -138,6 +134,50 @@
   return kErrorNone;
 }
 
+DisplayError OfflineCtrl::OpenRotatorSession(HWLayers *hw_layers) {
+  HWLayersInfo &hw_layer_info = hw_layers->info;
+  DisplayError error = kErrorNone;
+
+  for (uint32_t i = 0; i < hw_layer_info.count; i++) {
+    Layer& layer = hw_layer_info.stack->layers[hw_layer_info.index[i]];
+    bool rot90 = (layer.transform.rotation == 90.0f);
+
+    for (uint32_t count = 0; count < 2; count++) {
+      HWRotateInfo *rotate_info = &hw_layers->config[i].rotates[count];
+      HWBufferInfo *rot_buf_info = &rotate_info->hw_buffer_info;
+
+      if (!rotate_info->valid || rot_buf_info->session_id >= 0) {
+        continue;
+      }
+
+      rotate_info->input_buffer = layer.input_buffer;
+      rotate_info->frame_rate = layer.frame_rate;
+
+      error = hw_intf_->OpenRotatorSession(hw_rotator_device_, rotate_info);
+      if (LIKELY(error != kErrorNone)) {
+        return error;
+      }
+    }
+  }
+
+  return kErrorNone;
+}
+
+DisplayError OfflineCtrl::CloseRotatorSession(HWLayers *hw_layers) {
+  DisplayError error = kErrorNone;
+  uint32_t i = 0;
+
+  while (hw_layers->closed_session_ids[i] >= 0) {
+    error = hw_intf_->CloseRotatorSession(hw_rotator_device_, hw_layers->closed_session_ids[i]);
+    if (LIKELY(error != kErrorNone)) {
+      return error;
+    }
+    hw_layers->closed_session_ids[i++] = -1;
+  }
+
+  return kErrorNone;
+}
+
 bool OfflineCtrl::IsRotationRequired(HWLayers *hw_layers) {
   HWLayersInfo &layer_info = hw_layers->info;
 
diff --git a/displayengine/libs/core/offline_ctrl.h b/displayengine/libs/core/offline_ctrl.h
index fafdf7c..fa8b264 100644
--- a/displayengine/libs/core/offline_ctrl.h
+++ b/displayengine/libs/core/offline_ctrl.h
@@ -50,6 +50,8 @@
     DisplayOfflineContext() : display_type(kPrimary), pending_rot_commit(false) { }
   };
 
+  DisplayError OpenRotatorSession(HWLayers *hw_layers);
+  DisplayError CloseRotatorSession(HWLayers *hw_layers);
   bool IsRotationRequired(HWLayers *hw_layers);
 
   HWInterface *hw_intf_;
diff --git a/displayengine/libs/core/res_manager.cpp b/displayengine/libs/core/res_manager.cpp
index 761ab01..dfd1e0a 100644
--- a/displayengine/libs/core/res_manager.cpp
+++ b/displayengine/libs/core/res_manager.cpp
@@ -642,15 +642,17 @@
   for (uint32_t i = 0; i < layer_info.count; i++) {
     Layer& layer = layer_info.stack->layers[layer_info.index[i]];
     HWRotateInfo *rotate = &hw_layers->config[i].rotates[0];
+    bool rot90 = (layer.transform.rotation == 90.0f);
 
     if (rotate->valid) {
       LayerBufferFormat rot_ouput_format;
-      SetRotatorOutputFormat(layer.input_buffer->format, false, true, &rot_ouput_format);
+      SetRotatorOutputFormat(layer.input_buffer->format, false, rot90, &rot_ouput_format);
 
       HWBufferInfo *hw_buffer_info = &rotate->hw_buffer_info;
       hw_buffer_info->buffer_config.width = UINT32(rotate->dst_roi.right - rotate->dst_roi.left);
       hw_buffer_info->buffer_config.height = UINT32(rotate->dst_roi.bottom - rotate->dst_roi.top);
       hw_buffer_info->buffer_config.format = rot_ouput_format;
+      // Allocate two rotator output buffers by default for double buffering.
       hw_buffer_info->buffer_config.buffer_count = 2;
       hw_buffer_info->buffer_config.secure = layer.input_buffer->flags.secure;
 
@@ -663,12 +665,13 @@
     rotate = &hw_layers->config[i].rotates[1];
     if (rotate->valid) {
       LayerBufferFormat rot_ouput_format;
-      SetRotatorOutputFormat(layer.input_buffer->format, false, true, &rot_ouput_format);
+      SetRotatorOutputFormat(layer.input_buffer->format, false, rot90, &rot_ouput_format);
 
       HWBufferInfo *hw_buffer_info = &rotate->hw_buffer_info;
       hw_buffer_info->buffer_config.width = UINT32(rotate->dst_roi.right - rotate->dst_roi.left);
       hw_buffer_info->buffer_config.height = UINT32(rotate->dst_roi.bottom - rotate->dst_roi.top);
       hw_buffer_info->buffer_config.format = rot_ouput_format;
+      // Allocate two rotator output buffers by default for double buffering.
       hw_buffer_info->buffer_config.buffer_count = 2;
       hw_buffer_info->buffer_config.secure = layer.input_buffer->flags.secure;
 
diff --git a/displayengine/libs/hwc/hwc_session.cpp b/displayengine/libs/hwc/hwc_session.cpp
index 3bc4fd1..1b686bf 100644
--- a/displayengine/libs/hwc/hwc_session.cpp
+++ b/displayengine/libs/hwc/hwc_session.cpp
@@ -329,17 +329,18 @@
   switch (disp) {
   case HWC_DISPLAY_PRIMARY:
     status = hwc_session->display_primary_->SetPowerMode(mode);
+  // Set the power mode for virtual display while setting power mode for primary, as surfaceflinger
+  // does not invoke SetPowerMode() for virtual display.
+  case HWC_DISPLAY_VIRTUAL:
+    if (hwc_session->display_virtual_) {
+      status = hwc_session->display_virtual_->SetPowerMode(mode);
+    }
     break;
   case HWC_DISPLAY_EXTERNAL:
     if (hwc_session->display_external_) {
       status = hwc_session->display_external_->SetPowerMode(mode);
     }
     break;
-  case HWC_DISPLAY_VIRTUAL:
-    if (hwc_session->display_virtual_) {
-      status = hwc_session->display_virtual_->SetPowerMode(mode);
-    }
-    break;
   default:
     status = -EINVAL;
   }
diff --git a/libgralloc/adreno_utils.h b/libgralloc/adreno_utils.h
index 6cb7810..78f49da 100644
--- a/libgralloc/adreno_utils.h
+++ b/libgralloc/adreno_utils.h
@@ -36,6 +36,7 @@
     ADRENO_PIXELFORMAT_NV12          = 103,
     ADRENO_PIXELFORMAT_YUY2          = 107,
     ADRENO_PIXELFORMAT_B4G4R4A4      = 115,
+    ADRENO_PIXELFORMAT_NV12_EXT      = 506,  // NV12 with non-std alignment and offsets
     ADRENO_PIXELFORMAT_R8G8B8        = 508,  // GL_RGB8
     ADRENO_PIXELFORMAT_A1B5G5R5      = 519,  // GL_RGB5_A1
     ADRENO_PIXELFORMAT_R8G8B8X8_SRGB = 520,  // GL_SRGB8
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index fd98154..f70ead3 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -308,9 +308,10 @@
         case HAL_PIXEL_FORMAT_sRGB_A_8888:
             return ADRENO_PIXELFORMAT_R8G8B8A8_SRGB;
         case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+            return ADRENO_PIXELFORMAT_NV12;
         case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
         case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS_UBWC:
-            return ADRENO_PIXELFORMAT_NV12;
+            return ADRENO_PIXELFORMAT_NV12_EXT;
         default:
             ALOGE("%s: No map for format: 0x%x", __FUNCTION__, hal_format);
             break;
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index e9b9d9d..f973b76 100755
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -33,44 +33,42 @@
 #define ROUND_UP_PAGESIZE(x) ( (((unsigned long)(x)) + PAGE_SIZE-1)  & \
                                (~(PAGE_SIZE-1)) )
 
-enum {
-    /* gralloc usage bits indicating the type
-     * of allocation that should be used */
+/* Gralloc usage bits indicating the type of allocation that should be used */
+/* SYSTEM heap comes from kernel vmalloc, can never be uncached,
+ * is not secured */
+#define GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP     GRALLOC_USAGE_PRIVATE_0
 
-    /* SYSTEM heap comes from kernel vmalloc,
-     * can never be uncached, is not secured*/
-    GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP     =       GRALLOC_USAGE_PRIVATE_0,
+/* Non linear, Universal Bandwidth Compression */
+#define GRALLOC_USAGE_PRIVATE_ALLOC_UBWC      GRALLOC_USAGE_PRIVATE_1
 
-    /* Non linear, Universal Bandwidth Compression */
-    GRALLOC_USAGE_PRIVATE_ALLOC_UBWC      =       GRALLOC_USAGE_PRIVATE_1,
+/* IOMMU heap comes from manually allocated pages, can be cached/uncached,
+ * is not secured */
+#define GRALLOC_USAGE_PRIVATE_IOMMU_HEAP      GRALLOC_USAGE_PRIVATE_2
 
-    /* IOMMU heap comes from manually allocated pages,
-     * can be cached/uncached, is not secured */
-    GRALLOC_USAGE_PRIVATE_IOMMU_HEAP      =       GRALLOC_USAGE_PRIVATE_2,
-    /* MM heap is a carveout heap for video, can be secured*/
-    GRALLOC_USAGE_PRIVATE_MM_HEAP         =       GRALLOC_USAGE_PRIVATE_3,
-    /* ADSP heap is a carveout heap, is not secured*/
-    GRALLOC_USAGE_PRIVATE_ADSP_HEAP       =       0x01000000,
+/* MM heap is a carveout heap for video, can be secured */
+#define GRALLOC_USAGE_PRIVATE_MM_HEAP         GRALLOC_USAGE_PRIVATE_3
 
-    /* Set this for allocating uncached memory (using O_DSYNC)
-     * cannot be used with noncontiguous heaps */
-    GRALLOC_USAGE_PRIVATE_UNCACHED        =       0x02000000,
+/* ADSP heap is a carveout heap, is not secured */
+#define GRALLOC_USAGE_PRIVATE_ADSP_HEAP       0x01000000
 
-    /* Buffer content should be displayed on an primary display only */
-    GRALLOC_USAGE_PRIVATE_INTERNAL_ONLY   =       0x04000000,
+/* Set this for allocating uncached memory (using O_DSYNC),
+ * cannot be used with noncontiguous heaps */
+#define GRALLOC_USAGE_PRIVATE_UNCACHED        0x02000000
 
-    /* Buffer content should be displayed on an external display only */
-    GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY   =       0x08000000,
+/* Buffer content should be displayed on an primary display only */
+#define GRALLOC_USAGE_PRIVATE_INTERNAL_ONLY   0x04000000
 
-    /* This flag is set for WFD usecase */
-    GRALLOC_USAGE_PRIVATE_WFD             =       0x00200000,
+/* Buffer content should be displayed on an external display only */
+#define GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY   0x08000000
 
-    /* CAMERA heap is a carveout heap for camera, is not secured*/
-    GRALLOC_USAGE_PRIVATE_CAMERA_HEAP     =       0x00400000,
+/* This flag is set for WFD usecase */
+#define GRALLOC_USAGE_PRIVATE_WFD             0x00200000
 
-    /* This flag is used for SECURE display usecase */
-    GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY  =       0x00800000,
-};
+/* CAMERA heap is a carveout heap for camera, is not secured */
+#define GRALLOC_USAGE_PRIVATE_CAMERA_HEAP     0x00400000
+
+/* This flag is used for SECURE display usecase */
+#define GRALLOC_USAGE_PRIVATE_SECURE_DISPLAY  0x00800000
 
 /* define Gralloc perform */
 #define GRALLOC_MODULE_PERFORM_CREATE_HANDLE_FROM_BUFFER 1
@@ -84,6 +82,7 @@
 #define GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE 6
 #define GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO 7
 #define GRALLOC_MODULE_PERFORM_GET_MAP_SECURE_BUFFER_INFO 8
+#define GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG 9
 
 #define GRALLOC_HEAP_MASK   (GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP    |\
                              GRALLOC_USAGE_PRIVATE_IOMMU_HEAP     |\
diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp
index 44f4fb2..5382300 100644
--- a/libgralloc/mapper.cpp
+++ b/libgralloc/mapper.cpp
@@ -447,6 +447,17 @@
                 }
             } break;
 
+        case GRALLOC_MODULE_PERFORM_GET_UBWC_FLAG:
+            {
+                private_handle_t* hnd =  va_arg(args, private_handle_t*);
+                int *flag = va_arg(args, int *);
+                if (private_handle_t::validate(hnd)) {
+                    return res;
+                }
+                *flag = hnd->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED;
+                res = 0;
+            } break;
+
         default:
             break;
     }
diff --git a/libhdmi/hdmi.cpp b/libhdmi/hdmi.cpp
index bca7a0b..1b2ffe0 100644
--- a/libhdmi/hdmi.cpp
+++ b/libhdmi/hdmi.cpp
@@ -95,6 +95,7 @@
     mUnderscanSupported(false), mMDPDownscaleEnabled(false)
 {
     memset(&mVInfo, 0, sizeof(mVInfo));
+    mFbNum = qdutils::getHDMINode();
 
     mDisplayId = HWC_DISPLAY_EXTERNAL;
     // Update the display if HDMI is connected as primary
@@ -102,7 +103,6 @@
         mDisplayId = HWC_DISPLAY_PRIMARY;
     }
 
-    mFbNum = overlay::Overlay::getInstance()->getFbForDpy(mDisplayId);
     // Disable HPD at start if HDMI is external, it will be enabled later
     // when the display powers on
     // This helps for framework reboot or adb shell stop/start
@@ -684,8 +684,7 @@
 }
 
 bool HDMIDisplay::isHDMIPrimaryDisplay() {
-    int hdmiNode = qdutils::getHDMINode();
-    return (hdmiNode == HWC_DISPLAY_PRIMARY);
+    return (mFbNum == HWC_DISPLAY_PRIMARY);
 }
 
 int HDMIDisplay::getConnectedState() {
@@ -739,6 +738,124 @@
     return 0;
 }
 
+static const char* getS3DStringFromMode(int s3dMode) {
+    const char* ret ;
+    switch(s3dMode) {
+    case HDMI_S3D_NONE:
+        ret = "None";
+        break;
+    case HDMI_S3D_SIDE_BY_SIDE:
+        ret = "SSH";
+        break;
+    case HDMI_S3D_TOP_AND_BOTTOM:
+        ret = "TAB";
+        break;
+    //FP (FramePacked) mode is not supported in the HAL
+    default:
+        ALOGD("%s: Unsupported s3d mode: %d", __FUNCTION__, s3dMode);
+        ret = NULL;
+    }
+    return ret;
+}
+
+bool HDMIDisplay::isS3DModeSupported(int s3dMode) {
+    if(s3dMode == HDMI_S3D_NONE)
+        return true;
+
+    char s3dEdidStr[PAGE_SIZE] = {'\0'};
+
+    const char *s3dModeString = getS3DStringFromMode(s3dMode);
+
+    if(s3dModeString == NULL)
+        return false;
+
+    int s3dEdidNode = openDeviceNode("edid_3d_modes", O_RDONLY);
+    if(s3dEdidNode >= 0) {
+        ssize_t len = read(s3dEdidNode, s3dEdidStr, sizeof(s3dEdidStr)-1);
+        if (len > 0) {
+            ALOGI("%s: s3dEdidStr: %s mCurrentMode:%d", __FUNCTION__,
+                    s3dEdidStr, mCurrentMode);
+            //Three level inception!
+            //The string looks like 16=SSH,4=FP:TAB:SSH,5=FP:SSH,32=FP:TAB:SSH
+            char *saveptr_l1, *saveptr_l2, *saveptr_l3;
+            char *l1, *l2, *l3;
+            int mode = 0;
+            l1 = strtok_r(s3dEdidStr,",", &saveptr_l1);
+            while (l1 != NULL) {
+                l2 = strtok_r(l1, "=", &saveptr_l2);
+                if (l2 != NULL)
+                    mode = atoi(l2);
+                while (l2 != NULL) {
+                    if (mode != mCurrentMode) {
+                        break;
+                    }
+                    l3 = strtok_r(l2, ":", &saveptr_l3);
+                    while (l3 != NULL) {
+                        if (strncmp(l3, s3dModeString,
+                                    strlen(s3dModeString)) == 0) {
+                            close(s3dEdidNode);
+                            return true;
+                        }
+                        l3 = strtok_r(NULL, ":", &saveptr_l3);
+                    }
+                    l2 = strtok_r(NULL, "=", &saveptr_l2);
+                }
+                l1 = strtok_r(NULL, ",", &saveptr_l1);
+            }
+
+        }
+    } else {
+        ALOGI("%s: /sys/class/graphics/fb%d/edid_3d_modes could not be opened : %s",
+                __FUNCTION__, mFbNum, strerror(errno));
+    }
+    close(s3dEdidNode);
+    return false;
+}
+
+bool HDMIDisplay::writeS3DMode(int s3dMode) {
+  bool ret = true;
+    if(mFbNum != -1) {
+        int hdmiS3DModeFile = openDeviceNode("s3d_mode", O_RDWR);
+        if(hdmiS3DModeFile >=0 ) {
+            char curModeStr[PROPERTY_VALUE_MAX];
+            int currentS3DMode = -1;
+            size_t len = read(hdmiS3DModeFile, curModeStr, sizeof(curModeStr) - 1);
+            if(len > 0) {
+                currentS3DMode = atoi(curModeStr);
+            } else {
+                ret = false;
+                ALOGE("%s: Failed to read s3d_mode", __FUNCTION__);
+            }
+
+            if (currentS3DMode >=0 && currentS3DMode != s3dMode) {
+                ssize_t err = -1;
+                ALOGD_IF(DEBUG, "%s: mode = %d",
+                        __FUNCTION__, s3dMode);
+                char mode[PROPERTY_VALUE_MAX];
+                snprintf(mode,sizeof(mode),"%d",s3dMode);
+                err = write(hdmiS3DModeFile, mode, sizeof(mode));
+                if (err <= 0) {
+                    ALOGE("%s: file write failed 's3d_mode'", __FUNCTION__);
+                    ret = false;
+                }
+            }
+            close(hdmiS3DModeFile);
+        }
+    }
+    return ret;
+}
+
+bool HDMIDisplay::configure3D(int s3dMode) {
+    if(isS3DModeSupported(s3dMode)) {
+        if(!writeS3DMode(s3dMode))
+            return false;
+    } else {
+        ALOGE("%s: 3D mode: %d is not supported", __FUNCTION__, s3dMode);
+        return false;
+    }
+    return true;
+}
+
 // returns false if the xres or yres of the new config do
 // not match the current config
 bool HDMIDisplay::isValidConfigChange(int newConfig) {
diff --git a/libhdmi/hdmi.h b/libhdmi/hdmi.h
index 32c48ff..d1d5759 100644
--- a/libhdmi/hdmi.h
+++ b/libhdmi/hdmi.h
@@ -64,6 +64,8 @@
     int getAttrForConfig(int config, uint32_t& xres,
             uint32_t& yres, uint32_t& refresh, uint32_t& fps) const;
     int getDisplayConfigs(uint32_t* configs, size_t* numConfigs) const;
+    bool configure3D(int s3dMode);
+    bool isS3DModeSupported(int s3dMode);
 
 private:
     int getModeCount() const;
@@ -87,6 +89,7 @@
     void requestNewPage(int pageNumber);
     void readConfigs();
     bool readResFile(char* configBuffer);
+    bool writeS3DMode(int s3dMode);
 
     int mFd;
     int mFbNum;
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 65482d7..68f168a 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -131,8 +131,10 @@
     return renderArea;
 }
 
-bool CopyBit::isLayerChanging(hwc_display_contents_1_t *list, int k) {
+bool CopyBit::isLayerChanging(hwc_context_t *ctx,
+                                 hwc_display_contents_1_t *list, int k) {
     if((mLayerCache.hnd[k] != list->hwLayers[k].handle) ||
+            (mLayerCache.drop[k] != ctx->copybitDrop[k]) ||
             (mLayerCache.displayFrame[k].left !=
                          list->hwLayers[k].displayFrame.left) ||
             (mLayerCache.displayFrame[k].top !=
@@ -161,7 +163,7 @@
     int updatingLayerCount = 0;
     for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){
        //swap rect will kick in only for single updating layer
-       if(isLayerChanging(list, k)) {
+       if(isLayerChanging(ctx, list, k)) {
            updatingLayerCount ++;
            if(updatingLayerCount == 1)
              changingLayerIndex = k;
@@ -1233,6 +1235,7 @@
    for (int i=0; i<ctx->listStats[dpy].numAppLayers; i++){
       hnd[i] = list->hwLayers[i].handle;
       displayFrame[i] = list->hwLayers[i].displayFrame;
+      drop[i] = ctx->copybitDrop[i];
    }
 }
 
diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h
index 6ead4a7..4442afc 100644
--- a/libhwcomposer/hwc_copybit.h
+++ b/libhwcomposer/hwc_copybit.h
@@ -61,6 +61,7 @@
       int layerCount;
       buffer_handle_t hnd[MAX_NUM_APP_LAYERS];
       hwc_rect_t displayFrame[MAX_NUM_APP_LAYERS];
+      bool drop[MAX_NUM_APP_LAYERS];
       /* c'tor */
       LayerCache();
       /* clear caching info*/
@@ -135,7 +136,8 @@
                   int dpy);
     int checkDirtyRect(hwc_context_t *ctx, hwc_display_contents_1_t *list,
                   int dpy);
-    bool isLayerChanging(hwc_display_contents_1_t *list, int k);
+    bool isLayerChanging(hwc_context_t *ctx,
+                            hwc_display_contents_1_t *list, int k);
 };
 
 }; //namespace qhwc
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 8660740..ef83008 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -25,6 +25,7 @@
 #include <overlayRotator.h>
 #include "hwc_fbupdate.h"
 #include "mdp_version.h"
+#include <video/msm_hdmi_modes.h>
 
 using namespace qdutils;
 using namespace overlay;
@@ -499,10 +500,25 @@
     hwc_rect_t dstL = displayFrame;
     hwc_rect_t dstR = displayFrame;
 
+    if(ctx->dpyAttr[mDpy].s3dMode == HDMI_S3D_SIDE_BY_SIDE) {
+        dstL.left = displayFrame.left/2;
+        dstL.right = displayFrame.right/2;
+
+        dstR.left = mAlignedFBWidth/2 + displayFrame.left/2;
+        dstR.right = mAlignedFBWidth/2 + displayFrame.right/2;
+    } else if(ctx->dpyAttr[mDpy].s3dMode == HDMI_S3D_TOP_AND_BOTTOM) {
+        dstL.top = displayFrame.top/2;
+        dstL.bottom = displayFrame.bottom/2;
+
+        dstR.top = mAlignedFBHeight/2 + displayFrame.top/2;
+        dstR.bottom = mAlignedFBHeight/2 + displayFrame.bottom/2;
+    }
+
     //Request left pipe (or 1 by default)
     Overlay::PipeSpecs pipeSpecs;
     pipeSpecs.formatClass = Overlay::FORMAT_RGB;
-    pipeSpecs.needsScaling = qhwc::needsScaling(layer);
+    pipeSpecs.needsScaling = (qhwc::needsScaling(layer) ||
+            needs3DComposition(ctx,mDpy));
     pipeSpecs.dpy = mDpy;
     pipeSpecs.mixer = Overlay::MIXER_DEFAULT;
     pipeSpecs.fb = true;
@@ -519,6 +535,7 @@
         a) FB's width is > Mixer width or
         b) On primary, driver has indicated with caps to split always. This is
            based on an empirically derived value of panel height.
+        c) The composition is 3D
     */
 
     const bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
@@ -533,7 +550,8 @@
 
     if((cropWidth > qdutils::MDPVersion::getInstance().getMaxPipeWidth()) or
             (primarySplitAlways and
-            (cropWidth > lSplit or layerClock > mixerClock))) {
+            (cropWidth > lSplit or layerClock > mixerClock)) or
+            needs3DComposition(ctx, mDpy)) {
         destR = ov.getPipe(pipeSpecs);
         if(destR == ovutils::OV_INVALID) {
             ALOGE("%s: No pipes available to configure fb for dpy %d's right"
@@ -546,10 +564,12 @@
         }
 
         //Split crop equally when using 2 pipes
-        cropL.right = (sourceCrop.right + sourceCrop.left) / 2;
-        cropR.left = cropL.right;
-        dstL.right = (displayFrame.right + displayFrame.left) / 2;
-        dstR.left = dstL.right;
+        if(!needs3DComposition(ctx, mDpy)) {
+            cropL.right = (sourceCrop.right + sourceCrop.left) / 2;
+            cropR.left = cropL.right;
+            dstL.right = (displayFrame.right + displayFrame.left) / 2;
+            dstR.left = dstL.right;
+        }
     }
 
     mDestLeft = destL;
@@ -563,6 +583,12 @@
         }
     }
 
+    // XXX: Figure out why we need this with source split
+    // Currently, the driver silently fails to configure the right pipe
+    // if we don't increment the zorder
+    if (needs3DComposition(ctx, mDpy))
+        parg.zorder = eZorder(parg.zorder + 1);
+
     //configure right pipe
     if(destR != OV_INVALID) {
         if(configMdp(ctx->mOverlay, parg, orient,
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index caa1344..b45279f 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -806,6 +806,10 @@
         return false;
     }
 
+    // No MDP composition for 3D
+    if(needs3DComposition(ctx, mDpy))
+        return false;
+
     // check for action safe flag and MDP scaling mode which requires scaling.
     if(ctx->dpyAttr[mDpy].mActionSafePresent
             || ctx->dpyAttr[mDpy].mMDPScalingMode) {
@@ -1340,7 +1344,7 @@
     if(mCurrentFrame.fbCount)
         mCurrentFrame.fbZ = mCurrentFrame.mdpCount;
 
-    if(sEnableYUVsplit){
+    if(sEnableYUVsplit || needs3DComposition(ctx, mDpy)){
         adjustForSourceSplit(ctx, list);
     }
 
@@ -1370,6 +1374,10 @@
         return false;
     }
 
+    // No MDP composition for 3D
+    if(needs3DComposition(ctx,mDpy))
+        return false;
+
     const bool secureOnly = true;
     return mdpOnlyLayersComp(ctx, list, not secureOnly) or
             mdpOnlyLayersComp(ctx, list, secureOnly);
@@ -1831,6 +1839,9 @@
                 }
                 continue;
             }
+            if(needs3DComposition(ctx,mDpy) && get3DFormat(hnd) != HAL_NO_3D) {
+                mdpNextZOrder++;
+            }
             if(configure(ctx, layer, mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
                 ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
                         layer %d",__FUNCTION__, index);
@@ -2083,7 +2094,7 @@
     return ret;
 }
 
-bool MDPComp::allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index) {
+bool MDPComp::allocSplitVGPipes(hwc_context_t *ctx, int index) {
 
     bool bRet = true;
     int mdpIndex = mCurrentFrame.layerToMDP[index];
@@ -2186,7 +2197,7 @@
         hwc_layer_1_t* layer = &list->hwLayers[index];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
         if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
-            if(allocSplitVGPipesfor4k2k(ctx, index)){
+            if(allocSplitVGPipes(ctx, index)){
                 continue;
             }
         }
@@ -2363,7 +2374,9 @@
                 mdpNextZOrder++;
                 hwc_layer_1_t* layer = &list->hwLayers[index];
                 private_handle_t *hnd = (private_handle_t *)layer->handle;
-                if(isYUVSplitNeeded(hnd)) {
+                if(isYUVSplitNeeded(hnd) ||
+                        (needs3DComposition(ctx,mDpy) &&
+                         get3DFormat(hnd) != HAL_NO_3D)) {
                     hwc_rect_t dst = layer->displayFrame;
                     if((dst.left > lSplit) || (dst.right < lSplit)) {
                         mCurrentFrame.mdpCount += 1;
@@ -2426,11 +2439,16 @@
         const int lSplit = getLeftSplit(ctx, mDpy);
         if(isYUVSplitNeeded(hnd) && sEnableYUVsplit){
             if((dst.left > lSplit)||(dst.right < lSplit)){
-                if(allocSplitVGPipesfor4k2k(ctx, index)){
+                if(allocSplitVGPipes(ctx, index)){
                     continue;
                 }
             }
         }
+        //XXX: Check for forced 2D composition
+        if(needs3DComposition(ctx, mDpy) && get3DFormat(hnd) != HAL_NO_3D)
+            if(allocSplitVGPipes(ctx,index))
+                continue;
+
         int mdpIndex = mCurrentFrame.layerToMDP[index];
         PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
         info.pipeInfo = new MdpPipeInfoSplit;
@@ -2493,7 +2511,9 @@
     }
 
     // Set the Handle timeout to true for MDP or MIXED composition.
-    if(sIdleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
+    if(sIdleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount &&
+            !(needs3DComposition(ctx, HWC_DISPLAY_PRIMARY) ||
+                needs3DComposition(ctx, HWC_DISPLAY_EXTERNAL))) {
         sHandleTimeout = true;
     }
 
@@ -2518,7 +2538,8 @@
 
         int mdpIndex = mCurrentFrame.layerToMDP[i];
 
-        if(isYUVSplitNeeded(hnd) && sEnableYUVsplit)
+        if((isYUVSplitNeeded(hnd) && sEnableYUVsplit) ||
+                (needs3DComposition(ctx, mDpy) && get3DFormat(hnd) != HAL_NO_3D))
         {
             MdpYUVPipeInfo& pipe_info =
                 *(MdpYUVPipeInfo*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
@@ -2826,6 +2847,7 @@
     int rotFlags = ROT_FLAGS_NONE;
     uint32_t format = ovutils::getMdpFormat(hnd->format, hnd->flags);
     Whf whf(getWidth(hnd), getHeight(hnd), format, hnd->size);
+    eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
 
     ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d"
              "dest_pipeR: %d",__FUNCTION__, layer, z, lDest, rDest);
@@ -2841,6 +2863,12 @@
         trimAgainstROI(ctx, crop, dst);
     }
 
+    if(needs3DComposition(ctx, mDpy) &&
+            get3DFormat(hnd) != HAL_NO_3D){
+        return configure3DVideo(ctx, layer, mDpy, mdpFlags, z, lDest,
+                rDest, &PipeLayerPair.rot);
+    }
+
     // Handle R/B swap
     if (layer->flags & HWC_FORMAT_RB_SWAP) {
         if (hnd->format == HAL_PIXEL_FORMAT_RGBA_8888)
@@ -2857,7 +2885,6 @@
     calcExtDisplayPosition(ctx, hnd, mDpy, crop, dst, transform, orient);
 
     int downscale = getRotDownscale(ctx, layer);
-    eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
     setMdpFlags(ctx, layer, mdpFlags, downscale, transform);
 
     if(lDest != OV_INVALID && rDest != OV_INVALID) {
@@ -3044,9 +3071,7 @@
         int perfHint = 0x4501; // 45-display layer hint, 01-Enable
         sPerfLockHandle = sPerfLockAcquire(0 /*handle*/, 0/*duration*/,
                                     &perfHint, sizeof(perfHint)/sizeof(int));
-        if(sPerfLockHandle < 0) {
-            ALOGE("Perf Lock Acquire Failed");
-        } else {
+        if(sPerfLockHandle > 0) {
             perflockFlag = 1;
         }
     }
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 7c46c1a..a83f51f 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -270,7 +270,7 @@
     //Enable 4kx2k yuv layer split
     static bool sEnableYUVsplit;
     bool mModeOn; // if prepare happened
-    bool allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index);
+    bool allocSplitVGPipes(hwc_context_t *ctx, int index);
     //Enable Partial Update for MDP3 targets
     static bool enablePartialUpdateForMDP3;
     static void *sLibPerfHint;
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 09013c6..487ec77 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -35,6 +35,8 @@
 #include <hwc_virtual.h>
 #include <overlay.h>
 #include <display_config.h>
+#include <hdmi.h>
+#include <video/msm_hdmi_modes.h>
 
 #define QCLIENT_DEBUG 0
 
@@ -338,6 +340,21 @@
     }
 }
 
+static void setS3DMode(hwc_context_t* ctx, int mode) {
+    if (ctx->mHDMIDisplay) {
+        if(ctx->mHDMIDisplay->isS3DModeSupported(mode)) {
+            ALOGD("%s: Force S3D mode to %d", __FUNCTION__, mode);
+            Locker::Autolock _sl(ctx->mDrawLock);
+            ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].s3dModeForced = true;
+            setup3DMode(ctx, HWC_DISPLAY_EXTERNAL, mode);
+        } else {
+            ALOGD("%s: mode %d is not supported", __FUNCTION__, mode);
+        }
+    } else {
+        ALOGE("%s: No HDMI Display detected", __FUNCTION__);
+    }
+}
+
 status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
         Parcel* outParcel) {
     status_t ret = NO_ERROR;
@@ -398,6 +415,9 @@
         case IQService::TOGGLE_SCREEN_UPDATE:
             toggleScreenUpdate(mHwcContext, inParcel->readInt32());
             break;
+        case IQService::SET_S3D_MODE:
+            setS3DMode(mHwcContext, inParcel->readInt32());
+            break;
         default:
             ret = NO_ERROR;
     }
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 9ea8246..05ab503 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -45,6 +45,7 @@
 #include "qd_utils.h"
 #include <sys/sysinfo.h>
 #include <dlfcn.h>
+#include <video/msm_hdmi_modes.h>
 
 using namespace qClient;
 using namespace qService;
@@ -351,8 +352,14 @@
         ctx->dpyAttr[i].mActionSafePresent = false;
         ctx->dpyAttr[i].mAsWidthRatio = 0;
         ctx->dpyAttr[i].mAsHeightRatio = 0;
+        ctx->dpyAttr[i].s3dMode = HDMI_S3D_NONE;
+        ctx->dpyAttr[i].s3dModeForced = false;
     }
 
+    //Make sure that the 3D mode is unset at bootup
+    //This makes sure that the state is accurate on framework reboots
+    ctx->mHDMIDisplay->configure3D(HDMI_S3D_NONE);
+
     for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
         ctx->mPrevHwLayerCount[i] = 0;
     }
@@ -1008,6 +1015,8 @@
     ctx->listStats[dpy].refreshRateRequest = ctx->dpyAttr[dpy].refreshRate;
     uint32_t refreshRate = 0;
     qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
+    int s3dFormat = HAL_NO_3D;
+    int s3dLayerCount = 0;
 
     ctx->listStats[dpy].mAIVVideoMode = false;
     resetROI(ctx, dpy);
@@ -1063,6 +1072,14 @@
                 ctx->listStats[dpy].yuv4k2kIndices[yuv4k2kCount] = (int)i;
                 yuv4k2kCount++;
             }
+
+            // Gets set if one YUV layer is 3D
+            if (displaySupports3D(ctx,dpy)) {
+                s3dFormat = get3DFormat(hnd);
+                if(s3dFormat != HAL_NO_3D)
+                    s3dLayerCount++;
+            }
+
         }
         if(layer->blending == HWC_BLENDING_PREMULT)
             ctx->listStats[dpy].preMultipliedAlpha = true;
@@ -1089,6 +1106,17 @@
         }
 #endif
     }
+
+    //Set the TV's 3D mode based on format if it was not forced
+    //Only one 3D YUV layer is supported on external
+    //If there is more than one 3D YUV layer, the switch to 3D cannot occur.
+    if( !ctx->dpyAttr[dpy].s3dModeForced && (s3dLayerCount <= 1)) {
+        //XXX: Rapidly going in and out of 3D mode in some cases such
+        // as rotation might cause flickers. The OEMs are recommended to disable
+        // rotation on HDMI globally or in the app that plays 3D video
+        setup3DMode(ctx, dpy, convertS3DFormatToMode(s3dFormat));
+    }
+
     if(ctx->listStats[dpy].yuvCount > 0) {
         if (property_get("hw.cabl.yuv", property, NULL) > 0) {
             if (atoi(property) != 1) {
@@ -2197,6 +2225,113 @@
     return 0;
 }
 
+int configure3DVideo(hwc_context_t *ctx, hwc_layer_1_t *layer,
+        const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
+        const eDest& lDest, const eDest& rDest,
+        Rotator **rot) {
+    private_handle_t *hnd = (private_handle_t *)layer->handle;
+    if(!hnd) {
+        ALOGE("%s: layer handle is NULL", __FUNCTION__);
+        return -1;
+    }
+    //Both pipes are configured to the same mixer
+    eZorder lz = z;
+    eZorder rz = (eZorder)(z + 1);
+
+    MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+
+    hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+    hwc_rect_t dst = layer->displayFrame;
+    int transform = layer->transform;
+    eTransform orient = static_cast<eTransform>(transform);
+    int rotFlags = ROT_FLAGS_NONE;
+    uint32_t format = ovutils::getMdpFormat(hnd->format, hnd->flags);
+    Whf whf(getWidth(hnd), getHeight(hnd), format, (uint32_t)hnd->size);
+
+    int downscale = getRotDownscale(ctx, layer);
+    setMdpFlags(ctx, layer, mdpFlagsL, downscale, transform);
+
+    //XXX: Check if rotation is supported and valid for 3D
+    if((has90Transform(layer) or downscale) and isRotationDoable(ctx, hnd)) {
+        (*rot) = ctx->mRotMgr->getNext();
+        if((*rot) == NULL) return -1;
+        ctx->mLayerRotMap[dpy]->add(layer, *rot);
+        //Configure rotator for pre-rotation
+        if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
+            ALOGE("%s: configRotator failed!", __FUNCTION__);
+            return -1;
+        }
+        updateSource(orient, whf, crop, *rot);
+        rotFlags |= ROT_PREROTATED;
+    }
+
+    eMdpFlags mdpFlagsR = mdpFlagsL;
+
+    hwc_rect_t cropL = crop, dstL = dst;
+    hwc_rect_t cropR = crop, dstR = dst;
+    int hw_w = ctx->dpyAttr[dpy].xres;
+    int hw_h = ctx->dpyAttr[dpy].yres;
+
+    if(get3DFormat(hnd) == HAL_3D_SIDE_BY_SIDE_L_R ||
+            get3DFormat(hnd) == HAL_3D_SIDE_BY_SIDE_R_L) {
+        // Calculate Left rects
+        // XXX: This assumes crop.right/2 is the center point of the video
+        cropL.right = crop.right/2;
+        dstL.left = dst.left/2;
+        dstL.right = dst.right/2;
+
+        // Calculate Right rects
+        cropR.left = crop.right/2;
+        dstR.left = hw_w/2 + dst.left/2;
+        dstR.right = hw_w/2 + dst.right/2;
+    } else if(get3DFormat(hnd) == HAL_3D_TOP_BOTTOM) {
+        // Calculate Left rects
+        cropL.bottom = crop.bottom/2;
+        dstL.top = dst.top/2;
+        dstL.bottom = dst.bottom/2;
+
+        // Calculate Right rects
+        cropR.top = crop.bottom/2;
+        dstR.top = hw_h/2 + dst.top/2;
+        dstR.bottom = hw_h/2 + dst.bottom/2;
+    } else {
+        ALOGE("%s: Unsupported 3D mode ", __FUNCTION__);
+        return -1;
+    }
+
+    //For the mdp, since either we are pre-rotating or MDP does flips
+    orient = OVERLAY_TRANSFORM_0;
+    transform = 0;
+
+    //configure left pipe
+    if(lDest != OV_INVALID) {
+        PipeArgs pargL(mdpFlagsL, whf, lz,
+                       static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
+                       (ovutils::eBlending) getBlending(layer->blending));
+
+        if(configMdp(ctx->mOverlay, pargL, orient,
+                cropL, dstL, metadata, lDest) < 0) {
+            ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
+            return -1;
+        }
+    }
+
+    //configure right pipe
+    if(rDest != OV_INVALID) {
+        PipeArgs pargR(mdpFlagsR, whf, rz,
+                       static_cast<eRotFlags>(rotFlags),
+                       layer->planeAlpha,
+                       (ovutils::eBlending) getBlending(layer->blending));
+        if(configMdp(ctx->mOverlay, pargR, orient,
+                cropR, dstR, metadata, rDest) < 0) {
+            ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
 int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
         const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
         const eDest& lDest, const eDest& rDest,
@@ -2810,4 +2945,41 @@
     ctx->dpyAttr[dpy].isActive = false;
 }
 
+int convertS3DFormatToMode(int s3DFormat) {
+    int ret;
+    switch(s3DFormat) {
+    case HAL_3D_SIDE_BY_SIDE_L_R:
+    case HAL_3D_SIDE_BY_SIDE_R_L:
+        ret = HDMI_S3D_SIDE_BY_SIDE;
+        break;
+    case HAL_3D_TOP_BOTTOM:
+        ret = HDMI_S3D_TOP_AND_BOTTOM;
+        break;
+    default:
+        ret = HDMI_S3D_NONE;
+    }
+    return ret;
+}
+
+bool needs3DComposition(hwc_context_t* ctx, int dpy) {
+    return (displaySupports3D(ctx, dpy) && ctx->dpyAttr[dpy].connected &&
+            ctx->dpyAttr[dpy].s3dMode != HDMI_S3D_NONE);
+}
+
+void setup3DMode(hwc_context_t *ctx, int dpy, int s3dMode) {
+    if (ctx->dpyAttr[dpy].s3dMode != s3dMode) {
+        ALOGD("%s: setup 3D mode: %d", __FUNCTION__, s3dMode);
+        if(ctx->mHDMIDisplay->configure3D(s3dMode)) {
+            ctx->dpyAttr[dpy].s3dMode = s3dMode;
+        }
+    }
+}
+
+bool displaySupports3D(hwc_context_t* ctx, int dpy) {
+    return ((dpy == HWC_DISPLAY_EXTERNAL) ||
+            ((dpy == HWC_DISPLAY_PRIMARY) &&
+             ctx->mHDMIDisplay->isHDMIPrimaryDisplay()));
+}
+
+
 };//namespace qhwc
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index a97c59b..f11eed5 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -117,6 +117,18 @@
     uint32_t xres_new;
     uint32_t yres_new;
 
+    // This is the 3D mode to which the TV is set
+    // The mode may be set via the appearance of a layer with 3D format
+    // or by forcing the mode via binder.
+    // If the mode is set via binder, the s3dModeForced flag is set, so that the
+    // mode is not changed back when the 3D video layer drops out.
+    // If the forced mode is different from the one in 3D video, the results
+    // are unpredictable. The assumption is made here that the caller forcing
+    // the mode via binder knows the right formats to use.
+    // The s3dModeForced flag is also used to force 2D if the s3dMode is
+    // HDMI_S3D_NONE
+    int s3dMode;
+    bool s3dModeForced;
 };
 
 struct ListStats {
@@ -411,6 +423,15 @@
         const ovutils::eDest& lDest,
         const ovutils::eDest& rDest, overlay::Rotator **rot);
 
+//Check if the current round needs 3D composition
+bool needs3DComposition(hwc_context_t* ctx, int dpy);
+
+//Routine to configure 3D video
+int configure3DVideo(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
+        ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
+        const ovutils::eDest& lDest,
+        const ovutils::eDest& rDest, overlay::Rotator **rot);
+
 //Routine to split and configure high resolution YUV layer (> 2048 width)
 int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
         const int& dpy,
@@ -444,6 +465,16 @@
 // Checks if boot animation has completed and applies default mode
 void processBootAnimCompleted(hwc_context_t *ctx);
 
+//The gralloc API and driver have different formats
+//The format needs to be converted before passing to libhdmi
+int convertS3DFormatToMode(int s3DFormat);
+
+//Configure resources for 3D mode
+void setup3DMode(hwc_context_t* ctx, int dpy, int s3dMode);
+
+//Checks if this display supports 3D
+bool displaySupports3D(hwc_context_t* ctx, int dpy);
+
 // Inline utility functions
 static inline bool isSkipLayer(const hwc_layer_1_t* l) {
     return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER)));
@@ -489,6 +520,14 @@
     return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY));
 }
 
+static inline uint32_t get3DFormat(const private_handle_t* hnd) {
+    MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
+    if(isYuvBuffer(hnd) && metadata && metadata->operation & S3D_FORMAT) {
+        return metadata->s3dFormat;
+    }
+    return HAL_NO_3D;
+}
+
 static inline int getWidth(const private_handle_t* hnd) {
     MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
     if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
@@ -644,7 +683,7 @@
     bool mBWCEnabled;
     // Provides a way for OEM's to disable setting dynfps via metadata.
     bool mUseMetaDataRefreshRate;
-   // Stores the hpd enabled status- avoids re-enabling HDP on suspend resume.
+    // Stores the hpd enabled status- avoids re-enabling HDP on suspend resume.
     bool mHPDEnabled;
     //Used to notify that boot has completed
     bool mBootAnimCompleted;
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index cd2d116..796e506 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -60,6 +60,7 @@
         SET_PARTIAL_UPDATE = 19,   // Preference on partial update feature
         TOGGLE_SCREEN_UPDATE = 20, // Provides ability to disable screen updates
         SET_FRAME_DUMP_CONFIG = 21,  // Provides ability to set the frame dump config
+        SET_S3D_MODE = 22, // Set the 3D mode as specified in msm_hdmi_modes.h
         COMMAND_LIST_END = 400,
     };