Merge "hwc/overlay: Implement rotator caching"
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index f3243fc..944f152 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -1324,7 +1324,9 @@
             rotData.acq_fen_fd_cnt = 1; //1 ioctl call per rot session
         }
         int ret = 0;
-        ret = ioctl(rotFd, MSMFB_BUFFER_SYNC, &rotData);
+        if(not ctx->mLayerRotMap[dpy]->isRotCached(i))
+            ret = ioctl(rotFd, MSMFB_BUFFER_SYNC, &rotData);
+
         if(ret < 0) {
             ALOGE("%s: ioctl MSMFB_BUFFER_SYNC failed for rot sync, err=%s",
                     __FUNCTION__, strerror(errno));
@@ -2260,9 +2262,27 @@
     reset();
 }
 
+bool LayerRotMap::isRotCached(uint32_t index) const {
+    overlay::Rotator* rot = getRot(index);
+    hwc_layer_1_t* layer =  getLayer(index);
+
+    if(rot and layer and layer->handle) {
+        private_handle_t *hnd = (private_handle_t *)(layer->handle);
+        return (rot->isRotCached(hnd->fd,(uint32_t)(hnd->offset)));
+    }
+    return false;
+}
+
 void LayerRotMap::setReleaseFd(const int& fence) {
     for(uint32_t i = 0; i < mCount; i++) {
-        mRot[i]->setReleaseFd(dup(fence));
+        if(mRot[i] and mLayer[i] and mLayer[i]->handle) {
+            /* Ensure that none of the above (Rotator-instance,
+             * layer and layer-handle) are NULL*/
+            if(isRotCached(i))
+                mRot[i]->setPrevBufReleaseFd(dup(fence));
+            else
+                mRot[i]->setCurrBufReleaseFd(dup(fence));
+        }
     }
 }
 
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index ad71919..3648ba7 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -201,6 +201,7 @@
     uint32_t getCount() const;
     hwc_layer_1_t* getLayer(uint32_t index) const;
     overlay::Rotator* getRot(uint32_t index) const;
+    bool isRotCached(uint32_t index) const;
     void setReleaseFd(const int& fence);
 private:
     hwc_layer_1_t* mLayer[overlay::RotMgr::MAX_ROT_SESS];
diff --git a/liboverlay/overlayMdpRot.cpp b/liboverlay/overlayMdpRot.cpp
index 6105736..d322897 100755
--- a/liboverlay/overlayMdpRot.cpp
+++ b/liboverlay/overlayMdpRot.cpp
@@ -37,10 +37,18 @@
 
 void MdpRot::setRotations(uint32_t r) { mRotImgInfo.rotations = (uint8_t)r; }
 
+int MdpRot::getSrcMemId() const {
+    return mRotDataInfo.src.memory_id;
+}
+
 int MdpRot::getDstMemId() const {
     return mRotDataInfo.dst.memory_id;
 }
 
+uint32_t MdpRot::getSrcOffset() const {
+    return mRotDataInfo.src.offset;
+}
+
 uint32_t MdpRot::getDstOffset() const {
     return mRotDataInfo.dst.offset;
 }
@@ -147,7 +155,6 @@
             mRotImgInfo.enable = 0;
             return false;
         }
-        save();
         mRotDataInfo.session_id = mRotImgInfo.session_id;
     }
     return true;
