sdm: Add support for hybrid composition

- Add interface for hybrid composition where some part
  of layer is composed by blit engine and rest by SDE.
- Use BlitEngine interface for the blit composition
- Allocate blit target buffers in Commit and use Reconfig to
  re-validate the Hybrid composition
- Add C2D as a BlitEngine to get layers composed on the blit
  target.

Change-Id: I849da73055920ab13c1a260c9511478457e6894b
diff --git a/sdm/include/core/layer_stack.h b/sdm/include/core/layer_stack.h
index 37182cc..e5b23cc 100644
--- a/sdm/include/core/layer_stack.h
+++ b/sdm/include/core/layer_stack.h
@@ -62,16 +62,32 @@
   @sa Layer
 */
 enum LayerComposition {
-  kCompositionGPU,        //!< This layer will be drawn into the target buffer by GPU. Display
-                          //!< device will mark the layer for SDE composition if it can handle it
-                          //!< or it will mark the layer for GPU composition.
+  kCompositionGPU,          //!< This layer will be drawn onto the target buffer by GPU. Display
+                            //!< device will mark the layer for GPU composition if it can not handle
+                            //!< it completely.
 
-  kCompositionSDE,        //!< This layer will be handled by SDE. It must not be composed by GPU.
+  kCompositionSDE,          //!< This layer will be handled by SDE. It must not be composed by GPU.
 
-  kCompositionGPUTarget,  //!< This layer will hold result of composition for layers marked for GPU
-                          //!< composition. If display device sets all other layers for SDE
-                          //!< composition then this layer would be ignored during Commit().
-                          //!< Only one layer shall be marked as target buffer by the caller.
+  kCompositionHybrid,       //!< This layer will be drawn by a blit engine and SDE together. Display
+                            //!< device will split the layer, update the blit rectangle that
+                            //!< need to be composed by a blit engine and update original source
+                            //!< rectangle that will be composed by SDE.
+
+  kCompositionBlit,         //!< This layer will be composed using Blit Engine
+
+  kCompositionGPUTarget,    //!< This layer will hold result of composition for layers marked for
+                            //!< GPU composition.
+                            //!< If display device does not set any layer for SDE composition then
+                            //!< this would be ignored during Commit().
+                            //!< Only one layer shall be marked as target buffer by the caller.
+                            //!< GPU target layer shall be after application layers in layer stack.
+
+  kCompositionBlitTarget,   //!< This layer will hold result of composition for blit rectangles
+                            //!< from the layers marked for hybrid composition. Nth blit rectangle
+                            //!< in a layer shall be composed onto Nth blit target.
+                            //!< If display device does not set any layer for hybrid composition
+                            //!< then this would be ignored during Commit().
+                            //!< Blit target layers shall be after GPU target layer in layer stack.
 };
 
 enum LayerColorSpace {
@@ -138,10 +154,15 @@
                                       //!< stack contains secure layers.
 
       uint32_t animating : 1;         //!< This flag shall be set by client to indicate that the
-                                      //!<  current frame is animating.
-      };
+                                      //!<  current frame is animating.i
 
-      uint32_t flags;   //!< For initialization purpose only. Client shall not refer it directly.
+      uint64_t attributes_changed : 1;
+                                      //!< This flag shall be set by client to indicate that the
+                                      //!< current frame has some properties changed and
+                                      //!< needs re-config.
+    };
+
+    uint32_t flags;   //!< For initialization purpose only. Client shall not refer it directly.
   };
 
   LayerStackFlags() : flags(0) { }
@@ -202,6 +223,11 @@
   LayerRectArray dirty_regions;     //!< Rectangular areas in the current frames that have changed
                                     //!< in comparison to previous frame.
 
+  LayerRectArray blit_regions;      //!< Rectangular areas of this layer which need to composed
+                                    //!< to blit target. Display device will update blit rectangles
+                                    //!< if a layer composition is set as hybrid. Nth blit rectangle
+                                    //!< shall be composed onto Nth blit target.
+
   LayerBlending blending;           //!< Blending operation which need to be applied on the layer
                                     //!< buffer during composition.
 
diff --git a/sdm/include/utils/constants.h b/sdm/include/utils/constants.h
index bf5a916..9ea6e70 100644
--- a/sdm/include/utils/constants.h
+++ b/sdm/include/utils/constants.h
@@ -87,6 +87,7 @@
 
   const int kThreadPriorityUrgent = -9;
   const int kMaxRotatePerLayer = 2;
+  const uint32_t kMaxBlitTargetLayers = 2;
 
   typedef void * Handle;
 
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
index 69e3ec7..d20f0b6 100644
--- a/sdm/libs/core/comp_manager.cpp
+++ b/sdm/libs/core/comp_manager.cpp
@@ -258,6 +258,29 @@
   return kErrorNone;
 }
 
