Merge "hwc: Modify MDPOnly composition to allow only secure RGB layers"
diff --git a/displayengine/include/core/layer_buffer.h b/displayengine/include/core/layer_buffer.h
index 5e813ea..c069c60 100755
--- a/displayengine/include/core/layer_buffer.h
+++ b/displayengine/include/core/layer_buffer.h
@@ -108,11 +108,13 @@
   @sa LayerBuffer
 */
 struct LayerBufferFlags {
-  uint64_t secure : 1;  //!< This flag shall be set by client to indicate that the buffer need
-                        //!< to be handled securely.
-  uint64_t video  : 1;  //!< This flag shall be set by client to indicate that the buffer is
-                        //!< video/ui buffer
-  LayerBufferFlags() : secure(0) { }
+  uint64_t secure : 1;      //!< This flag shall be set by client to indicate that the buffer need
+                            //!< to be handled securely.
+  uint64_t video  : 1;      //!< This flag shall be set by client to indicate that the buffer is
+                            //!< video/ui buffer
+  uint64_t macro_tile : 1;  //!< This flag shall be set by client to indicate that the buffer format
+                            //!< is macro tiled.
+  LayerBufferFlags() : secure(0), video(0), macro_tile(0) { }
 };
 
 /*! @brief This structure defines a layer buffer handle which contains raw buffer and its associated
diff --git a/displayengine/libs/core/hw_framebuffer.cpp b/displayengine/libs/core/hw_framebuffer.cpp
index 3a0f2d0..e7c8664 100644
--- a/displayengine/libs/core/hw_framebuffer.cpp
+++ b/displayengine/libs/core/hw_framebuffer.cpp
@@ -513,6 +513,15 @@
       if (error != kErrorNone) {
         return error;
       }
+
+      if (layer.transform.flip_vertical) {
+        mdp_layer.flags |= MDP_LAYER_FLIP_UD;
+      }
+
+      if (layer.transform.flip_horizontal) {
+        mdp_layer.flags |= MDP_LAYER_FLIP_LR;
+      }
+
       mdp_layer_count++;
     }
   }
diff --git a/displayengine/libs/core/hw_interface.h b/displayengine/libs/core/hw_interface.h
index 84870b8..99d392d 100644
--- a/displayengine/libs/core/hw_interface.h
+++ b/displayengine/libs/core/hw_interface.h
@@ -92,6 +92,20 @@
       has_non_scalar_rgb(false), is_src_split(false), always_src_split(false) { }
 };
 
+struct HWRotateInfo {
+  uint32_t pipe_id;
+  LayerRect src_roi;
+  LayerRect dst_roi;
+  HWBlockType writeback_id;
+  float downscale_ratio_x;
+  float downscale_ratio_y;
+
+  HWRotateInfo() : pipe_id(0), writeback_id(kHWWriteback0), downscale_ratio_x(1.0f),
+      downscale_ratio_y(1.0f) { }
+
+  inline void Reset() { *this = HWRotateInfo(); }
+};
+
 struct HWPipeInfo {
   uint32_t pipe_id;
   LayerRect src_roi;
@@ -99,15 +113,19 @@
   uint8_t decimation;
 
   HWPipeInfo() : pipe_id(0), decimation(1) { }
+
+  inline void Reset() { *this = HWPipeInfo(); }
 };
 
 struct HWLayerConfig {
-  bool use_non_dma_pipe;
-  bool is_right_pipe;
-  HWPipeInfo left_pipe;
-  HWPipeInfo right_pipe;
+  bool use_non_dma_pipe;  // set by client
+  bool is_right_pipe;  // indicate if right pipe is valid
+  HWPipeInfo left_pipe;  // pipe for left side of the buffer
+  HWPipeInfo right_pipe;  // pipe for right side of the buffer
+  HWRotateInfo left_rotate;  // rotation for left side of the buffer
+  HWRotateInfo right_rotate;  // rotation for right side of the buffer
 
-  HWLayerConfig() : use_non_dma_pipe(false), is_right_pipe(true) { }
+  HWLayerConfig() : use_non_dma_pipe(false), is_right_pipe(false) { }
 };
 
 struct HWLayers {
diff --git a/displayengine/libs/core/res_config.cpp b/displayengine/libs/core/res_config.cpp
old mode 100755
new mode 100644
index 73ea4a4..974897c
--- a/displayengine/libs/core/res_config.cpp
+++ b/displayengine/libs/core/res_config.cpp
@@ -32,115 +32,285 @@
 
 namespace sde {
 
-DisplayError ResManager::Config(DisplayResourceContext *display_resource_ctx, HWLayers *hw_layers) {
-  HWBlockType hw_block_id = display_resource_ctx->hw_block_id;
+void ResManager::RotationConfig(const LayerTransform &transform, LayerRect *src_rect,
+                              HWRotateInfo *left_rotate, HWRotateInfo *right_rotate,
+                              uint32_t *rotate_count) {
+  float src_width = src_rect->right - src_rect->left;
+  float src_height = src_rect->bottom - src_rect->top;
+  LayerRect dst_rect;
+  // Rotate output is a temp buffer, always output to the top left corner for saving memory
+  dst_rect.top = 0.0f;
+  dst_rect.left = 0.0f;
+  // downscale when doing rotation
+  dst_rect.right = src_height / left_rotate->downscale_ratio_x;
+  dst_rect.bottom = src_width / left_rotate->downscale_ratio_y;
+
+  left_rotate->src_roi = *src_rect;
+  left_rotate->pipe_id = kPipeIdNeedsAssignment;
+  left_rotate->dst_roi = dst_rect;
+  // Always use one rotator for now
+  right_rotate->Reset();
+
+  *src_rect = dst_rect;
+  (*rotate_count)++;
+}
+
+DisplayError ResManager::SrcSplitConfig(DisplayResourceContext *display_resource_ctx,
+                                        const LayerTransform &transform, const LayerRect &src_rect,
+                                        const LayerRect &dst_rect, HWLayerConfig *layer_config) {
   HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
-  HWLayersInfo &layer_info = hw_layers->info;
+  HWPipeInfo *left_pipe = &layer_config->left_pipe;
+  HWPipeInfo *right_pipe = &layer_config->right_pipe;
+  layer_config->is_right_pipe = false;
 
-  for (uint32_t i = 0; i < layer_info.count; i++) {
-    Layer& layer = layer_info.stack->layers[layer_info.index[i]];
-    float w_scale, h_scale;
-    if (!IsValidDimension(layer, &w_scale, &h_scale)) {
-      DLOGV("Invalid dimension");
+  if ((src_rect.right - src_rect.left) >= kMaxSourcePipeWidth ||
+      (dst_rect.right - dst_rect.left) >= kMaxInterfaceWidth || hw_res_info_.always_src_split) {
+    SplitRect(transform.flip_horizontal, src_rect, dst_rect, &left_pipe->src_roi,
+              &left_pipe->dst_roi, &right_pipe->src_roi, &right_pipe->dst_roi);
+    left_pipe->pipe_id = kPipeIdNeedsAssignment;
+    right_pipe->pipe_id = kPipeIdNeedsAssignment;
+    layer_config->is_right_pipe = true;
+  } else {
+    left_pipe->src_roi = src_rect;
+    left_pipe->dst_roi = dst_rect;
+    left_pipe->pipe_id = kPipeIdNeedsAssignment;
+    right_pipe->Reset();
+  }
+  return kErrorNone;
+}
+
+DisplayError ResManager::DisplaySplitConfig(DisplayResourceContext *display_resource_ctx,
+                                            const LayerTransform &transform,
+                                            const LayerRect &src_rect, const LayerRect &dst_rect,
+                                            HWLayerConfig *layer_config) {
+  HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
+  // for display split case
+  HWPipeInfo *left_pipe = &layer_config->left_pipe;
+  HWPipeInfo *right_pipe = &layer_config->right_pipe;
+  LayerRect scissor, dst_left, crop_left, crop_right, dst_right;
+  layer_config->is_right_pipe = false;
+  scissor.right = FLOAT(display_attributes.split_left);
+  scissor.bottom = FLOAT(display_attributes.y_pixels);
+
+  crop_left = src_rect;
+  dst_left = dst_rect;
+  crop_right = crop_left;
+  dst_right = dst_left;
+  CalculateCropRects(scissor, transform, &crop_left, &dst_left);
+
+  scissor.left = FLOAT(display_attributes.split_left);
+  scissor.top = 0.0f;
+  scissor.right = FLOAT(display_attributes.x_pixels);
+  scissor.bottom = FLOAT(display_attributes.y_pixels);
+  CalculateCropRects(scissor, transform, &crop_right, &dst_right);
+  if ((crop_left.right - crop_left.left) >= kMaxSourcePipeWidth) {
+    if (crop_right.right != crop_right.left)
       return kErrorNotSupported;
-    }
+    // 2 pipes both are on the left
+    SplitRect(transform.flip_horizontal, crop_left, dst_left, &left_pipe->src_roi,
+              &left_pipe->dst_roi, &right_pipe->src_roi, &right_pipe->dst_roi);
+    left_pipe->pipe_id = kPipeIdNeedsAssignment;
+    right_pipe->pipe_id = kPipeIdNeedsAssignment;
+    layer_config->is_right_pipe = true;
+  } else if ((crop_right.right - crop_right.left) >= kMaxSourcePipeWidth) {
+    if (crop_left.right != crop_left.left)
+      return kErrorNotSupported;
+    // 2 pipes both are on the right
+    SplitRect(transform.flip_horizontal, crop_right, dst_right, &left_pipe->src_roi,
+              &left_pipe->dst_roi, &right_pipe->src_roi, &right_pipe->dst_roi);
+    left_pipe->pipe_id = kPipeIdNeedsAssignment;
+    right_pipe->pipe_id = kPipeIdNeedsAssignment;
+    layer_config->is_right_pipe = true;
+  } else if (UINT32(dst_left.right) > UINT32(dst_left.left)) {
+    // assign left pipe
+    left_pipe->src_roi = crop_left;
+    left_pipe->dst_roi = dst_left;
+    left_pipe->pipe_id = kPipeIdNeedsAssignment;
+  } else {
+    // Set default value, left_pipe is not needed.
+    left_pipe->Reset();
+  }
 
-    LayerRect scissor;
-    scissor.right = FLOAT(display_attributes.split_left);
-    scissor.bottom = FLOAT(display_attributes.y_pixels);
-    LayerRect crop = layer.src_rect;
-    LayerRect dst = layer.dst_rect;
-    LayerRect cropRight = crop;
-    LayerRect dstRight = dst;
-    CalculateCropRects(&crop, &dst, scissor, layer.transform);
-    HWPipeInfo *pipe_info = &hw_layers->config[i].left_pipe;
-
-    pipe_info->src_roi = crop;
-    pipe_info->dst_roi = dst;
-
-    float crop_width = cropRight.right - cropRight.left;
-    pipe_info = &hw_layers->config[i].right_pipe;
-    if ((dstRight.right - dstRight.left) > kMaxInterfaceWidth ||
-         crop_width > kMaxInterfaceWidth ||
-        ((hw_block_id == kHWPrimary) &&
-         (crop_width > display_attributes.split_left))) {
-      scissor.left = FLOAT(display_attributes.split_left);
-      scissor.top = 0.0f;
-      scissor.right = FLOAT(display_attributes.x_pixels);
-      scissor.bottom = FLOAT(display_attributes.y_pixels);
-      CalculateCropRects(&cropRight, &dstRight, scissor, layer.transform);
-      pipe_info->src_roi = cropRight;
-      pipe_info->dst_roi = dstRight;
-      pipe_info->pipe_id = -1;
+  // assign right pipe if needed
+  if (UINT32(dst_right.right) > UINT32(dst_right.left)) {
+    if (left_pipe->pipe_id) {
+      right_pipe->src_roi = crop_right;
+      right_pipe->dst_roi = dst_right;
+      right_pipe->pipe_id = kPipeIdNeedsAssignment;
+      layer_config->is_right_pipe = true;
     } else {
-      // need not right pipe
-      pipe_info->pipe_id = 0;
+      // If left pipe is not used, use left pipe first.
+      left_pipe->src_roi = crop_right;
+      left_pipe->dst_roi = dst_right;
+      left_pipe->pipe_id = kPipeIdNeedsAssignment;
+      right_pipe->Reset();
     }
+  } else {
+    // need not right pipe
+    right_pipe->Reset();
   }
 
   return kErrorNone;
 }
 
-bool ResManager::IsValidDimension(const Layer& layer, float *width_scale, float *height_scale) {
-  if (IsNonIntegralSrcCrop(layer.src_rect)) {
-    return false;
-  }
+DisplayError ResManager::Config(DisplayResourceContext *display_resource_ctx, HWLayers *hw_layers,
+                                uint32_t *rotate_count) {
+  HWBlockType hw_block_id = display_resource_ctx->hw_block_id;
+  HWDisplayAttributes &display_attributes = display_resource_ctx->display_attributes;
+  HWLayersInfo &layer_info = hw_layers->info;
+  DisplayError error = kErrorNone;
 
-  LayerRect crop;
-  LayerRect dst;
-  IntegerizeRect(&crop, layer.src_rect);
-  IntegerizeRect(&dst, layer.dst_rect);
+  for (uint32_t i = 0; i < layer_info.count; i++) {
+    Layer& layer = layer_info.stack->layers[layer_info.index[i]];
+    float rot_scale_x = 1.0f, rot_scale_y = 1.0f;
+    if (!IsValidDimension(layer.src_rect, layer.dst_rect)) {
+      DLOGE_IF(kTagResources, "Input is invalid");
+      LogRectVerbose("input layer src_rect", layer.src_rect);
+      LogRectVerbose("input layer dst_rect", layer.dst_rect);
+      return kErrorNotSupported;
+    }
 
-  bool rotated90 = (static_cast<int>(layer.transform.rotation) == 90);
-  float crop_w = rotated90 ? crop.bottom - crop.top : crop.right - crop.left;
-  float crop_h = rotated90 ? crop.right - crop.left : crop.bottom - crop.top;
-  float dst_w = dst.right - dst.left;
-  float dst_h = dst.bottom - dst.top;
+    LayerRect scissor, src_rect, dst_rect;
+    src_rect = layer.src_rect;
+    dst_rect = layer.dst_rect;
+    scissor.right = FLOAT(display_attributes.x_pixels);
+    scissor.bottom = FLOAT(display_attributes.y_pixels);
+    CalculateCropRects(scissor, layer.transform, &src_rect, &dst_rect);
 
-  if ((dst_w < 1) || (dst_h < 1)) {
-    return false;
-  }
+    if (ValidateScaling(layer, src_rect, dst_rect, &rot_scale_x, &rot_scale_y))
+      return kErrorNotSupported;
 
-  float w_scale = crop_w / dst_w;
-  float h_scale = crop_h / dst_h;
+    HWRotateInfo *left_rotate, *right_rotate;
+    // config rotator first
+    left_rotate = &hw_layers->config[i].left_rotate;
+    right_rotate = &hw_layers->config[i].right_rotate;
 
-  if ((crop_w < kMaxCropWidth) ||(crop_h < kMaxCropHeight)) {
-    return false;
-  }
+    LayerTransform transform = layer.transform;
+    if (IsRotationNeeded(transform.rotation) ||
+        UINT32(rot_scale_x) != 1 || UINT32(rot_scale_y) != 1) {
+      left_rotate->downscale_ratio_x = rot_scale_x;
+      right_rotate->downscale_ratio_x = rot_scale_x;
+      left_rotate->downscale_ratio_y = rot_scale_y;
+      right_rotate->downscale_ratio_y = rot_scale_y;
 
-  if ((w_scale > 1.0f) || (h_scale > 1.0f)) {
-    const uint32_t max_scale_down = hw_res_info_.max_scale_down;
-
-    if (!hw_res_info_.has_decimation) {
-      if (crop_w > kMaxSourcePipeWidth || w_scale > max_scale_down || h_scale > max_scale_down) {
-        return false;
-      }
+      RotationConfig(layer.transform, &src_rect, left_rotate, right_rotate, rotate_count);
+      // rotator will take care of flipping, reset tranform
+      transform = LayerTransform();
     } else {
-      if (w_scale > max_scale_down || h_scale > max_scale_down) {
-        return false;
-      }
+      left_rotate->Reset();
+      right_rotate->Reset();
+    }
+
+    if (hw_res_info_.is_src_split) {
+      error = SrcSplitConfig(display_resource_ctx, transform, src_rect,
+                             dst_rect, &hw_layers->config[i]);
+    } else {
+      error = DisplaySplitConfig(display_resource_ctx, transform, src_rect,
+                                 dst_rect, &hw_layers->config[i]);
+    }
+
+    if (error != kErrorNone)
+      break;
+
+    DLOGV_IF(kTagResources, "layer = %d, left pipe_id = %x",
+             i, hw_layers->config[i].left_pipe.pipe_id);
+    LogRectVerbose("input layer src_rect", layer.src_rect);
+    LogRectVerbose("input layer dst_rect", layer.dst_rect);
+    LogRectVerbose("cropped src_rect", src_rect);
+    LogRectVerbose("cropped dst_rect", dst_rect);
+    LogRectVerbose("left pipe src", hw_layers->config[i].left_pipe.src_roi);
+    LogRectVerbose("left pipe dst", hw_layers->config[i].left_pipe.dst_roi);
+    if (hw_layers->config[i].right_pipe.pipe_id) {
+      LogRectVerbose("right pipe src", hw_layers->config[i].right_pipe.src_roi);
+      LogRectVerbose("right pipe dst", hw_layers->config[i].right_pipe.dst_roi);
     }
   }
 
-  if (((w_scale < 1.0f) || (h_scale < 1.0f)) && (w_scale > 0.0f) && (h_scale > 0.0f)) {
-    const uint32_t max_scale_up = hw_res_info_.max_scale_up;
-    const float w_uscale = 1.0f / w_scale;
-    const float h_uscale = 1.0f / h_scale;
-
-    if (w_uscale > max_scale_up || h_uscale > max_scale_up) {
-      return false;
-    }
-  }
-
-  *width_scale = w_scale;
-  *height_scale = h_scale;
-
-  return true;
+  return error;
 }
 
-void ResManager::CalculateCut(float *left_cut_ratio,
-    float *top_cut_ratio, float *right_cut_ratio, float *bottom_cut_ratio,
-    const LayerTransform& transform) {
+DisplayError ResManager::ValidateScaling(const Layer &layer, const LayerRect &crop,
+                                         const LayerRect &dst, float *rot_scale_x,
+                                         float *rot_scale_y) {
+  bool rotated90 = IsRotationNeeded(layer.transform.rotation);
+  float crop_width = rotated90 ? crop.bottom - crop.top : crop.right - crop.left;
+  float crop_height = rotated90 ? crop.right - crop.left : crop.bottom - crop.top;
+  float dst_width = dst.right - dst.left;
+  float dst_height = dst.bottom - dst.top;
+
+  if ((dst_width < 1.0f) || (dst_height < 1.0f)) {
+    DLOGV_IF(kTagResources, "Destination region is too small w = %d, h = %d",
+    dst_width, dst_height);
+    return kErrorNotSupported;
+  }
+
+  if ((crop_width < 1.0f) || (crop_height < 1.0f)) {
+    DLOGV_IF(kTagResources, "source region is too small w = %d, h = %d", crop_width, crop_height);
+    return kErrorNotSupported;
+  }
+
+  float scale_x = crop_width / dst_width;
+  float scale_y = crop_height / dst_height;
+
+  if ((UINT32(scale_x) > 1) || (UINT32(scale_y) > 1)) {
+    const uint32_t max_scale_down = hw_res_info_.max_scale_down;
+    uint32_t max_downscale_with_rotator;
+
+    if (hw_res_info_.has_rotator_downscale)
+      max_downscale_with_rotator = max_scale_down * kMaxRotateDownScaleRatio;
+    else
+      max_downscale_with_rotator = max_scale_down;
+
+    if (((!hw_res_info_.has_decimation) || (IsMacroTileFormat(layer.input_buffer))) &&
+        (scale_x > max_scale_down || scale_y > max_scale_down)) {
+      DLOGV_IF(kTagResources,
+               "Scaling down is over the limit is_tile = %d, scale_x = %d, scale_y = %d",
+               IsMacroTileFormat(layer.input_buffer), scale_x, scale_y);
+      return kErrorNotSupported;
+    } else if (scale_x > max_downscale_with_rotator || scale_y > max_downscale_with_rotator) {
+      DLOGV_IF(kTagResources, "Scaling down is over the limit scale_x = %d, scale_y = %d",
+               scale_x, scale_y);
+      return kErrorNotSupported;
+    }
+  }
+
+  const uint32_t max_scale_up = hw_res_info_.max_scale_up;
+  if (UINT32(scale_x) < 1 && scale_x > 0.0f) {
+    if ((1.0f / scale_x) > max_scale_up) {
+      DLOGV_IF(kTagResources, "Scaling up is over limit scale_x = %d", 1.0f / scale_x);
+      return kErrorNotSupported;
+    }
+  }
+
+  if (UINT32(scale_y) < 1 && scale_y > 0.0f) {
+    if ((1.0f / scale_y) > max_scale_up) {
+      DLOGV_IF(kTagResources, "Scaling up is over limit scale_y = %d", 1.0f / scale_y);
+      return kErrorNotSupported;
+    }
+  }
+
+  // Calculate rotator downscale ratio
+  float rot_scale = 1.0f;
+  while (scale_x > hw_res_info_.max_scale_down) {
+    scale_x /= 2;
+    rot_scale *= 2;
+  }
+  *rot_scale_x = rot_scale;
+
+  rot_scale = 1.0f;
+  while (scale_y > hw_res_info_.max_scale_down) {
+    scale_y /= 2;
+    rot_scale *= 2;
+  }
+  *rot_scale_y = rot_scale;
+  DLOGV_IF(kTagResources, "rotator scaling hor = %.0f, ver = %.0f", *rot_scale_x, *rot_scale_y);
+
+  return kErrorNone;
+}
+
+void ResManager::CalculateCut(const LayerTransform &transform, float *left_cut_ratio,
+                              float *top_cut_ratio, float *right_cut_ratio,
+                              float *bottom_cut_ratio) {
   if (transform.flip_horizontal) {
     Swap(*left_cut_ratio, *right_cut_ratio);
   }
@@ -149,7 +319,7 @@
     Swap(*top_cut_ratio, *bottom_cut_ratio);
   }
 
-  if (UINT32(transform.rotation) == 90) {
+  if (IsRotationNeeded(transform.rotation)) {
     // Anti clock swapping
     float tmp_cut_ratio = *left_cut_ratio;
     *left_cut_ratio = *top_cut_ratio;
@@ -159,75 +329,80 @@
   }
 }
 
-void ResManager::CalculateCropRects(LayerRect *crop, LayerRect *dst,
-    const LayerRect& scissor, const LayerTransform& transform) {
-  float& crop_l = crop->left;
-  float& crop_t = crop->top;
-  float& crop_r = crop->right;
-  float& crop_b = crop->bottom;
-  float crop_w = crop->right - crop->left;
-  float crop_h = crop->bottom - crop->top;
+void ResManager::CalculateCropRects(const LayerRect &scissor, const LayerTransform &transform,
+                                    LayerRect *crop, LayerRect *dst) {
+  float &crop_left = crop->left;
+  float &crop_top = crop->top;
+  float &crop_right = crop->right;
+  float &crop_bottom = crop->bottom;
+  float crop_width = crop->right - crop->left;
+  float crop_height = crop->bottom - crop->top;
 
-  float& dst_l = dst->left;
-  float& dst_t = dst->top;
-  float& dst_r = dst->right;
-  float& dst_b = dst->bottom;
-  float dst_w = (dst->right > dst->left) ? dst->right - dst->left :
-    dst->left - dst->right;
-  float dst_h = (dst->bottom > dst->top) ? dst->bottom > dst->top :
-    dst->top > dst->bottom;
+  float &dst_left = dst->left;
+  float &dst_top = dst->top;
+  float &dst_right = dst->right;
+  float &dst_bottom = dst->bottom;
+  float dst_width = dst->right - dst->left;
+  float dst_height = dst->bottom - dst->top;
 
-  const float& sci_l = scissor.left;
-  const float& sci_t = scissor.top;
-  const float& sci_r = scissor.right;
-  const float& sci_b = scissor.bottom;
+  const float &sci_left = scissor.left;
+  const float &sci_top = scissor.top;
+  const float &sci_right = scissor.right;
+  const float &sci_bottom = scissor.bottom;
 
-  float left_cut_ratio = 0.0, right_cut_ratio = 0.0, top_cut_ratio = 0.0,
-    bottom_cut_ratio = 0.0;
+  float left_cut_ratio = 0.0, right_cut_ratio = 0.0, top_cut_ratio = 0.0, bottom_cut_ratio = 0.0;
+  bool need_cut = false;
 
-  if (dst_l < sci_l) {
-    left_cut_ratio = (sci_l - dst_l) / dst_w;
-    dst_l = sci_l;
+  if (dst_left < sci_left) {
+    left_cut_ratio = (sci_left - dst_left) / dst_width;
+    dst_left = sci_left;
+    need_cut = true;
   }
 
-  if (dst_r > sci_r) {
-    right_cut_ratio = (dst_r - sci_r) / dst_w;
-    dst_r = sci_r;
+  if (dst_right > sci_right) {
+    right_cut_ratio = (dst_right - sci_right) / dst_width;
+    dst_right = sci_right;
+    need_cut = true;
   }
 
-  if (dst_t < sci_t) {
-    top_cut_ratio = (sci_t - dst_t) / (dst_h);
-    dst_t = sci_t;
+  if (dst_top < sci_top) {
+    top_cut_ratio = (sci_top - dst_top) / (dst_height);
+    dst_top = sci_top;
+    need_cut = true;
   }
 
-  if (dst_b > sci_b) {
-    bottom_cut_ratio = (dst_b - sci_b) / (dst_h);
-    dst_b = sci_b;
+  if (dst_bottom > sci_bottom) {
+    bottom_cut_ratio = (dst_bottom - sci_bottom) / (dst_height);
+    dst_bottom = sci_bottom;
+    need_cut = true;
   }
 
-  CalculateCut(&left_cut_ratio, &top_cut_ratio, &right_cut_ratio, &bottom_cut_ratio, transform);
-  crop_l += crop_w * left_cut_ratio;
-  crop_t += crop_h * top_cut_ratio;
-  crop_r -= crop_w * right_cut_ratio;
-  crop_b -= crop_h * bottom_cut_ratio;
+  if (!need_cut)
+    return;
+
+  CalculateCut(transform, &left_cut_ratio, &top_cut_ratio, &right_cut_ratio, &bottom_cut_ratio);
+  crop_left += crop_width * left_cut_ratio;
+  crop_top += crop_height * top_cut_ratio;
+  crop_right -= crop_width * right_cut_ratio;
+  crop_bottom -= crop_height * bottom_cut_ratio;
 }
 
-bool ResManager::IsNonIntegralSrcCrop(const LayerRect& crop) {
-  if (crop.left - roundf(crop.left)     ||
-      crop.top - roundf(crop.top)       ||
-      crop.right - roundf(crop.right)   ||
-      crop.bottom - roundf(crop.bottom)) {
-    return true;
-  } else {
+bool ResManager::IsValidDimension(const LayerRect &src, const LayerRect &dst) {
+  // Make sure source in integral
+  if (src.left - roundf(src.left)     ||
+      src.top - roundf(src.top)       ||
+      src.right - roundf(src.right)   ||
+      src.bottom - roundf(src.bottom)) {
+    DLOGE_IF(kTagResources, "Input ROI is not integral");
     return false;
   }
-}
 
-void ResManager::IntegerizeRect(LayerRect *dst_rect, const LayerRect &src_rect) {
-  dst_rect->left = ceilf(src_rect.left);
-  dst_rect->top = ceilf(src_rect.top);
-  dst_rect->right = floorf(src_rect.right);
-  dst_rect->bottom = floorf(src_rect.bottom);
+  if (src.left > src.right || src.top > src.bottom || dst.left > dst.right ||
+      dst.top > dst.bottom) {
+    return false;
+  } else {
+    return true;
+  }
 }
 
 void ResManager::SetDecimationFactor(HWPipeInfo *pipe) {
@@ -248,5 +423,58 @@
   pipe->decimation = UINT8(powf(2.0f, decimation_factor));
 }
 
-}  // namespace sde
+void ResManager::SplitRect(bool flip_horizontal, const LayerRect &src_rect,
+                           const LayerRect &dst_rect, LayerRect *src_left, LayerRect *dst_left,
+                           LayerRect *src_right, LayerRect *dst_right) {
+  // Split rectangle horizontally and evenly into two.
+  float src_width = src_rect.right - src_rect.left;
+  float dst_width = dst_rect.right - dst_rect.left;
+  if (flip_horizontal) {
+    src_left->top = src_rect.top;
+    src_left->left = src_rect.left;
+    src_left->right = src_rect.left + (src_width / 2);
+    src_left->bottom = src_rect.bottom;
 
+    dst_left->top = dst_rect.top;
+    dst_left->left = dst_rect.left + (dst_width / 2);
+    dst_left->right = dst_rect.right;
+    dst_left->bottom = dst_rect.bottom;
+
+    src_right->top = src_rect.top;
+    src_right->left = src_left->right;
+    src_right->right = src_rect.right;
+    src_right->bottom = src_rect.bottom;
+
+    dst_right->top = dst_rect.top;
+    dst_right->left = dst_rect.left;
+    dst_right->right = dst_left->left;
+    dst_right->bottom = dst_rect.bottom;
+  } else {
+    src_left->top = src_rect.top;
+    src_left->left = src_rect.left;
+    src_left->right = src_rect.left + (src_width / 2);
+    src_left->bottom = src_rect.bottom;
+
+    dst_left->top = dst_rect.top;
+    dst_left->left = dst_rect.left;
+    dst_left->right = dst_rect.left + (dst_width / 2);
+    dst_left->bottom = dst_rect.bottom;
+
+    src_right->top = src_rect.top;
+    src_right->left = src_left->right;
+    src_right->right = src_rect.right;
+    src_right->bottom = src_rect.bottom;
+
+    dst_right->top = dst_rect.top;
+    dst_right->left = dst_left->right;
+    dst_right->right = dst_rect.right;
+    dst_right->bottom = dst_rect.bottom;
+  }
+}
+
+void ResManager::LogRectVerbose(const char *prefix, const LayerRect &roi) {
+  DLOGV_IF(kTagResources,"%s: left = %.0f, top = %.0f, right = %.0f, bottom = %.0f",
+           prefix, roi.left, roi.top, roi.right, roi.bottom);
+}
+
+}  // namespace sde
diff --git a/displayengine/libs/core/res_manager.cpp b/displayengine/libs/core/res_manager.cpp
old mode 100755
new mode 100644
index 1ccb410..38ef319
--- a/displayengine/libs/core/res_manager.cpp
+++ b/displayengine/libs/core/res_manager.cpp
@@ -32,7 +32,7 @@
 namespace sde {
 
 ResManager::ResManager()
-  : num_pipe_(0), vig_pipes_(NULL), rgb_pipes_(NULL), dma_pipes_(NULL), frame_start_(false) {
+  : num_pipe_(0), vig_pipes_(NULL), rgb_pipes_(NULL), dma_pipes_(NULL), virtual_count_(0) {
 }
 
 DisplayError ResManager::Init(const HWResourceInfo &hw_res_info) {
@@ -40,9 +40,11 @@
 
   DisplayError error = kErrorNone;
 
+  // TODO: Remove this. Disable src_split as kernel not supported yet
+  hw_res_info_.is_src_split = false;
   num_pipe_ = hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe + hw_res_info_.num_dma_pipe;
 
-  if (UNLIKELY(num_pipe_ > kPipeIdMax)) {
+  if (num_pipe_ > kPipeIdMax) {
     DLOGE("Number of pipe is over the limit! %d", num_pipe_);
     return kErrorParameters;
   }
@@ -77,6 +79,20 @@
   DLOGI("hw_rev=%x, DMA=%d RGB=%d VIG=%d", hw_res_info_.hw_revision, hw_res_info_.num_dma_pipe,
     hw_res_info_.num_rgb_pipe, hw_res_info_.num_vig_pipe);
 
+  if (hw_res_info_.num_rotator > kMaxNumRotator) {
+    DLOGE("Number of rotator is over the limit! %d", hw_res_info_.num_rotator);
+    return kErrorParameters;
+  }
+
+  if (hw_res_info_.num_rotator > 0) {
+    rotators_[0].pipe_index = dma_pipes_[0].index;
+    rotators_[0].writeback_id = kHWWriteback0;
+  }
+  if (hw_res_info_.num_rotator > 1) {
+    rotators_[1].pipe_index = dma_pipes_[1].index;
+    rotators_[1].writeback_id = kHWWriteback1;
+  }
+
   // Used by splash screen
   rgb_pipes_[0].state = kPipeStateOwnedByKernel;
   rgb_pipes_[1].state = kPipeStateOwnedByKernel;
@@ -89,28 +105,27 @@
 }
 
 DisplayError ResManager::RegisterDisplay(DisplayType type, const HWDisplayAttributes &attributes,
-                                        Handle *display_ctx) {
+                                         Handle *display_ctx) {
   DisplayError error = kErrorNone;
 
   HWBlockType hw_block_id = kHWBlockMax;
   switch (type) {
   case kPrimary:
-    if (UNLIKELY(!hw_block_ctx_[kHWPrimary].is_in_use)) {
+    if (!hw_block_ctx_[kHWPrimary].is_in_use) {
       hw_block_id = kHWPrimary;
     }
     break;
 
   case kHDMI:
-    if (UNLIKELY(!hw_block_ctx_[kHWHDMI].is_in_use)) {
+    if (!hw_block_ctx_[kHWHDMI].is_in_use) {
       hw_block_id = kHWHDMI;
     }
     break;
 
   case kVirtual:
-    // assume only WB2 can be used for vitrual display
-    if (UNLIKELY(!hw_block_ctx_[kHWWriteback2].is_in_use)) {
-      hw_block_id = kHWWriteback2;
-    }
+    // assume only WB2 can be used for virtual display
+    virtual_count_++;
+    hw_block_id = kHWWriteback2;
     break;
 
   default:
@@ -118,12 +133,12 @@
     return kErrorParameters;
   }
 
-  if (UNLIKELY(hw_block_id == kHWBlockMax)) {
+  if (hw_block_id == kHWBlockMax) {
     return kErrorResources;
   }
 
   DisplayResourceContext *display_resource_ctx = new DisplayResourceContext();
-  if (UNLIKELY(!display_resource_ctx)) {
+  if (!display_resource_ctx) {
     return kErrorMemory;
   }
 
@@ -132,10 +147,12 @@
   display_resource_ctx->display_attributes = attributes;
   display_resource_ctx->display_type = type;
   display_resource_ctx->hw_block_id = hw_block_id;
+  if (!display_resource_ctx->display_attributes.is_device_split)
+    display_resource_ctx->display_attributes.split_left =
+      display_resource_ctx->display_attributes.x_pixels;
 
   *display_ctx = display_resource_ctx;
-
-  return kErrorNone;
+  return error;
 }
 
 DisplayError ResManager::UnregisterDisplay(Handle display_ctx) {
@@ -143,25 +160,33 @@
                           reinterpret_cast<DisplayResourceContext *>(display_ctx);
 
   Purge(display_ctx);
-  hw_block_ctx_[display_resource_ctx->hw_block_id].is_in_use = false;
+  if (display_resource_ctx->hw_block_id == kHWWriteback2) {
+    virtual_count_--;
+    if (!virtual_count_)
+      hw_block_ctx_[display_resource_ctx->hw_block_id].is_in_use = false;
+  } else {
+    hw_block_ctx_[display_resource_ctx->hw_block_id].is_in_use = false;
+  }
+  if (!hw_block_ctx_[display_resource_ctx->hw_block_id].is_in_use)
+    ClearDedicated(display_resource_ctx->hw_block_id);
+
   delete display_resource_ctx;
 
   return kErrorNone;
 }
 
-
 DisplayError ResManager::Start(Handle display_ctx) {
   locker_.Lock();
 
   DisplayResourceContext *display_resource_ctx =
                           reinterpret_cast<DisplayResourceContext *>(display_ctx);
 
-  if (frame_start_) {
+  if (display_resource_ctx->frame_start) {
     return kErrorNone;  // keep context locked.
   }
 
   // First call in the cycle
-  frame_start_ = true;
+  display_resource_ctx->frame_start = true;
   display_resource_ctx->frame_count++;
 
   // Release the pipes not used in the previous cycle
@@ -172,6 +197,20 @@
       src_pipes_[i].state = kPipeStateIdle;
     }
   }
+
+  // Clear rotator usage
+  for (uint32_t i = 0; i < hw_res_info_.num_rotator; i++) {
+    uint32_t pipe_index;
+    pipe_index = rotators_[i].pipe_index;
+    if (rotators_[i].client_bit_mask == 0 &&
+        src_pipes_[pipe_index].state == kPipeStateToRelease &&
+        src_pipes_[pipe_index].hw_block_id == rotators_[i].writeback_id) {
+      src_pipes_[pipe_index].dedicated_hw_block = kHWBlockMax;
+      src_pipes_[pipe_index].state = kPipeStateIdle;
+    }
+    CLEAR_BIT(rotators_[i].client_bit_mask, display_resource_ctx->hw_block_id);
+  }
+
   return kErrorNone;
 }
 
@@ -191,24 +230,33 @@
   DisplayError error = kErrorNone;
   const struct HWLayersInfo &layer_info = hw_layers->info;
 
-  if (UNLIKELY(layer_info.count > num_pipe_)) {
+  if (layer_info.count > num_pipe_) {
     return kErrorResources;
   }
 
-  error = Config(display_resource_ctx, hw_layers);
-  if (UNLIKELY(error != kErrorNone)) {
+  uint32_t rotate_count = 0;
+  error = Config(display_resource_ctx, hw_layers, &rotate_count);
+  if (error != kErrorNone) {
     return error;
   }
 
-  uint32_t left_index = 0;
+  uint32_t left_index = kPipeIdMax;
   bool need_scale = false;
   HWBlockType hw_block_id = display_resource_ctx->hw_block_id;
+  HWBlockType rotator_block = kHWBlockMax;
 
   // Clear reserved marking
   for (uint32_t i = 0; i < num_pipe_; i++) {
-    src_pipes_[i].reserved = false;
+    if (src_pipes_[i].reserved_hw_block == hw_block_id)
+      src_pipes_[i].reserved_hw_block = kHWBlockMax;
   }
 
+  // allocate rotator
+  error = AcquireRotator(display_resource_ctx, rotate_count);
+  if (error != kErrorNone)
+    return error;
+
+  rotate_count = 0;
   for (uint32_t i = 0; i < layer_info.count; i++) {
     Layer &layer = layer_info.stack->layers[layer_info.index[i]];
     bool use_non_dma_pipe = hw_layers->config[i].use_non_dma_pipe;
@@ -218,28 +266,33 @@
       use_non_dma_pipe = true;
     }
 
+    AssignRotator(&hw_layers->config[i].left_rotate, &rotate_count);
+    AssignRotator(&hw_layers->config[i].right_rotate, &rotate_count);
+
     HWPipeInfo *pipe_info = &hw_layers->config[i].left_pipe;
 
-    need_scale = IsScalingNeeded(pipe_info);
-
     // Should have a generic macro
-    bool is_yuv = (layer.input_buffer->format >= kFormatYCbCr420Planar);
+    bool is_yuv = IsYuvFormat(layer.input_buffer->format);
 
-    left_index = GetPipe(hw_block_id, is_yuv, need_scale, false, use_non_dma_pipe);
-    if (left_index >= num_pipe_) {
-      goto Acquire_failed;
+    // left pipe is needed
+    if (pipe_info->pipe_id) {
+      need_scale = IsScalingNeeded(pipe_info);
+      left_index = GetPipe(hw_block_id, is_yuv, need_scale, false, use_non_dma_pipe);
+      if (left_index >= num_pipe_) {
+        goto CleanupOnError;
+      }
+      src_pipes_[left_index].reserved_hw_block = hw_block_id;
     }
 
-    src_pipes_[left_index].reserved = true;
     SetDecimationFactor(pipe_info);
 
     pipe_info =  &hw_layers->config[i].right_pipe;
     if (pipe_info->pipe_id == 0) {
       // assign single pipe
-      hw_layers->config[i].left_pipe.pipe_id = src_pipes_[left_index].mdss_pipe_id;
-      src_pipes_[left_index].at_right = false;
-      hw_layers->config[i].is_right_pipe = false;
-      src_pipes_[left_index].at_right = false;
+      if (left_index < num_pipe_) {
+        hw_layers->config[i].left_pipe.pipe_id = src_pipes_[left_index].mdss_pipe_id;
+        src_pipes_[left_index].at_right = false;
+      }
       continue;
     }
 
@@ -248,7 +301,7 @@
     uint32_t right_index;
     right_index = GetPipe(hw_block_id, is_yuv, need_scale, true, use_non_dma_pipe);
     if (right_index >= num_pipe_) {
-      goto Acquire_failed;
+      goto CleanupOnError;
     }
 
     if (src_pipes_[right_index].priority < src_pipes_[left_index].priority) {
@@ -257,25 +310,31 @@
     }
 
     // assign dual pipes
-    hw_layers->config[i].right_pipe.pipe_id = src_pipes_[right_index].mdss_pipe_id;
-    src_pipes_[right_index].reserved = true;
+    pipe_info->pipe_id = src_pipes_[right_index].mdss_pipe_id;
+    src_pipes_[right_index].reserved_hw_block = hw_block_id;
     src_pipes_[right_index].at_right = true;
-    src_pipes_[left_index].reserved = true;
+    src_pipes_[left_index].reserved_hw_block = hw_block_id;
     src_pipes_[left_index].at_right = false;
     hw_layers->config[i].left_pipe.pipe_id = src_pipes_[left_index].mdss_pipe_id;
     SetDecimationFactor(pipe_info);
+
+    DLOGV_IF(kTagResources, "Pipe acquired, layer index = %d, left_pipe = %x, right_pipe = %x",
+            i, hw_layers->config[i].left_pipe.pipe_id,  pipe_info->pipe_id);
   }
 
   if (!CheckBandwidth(display_resource_ctx, hw_layers)) {
     DLOGV_IF(kTagResources, "Bandwidth check failed!");
-    goto Acquire_failed;
+    goto CleanupOnError;
   }
 
   return kErrorNone;
 
-Acquire_failed:
-  for (uint32_t i = 0; i < num_pipe_; i++)
-    src_pipes_[i].reserved = false;
+CleanupOnError:
+  DLOGV_IF(kTagResources, "Resource reserving failed! hw_block = %d", hw_block_id);
+  for (uint32_t i = 0; i < num_pipe_; i++) {
+    if (src_pipes_[i].reserved_hw_block == hw_block_id)
+      src_pipes_[i].reserved_hw_block = kHWBlockMax;
+  }
   return kErrorResources;
 }
 
@@ -486,6 +545,7 @@
 }
 
 void ResManager::PostCommit(Handle display_ctx, HWLayers *hw_layers) {
+  SCOPE_LOCK(locker_);
   DisplayResourceContext *display_resource_ctx =
                           reinterpret_cast<DisplayResourceContext *>(display_ctx);
   HWBlockType hw_block_id = display_resource_ctx->hw_block_id;
@@ -494,23 +554,23 @@
   DLOGV_IF(kTagResources, "Resource for hw_block = %d, frame_count = %d", hw_block_id, frame_count);
 
   for (uint32_t i = 0; i < num_pipe_; i++) {
-    if (src_pipes_[i].reserved) {
+    if (src_pipes_[i].reserved_hw_block == hw_block_id) {
       src_pipes_[i].hw_block_id = hw_block_id;
       src_pipes_[i].state = kPipeStateAcquired;
       src_pipes_[i].state_frame_count = frame_count;
       DLOGV_IF(kTagResources, "Pipe acquired index = %d, type = %d, pipe_id = %x", i,
-            src_pipes_[i].type, src_pipes_[i].mdss_pipe_id);
+               src_pipes_[i].type, src_pipes_[i].mdss_pipe_id);
     } else if ((src_pipes_[i].hw_block_id == hw_block_id) &&
                (src_pipes_[i].state == kPipeStateAcquired)) {
       src_pipes_[i].state = kPipeStateToRelease;
       src_pipes_[i].state_frame_count = frame_count;
       DLOGV_IF(kTagResources, "Pipe to release index = %d, type = %d, pipe_id = %x", i,
-            src_pipes_[i].type, src_pipes_[i].mdss_pipe_id);
+               src_pipes_[i].type, src_pipes_[i].mdss_pipe_id);
     }
   }
 
   // handoff pipes which are used by splash screen
-  if (UNLIKELY((frame_count == 1) && (hw_block_id == kHWPrimary))) {
+  if ((frame_count == 1) && (hw_block_id == kHWPrimary)) {
     for (uint32_t i = 0; i < num_pipe_; i++) {
       if ((src_pipes_[i].state == kPipeStateOwnedByKernel)) {
         src_pipes_[i].state = kPipeStateToRelease;
@@ -518,8 +578,21 @@
       }
     }
   }
-
-  frame_start_ = false;
+  // set rotator pipes
+  for (uint32_t i = 0; i < hw_res_info_.num_rotator; i++) {
+    uint32_t pipe_index;
+    pipe_index = rotators_[i].pipe_index;
+    if (IS_BIT_SET(rotators_[i].client_bit_mask, hw_block_id)) {
+      src_pipes_[pipe_index].hw_block_id = rotators_[i].writeback_id;
+      src_pipes_[pipe_index].state = kPipeStateAcquired;
+    } else if (!rotators_[i].client_bit_mask) {
+      src_pipes_[pipe_index].dedicated_hw_block = kHWBlockMax;
+      if (src_pipes_[pipe_index].hw_block_id == rotators_[i].writeback_id &&
+          src_pipes_[pipe_index].state == kPipeStateAcquired)
+        src_pipes_[pipe_index].state = kPipeStateToRelease;
+    }
+  }
+  display_resource_ctx->frame_start = false;
 }
 
 void ResManager::Purge(Handle display_ctx) {
@@ -531,11 +604,11 @@
 
   for (uint32_t i = 0; i < num_pipe_; i++) {
     if (src_pipes_[i].hw_block_id == hw_block_id)
-      src_pipes_[i].state = kPipeStateIdle;
+      src_pipes_[i].ResetState();
   }
+  ClearRotator(display_resource_ctx);
 }
 
-
 uint32_t ResManager::GetMdssPipeId(PipeType type, uint32_t index) {
   uint32_t mdss_id = kPipeIdMax;
   switch (type) {
@@ -572,34 +645,19 @@
   return (1 << mdss_id);
 }
 
-uint32_t ResManager::NextPipe(PipeType type, HWBlockType hw_block_id, bool at_right) {
-  uint32_t num_pipe = 0;
+uint32_t ResManager::SearchPipe(HWBlockType hw_block_id, SourcePipe *src_pipes,
+                                uint32_t num_pipe, bool at_right) {
   uint32_t index = kPipeIdMax;
-  SourcePipe *src_pipe = NULL;
+  SourcePipe *src_pipe;
+  HWBlockType dedicated_block;
 
-  switch (type) {
-  case kPipeTypeVIG:
-    src_pipe = vig_pipes_;
-    num_pipe = hw_res_info_.num_vig_pipe;
-    break;
-  case kPipeTypeRGB:
-    src_pipe = rgb_pipes_;
-    num_pipe = hw_res_info_.num_rgb_pipe;
-    break;
-  case kPipeTypeDMA:
-  default:
-    src_pipe = dma_pipes_;
-    num_pipe = hw_res_info_.num_dma_pipe;
-    break;
-  }
-
-  // search the pipe being used
+  // search dedicated idle pipes
   for (uint32_t i = 0; i < num_pipe; i++) {
-    if (!src_pipe[i].reserved &&
-        (src_pipe[i].state == kPipeStateAcquired) &&
-        (src_pipe[i].hw_block_id == hw_block_id) &&
-        (src_pipe[i].at_right == at_right)) {
-      index = src_pipe[i].index;
+    src_pipe = &src_pipes[i];
+    if (src_pipe->reserved_hw_block == kHWBlockMax &&
+        src_pipe->state == kPipeStateIdle &&
+        src_pipe->dedicated_hw_block == hw_block_id) {
+      index = src_pipe->index;
       break;
     }
   }
@@ -609,19 +667,63 @@
     return index;
   }
 
+  // search the pipe being used
   for (uint32_t i = 0; i < num_pipe; i++) {
-    if (!src_pipe[i].reserved &&
-        ((src_pipe[i].state == kPipeStateIdle) ||
-         ((src_pipe[i].state == kPipeStateAcquired) &&
-         (src_pipe[i].hw_block_id == hw_block_id)))) {
-      index = src_pipe[i].index;
+    src_pipe = &src_pipes[i];
+    dedicated_block = src_pipe->dedicated_hw_block;
+    if (src_pipe->reserved_hw_block == kHWBlockMax &&
+        (src_pipe->state == kPipeStateAcquired) &&
+        (src_pipe->hw_block_id == hw_block_id) &&
+        (src_pipe->at_right == at_right) &&
+        (dedicated_block == hw_block_id || dedicated_block == kHWBlockMax)) {
+      index = src_pipe->index;
       break;
     }
   }
 
+  // found
+  if (index < num_pipe_) {
+    return index;
+  }
+
+  // search the pipes idle or being used but not at the same side
+  for (uint32_t i = 0; i < num_pipe; i++) {
+    src_pipe = &src_pipes[i];
+    dedicated_block = src_pipe->dedicated_hw_block;
+    if (src_pipe->reserved_hw_block == kHWBlockMax &&
+        ((src_pipe->state == kPipeStateIdle) ||
+         (src_pipe->state == kPipeStateAcquired && src_pipe->hw_block_id == hw_block_id)) &&
+         (dedicated_block == hw_block_id || dedicated_block == kHWBlockMax)) {
+      index = src_pipe->index;
+      break;
+    }
+  }
   return index;
 }
 
+uint32_t ResManager::NextPipe(PipeType type, HWBlockType hw_block_id, bool at_right) {
+  uint32_t num_pipe = 0;
+  SourcePipe *src_pipes = NULL;
+
+  switch (type) {
+  case kPipeTypeVIG:
+    src_pipes = vig_pipes_;
+    num_pipe = hw_res_info_.num_vig_pipe;
+    break;
+  case kPipeTypeRGB:
+    src_pipes = rgb_pipes_;
+    num_pipe = hw_res_info_.num_rgb_pipe;
+    break;
+  case kPipeTypeDMA:
+  default:
+    src_pipes = dma_pipes_;
+    num_pipe = hw_res_info_.num_dma_pipe;
+    break;
+  }
+
+  return SearchPipe(hw_block_id, src_pipes, num_pipe, at_right);
+}
+
 uint32_t ResManager::GetPipe(HWBlockType hw_block_id, bool is_yuv, bool need_scale, bool at_right,
                              bool use_non_dma_pipe) {
   uint32_t index = kPipeIdMax;
@@ -634,7 +736,7 @@
       index = NextPipe(kPipeTypeDMA, hw_block_id, at_right);
     }
 
-    if ((index >= num_pipe_) && (!need_scale || hw_res_info_.has_non_scalar_rgb)) {
+    if ((index >= num_pipe_) && (!need_scale || !hw_res_info_.has_non_scalar_rgb)) {
       index = NextPipe(kPipeTypeRGB, hw_block_id, at_right);
     }
 
@@ -656,6 +758,184 @@
 
 void ResManager::AppendDump(char *buffer, uint32_t length) {
   SCOPE_LOCK(locker_);
+  AppendString(buffer, length, "\nresource manager pipe state");
+  for (uint32_t i = 0; i < num_pipe_; i++) {
+    SourcePipe *src_pipe = &src_pipes_[i];
+    AppendString(buffer, length,
+                 "\nindex = %d, id = %x, reserved = %d, state = %d, at_right = %d, dedicated = %d",
+                 src_pipe->index, src_pipe->mdss_pipe_id, src_pipe->reserved_hw_block,
+                 src_pipe->state, src_pipe->at_right, src_pipe->dedicated_hw_block);
+  }
+}
+
+// This is to reserve resources for the device or rotator
+DisplayError ResManager::MarkDedicated(DisplayResourceContext *display_resource_ctx,
+                                       struct HWRotator *rotator) {
+  uint32_t num_base_pipe = 0, base_pipe_index = 0, num_vig_pipe = 0, i, vig_pipe_index = 0;
+  bool force = false;
+  SourcePipe *src_pipe = NULL;
+  HWBlockType hw_block_id;
+  if (rotator == NULL) {
+    hw_block_id = display_resource_ctx->hw_block_id;
+    switch (display_resource_ctx->display_type) {
+    case kPrimary:
+      src_pipe= rgb_pipes_;
+      if (display_resource_ctx->display_attributes.is_device_split ||
+          hw_res_info_.is_src_split) {
+        num_base_pipe = 2;
+        num_vig_pipe = 2;
+      } else {
+        num_base_pipe = 1;
+        num_vig_pipe = 1;
+      }
+      src_pipe = rgb_pipes_;
+      force = true;
+      break;
+    // HDMI and Virtual are using the same strategy
+    case kHDMI:
+    case kVirtual:
+      if (display_resource_ctx && display_resource_ctx->display_attributes.is_device_split) {
+        num_base_pipe = 2;
+        num_vig_pipe = 2;
+      } else {
+        num_base_pipe = 1;
+        num_vig_pipe = 1;
+      }
+      break;
+    default:
+      DLOGE("Wrong device type %d", display_resource_ctx->display_type);
+      break;
+    }
+  } else {
+    hw_block_id = rotator->writeback_id;
+    num_base_pipe = 1;
+    base_pipe_index = rotator->pipe_index;
+    src_pipe = &src_pipes_[base_pipe_index];
+    force = true;
+  }
+
+  if (!num_base_pipe) {
+    DLOGE("Cannot reserve dedicated pipe %d", hw_block_id);
+    return kErrorResources;
+  }
+
+  // Only search the assigned pipe type
+  if (force) {
+    for (i = 0; i < num_base_pipe; i++) {
+      if (src_pipe->dedicated_hw_block != kHWBlockMax)
+        DLOGV_IF(kTagResources, "Overwrite dedicated block %d", src_pipe->dedicated_hw_block);
+      src_pipe->dedicated_hw_block = hw_block_id;
+      src_pipe++;
+    }
+    num_base_pipe = 0;
+  } else {
+    // search available pipes
+    src_pipe = rgb_pipes_;
+    uint32_t num_pipe = hw_res_info_.num_rgb_pipe + hw_res_info_.num_vig_pipe;
+    for (i = 0; i < num_pipe; i++) {
+      if (src_pipe->dedicated_hw_block == kHWBlockMax ||
+          src_pipe->dedicated_hw_block == hw_block_id) {
+        src_pipe->dedicated_hw_block = hw_block_id;
+        num_base_pipe--;
+        if (!num_base_pipe)
+          break;
+      }
+      src_pipe++;
+    }
+    if (num_base_pipe) {
+      for (i = 0; i < num_pipe; i++) {
+        if (src_pipe->dedicated_hw_block == hw_block_id)
+          src_pipe->dedicated_hw_block = kHWBlockMax;
+        src_pipe++;
+      }
+      DLOGE("Cannot reserve dedicated pipe %d", hw_block_id);
+      return kErrorResources;
+    }
+  }
+  // optional for vig pipes
+  src_pipe= vig_pipes_;
+  for (i = 0; i < num_vig_pipe; i++) {
+    if (src_pipe->dedicated_hw_block == kHWBlockMax ||
+        src_pipe->dedicated_hw_block == hw_block_id) {
+      src_pipe->dedicated_hw_block = hw_block_id;
+      num_vig_pipe--;
+      if (!num_vig_pipe)
+        break;
+    }
+    src_pipe++;
+  }
+  return kErrorNone;
+}
+
+void ResManager::ClearDedicated(HWBlockType hw_block_id) {
+  SourcePipe *src_pipe = src_pipes_;
+  for (uint32_t i = 0; i < num_pipe_; i++) {
+    if (src_pipe->dedicated_hw_block == hw_block_id)
+      src_pipe->dedicated_hw_block = kHWBlockMax;
+  }
+}
+
+DisplayError ResManager::AcquireRotator(DisplayResourceContext *display_resource_ctx,
+                                        const uint32_t rotate_count) {
+  if (rotate_count == 0)
+    return kErrorNone;
+  if (hw_res_info_.num_rotator == 0)
+    return kErrorResources;
+
+  uint32_t i, j, pipe_index, num_rotator;
+  if (rotate_count > hw_res_info_.num_rotator)
+    num_rotator = hw_res_info_.num_rotator;
+  else
+    num_rotator = rotate_count;
+
+  for (i = 0; i < num_rotator; i++) {
+    uint32_t rotate_pipe_index = rotators_[i].pipe_index;
+    MarkDedicated(display_resource_ctx, &rotators_[i]);
+    if (src_pipes_[rotate_pipe_index].reserved_hw_block != kHWBlockMax) {
+      DLOGV_IF(kTagResources, "pipe %x is reserved by block:%d",
+               src_pipes_[rotate_pipe_index].mdss_pipe_id,
+               src_pipes_[rotate_pipe_index].reserved_hw_block);
+      return kErrorResources;
+    }
+    pipe_index = SearchPipe(rotators_[i].writeback_id, &src_pipes_[rotate_pipe_index], 1, false);
+    if (pipe_index >= num_pipe_) {
+      DLOGV_IF(kTagResources, "pipe %x is not ready for rotator",
+               src_pipes_[rotate_pipe_index].mdss_pipe_id);
+      return kErrorResources;
+    }
+  }
+
+  for (i = 0; i < num_rotator; i++)
+    SET_BIT(rotators_[i].client_bit_mask, display_resource_ctx->hw_block_id);
+
+  return kErrorNone;
+}
+
+void ResManager::AssignRotator(HWRotateInfo *rotate, uint32_t *rotate_count) {
+  if (!rotate->pipe_id)
+    return;
+  // Interleave rotator assignment
+  if ((*rotate_count & 0x1) && (hw_res_info_.num_rotator > 1)) {
+    rotate->pipe_id = src_pipes_[rotators_[1].pipe_index].mdss_pipe_id;
+    rotate->writeback_id = rotators_[1].writeback_id;
+  } else {
+    rotate->pipe_id = src_pipes_[rotators_[0].pipe_index].mdss_pipe_id;
+    rotate->writeback_id = rotators_[0].writeback_id;
+  }
+  (*rotate_count)++;
+}
+
+void ResManager::ClearRotator(DisplayResourceContext *display_resource_ctx) {
+  for (uint32_t i = 0; i < hw_res_info_.num_rotator; i++) {
+    uint32_t pipe_index;
+    pipe_index = rotators_[i].pipe_index;
+    CLEAR_BIT(rotators_[i].client_bit_mask, display_resource_ctx->hw_block_id);
+    if (rotators_[i].client_bit_mask == 0 &&
+        src_pipes_[pipe_index].dedicated_hw_block == rotators_[i].writeback_id) {
+      src_pipes_[pipe_index].dedicated_hw_block = kHWBlockMax;
+      src_pipes_[pipe_index].state = kPipeStateIdle;
+    }
+  }
 }
 
 }  // namespace sde
diff --git a/displayengine/libs/core/res_manager.h b/displayengine/libs/core/res_manager.h
index ab1c9c7..18900f3 100644
--- a/displayengine/libs/core/res_manager.h
+++ b/displayengine/libs/core/res_manager.h
@@ -39,7 +39,7 @@
   DisplayError Init(const HWResourceInfo &hw_res_info);
   DisplayError Deinit();
   DisplayError RegisterDisplay(DisplayType type, const HWDisplayAttributes &attributes,
-                              Handle *display_ctx);
+                               Handle *display_ctx);
   DisplayError UnregisterDisplay(Handle display_ctx);
   DisplayError Start(Handle display_ctx);
   DisplayError Stop(Handle display_ctx);
@@ -80,11 +80,12 @@
     kPipeStateOwnedByKernel,  // Pipe state when pipe is owned by kernel
   };
 
+  // todo: retrieve all these from kernel
   enum {
     kMaxSourcePipeWidth = 2048,
     kMaxInterfaceWidth = 2048,
-    kMaxCropWidth = 5,
-    kMaxCropHeight = 5,
+    kMaxRotateDownScaleRatio = 8,
+    kMaxNumRotator = 2,
   };
 
   struct SourcePipe {
@@ -96,11 +97,17 @@
     bool at_right;
     uint64_t state_frame_count;
     int priority;
-    bool reserved;
+    HWBlockType reserved_hw_block;
+    HWBlockType dedicated_hw_block;
 
-    SourcePipe() : type(kPipeTypeUnused), mdss_pipe_id(kPipeIdMax), index(0), state(kPipeStateIdle),
-                   hw_block_id(kHWBlockMax), at_right(false), state_frame_count(0), priority(0),
-                   reserved(false) { }
+    SourcePipe() : type(kPipeTypeUnused), mdss_pipe_id(kPipeIdMax), index(0),
+                   state(kPipeStateIdle), hw_block_id(kHWBlockMax), at_right(false),
+                   state_frame_count(0), priority(0), reserved_hw_block(kHWBlockMax),
+                   dedicated_hw_block(kHWBlockMax) { }
+
+    inline void ResetState() { state = kPipeStateIdle; hw_block_id = kHWBlockMax;
+        at_right = false; reserved_hw_block = kHWBlockMax; dedicated_hw_block = kHWBlockMax; }
+
   };
 
   struct DisplayResourceContext {
@@ -109,8 +116,10 @@
     HWBlockType hw_block_id;
     uint64_t frame_count;
     int32_t session_id;  // applicable for virtual display sessions only
-
-    DisplayResourceContext() : hw_block_id(kHWBlockMax), frame_count(0), session_id(-1) { }
+    uint32_t rotate_count;
+    bool frame_start;
+    DisplayResourceContext() : hw_block_id(kHWBlockMax), frame_count(0), session_id(-1),
+                    rotate_count(0), frame_start(false) { }
   };
 
   struct HWBlockContext {
@@ -118,25 +127,60 @@
     HWBlockContext() : is_in_use(false) { }
   };
 
+  struct HWRotator {
+    uint32_t pipe_index;
+    HWBlockType writeback_id;
+    uint32_t client_bit_mask;
+    HWRotator() : pipe_index(0), writeback_id(kHWBlockMax), client_bit_mask(0) { }
+  };
+
+  static const int kPipeIdNeedsAssignment = -1;
+
   uint32_t GetMdssPipeId(PipeType pipe_type, uint32_t index);
   uint32_t NextPipe(PipeType pipe_type, HWBlockType hw_block_id, bool at_right);
+  uint32_t SearchPipe(HWBlockType hw_block_id, SourcePipe *src_pipes, uint32_t num_pipe,
+                      bool at_right);
   uint32_t GetPipe(HWBlockType hw_block_id, bool is_yuv, bool need_scale, bool at_right,
                    bool use_non_dma_pipe);
   bool IsScalingNeeded(const HWPipeInfo *pipe_info);
-  DisplayError Config(DisplayResourceContext *display_resource_ctx, HWLayers *hw_layers);
-  bool IsValidDimension(const Layer &layer, float *width_scale, float *height_scale);
-  void CalculateCut(float *left_cut_ratio, float *top_cut_ratio, float *right_cut_ratio,
-                    float *bottom_cut_ratio, const LayerTransform &transform);
-  void CalculateCropRects(LayerRect *crop, LayerRect *dst,
-                          const LayerRect &scissor, const LayerTransform &transform);
-  bool IsNonIntegralSrcCrop(const LayerRect &crop);
-  void IntegerizeRect(LayerRect *dst_rect, const LayerRect &src_rect);
+  DisplayError Config(DisplayResourceContext *display_resource_ctx, HWLayers *hw_layers,
+                      uint32_t *rotate_count);
+  DisplayError DisplaySplitConfig(DisplayResourceContext *display_resource_ctx,
+                                  const LayerTransform &transform, const LayerRect &src_rect,
+                                  const LayerRect &dst_rect, HWLayerConfig *layer_config);
+  DisplayError ValidateScaling(const Layer &layer, const LayerRect &crop,
+                               const LayerRect &dst, float *rot_scale_x, float *rot_scale_y);
+  DisplayError SrcSplitConfig(DisplayResourceContext *display_resource_ctx,
+                              const LayerTransform &transform, const LayerRect &src_rect,
+                              const LayerRect &dst_rect, HWLayerConfig *layer_config);
+  void CalculateCut(const LayerTransform &transform, float *left_cut_ratio, float *top_cut_ratio,
+                    float *right_cut_ratio, float *bottom_cut_ratio);
+  void CalculateCropRects(const LayerRect &scissor, const LayerTransform &transform,
+                          LayerRect *crop, LayerRect *dst);
+  bool IsValidDimension(const LayerRect &src, const LayerRect &dst);
   bool CheckBandwidth(DisplayResourceContext *display_ctx, HWLayers *hw_layers);
   float GetPipeBw(DisplayResourceContext *display_ctx, HWPipeInfo *pipe, float bpp);
   float GetClockForPipe(DisplayResourceContext *display_ctx, HWPipeInfo *pipe);
   float GetOverlapBw(HWLayers *hw_layers, float *pipe_bw, bool left_mixer);
   void SetDecimationFactor(HWPipeInfo *pipe);
   float GetBpp(LayerBufferFormat format);
+  void SplitRect(bool flip_horizontal, const LayerRect &src_rect, const LayerRect &dst_rect,
+                 LayerRect *src_left, LayerRect *dst_left, LayerRect *src_right,
+                 LayerRect *dst_right);
+  bool IsMacroTileFormat(const LayerBuffer *buffer) { return buffer->flags.macro_tile; }
+  bool IsYuvFormat(LayerBufferFormat format) { return (format >= kFormatYCbCr420Planar); }
+  bool IsRotationNeeded(float rotation)
+         { return (UINT32(rotation) == 90 || UINT32(rotation) == 270); }
+  void LogRectVerbose(const char *prefix, const LayerRect &roi);
+  DisplayError MarkDedicated(DisplayResourceContext *display_resource_ctx,
+                             struct HWRotator *rotator);
+  void ClearDedicated(HWBlockType hw_block_id);
+  void RotationConfig(const LayerTransform &transform, LayerRect *src_rect,
+                      HWRotateInfo *left_rotate, HWRotateInfo *right_rotate, uint32_t *rotate_cnt);
+  DisplayError AcquireRotator(DisplayResourceContext *display_resource_ctx,
+                              const uint32_t roate_cnt);
+  void AssignRotator(HWRotateInfo *rotate, uint32_t *rotate_cnt);
+  void ClearRotator(DisplayResourceContext *display_resource_ctx);
 
   template <class T>
   inline void Swap(T &a, T &b) {
@@ -157,6 +201,8 @@
   float bw_claimed_;  // Bandwidth claimed by other display
   float clk_claimed_;  // Clock claimed by other display
   float last_primary_bw_;
+  uint32_t virtual_count_;
+  struct HWRotator rotators_[kMaxNumRotator];
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_display.cpp b/displayengine/libs/hwc/hwc_display.cpp
index 7827af2..771c07f 100644
--- a/displayengine/libs/hwc/hwc_display.cpp
+++ b/displayengine/libs/hwc/hwc_display.cpp
@@ -369,6 +369,8 @@
     return -EINVAL;
   }
 
+  int status = 0;
+
   size_t num_hw_layers = content_list->numHwLayers;
   if (num_hw_layers <= 1) {
     if (!num_hw_layers) {
@@ -401,7 +403,7 @@
   DisplayError error = display_intf_->Commit(&layer_stack_);
   if (UNLIKELY(error != kErrorNone)) {
     DLOGE("Commit failed. Error = %d", error);
-    return -EINVAL;
+    status = -EINVAL;
   }
 
   for (size_t i = 0; i < num_hw_layers; i++) {
@@ -409,7 +411,8 @@
     Layer &layer = layer_stack_.layers[i];
     LayerBuffer *layer_buffer = layer_stack_.layers[i].input_buffer;
 
-    if (layer.composition == kCompositionSDE || layer.composition == kCompositionGPUTarget) {
+    if ((status == 0) && (layer.composition == kCompositionSDE ||
+                         layer.composition == kCompositionGPUTarget)) {
       hwc_layer.releaseFenceFd = layer_buffer->release_fence_fd;
     }
 
@@ -418,7 +421,7 @@
     }
   }
 
-  return 0;
+  return status;
 }
 
 bool HWCDisplay::NeedsFrameBufferRefresh(hwc_display_contents_1_t *content_list) {
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 6336655..0661d5f 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -19,6 +19,7 @@
 #include <math.h>
 #include "hwc_mdpcomp.h"
 #include <sys/ioctl.h>
+#include <dlfcn.h>
 #include "hdmi.h"
 #include "qdMetaData.h"
 #include "mdp_version.h"
@@ -50,6 +51,12 @@
 int MDPComp::sMaxSecLayers = 1;
 bool MDPComp::enablePartialUpdateForMDP3 = false;
 bool MDPComp::sIsPartialUpdateActive = true;
+void *MDPComp::sLibPerfHint = NULL;
+int MDPComp::sPerfLockHandle = 0;
+int (*MDPComp::sPerfLockAcquire)(int, int, int*, int) = NULL;
+int (*MDPComp::sPerfLockRelease)(int value) = NULL;
+int MDPComp::sPerfHintWindow = -1;
+
 MDPComp* MDPComp::getObject(hwc_context_t *ctx, const int& dpy) {
     if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
         sSrcSplitEnabled = true;
@@ -194,6 +201,14 @@
 
     sIsPartialUpdateActive = getPartialUpdatePref(ctx);
 
+    if(property_get("persist.mdpcomp_perfhint", property, "-1") > 0) {
+        int val = atoi(property);
+        if(val > 0 && loadPerfLib()) {
+            sPerfHintWindow = val;
+            ALOGI("PerfHintWindow = %d", sPerfHintWindow);
+        }
+    }
+
     return true;
 }
 
@@ -1901,25 +1916,38 @@
     return true;
 }
 
+// Checks only if videos or single layer(RGB) is updating
+// which is used for setting dynamic fps or perf hint for single
+// layer video playback
+bool MDPComp::onlyVideosUpdating(hwc_context_t *ctx,
+                                hwc_display_contents_1_t* list) {
+    bool support = false;
+    FrameInfo frame;
+    frame.reset(mCurrentFrame.layerCount);
+    memset(&frame.drop, 0, sizeof(frame.drop));
+    frame.dropCount = 0;
+    ALOGD_IF(isDebug(), "%s: Update Cache and YUVInfo", __FUNCTION__);
+    updateLayerCache(ctx, list, frame);
+    updateYUV(ctx, list, false /*secure only*/, frame);
+    // There are only updating YUV layers or there is single RGB
+    // Layer(Youtube)
+    if((ctx->listStats[mDpy].yuvCount == frame.mdpCount) ||
+                                        (frame.layerCount == 1)) {
+        support = true;
+    }
+    return support;
+}
+
 void MDPComp::setDynRefreshRate(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
     //For primary display, set the dynamic refreshrate
     if(!mDpy && qdutils::MDPVersion::getInstance().isDynFpsSupported() &&
                                         ctx->mUseMetaDataRefreshRate) {
-        FrameInfo frame;
-        frame.reset(mCurrentFrame.layerCount);
-        memset(&frame.drop, 0, sizeof(frame.drop));
-        frame.dropCount = 0;
-        ALOGD_IF(isDebug(), "%s: Update Cache and YUVInfo for Dyn Refresh Rate",
-                 __FUNCTION__);
-        updateLayerCache(ctx, list, frame);
-        updateYUV(ctx, list, false /*secure only*/, frame);
         uint32_t refreshRate = ctx->dpyAttr[mDpy].refreshRate;
         MDPVersion& mdpHw = MDPVersion::getInstance();
         if(sIdleFallBack) {
             //Set minimum panel refresh rate during idle timeout
             refreshRate = mdpHw.getMinFpsSupported();
-        } else if((ctx->listStats[mDpy].yuvCount == frame.mdpCount) ||
-                                (frame.layerCount == 1)) {
+        } else if(onlyVideosUpdating(ctx, list)) {
             //Set the new fresh rate, if there is only one updating YUV layer
             //or there is one single RGB layer with this request
             refreshRate = ctx->listStats[mDpy].refreshRateRequest;
@@ -2037,6 +2065,7 @@
 #ifdef DYNAMIC_FPS
     setDynRefreshRate(ctx, list);
 #endif
+    setPerfHint(ctx, list);
 
     mCachedFrame.cacheAll(list);
     mCachedFrame.updateCounts(mCurrentFrame);
@@ -2823,5 +2852,66 @@
     sIsPartialUpdateActive = enable;
     return 0;
 }
+
+bool MDPComp::loadPerfLib() {
+    char perfLibPath[PROPERTY_VALUE_MAX] = {0};
+    bool success = false;
+    if((property_get("ro.vendor.extension_library", perfLibPath, NULL) <= 0)) {
+        ALOGE("vendor library not set in ro.vendor.extension_library");
+        return false;
+    }
+
+    sLibPerfHint = dlopen(perfLibPath, RTLD_NOW);
+    if(sLibPerfHint) {
+        *(void **)&sPerfLockAcquire = dlsym(sLibPerfHint, "perf_lock_acq");
+        *(void **)&sPerfLockRelease = dlsym(sLibPerfHint, "perf_lock_rel");
+        if (!sPerfLockAcquire || !sPerfLockRelease) {
+            ALOGE("Failed to load symbols for perfLock");
+            dlclose(sLibPerfHint);
+            sLibPerfHint = NULL;
+            return false;
+        }
+        success = true;
+        ALOGI("Successfully Loaded perf hint API's");
+    } else {
+        ALOGE("Failed to open %s : %s", perfLibPath, dlerror());
+    }
+    return success;
+}
+
+void MDPComp::setPerfHint(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+    if ((sPerfHintWindow < 0) || mDpy || !sLibPerfHint) {
+        return;
+    }
+    static int count = sPerfHintWindow;
+    static int perflockFlag = 0;
+
+    /* Send hint to mpctl when single layer is updated
+     * for a successful number of windows. Hint release
+     * happens immediately upon multiple layer update.
+     */
+    if (onlyVideosUpdating(ctx, list)) {
+        if(count) {
+            count--;
+        }
+    } else {
+        if (perflockFlag) {
+            perflockFlag = 0;
+            sPerfLockRelease(sPerfLockHandle);
+        }
+        count = sPerfHintWindow;
+    }
+    if (count == 0 && !perflockFlag) {
+        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 {
+            perflockFlag = 1;
+        }
+    }
+}
+
 }; //namespace
 
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 4978182..302b047 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -247,6 +247,10 @@
             hwc_display_contents_1_t* list);
     /* checks for conditions to enable partial udpate */
     bool canPartialUpdate(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+    // Checks if only videocontent is updating
+    bool onlyVideosUpdating(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+    static bool loadPerfLib();
+    void setPerfHint(hwc_context_t *ctx, hwc_display_contents_1_t* list);
 
     int mDpy;
     static bool sEnabled;
@@ -269,6 +273,12 @@
     bool allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index);
     //Enable Partial Update for MDP3 targets
     static bool enablePartialUpdateForMDP3;
+    static void *sLibPerfHint;
+    static int sPerfLockHandle;
+    static int (*sPerfLockAcquire)(int, int, int*, int);
+    static int (*sPerfLockRelease)(int value);
+    static int sPerfHintWindow;
+
 };
 
 class MDPCompNonSplit : public MDPComp {