Merge "hwc: Support for windowboxing feature on external"
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index aed9e3c..310e171 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -710,6 +710,16 @@
     const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
     int priDispW = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
 
+    // This is a special mode which needs to be handled separately.
+    // Only AIV tagged layers will be displayed on external in this mode.
+    // This is applicable only for external display , Return false, so that
+    // this will be handled separately
+    if(ctx->mAIVVideoMode[mDpy]) {
+        ALOGD_IF(isDebug(), "%s: AIV Video Mode enabled dpy %d",
+            __FUNCTION__, mDpy);
+        return false;
+    }
+
     // No Idle fall back, if secure display or secure RGB layers are present or
     // if there's only a single layer being composed
     if(sIdleFallBack && (!ctx->listStats[mDpy].secureUI &&
@@ -1251,8 +1261,55 @@
     return true;
 }
 
+bool MDPComp::tryAIVVideoMode(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list) {
+    if(sSimulationFlags & MDPCOMP_AVOID_AIV_VIDEO_MODE)
+        return false;
+    if(!ctx->mAIVVideoMode[mDpy]) {
+        return false;
+    }
+    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+
+    mCurrentFrame.reset(numAppLayers);
+    updateAIVLayers(ctx, list);
+    int mdpCount = mCurrentFrame.mdpCount;
+
+    if(mdpCount == 0) {
+        reset(ctx);
+        return false;
+    }
+
+    if(mCurrentFrame.fbCount) {
+        mCurrentFrame.fbZ = mCurrentFrame.mdpCount;
+    }
+
+    if(sEnableYUVsplit){
+        adjustForSourceSplit(ctx, list);
+    }
+
+    if(!postHeuristicsHandling(ctx, list)) {
+        ALOGD_IF(isDebug(), "post heuristic handling failed");
+        reset(ctx);
+        return false;
+    }
+
+    ALOGD_IF(sSimulationFlags,"%s: AIV_VIDEO_MODE_COMP SUCCEEDED",
+             __FUNCTION__);
+    return true;
+}
+
 bool MDPComp::tryVideoOnly(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
+    // This is a special mode which needs to be handled separately.
+    // Only AIV tagged layers will be displayed on external in this mode.
+    // This is applicable only for external display , Return false, so that
+    // this will be handled separately
+    if(ctx->mAIVVideoMode[mDpy]) {
+        ALOGD_IF(isDebug(), "%s: AIV Video Mode enabled dpy %d",
+            __FUNCTION__, mDpy);
+        return false;
+    }
+
     const bool secureOnly = true;
     return videoOnlyComp(ctx, list, not secureOnly) or
             videoOnlyComp(ctx, list, secureOnly);
@@ -1302,6 +1359,16 @@
 /* if tryFullFrame fails, try to push all video and secure RGB layers to MDP */
 bool MDPComp::tryMDPOnlyLayers(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
+    // This is a special mode which needs to be handled separately.
+    // Only AIV tagged layers will be displayed on external in this mode.
+    // This is applicable only for external display , Return false, so that
+    // this will be handled separately
+    if(ctx->mAIVVideoMode[mDpy]) {
+        ALOGD_IF(isDebug(), "%s: AIV Video Mode enabled dpy %d",
+            __FUNCTION__, mDpy);
+        return false;
+    }
+
     const bool secureOnly = true;
     return mdpOnlyLayersComp(ctx, list, not secureOnly) or
             mdpOnlyLayersComp(ctx, list, secureOnly);
@@ -1598,6 +1665,29 @@
             __FUNCTION__, frame.mdpCount, frame.fbCount, frame.dropCount);
 }
 
+// Mark AIV layers for composition and drop other non-AIV layers.
+void MDPComp::updateAIVLayers(hwc_context_t* ctx,
+                              hwc_display_contents_1_t* list) {
+    for (size_t i = 0; i < (size_t)ctx->listStats[mDpy].numAppLayers; i++) {
+        hwc_layer_1_t * layer = &list->hwLayers[i];
+        if(isAIVVideoLayer(layer)) {
+            if(isYUVDoable(ctx, layer)) {
+                mCurrentFrame.isFBComposed[i] = false;
+                mCurrentFrame.fbCount--;
+            }
+        } else if(!isAIVCCLayer(layer)) {
+            mCurrentFrame.dropCount++;
+            mCurrentFrame.drop[i] = true;
+        }
+    }
+    mCurrentFrame.fbCount -= mCurrentFrame.dropCount;
+    mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
+            mCurrentFrame.fbCount - mCurrentFrame.dropCount;
+    ALOGD_IF(isDebug(),"%s: fb count: %d mdp count %d drop count %d",
+        __FUNCTION__, mCurrentFrame.fbCount, mCurrentFrame.mdpCount,
+        mCurrentFrame.dropCount);
+}
+
 void MDPComp::updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list,
         bool secureOnly, FrameInfo& frame) {
     int nYuvCount = ctx->listStats[mDpy].yuvCount;
@@ -1877,7 +1967,7 @@
         // if tryFullFrame fails, try to push all video and secure RGB layers
         // to MDP for composition.
         mModeOn = tryFullFrame(ctx, list) || tryMDPOnlyLayers(ctx, list) ||
-                  tryVideoOnly(ctx, list);
+                  tryVideoOnly(ctx, list) || tryAIVVideoMode(ctx, list);
         if(mModeOn) {
             setMDPCompLayerFlags(ctx, list);
         } else {
@@ -2566,6 +2656,10 @@
         else if (hnd->format == HAL_PIXEL_FORMAT_RGBX_8888)
             whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888);
     }
