hwc: Use intermediate buffers for copybit

The earlier copybit solution involved blitting directly into
the SurfaceFlinger's framebuffer target. That solution involved
unnecessary framework changes and caused issues when the
framebuffer was being written to both by GL and copybit.
Update hwc_copybit to use our own buffers for this purpose.
We also make sure we display only the region we're interested in
so that unnecessary artifacts from previous blits do not show up
on the display. This way, we can avoid clearing the intermediate
buffers every frame.

Change-Id: I713b3fc606e0768444c621af76853ece41964da1
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index c2688b5..593bc09 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -17,13 +17,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #include <fcntl.h>
 #include <errno.h>
 
 #include <cutils/log.h>
 #include <cutils/atomic.h>
 #include <EGL/egl.h>
+#include <utils/Trace.h>
 
 #include <overlay.h>
 #include <fb_priv.h>
@@ -136,7 +137,7 @@
             if(!ret) {
                 // IF MDPcomp fails use this route
                 VideoOverlay::prepare(ctx, list, dpy);
-                ctx->mFBUpdate[dpy]->prepare(ctx, fbLayer);
+                ctx->mFBUpdate[dpy]->prepare(ctx, list);
             }
             ctx->mLayerCache[dpy]->updateLayerCache(list);
             // Use Copybit, when MDP comp fails
@@ -161,7 +162,7 @@
                 setListStats(ctx, list, dpy);
                 reset_layer_prop(ctx, dpy);
                 VideoOverlay::prepare(ctx, list, dpy);
-                ctx->mFBUpdate[dpy]->prepare(ctx, fbLayer);
+                ctx->mFBUpdate[dpy]->prepare(ctx, list);
                 ctx->mLayerCache[dpy]->updateLayerCache(list);
                 if(ctx->mCopyBit[dpy])
                     ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
@@ -234,6 +235,7 @@
 
 static int hwc_blank(struct hwc_composer_device_1* dev, int dpy, int blank)
 {
+    ATRACE_CALL();
     hwc_context_t* ctx = (hwc_context_t*)(dev);
     private_module_t* m = reinterpret_cast<private_module_t*>(
         ctx->mFbDev->common.module);
@@ -309,6 +311,7 @@
 }
 
 static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+    ATRACE_CALL();
     int ret = 0;
     const int dpy = HWC_DISPLAY_PRIMARY;
 
@@ -316,8 +319,9 @@
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
         int fd = -1; //FenceFD from the Copybit(valid in async mode)
+        bool copybitDone = false;
         if(ctx->mCopyBit[dpy])