+DisplayError CompManager::ReConfigure(Handle display_ctx, HWLayers *hw_layers) {
+  SCOPE_LOCK(locker_);
+
+  DisplayCompositionContext *display_comp_ctx =
+                             reinterpret_cast<DisplayCompositionContext *>(display_ctx);
+  Handle &display_resource_ctx = display_comp_ctx->display_resource_ctx;
+
+  DisplayError error = kErrorUndefined;
+  resource_intf_->Start(display_resource_ctx);
+  error = resource_intf_->Acquire(display_resource_ctx, hw_layers);
+
+  if (error != kErrorNone) {
+    DLOGE("Reconfigure failed for display = %d", display_comp_ctx->display_type);
+  }
+
+  resource_intf_->Stop(display_resource_ctx);
+  if (error != kErrorNone) {
+      error = resource_intf_->PostPrepare(display_resource_ctx, hw_layers);
+  }
+
+  return error;
+}
+
 DisplayError CompManager::PostCommit(Handle display_ctx, HWLayers *hw_layers) {
   SCOPE_LOCK(locker_);
 
diff --git a/sdm/libs/core/comp_manager.h b/sdm/libs/core/comp_manager.h
index f48beed..61e0581 100644
--- a/sdm/libs/core/comp_manager.h
+++ b/sdm/libs/core/comp_manager.h
@@ -49,6 +49,7 @@
   void PrePrepare(Handle display_ctx, HWLayers *hw_layers);
   DisplayError Prepare(Handle display_ctx, HWLayers *hw_layers);
   DisplayError PostPrepare(Handle display_ctx, HWLayers *hw_layers);
+  DisplayError ReConfigure(Handle display_ctx, HWLayers *hw_layers);
   DisplayError PostCommit(Handle display_ctx, HWLayers *hw_layers);
   void Purge(Handle display_ctx);
   bool ProcessIdleTimeout(Handle display_ctx);
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 6cda9fd..a751b20 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -214,6 +214,19 @@
 
   pending_commit_ = false;
 
+  // Layer stack attributes has changed, need to Reconfigure, currently in use for Hybrid Comp
+  if (layer_stack->flags.attributes_changed) {
+    error = comp_manager_->ReConfigure(display_comp_ctx_, &hw_layers_);
+    if (error != kErrorNone) {
+      return error;
+    }
+
+    error = hw_intf_->Validate(&hw_layers_);
+    if (error != kErrorNone) {
+        return error;
+    }
+  }
+
   if (rotator_intf_ && IsRotationRequired(&hw_layers_)) {
     error = rotator_intf_->Commit(display_rotator_ctx_, &hw_layers_);
     if (error != kErrorNone) {
@@ -563,7 +576,10 @@
   switch (composition) {
   case kCompositionGPU:         return "GPU";
   case kCompositionSDE:         return "SDE";
+  case kCompositionHybrid:      return "HYBRID";
+  case kCompositionBlit:        return "BLIT";
   case kCompositionGPUTarget:   return "GPU_TARGET";
+  case kCompositionBlitTarget:  return "BLIT_TARGET";
   default:                      return "UNKNOWN";
   }
 }
diff --git a/sdm/libs/core/strategy.cpp b/sdm/libs/core/strategy.cpp
index 183384e..f009d3a 100644
--- a/sdm/libs/core/strategy.cpp
+++ b/sdm/libs/core/strategy.cpp
@@ -128,16 +128,17 @@
     return kErrorUndefined;
   }
 
-  // Mark all layers for GPU composition. Find GPU target buffer and store its index for
+  // Mark all application layers for GPU composition. Find GPU target buffer and store its index for
   // programming the hardware.
   LayerStack *layer_stack = hw_layers_info_->stack;
   uint32_t &hw_layer_count = hw_layers_info_->count;
   hw_layer_count = 0;
+
   for (uint32_t i = 0; i < layer_stack->layer_count; i++) {
     LayerComposition &composition = layer_stack->layers[i].composition;
     if (composition == kCompositionGPUTarget) {
       hw_layers_info_->index[hw_layer_count++] = i;
-    } else {
+    } else if (composition != kCompositionBlitTarget) {
       composition = kCompositionGPU;
     }
   }
diff --git a/sdm/libs/hwc/Android.mk b/sdm/libs/hwc/Android.mk
index ed07ac3..56992d4 100644
--- a/sdm/libs/hwc/Android.mk
+++ b/sdm/libs/hwc/Android.mk
@@ -7,7 +7,9 @@
 LOCAL_C_INCLUDES              := hardware/qcom/display/sdm/include/ \
                                  hardware/qcom/display/libgralloc/ \
                                  hardware/qcom/display/libqservice/ \
-                                 hardware/qcom/display/libqdutils/
+                                 hardware/qcom/display/libqdutils/ \
+                                 hardware/qcom/display/libcopybit/
+
 LOCAL_CFLAGS                  := -Wno-missing-field-initializers -Wno-unused-parameter \
                                  -Wconversion -Wall -Werror \
                                  -DLOG_TAG=\"SDM\"
@@ -19,7 +21,7 @@
 
 LOCAL_SHARED_LIBRARIES        := libsdmcore libqservice libbinder libhardware libhardware_legacy \
                                  libutils libcutils libsync libmemalloc libqdutils libdl \
-                                 libpowermanager
+                                 libpowermanager libsdmutils
 
 LOCAL_SRC_FILES               := hwc_session.cpp \
                                  hwc_display.cpp \
@@ -29,6 +31,7 @@
                                  hwc_debugger.cpp \
                                  hwc_buffer_allocator.cpp \
                                  hwc_buffer_sync_handler.cpp \
-                                 hwc_color_manager.cpp
+                                 hwc_color_manager.cpp \
+                                 blit_engine_c2d.cpp
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/sdm/libs/hwc/blit_engine.h b/sdm/libs/hwc/blit_engine.h
new file mode 100644
index 0000000..6fa9733
--- /dev/null
+++ b/sdm/libs/hwc/blit_engine.h
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*  * Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+*  * Redistributions in binary form must reproduce the above
+*    copyright notice, this list of conditions and the following
+*    disclaimer in the documentation and/or other materials provided
+*    with the distribution.
+*  * Neither the name of The Linux Foundation nor the names of its
+*    contributors may be used to endorse or promote products derived
+*    from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*! @file blit_engine.h
+  @brief Interface file for Blit based compositior.
+
+  @details The client can use this interface to get the blit composition done
+
+*/
+
+#ifndef __BLIT_ENGINE_H__
+#define __BLIT_ENGINE_H__
+
+namespace sdm {
+
+/*! @brief Blit Engine implemented by the client
+
+  @details This class declares prototype for BlitEngine Interface which must be
+  implemented by the client. HWC will use this interface to use a Blit engine to get the
+  composition done.
+
+*/
+class BlitEngine {
+ public:
+  BlitEngine() { }
+  virtual ~BlitEngine() { }
+
+  virtual int Init() = 0;
+  virtual void DeInit() = 0;
+  virtual int Prepare(LayerStack *layer_stack) = 0;
+  virtual int PreCommit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) = 0;
+  virtual int Commit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) = 0;
+  virtual void PostCommit(LayerStack *layer_stack) = 0;
+  virtual bool BlitActive() = 0;
+  virtual void SetFrameDumpConfig(uint32_t count) = 0;
+};
+
+}  // namespace sdm
+
+#endif  // __BLIT_ENGINE_H__
diff --git a/sdm/libs/hwc/blit_engine_c2d.cpp b/sdm/libs/hwc/blit_engine_c2d.cpp
new file mode 100644
index 0000000..0fbe148
--- /dev/null
+++ b/sdm/libs/hwc/blit_engine_c2d.cpp
@@ -0,0 +1,563 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*  * Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+*  * Redistributions in binary form must reproduce the above
+*    copyright notice, this list of conditions and the following
+*    disclaimer in the documentation and/or other materials provided
+*    with the distribution.
+*  * Neither the name of The Linux Foundation nor the names of its
+*    contributors may be used to endorse or promote products derived
+*    from this software without specific prior written permission.
+*
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+* Portions formerly licensed under Apache License, Version 2.0, are re licensed
+* under section 4 of Apache License, Version 2.0.
+
+* Copyright (C) 2010 The Android Open Source Project
+
+* Not a Contribution.
+
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+
+* http://www.apache.org/licenses/LICENSE-2.0
+
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include <hardware/hardware.h>
+#include <sync/sync.h>
+#include <copybit.h>
+#include <memalloc.h>
+#include <alloc_controller.h>
+#include <gr.h>
+
+#include <utils/constants.h>
+#include <utils/rect.h>
+
+#include "blit_engine_c2d.h"
+
+#define __CLASS__ "BlitEngineC2D"
+
+namespace sdm {
+
+
+BlitEngineC2d::RegionIterator::RegionIterator(LayerRectArray rect) {
+  rect_array = rect;
+  r.end = INT(rect.count);
+  r.current = 0;
+  this->next = iterate;
+}
+
+int BlitEngineC2d::RegionIterator::iterate(copybit_region_t const *self, copybit_rect_t *rect) {
+  if (!self || !rect) {
+    DLOGE("iterate invalid parameters");
+    return 0;
+  }
+
+  RegionIterator const *me = static_cast<RegionIterator const*>(self);
+  if (me->r.current != me->r.end) {
+    rect->l = INT(me->rect_array.rect[me->r.current].left);
+    rect->t = INT(me->rect_array.rect[me->r.current].top);
+    rect->r = INT(me->rect_array.rect[me->r.current].right);
+    rect->b = INT(me->rect_array.rect[me->r.current].bottom);
+    me->r.current++;
+    return 1;
+  }
+  return 0;
+}
+
+BlitEngineC2d::BlitEngineC2d() : blit_active_(false), dump_frame_count_(0), dump_frame_index_(0) {
+  for (uint32_t i = 0; i < kNumBlitTargetBuffers; i++) {
+    blit_target_buffer_[i] = NULL;
+    release_fence_fd_[i] = -1;
+  }
+}
+
+BlitEngineC2d::~BlitEngineC2d() {
+  if (blit_engine_c2d_) {
+    copybit_close(blit_engine_c2d_);
+    blit_engine_c2d_ = NULL;
+  }
+  FreeBlitTargetBuffers();
+}
+
+int BlitEngineC2d::Init() {
+  hw_module_t const *module;
+
+  if (hw_get_module("copybit", &module) == 0) {
+    if (copybit_open(module, &blit_engine_c2d_) < 0) {
+      DLOGI("CopyBitC2D Open failed.");
+      return -1;
+    }
+    DLOGI("Opened Copybit Module");
+  } else {
+    DLOGI("Copybit HW Module not found");
+    return -1;
+  }
+
+  return 0;
+}
+
+void BlitEngineC2d::DeInit() {
+  FreeBlitTargetBuffers();
+  if (blit_engine_c2d_) {
+    copybit_close(blit_engine_c2d_);
+    blit_engine_c2d_ = NULL;
+  }
+}
+
+int BlitEngineC2d::AllocateBlitTargetBuffers(uint32_t width, uint32_t height, uint32_t format) {
+  int status = 0;
+  if (width <= 0 || height <= 0) {
+    return false;
+  }
+
+  if (blit_target_buffer_[0]) {
+    // Free and reallocate the buffers if the w/h changes
+    if (INT(width) != blit_target_buffer_[0]->width ||
+        INT(height) != blit_target_buffer_[0]->height) {
+      FreeBlitTargetBuffers();
+    }
+  }
+
+  for (uint32_t i = 0; i < kNumBlitTargetBuffers; i++) {
+    if (blit_target_buffer_[i] == NULL) {
+      status = alloc_buffer(&blit_target_buffer_[i], width, height, format,
+                         GRALLOC_USAGE_PRIVATE_IOMMU_HEAP);
+    }
+    if (status < 0) {
+      DLOGE("Allocation of Blit target Buffer failed");
+      FreeBlitTargetBuffers();
+      break;
+    }
+  }
+
+  return status;
+}
+
+void BlitEngineC2d::FreeBlitTargetBuffers() {
+  for (uint32_t i = 0; i < kNumBlitTargetBuffers; i++) {
+    private_handle_t **target_buffer = &blit_target_buffer_[i];
+    if (*target_buffer) {
+      // Free the valid fence
+      if (release_fence_fd_[i] >= 0) {
+        close(release_fence_fd_[i]);
+        release_fence_fd_[i] = -1;
+      }
+      free_buffer(*target_buffer);
+      *target_buffer = NULL;
+    }
+  }
+}
+
+int BlitEngineC2d::ClearTargetBuffer(private_handle_t* hnd, const LayerRect& rect) {
+  int status = 0;
+  copybit_rect_t clear_rect = {INT(rect.left), INT(rect.top), INT(rect.right), INT(rect.bottom)};
+
+  copybit_image_t buffer;
+  buffer.w = ALIGN((hnd->width), 32);
+  buffer.h = hnd->height;
+  buffer.format = hnd->format;
+  buffer.base = reinterpret_cast<void *>(hnd->base);
+  buffer.handle = reinterpret_cast<native_handle_t *>(hnd);
+
+  status = blit_engine_c2d_->clear(blit_engine_c2d_, &buffer, &clear_rect);
+  return status;
+}
+
+void BlitEngineC2d::PostCommit(LayerStack *layer_stack) {
+  int fence_fd = -1;
+  uint32_t count = 0;
+  int fd = -1;
+
+  for (uint32_t i = blit_target_start_index_-2; (i > 0) && (count < num_blit_target_); i--) {
+    Layer &layer = layer_stack->layers[i];
+    LayerBuffer *layer_buffer = layer.input_buffer;
+    if (layer.composition == kCompositionBlit) {
+      int index = blit_target_start_index_ + count;
+      layer_buffer->release_fence_fd = layer_stack->layers[index].input_buffer->release_fence_fd;
+      fence_fd = layer_buffer->release_fence_fd;
+      close(layer_buffer->acquire_fence_fd);
+      layer_buffer->acquire_fence_fd = -1;
+      layer_stack->layers[index].input_buffer->release_fence_fd = -1;
+      fd = layer_stack->layers[index].input_buffer->acquire_fence_fd;
+      layer_stack->layers[index].input_buffer->acquire_fence_fd = -1;
+      count++;
+    }
+  }
+
+  if (fd >= 0) {
+    // Close the C2D fence FD
+    close(fd);
+  }
+  SetReleaseFence(fence_fd);
+}
+
+// Sync wait to close the previous fd
+void BlitEngineC2d::SetReleaseFence(int fd) {
+  if (release_fence_fd_[current_blit_target_index_] >= 0) {
+    int ret = -1;
+    ret = sync_wait(release_fence_fd_[current_blit_target_index_], 1000);
+    if (ret < 0) {
+      DLOGE("sync_wait error! errno = %d, err str = %s", errno, strerror(errno));
+    }
+    close(release_fence_fd_[current_blit_target_index_]);
+  }
+  release_fence_fd_[current_blit_target_index_] = dup(fd);
+}
+
+bool BlitEngineC2d::BlitActive() {
+  return blit_active_;
+}
+
+void BlitEngineC2d::SetFrameDumpConfig(uint32_t count) {
+  dump_frame_count_ = count;
+  dump_frame_index_ = 0;
+}
+
+int BlitEngineC2d::Prepare(LayerStack *layer_stack) {
+  blit_target_start_index_ = 0;
+
+  uint32_t gpu_target_index = layer_stack->layer_count-1;
+  uint32_t i = INT(layer_stack->layer_count-1);
+
+  for (i = 0; i < layer_stack->layer_count; i++) {
+    Layer &layer = layer_stack->layers[i];
+    if (IsUBWCFormat(layer.input_buffer->format)) {
+      // UBWC is not currently supported
+      DLOGW("UBWC format found, cant support BLIT");
+      return -1;
+    }
+    if (layer.composition == kCompositionGPUTarget) {
+      // Need FBT size for allocating buffers
+      gpu_target_index = i;
+      break;
+    }
+  }
+
+  if ((layer_stack->layer_count-1) == gpu_target_index) {
+    // No blit target layer
+    return -1;
+  }
+
+  blit_target_start_index_ = ++i;
+  num_blit_target_= layer_stack->layer_count - blit_target_start_index_;
+
+  LayerBuffer *layer_buffer = layer_stack->layers[gpu_target_index].input_buffer;
+  int fbwidth = INT(layer_buffer->width);
+  int fbheight = INT(layer_buffer->height);
+  if ((fbwidth < 0) || (fbheight < 0)) {
+    return -1;
+  }
+
+  current_blit_target_index_ = (current_blit_target_index_ + 1) % kNumBlitTargetBuffers;
+  int k = blit_target_start_index_;
+
+  for (uint32_t j = 0; j < num_blit_target_; j++, k++) {
+    Layer &layer = layer_stack->layers[k];
+    LayerBuffer *layer_buffer = layer.input_buffer;
+
+    // Set the buffer height and width
+    layer_buffer->width = fbwidth;
+    layer_buffer->height = fbheight/3;
+
+    layer.plane_alpha = 0xFF;
+    layer.blending = kBlendingOpaque;
+    layer.composition = kCompositionBlitTarget;
+  }
+
+  return 0;
+}
+
+int BlitEngineC2d::PreCommit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) {
+  int status = 0;
+  uint32_t num_app_layers = (uint32_t) content_list->numHwLayers-1;
+  int target_width = 0;
+  int target_height = 0;
+  uint32_t processed_blit = 0;
+  LayerRect dst_rects[kMaxBlitTargetLayers];
+  bool blit_needed = false;
+
+  for (uint32_t i = num_app_layers-1; (i > 0) && (processed_blit < num_blit_target_); i--) {
+    Layer &layer = layer_stack->layers[i];
+    if (layer.composition != kCompositionBlit) {
+      continue;
+    }
+    blit_needed = true;
+    layer_stack->flags.attributes_changed = true;
+
+    Layer &blit_layer = layer_stack->layers[blit_target_start_index_ + processed_blit];
+    LayerRect &blit_src_rect = blit_layer.src_rect;
+    int width = INT(layer.dst_rect.right - layer.dst_rect.left);
+    int height = INT(layer.dst_rect.bottom - layer.dst_rect.top);
+    // TODO(user): FrameBuffer is assumed to be RGBA
+    AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(width, height,
+                                 INT(HAL_PIXEL_FORMAT_RGBA_8888), 0, width, height);
+
+    target_width = MAX(target_width, width);
+    target_height += height;
+
+    // Left will be zero always
+    dst_rects[processed_blit].top = FLOAT(target_height - height);
+    dst_rects[processed_blit].right = dst_rects[processed_blit].left +
+                                      (layer.dst_rect.right - layer.dst_rect.left);
+    dst_rects[processed_blit].bottom = (dst_rects[processed_blit].top +
+                                      (layer.dst_rect.bottom - layer.dst_rect.top));
+    blit_src_rect = dst_rects[processed_blit];
+    processed_blit++;
+  }
+
+  // Allocate a single buffer of RGBA8888 format
+  if (blit_needed && (AllocateBlitTargetBuffers(target_width, target_height,
+                                                HAL_PIXEL_FORMAT_RGBA_8888) < 0)) {
+      status = -1;
+      return status;
+  }
+
+  if (blit_needed) {
+    for (uint32_t j = 0; j < num_blit_target_; j++) {
+      Layer &layer = layer_stack->layers[j + content_list->numHwLayers];
+      private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
+      // Set the fd information
+      if (layer.input_buffer) {
+        layer.input_buffer->width = target_width;
+        layer.input_buffer->height = target_height;
+        layer.input_buffer->planes[0].fd = target_buffer->fd;
+        layer.input_buffer->planes[0].offset = 0;
+        layer.input_buffer->planes[0].stride = target_buffer->width;
+      }
+    }
+  }
+
+  return status;
+}
+
+int BlitEngineC2d::Commit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) {
+  int fd = -1;
+  int status = 0;
+  bool hybrid_present = false;
+  uint32_t num_app_layers = (uint32_t) content_list->numHwLayers-1;
+  private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
+  blit_active_ = false;
+
+  // if not Blit Targets return
+  for (uint32_t i = 0; i < num_app_layers; i++) {
+    Layer &layer = layer_stack->layers[i];
+    if (layer.composition == kCompositionHybrid || layer.composition == kCompositionBlit) {
+      hybrid_present = true;
+    }
+  }
+
+  if (!hybrid_present) {
+    return status;
+  }
+
+  // Clear blit target buffer
+  LayerRect clear_rect;
+  clear_rect.left =  0;
+  clear_rect.top = 0;
+  clear_rect.right = FLOAT(target_buffer->width);
+  clear_rect.bottom = FLOAT(target_buffer->height);
+  ClearTargetBuffer(target_buffer, clear_rect);
+
+  int copybit_layer_count = 0;
+  uint32_t processed_blit = 0;
+  for (uint32_t i = num_app_layers-1; (i > 0) && (processed_blit < num_blit_target_) &&
+      (status == 0); i--) {
+    Layer &layer = layer_stack->layers[i];
+    if (layer.composition != kCompositionBlit) {
+      continue;
+    }
+
+    for (uint32_t k = 0; k <= i; k++) {
+      Layer &bottom_layer = layer_stack->layers[k];
+      LayerBuffer *layer_buffer = bottom_layer.input_buffer;
+      // if layer below the blit layer does not intersect, ignore that layer
+      LayerRect inter_sect = Intersection(layer.dst_rect, bottom_layer.dst_rect);
+      if (bottom_layer.composition != kCompositionHybrid && !IsValid(inter_sect)) {
+        continue;
+      }
+      if (bottom_layer.composition == kCompositionGPU ||
+          bottom_layer.composition == kCompositionSDE ||
+          bottom_layer.composition == kCompositionGPUTarget) {
+        continue;
+      }
+
+      // For each layer marked as Hybrid, wait for acquire fence and then blit using the C2D
+      if (layer_buffer->acquire_fence_fd >= 0) {
+        // Wait for acquire fence on the App buffers.
+        if (sync_wait(layer_buffer->acquire_fence_fd, 1000) < 0) {
+          DLOGE("sync_wait error!! error no = %d err str = %s", errno, strerror(errno));
+        }
+        layer_buffer->acquire_fence_fd = -1;
+      }
+      hwc_layer_1_t *hwc_layer = &content_list->hwLayers[k];
+      LayerRect src_rect = bottom_layer.blit_regions.rect[processed_blit];
+      Layer &blit_layer = layer_stack->layers[blit_target_start_index_ + processed_blit];
+      LayerRect dest_rect = blit_layer.src_rect;
+      int ret_val = DrawRectUsingCopybit(hwc_layer, &bottom_layer, src_rect, dest_rect);
+      copybit_layer_count++;
+      if (ret_val < 0) {
+        copybit_layer_count = 0;
+        DLOGE("DrawRectUsingCopyBit failed");
+        status = -1;
+        break;
+      }
+    }
+    processed_blit++;
+  }
+
+  if (copybit_layer_count) {
+    blit_active_ = true;
+    blit_engine_c2d_->flush_get_fence(blit_engine_c2d_, &fd);
+  }
+
+  if (blit_active_) {
+    // dump the render buffer
+    DumpBlitTargetBuffer(fd);
+
+    // Set the fd to the LayerStack BlitTargets fd
+    for (uint32_t k = blit_target_start_index_; k < layer_stack->layer_count; k++) {
+      Layer &layer = layer_stack->layers[k];
+      LayerBuffer *layer_buffer = layer.input_buffer;
+      layer_buffer->acquire_fence_fd = fd;
+    }
+  }
+
+  return status;
+}
+
+int BlitEngineC2d::DrawRectUsingCopybit(hwc_layer_1_t *hwc_layer, Layer *layer,
+                                        LayerRect blit_rect, LayerRect blit_dest_Rect) {
+  private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
+  const private_handle_t *hnd = static_cast<const private_handle_t *>(hwc_layer->handle);
+  LayerBuffer *layer_buffer = layer->input_buffer;
+
+  // Set the Copybit Source
+  copybit_image_t src;
+  src.handle = const_cast<native_handle_t *>(hwc_layer->handle);
+  src.w = hnd->width;
+  src.h = hnd->height;
+  src.base = reinterpret_cast<void *>(hnd->base);
+  src.format = hnd->format;
+  src.horiz_padding = 0;
+  src.vert_padding = 0;
+
+  // Copybit source rect
+  copybit_rect_t src_rect = {INT(blit_rect.left), INT(blit_rect.top), INT(blit_rect.right),
+                            INT(blit_rect.bottom)};
+
+  // Copybit destination rect
+  copybit_rect_t dst_rect = {INT(blit_dest_Rect.left), INT(blit_dest_Rect.top),
+                            INT(blit_dest_Rect.right), INT(blit_dest_Rect.bottom)};
+
+  // Copybit destination buffer
+  copybit_image_t dst;
+  dst.handle = static_cast<native_handle_t *>(target_buffer);
+  dst.w = ALIGN(target_buffer->width, 32);
+  dst.h = ALIGN((target_buffer->height), 32);
+  dst.base = reinterpret_cast<void *>(target_buffer->base);
+  dst.format = target_buffer->format;
+
+  // Copybit region is the destRect
+  LayerRect region_rect;
+  region_rect.left = FLOAT(dst_rect.l);
+  region_rect.top = FLOAT(dst_rect.t);
+  region_rect.right = FLOAT(dst_rect.r);
+  region_rect.bottom = FLOAT(dst_rect.b);
+
+  LayerRectArray region;
+  region.count = 1;
+  region.rect  = &region_rect;
+  RegionIterator copybitRegion(region);
+  int acquireFd = layer_buffer->acquire_fence_fd;
+
+  // FRAMEBUFFER_WIDTH/HEIGHT for c2d is the target buffer w/h
+  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_FRAMEBUFFER_WIDTH,
+                                  target_buffer->width);
+  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_FRAMEBUFFER_HEIGHT,
+                                  target_buffer->height);
+  int transform = 0;
+  if (layer->transform.rotation) transform |= COPYBIT_TRANSFORM_ROT_90;
+  if (layer->transform.flip_horizontal) transform |= COPYBIT_TRANSFORM_FLIP_H;
+  if (layer->transform.flip_vertical) transform |= COPYBIT_TRANSFORM_FLIP_V;
+  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_TRANSFORM, transform);
+  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_PLANE_ALPHA, hwc_layer->planeAlpha);
+  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_BLEND_MODE, hwc_layer->blending);
+  blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_DITHER,
+    (dst.format == HAL_PIXEL_FORMAT_RGB_565) ? COPYBIT_ENABLE : COPYBIT_DISABLE);
+  blit_engine_c2d_->set_sync(blit_engine_c2d_, acquireFd);
+  int err = blit_engine_c2d_->stretch(blit_engine_c2d_, &dst, &src, &dst_rect, &src_rect,
+                                      &copybitRegion);
+
+  if (err < 0) {
+    DLOGE("copybit stretch failed");
+  }
+
+  return err;
+}
+
+bool BlitEngineC2d::IsUBWCFormat(LayerBufferFormat format) {
+  switch (format) {
+  case kFormatRGBA8888Ubwc:
+  case kFormatRGBX8888Ubwc:
+  case kFormatRGB565Ubwc:
+  case kFormatYCbCr420SPVenusUbwc:
+    return true;
+  default:
+    return false;
+  }
+}
+
+void BlitEngineC2d::DumpBlitTargetBuffer(int fd) {
+  if (!dump_frame_count_) {
+    return;
+  }
+
+  private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
+
+  if (fd >= 0) {
+    int error = sync_wait(fd, 1000);
+    if (error < 0) {
+      DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
+      return;
+    }
+  }
+
+  char dump_file_name[PATH_MAX];
+  size_t result = 0;
+  snprintf(dump_file_name, sizeof(dump_file_name), "/data/misc/display/frame_dump_primary"
+           "/blit_target_%d.raw", (dump_frame_index_));
+  FILE* fp = fopen(dump_file_name, "w+");
+  if (fp) {
+    result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp);
+    fclose(fp);
+  }
+  dump_frame_count_--;
+  dump_frame_index_++;
+}
+
+}  // namespace sdm
+
diff --git a/sdm/libs/hwc/blit_engine_c2d.h b/sdm/libs/hwc/blit_engine_c2d.h
new file mode 100644
index 0000000..4034114
--- /dev/null
+++ b/sdm/libs/hwc/blit_engine_c2d.h
@@ -0,0 +1,122 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*  * Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+*  * Redistributions in binary form must reproduce the above
+*    copyright notice, this list of conditions and the following
+*    disclaimer in the documentation and/or other materials provided
+*    with the distribution.
+*  * Neither the name of The Linux Foundation nor the names of its
+*    contributors may be used to endorse or promote products derived
+*    from this software without specific prior written permission.
+*
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+* Portions formerly licensed under Apache License, Version 2.0, are re licensed
+* under section 4 of Apache License, Version 2.0.
+
+* Copyright (C) 2010 The Android Open Source Project
+
+* Not a Contribution.
+
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+
+* http://www.apache.org/licenses/LICENSE-2.0
+
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+/*! @file blit_engine.h
+  @brief Interface file for Blit based compositior.
+
+  @details The client can use this interface to get the blit composition done
+
+*/
+
+#include <hardware/hwcomposer.h>
+#include <core/layer_stack.h>
+#include <copybit.h>
+#include "blit_engine.h"
+
+#ifndef __BLIT_ENGINE_C2D_H__
+#define __BLIT_ENGINE_C2D_H__
+
+namespace sdm {
+
+// C2D Blit implemented by the client
+// This class implements the BlitEngine Interface which is used to get the
+// Blit composition using C2D
+class BlitEngineC2d : public BlitEngine {
+ public:
+  BlitEngineC2d();
+  virtual ~BlitEngineC2d();
+
+  virtual int Init();
+  virtual void DeInit();
+  virtual int Prepare(LayerStack *layer_stack);
+  virtual int PreCommit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack);
+  virtual int Commit(hwc_display_contents_1_t *content_list, LayerStack *layer_stack);
+  virtual void PostCommit(LayerStack *layer_stack);
+  virtual bool BlitActive();
+  virtual void SetFrameDumpConfig(uint32_t count);
+
+
+ private:
+  static const uint32_t kNumBlitTargetBuffers = 3;
+
+  struct Range {
+    int current;
+    int end;
+  };
+
+  struct RegionIterator : public copybit_region_t {
+    explicit RegionIterator(LayerRectArray rect);
+   private:
+    static int iterate(copybit_region_t const *self, copybit_rect_t *rect);
+    LayerRectArray rect_array;
+    mutable Range r;
+  };
+
+  int AllocateBlitTargetBuffers(uint32_t width, uint32_t height, uint32_t format);
+  void FreeBlitTargetBuffers();
+  int ClearTargetBuffer(private_handle_t* hnd, const LayerRect& rect);
+  int DrawRectUsingCopybit(hwc_layer_1_t *hwc_layer, Layer *layer, LayerRect blit_rect,
+                           LayerRect blit_dest_Rect);
+  void SetReleaseFence(int fence_fd);
+  bool IsUBWCFormat(LayerBufferFormat format);
+  void DumpBlitTargetBuffer(int fd);
+
+  copybit_device_t *blit_engine_c2d_;
+  private_handle_t *blit_target_buffer_[kNumBlitTargetBuffers];
+  uint32_t current_blit_target_index_;
+  int release_fence_fd_[kNumBlitTargetBuffers];
+  uint32_t num_blit_target_;
+  int blit_target_start_index_;
+  bool blit_active_;
+  uint32_t dump_frame_count_;
+  uint32_t dump_frame_index_;
+};
+
+}  // namespace sdm
+
+#endif  // __BLIT_ENGINE_C2D_H__
diff --git a/sdm/libs/hwc/hwc_display.cpp b/sdm/libs/hwc/hwc_display.cpp
index 3b10d7a..7b2766c 100644
--- a/sdm/libs/hwc/hwc_display.cpp
+++ b/sdm/libs/hwc/hwc_display.cpp
@@ -37,18 +37,19 @@
 
 #include "hwc_display.h"
 #include "hwc_debugger.h"
