Merge "hwc: Add assertive display support."
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index 4b9d04b..87a7815 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -22,6 +22,7 @@
                                  hwc_mdpcomp.cpp  \
                                  hwc_copybit.cpp  \
                                  hwc_qclient.cpp  \
-                                 hwc_dump_layers.cpp
+                                 hwc_dump_layers.cpp \
+                                 hwc_ad.cpp
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 6dd77b1..09fef80 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -36,6 +36,7 @@
 #include "hwc_dump_layers.h"
 #include "external.h"
 #include "hwc_copybit.h"
+#include "hwc_ad.h"
 #include "profiler.h"
 
 using namespace qhwc;
@@ -107,6 +108,8 @@
         if(ctx->mCopyBit[i])
             ctx->mCopyBit[i]->reset();
     }
+
+    ctx->mAD->reset();
 }
 
 //clear prev layer prop flags and realloc for current frame
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
new file mode 100644
index 0000000..ef5980c
--- /dev/null
+++ b/libhwcomposer/hwc_ad.cpp
@@ -0,0 +1,261 @@
+/*
+* Copyright (c) 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
+* 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.
+*/
+
+#include <unistd.h>
+#include <overlay.h>
+#include <overlayUtils.h>
+#include <overlayWriteback.h>
+#include <mdp_version.h>
+#include "hwc_ad.h"
+#include "hwc_utils.h"
+#include "external.h"
+
+#define DEBUG 0
+using namespace overlay;
+using namespace overlay::utils;
+namespace qhwc {
+
+//Opens writeback framebuffer and returns fd.
+static int openWbFb() {
+    int wbFd = -1;
+    //Check opening which FB would connect LM to WB
+    const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
+    if(wbFbNum >= 0) {
+        char wbFbPath[256];
+        snprintf (wbFbPath, sizeof(wbFbPath),
+                "/sys/class/graphics/fb%d", wbFbNum);
+        //Opening writeback fb first time would create ad node if the device
+        //supports adaptive display
+        wbFd = open(wbFbPath, O_RDONLY);
+        if(wbFd < 0) {
+            ALOGE("%s: Failed to open /sys/class/graphics/fb%d with error %s",
+                    __func__, wbFbNum, strerror(errno));
+        }
+    } else {
+        ALOGD_IF(DEBUG, "%s: No writeback available", __func__);
+    }
+    return wbFd;
+}
+
+static inline void closeWbFb(int& fd) {
+    if(fd >= 0) {
+        close(fd);
+        fd = -1;
+    } else {
+        ALOGE("%s: Invalid fd %d", __func__, fd);
+    }
+}
+
+//Helper to write data to ad node
+static void adWrite(const int& value) {
+    const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
+    char wbFbPath[256];
+    snprintf (wbFbPath, sizeof(wbFbPath),
+            "/sys/class/graphics/fb%d/ad", wbFbNum);
+    int adFd = open(wbFbPath, O_WRONLY);
+    if(adFd >= 0) {
+        char opStr[4] = "";
+        snprintf(opStr, sizeof(opStr), "%d", value);
+        int ret = write(adFd, opStr, strlen(opStr));
+        if(ret < 0) {
+            ALOGE("%s: Failed to write %d with error %s",
+                    __func__, value, strerror(errno));
+        } else if (ret == 0){
+            ALOGE("%s Nothing written to ad", __func__);
+        } else {
+            ALOGD_IF(DEBUG, "%s: Wrote %d to ad", __func__, value);
+        }
+        close(adFd);
+    } else {
+        ALOGE("%s: Failed to open /sys/class/graphics/fb%d/ad with error %s",
+                __func__, wbFbNum, strerror(errno));
+    }
+}
+
+//Helper to read data from ad node
+static int adRead() {
+    const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
+    int ret = -1;
+    char wbFbPath[256];
+    snprintf (wbFbPath, sizeof(wbFbPath),
+            "/sys/class/graphics/fb%d/ad", wbFbNum);
+    int adFd = open(wbFbPath, O_RDONLY);
+    if(adFd >= 0) {
+        char opStr[4] = {'\0'};
+        if(read(adFd, opStr, strlen(opStr)) >= 0) {
+            //Should return -1, 0 or 1
+            ret = atoi(opStr);
+            ALOGD_IF(DEBUG, "%s: Read %d from ad", __func__, ret);
+        } else {
+            ALOGE("%s: Read from ad node failed with error %s", __func__,
+                    strerror(errno));
+        }
+        close(adFd);
+    } else {
+        ALOGE("%s: Failed to open /sys/class/graphics/fb%d/ad with error %s",
+                __func__, wbFbNum, strerror(errno));
+    }
+    return ret;
+}
+
+AssertiveDisplay::AssertiveDisplay() :mWbFd(-1), mDoable(false),
+        mFeatureEnabled(false), mDest(overlay::utils::OV_INVALID) {
+    int fd = openWbFb();
+    if(fd >= 0) {
+        //-1 means feature is disabled on device
+        // 0 means feature exists but turned off, will be turned on by hwc
+        // 1 means feature is turned on by hwc
+        if(adRead() >= 0) {
+            ALOGD_IF(DEBUG, "Assertive display feature supported");
+            mFeatureEnabled = true;
+        }
+        closeWbFb(fd);
+    }
+}
+
+void AssertiveDisplay::markDoable(hwc_context_t *ctx,
+        const hwc_display_contents_1_t* list) {
+    mDoable = false;
+    if(mFeatureEnabled &&
+        !ctx->mExtDisplay->isExternalConnected() &&
+        ctx->listStats[HWC_DISPLAY_PRIMARY].yuvCount == 1) {
+        int nYuvIndex = ctx->listStats[HWC_DISPLAY_PRIMARY].yuvIndices[0];
+        const hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
+        private_handle_t *hnd = (private_handle_t *)layer->handle;
+        if(hnd && hnd->width <= qdutils::MAX_DISPLAY_DIM) {
+            mDoable = true;
+        }
+    }
+}
+
+bool AssertiveDisplay::prepare(hwc_context_t *ctx,
+        const hwc_rect_t& crop,
+        const Whf& whf,
+        const private_handle_t *hnd) {
+    if(!isDoable()) {
+        if(isModeOn()) {
+            //Cleanup one time during this switch
+            const int off = 0;
+            adWrite(off);
+            closeWbFb(mWbFd);
+        }
+        return false;
+    }
+
+    ovutils::eDest dest = ctx->mOverlay->nextPipe(ovutils::OV_MDP_PIPE_VG,
+            overlay::Overlay::DPY_WRITEBACK, Overlay::MIXER_DEFAULT);
+    if(dest == OV_INVALID) {
+        ALOGE("%s failed: No VG pipe available", __func__);
+        mDoable = false;
+        return false;
+    }
+
+    overlay::Writeback *wb = overlay::Writeback::getInstance();
+
+    if(!wb->configureDpyInfo(hnd->width, hnd->height)) {
+        ALOGE("%s: config display failed", __func__);
+        mDoable = false;
+        return false;
+    }
+
+    int tmpW, tmpH, size;
+    int format = ovutils::getHALFormat(wb->getOutputFormat());
+    if(format < 0) {
+        ALOGE("%s invalid format %d", __func__, format);
+        mDoable = false;
+        return false;
+    }
+
+    size = getBufferSizeAndDimensions(hnd->width, hnd->height,
+                format, tmpW, tmpH);
+
+    if(!wb->configureMemory(size, isSecureBuffer(hnd))) {
+        ALOGE("%s: config memory failed", __func__);
+        mDoable = false;
+        return false;
+    }
+
+    eMdpFlags mdpFlags = OV_MDP_FLAGS_NONE;
+    if(isSecureBuffer(hnd)) {
+        ovutils::setMdpFlags(mdpFlags,
+                ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
+    }
+
+    PipeArgs parg(mdpFlags, whf, ZORDER_0, IS_FG_OFF,
+            ROT_FLAGS_NONE);
+    hwc_rect_t dst = crop; //input same as output
+
+    if(configMdp(ctx->mOverlay, parg, OVERLAY_TRANSFORM_0, crop, dst, NULL,
+                dest) < 0) {
+        ALOGE("%s: configMdp failed", __func__);
+        mDoable = false;
+        return false;
+    }
+
+    mDest = dest;
+    if(!isModeOn()) {
+        mWbFd = openWbFb();
+        if(mWbFd >= 0) {
+            //write to sysfs, one time during this switch
+            const int on = 1;
+            adWrite(on);
+        }
+    }
+    return true;
+}
+
+bool AssertiveDisplay::draw(hwc_context_t *ctx, int fd, uint32_t offset) {
+    if(!isDoable() || !isModeOn()) {
+        return false;
+    }
+
+    if (!ctx->mOverlay->queueBuffer(fd, offset, mDest)) {
+        ALOGE("%s: queueBuffer failed", __func__);
+        return false;
+    }
+
+    overlay::Writeback *wb = overlay::Writeback::getInstance();
+    if(!wb->writeSync()) {
+        return false;
+    }
+
+    return true;
+}
+
+int AssertiveDisplay::getDstFd(hwc_context_t *ctx) const {
+    overlay::Writeback *wb = overlay::Writeback::getInstance();
+    return wb->getDstFd();
+}
+
+uint32_t AssertiveDisplay::getDstOffset(hwc_context_t *ctx) const {
+    overlay::Writeback *wb = overlay::Writeback::getInstance();
+    return wb->getOffset();
+}
+
+}
diff --git a/libhwcomposer/hwc_ad.h b/libhwcomposer/hwc_ad.h
new file mode 100644
index 0000000..38b724d
--- /dev/null
+++ b/libhwcomposer/hwc_ad.h
@@ -0,0 +1,67 @@
+/*
+* Copyright (c) 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
+* 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.
+*/
+
+#ifndef HWC_AD_H
+#define HWC_AD_H
+
+#include <overlayUtils.h>
+#include <hwc_utils.h>
+
+struct hwc_context_t;
+
+namespace qhwc {
+
+class AssertiveDisplay {
+public:
+    AssertiveDisplay();
+    void markDoable(hwc_context_t *ctx, const hwc_display_contents_1_t* list);
+    bool prepare(hwc_context_t *ctx, const hwc_rect_t& crop,
+            const overlay::utils::Whf& whf,
+            const private_handle_t *hnd);
+    bool draw(hwc_context_t *ctx, int fd, uint32_t offset);
+    //Resets a few members on each draw round
+    void reset() { mDoable = false;
+            mDest = overlay::utils::OV_INVALID;
+    }
+    bool isDoable() const { return mDoable; }
+    bool isModeOn() const { return (mWbFd >= 0); }
+    int getDstFd(hwc_context_t *ctx) const;
+    uint32_t getDstOffset(hwc_context_t *ctx) const;
+
+private:
+    //State of feature turned on and off
+    int mWbFd;
+    bool mDoable;
+    //State of feature existence on certain devices and configs.
+    bool mFeatureEnabled;
+    overlay::utils::eDest mDest;
+};
+
+}
+#endif
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 69e81db..31b9645 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -23,6 +23,7 @@
 #include "qdMetaData.h"
 #include "mdp_version.h"
 #include "hwc_fbupdate.h"
+#include "hwc_ad.h"
 #include <overlayRotator.h>
 
 using namespace overlay;
@@ -453,6 +454,10 @@
                    return false;
     }
 
