hwc: Partial update support for ping pong split.
ping-pong split needs source split to be enabled to stage two
pipes of a layer in the same Z order. This change adds partial
update support to generate ROI when source split is enabled.
When configured, ping-pong-split splits the layer mixer output equally
across two DSI's. To meet this limitation, the generated ROI is
adjusted to have equal widths from the panel mid point.
Change-Id: Ic307a1d5b902af9e352b0dfc6f5ab474ecd9c8a4
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 7f31ad0..f3cd5f7 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -525,9 +525,11 @@
return ret;
}
-void MDPCompNonSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) {
+void MDPCompNonSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect &crop,
+ hwc_rect &dst) {
hwc_rect_t roi = ctx->listStats[mDpy].lRoi;
- fbRect = getIntersection(fbRect, roi);
+ dst = getIntersection(dst, roi);
+ crop = dst;
}
/* 1) Identify layers that are not visible or lying outside the updating ROI and
@@ -622,14 +624,20 @@
ctx->listStats[mDpy].lRoi.right, ctx->listStats[mDpy].lRoi.bottom);
}
-void MDPCompSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) {
- hwc_rect l_roi = ctx->listStats[mDpy].lRoi;
- hwc_rect r_roi = ctx->listStats[mDpy].rRoi;
-
- hwc_rect_t l_fbRect = getIntersection(fbRect, l_roi);
- hwc_rect_t r_fbRect = getIntersection(fbRect, r_roi);
- fbRect = getUnion(l_fbRect, r_fbRect);
+void MDPCompSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect &crop,
+ hwc_rect &dst) {
+ hwc_rect roi = getUnion(ctx->listStats[mDpy].lRoi,
+ ctx->listStats[mDpy].rRoi);
+ hwc_rect tmpDst = getIntersection(dst, roi);
+ if(!isSameRect(dst, tmpDst)) {
+ crop.left = crop.left + (tmpDst.left - dst.left);
+ crop.top = crop.top + (tmpDst.top - dst.top);
+ crop.right = crop.left + (tmpDst.right - tmpDst.left);
+ crop.bottom = crop.top + (tmpDst.bottom - tmpDst.top);
+ dst = tmpDst;
+ }
}
+
/* 1) Identify layers that are not visible or lying outside BOTH the updating
* ROI's and drop them from composition. If a layer is spanning across both
* the halves of the screen but needed by only ROI, the non-contributing
@@ -1761,7 +1769,7 @@
fbRect = getUnion(fbRect, dst);
}
}
- trimAgainstROI(ctx, fbRect);
+ trimAgainstROI(ctx, fbRect, fbRect);
return fbRect;
}
@@ -2608,6 +2616,122 @@
}
//================MDPCompSrcSplit==============================================
+
+bool MDPCompSrcSplit::validateAndApplyROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ hwc_rect_t visibleRect = ctx->listStats[mDpy].lRoi;
+
+ for(int i = numAppLayers - 1; i >= 0; i--) {
+ if(!isValidRect(visibleRect)) {
+ mCurrentFrame.drop[i] = true;
+ mCurrentFrame.dropCount++;
+ continue;
+ }
+
+ const hwc_layer_1_t* layer = &list->hwLayers[i];
+ hwc_rect_t dstRect = layer->displayFrame;
+ hwc_rect_t res = getIntersection(visibleRect, dstRect);
+
+ if(!isValidRect(res)) {
+ mCurrentFrame.drop[i] = true;
+ mCurrentFrame.dropCount++;
+ } else {
+ /* Reset frame ROI when any layer which needs scaling also needs ROI
+ * cropping */
+ if(!isSameRect(res, dstRect) && needsScaling (layer)) {
+ ALOGI("%s: Resetting ROI due to scaling", __FUNCTION__);
+ memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
+ mCurrentFrame.dropCount = 0;
+ return false;
+ }
+
+ /* deduct any opaque region from visibleRect */
+ if (layer->blending == HWC_BLENDING_NONE &&
+ layer->planeAlpha == 0xFF)
+ visibleRect = deductRect(visibleRect, res);
+ }
+ }
+ return true;
+}
+
+/*
+ * HW Limitation: ping pong split can always split the ping pong output
+ * equally across two DSI's. So the ROI programmed should be of equal width
+ * for both the halves
+ */
+void MDPCompSrcSplit::generateROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list) {
+ int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+
+
+ if(!canPartialUpdate(ctx, list))
+ return;
+
+ struct hwc_rect roi = (struct hwc_rect){0, 0, 0, 0};
+ hwc_rect fullFrame = (struct hwc_rect) {0, 0,(int)ctx->dpyAttr[mDpy].xres,
+ (int)ctx->dpyAttr[mDpy].yres};
+
+ for(int index = 0; index < numAppLayers; index++ ) {
+ hwc_layer_1_t* layer = &list->hwLayers[index];
+
+ // If we have a RGB layer which needs rotation, no partial update
+ if(!isYuvBuffer((private_handle_t *)layer->handle) && layer->transform)
+ return;
+
+ if ((mCachedFrame.hnd[index] != layer->handle) ||
+ isYuvBuffer((private_handle_t *)layer->handle)) {
+ hwc_rect_t dst = layer->displayFrame;
+ hwc_rect_t updatingRect = dst;
+
+#ifdef QCOM_BSP
+ if(!needsScaling(layer) && !layer->transform)
+ {
+ hwc_rect_t src = integerizeSourceCrop(layer->sourceCropf);
+ int x_off = dst.left - src.left;
+ int y_off = dst.top - src.top;
+ updatingRect = moveRect(layer->dirtyRect, x_off, y_off);
+ }
+#endif
+
+ roi = getUnion(roi, updatingRect);
+ }
+ }
+
+ /* No layer is updating. Still SF wants a refresh.*/
+ if(!isValidRect(roi))
+ return;
+
+ roi = expandROIFromMidPoint(roi, fullFrame);
+
+ hwc_rect lFrame = fullFrame;
+ lFrame.right /= 2;
+ hwc_rect lRoi = getIntersection(roi, lFrame);
+
+ // Align ROI coordinates to panel restrictions
+ lRoi = getSanitizeROI(lRoi, lFrame);
+
+ hwc_rect rFrame = fullFrame;
+ rFrame.left = lFrame.right;
+ hwc_rect rRoi = getIntersection(roi, rFrame);
+
+ // Align ROI coordinates to panel restrictions
+ rRoi = getSanitizeROI(rRoi, rFrame);
+
+ roi = getUnion(lRoi, rRoi);
+
+ ctx->listStats[mDpy].lRoi = roi;
+ if(!validateAndApplyROI(ctx, list))
+ resetROI(ctx, mDpy);
+
+ ALOGD_IF(isDebug(),"%s: generated ROI: [%d, %d, %d, %d] [%d, %d, %d, %d]",
+ __FUNCTION__,
+ ctx->listStats[mDpy].lRoi.left, ctx->listStats[mDpy].lRoi.top,
+ ctx->listStats[mDpy].lRoi.right, ctx->listStats[mDpy].lRoi.bottom,
+ ctx->listStats[mDpy].rRoi.left, ctx->listStats[mDpy].rRoi.top,
+ ctx->listStats[mDpy].rRoi.right, ctx->listStats[mDpy].rRoi.bottom);
+}
+
bool MDPCompSrcSplit::acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
MdpPipeInfoSplit& pipe_info) {
private_handle_t *hnd = (private_handle_t *)layer->handle;
@@ -2616,6 +2740,9 @@
pipe_info.lIndex = ovutils::OV_INVALID;
pipe_info.rIndex = ovutils::OV_INVALID;
+ if(qdutils::MDPVersion::getInstance().isPartialUpdateEnabled() && !mDpy)
+ trimAgainstROI(ctx,crop, dst);
+
//If 2 pipes are staged on a single stage of a mixer, then the left pipe
//should have a higher priority than the right one. Pipe priorities are
//starting with VG0, VG1 ... , RGB0 ..., DMA1
@@ -2703,6 +2830,17 @@
ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d"
"dest_pipeR: %d",__FUNCTION__, layer, z, lDest, rDest);
+ if(qdutils::MDPVersion::getInstance().isPartialUpdateEnabled() && !mDpy) {
+ /* MDP driver crops layer coordinates against ROI in Non-Split
+ * and Split MDP comp. But HWC needs to crop them for source split.
+ * Reason: 1) Source split is efficient only when the final effective
+ * load is distributed evenly across mixers.
+ * 2) We have to know the effective width of the layer that
+ * the ROI needs to find the no. of pipes the layer needs.
+ */
+ trimAgainstROI(ctx, crop, dst);
+ }
+
// Handle R/B swap
if (layer->flags & HWC_FORMAT_RB_SWAP) {
if (hnd->format == HAL_PIXEL_FORMAT_RGBA_8888)
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 302b047..7c46c1a 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -160,9 +160,9 @@
/* validates the ROI generated for fallback conditions */
virtual bool validateAndApplyROI(hwc_context_t *ctx,
hwc_display_contents_1_t* list) = 0;
- /* Trims fbRect calculated against ROI generated */
- virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) = 0;
-
+ /* Trims layer coordinates against ROI generated */
+ virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& crop,
+ hwc_rect& dst) = 0;
/* set/reset flags for MDPComp */
void setMDPCompLayerFlags(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
@@ -315,8 +315,9 @@
/* validates the ROI generated for fallback conditions */
virtual bool validateAndApplyROI(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
- /* Trims fbRect calculated against ROI generated */
- virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect);
+ /* Trims layer coordinates against ROI generated */
+ virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& crop,
+ hwc_rect& dst);
};
class MDPCompSplit : public MDPComp {
@@ -342,6 +343,9 @@
/* allocates pipes to selected candidates */
virtual bool allocLayerPipes(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
+ /* Trims layer coordinates against ROI generated */
+ virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& crop,
+ hwc_rect& dst);
private:
/* Increments mdpCount if 4k2k yuv layer split is enabled.
* updates framebuffer z order if fb lies above source-split layer */
@@ -357,8 +361,6 @@
/* validates the ROI generated for fallback conditions */
virtual bool validateAndApplyROI(hwc_context_t *ctx,
hwc_display_contents_1_t* list);
- /* Trims fbRect calculated against ROI generated */
- virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect);
};
class MDPCompSrcSplit : public MDPCompSplit {
@@ -371,6 +373,12 @@
virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
PipeLayerPair& pipeLayerPair);
+ /* generates ROI based on the modified area of the frame */
+ virtual void generateROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
+ /* validates the ROI generated for fallback conditions */
+ virtual bool validateAndApplyROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list);
};
}; //namespace
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index bc3491e..e3ba83d 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -2577,6 +2577,30 @@
}
}
+hwc_rect expandROIFromMidPoint(hwc_rect roi, hwc_rect fullFrame) {
+ int lRoiWidth = 0, rRoiWidth = 0;
+ int half_frame_width = fullFrame.right/2;
+
+ hwc_rect lFrame = fullFrame;
+ hwc_rect rFrame = fullFrame;
+ lFrame.right = (lFrame.right - lFrame.left)/2;
+ rFrame.left = lFrame.right;
+
+ hwc_rect lRoi = getIntersection(roi, lFrame);
+ hwc_rect rRoi = getIntersection(roi, rFrame);
+
+ lRoiWidth = lRoi.right - lRoi.left;
+ rRoiWidth = rRoi.right - rRoi.left;
+
+ if(lRoiWidth && rRoiWidth) {
+ if(lRoiWidth < rRoiWidth)
+ roi.left = half_frame_width - rRoiWidth;
+ else
+ roi.right = half_frame_width + lRoiWidth;
+ }
+ return roi;
+}
+
void resetROI(hwc_context_t *ctx, const int dpy) {
const int fbXRes = (int)ctx->dpyAttr[dpy].xres;
const int fbYRes = (int)ctx->dpyAttr[dpy].yres;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 797f9b0..d419213 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -352,6 +352,9 @@
// Resets display ROI to full panel resoluion
void resetROI(hwc_context_t *ctx, const int dpy);
+// Modifies ROI even from middle of the screen
+hwc_rect expandROIFromMidPoint(hwc_rect roi, hwc_rect fullFrame);
+
// Aligns updating ROI to panel restrictions
hwc_rect_t getSanitizeROI(struct hwc_rect roi, hwc_rect boundary);