Merge "hwc: Handle WFD Pause/Resume usecase"
diff --git a/common.mk b/common.mk
index 360032b..f2ae8b2 100644
--- a/common.mk
+++ b/common.mk
@@ -12,10 +12,13 @@
     common_includes += $(TARGET_OUT_HEADERS)/pp/inc
 endif
 
-
 #Common libraries external to display HAL
 common_libs := liblog libutils libcutils libhardware
 
+ifeq ($(TARGET_USES_POST_PROCESSING),true)
+    common_libs += libmm-abl
+endif
+
 #Common C flags
 common_flags := -DDEBUG_CALC_FPS -Wno-missing-field-initializers
 common_flags += -Werror
diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp
index efbd350..5c58dd3 100644
--- a/libcopybit/copybit_c2d.cpp
+++ b/libcopybit/copybit_c2d.cpp
@@ -1259,10 +1259,11 @@
             return status;
         }
 
-        // Flush the cache
+        // Clean the cache
         IMemAlloc* memalloc = sAlloc->getAllocator(src_hnd->flags);
         if (memalloc->clean_buffer((void *)(src_hnd->base), src_hnd->size,
-                                   src_hnd->offset, src_hnd->fd)) {
+                                   src_hnd->offset, src_hnd->fd,
+                                   gralloc::CACHE_CLEAN)) {
             ALOGE("%s: clean_buffer failed", __FUNCTION__);
             delete_handle(dst_hnd);
             delete_handle(src_hnd);
@@ -1343,10 +1344,11 @@
             unmap_gpuaddr(ctx, mapped_src_idx);
             return status;
         }
-        // Invalidate the cache.
+        // Clean the cache.
         IMemAlloc* memalloc = sAlloc->getAllocator(dst_hnd->flags);
         memalloc->clean_buffer((void *)(dst_hnd->base), dst_hnd->size,
-                               dst_hnd->offset, dst_hnd->fd);
+                               dst_hnd->offset, dst_hnd->fd,
+                               gralloc::CACHE_CLEAN);
     }
     delete_handle(dst_hnd);
     delete_handle(src_hnd);
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index af28bce..cf84a39 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -99,6 +99,8 @@
     setResolution(mode);
     setDpyHdmiAttr();
     setExternalDisplay(true, mHdmiFbNum);
+    // set system property
+    property_set("hw.hdmiON", "1");
     return 0;
 }
 
@@ -128,6 +130,8 @@
         closeFrameBuffer();
         resetInfo();
         setExternalDisplay(false);
+        // unset system property
+        property_set("hw.hdmiON", "0");
     }
     return 0;
 }
@@ -142,29 +146,17 @@
     return 0;
 }
 
-void ExternalDisplay::processUEventOnline(const char *str) {
+int ExternalDisplay::ignoreRequest(const char *str) {
     const char *s1 = str + strlen("change@/devices/virtual/switch/");
-    if(!strncmp(s1,"hdmi",strlen(s1))) {
-        // hdmi online event..!
-        configureHDMIDisplay();
-        // set system property
-        property_set("hw.hdmiON", "1");
-    }else if(!strncmp(s1,"wfd",strlen(s1))) {
-        // wfd online event..!
-        configureWFDDisplay();
+    if(!strncmp(s1,"wfd",strlen(s1))) {
+        if(mConnectedFbNum == mHdmiFbNum) {
+            ALOGE("Ignore wfd event when HDMI is active");
+            return true;
+        }
     }
+    return false;
 }
 
-void ExternalDisplay::processUEventOffline(const char *str) {
-    const char *s1 = str + strlen("change@/devices/virtual/switch/");
-    if(!strncmp(s1,"hdmi",strlen(s1))) {
-        teardownHDMIDisplay();
-        // unset system property
-        property_set("hw.hdmiON", "0");
-    }else if(!strncmp(s1,"wfd",strlen(s1))) {
-        teardownWFDDisplay();
-    }
-}
 
 ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1),
     mCurrentMode(-1), mConnected(0), mConnectedFbNum(0), mModeCount(0),
diff --git a/libexternal/external.h b/libexternal/external.h
index d46eec1..847b25c 100644
--- a/libexternal/external.h
+++ b/libexternal/external.h
@@ -47,11 +47,16 @@
     void setExternalDisplay(bool connected, int extFbNum = 0);
     bool isExternalConnected() { return mConnected;};
     void  setExtDpyNum(int extDpyNum) { mExtDpyNum = extDpyNum;};
+    int  getExternalType() {return mConnectedFbNum;};
+    bool isWFDActive() {return (mConnectedFbNum == mWfdFbNum);};
     void setHPD(uint32_t startEnd);
     void setEDIDMode(int resMode);
     void setActionSafeDimension(int w, int h);
-    void processUEventOnline(const char *str);
-    void processUEventOffline(const char *str);
+    int ignoreRequest(const char *str);
+    int  configureHDMIDisplay();
+    int  configureWFDDisplay();
+    int  teardownHDMIDisplay();
+    int  teardownWFDDisplay();
 
 private:
     void readCEUnderscanInfo();
@@ -72,10 +77,6 @@
     void setDpyWfdAttr();
     void getAttrForMode(int& width, int& height, int& fps);
     void updateExtDispDevFbIndex();
-    int  configureHDMIDisplay();
-    int  configureWFDDisplay();
-    int  teardownHDMIDisplay();
-    int  teardownWFDDisplay();
     int  getExtFbNum(int &fbNum);
 
     mutable android::Mutex mExtDispLock;
diff --git a/libgralloc/ionalloc.cpp b/libgralloc/ionalloc.cpp
index 8480f98..83e62e7 100644
--- a/libgralloc/ionalloc.cpp
+++ b/libgralloc/ionalloc.cpp
@@ -145,7 +145,8 @@
         }
         memset(base, 0, ionAllocData.len);
         // Clean cache after memset