+    if(ctx->mAD->isDoable()) {
+        return false;
+    }
+
     //If all above hard conditions are met we can do full or partial MDP comp.
     bool ret = false;
     if(fullMDPComp(ctx, list)) {
@@ -955,6 +960,14 @@
 
         int fd = hnd->fd;
         uint32_t offset = hnd->offset;
+
+        if(ctx->mAD->isModeOn()) {
+            if(ctx->mAD->draw(ctx, fd, offset)) {
+                fd = ctx->mAD->getDstFd(ctx);
+                offset = ctx->mAD->getDstOffset(ctx);
+            }
+        }
+
         Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
         if(rot) {
             if(!rot->queueBuffer(fd, offset))
@@ -1150,6 +1163,13 @@
         int fd = hnd->fd;
         int offset = hnd->offset;
 
+        if(ctx->mAD->isModeOn()) {
+            if(ctx->mAD->draw(ctx, fd, offset)) {
+                fd = ctx->mAD->getDstFd(ctx);
+                offset = ctx->mAD->getDstOffset(ctx);
+            }
+        }
+
         if(rot) {
             rot->queueBuffer(fd, offset);
             fd = rot->getDstMemId();
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 1c881cb..2c02e5b 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -27,9 +27,11 @@
 #include <gralloc_priv.h>
 #include <overlay.h>
 #include <overlayRotator.h>
+#include <overlayWriteback.h>
 #include "hwc_utils.h"
 #include "hwc_mdpcomp.h"
 #include "hwc_fbupdate.h"
+#include "hwc_ad.h"
 #include "mdp_version.h"
 #include "hwc_copybit.h"
 #include "hwc_dump_layers.h"
@@ -161,6 +163,7 @@
     }
 
     MDPComp::init(ctx);
+    ctx->mAD = new AssertiveDisplay();
 
     ctx->vstate.enable = false;
     ctx->vstate.fakevsync = false;
@@ -234,6 +237,10 @@
             ctx->mLayerRotMap[i] = NULL;
         }
     }
