display: Add support for MDP Composition

This change
   1) implements MDP Composition upto 3 layers
   2) adds invalidator support to fall back to FB
      composition during idle screen condition.

Change-Id: I55f27321fd0df096b353d66aaad1cc720cd4b84b
Acked-by: Jeykumar Sankaran <jsanka@codeaurora.org>
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index 9808aa5..05d033e 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -11,5 +11,6 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
 LOCAL_SRC_FILES               :=  hwc.cpp hwc_video.cpp hwc_utils.cpp \
                                   hwc_uimirror.cpp hwc_external.cpp \
-                                  hwc_uevents.cpp hwc_copybit.cpp
+                                  hwc_uevents.cpp hwc_copybit.cpp \
+                                  hwc_mdpcomp.cpp
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index ba87f90..c28cf03 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -30,6 +30,7 @@
 #include "hwc_uimirror.h"
 #include "hwc_copybit.h"
 #include "hwc_external.h"
+#include "hwc_mdpcomp.h"
 
 using namespace qhwc;
 
@@ -85,6 +86,8 @@
             //Nothing here
         } else if(UIMirrorOverlay::prepare(ctx, list)) {
             ctx->overlayInUse = true;
+        } else if(MDPComp::configure(dev, list)) {
+            ctx->overlayInUse = true;
         } else if (0) {
             //Other features
             ctx->overlayInUse = true;
@@ -153,6 +156,7 @@
     if (LIKELY(list)) {
         VideoOverlay::draw(ctx, list);
         CopyBit::draw(ctx, list, (EGLDisplay)dpy, (EGLSurface)sur);
+        MDPComp::draw(ctx, list);
         EGLBoolean sucess = eglSwapBuffers((EGLDisplay)dpy, (EGLSurface)sur);
         UIMirrorOverlay::draw(ctx);
         if(ctx->mExtDisplay->getExternalDisplay())
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
new file mode 100755
index 0000000..8107400
--- /dev/null
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -0,0 +1,829 @@
+/*
+ * Copyright (C) 2012, Code Aurora Forum. All rights reserved.
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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 "hwc_mdpcomp.h"
+#include "hwc_qbuf.h"
+#include "hwc_external.h"
+
+#define SUPPORT_4LAYER 0
+
+namespace qhwc {
+
+/****** Class PipeMgr ***********/
+
+void inline PipeMgr::reset() {
+    mVGPipes = MAX_VG;
+    mVGUsed = 0;
+    mVGIndex = 0;
+    mRGBPipes = MAX_RGB;
+    mRGBUsed = 0;
+    mRGBIndex = MAX_VG;
+    mTotalAvail = mVGPipes + mRGBPipes;
+    memset(&mStatus, 0x0 , sizeof(int)*mTotalAvail);
+}
+
+int PipeMgr::req_for_pipe(int pipe_req) {
+
+    switch(pipe_req) {
+        case PIPE_REQ_VG: //VG
+            if(mVGPipes){
+                mVGPipes--;
+                mVGUsed++;
+                mTotalAvail--;
+                return PIPE_REQ_VG;
+            }
+        case PIPE_REQ_RGB: // RGB
+            if(mRGBPipes) {
+                mRGBPipes--;
+                mRGBUsed++;
+                mTotalAvail--;
+                return PIPE_REQ_RGB;
+            }
+            return PIPE_NONE;
+        case PIPE_REQ_FB: //FB
+            if(mRGBPipes) {
+               mRGBPipes--;
+               mRGBUsed++;
+               mTotalAvail--;
+               mStatus[VAR_INDEX] = PIPE_IN_FB_MODE;
+               return PIPE_REQ_FB;
+           }
+        default:
+            break;
+    };
+    return PIPE_NONE;
+}
+
+int PipeMgr::assign_pipe(int pipe_pref) {
+    switch(pipe_pref) {
+        case PIPE_REQ_VG: //VG
+            if(mVGUsed) {
+                mVGUsed--;
+                mStatus[mVGIndex] = PIPE_IN_COMP_MODE;
+                return mVGIndex++;
+            }
+        case PIPE_REQ_RGB: //RGB
+            if(mRGBUsed) {
+                mRGBUsed--;
+                mStatus[mRGBIndex] = PIPE_IN_COMP_MODE;
+                return mRGBIndex++;
+            }
+        default:
+            ALOGE("%s: PipeMgr:invalid case in pipe_mgr_assign",
+                                                       __FUNCTION__);
+            return -1;
+    };
+}
+
+/****** Class MDPComp ***********/
+
+MDPComp::State MDPComp::sMDPCompState = MDPCOMP_OFF;
+struct MDPComp::frame_info MDPComp::sCurrentFrame;
+PipeMgr MDPComp::sPipeMgr;
+IdleInvalidator *MDPComp::idleInvalidator = NULL;
+bool MDPComp::sIdleFallBack = false;
+bool MDPComp::sDebugLogs = false;
+int MDPComp::sSkipCount = 0;
+int MDPComp::sMaxLayers = 0;
+
+bool MDPComp::deinit() {
+    //XXX: Tear down MDP comp state
+    return true;
+}
+
+void MDPComp::timeout_handler(void *udata) {
+    struct hwc_context_t* ctx = (struct hwc_context_t*)(udata);
+
+    if(!ctx) {
+        ALOGE("%s: received empty data in timer callback", __FUNCTION__);
+        return;
+    }
+
+    hwc_procs* proc = (hwc_procs*)ctx->device.reserved_proc[0];
+
+    if(!proc) {
+        ALOGE("%s: HWC proc not registered", __FUNCTION__);
+        return;
+    }
+    sIdleFallBack = true;
+    /* Trigger SF to redraw the current frame */
+    proc->invalidate(proc);
+}
+
+void MDPComp::reset( hwc_context_t *ctx, hwc_layer_list_t* list ) {
+    sCurrentFrame.count = 0;
+    free(sCurrentFrame.pipe_layer);
+    sCurrentFrame.pipe_layer = NULL;
+
+    //Reset MDP pipes
+    sPipeMgr.reset();
+    sPipeMgr.setStatus(VAR_INDEX, PIPE_IN_FB_MODE);
+
+#if SUPPORT_4LAYER
+    configure_var_pipe(ctx);
+#endif
+
+    //Reset flags and states
+    unsetMDPCompLayerFlags(ctx, list);
+    if(sMDPCompState == MDPCOMP_ON) {
+        sMDPCompState = MDPCOMP_OFF_PENDING;
+    }
+}
+
+void MDPComp::setLayerIndex(hwc_layer_t* layer, const int pipe_index)
+{
+    layer->flags &= ~HWC_MDPCOMP_INDEX_MASK;
+    layer->flags |= pipe_index << MDPCOMP_INDEX_OFFSET;
+}
+
+int MDPComp::getLayerIndex(hwc_layer_t* layer)
+{
+    int byp_index = -1;
+
+    if(layer->flags & HWC_MDPCOMP) {
+        byp_index = ((layer->flags & HWC_MDPCOMP_INDEX_MASK) >>
+                                               MDPCOMP_INDEX_OFFSET);
+        byp_index = (byp_index < sMaxLayers ? byp_index : -1 );
+    }
+    return byp_index;
+}
+void MDPComp::print_info(hwc_layer_t* layer)
+{
+     hwc_rect_t sourceCrop = layer->sourceCrop;
+     hwc_rect_t displayFrame = layer->displayFrame;
+
+     int s_l = sourceCrop.left;
+     int s_t = sourceCrop.top;
+     int s_r = sourceCrop.right;
+     int s_b = sourceCrop.bottom;
+
+     int d_l = displayFrame.left;
+     int d_t = displayFrame.top;
+     int d_r = displayFrame.right;
+     int d_b = displayFrame.bottom;
+
+     ALOGD_IF(isDebug(), "src:[%d,%d,%d,%d] (%d x %d) \
+                             dst:[%d,%d,%d,%d] (%d x %d)",
+                             s_l, s_t, s_r, s_b, (s_r - s_l), (s_b - s_t),
+                             d_l, d_t, d_r, d_b, (d_r - d_l), (d_b - d_t));
+}
+/*
+ * Configures pipe(s) for MDP composition
+ */
+int MDPComp::prepare(hwc_context_t *ctx, hwc_layer_t *layer,
+                                            mdp_pipe_info& mdp_info) {
+
+    int nPipeIndex = mdp_info.index;
+
+    if (ctx) {
+
+        private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+        overlay::Overlay& ov = *(ctx->mOverlay);
+
+        if(!hnd) {
+            ALOGE("%s: layer handle is NULL", __FUNCTION__);
+            return -1;
+        }
+
+
+        int hw_w = ctx->mFbDev->width;
+        int hw_h = ctx->mFbDev->height;
+
+
+        hwc_rect_t sourceCrop = layer->sourceCrop;
+        hwc_rect_t displayFrame = layer->displayFrame;
+
+        const int src_w = sourceCrop.right - sourceCrop.left;
+        const int src_h = sourceCrop.bottom - sourceCrop.top;
+
+        hwc_rect_t crop = sourceCrop;
+        int crop_w = crop.right - crop.left;
+        int crop_h = crop.bottom - crop.top;
+
+        hwc_rect_t dst = displayFrame;
+        int dst_w = dst.right - dst.left;
+        int dst_h = dst.bottom - dst.top;
+
+        //REDUNDANT ??
+        if(hnd != NULL &&
+               (hnd->flags & private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM )) {
+            ALOGE("%s: failed due to non-pmem memory",__FUNCTION__);
+            return -1;
+        }
+
+        if(dst.left < 0 || dst.top < 0 ||
+               dst.right > hw_w || dst.bottom > hw_h) {
+            ALOGD_IF(isDebug(),"%s: Destination has negative coordinates",
+                                                                  __FUNCTION__);
+
+            qhwc::calculate_crop_rects(crop, dst, hw_w, hw_h);
+
+            //Update calulated width and height
+            crop_w = crop.right - crop.left;
+            crop_h = crop.bottom - crop.top;
+
+            dst_w = dst.right - dst.left;
+            dst_h = dst.bottom - dst.top;
+        }
+
+        if( (dst_w > hw_w)|| (dst_h > hw_h)) {
+            ALOGD_IF(isDebug(),"%s: Dest rect exceeds FB", __FUNCTION__);
+            print_info(layer);
+            dst_w = hw_w;
+            dst_h = hw_h;
+        }
+
+        // Determine pipe to set based on pipe index
+        ovutils::eDest dest = ovutils::OV_PIPE_ALL;
+        if (nPipeIndex == 0) {
+            dest = ovutils::OV_PIPE0;
+        } else if (nPipeIndex == 1) {
+            dest = ovutils::OV_PIPE1;
+        } else if (nPipeIndex == 2) {
+            dest = ovutils::OV_PIPE2;
+        }
+
+        ovutils::eZorder zOrder = ovutils::ZORDER_0;
+
+        if(mdp_info.z_order == 0 ) {
+            zOrder = ovutils::ZORDER_0;
+        } else if(mdp_info.z_order == 1 ) {
+            zOrder = ovutils::ZORDER_1;
+        } else if(mdp_info.z_order == 2 ) {
+            zOrder = ovutils::ZORDER_2;
+        }
+
+        // Order order order
+        // setSource - just setting source
+        // setParameter - changes src w/h/f accordingly
+        // setCrop - ROI - src_rect
+        // setPosition - dst_rect
+        // commit - commit changes to mdp driver
+        // queueBuffer - not here, happens when draw is called
+
+        ovutils::eTransform orient =
+            static_cast<ovutils::eTransform>(layer->transform);
+
+        ov.setTransform(orient, dest);
+        ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
+        ovutils::eMdpFlags mdpFlags = mdp_info.isVG ? ovutils::OV_MDP_PIPE_SHARE
+                                                   : ovutils::OV_MDP_FLAGS_NONE;
+        ovutils::eIsFg isFG = mdp_info.isFG ? ovutils::IS_FG_SET
+                                                           : ovutils::IS_FG_OFF;
+        ovutils::PipeArgs parg(mdpFlags,
+                               info,
+                               zOrder,
+                               isFG,
+                               ovutils::ROT_FLAG_DISABLED);
+
+        ovutils::PipeArgs pargs[MAX_PIPES] = { parg, parg, parg };
+        if (!ov.setSource(pargs, dest)) {
+            ALOGE("%s: setSource failed", __FUNCTION__);
+            return -1;
+        }
+
+        ovutils::Dim dcrop(crop.left, crop.top, crop_w, crop_h);
+        if (!ov.setCrop(dcrop, dest)) {
+            ALOGE("%s: setCrop failed", __FUNCTION__);
+            return -1;
+        }
+
+        ovutils::Dim dim(dst.left, dst.top, dst_w, dst_h);
+        if (!ov.setPosition(dim, dest)) {
+            ALOGE("%s: setPosition failed", __FUNCTION__);
+            return -1;
+        }
+
+        ALOGD_IF(isDebug(),"%s: MDP set: crop[%d,%d,%d,%d] dst[%d,%d,%d,%d] \
+                       nPipe: %d isFG: %d zorder: %d",__FUNCTION__, dcrop.x,
+                       dcrop.y,dcrop.w, dcrop.h, dim.x, dim.y, dim.w, dim.h,
+                       nPipeIndex,mdp_info.isFG, mdp_info.z_order);
+
+        if (!ov.commit(dest)) {
+            ALOGE("%s: commit failed", __FUNCTION__);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/*
+ * MDPComp not possible when
+ * 1. We have more than sMaxLayers
+ * 2. External display connected
+ * 3. Composition is triggered by
+ *    Idle timer expiry
+ * 4. Rotation is  needed
+ * 5. Overlay in use
+ */
+
+bool MDPComp::is_doable(hwc_composer_device_t *dev,
+                                                const hwc_layer_list_t* list) {
+    hwc_context_t* ctx = (hwc_context_t*)(dev);
+
+    if(!ctx) {
+        ALOGE("%s: hwc context is NULL", __FUNCTION__);
+        return false;
+    }
+
+    //Number of layers
+    if(list->numHwLayers < 1 || list->numHwLayers > sMaxLayers) {
+        ALOGD_IF(isDebug(), "%s: Unsupported number of layers",__FUNCTION__);
+        return false;
+    }
+
+    //Disable MDPComp when ext display connected
+    if(ctx->mExtDisplay->getExternalDisplay()) {
+        ALOGD_IF(isDebug(), "%s: External display connected.", __FUNCTION__);
+    }
+
+    //FB composition on idle timeout
+    if(sIdleFallBack) {
+        ALOGD_IF(isDebug(), "%s: idle fallback",__FUNCTION__);
+        return false;
+    }
+
+    //MDP composition is not efficient if rotation is needed.
+    for(unsigned int i = 0; i < list->numHwLayers; ++i) {
+        if(list->hwLayers[i].transform) {
+                ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__);
+                return false;
+        }
+    }
+
+    return true;
+}
+
+void MDPComp::setMDPCompLayerFlags(hwc_layer_list_t* list) {
+
+    for(int index = 0 ; index < sCurrentFrame.count; index++ )
+    {
+        int layer_index = sCurrentFrame.pipe_layer[index].layer_index;
+        if(layer_index >= 0) {
+            hwc_layer_t* layer = &(list->hwLayers[layer_index]);
+
+            layer->flags |= HWC_MDPCOMP;
+            layer->compositionType = HWC_OVERLAY;
+            layer->hints |= HWC_HINT_CLEAR_FB;
+        }
+    }
+}
+
+void MDPComp::get_layer_info(hwc_layer_t* layer, int& flags) {
+
+    private_handle_t* hnd = (private_handle_t*)layer->handle;
+
+    if(layer->flags & HWC_SKIP_LAYER) {
+        flags |= MDPCOMP_LAYER_SKIP;
+    } else if(hnd != NULL &&
+        (hnd->flags & private_handle_t::PRIV_FLAGS_NONCONTIGUOUS_MEM )) {
+        flags |= MDPCOMP_LAYER_UNSUPPORTED_MEM;
+    }
+
+    if(layer->blending != HWC_BLENDING_NONE)
+        flags |= MDPCOMP_LAYER_BLEND;
+
+    int dst_w, dst_h;
+    getLayerResolution(layer, dst_w, dst_h);
+
+    hwc_rect_t sourceCrop = layer->sourceCrop;
+    const int src_w = sourceCrop.right - sourceCrop.left;
+    const int src_h = sourceCrop.bottom - sourceCrop.top;
+    if(((src_w > dst_w) || (src_h > dst_h))) {
+        flags |= MDPCOMP_LAYER_DOWNSCALE;
+    }
+}
+
+int MDPComp::mark_layers(hwc_layer_list_t* list, layer_mdp_info* layer_info,
+                                                    frame_info& current_frame) {
+
+    int layer_count = list->numHwLayers;
+
+    if(layer_count > sMaxLayers) {
+        if(!sPipeMgr.req_for_pipe(PIPE_REQ_FB)) {
+            ALOGE("%s: binding var pipe to FB failed!!", __FUNCTION__);
+            return 0;
+        }
+    }
+
+    //Parse layers from higher z-order
+    for(int index = layer_count - 1 ; index >= 0; index-- ) {
+        hwc_layer_t* layer = &list->hwLayers[index];
+
+        int layer_prop = 0;
+        get_layer_info(layer, layer_prop);
+
+        ALOGD_IF(isDebug(),"%s: prop for layer [%d]: %x", __FUNCTION__,
+                                                             index, layer_prop);
+
+        //Both in cases of NON-CONTIGUOUS memory or SKIP layer,
+        //current version of mdp composition falls back completely to FB
+        //composition.
+        //TO DO: Support dual mode composition
+
+        if(layer_prop & MDPCOMP_LAYER_UNSUPPORTED_MEM) {
+            ALOGD_IF(isDebug(), "%s: Non contigous memory",__FUNCTION__);
+            return MDPCOMP_ABORT;
+        }
+
+        if(layer_prop & MDPCOMP_LAYER_SKIP) {
+            ALOGD_IF(isDebug(), "%s:skip layer",__FUNCTION__);
+            return MDPCOMP_ABORT;
+        }
+
+        //Request for MDP pipes
+        int pipe_pref = PIPE_REQ_VG;
+
+        if((layer_prop & MDPCOMP_LAYER_DOWNSCALE) &&
+                        (layer_prop & MDPCOMP_LAYER_BLEND)) {
+            pipe_pref = PIPE_REQ_RGB;
+         }
+
+        int allocated_pipe = sPipeMgr.req_for_pipe( pipe_pref);
+        if(allocated_pipe) {
+          layer_info[index].can_use_mdp = true;
+          layer_info[index].pipe_pref = allocated_pipe;
+          current_frame.count++;
+        }else {
+            ALOGE("%s: pipe marking in mark layer fails for : %d",
+                                          __FUNCTION__, allocated_pipe);
+            return MDPCOMP_FAILURE;
+        }
+    }
+    return MDPCOMP_SUCCESS;
+}
+
+void MDPComp::reset_layer_mdp_info(layer_mdp_info* layer_info, int count) {
+    for(int i = 0 ; i < count; i++ ) {
+        layer_info[i].can_use_mdp = false;
+        layer_info[i].pipe_pref = PIPE_NONE;
+    }
+}
+
+bool MDPComp::alloc_layer_pipes(hwc_layer_list_t* list,
+                        layer_mdp_info* layer_info, frame_info& current_frame) {
+
+    int layer_count = list->numHwLayers;
+    int mdp_count = current_frame.count;
+    int fallback_count = layer_count - mdp_count;
+    int frame_pipe_count = 0;
+
+    ALOGD_IF(isDebug(), "%s:  dual mode: %d  total count: %d \
+                                mdp count: %d fallback count: %d",
+                            __FUNCTION__, (layer_count != mdp_count),
+                            layer_count, mdp_count, fallback_count);
+
+    for(int index = 0 ; index < layer_count ; index++ ) {
+        hwc_layer_t* layer = &list->hwLayers[index];
+
+        if(layer_info[index].can_use_mdp) {
+             pipe_layer_pair& info = current_frame.pipe_layer[frame_pipe_count];
+             mdp_pipe_info& pipe_info = info.pipe_index;
+
+             pipe_info.index = sPipeMgr.assign_pipe(layer_info[index].pipe_pref);
+             pipe_info.isVG = (layer_info[index].pipe_pref == PIPE_REQ_VG);
+             pipe_info.isFG = (frame_pipe_count == 0);
+             /* if VAR pipe is attached to FB, FB will be updated with
+                VSYNC WAIT flag, so no need to set VSYNC WAIT for any
+                bypass pipes. if not, set VSYNC WAIT to the last updating pipe*/
+             pipe_info.vsync_wait =
+                 (sPipeMgr.getStatus(VAR_INDEX) == PIPE_IN_FB_MODE) ? false:
+                                      (frame_pipe_count == (mdp_count - 1));
+             /* All the layers composed on FB will have MDP zorder 0, so start
+                assigning from  1*/
+                pipe_info.z_order = index -
+                        (fallback_count ? fallback_count - 1 : fallback_count);
+
+             info.layer_index = index;
+             frame_pipe_count++;
+        }
+    }
+    return 1;
+}
+
+//returns array of layers and their allocated pipes
+bool MDPComp::parse_and_allocate(hwc_context_t* ctx, hwc_layer_list_t* list,
+                                                  frame_info& current_frame ) {
+
+    int layer_count = list->numHwLayers;
+
+    /* clear pipe status */
+    sPipeMgr.reset();
+
+    layer_mdp_info* bp_layer_info = (layer_mdp_info*)
+                                   malloc(sizeof(layer_mdp_info)* layer_count);
+
+    reset_layer_mdp_info(bp_layer_info, layer_count);
+
+    /* iterate through layer list to mark candidate */
+    if(mark_layers(list, bp_layer_info, current_frame) == MDPCOMP_ABORT) {
+        free(bp_layer_info);
+        current_frame.count = 0;
+        ALOGE_IF(isDebug(), "%s:mark_layers failed!!", __FUNCTION__);
+        return false;
+    }
+    current_frame.pipe_layer = (pipe_layer_pair*)
+                          malloc(sizeof(pipe_layer_pair) * current_frame.count);
+
+    /* allocate MDP pipes for marked layers */
+    alloc_layer_pipes( list, bp_layer_info, current_frame);
+
+    free(bp_layer_info);
+    return true;
+}
+#if SUPPORT_4LAYER
+int MDPComp::configure_var_pipe(hwc_context_t* ctx) {
+
+    if(!ctx) {
+       ALOGE("%s: invalid context", __FUNCTION__);
+       return -1;
+    }
+
+    framebuffer_device_t *fbDev = ctx->fbDev;
+    if (!fbDev) {
+        ALOGE("%s: fbDev is NULL", __FUNCTION__);
+        return -1;
+    }
+
+    int new_mode = -1, cur_mode;
+    fbDev->perform(fbDev,EVENT_GET_VAR_PIPE_MODE, (void*)&cur_mode);
+
+    if(sPipeMgr.getStatus(VAR_INDEX) == PIPE_IN_FB_MODE) {
+        new_mode = VAR_PIPE_FB_ATTACH;
+    } else if(sPipeMgr.getStatus(VAR_INDEX) == PIPE_IN_BYP_MODE) {
+        new_mode = VAR_PIPE_FB_DETACH;
+        fbDev->perform(fbDev,EVENT_WAIT_POSTBUFFER,NULL);
+    }
+
+    ALOGD_IF(isDebug(),"%s: old_mode: %d new_mode: %d", __FUNCTION__,
+                                                      cur_mode, new_mode);
+
+    if((new_mode != cur_mode) && (new_mode >= 0)) {
+       if(fbDev->perform(fbDev,EVENT_SET_VAR_PIPE_MODE,(void*)&new_mode) < 0) {
+           ALOGE("%s: Setting var pipe mode failed", __FUNCTION__);
+       }
+    }
+
+    return 0;
+}
+#endif
+
+bool MDPComp::setup(hwc_context_t* ctx, hwc_layer_list_t* list) {
+    int nPipeIndex, vsync_wait, isFG;
+    int numHwLayers = list->numHwLayers;
+
+    frame_info &current_frame = sCurrentFrame;
+    current_frame.count = 0;
+
+    if(!ctx) {
+       ALOGE("%s: invalid context", __FUNCTION__);
+       return -1;
+    }
+
+    framebuffer_device_t *fbDev = ctx->mFbDev;
+    if (!fbDev) {
+        ALOGE("%s: fbDev is NULL", __FUNCTION__);
+        return -1;
+    }
+
+    if(!parse_and_allocate(ctx, list, current_frame)) {
+#if SUPPORT_4LAYER
+       int mode = VAR_PIPE_FB_ATTACH;
+       if(fbDev->perform(fbDev,EVENT_SET_VAR_PIPE_MODE,(void*)&mode) < 0 ) {
+           ALOGE("%s: setting var pipe mode failed", __FUNCTION__);
+       }
+#endif
+       ALOGD_IF(isDebug(), "%s: Falling back to FB", __FUNCTION__);
+       return false;
+    }
+#if SUPPORT_4LAYER
+    configure_var_pipe(ctx);
+#endif
+
+    overlay::Overlay& ov = *(ctx->mOverlay);
+    ovutils::eOverlayState state = ov.getState();
+
+    if (current_frame.count == 1) {
+         state = ovutils::OV_BYPASS_1_LAYER;
+    } else if (current_frame.count == 2) {
+         state = ovutils::OV_BYPASS_2_LAYER;
+    } else if (current_frame.count == 3) {
+         state = ovutils::OV_BYPASS_3_LAYER;
+   }
+
+      ov.setState(state);
+
+
+    for (int index = 0 ; index < current_frame.count; index++) {
+        int layer_index = current_frame.pipe_layer[index].layer_index;
+        hwc_layer_t* layer = &list->hwLayers[layer_index];
+        mdp_pipe_info& cur_pipe = current_frame.pipe_layer[index].pipe_index;
+
+        if( prepare(ctx, layer, cur_pipe) != 0 ) {
+           ALOGD_IF(isDebug(), "%s: MDPComp failed to configure overlay for \
+                                    layer %d with pipe index:%d",__FUNCTION__,
+                                    index, cur_pipe.index);
+           return false;
+         } else {
+            setLayerIndex(layer, index);
+         }
+    }
+    return true;
+}
+
+void MDPComp::unsetMDPCompLayerFlags(hwc_context_t* ctx, hwc_layer_list_t* list)
+{
+    if (!list)
+        return;
+
+    for (int index = 0 ; index < sCurrentFrame.count; index++) {
+        int l_index = sCurrentFrame.pipe_layer[index].layer_index;
+        if(list->hwLayers[l_index].flags & HWC_MDPCOMP) {
+            list->hwLayers[l_index].flags &= ~HWC_MDPCOMP;
+        }
+    }
+}
+
+int MDPComp::draw(hwc_context_t *ctx, hwc_layer_list_t* list) {
+
+    if(!isEnabled()) {
+        ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled",__FUNCTION__);
+        return 0;
+     }
+
+    if(!ctx || !list) {
+        ALOGE("%s: invalid contxt or list",__FUNCTION__);
+        return -1;
+    }
+
+    overlay::Overlay& ov = *(ctx->mOverlay);
+
+    for(unsigned int i = 0; i < list->numHwLayers; i++ )
+    {
+        hwc_layer_t *layer = &list->hwLayers[i];
+
+        if(!(layer->flags & HWC_MDPCOMP)) {
+            ALOGD_IF(isDebug(), "%s: Layer Not flagged for MDP comp",
+                                                                __FUNCTION__);
+            continue;
+        }
+
+        int data_index = getLayerIndex(layer);
+        mdp_pipe_info& pipe_info =
+                          sCurrentFrame.pipe_layer[data_index].pipe_index;
+        int index = pipe_info.index;
+
+        if(index < 0) {
+            ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, index);
+            return -1;
+        }
+
+        /* reset Invalidator */
+        if(idleInvalidator)
+        idleInvalidator->markForSleep();
+
+        ovutils::eDest dest;
+
+        if (index == 0) {
+            dest = ovutils::OV_PIPE0;
+        } else if (index == 1) {
+            dest = ovutils::OV_PIPE1;
+        } else if (index == 2) {
+            dest = ovutils::OV_PIPE2;
+        }
+
+        if (ctx ) {
+            private_handle_t *hnd = (private_handle_t *)layer->handle;
+            if(!hnd) {
+                ALOGE("%s handle null", __FUNCTION__);
+                return -1;
+            }
+
+            //lock buffer before queue
+            //XXX: Handle lock failure
+            ctx->qbuf->lockAndAdd(hnd);
+
+            ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
+                                 using  pipe: %d", __FUNCTION__, layer,
+                                 hnd, index );
+
+            if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) {
+                ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
+                return -1;
+            }
+        }
+        layer->flags &= ~HWC_MDPCOMP;
+        layer->flags |= HWC_MDPCOMP_INDEX_MASK;
+    }
+    return 0;
+}
+
+bool MDPComp::init(hwc_context_t *dev) {
+
+    if(!dev) {
+        ALOGE("%s: Invalid hwc context!!",__FUNCTION__);
+        return false;
+    }
+
+#if SUPPORT_4LAYER
+    if(MAX_MDPCOMP_LAYERS > MAX_STATIC_PIPES) {
+        framebuffer_device_t *fbDev = dev->fbDevice;
+        if(fbDev == NULL) {
+            ALOGE("%s: FATAL: framebuffer device is NULL", __FUNCTION__);
+            return false;
+        }
+
+        //Receive VAR pipe object from framebuffer
+        if(fbDev->perform(fbDev,EVENT_GET_VAR_PIPE,(void*)&ov) < 0) {
+            ALOGE("%s: FATAL: getVariablePipe failed!!", __FUNCTION__);
+            return false;
+        }
+
+        sPipeMgr.setStatus(VAR_INDEX, PIPE_IN_FB_MODE);
+    }
+#endif
+    char property[PROPERTY_VALUE_MAX];
+
+    sMaxLayers = 0;
+    if(property_get("debug.mdpcomp.maxlayer", property, NULL) > 0) {
+        if(atoi(property) != 0)
+           sMaxLayers = atoi(property);
+    }
+
+    sDebugLogs = false;
+    if(property_get("debug.mdpcomp.logs", property, NULL) > 0) {
+        if(atoi(property) != 0)
+           sDebugLogs = true;
+    }
+
+    unsigned long idle_timeout = DEFAULT_IDLE_TIME;
+    if(property_get("debug.mdpcomp.idletime", property, NULL) > 0) {
+        if(atoi(property) != 0)
+           idle_timeout = atoi(property);
+    }
+
+    //create Idle Invalidator
+    idleInvalidator = IdleInvalidator::getInstance();
+
+    if(idleInvalidator == NULL) {
+       ALOGE("%s: failed to instantiate idleInvalidator  object", __FUNCTION__);
+    } else {
+       idleInvalidator->init(timeout_handler, dev, idle_timeout);
+    }
+    return true;
+}
+
+bool MDPComp::configure(hwc_composer_device_t *dev,  hwc_layer_list_t* list) {
+
+    if(!isEnabled()) {
+        ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
+        return false;
+    }
+
+    hwc_context_t* ctx = (hwc_context_t*)(dev);
+
+    bool isMDPCompUsed = true;
+    bool doable = is_doable(dev, list);
+
+    if(doable) {
+        if(setup(ctx, list)) {
+            setMDPCompLayerFlags(list);
+            sMDPCompState = MDPCOMP_ON;
+        } else {
+            ALOGD_IF(isDebug(),"%s: MDP Comp Failed",__FUNCTION__);
+            isMDPCompUsed = false;
+        }
+     } else {
+        ALOGD_IF( isDebug(),"%s: MDP Comp not possible[%d]",__FUNCTION__,
+                   doable);
+        isMDPCompUsed = false;
+     }
+
+     //Reset states
+     if(!isMDPCompUsed) {
+        //Reset current frame
+         reset(ctx, list);
+     }
+
+     sIdleFallBack = false;
+
+     return isMDPCompUsed;
+}
+}; //namespace
+
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
new file mode 100755
index 0000000..199204c
--- /dev/null
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2012, Code Aurora Forum. All rights reserved.
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * 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.
+ */
+
+#ifndef HWC_MDP_COMP
+#define HWC_MDP_COMP
+
+#include <hwc_utils.h>
+#include <idle_invalidator.h>
+#include <cutils/properties.h>
+#include <overlay.h>
+
+#define MAX_STATIC_PIPES 3
+#define MDPCOMP_INDEX_OFFSET 4
+#define DEFAULT_IDLE_TIME 2000
+
+#define MAX_VG 2
+#define MAX_RGB 2
+#define VAR_INDEX 3
+#define MAX_PIPES (MAX_VG + MAX_RGB)
+#define HWC_MDPCOMP_INDEX_MASK 0x00000030
+
+
+//struct hwc_context_t;
+
+namespace qhwc {
+
+// pipe status
+enum {
+    PIPE_UNASSIGNED = 0,
+    PIPE_IN_FB_MODE,
+    PIPE_IN_COMP_MODE,
+};
+
+// pipe request
+enum {
+    PIPE_NONE = 0,
+    PIPE_REQ_VG,
+    PIPE_REQ_RGB,
+    PIPE_REQ_FB,
+};
+
+// MDP Comp Status
+enum {
+    MDPCOMP_SUCCESS = 0,
+    MDPCOMP_FAILURE,
+    MDPCOMP_ABORT,
+};
+
+//This class manages the status of 4 MDP pipes and keeps
+//track of Variable pipe mode.
+class PipeMgr {
+
+public:
+    PipeMgr() { reset();}
+    //reset pipemgr params
+    void reset();
+
+    //Based on the preference received, pipe mgr
+    //allocates the best available pipe to handle
+    //the case
+    int req_for_pipe(int pipe_req);
+
+    //Allocate requested pipe and update availablity
+    int assign_pipe(int pipe_pref);
+
+    // Get/Set pipe status
+    void setStatus(int pipe_index, int pipe_status) {
+        mStatus[pipe_index] = pipe_status;
+    }
+    int getStatus(int pipe_index) {
+        return mStatus[pipe_index];
+    }
+private:
+    int mVGPipes;
+    int mVGUsed;
+    int mVGIndex;
+    int mRGBPipes;
+    int mRGBUsed;
+    int mRGBIndex;
+    int mTotalAvail;
+    int mStatus[MAX_PIPES];
+};
+
+
+class MDPComp {
+    enum State {
+        MDPCOMP_ON = 0,
+        MDPCOMP_OFF,
+        MDPCOMP_OFF_PENDING,
+    };
+
+    enum {
+        MDPCOMP_LAYER_BLEND = 1,
+        MDPCOMP_LAYER_DOWNSCALE = 2,
+        MDPCOMP_LAYER_SKIP = 4,
+        MDPCOMP_LAYER_UNSUPPORTED_MEM = 8,
+    };
+
+    struct mdp_pipe_info {
+        int index;
+        int z_order;
+        bool isVG;
+        bool isFG;
+        bool vsync_wait;
+    };
+
+    struct pipe_layer_pair {
+        int layer_index;
+        mdp_pipe_info pipe_index;
+        native_handle_t* handle;
+    };
+
+    struct frame_info {
+        int count;
+        struct pipe_layer_pair* pipe_layer;
+
+    };
+
+    struct layer_mdp_info {
+        bool can_use_mdp;
+        int pipe_pref;
+    };
+
+    static State sMDPCompState;
+    static IdleInvalidator *idleInvalidator;
+    static struct frame_info sCurrentFrame;
+    static PipeMgr sPipeMgr;
+    static int sSkipCount;
+    static int sMaxLayers;
+    static bool sDebugLogs;
+    static bool sIdleFallBack;
+
+public:
+    /* Handler to invoke frame redraw on Idle Timer expiry */
+    static void timeout_handler(void *udata);
+
+    /* configure/tear-down MDPComp params*/
+    static bool init(hwc_context_t *ctx);
+    static bool deinit();
+
+    /*sets up mdp comp for the current frame */
+    static bool configure(hwc_composer_device_t *ctx,  hwc_layer_list_t* list);
+
+    /* draw */
+    static int draw(hwc_context_t *ctx, hwc_layer_list_t *list);
+
+    /* store frame stats */
+    static void setStats(int skipCt) { sSkipCount  = skipCt;};
+
+private:
+
+    /* get/set pipe index associated with overlay layers */
+    static void setLayerIndex(hwc_layer_t* layer, const int pipe_index);
+    static int  getLayerIndex(hwc_layer_t* layer);
+
+    /* set/reset flags for MDPComp */
+    static void setMDPCompLayerFlags(hwc_layer_list_t* list);
+    static void unsetMDPCompLayerFlags(hwc_context_t* ctx,
+                                       hwc_layer_list_t* list);
+
+    static void print_info(hwc_layer_t* layer);
+
+    /* configure's overlay pipes for the frame */
+    static int  prepare(hwc_context_t *ctx, hwc_layer_t *layer,
+                        mdp_pipe_info& mdp_info);
+
+    /* checks for conditions where mdpcomp is not possible */
+    static bool is_doable(hwc_composer_device_t *dev,
+                           const hwc_layer_list_t* list);
+
+    static bool setup(hwc_context_t* ctx, hwc_layer_list_t* list);
+
+    /* parses layer for properties affecting mdp comp */
+    static void get_layer_info(hwc_layer_t* layer, int& flags);
+
+    /* iterates through layer list to choose candidate to use overlay */
+    static int  mark_layers(hwc_layer_list_t* list, layer_mdp_info* layer_info,
+                                                  frame_info& current_frame);
+    static bool parse_and_allocate(hwc_context_t* ctx, hwc_layer_list_t* list,
+                                                  frame_info& current_frame );
+
+    /* clears layer info struct */
+    static void reset_layer_mdp_info(layer_mdp_info* layer_mdp_info,int count);
+
+    /* allocates pipes to selected candidates */
+    static bool alloc_layer_pipes(hwc_layer_list_t* list,
+                                  layer_mdp_info* layer_info,
+                                  frame_info& current_frame);
+    /* updates variable pipe mode for the current frame */
+    static int  configure_var_pipe(hwc_context_t* ctx);
+
+    /* get/set states */
+    static State get_state() { return sMDPCompState; };
+    static void set_state(State state) { sMDPCompState = state; };
+
+    /* reset state */
+    static void reset( hwc_context_t *ctx, hwc_layer_list_t* list );
+
+    /* Is feature enabled */
+    static bool isEnabled() { return sMaxLayers ? true : false; };
+    /* Is debug enabled */
+    static bool isDebug() { return sDebugLogs ? true : false; };
+};
+}; //namespace
+#endif
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 870a758..0b62a98 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -22,6 +22,7 @@
 #include "hwc_qbuf.h"
 #include "hwc_copybit.h"
 #include "hwc_external.h"