-        clean_buffer(base, data.size, data.offset, fd_data.fd);
+        clean_buffer(base, data.size, data.offset, fd_data.fd,
+                     CACHE_CLEAN_AND_INVALIDATE);
     }
 
     data.base = base;
@@ -209,7 +210,7 @@
     return err;
 
 }
-int IonAlloc::clean_buffer(void *base, size_t size, int offset, int fd)
+int IonAlloc::clean_buffer(void *base, size_t size, int offset, int fd, int op)
 {
     struct ion_flush_data flush_data;
     struct ion_fd_data fd_data;
@@ -237,7 +238,18 @@
 
 #ifdef NEW_ION_API
     struct ion_custom_data d;
-    d.cmd = ION_IOC_CLEAN_INV_CACHES;
+    switch(op) {
+    case CACHE_CLEAN:
+        d.cmd = ION_IOC_CLEAN_CACHES;
+        break;
+    case CACHE_INVALIDATE:
+            d.cmd = ION_IOC_INV_CACHES;
+        break;
+    case CACHE_CLEAN_AND_INVALIDATE:
+    default:
+        d.cmd = ION_IOC_CLEAN_INV_CACHES;
+    }
+
     d.arg = (unsigned long int)&flush_data;
 
     if(ioctl(mIonFd, ION_IOC_CUSTOM, &d)) {
diff --git a/libgralloc/ionalloc.h b/libgralloc/ionalloc.h
index 7a11a34..174f44b 100644
--- a/libgralloc/ionalloc.h
+++ b/libgralloc/ionalloc.h
@@ -51,7 +51,7 @@
                              int offset);
 
     virtual int clean_buffer(void*base, size_t size,
-                             int offset, int fd);
+                             int offset, int fd, int op);
 
     IonAlloc() { mIonFd = FD_INIT; }
 
diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp
index 9c97aae..5a32975 100644
--- a/libgralloc/mapper.cpp
+++ b/libgralloc/mapper.cpp
@@ -222,12 +222,19 @@
             pthread_mutex_unlock(lock);
         }
         *vaddr = (void*)hnd->base;
-
+        //Invalidate if reading in software. No need to do this for the metadata
+        //buffer as it is only read/written in software.
+        IMemAlloc* memalloc = getAllocator(hnd->flags) ;
+        err = memalloc->clean_buffer((void*)hnd->base,
+                                     hnd->size, hnd->offset, hnd->fd,
+                                     CACHE_INVALIDATE);
         if ((usage & GRALLOC_USAGE_SW_WRITE_MASK) &&
             !(hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER)) {
             // Mark the buffer to be flushed after cpu read/write
             hnd->flags |= private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
         }
+    } else {
+        hnd->flags |= private_handle_t::PRIV_FLAGS_DO_NOT_FLUSH;
     }
     return err;
 }
@@ -237,26 +244,26 @@
 {
     if (private_handle_t::validate(handle) < 0)
         return -EINVAL;
-
+    int err = 0;
     private_handle_t* hnd = (private_handle_t*)handle;
+    IMemAlloc* memalloc = getAllocator(hnd->flags);
 
     if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) {
-        int err;
-        IMemAlloc* memalloc = getAllocator(hnd->flags) ;
         err = memalloc->clean_buffer((void*)hnd->base,
-                                     hnd->size, hnd->offset, hnd->fd);
-        ALOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%x, flags = 0x%x) err=%s\n",
-                 hnd, hnd->offset, hnd->size, hnd->flags, strerror(errno));
-        unsigned long size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
-        err = memalloc->clean_buffer((void*)hnd->base_metadata, size,
-                hnd->offset_metadata, hnd->fd_metadata);
-        ALOGE_IF(err < 0, "cannot flush handle %p (offs=%x len=%lu, "
-                "flags = 0x%x) err=%s\n", hnd, hnd->offset_metadata, size,
-                hnd->flags, strerror(errno));
+                                     hnd->size, hnd->offset, hnd->fd,
+                                     CACHE_CLEAN_AND_INVALIDATE);
         hnd->flags &= ~private_handle_t::PRIV_FLAGS_NEEDS_FLUSH;