+    // update source crop and destination position of AIV video layer.
+    if(ctx->mAIVVideoMode[mDpy] &&isYuvBuffer(hnd)) {
+        updateExtDisplayCoordinates(ctx, crop, dst, mDpy);
+    }
     /* Calculate the external display position based on MDP downscale,
        ActionSafe, and extorientation features. */
     calcExtDisplayPosition(ctx, hnd, mDpy, crop, dst, transform, orient);
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 3ed9186..5b47984 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -75,6 +75,7 @@
         MDPCOMP_AVOID_LOAD_MDP = 0x004,
         MDPCOMP_AVOID_VIDEO_ONLY = 0x008,
         MDPCOMP_AVOID_MDP_ONLY_LAYERS = 0x010,
+        MDPCOMP_AVOID_AIV_VIDEO_MODE = 0x020,
     };
 
     /* mdp pipe data */
@@ -187,6 +188,8 @@
     bool loadBasedComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     /* Checks if its worth doing load based partial comp */
     bool isLoadBasedCompDoable(hwc_context_t *ctx);
+    /* checks for conditions where AIV layers cannot be bypassed */
+    bool tryAIVVideoMode(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     /* checks for conditions where only video can be bypassed */
     bool tryVideoOnly(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     bool videoOnlyComp(hwc_context_t *ctx, hwc_display_contents_1_t* list,
@@ -222,6 +225,9 @@
     bool intersectingUpdatingLayers(const hwc_display_contents_1_t* list,
             int fromIndex, int toIndex, int targetLayerIndex);
 
+    /* Mark AIV layers for composition and drop other non-AIV layers.*/
+    void updateAIVLayers(hwc_context_t* ctx, hwc_display_contents_1_t* list);
+
         /* updates cache map with YUV info */
     void updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list,
             bool secureOnly, FrameInfo& frame);
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 7902199..f471872 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -370,6 +370,13 @@
     ctx->mGPUHintInfo.mCompositionState = COMPOSITION_STATE_MDP;
     ctx->mGPUHintInfo.mCurrGPUPerfMode = EGL_GPU_LEVEL_0;
 #endif
+    // Read the system property to determine if windowboxing feature is enabled.
+    ctx->mWindowboxFeature = false;
+    if(property_get("sys.hwc.windowbox_feature", value, "false")
+            && !strcmp(value, "true")) {
+        ctx->mWindowboxFeature = true;
+    }
+
     memset(&(ctx->mPtorInfo), 0, sizeof(ctx->mPtorInfo));
     ALOGI("Initializing Qualcomm Hardware Composer");
     ALOGI("MDP version: %d", ctx->mMDP.version);
@@ -959,6 +966,7 @@
     uint32_t refreshRate = 0;
     qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
 
+    ctx->mAIVVideoMode[dpy] = false;
     resetROI(ctx, dpy);
 
     trimList(ctx, list, dpy);
@@ -968,6 +976,9 @@
         private_handle_t *hnd = (private_handle_t *)layer->handle;
 
 #ifdef QCOM_BSP
+        if(ctx->mWindowboxFeature && dpy && isAIVVideoLayer(layer)) {
+            ctx->mAIVVideoMode[dpy] = true;
+        }
         if (layer->flags & HWC_SCREENSHOT_ANIMATOR_LAYER) {
             ctx->listStats[dpy].isDisplayAnimating = true;
         }
@@ -1819,6 +1830,66 @@
     return downscale;
 }
 
+bool isZoomModeEnabled(hwc_rect_t crop) {
+    // This does not work for zooming in top left corner of the image
+    return(crop.top > 0 || crop.left > 0);
+}
+
+void updateCropAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& crop, int dpy) {
+    ALOGD_IF(HWC_UTILS_DEBUG, "dpy %d Source crop [%d %d %d %d]", dpy,
+             crop.left, crop.top, crop.right, crop.bottom);
+    if(isZoomModeEnabled(crop)) {
+        Dim srcCrop(crop.left, crop.top,
+                crop.right - crop.left,
+                crop.bottom - crop.top);
+        int extW = ctx->dpyAttr[dpy].xres;
+        int extH = ctx->dpyAttr[dpy].yres;
+        //Crop the original video in order to fit external display aspect ratio
+        if(srcCrop.w * extH < extW * srcCrop.h) {
+            int offset = (srcCrop.h - ((srcCrop.w * extH) / extW)) / 2;
+            crop.top += offset;
+            crop.bottom -= offset;
+        } else {
+            int offset = (srcCrop.w - ((extW * srcCrop.h) / extH)) / 2;
+            crop.left += offset;
+            crop.right -= offset;
+        }
+        ALOGD_IF(HWC_UTILS_DEBUG, "External Resolution [%d %d] dpy %d Modified"
+                 " source crop [%d %d %d %d]", extW, extH, dpy,
+                 crop.left, crop.top, crop.right, crop.bottom);
+    }
+}
+
+void updateDestAIVVideoMode(hwc_context_t *ctx, hwc_rect_t crop,
+                           hwc_rect_t& dst, int dpy) {
+    ALOGD_IF(HWC_UTILS_DEBUG, "dpy %d Destination position [%d %d %d %d]", dpy,
+             dst.left, dst.top, dst.right, dst.bottom);
+    Dim srcCrop(crop.left, crop.top,
+            crop.right - crop.left,
+            crop.bottom - crop.top);
+    int extW = ctx->dpyAttr[dpy].xres;
+    int extH = ctx->dpyAttr[dpy].yres;
+    // Set the destination coordinates of external display to full screen,
+    // when zoom in mode is enabled or video aspect ratio matches with the
+    // external display aspect ratio
+    if((srcCrop.w * extH == extW * srcCrop.h) || (isZoomModeEnabled(crop))) {
+        dst.left = 0;
+        dst.top = 0;
+        dst.right = extW;
+        dst.bottom = extH;
+    }
+    ALOGD_IF(HWC_UTILS_DEBUG, "External Resolution [%d %d] dpy %d Modified"
+             " Destination position [%d %d %d %d] Source crop [%d %d %d %d]",
+             extW, extH, dpy, dst.left, dst.top, dst.right, dst.bottom,
+             crop.left, crop.top, crop.right, crop.bottom);
+}
+
+void updateExtDisplayCoordinates(hwc_context_t *ctx, hwc_rect_t& crop,
+                           hwc_rect_t& dst, int dpy) {
+    updateCropAIVVideoMode(ctx, crop, dpy);
+    updateDestAIVVideoMode(ctx, crop, dst, dpy);
+}
+
 int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
         const int& dpy, eMdpFlags& mdpFlags, eZorder& z,
         const eDest& dest, Rotator **rot) {
@@ -1851,7 +1922,10 @@
         else if (hnd->format == HAL_PIXEL_FORMAT_RGBX_8888)
             whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888);
     }