+#include "hwc_mdpcomp.h"
 
 namespace qhwc {
 
@@ -43,6 +44,7 @@
     ctx->hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay();
     ctx->mCopybitEngine = CopybitEngine::getInstance();
     ctx->mExtDisplay = new ExternalDisplay(ctx);
+    MDPComp::init(ctx);
 
     init_uevent_thread(ctx);
 
@@ -103,6 +105,7 @@
     int yuvCount = 0;
     int yuvLayerIndex = -1;
     bool isYuvLayerSkip = false;
+    int skipCount = 0;
 
     for (size_t i = 0; i < list->numHwLayers; i++) {
         private_handle_t *hnd =
@@ -120,11 +123,13 @@
             if(yuvLayerIndex != -1 && yuvLayerIndex < (ssize_t)i) {
                 isYuvLayerSkip = true;
             }
+            skipCount++;
         }
     }
 
     VideoOverlay::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip);
     CopyBit::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip);
+    MDPComp::setStats(skipCount);
 
     ctx->numHwLayers = list->numHwLayers;
     return;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 1e405f7..a6c1446 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -50,6 +50,12 @@
     HWC_USE_COPYBIT                // This layer is to be handled by copybit
 };
 
+enum {
+    HWC_MDPCOMP = 0x00000002,
+    HWC_LAYER_RESERVED_0 = 0x00000004,
+    HWC_LAYER_RESERVED_1 = 0x00000008
+};
+
 
 class ExternalDisplay;
 class CopybitEngine;
@@ -81,6 +87,13 @@
 // Initialize uevent thread
 void init_uevent_thread(hwc_context_t* ctx);
 
+inline void getLayerResolution(const hwc_layer_t* layer,
+                                         int& width, int& height)
+{
+    hwc_rect_t displayFrame  = layer->displayFrame;
+    width = displayFrame.right - displayFrame.left;
+    height = displayFrame.bottom - displayFrame.top;
+}
 }; //qhwc namespace
 
 // -----------------------------------------------------------------------------