+    if(ctx->mAD) {
+        delete ctx->mAD;
+        ctx->mAD = NULL;
+    }
 
 
 }
@@ -475,6 +482,9 @@
     if(prevYuvCount != ctx->listStats[dpy].yuvCount) {
         ctx->mVideoTransFlag = true;
     }
+    if(dpy == HWC_DISPLAY_PRIMARY) {
+        ctx->mAD->markDoable(ctx, list);
+    }
 }
 
 
@@ -991,6 +1001,13 @@
     setMdpFlags(layer, mdpFlags, downscale, transform);
     trimLayer(ctx, dpy, transform, crop, dst);
 
+    //Will do something only if feature enabled and conditions suitable
+    //hollow call otherwise
+    if(ctx->mAD->prepare(ctx, crop, whf, hnd)) {
+        overlay::Writeback *wb = overlay::Writeback::getInstance();
+        whf.format = wb->getOutputFormat();
+    }
+
     if(isYuvBuffer(hnd) && //if 90 component or downscale, use rot
             ((transform & HWC_TRANSFORM_ROT_90) || downscale)) {
         *rot = ctx->mRotMgr->getNext();
@@ -1069,6 +1086,13 @@
     setMdpFlags(layer, mdpFlagsL, 0, transform);
     trimLayer(ctx, dpy, transform, crop, dst);
 
+    //Will do something only if feature enabled and conditions suitable
+    //hollow call otherwise
+    if(ctx->mAD->prepare(ctx, crop, whf, hnd)) {
+        overlay::Writeback *wb = overlay::Writeback::getInstance();
+        whf.format = wb->getOutputFormat();
+    }
+
     if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
         (*rot) = ctx->mRotMgr->getNext();
         if((*rot) == NULL) return -1;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index e214aee..c4fd345 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -55,6 +55,7 @@
 class MDPComp;
 class CopyBit;
 class HwcDebug;
+class AssertiveDisplay;
 
 
 struct MDPInfo {
@@ -321,6 +322,7 @@
     qhwc::LayerProp *layerProp[HWC_NUM_DISPLAY_TYPES];
     qhwc::MDPComp *mMDPComp[HWC_NUM_DISPLAY_TYPES];
     qhwc::HwcDebug *mHwcDebug[HWC_NUM_DISPLAY_TYPES];
+    qhwc::AssertiveDisplay *mAD;
 
     // No animation on External display feature
     // Notifies hwcomposer about the device orientation before animation.
diff --git a/liboverlay/overlayWriteback.cpp b/liboverlay/overlayWriteback.cpp
index b6ed53c..f711ca6 100644
--- a/liboverlay/overlayWriteback.cpp
+++ b/liboverlay/overlayWriteback.cpp
@@ -73,12 +73,13 @@
 }
 
 //=========== class Writeback =================================================
-Writeback::Writeback() : mXres(0), mYres(0) {
+Writeback::Writeback() : mXres(0), mYres(0), mOpFmt(-1) {
     int fbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
     if(!utils::openDev(mFd, fbNum, Res::fbPath, O_RDWR)) {
         ALOGE("%s failed to init %s", __func__, Res::fbPath);
         return;
     }
+    queryOutputFormat();
     startSession();
 }
 
@@ -184,6 +185,17 @@
     return writeSync(mWbMem.getDstFd(), mWbMem.getOffset());
 }
 
+void Writeback::queryOutputFormat() {
+    struct msmfb_metadata metadata;
+    memset(&metadata, 0 , sizeof(metadata));
+    metadata.op = metadata_op_wb_format;
+    if (ioctl(mFd.getFD(), MSMFB_METADATA_GET, &metadata) < 0) {
+        ALOGE("Error retrieving MDP Writeback format");
+        return;
+    }
+    mOpFmt = metadata.data.mixer_cfg.writeback_format;
+}
+
 //static
 
 Writeback *Writeback::getInstance() {
diff --git a/liboverlay/overlayWriteback.h b/liboverlay/overlayWriteback.h
index fbfd889..6280391 100644
--- a/liboverlay/overlayWriteback.h
+++ b/liboverlay/overlayWriteback.h
@@ -81,6 +81,7 @@
     bool queueBuffer(int opFd, uint32_t opOffset);
     uint32_t getOffset() const { return mWbMem.getOffset(); }
     int getDstFd() const { return mWbMem.getDstFd(); }
+    int getOutputFormat() const { return mOpFmt; }
 
     static Writeback* getInstance();
     static void configBegin() { sUsed = false; }
@@ -93,11 +94,13 @@
     bool stopSession();
     //Actually block_until_write_done for the usage here.
     bool dequeueBuffer();
+    void queryOutputFormat();
     OvFD mFd;
     WritebackMem mWbMem;
     struct msmfb_data mFbData;
     int mXres;
     int mYres;
+    int mOpFmt;
 
     static bool sUsed;
     static Writeback *sWb;