-            ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
+            copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
         if(list->numHwLayers > 1)
             hwc_sync(ctx, list, dpy, fd);
         if (!VideoOverlay::draw(ctx, list, dpy)) {
@@ -331,11 +335,16 @@
 
         //TODO We dont check for SKIP flag on this layer because we need PAN
         //always. Last layer is always FB
-        private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
+        private_handle_t *hnd = NULL;
+        if(copybitDone) {
+            hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
+        } else {
+            hnd = (private_handle_t *)fbLayer->handle;
+        }
         if(fbLayer->compositionType == HWC_FRAMEBUFFER_TARGET && hnd) {
             if(!(fbLayer->flags & HWC_SKIP_LAYER) &&
                 (list->numHwLayers > 1)) {
-                if (!ctx->mFBUpdate[dpy]->draw(ctx, fbLayer)) {
+                if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
                     ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
                     ret = -1;
                 }
@@ -352,7 +361,9 @@
 }
 
 static int hwc_set_external(hwc_context_t *ctx,
-        hwc_display_contents_1_t* list, int dpy) {
+                            hwc_display_contents_1_t* list, int dpy)
+{
+    ATRACE_CALL();
     int ret = 0;
     Locker::Autolock _l(ctx->mExtSetLock);
 
@@ -362,8 +373,9 @@
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
         int fd = -1; //FenceFD from the Copybit(valid in async mode)
+        bool copybitDone = false;
         if(ctx->mCopyBit[dpy])
-            ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
+            copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
 
         if(list->numHwLayers > 1)
             hwc_sync(ctx, list, dpy, fd);
@@ -373,11 +385,17 @@
             ret = -1;
         }
 
-        private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
+        private_handle_t *hnd = NULL;
+        if(copybitDone) {
+            hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
+        } else {
+            hnd = (private_handle_t *)fbLayer->handle;
+        }
+
         if(fbLayer->compositionType == HWC_FRAMEBUFFER_TARGET &&
                 !(fbLayer->flags & HWC_SKIP_LAYER) && hnd &&
                 (list->numHwLayers > 1)) {
-            if (!ctx->mFBUpdate[dpy]->draw(ctx, fbLayer)) {
+            if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
                 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
                 ret = -1;
             }
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 8ce9f0d..4549dcf 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -23,11 +23,7 @@
 #include <utils/Timers.h>
 #include "hwc_copybit.h"
 #include "comptype.h"
-
-//XXX: Remove HWC_BLIT
-#ifndef QCOM_BSP
-#define HWC_BLIT 4
-#endif
+#include "gr.h"
 
 namespace qhwc {
 
@@ -164,27 +160,42 @@
 
     bool useCopybitForYUV = canUseCopybitForYUV(ctx);
     bool useCopybitForRGB = canUseCopybitForRGB(ctx, list, dpy);
+    LayerProp *layerProp = ctx->layerProp[dpy];
+    size_t fbLayerIndex = ctx->listStats[dpy].fbLayerIndex;
+    hwc_layer_1_t *fbLayer = &list->hwLayers[fbLayerIndex];
+    private_handle_t *fbHnd = (private_handle_t *)fbLayer->handle;
+
+
+
+    //Allocate render buffers if they're not allocated
+    if (useCopybitForYUV || useCopybitForRGB) {
+        int ret = allocRenderBuffers(fbHnd->width,
+                                     fbHnd->height,
+                                     fbHnd->format);
+        if (ret < 0) {
+            return false;
+        } else {
+            mCurRenderBufferIndex = (mCurRenderBufferIndex + 1) %
+                NUM_RENDER_BUFFERS;
+        }
+    }
+
 
     // numAppLayers-1, as we iterate till 0th layer index
     for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
         private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
 
-        if (hnd->bufferType == BUFFER_TYPE_VIDEO) {
-            //YUV layer, check, if copybit can be used
-            // mark the video layer to gpu when all layer is
-            // going to gpu in case of dynamic composition.
-            if (useCopybitForYUV) {
-                list->hwLayers[i].compositionType = HWC_BLIT;
-                mCopyBitDraw = true;
-            }
-        } else if (hnd->bufferType == BUFFER_TYPE_UI) {
-            //RGB layer, check, if copybit can be used
-            if (useCopybitForRGB) {
-                ALOGD_IF(DEBUG_COPYBIT, "%s: Marking layer[%d] for copybit for"
-                                "dpy[%d] ", __FUNCTION__, i, dpy);
-                list->hwLayers[i].compositionType = HWC_BLIT;
-                mCopyBitDraw = true;
-            }
+        if ((hnd->bufferType == BUFFER_TYPE_VIDEO && useCopybitForYUV) ||
+            (hnd->bufferType == BUFFER_TYPE_UI && useCopybitForRGB)) {
+            layerProp[i].mFlags |= HWC_COPYBIT;
+            list->hwLayers[i].compositionType = HWC_OVERLAY;
+            mCopyBitDraw = true;
+        } else {
+            // We currently cannot mix copybit layers with layers marked to
+            // be drawn on the framebuffer or that are on the layer cache.
+            mCopyBitDraw = false;
+            //There is no need to reset layer properties here as we return in
+            //draw if mCopyBitDraw is false
         }
     }
     return true;
@@ -195,23 +206,29 @@
     // draw layers marked for COPYBIT
     int retVal = true;
     int copybitLayerCount = 0;
+    LayerProp *layerProp = ctx->layerProp[dpy];
 
     if(mCopyBitDraw == false) // there is no layer marked for copybit
-        return true ;
+        return false ;
 
-    size_t fbLayerIndex = ctx->listStats[dpy].fbLayerIndex;
-    hwc_layer_1_t *fbLayer = &list->hwLayers[fbLayerIndex];
     //render buffer
-    private_handle_t *renderBuffer = (private_handle_t *)fbLayer->handle;
+    private_handle_t *renderBuffer = getCurrentRenderBuffer();
     if (!renderBuffer) {
-        ALOGE("%s: HWC_FRAMEBUFFER_TARGET layer handle is NULL", __FUNCTION__);
+        ALOGE("%s: Render buffer layer handle is NULL", __FUNCTION__);
         return false;
     }
-    // numAppLayers-1, as we iterate from 0th layer index with HWC_BLIT flag
+
+    //Wait for the previous frame to complete before rendering onto it
+    if(mRelFd[0] >=0) {
+        sync_wait(mRelFd[0], 1000);
+        close(mRelFd[0]);
+        mRelFd[0] = -1;
+    }
+    // numAppLayers-1, as we iterate from 0th layer index with HWC_COPYBIT flag
     for (int i = 0; i <= (ctx->listStats[dpy].numAppLayers-1); i++) {
         hwc_layer_1_t *layer = &list->hwLayers[i];
-        if(!list->hwLayers[i].compositionType == HWC_BLIT) {
-            ALOGD_IF(DEBUG_COPYBIT, "%s: Not Marked for C2D", __FUNCTION__);
+        if(!(layerProp[i].mFlags & HWC_COPYBIT)) {
+            ALOGD_IF(DEBUG_COPYBIT, "%s: Not Marked for copybit", __FUNCTION__);
             continue;
         }
         int ret = -1;
@@ -372,7 +389,7 @@
        }
        ALOGE("%s:%d::tmp_w = %d,tmp_h = %d",__FUNCTION__,__LINE__,tmp_w,tmp_h);
 
-       int usage = GRALLOC_USAGE_PRIVATE_MM_HEAP;
+       int usage = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP;
 
        if (0 == alloc_buffer(&tmpHnd, tmp_w, tmp_h, fbHandle->format, usage)){
             copybit_image_t tmp_dst;
@@ -463,12 +480,55 @@
 }
 
 
+int CopyBit::allocRenderBuffers(int w, int h, int f)
+{
+    int ret = 0;
+    for (int i = 0; i < NUM_RENDER_BUFFERS; i++) {
+        if (mRenderBuffer[i] == NULL) {
+            ret = alloc_buffer(&mRenderBuffer[i],
+                               w, h, f,
+                               GRALLOC_USAGE_PRIVATE_IOMMU_HEAP);
+        }
+        if(ret < 0) {
+            freeRenderBuffers();
+            break;
+        }
+    }
+    return ret;
+}
+
+void CopyBit::freeRenderBuffers()
+{
+    for (int i = 0; i < NUM_RENDER_BUFFERS; i++) {
+        if(mRenderBuffer[i]) {
+            free_buffer(mRenderBuffer[i]);
+            mRenderBuffer[i] = NULL;
+        }
+    }
+}
+
+private_handle_t * CopyBit::getCurrentRenderBuffer() {
+    return mRenderBuffer[mCurRenderBufferIndex];
+}
+
+void CopyBit::setReleaseFd(int fd) {
+    if(mRelFd[0] >=0)
+        close(mRelFd[0]);
+    mRelFd[0] = mRelFd[1];
+    mRelFd[1] = dup(fd);
+}
+
 struct copybit_device_t* CopyBit::getCopyBitDevice() {
     return mEngine;
 }
 
-CopyBit::CopyBit():mIsModeOn(false), mCopyBitDraw(false){
+CopyBit::CopyBit():mIsModeOn(false), mCopyBitDraw(false),
+    mCurRenderBufferIndex(0){
     hw_module_t const *module;
+    for (int i = 0; i < NUM_RENDER_BUFFERS; i++)
+        mRenderBuffer[i] = NULL;
+    mRelFd[0] = -1;
+    mRelFd[1] = -1;
     if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
         if(copybit_open(module, &mEngine) < 0) {
             ALOGE("FATAL ERROR: copybit open failed.");
@@ -480,6 +540,11 @@
 
 CopyBit::~CopyBit()
 {
+    freeRenderBuffers();
+    if(mRelFd[0] >=0)
+        close(mRelFd[0]);
+    if(mRelFd[1] >=0)
+        close(mRelFd[1]);
     if(mEngine)
     {
         copybit_close(mEngine);
diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h
index 015d85a..45d254a 100644
--- a/libhwcomposer/hwc_copybit.h
+++ b/libhwcomposer/hwc_copybit.h
@@ -21,8 +21,7 @@
 #define HWC_COPYBIT_H
 #include "hwc_utils.h"
 
-#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
-#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
+#define NUM_RENDER_BUFFERS 2
 
 namespace qhwc {
 
@@ -40,6 +39,11 @@
                                                         int dpy, int* fd);
     // resets the values
     void reset();
+
+    private_handle_t * getCurrentRenderBuffer();
+
+    void setReleaseFd(int fd);
+
 private:
     // holds the copybit device
     struct copybit_device_t *mEngine;
@@ -61,6 +65,19 @@
 
     void getLayerResolution(const hwc_layer_1_t* layer,
                                    unsigned int &width, unsigned int& height);
+
+    int allocRenderBuffers(int w, int h, int f);
+
+    void freeRenderBuffers();
+
+    private_handle_t* mRenderBuffer[NUM_RENDER_BUFFERS];
+
+    // Index of the current intermediate render buffer
+    int mCurRenderBufferIndex;
+
+    //These are the the release FDs of the T-2 and T-1 round
+    //We wait on the T-2 fence
+    int mRelFd[2];
 };
 
 }; //namespace qhwc
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index a0dbbe3..f9161a3 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -46,21 +46,24 @@
     mDest = ovutils::OV_INVALID;
 }
 
-bool FBUpdateLowRes::prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer) {
+bool FBUpdateLowRes::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list)
+{
     if(!ctx->mMDP.hasOverlay) {
         ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
                 __FUNCTION__);
        return false;
     }
-    mModeOn = configure(ctx, fblayer);
+    mModeOn = configure(ctx, list);
     ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
     return mModeOn;
 }
 
 // Configure
-bool FBUpdateLowRes::configure(hwc_context_t *ctx, hwc_layer_1_t *layer)
+bool FBUpdateLowRes::configure(hwc_context_t *ctx,
+                               hwc_display_contents_1 *list)
 {
     bool ret = false;
+    hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
     if (LIKELY(ctx->mOverlay)) {
         overlay::Overlay& ov = *(ctx->mOverlay);
         private_handle_t *hnd = (private_handle_t *)layer->handle;
@@ -87,7 +90,8 @@
                 ovutils::ROT_FLAGS_NONE);
         ov.setSource(parg, dest);
 
-        hwc_rect_t sourceCrop = layer->sourceCrop;
+        hwc_rect_t sourceCrop;
+        getNonWormholeRegion(list, sourceCrop);
         // x,y,w,h
         ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
                 sourceCrop.right - sourceCrop.left,
@@ -99,7 +103,7 @@
                 static_cast<ovutils::eTransform>(transform);
         ov.setTransform(orient, dest);
 
-        hwc_rect_t displayFrame = layer->displayFrame;
+        hwc_rect_t displayFrame = sourceCrop;
         ovutils::Dim dpos(displayFrame.left,
                 displayFrame.top,
                 displayFrame.right - displayFrame.left,
@@ -118,7 +122,7 @@
     return ret;
 }
 
-bool FBUpdateLowRes::draw(hwc_context_t *ctx, hwc_layer_1_t *layer)
+bool FBUpdateLowRes::draw(hwc_context_t *ctx, private_handle_t *hnd)
 {
     if(!mModeOn) {
         return true;
@@ -126,7 +130,6 @@
     bool ret = true;
     overlay::Overlay& ov = *(ctx->mOverlay);
     ovutils::eDest dest = mDest;
-    private_handle_t *hnd = (private_handle_t *)layer->handle;
     if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) {
         ALOGE("%s: queueBuffer failed for FBUpdate", __FUNCTION__);
         ret = false;
@@ -143,21 +146,24 @@
     mDestRight = ovutils::OV_INVALID;
 }
 
-bool FBUpdateHighRes::prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer) {
+bool FBUpdateHighRes::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list)
+{
     if(!ctx->mMDP.hasOverlay) {
         ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
                 __FUNCTION__);
        return false;
     }
     ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
-    mModeOn = configure(ctx, fblayer);
+    mModeOn = configure(ctx, list);
     return mModeOn;
 }
 
 // Configure
-bool FBUpdateHighRes::configure(hwc_context_t *ctx, hwc_layer_1_t *layer)
+bool FBUpdateHighRes::configure(hwc_context_t *ctx,
+                                hwc_display_contents_1 *list)
 {
     bool ret = false;
+    hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
     if (LIKELY(ctx->mOverlay)) {
         overlay::Overlay& ov = *(ctx->mOverlay);
         private_handle_t *hnd = (private_handle_t *)layer->handle;
@@ -199,7 +205,8 @@
                 ovutils::ROT_FLAGS_NONE);
         ov.setSource(pargR, destR);
 
-        hwc_rect_t sourceCrop = layer->sourceCrop;
+        hwc_rect_t sourceCrop;
+        getNonWormholeRegion(list, sourceCrop);
         ovutils::Dim dcropL(sourceCrop.left, sourceCrop.top,
                 (sourceCrop.right - sourceCrop.left) / 2,
                 sourceCrop.bottom - sourceCrop.top);
@@ -217,7 +224,7 @@
         ov.setTransform(orient, destL);
         ov.setTransform(orient, destR);
 
-        hwc_rect_t displayFrame = layer->displayFrame;
+        hwc_rect_t displayFrame = sourceCrop;
         //For FB left, top will always be 0
         //That should also be the case if using 2 mixers for single display
         ovutils::Dim dpos(displayFrame.left,
@@ -240,7 +247,7 @@
     return ret;
 }
 
-bool FBUpdateHighRes::draw(hwc_context_t *ctx, hwc_layer_1_t *layer)
+bool FBUpdateHighRes::draw(hwc_context_t *ctx, private_handle_t *hnd)
 {
     if(!mModeOn) {
         return true;
@@ -249,7 +256,6 @@
     overlay::Overlay& ov = *(ctx->mOverlay);
     ovutils::eDest destL = mDestLeft;
     ovutils::eDest destR = mDestRight;
-    private_handle_t *hnd = (private_handle_t *)layer->handle;
     if (!ov.queueBuffer(hnd->fd, hnd->offset, destL)) {
         ALOGE("%s: queue failed for left of dpy = %d",
                 __FUNCTION__, mDpy);
diff --git a/libhwcomposer/hwc_fbupdate.h b/libhwcomposer/hwc_fbupdate.h
index a30a3af..5fc7708 100644
--- a/libhwcomposer/hwc_fbupdate.h
+++ b/libhwcomposer/hwc_fbupdate.h
@@ -34,9 +34,9 @@
     explicit IFBUpdate(const int& dpy) : mDpy(dpy) {}
     virtual ~IFBUpdate() {};
     // Sets up members and prepares overlay if conditions are met
-    virtual bool prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer) = 0;
+    virtual bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list) = 0;
     // Draws layer
-    virtual bool draw(hwc_context_t *ctx, hwc_layer_1_t *fblayer) = 0;
+    virtual bool draw(hwc_context_t *ctx, private_handle_t *hnd) = 0;
     //Reset values
     virtual void reset();
     //Factory method that returns a low-res or high-res version
@@ -52,11 +52,12 @@
 public:
     explicit FBUpdateLowRes(const int& dpy);
     virtual ~FBUpdateLowRes() {};
-    bool prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
-    bool draw(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
+    bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list);
+
+    bool draw(hwc_context_t *ctx, private_handle_t *hnd);
     void reset();
 private:
-    bool configure(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
+    bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list);
     ovutils::eDest mDest; //pipe to draw on
 };
 
@@ -65,11 +66,11 @@
 public:
     explicit FBUpdateHighRes(const int& dpy);
     virtual ~FBUpdateHighRes() {};
-    bool prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
-    bool draw(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
+    bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list);
+    bool draw(hwc_context_t *ctx, private_handle_t *hnd);
     void reset();
 private:
-    bool configure(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
+    bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list);
     ovutils::eDest mDestLeft; //left pipe to draw on
     ovutils::eDest mDestRight; //right pipe to draw on
 };
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 82ab25c..5193644 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -364,6 +364,33 @@
     crop_b -= crop_h * bottomCutRatio;
 }
 
+void getNonWormholeRegion(hwc_display_contents_1_t* list,
+                              hwc_rect_t& nwr)
+{
+    uint32_t last = list->numHwLayers - 1;
+    hwc_rect_t fbDisplayFrame = list->hwLayers[last].displayFrame;
+    //Initiliaze nwr to first frame
+    nwr.left =  list->hwLayers[0].displayFrame.left;
+    nwr.top =  list->hwLayers[0].displayFrame.top;
+    nwr.right =  list->hwLayers[0].displayFrame.right;
+    nwr.bottom =  list->hwLayers[0].displayFrame.bottom;
+
+    for (uint32_t i = 1; i < last; i++) {
+        hwc_rect_t displayFrame = list->hwLayers[i].displayFrame;
+        nwr.left   = min(nwr.left, displayFrame.left);
+        nwr.top    = min(nwr.top, displayFrame.top);
+        nwr.right  = max(nwr.right, displayFrame.right);
+        nwr.bottom = max(nwr.bottom, displayFrame.bottom);
+    }
+
+    //Intersect with the framebuffer
+    nwr.left   = max(nwr.left, fbDisplayFrame.left);
+    nwr.top    = max(nwr.top, fbDisplayFrame.top);
+    nwr.right  = min(nwr.right, fbDisplayFrame.right);
+    nwr.bottom = min(nwr.bottom, fbDisplayFrame.bottom);
+
+}
+
 bool isExternalActive(hwc_context_t* ctx) {
     return ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive;
 }
@@ -452,6 +479,8 @@
         fd = -1;
     }
 
+    if (ctx->mCopyBit[dpy])
+        ctx->mCopyBit[dpy]->setReleaseFd(releaseFd);
     if(UNLIKELY(swapzero)){
         list->retireFenceFd = -1;
         close(releaseFd);
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 671fbba..187c43a 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -56,6 +56,7 @@
 class MDPComp;
 class CopyBit;
 
+
 struct MDPInfo {
     int version;
     char panel;
@@ -97,6 +98,7 @@
 // LayerProp::flag values
 enum {
     HWC_MDPCOMP = 0x00000001,
+    HWC_COPYBIT = 0x00000002,
 };
 
 class LayerCache {
@@ -132,6 +134,8 @@
 //Crops source buffer against destination and FB boundaries
 void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
                          const hwc_rect_t& scissor, int orient);
+void getNonWormholeRegion(hwc_display_contents_1_t* list,
+                              hwc_rect_t& nwr);
 bool isSecuring(hwc_context_t* ctx);
 bool isSecureModePolicy(int mdpVersion);
 bool isExternalActive(hwc_context_t* ctx);
@@ -185,6 +189,9 @@
     return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_CC));
 }
 
+template<typename T> inline T max(T a, T b) { return (a > b) ? a : b; }
+template<typename T> inline T min(T a, T b) { return (a < b) ? a : b; }
+
 // Initialize uevent thread
 void init_uevent_thread(hwc_context_t* ctx);
 // Initialize vsync thread