@@ -238,7 +245,10 @@
 }
 
 bool MdpRot::queueBuffer(int fd, uint32_t offset) {
-    if(enabled()) {
+    if(enabled() and (not isRotCached(fd,offset))) {
+        int prev_fd = getSrcMemId();
+        uint32_t prev_offset = getSrcOffset();
+
         mRotDataInfo.src.memory_id = fd;
         mRotDataInfo.src.offset = offset;
 
@@ -249,14 +259,17 @@
 
         mRotDataInfo.dst.offset =
                 mMem.mRotOffset[mMem.mCurrIndex];
-        mMem.mCurrIndex =
-                (mMem.mCurrIndex + 1) % mMem.mem.numBufs();
 
         if(!overlay::mdp_wrapper::rotate(mFd.getFD(), mRotDataInfo)) {
             ALOGE("MdpRot failed rotate");
             dump();
+            mRotDataInfo.src.memory_id = prev_fd;
+            mRotDataInfo.src.offset = prev_offset;
             return false;
         }
+        save();
+        mMem.mCurrIndex =
+                (mMem.mCurrIndex + 1) % mMem.mem.numBufs();
     }
     return true;
 }
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index 8e55362..87e134a 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -51,10 +51,18 @@
 
 void MdssRot::setRotations(uint32_t flags) { mRotInfo.flags |= flags; }
 
+int MdssRot::getSrcMemId() const {
+    return mRotData.data.memory_id;
+}
+
 int MdssRot::getDstMemId() const {
     return mRotData.dst_data.memory_id;
 }
 
+uint32_t MdssRot::getSrcOffset() const {
+    return mRotData.data.offset;
+}
+
 uint32_t MdssRot::getDstOffset() const {
     return mRotData.dst_data.offset;
 }
@@ -81,6 +89,19 @@
 
 uint32_t MdssRot::getSessId() const { return mRotInfo.id; }
 
+void MdssRot::save() {
+    mLSRotInfo = mRotInfo;
+}
+
+bool MdssRot::rotConfChanged() const {
+    // 0 means same
+    if(0 == ::memcmp(&mRotInfo, &mLSRotInfo,
+                     sizeof (mdp_overlay))) {
+        return false;
+    }
+    return true;
+}
+
 bool MdssRot::init() {
     if(!utils::openDev(mFd, 0, Res::fbPath, O_RDWR)) {
         ALOGE("MdssRot failed to init fb0");
@@ -164,7 +185,10 @@
 }
 
 bool MdssRot::queueBuffer(int fd, uint32_t offset) {
-    if(enabled()) {
+    if(enabled() and (not isRotCached(fd,offset))) {
+        int prev_fd = getSrcMemId();
+        uint32_t prev_offset = getSrcOffset();
+
         mRotData.data.memory_id = fd;
         mRotData.data.offset = offset;
 
@@ -175,14 +199,17 @@
 
         mRotData.dst_data.offset =
                 mMem.mRotOffset[mMem.mCurrIndex];
-        mMem.mCurrIndex =
-                (mMem.mCurrIndex + 1) % mMem.mem.numBufs();
 
         if(!overlay::mdp_wrapper::play(mFd.getFD(), mRotData)) {
             ALOGE("MdssRot play failed!");
             dump();
+            mRotData.data.memory_id = prev_fd;
+            mRotData.data.offset = prev_offset;
             return false;
         }
+        save();
+        mMem.mCurrIndex =
+                (mMem.mCurrIndex + 1) % mMem.mem.numBufs();
     }
     return true;
 }
@@ -260,6 +287,7 @@
 
 void MdssRot::reset() {
     ovutils::memset0(mRotInfo);
+    ovutils::memset0(mLSRotInfo);
     ovutils::memset0(mRotData);
     mRotData.data.memory_id = -1;
     mRotInfo.id = MSMFB_NEW_REQUEST;
diff --git a/liboverlay/overlayRotator.cpp b/liboverlay/overlayRotator.cpp
index 06e9074..b55f06a 100644
--- a/liboverlay/overlayRotator.cpp
+++ b/liboverlay/overlayRotator.cpp
@@ -29,6 +29,17 @@
 
 //============Rotator=========================
 
+Rotator::Rotator() {
+    char property[PROPERTY_VALUE_MAX];
+    mRotCacheDisabled = false;
+    if((property_get("debug.rotcache.disable", property, NULL) > 0) &&
+       (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+        (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+        /* Used in debugging to turnoff rotator caching */
+        mRotCacheDisabled = true;
+    }
+}
+
 Rotator::~Rotator() {}
 
 Rotator* Rotator::getRotator() {
@@ -70,6 +81,20 @@
     return TYPE_MDP;
 }
 
+bool Rotator::isRotCached(int fd, uint32_t offset) const {
+    if(mRotCacheDisabled or rotConfChanged() or rotDataChanged(fd,offset))
+        return false;
+    return true;
+}
+
+bool Rotator::rotDataChanged(int fd, uint32_t offset) const {
+    /* fd and offset are the attributes of the current rotator input buffer.
+     * At this instance, getSrcMemId() and getSrcOffset() return the
+     * attributes of the previous rotator input buffer */
+    if( (fd == getSrcMemId()) and (offset == getSrcOffset()) )
+        return false;
+    return true;
+}
 
 //============RotMem=========================
 
@@ -98,7 +123,7 @@
     }
 }
 
-void RotMem::setReleaseFd(const int& fence) {
+void RotMem::setCurrBufReleaseFd(const int& fence) {
     int ret = 0;
 
     if(mRelFence[mCurrIndex] >= 0) {
@@ -116,6 +141,20 @@
     mRelFence[mCurrIndex] = fence;
 }
 
+void RotMem::setPrevBufReleaseFd(const int& fence) {
+    uint32_t numRotBufs = mem.numBufs();
+    uint32_t prevIndex = (mCurrIndex + numRotBufs - 1) % (numRotBufs);
+
+    if(mRelFence[prevIndex] >= 0) {
+        /* No need of any wait as nothing will be written into this
+         * buffer by the rotator (this func is called when rotator is
+         * in cache mode) */
+        ::close(mRelFence[prevIndex]);
+    }
+
+    mRelFence[prevIndex] = fence;
+}
+
 //============RotMgr=========================
 RotMgr * RotMgr::sRotMgr = NULL;
 
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index 3f09a23..e045b44 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -52,7 +52,8 @@
     bool close();
     bool valid() { return mem.valid(); }
     uint32_t size() const { return mem.bufSz(); }
-    void setReleaseFd(const int& fence);
+    void setCurrBufReleaseFd(const int& fence);
+    void setPrevBufReleaseFd(const int& fence);
 
     // rotator data info dst offset
     uint32_t mRotOffset[ROT_NUM_BUFS];
@@ -72,9 +73,20 @@
     virtual void setFlags(const utils::eMdpFlags& flags) = 0;
     virtual void setTransform(const utils::eTransform& rot) = 0;
     virtual bool commit() = 0;
+    /* return true if the current rotator state is cached */
+    virtual bool isRotCached(int fd, uint32_t offset) const;
+    /* return true if current rotator config is same as the last round*/
+    virtual bool rotConfChanged() const = 0;
+    /* return true if the current rotator input buffer fd and offset
+     * are same as the last round */
+    virtual bool rotDataChanged(int fd, uint32_t offset) const;
     virtual void setDownscale(int ds) = 0;
+    /* returns the src buffer of the rotator for the previous/current round,
+     * depending on when it is called(before/after the queuebuffer)*/
+    virtual int getSrcMemId() const = 0;
     //Mem id and offset should be retrieved only after rotator kickoff
     virtual int getDstMemId() const = 0;
+    virtual uint32_t getSrcOffset() const = 0;
     virtual uint32_t getDstOffset() const = 0;
     //Destination width, height, format, position should be retrieved only after
     //rotator configuration is committed via commit API
@@ -85,7 +97,12 @@
     virtual bool queueBuffer(int fd, uint32_t offset) = 0;
     virtual void dump() const = 0;
     virtual void getDump(char *buf, size_t len) const = 0;
-    void setReleaseFd(const int& fence) { mMem.setReleaseFd(fence); }
+    inline void setCurrBufReleaseFd(const int& fence) {
+        mMem.setCurrBufReleaseFd(fence);
+    }
+    inline void setPrevBufReleaseFd(const int& fence) {
+        mMem.setPrevBufReleaseFd(fence);
+    }
     static Rotator *getRotator();
     /* Returns downscale by successfully applying constraints
      * Returns 0 if target doesnt support rotator downscaling
@@ -98,10 +115,11 @@
 protected:
     /* Rotator memory manager */
     RotMem mMem;
-    explicit Rotator() {}
+    Rotator();
     static uint32_t calcOutputBufSize(const utils::Whf& destWhf);
 
 private:
+    bool mRotCacheDisabled;
     /*Returns rotator h/w type */
     static int getRotatorHwType();
     friend class RotMgr;
@@ -119,8 +137,11 @@
     virtual void setFlags(const utils::eMdpFlags& flags);
     virtual void setTransform(const utils::eTransform& rot);
     virtual bool commit();
+    virtual bool rotConfChanged() const;
     virtual void setDownscale(int ds);
+    virtual int getSrcMemId() const;
     virtual int getDstMemId() const;
+    virtual uint32_t getSrcOffset() const;
     virtual uint32_t getDstOffset() const;
     virtual uint32_t getDstFormat() const;
     virtual utils::Whf getDstWhf() const;
@@ -143,9 +164,6 @@
     void doTransform();
     /* reset underlying data, basically memset 0 */
     void reset();
-    /* return true if current rotator config is different
-     * than last known config */
-    bool rotConfChanged() const;
     /* save mRotImgInfo to be last known good config*/
     void save();
     /* Calculates the rotator's o/p buffer size post the transform calcs and
@@ -191,8 +209,11 @@
     virtual void setFlags(const utils::eMdpFlags& flags);
     virtual void setTransform(const utils::eTransform& rot);
     virtual bool commit();
+    virtual bool rotConfChanged() const;
     virtual void setDownscale(int ds);
+    virtual int getSrcMemId() const;
     virtual int getDstMemId() const;
+    virtual uint32_t getSrcOffset() const;
     virtual uint32_t getDstOffset() const;
     virtual uint32_t getDstFormat() const;
     virtual utils::Whf getDstWhf() const;
@@ -215,6 +236,8 @@
     void doTransform();
     /* reset underlying data, basically memset 0 */
     void reset();
+    /* save mRotInfo to be last known good config*/
+    void save();
     /* Calculates the rotator's o/p buffer size post the transform calcs and
      * knowing the o/p format depending on whether fastYuv is enabled or not */
     uint32_t calcOutputBufSize();
@@ -241,7 +264,9 @@
             const uint32_t& downscale);
 
     /* MdssRot info structure */
-    mdp_overlay   mRotInfo;
+    mdp_overlay mRotInfo;
+    /* Last saved MdssRot info structure*/
+    mdp_overlay mLSRotInfo;
     /* MdssRot data structure */
     msmfb_overlay_data mRotData;
     /* Orientation */