-
+    // update source crop and destination position of AIV video layer.
+    if(ctx->mAIVVideoMode[dpy] && isYuvBuffer(hnd)) {
+        updateExtDisplayCoordinates(ctx, crop, dst, dpy);
+    }
     calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
     int downscale = getRotDownscale(ctx, layer);
     setMdpFlags(ctx, layer, mdpFlags, downscale, transform);
@@ -1946,7 +2020,12 @@
             whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888);
     }
 
-    /* Calculate the external display position based on MDP scaling mode,
+    // update source crop and destination position of AIV video layer.
+    if(ctx->mAIVVideoMode[dpy] && isYuvBuffer(hnd)) {
+        updateExtDisplayCoordinates(ctx, crop, dst, dpy);
+    }
+
+    /* Calculate the external display position based on MDP downscale,
        ActionSafe, and extorientation features. */
     calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
     int downscale = getRotDownscale(ctx, layer);
@@ -2087,6 +2166,11 @@
     Whf whf(getWidth(hnd), getHeight(hnd),
             getMdpFormat(hnd->format), (uint32_t)hnd->size);
 
+    // update source crop and destination position of AIV video layer.
+    if(ctx->mAIVVideoMode[dpy] && isYuvBuffer(hnd)) {
+        updateExtDisplayCoordinates(ctx, crop, dst, dpy);
+    }
+
     /* Calculate the external display position based on MDP downscale,
        ActionSafe, and extorientation features. */
     calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 3d97319..c443bf8 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -182,6 +182,12 @@
     HWC_COPYBIT = 0x00000002,
 };
 