+#include "blit_engine_c2d.h"
 
 #define __CLASS__ "HWCDisplay"
 
 namespace sdm {
 
 HWCDisplay::HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type,
-                       int id)
-  : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), display_intf_(NULL),
-    flush_(false), dump_frame_count_(0), dump_frame_index_(0),
+                       int id, bool needs_blit)
+  : core_intf_(core_intf), hwc_procs_(hwc_procs), type_(type), id_(id), needs_blit_(needs_blit),
+    display_intf_(NULL), flush_(false), dump_frame_count_(0), dump_frame_index_(0),
     dump_input_layers_(false), swap_interval_zero_(false), framebuffer_config_(NULL),
     display_paused_(false), use_metadata_refresh_rate_(false), metadata_refresh_rate_(0),
-    boot_animation_completed_(false) {
+    boot_animation_completed_(false), use_blit_comp_(false), blit_engine_(NULL) {
 }
 
 int HWCDisplay::Init() {
@@ -73,6 +74,19 @@
     return -EINVAL;
   }
 
+  if (needs_blit_) {
+    blit_engine_ = new BlitEngineC2d();
+    if (!blit_engine_) {
+      DLOGI("Create Blit Engine C2D failed");
+    } else {
+      if (blit_engine_->Init() < 0) {
+        DLOGI("Blit Engine Init failed, Blit Composition will not be used!!");
+        delete blit_engine_;
+        blit_engine_= NULL;
+      }
+    }
+  }
+
   return 0;
 }
 