+    } else if(hnd->flags & private_handle_t::PRIV_FLAGS_DO_NOT_FLUSH) {
+        hnd->flags &= ~private_handle_t::PRIV_FLAGS_DO_NOT_FLUSH;
+    } else {
+        //Probably a round about way to do this, but this avoids adding new
+        //flags
+        err = memalloc->clean_buffer((void*)hnd->base,
+                                     hnd->size, hnd->offset, hnd->fd,
+                                     CACHE_INVALIDATE);
     }
 
-    return 0;
+    return err;
 }
 
 /*****************************************************************************/
diff --git a/libgralloc/memalloc.h b/libgralloc/memalloc.h
index 73ac652..664bfa2 100644
--- a/libgralloc/memalloc.h
+++ b/libgralloc/memalloc.h
@@ -34,6 +34,12 @@
 
 namespace gralloc {
 
+enum {
+    CACHE_CLEAN = 0x1,
+    CACHE_INVALIDATE,
+    CACHE_CLEAN_AND_INVALIDATE,
+};
+
 struct alloc_data {
     void           *base;
     int            fd;
@@ -68,7 +74,7 @@
 
     // Clean and invalidate
     virtual int clean_buffer(void *base, size_t size,
-                             int offset, int fd) = 0;
+                             int offset, int fd, int op) = 0;
 
     // Destructor
     virtual ~IMemAlloc() {};
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 56432db..e8559ac 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -631,6 +631,7 @@
             hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
             PipeLayerPair& info = currentFrame.pipeLayer[nYuvIndex];
             info.pipeInfo = new MdpPipeInfoHighRes;
+            info.rot = NULL;
             MdpPipeInfoHighRes& pipe_info = *(MdpPipeInfoHighRes*)info.pipeInfo;
             if(!acquireMDPPipes(ctx, layer, pipe_info,MDPCOMP_OV_VG)) {
                 ALOGD_IF(isDebug(),"%s: Unable to get pipe for videos",
@@ -651,6 +652,7 @@
 
         PipeLayerPair& info = currentFrame.pipeLayer[index];
         info.pipeInfo = new MdpPipeInfoHighRes;
+        info.rot = NULL;
         MdpPipeInfoHighRes& pipe_info = *(MdpPipeInfoHighRes*)info.pipeInfo;
 
         ePipeType type = MDPCOMP_OV_ANY;
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index f01fcc2..b98db73 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -33,7 +33,7 @@
 #include "external.h"
 
 namespace qhwc {
-
+#define HWC_UEVENT_SWITCH_STR  "change@/devices/virtual/switch/"
 #define HWC_UEVENT_THREAD_NAME "hwcUeventThread"
 
 /* External Display states */
@@ -51,6 +51,32 @@
     return false;
 }
 
+static void setup(hwc_context_t* ctx, int dpy, bool usecopybit)
+{
+    ctx->mFBUpdate[dpy] =
+            IFBUpdate::getObject(ctx->dpyAttr[dpy].xres, dpy);
+    if(usecopybit)
+        ctx->mCopyBit[dpy] = new CopyBit();
+    ctx->mVidOv[dpy] =
+            IVideoOverlay::getObject(ctx->dpyAttr[dpy].xres, dpy);
+}
+
+static void clear(hwc_context_t* ctx, int dpy)
+{
+    if(ctx->mFBUpdate[dpy]) {
+        delete ctx->mFBUpdate[dpy];
+        ctx->mFBUpdate[dpy] = NULL;
+    }
+    if(ctx->mCopyBit[dpy]){
+        delete ctx->mCopyBit[dpy];
+        ctx->mCopyBit[dpy] = NULL;
+    }
+    if(ctx->mVidOv[dpy]) {
+        delete ctx->mVidOv[dpy];
+        ctx->mVidOv[dpy] = NULL;
+    }
+}
+
 static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
 {
     int vsync = 0;
@@ -65,7 +91,6 @@
                            qdutils::COMPOSITION_TYPE_C2D)) {
         usecopybit = true;
     }
-
     if(!strcasestr("change@/devices/virtual/switch/hdmi", str) &&
        !strcasestr("change@/devices/virtual/switch/wfd", str)) {
         ALOGD_IF(UEVENT_DEBUG, "%s: Not Ext Disp Event ", __FUNCTION__);
@@ -84,9 +109,6 @@
 
     int dpy = isHDMI(str) ? HWC_DISPLAY_EXTERNAL : extDpyNum;
 
-    // update extDpyNum
-    ctx->mExtDisplay->setExtDpyNum(dpy);
-
     // parse HDMI/WFD switch state for connect/disconnect
     // for HDMI:
     // The event will be of the form:
@@ -106,30 +128,33 @@
         if (str - udata >= len)
             break;
     }
+    ALOGD_IF(UEVENT_DEBUG, "Received str:%s",udata);
 
+    if(connected != EXTERNAL_ONLINE) {
+        if(ctx->mExtDisplay->ignoreRequest(udata)) {
+            ALOGD_IF(UEVENT_DEBUG,"No need to process this connection request"
+                                  "str:%s",udata);
+           ctx->dpyAttr[dpy].isActive = true;
+           return;
+        }
+    }
+
+    // update extDpyNum
+    ctx->mExtDisplay->setExtDpyNum(dpy);
     switch(connected) {
         case EXTERNAL_OFFLINE:
             {   // disconnect event
-                ctx->mExtDisplay->processUEventOffline(udata);
-                if(ctx->mFBUpdate[dpy]) {
-                    Locker::Autolock _l(ctx->mExtSetLock);
-                    delete ctx->mFBUpdate[dpy];
-                    ctx->mFBUpdate[dpy] = NULL;
+                const char *s1 = udata + strlen(HWC_UEVENT_SWITCH_STR);
+                if(!strncmp(s1,"hdmi",strlen(s1))) {
+                    ctx->mExtDisplay->teardownHDMIDisplay();
+                }else if(!strncmp(s1,"wfd",strlen(s1))) {
+                    ctx->mExtDisplay->teardownWFDDisplay();
                 }
-                if(ctx->mVidOv[dpy]) {
-                    Locker::Autolock _l(ctx->mExtSetLock);
-                    delete ctx->mVidOv[dpy];
-                    ctx->mVidOv[dpy] = NULL;
-                }
-                if(ctx->mCopyBit[dpy]){
-                    Locker::Autolock _l(ctx->mExtSetLock);
-                    delete ctx->mCopyBit[dpy];
-                    ctx->mCopyBit[dpy] = NULL;
-                }
+                Locker::Autolock _l(ctx->mExtSetLock);
+                clear(ctx, dpy);
                 ALOGD("%s sending hotplug: connected = %d and dpy:%d",
                       __FUNCTION__, connected, dpy);
                 ctx->dpyAttr[dpy].connected = false;
-                Locker::Autolock _l(ctx->mExtSetLock);
                 //hwc comp could be on
                 ctx->proc->hotplug(ctx->proc, dpy, connected);
                 break;
@@ -137,14 +162,38 @@
         case EXTERNAL_ONLINE:
             {   // connect case
                 ctx->mExtDispConfiguring = true;
-                ctx->mExtDisplay->processUEventOnline(udata);
-                ctx->mFBUpdate[dpy] =
-                        IFBUpdate::getObject(ctx->dpyAttr[dpy].xres, dpy);
-                ctx->mVidOv[dpy] =
-                        IVideoOverlay::getObject(ctx->dpyAttr[dpy].xres, dpy);
+                const char *s1 = udata + strlen(HWC_UEVENT_SWITCH_STR);
+                if(!strncmp(s1,"hdmi",strlen(s1))) {
+                    // hdmi online event..!
+                    // check if WFD is configured
+                    if(ctx->mExtDisplay->isWFDActive()) {
+                        ALOGD_IF(UEVENT_DEBUG,"Received HDMI connection request"
+                                "when WFD is active");
+                        // teardown Active WFD Display
+                        ctx->mExtDisplay->teardownWFDDisplay();
+                        {
+                            Locker::Autolock _l(ctx->mExtSetLock);
+                            clear(ctx, dpy);
+                            //send hotplug disconnect event
+                            ALOGD_IF(UEVENT_DEBUG, "sending hotplug: disconnect"
+                                    "for WFD");
+                            // hwc comp could be on
+                            ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_OFFLINE);
+                        }
+                        //Invalidate
+                        ctx->proc->invalidate(ctx->proc);
+                        //wait for 1 second
+                        ALOGE_IF(UEVENT_DEBUG, "wait for 1 second -- padding"
+                                "round");
+                        sleep(1);
+                    }
+                    ctx->mExtDisplay->configureHDMIDisplay();
+                } else if(!strncmp(s1,"wfd",strlen(s1))) {
+                    // wfd online event..!
+                    ctx->mExtDisplay->configureWFDDisplay();
+                }
                 ctx->dpyAttr[dpy].isPause = false;
-                if(usecopybit)
-                    ctx->mCopyBit[dpy] = new CopyBit();
+                setup(ctx, dpy, usecopybit);
                 ALOGD("%s sending hotplug: connected = %d", __FUNCTION__,
                         connected);
                 ctx->dpyAttr[dpy].connected = true;
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index dd8c292..5018d2e 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -605,6 +605,13 @@
             ovutils::setMdpFlags(mdpFlags,  ovutils::OV_MDP_FLIP_V);
         }
     }
+
+    if(metadata &&
+        ((metadata->operation & PP_PARAM_HSIC)
+        || (metadata->operation & PP_PARAM_IGC)
+        || (metadata->operation & PP_PARAM_SHARP2))) {
+        ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_PP_EN);
+    }
 }
 
 static inline int configRotator(Rotator *rot, const Whf& whf,
@@ -620,7 +627,8 @@
 
 static inline int configMdp(Overlay *ov, const PipeArgs& parg,
         const eTransform& orient, const hwc_rect_t& crop,
-        const hwc_rect_t& pos, const eDest& dest) {
+        const hwc_rect_t& pos, const MetaData_t *metadata,
+        const eDest& dest) {
     ov->setSource(parg, dest);
     ov->setTransform(orient, dest);
 
@@ -634,6 +642,9 @@
     Dim position(pos.left, pos.top, posW, posH);
     ov->setPosition(position, dest);
 
+    if (metadata)
+        ov->setVisualParams(*metadata, dest);
+
     if (!ov->commit(dest)) {
         return -1;
     }
@@ -665,6 +676,8 @@
         return -1;
     }
 
+    MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+
     hwc_rect_t crop = layer->sourceCrop;
     hwc_rect_t dst = layer->displayFrame;
     int transform = layer->transform;
@@ -706,7 +719,7 @@
     transform = 0;
 
     PipeArgs parg(mdpFlags, whf, z, isFg, static_cast<eRotFlags>(rotFlags));
-    if(configMdp(ctx->mOverlay, parg, orient, crop, dst, dest) < 0) {
+    if(configMdp(ctx->mOverlay, parg, orient, crop, dst, metadata, dest) < 0) {
         ALOGE("%s: commit failed for low res panel", __FUNCTION__);
         return -1;
     }
@@ -723,6 +736,8 @@
         return -1;
     }
 
+    MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+
     int hw_w = ctx->dpyAttr[dpy].xres;
     int hw_h = ctx->dpyAttr[dpy].yres;
     hwc_rect_t crop = layer->sourceCrop;
@@ -798,7 +813,7 @@
         PipeArgs pargL(mdpFlagsL, whf, z, isFg,
                 static_cast<eRotFlags>(rotFlags));
         if(configMdp(ctx->mOverlay, pargL, orient,
-                tmp_cropL, tmp_dstL, lDest) < 0) {
+                tmp_cropL, tmp_dstL, metadata, lDest) < 0) {
             ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
             return -1;
         }
@@ -811,7 +826,7 @@
         tmp_dstR.right = tmp_dstR.right - tmp_dstR.left;
         tmp_dstR.left = 0;
         if(configMdp(ctx->mOverlay, pargR, orient,
-                tmp_cropR, tmp_dstR, rDest) < 0) {
+                tmp_cropR, tmp_dstR, metadata, rDest) < 0) {
             ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
             return -1;
         }
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index d22aedb..1faeadf 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -30,6 +30,7 @@
 #include "overlay.h"
 #include "pipes/overlayGenPipe.h"
 #include "mdp_version.h"