+// AIV specific flags
+enum {
+    HWC_AIV_VIDEO = 0x80000000,
+    HWC_AIV_CC    = 0x40000000,
+};
+
 // HAL specific features
 enum {
     HWC_COLOR_FILL = 0x00000008,
@@ -372,6 +378,12 @@
 void updateSource(ovutils::eTransform& orient, ovutils::Whf& whf,
         hwc_rect_t& crop, overlay::Rotator *rot);
 
+bool isZoomModeEnabled(hwc_rect_t crop);
+void updateCropAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& crop, int dpy);
+void updateDestAIVVideoMode(hwc_context_t *ctx, hwc_rect_t& dst, int dpy);
+void updateExtDisplayCoordinates(hwc_context_t *ctx, hwc_rect_t& crop,
+                           hwc_rect_t& dst, int dpy);
+
 //Routine to configure low resolution panels (<= 2048 width)
 int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
         ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
@@ -419,6 +431,14 @@
     return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER)));
 }
 
+static inline bool isAIVVideoLayer(const hwc_layer_1_t* l) {
+    return (UNLIKELY(l && (l->flags & HWC_AIV_VIDEO)));
+}
+
+static inline bool isAIVCCLayer(const hwc_layer_1_t* l) {
+    return (UNLIKELY(l && (l->flags & HWC_AIV_CC)));
+}
+
 // Returns true if the buffer is yuv
 static inline bool isYuvBuffer(const private_handle_t* hnd) {
     return (hnd && (hnd->bufferType == BUFFER_TYPE_VIDEO));
@@ -598,6 +618,9 @@
     bool mThermalBurstMode;
     //Layers out of ROI
     bool copybitDrop[MAX_NUM_APP_LAYERS];
+    // Flags related to windowboxing feature
+    bool mAIVVideoMode[HWC_NUM_DISPLAY_TYPES];
+    bool mWindowboxFeature;
 };
 
 namespace qhwc {