@@ -90,6 +104,12 @@
 
   delete framebuffer_config_;
 
+  if (blit_engine_) {
+    blit_engine_->DeInit();
+    delete blit_engine_;
+    blit_engine_= NULL;
+  }
+
   return 0;
 }
 
@@ -231,6 +251,10 @@
   dump_frame_index_ = 0;
   dump_input_layers_ = ((bit_mask_layer_type & (1 << INPUT_LAYER_DUMP)) != 0);
 
+  if (blit_engine_) {
+    blit_engine_->SetFrameDumpConfig(count);
+  }
+
   DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
 }
 
@@ -261,13 +285,25 @@
   }
 
   size_t num_hw_layers = content_list->numHwLayers;
+  uint32_t blit_target_count = 0;
+
+  if (needs_blit_ && blit_engine_) {
+    blit_target_count = kMaxBlitTargetLayers;
+  }
 
   // Allocate memory for a) total number of layers b) buffer handle for each layer c) number of
   // visible rectangles in each layer d) dirty rectangle for each layer
-  size_t required_size = num_hw_layers * (sizeof(Layer) + sizeof(LayerBuffer));
-  for (size_t i = 0; i < num_hw_layers; i++) {
-    // visible rectangles + 1 dirty rectangle
-    size_t num_rects = content_list->hwLayers[i].visibleRegionScreen.numRects + 1;
+  size_t required_size = (num_hw_layers + blit_target_count) *
+                         (sizeof(Layer) + sizeof(LayerBuffer));
+
+  for (size_t i = 0; i < num_hw_layers + blit_target_count; i++) {
+    uint32_t num_visible_rects = 1;
+    if (i < num_hw_layers) {
+      num_visible_rects = INT32(content_list->hwLayers[i].visibleRegionScreen.numRects);
+    }
+
+    // visible rectangles + 1 dirty rectangle + blit rectangle
+    size_t num_rects = num_visible_rects + 1 + blit_target_count;
     required_size += num_rects * sizeof(LayerRect);
   }
 
@@ -281,7 +317,6 @@
 
     // Allocate in multiple of kSizeSteps.
     required_size = ROUND_UP(required_size, layer_stack_memory_.kSizeSteps);
-
     layer_stack_memory_.raw = new uint8_t[required_size];
     if (!layer_stack_memory_.raw) {
       return -ENOMEM;
@@ -296,11 +331,16 @@
   // Layer array address
   layer_stack_ = LayerStack();
   layer_stack_.layers = reinterpret_cast<Layer *>(current_address);
-  layer_stack_.layer_count = static_cast<uint32_t>(num_hw_layers);
-  current_address += num_hw_layers * sizeof(Layer);
+  layer_stack_.layer_count = INT32(num_hw_layers + blit_target_count);
+  current_address += (num_hw_layers + blit_target_count) * sizeof(Layer);
 
-  for (size_t i = 0; i < num_hw_layers; i++) {
-    hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
+  for (size_t i = 0; i < num_hw_layers + blit_target_count; i++) {
+    uint32_t num_visible_rects = 1;
+    if (i < num_hw_layers) {
+      num_visible_rects =
+        static_cast<uint32_t>(content_list->hwLayers[i].visibleRegionScreen.numRects);
+    }
+
     Layer &layer = layer_stack_.layers[i];
     layer = Layer();
 
@@ -311,17 +351,25 @@
 
     // Visible rectangle address
     layer.visible_regions.rect = reinterpret_cast<LayerRect *>(current_address);
-    layer.visible_regions.count = static_cast<uint32_t>(hwc_layer.visibleRegionScreen.numRects);
+    layer.visible_regions.count = num_visible_rects;
     for (size_t i = 0; i < layer.visible_regions.count; i++) {
-      *layer.visible_regions.rect = LayerRect();
+      layer.visible_regions.rect[i] = LayerRect();
     }
-    current_address += hwc_layer.visibleRegionScreen.numRects * sizeof(LayerRect);
+    current_address += num_visible_rects * sizeof(LayerRect);
 
     // Dirty rectangle address
     layer.dirty_regions.rect = reinterpret_cast<LayerRect *>(current_address);
     layer.dirty_regions.count = 1;
     *layer.dirty_regions.rect = LayerRect();
     current_address += sizeof(LayerRect);
+
+    // Blit rectangle address
+    layer.blit_regions.rect = reinterpret_cast<LayerRect *>(current_address);
+    layer.blit_regions.count = blit_target_count;
+    for (size_t i = 0; i < layer.blit_regions.count; i++) {
+      layer.blit_regions.rect[i] = LayerRect();
+    }
+    current_address += layer.blit_regions.count * sizeof(LayerRect);
   }
 
   return 0;
@@ -422,6 +470,7 @@
   int ret;
 
   display_intf_->GetConfig(active_config_index, &active_config);
+  use_blit_comp_ = false;
 
   // Configure each layer
   for (size_t i = 0; i < num_hw_layers; i++) {
@@ -474,6 +523,18 @@
     }
   }
 
+  // Prepare the Blit Target
+  if (blit_engine_) {
+    int ret = blit_engine_->Prepare(&layer_stack_);
+    if (ret) {
+      // Blit engine cannot handle this layer stack, hence set the layer stack
+      // count to num_hw_layers
+      layer_stack_.layer_count -= kMaxBlitTargetLayers;
+    } else {
+      use_blit_comp_ = true;
+    }
+  }
+
   // Configure layer stack
   layer_stack_.flags.geometry_changed = ((content_list->flags & HWC_GEOMETRY_CHANGED) > 0);
 
@@ -497,7 +558,8 @@
     Layer &layer = layer_stack_.layers[i];
     LayerComposition composition = layer.composition;
 
-    if (composition == kCompositionSDE) {
+    if ((composition == kCompositionSDE) || (composition == kCompositionHybrid) ||
+        (composition == kCompositionBlit)) {
       hwc_layer.hints |= HWC_HINT_CLEAR_FB;
 
       if (use_metadata_refresh_rate_ && layer.frame_rate > metadata_refresh_rate_) {
@@ -537,10 +599,23 @@
       CommitLayerParams(&content_list->hwLayers[i], &layer_stack_.layers[i]);
     }
 
-    DisplayError error = display_intf_->Commit(&layer_stack_);
+    if (use_blit_comp_) {
+      status = blit_engine_->PreCommit(content_list, &layer_stack_);
+      if (status == 0) {
+        status = blit_engine_->Commit(content_list, &layer_stack_);
+        if (status != 0) {
+          DLOGE("Blit Comp Failed!");
+        }
+      }
+    }
+
+    DisplayError error = kErrorUndefined;
+    if (status == 0) {
+      error = display_intf_->Commit(&layer_stack_);
+      status = 0;
+    }
     if (error != kErrorNone) {
       DLOGE("Commit failed. Error = %d", error);
-
       // To prevent surfaceflinger infinite wait, flush the previous frame during Commit() so that
       // previous buffer and fences are released, and override the error.
       flush_ = true;
@@ -561,6 +636,11 @@
     }
   }
 
+  // Set the release fence fd to the blit engine
+  if (use_blit_comp_ && blit_engine_->BlitActive()) {
+    blit_engine_->PostCommit(&layer_stack_);
+  }
+
   for (size_t i = 0; i < num_hw_layers; i++) {
     hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
     Layer &layer = layer_stack_.layers[i];
@@ -595,7 +675,6 @@
     }
   }
 
-
   if (!flush_) {
     layer_stack_cache_.animating = layer_stack_.flags.animating;
 
@@ -663,7 +742,8 @@
   for (uint32_t i = 0; i < layer_count; i++) {
     Layer &layer = layer_stack_.layers[i];
 
-    if (layer.composition == kCompositionGPUTarget) {
+    if (layer.composition == kCompositionGPUTarget ||
+        layer.composition == kCompositionBlitTarget) {
       continue;
     }
 
@@ -691,15 +771,15 @@
 void HWCDisplay::SetComposition(const int32_t &source, LayerComposition *target) {
   switch (source) {
   case HWC_FRAMEBUFFER_TARGET:  *target = kCompositionGPUTarget;  break;
-  default:                      *target = kCompositionSDE;        break;
+  default:                      *target = kCompositionGPU;        break;
   }
 }
 
 void HWCDisplay::SetComposition(const int32_t &source, int32_t *target) {
   switch (source) {
   case kCompositionGPUTarget:   *target = HWC_FRAMEBUFFER_TARGET; break;
-  case kCompositionSDE:         *target = HWC_OVERLAY;            break;
-  default:                      *target = HWC_FRAMEBUFFER;        break;
+  case kCompositionGPU:         *target = HWC_FRAMEBUFFER;        break;
+  default:                      *target = HWC_OVERLAY;            break;
   }
 }
 
diff --git a/sdm/libs/hwc/hwc_display.h b/sdm/libs/hwc/hwc_display.h
index 7df23dc..8882613 100644
--- a/sdm/libs/hwc/hwc_display.h
+++ b/sdm/libs/hwc/hwc_display.h
@@ -32,6 +32,8 @@
 
 namespace sdm {
 
+class BlitEngine;
+
 class HWCDisplay : public DisplayEventHandler {
  public:
   virtual int Init();
@@ -93,7 +95,8 @@
     LayerStackCache() : layer_count(0), animating(false) { }
   };
 
-  HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type, int id);
+  HWCDisplay(CoreInterface *core_intf, hwc_procs_t const **hwc_procs, DisplayType type, int id,
+             bool needs_blit);
 
   // DisplayEventHandler methods
   virtual DisplayError VSync(const DisplayEventVSync &vsync);
@@ -130,6 +133,7 @@
   hwc_procs_t const **hwc_procs_;
   DisplayType type_;
   int id_;
+  bool needs_blit_;
   DisplayInterface *display_intf_;
   LayerStackMemory layer_stack_memory_;
   LayerStack layer_stack_;
@@ -152,6 +156,8 @@
   bool NeedsFrameBufferRefresh(hwc_display_contents_1_t *content_list);
   int PrepareLayerParams(hwc_layer_1_t *hwc_layer, Layer *layer, uint32_t fps);
   void CommitLayerParams(hwc_layer_1_t *hwc_layer, Layer *layer);
+  bool use_blit_comp_;
+  BlitEngine *blit_engine_;
 };
 
 inline int HWCDisplay::Perform(uint32_t operation, ...) {
diff --git a/sdm/libs/hwc/hwc_display_external.cpp b/sdm/libs/hwc/hwc_display_external.cpp
index c3a07e7..d40602e 100644
--- a/sdm/libs/hwc/hwc_display_external.cpp
+++ b/sdm/libs/hwc/hwc_display_external.cpp
@@ -91,7 +91,7 @@
 }
 
 HWCDisplayExternal::HWCDisplayExternal(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
-  : HWCDisplay(core_intf, hwc_procs, kHDMI, HWC_DISPLAY_EXTERNAL) {
+  : HWCDisplay(core_intf, hwc_procs, kHDMI, HWC_DISPLAY_EXTERNAL, false) {
 }
 
 int HWCDisplayExternal::Prepare(hwc_display_contents_1_t *content_list) {
diff --git a/sdm/libs/hwc/hwc_display_primary.cpp b/sdm/libs/hwc/hwc_display_primary.cpp
index 79deb25..8ac8389 100644
--- a/sdm/libs/hwc/hwc_display_primary.cpp
+++ b/sdm/libs/hwc/hwc_display_primary.cpp
@@ -84,7 +84,7 @@
 }
 
 HWCDisplayPrimary::HWCDisplayPrimary(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
-  : HWCDisplay(core_intf, hwc_procs, kPrimary, HWC_DISPLAY_PRIMARY) {
+  : HWCDisplay(core_intf, hwc_procs, kPrimary, HWC_DISPLAY_PRIMARY, true) {
 }
 
 void HWCDisplayPrimary::ProcessBootAnimCompleted() {
diff --git a/sdm/libs/hwc/hwc_display_virtual.cpp b/sdm/libs/hwc/hwc_display_virtual.cpp
index 319c0ee..15da858 100644
--- a/sdm/libs/hwc/hwc_display_virtual.cpp
+++ b/sdm/libs/hwc/hwc_display_virtual.cpp
@@ -98,7 +98,7 @@
 }
 
 HWCDisplayVirtual::HWCDisplayVirtual(CoreInterface *core_intf, hwc_procs_t const **hwc_procs)
-  : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL),
+  : HWCDisplay(core_intf, hwc_procs, kVirtual, HWC_DISPLAY_VIRTUAL, false),
     dump_output_layer_(false), output_buffer_(NULL) {
 }