+#include "qdMetaData.h"
 
 #define PIPE_DEBUG 0
 
@@ -194,6 +195,12 @@
     mPipeBook[index].mPipe->setSource(newArgs);
 }
 
+void Overlay::setVisualParams(const MetaData_t& metadata, utils::eDest dest) {
+    int index = (int)dest;
+    validate(index);
+    mPipeBook[index].mPipe->setVisualParams(metadata);
+}
+
 Overlay* Overlay::getInstance() {
     if(sInstance == NULL) {
         sInstance = new Overlay();
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index aa12b76..fdeebc2 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+* Copyright (c) 2011-2013, 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
@@ -33,6 +33,8 @@
 #include "overlayUtils.h"
 #include "utils/threads.h"
 
+struct MetaData_t;
+
 namespace overlay {
 class GenericPipe;
 
@@ -64,6 +66,7 @@
     void setCrop(const utils::Dim& d, utils::eDest dest);
     void setTransform(const int orientation, utils::eDest dest);
     void setPosition(const utils::Dim& dim, utils::eDest dest);
+    void setVisualParams(const MetaData_t& data, utils::eDest dest);
     bool commit(utils::eDest dest);
     bool queueBuffer(int fd, uint32_t offset, utils::eDest dest);
 
diff --git a/liboverlay/overlayCtrlData.h b/liboverlay/overlayCtrlData.h
index 5395834..513ebb9 100644
--- a/liboverlay/overlayCtrlData.h
+++ b/liboverlay/overlayCtrlData.h
@@ -65,6 +65,8 @@
     void setTransform(const utils::eTransform& p);
     /* set mdp position using dim */
     void setPosition(const utils::Dim& dim);
+    /* set mdp visual params using metadata */
+    bool setVisualParams(const MetaData_t &metadata);
     /* mdp set overlay/commit changes */
     bool commit();
 
@@ -171,6 +173,15 @@
     mMdp.setCrop(d);
 }
 
+inline bool Ctrl::setVisualParams(const MetaData_t &metadata)
+{
+    if (!mMdp.setVisualParams(metadata)) {
+        ALOGE("Ctrl setVisualParams failed in MDP setVisualParams");
+        return false;
+    }
+    return true;
+}
+
 inline void Ctrl::dump() const {
     ALOGE("== Dump Ctrl start ==");
     mMdp.dump();
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index d96066b..ee8bf51 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -18,6 +18,13 @@
 #include <mdp_version.h>
 #include "overlayUtils.h"
 #include "overlayMdp.h"
+#include "mdp_version.h"
+
+#define HSIC_SETTINGS_DEBUG 0
+
+static inline bool isEqual(float f1, float f2) {
+        return ((int)(f1*100) == (int)(f2*100)) ? true : false;
+}
 
 namespace ovutils = overlay::utils;
 namespace overlay {
@@ -53,6 +60,15 @@
     mLkgo.id = MSMFB_NEW_REQUEST;
     mOrientation = utils::OVERLAY_TRANSFORM_0;
     mDownscale = 0;
+#ifdef USES_POST_PROCESSING
+    mPPChanged = false;
+    memset(&mParams, 0, sizeof(struct compute_params));
+    mParams.params.conv_params.order = hsic_order_hsc_i;
+    mParams.params.conv_params.interface = interface_rec601;
+    mParams.params.conv_params.cc_matrix[0][0] = 1;
+    mParams.params.conv_params.cc_matrix[1][1] = 1;
+    mParams.params.conv_params.cc_matrix[2][2] = 1;
+#endif
 }
 
 bool MdpCtrl::close() {
@@ -63,7 +79,11 @@
             result = false;
         }
     }
-
+#ifdef USES_POST_PROCESSING
+    /* free allocated memory in PP */
+    if (mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data)
+            free(mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data);
+#endif
     reset();
 
     if(!mFd.close()) {
@@ -191,4 +211,120 @@
     ALOGE("== Dump MdpCtrl end ==");
 }
 
+bool MdpCtrl::setVisualParams(const MetaData_t& data) {
+    bool needUpdate = false;
+#ifdef USES_POST_PROCESSING
+    /* calculate the data */
+    if (data.operation & PP_PARAM_HSIC) {
+        if (mParams.params.pa_params.hue != data.hsicData.hue) {
+            ALOGD_IF(HSIC_SETTINGS_DEBUG,
+                "Hue has changed from %d to %d",
+                mParams.params.pa_params.hue,data.hsicData.hue);
+            needUpdate = true;
+        }
+
+        if (!isEqual(mParams.params.pa_params.sat,
+            data.hsicData.saturation)) {
+            ALOGD_IF(HSIC_SETTINGS_DEBUG,
+                "Saturation has changed from %f to %f",
+                mParams.params.pa_params.sat,
+                data.hsicData.saturation);
+            needUpdate = true;
+        }
+
+        if (mParams.params.pa_params.intensity != data.hsicData.intensity) {
+            ALOGD_IF(HSIC_SETTINGS_DEBUG,
+                "Intensity has changed from %d to %d",
+                mParams.params.pa_params.intensity,
+                data.hsicData.intensity);
+            needUpdate = true;
+        }
+
+        if (!isEqual(mParams.params.pa_params.contrast,
+            data.hsicData.contrast)) {
+            ALOGD_IF(HSIC_SETTINGS_DEBUG,
+                "Contrast has changed from %f to %f",
+                mParams.params.pa_params.contrast,
+                data.hsicData.contrast);
+            needUpdate = true;
+        }
+
+        if (needUpdate) {
+            mParams.params.pa_params.hue = data.hsicData.hue;
+            mParams.params.pa_params.sat = data.hsicData.saturation;
+            mParams.params.pa_params.intensity = data.hsicData.intensity;
+            mParams.params.pa_params.contrast = data.hsicData.contrast;
+            mParams.params.pa_params.ops = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
+            mParams.operation |= PP_OP_PA;
+        }
+    }
+
+    if (data.operation & PP_PARAM_SHARP2) {
+        if (mParams.params.sharp_params.strength != data.Sharp2Data.strength) {
+            needUpdate = true;
+        }
+        if (mParams.params.sharp_params.edge_thr != data.Sharp2Data.edge_thr) {
+            needUpdate = true;
+        }
+        if (mParams.params.sharp_params.smooth_thr !=
+                data.Sharp2Data.smooth_thr) {
+            needUpdate = true;
+        }
+        if (mParams.params.sharp_params.noise_thr !=
+                data.Sharp2Data.noise_thr) {
+            needUpdate = true;
+        }
+
+        if (needUpdate) {
+            mParams.params.sharp_params.strength = data.Sharp2Data.strength;
+            mParams.params.sharp_params.edge_thr = data.Sharp2Data.edge_thr;
+            mParams.params.sharp_params.smooth_thr =
+                data.Sharp2Data.smooth_thr;
+            mParams.params.sharp_params.noise_thr = data.Sharp2Data.noise_thr;
+            mParams.params.sharp_params.ops =
+                MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
+            mParams.operation |= PP_OP_SHARP;
+        }
+    }
+
+    if (data.operation & PP_PARAM_IGC) {
+        if (mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data == NULL){
+            uint32_t *igcData
+                = (uint32_t *)malloc(2 * MAX_IGC_LUT_ENTRIES * sizeof(uint32_t));
+            if (!igcData) {
+                ALOGE("IGC storage allocated failed");
+                return false;
+            }
+            mOVInfo.overlay_pp_cfg.igc_cfg.c0_c1_data = igcData;
+            mOVInfo.overlay_pp_cfg.igc_cfg.c2_data
+                = igcData + MAX_IGC_LUT_ENTRIES;
+        }
+
+        memcpy(mParams.params.igc_lut_params.c0,
+            data.igcData.c0, sizeof(uint16_t) * MAX_IGC_LUT_ENTRIES);
+        memcpy(mParams.params.igc_lut_params.c1,
+            data.igcData.c1, sizeof(uint16_t) * MAX_IGC_LUT_ENTRIES);
+        memcpy(mParams.params.igc_lut_params.c2,
+            data.igcData.c2, sizeof(uint16_t) * MAX_IGC_LUT_ENTRIES);
+
+        mParams.params.igc_lut_params.ops
+            = MDP_PP_OPS_WRITE | MDP_PP_OPS_ENABLE;
+        mParams.operation |= PP_OP_IGC;
+        needUpdate = true;
+    }
+
+    if (data.operation & PP_PARAM_VID_INTFC) {
+        mParams.params.conv_params.interface =
+            (interface_type) data.video_interface;
+        needUpdate = true;
+    }
+
+    if (needUpdate) {
+        display_pp_compute_params(&mParams, &mOVInfo.overlay_pp_cfg);
+        mPPChanged = true;
+    }
+#endif
+    return true;
+}
+
 } // overlay
diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h
index 08d744f..f77ffae 100644
--- a/liboverlay/overlayMdp.h
+++ b/liboverlay/overlayMdp.h
@@ -22,6 +22,10 @@
 
 #include "overlayUtils.h"
 #include "mdpWrapper.h"
+#include "qdMetaData.h"
+#ifdef USES_POST_PROCESSING
+#include "lib-postproc.h"
+#endif
 
 namespace overlay{
 
@@ -75,6 +79,8 @@
     utils::Dim getDstRectDim() const;
     /* returns a copy to src rect dim */
     utils::Dim getSrcRectDim() const;
+    /* setVisualParam */
+    bool setVisualParams(const MetaData_t& data);
 
 private:
     /* Perform transformation calculations */
@@ -119,6 +125,12 @@
     /* FD for the mdp fbnum */
     OvFD          mFd;
     int mDownscale;
+#ifdef USES_POST_PROCESSING
+    /* PP Compute Params */
+    struct compute_params mParams;
+    /* indicate if PP params have been changed */
+    bool mPPChanged;
+#endif
 };
 
 
@@ -227,6 +239,13 @@
 }
 
 inline bool MdpCtrl::ovChanged() const {
+#ifdef USES_POST_PROCESSING
+    // Some pp params are stored as pointer address,
+    // so can't compare their content directly.
+    if (mPPChanged) {
+        return true;
+    }
+#endif
     // 0 means same
     if(0 == ::memcmp(&mOVInfo, &mLkgo, sizeof (mdp_overlay))) {
         return false;
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index 3eabc1d..c189bb7 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -261,6 +261,7 @@
     OV_MDP_FLIP_H = MDP_FLIP_LR,
     OV_MDP_FLIP_V = MDP_FLIP_UD,
     OV_MDSS_MDP_RIGHT_MIXER = MDSS_MDP_RIGHT_MIXER,
+    OV_MDP_PP_EN = MDP_OVERLAY_PP_CFG_EN,
 };
 
 enum eZorder {
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index 9108acd..90697a7 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -115,6 +115,11 @@
     mCtrlData.ctrl.setPosition(d);
 }
 
+bool GenericPipe::setVisualParams(const MetaData_t &metadata)
+{
+        return mCtrlData.ctrl.setVisualParams(metadata);
+}
+
 bool GenericPipe::commit() {
     bool ret = false;
     int downscale_factor = utils::ROT_DS_NONE;
diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h
index c71f8d2..63ffd32 100644
--- a/liboverlay/pipes/overlayGenPipe.h
+++ b/liboverlay/pipes/overlayGenPipe.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+* Copyright (c) 2011-2013, 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
@@ -36,7 +36,6 @@
 
 namespace overlay {
 
-
 class GenericPipe : utils::NoCopy {
 public:
     /* ctor */
@@ -54,6 +53,8 @@
     void setTransform(const utils::eTransform& param);
     /* set mdp posision using dim */
     void setPosition(const utils::Dim& dim);
+    /* set visual param */
+    bool setVisualParams(const MetaData_t &metadata);
     /* commit changes to the overlay "set"*/
     bool commit();
     /* Data APIs */
diff --git a/libqdutils/qdMetaData.cpp b/libqdutils/qdMetaData.cpp
index a53ba07..cc7e44a 100644
--- a/libqdutils/qdMetaData.cpp
+++ b/libqdutils/qdMetaData.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 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
@@ -43,6 +43,10 @@
         ALOGE("%s: Bad fd for extra data!", __func__);
         return -1;
     }
+    if (!param) {
+        ALOGE("%s: input param is null!", __func__);
+        return -1;
+    }
     unsigned long size = ROUND_UP_PAGESIZE(sizeof(MetaData_t));
     void *base = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED,
         handle->fd_metadata, 0);
@@ -65,6 +69,12 @@
         case PP_PARAM_INTERLACED:
             data->interlaced = *((int32_t *)param);
             break;
+        case PP_PARAM_IGC:
+            memcpy((void *)&data->igcData, param, sizeof(IGCData_t));
+            break;
+        case PP_PARAM_SHARP2:
+            memcpy((void *)&data->Sharp2Data, param, sizeof(Sharp2Data_t));
+            break;
         default:
             ALOGE("Unknown paramType %d", paramType);
             break;
diff --git a/libqdutils/qdMetaData.h b/libqdutils/qdMetaData.h
index e60daed..bbca4b6 100644
--- a/libqdutils/qdMetaData.h
+++ b/libqdutils/qdMetaData.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 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
@@ -30,27 +30,45 @@
 #ifndef _QDMETADATA_H
 #define _QDMETADATA_H
 
+#define MAX_IGC_LUT_ENTRIES 256
 
-typedef struct {
+struct HSICData_t {
     int32_t hue;
     float   saturation;
     int32_t intensity;
     float   contrast;
-} HSICData_t;
+};
 
-typedef struct {
+struct Sharp2Data_t {
+    int32_t strength;
+    uint32_t edge_thr;
+    uint32_t smooth_thr;
+    uint32_t noise_thr;
+};
+
+struct IGCData_t{
+    uint16_t c0[MAX_IGC_LUT_ENTRIES];
+    uint16_t c1[MAX_IGC_LUT_ENTRIES];
+    uint16_t c2[MAX_IGC_LUT_ENTRIES];
+};
+
+struct MetaData_t {
     int32_t operation;
     int32_t interlaced;
     HSICData_t hsicData;
     int32_t sharpness;
     int32_t video_interface;
-} MetaData_t;
+    IGCData_t igcData;
+    Sharp2Data_t Sharp2Data;
+};
 
 typedef enum {
     PP_PARAM_HSIC       = 0x0001,
     PP_PARAM_SHARPNESS  = 0x0002,
     PP_PARAM_INTERLACED = 0x0004,
-    PP_PARAM_VID_INTFC  = 0x0008
+    PP_PARAM_VID_INTFC  = 0x0008,
+    PP_PARAM_IGC        = 0x0010,
+    PP_PARAM_SHARP2     = 0x0020,
 } DispParamType;
 
 int setMetaData(private_handle_t *handle, DispParamType paramType, void *param);