Merge "libqdutils: initialize split char array to 0"
diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp
index 25a2cae..ec12b83 100644
--- a/libcopybit/copybit.cpp
+++ b/libcopybit/copybit.cpp
@@ -129,6 +129,8 @@
case HAL_PIXEL_FORMAT_RGB_888: return MDP_RGB_888;
case HAL_PIXEL_FORMAT_RGBA_8888: return MDP_RGBA_8888;
case HAL_PIXEL_FORMAT_BGRA_8888: return MDP_BGRA_8888;
+ case HAL_PIXEL_FORMAT_YCrCb_422_I: return MDP_YCRYCB_H2V1;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I: return MDP_YCBYCR_H2V1;
case HAL_PIXEL_FORMAT_YCrCb_422_SP: return MDP_Y_CRCB_H2V1;
case HAL_PIXEL_FORMAT_YCrCb_420_SP: return MDP_Y_CRCB_H2V2;
case HAL_PIXEL_FORMAT_YCbCr_422_SP: return MDP_Y_CBCR_H2V1;
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 89d63e9..609f9c1 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -301,34 +301,37 @@
int hdmiEDIDFile = open(sysFsEDIDFilePath, O_RDONLY, 0);
int len = -1;
+ char edidStr[128] = {'\0'};
if (hdmiEDIDFile < 0) {
ALOGE("%s: edid_modes file '%s' not found",
__FUNCTION__, sysFsEDIDFilePath);
return false;
} else {
- len = read(hdmiEDIDFile, mEDIDs, sizeof(mEDIDs)-1);
+ len = read(hdmiEDIDFile, edidStr, sizeof(edidStr)-1);
ALOGD_IF(DEBUG, "%s: EDID string: %s length = %d",
- __FUNCTION__, mEDIDs, len);
+ __FUNCTION__, edidStr, len);
if ( len <= 0) {
ALOGE("%s: edid_modes file empty '%s'",
__FUNCTION__, sysFsEDIDFilePath);
+ edidStr[0] = '\0';
}
else {
- while (len > 1 && isspace(mEDIDs[len-1]))
+ while (len > 1 && isspace(edidStr[len-1])) {
--len;
- mEDIDs[len] = 0;
+ }
+ edidStr[len] = '\0';
}
}
close(hdmiEDIDFile);
if(len > 0) {
// Get EDID modes from the EDID strings
- mModeCount = parseResolution(mEDIDs, mEDIDModes);
+ mModeCount = parseResolution(edidStr, mEDIDModes);
ALOGD_IF(DEBUG, "%s: mModeCount = %d", __FUNCTION__,
mModeCount);
}
- return (strlen(mEDIDs) > 0);
+ return (len > 0);
}
bool ExternalDisplay::openFrameBuffer()
@@ -359,7 +362,6 @@
void ExternalDisplay::resetInfo()
{
memset(&mVInfo, 0, sizeof(mVInfo));
- memset(mEDIDs, 0, sizeof(mEDIDs));
memset(mEDIDModes, 0, sizeof(mEDIDModes));
mModeCount = 0;
mCurrentMode = -1;
diff --git a/libexternal/external.h b/libexternal/external.h
index 1a3602d..646e7a6 100644
--- a/libexternal/external.h
+++ b/libexternal/external.h
@@ -75,7 +75,6 @@
int mFd;
int mFbNum;
int mCurrentMode;
- char mEDIDs[128];
int mEDIDModes[64];
int mModeCount;
bool mUnderscanSupported;
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 89ac919..9af45e2 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -152,6 +152,8 @@
case HAL_PIXEL_FORMAT_YV12:
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ case HAL_PIXEL_FORMAT_YCrCb_422_I:
stride = ALIGN(width, 16);
break;
case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
@@ -324,6 +326,8 @@
break;
case HAL_PIXEL_FORMAT_YCbCr_422_SP:
case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ case HAL_PIXEL_FORMAT_YCrCb_422_I:
if(width & 1) {
ALOGE("width is odd for the YUV422_SP format");
return -EINVAL;
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index 3187648..b3fddf1 100644
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -100,6 +100,7 @@
HAL_PIXEL_FORMAT_RG_88 = 0x10E,
HAL_PIXEL_FORMAT_YCbCr_444_SP = 0x10F,
HAL_PIXEL_FORMAT_YCrCb_444_SP = 0x110,
+ HAL_PIXEL_FORMAT_YCrCb_422_I = 0x111,
HAL_PIXEL_FORMAT_INTERLACE = 0x180,
};
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index e970d4c..ec9abfb 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -494,7 +494,8 @@
}
}
- if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd,
+ ctx->listStats[dpy].roi)) {
ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
ret = -1;
}
diff --git a/libhwcomposer/hwc_dump_layers.cpp b/libhwcomposer/hwc_dump_layers.cpp
index cf23b65..b9c09b6 100644
--- a/libhwcomposer/hwc_dump_layers.cpp
+++ b/libhwcomposer/hwc_dump_layers.cpp
@@ -400,6 +400,10 @@
case HAL_PIXEL_FORMAT_YCbCr_422_I:
strcpy(pixFormatStr, "YCbCr_422_I_YUY2");
break;
+ case HAL_PIXEL_FORMAT_YCrCb_422_I:
+ strlcpy(pixFormatStr, "YCrCb_422_I_YVYU",
+ sizeof("YCrCb_422_I_YVYU"));
+ break;
case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
strcpy(pixFormatStr, "NV12_ENCODEABLE");
break;
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 44db2bc..4bbad8b 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -41,6 +41,7 @@
bool MDPComp::sDebugLogs = false;
bool MDPComp::sEnabled = false;
bool MDPComp::sEnableMixedMode = true;
+bool MDPComp::sEnablePartialFrameUpdate = false;
int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
float MDPComp::sMaxBw = 2.3f;
uint32_t MDPComp::sCompBytesClaimed = 0;
@@ -62,11 +63,8 @@
dumpsys_log(buf,"HWC Map for Dpy: %s \n",
(mDpy == 0) ? "\"PRIMARY\"" :
(mDpy == 1) ? "\"EXTERNAL\"" : "\"VIRTUAL\"");
- dumpsys_log(buf,"PREV_FRAME: layerCount:%2d mdpCount:%2d \
- cacheCount:%2d \n", mCachedFrame.layerCount,
- mCachedFrame.mdpCount, mCachedFrame.cacheCount);
- dumpsys_log(buf,"CURR_FRAME: layerCount:%2d mdpCount:%2d \
- fbCount:%2d \n", mCurrentFrame.layerCount,
+ dumpsys_log(buf,"CURR_FRAME: layerCount:%2d mdpCount:%2d "
+ "fbCount:%2d \n", mCurrentFrame.layerCount,
mCurrentFrame.mdpCount, mCurrentFrame.fbCount);
dumpsys_log(buf,"needsFBRedraw:%3s pipesUsed:%2d MaxPipesPerMixer: %d \n",
(mCurrentFrame.needsRedraw? "YES" : "NO"),
@@ -78,9 +76,10 @@
dumpsys_log(buf," %7d | %7s | %8d | %9s | %2d \n",
index,
(mCurrentFrame.isFBComposed[index] ? "YES" : "NO"),
- mCurrentFrame.layerToMDP[index],
+ mCurrentFrame.layerToMDP[index],
(mCurrentFrame.isFBComposed[index] ?
- (mCurrentFrame.needsRedraw ? "GLES" : "CACHE") : "MDP"),
+ (mCurrentFrame.drop[index] ? "DROP" :
+ (mCurrentFrame.needsRedraw ? "GLES" : "CACHE")) : "MDP"),
(mCurrentFrame.isFBComposed[index] ? mCurrentFrame.fbZ :
mCurrentFrame.mdpToLayer[mCurrentFrame.layerToMDP[index]].pipeInfo->zOrder));
dumpsys_log(buf,"\n");
@@ -109,12 +108,19 @@
sEnableMixedMode = false;
}
- sDebugLogs = false;
if(property_get("debug.mdpcomp.logs", property, NULL) > 0) {
if(atoi(property) != 0)
sDebugLogs = true;
}
+ if(property_get("persist.hwc.partialupdate.enable", property, NULL) > 0) {
+ if((atoi(property) != 0) && ctx->mMDP.panel == MIPI_CMD_PANEL &&
+ qdutils::MDPVersion::getInstance().is8x74v2())
+ sEnablePartialFrameUpdate = true;
+ }
+ ALOGE_IF(isDebug(), "%s: Partial Update applicable?: %d",__FUNCTION__,
+ sEnablePartialFrameUpdate);
+
sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
if(property_get("debug.mdpcomp.maxpermixer", property, "-1") > 0) {
int val = atoi(property);
@@ -185,8 +191,11 @@
layer->compositionType = HWC_OVERLAY;
layer->hints |= HWC_HINT_CLEAR_FB;
} else {
- if(!mCurrentFrame.needsRedraw)
+ /* Drop the layer when its already present in FB OR when it lies
+ * outside frame's ROI */
+ if(!mCurrentFrame.needsRedraw || mCurrentFrame.drop[index]) {
layer->compositionType = HWC_OVERLAY;
+ }
}
}
}
@@ -234,7 +243,7 @@
void MDPComp::LayerCache::reset() {
memset(&hnd, 0, sizeof(hnd));
mdpCount = 0;
- cacheCount = 0;
+ fbCount = 0;
layerCount = 0;
fbZ = -1;
}
@@ -248,11 +257,22 @@
void MDPComp::LayerCache::updateCounts(const FrameInfo& curFrame) {
mdpCount = curFrame.mdpCount;
- cacheCount = curFrame.fbCount;
+ fbCount = curFrame.fbCount;
layerCount = curFrame.layerCount;
fbZ = curFrame.fbZ;
}
+bool MDPComp::isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer) {
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ if((not isYuvBuffer(hnd) and has90Transform(layer)) or
+ (not isValidDimension(ctx,layer))
+ //More conditions here, SKIP, sRGB+Blend etc
+ ) {
+ return false;
+ }
+ return true;
+}
+
bool MDPComp::isValidDimension(hwc_context_t *ctx, hwc_layer_1_t *layer) {
const int dpy = HWC_DISPLAY_PRIMARY;
private_handle_t *hnd = (private_handle_t *)layer->handle;
@@ -368,6 +388,91 @@
return ret;
}
+bool MDPComp::validateAndApplyROI(hwc_context_t *ctx,
+ hwc_display_contents_1_t* list, hwc_rect_t roi) {
+ int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+
+ if(!isValidRect(roi))
+ return false;
+
+ for(int i = 0; i < numAppLayers; i++){
+ const hwc_layer_1_t* layer = &list->hwLayers[i];
+
+ hwc_rect_t dstRect = layer->displayFrame;
+ hwc_rect_t srcRect = layer->sourceCrop;
+ int transform = layer->transform;
+ trimLayer(ctx, mDpy, transform, srcRect, dstRect);
+
+ hwc_rect_t res = getIntersection(roi, dstRect);
+
+ int res_w = res.right - res.left;
+ int res_h = res.bottom - res.top;
+ int dst_w = dstRect.right - dstRect.left;
+ int dst_h = dstRect.bottom - dstRect.top;
+
+ if(!isValidRect(res)) {
+ mCurrentFrame.drop[i] = true;
+ mCurrentFrame.dropCount++;
+ }else {
+ /* Reset frame ROI when any layer which needs scaling also needs ROI
+ * cropping */
+ if((res_w != dst_w || res_h != dst_h) &&
+ needsScaling (ctx, layer, mDpy)) {
+ ALOGE("%s: Resetting ROI due to scaling", __FUNCTION__);
+ memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
+ mCurrentFrame.dropCount = 0;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void MDPComp::generateROI(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+ int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+
+ if(!sEnablePartialFrameUpdate) {
+ return;
+ }
+
+ if(mDpy || isDisplaySplit(ctx, mDpy)){
+ ALOGE_IF(isDebug(), "%s: ROI not supported for"
+ "the (1) external / virtual display's (2) dual DSI displays",
+ __FUNCTION__);
+ return;
+ }
+
+ if(list->flags & HWC_GEOMETRY_CHANGED)
+ return;
+
+ struct hwc_rect roi = (struct hwc_rect){0, 0, 0, 0};
+ for(int index = 0; index < numAppLayers; index++ ) {
+ if ((mCachedFrame.hnd[index] != list->hwLayers[index].handle) ||
+ isYuvBuffer((private_handle_t *)list->hwLayers[index].handle)) {
+ hwc_rect_t dstRect = list->hwLayers[index].displayFrame;
+ hwc_rect_t srcRect = list->hwLayers[index].sourceCrop;
+ int transform = list->hwLayers[index].transform;
+
+ /* Intersect against display boundaries */
+ trimLayer(ctx, mDpy, transform, srcRect, dstRect);
+ roi = getUnion(roi, dstRect);
+ }
+ }
+
+ if(!validateAndApplyROI(ctx, list, roi)){
+ roi = (struct hwc_rect) {0, 0,
+ (int)ctx->dpyAttr[mDpy].xres, (int)ctx->dpyAttr[mDpy].yres};
+ }
+
+ ctx->listStats[mDpy].roi.x = roi.left;
+ ctx->listStats[mDpy].roi.y = roi.top;
+ ctx->listStats[mDpy].roi.w = roi.right - roi.left;
+ ctx->listStats[mDpy].roi.h = roi.bottom - roi.top;
+
+ ALOGD_IF(isDebug(),"%s: generated ROI: [%d, %d, %d, %d]", __FUNCTION__,
+ roi.left, roi.top, roi.right, roi.bottom);
+}
+
/* Checks for conditions where all the layers marked for MDP comp cannot be
* bypassed. On such conditions we try to bypass atleast YUV layers */
bool MDPComp::isFullFrameDoable(hwc_context_t *ctx,
@@ -380,12 +485,6 @@
return false;
}
- if(mDpy > HWC_DISPLAY_PRIMARY){
- ALOGD_IF(isDebug(), "%s: Cannot support External display(s)",
- __FUNCTION__);
- return false;
- }
-
if(isSkipPresent(ctx, mDpy)) {
ALOGD_IF(isDebug(),"%s: SKIP present: %d",
__FUNCTION__,
@@ -399,27 +498,17 @@
return false;
}
- //MDP composition is not efficient if layer needs rotator.
for(int i = 0; i < numAppLayers; ++i) {
- // As MDP h/w supports flip operation, use MDP comp only for
- // 180 transforms. Fail for any transform involving 90 (90, 270).
hwc_layer_1_t* layer = &list->hwLayers[i];
private_handle_t *hnd = (private_handle_t *)layer->handle;
- if(layer->transform & HWC_TRANSFORM_ROT_90) {
- if(!isYuvBuffer(hnd) ) {
- ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__);
- return false;
- }else if(!canUseRotator(ctx, mDpy)) {
- ALOGD_IF(isDebug(), "%s: no free DMA pipe",__FUNCTION__);
+ if(isYuvBuffer(hnd) && has90Transform(layer)) {
+ if(!canUseRotator(ctx, mDpy)) {
+ ALOGD_IF(isDebug(), "%s: Can't use rotator for dpy %d",
+ __FUNCTION__, mDpy);
return false;
}
}
- if(!isValidDimension(ctx,layer)) {
- ALOGD_IF(isDebug(), "%s: Buffer is of invalid width",
- __FUNCTION__);
- return false;
- }
//For 8x26 with panel width>1k, if RGB layer needs HFLIP fail mdp comp
// may not need it if Gfx pre-rotation can handle all flips & rotations
@@ -445,14 +534,29 @@
}
bool MDPComp::fullMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
- //Setup mCurrentFrame
- mCurrentFrame.mdpCount = mCurrentFrame.layerCount;
+ //Will benefit presentation / secondary-only layer.
+ if((mDpy > HWC_DISPLAY_PRIMARY) &&
+ (list->numHwLayers - 1) > MAX_SEC_LAYERS) {
+ ALOGD_IF(isDebug(), "%s: Exceeds max secondary pipes",__FUNCTION__);
+ return false;
+ }
+
+ const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+ for(int i = 0; i < numAppLayers; i++) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ if(not isSupportedForMDPComp(ctx, layer)) {
+ ALOGD_IF(isDebug(), "%s: Unsupported layer in list",__FUNCTION__);
+ return false;
+ }
+ }
mCurrentFrame.fbCount = 0;
mCurrentFrame.fbZ = -1;
- memset(&mCurrentFrame.isFBComposed, 0, sizeof(mCurrentFrame.isFBComposed));
+ memcpy(&mCurrentFrame.isFBComposed, &mCurrentFrame.drop,
+ sizeof(mCurrentFrame.isFBComposed));
+ mCurrentFrame.mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount -
+ mCurrentFrame.dropCount;
- int mdpCount = mCurrentFrame.mdpCount;
- if(mdpCount > sMaxPipesPerMixer) {
+ if(mCurrentFrame.mdpCount > sMaxPipesPerMixer) {
ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
return false;
}
@@ -482,10 +586,35 @@
//Setup mCurrentFrame
mCurrentFrame.reset(numAppLayers);
updateLayerCache(ctx, list);
+
+ //If an MDP marked layer is unsupported cannot do partial MDP Comp
+ for(int i = 0; i < numAppLayers; i++) {
+ if(!mCurrentFrame.isFBComposed[i]) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ if(not isSupportedForMDPComp(ctx, layer)) {
+ ALOGD_IF(isDebug(), "%s: Unsupported layer in list",
+ __FUNCTION__);
+ return false;
+ }
+ }
+ }
+
updateYUV(ctx, list, false /*secure only*/);
- batchLayers(); //sets up fbZ also
+ bool ret = batchLayers(ctx, list); //sets up fbZ also
+ if(!ret) {
+ ALOGD_IF(isDebug(),"%s: batching failed, dpy %d",__FUNCTION__, mDpy);
+ return false;
+ }
int mdpCount = mCurrentFrame.mdpCount;
+
+ //Will benefit cases where a video has non-updating background.
+ if((mDpy > HWC_DISPLAY_PRIMARY) and
+ (mdpCount > MAX_SEC_LAYERS)) {
+ ALOGD_IF(isDebug(), "%s: Exceeds max secondary pipes",__FUNCTION__);
+ return false;
+ }
+
if(mdpCount > (sMaxPipesPerMixer - 1)) { // -1 since FB is used
ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
return false;
@@ -507,10 +636,11 @@
bool MDPComp::isOnlyVideoDoable(hwc_context_t *ctx,
hwc_display_contents_1_t* list, bool secureOnly) {
int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+
mCurrentFrame.reset(numAppLayers);
updateYUV(ctx, list, secureOnly);
int mdpCount = mCurrentFrame.mdpCount;
- int fbNeeded = int(mCurrentFrame.fbCount != 0);
+ int fbNeeded = (mCurrentFrame.fbCount != 0);
if(!isYuvPresent(ctx, mDpy)) {
return false;
@@ -572,65 +702,82 @@
return true;
}
-void MDPComp::batchLayers() {
+bool MDPComp::batchLayers(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
/* Idea is to keep as many contiguous non-updating(cached) layers in FB and
* send rest of them through MDP. NEVER mark an updating layer for caching.
* But cached ones can be marked for MDP*/
int maxBatchStart = -1;
+ int maxBatchEnd = -1;
int maxBatchCount = 0;
/* All or Nothing is cached. No batching needed */
if(!mCurrentFrame.fbCount) {
mCurrentFrame.fbZ = -1;
- return;
+ return true;
}
if(!mCurrentFrame.mdpCount) {
mCurrentFrame.fbZ = 0;
- return;
+ return true;
}
- /* Search for max number of contiguous (cached) layers */
+ /* Search for max number of contiguous (cached) layers excluding dropped
+ * layers */
int i = 0;
while (i < mCurrentFrame.layerCount) {
int count = 0;
+ int start = i;
while(mCurrentFrame.isFBComposed[i] && i < mCurrentFrame.layerCount) {
- count++; i++;
+ if(!mCurrentFrame.drop[i])
+ count++;
+ i++;
}
if(count > maxBatchCount) {
maxBatchCount = count;
- maxBatchStart = i - count;
+ maxBatchStart = start;
+ maxBatchEnd = i - 1;
mCurrentFrame.fbZ = maxBatchStart;
}
if(i < mCurrentFrame.layerCount) i++;
}
- /* reset rest of the layers for MDP comp */
+ mCurrentFrame.fbCount = maxBatchCount;
+
+ /* reset rest of the layers lying inside ROI for MDP comp */
for(int i = 0; i < mCurrentFrame.layerCount; i++) {
- if(i != maxBatchStart){
- mCurrentFrame.isFBComposed[i] = false;
- } else {
- i += maxBatchCount;
+ hwc_layer_1_t* layer = &list->hwLayers[i];
+ if((i < maxBatchStart || i > maxBatchEnd) &&
+ mCurrentFrame.isFBComposed[i]){
+ if(!mCurrentFrame.drop[i]){
+ //If an unsupported layer is being attempted to
+ //be pulled out we should fail
+ if(not isSupportedForMDPComp(ctx, layer)) {
+ return false;
+ }
+ mCurrentFrame.isFBComposed[i] = false;
+ }
}
}
- mCurrentFrame.fbCount = maxBatchCount;
mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
- mCurrentFrame.fbCount;
+ mCurrentFrame.fbCount - mCurrentFrame.dropCount;
ALOGD_IF(isDebug(),"%s: cached count: %d",__FUNCTION__,
mCurrentFrame.fbCount);
+
+ return true;
}
void MDPComp::updateLayerCache(hwc_context_t* ctx,
- hwc_display_contents_1_t* list) {
-
+ hwc_display_contents_1_t* list) {
int numAppLayers = ctx->listStats[mDpy].numAppLayers;
- int numCacheableLayers = 0;
+ int fbCount = 0;
for(int i = 0; i < numAppLayers; i++) {
+ hwc_layer_1_t* layer = &list->hwLayers[i];
if (mCachedFrame.hnd[i] == list->hwLayers[i].handle) {
- numCacheableLayers++;
+ if(!mCurrentFrame.drop[i])
+ fbCount++;
mCurrentFrame.isFBComposed[i] = true;
} else {
mCurrentFrame.isFBComposed[i] = false;
@@ -638,10 +785,13 @@
}
}
- mCurrentFrame.fbCount = numCacheableLayers;
- mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
- mCurrentFrame.fbCount;
- ALOGD_IF(isDebug(),"%s: cached count: %d",__FUNCTION__, numCacheableLayers);
+ mCurrentFrame.fbCount = fbCount;
+ mCurrentFrame.mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount
+ - mCurrentFrame.dropCount;
+
+ ALOGD_IF(isDebug(),"%s: MDP count: %d FB count %d drop count: %d"
+ ,__FUNCTION__, mCurrentFrame.mdpCount, mCurrentFrame.fbCount,
+ mCurrentFrame.dropCount);
}
void MDPComp::updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list,
@@ -677,8 +827,8 @@
}
mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
- mCurrentFrame.fbCount;
- ALOGD_IF(isDebug(),"%s: cached count: %d",__FUNCTION__,
+ mCurrentFrame.fbCount - mCurrentFrame.dropCount;
+ ALOGD_IF(isDebug(),"%s: fb count: %d",__FUNCTION__,
mCurrentFrame.fbCount);
}
@@ -703,7 +853,7 @@
layer %d",__FUNCTION__, index);
return false;
}
- } else if(fbBatch == false) {
+ } else if(fbBatch == false && !mCurrentFrame.drop[index]) {
mdpNextZOrder++;
fbBatch = true;
}
@@ -791,15 +941,17 @@
//reset old data
mCurrentFrame.reset(numLayers);
+ memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
+ mCurrentFrame.dropCount = 0;
//number of app layers exceeds MAX_NUM_APP_LAYERS fall back to GPU
//do not cache the information for next draw cycle.
if(numLayers > MAX_NUM_APP_LAYERS) {
mCachedFrame.updateCounts(mCurrentFrame);
- ALOGD_IF(isDebug(), "%s: Number of App layers exceeded the limit ",
- __FUNCTION__);
+ ALOGE("%s: Number of App layers exceeded the limit ",
+ __FUNCTION__);
ret = -1;
- goto exit;
+ return ret;
}
//Hard conditions, if not met, cannot do MDP comp
@@ -811,6 +963,8 @@
goto exit;
}
+ generateROI(ctx, list);
+
//Check whether layers marked for MDP Composition is actually doable.
if(isFullFrameDoable(ctx, list)) {
mCurrentFrame.map();
@@ -836,12 +990,11 @@
mCurrentFrame.needsRedraw = false;
if(mCurrentFrame.fbCount &&
((mCurrentFrame.mdpCount != mCachedFrame.mdpCount) ||
- (mCurrentFrame.fbCount != mCachedFrame.cacheCount) ||
+ (mCurrentFrame.fbCount != mCachedFrame.fbCount) ||
(mCurrentFrame.fbZ != mCachedFrame.fbZ) ||
(!mCurrentFrame.mdpCount) ||
(list->flags & HWC_GEOMETRY_CHANGED) ||
- isSkipPresent(ctx, mDpy) ||
- (mDpy > HWC_DISPLAY_PRIMARY))) {
+ isSkipPresent(ctx, mDpy))) {
mCurrentFrame.needsRedraw = true;
}
}
@@ -881,6 +1034,7 @@
//UpdateLayerFlags
setMDPCompLayerFlags(ctx, list);
+ mCachedFrame.cacheAll(list);
mCachedFrame.updateCounts(mCurrentFrame);
// unlock it before calling dump function to avoid deadlock
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 7fb0968..d872cdf 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -55,6 +55,8 @@
static void reset() { sCompBytesClaimed = 0; };
protected:
+ enum { MAX_SEC_LAYERS = 1 }; //TODO add property support
+
enum ePipeType {
MDPCOMP_OV_RGB = ovutils::OV_MDP_PIPE_RGB,
MDPCOMP_OV_VG = ovutils::OV_MDP_PIPE_VG,
@@ -88,6 +90,10 @@
/* layer composing on FB? */
int fbCount;
bool isFBComposed[MAX_NUM_APP_LAYERS];
+ /* layers lying outside ROI. Will
+ * be dropped off from the composition */
+ int dropCount;
+ bool drop[MAX_NUM_APP_LAYERS];
bool needsRedraw;
int fbZ;
@@ -103,7 +109,7 @@
struct LayerCache {
int layerCount;
int mdpCount;
- int cacheCount;
+ int fbCount;
int fbZ;
buffer_handle_t hnd[MAX_NUM_APP_LAYERS];
@@ -148,6 +154,10 @@
hwc_display_contents_1_t* list);
/* checks if the required bandwidth exceeds a certain max */
bool bandwidthCheck(hwc_context_t *ctx, const uint32_t& size);
+ /* generates ROI based on the modified area of the frame */
+ void generateROI(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+ bool validateAndApplyROI(hwc_context_t *ctx, hwc_display_contents_1_t* list,
+ hwc_rect_t roi);
/* Is debug enabled */
static bool isDebug() { return sDebugLogs ? true : false; };
@@ -158,17 +168,20 @@
/* tracks non updating layers*/
void updateLayerCache(hwc_context_t* ctx, hwc_display_contents_1_t* list);
/* optimize layers for mdp comp*/
- void batchLayers();
+ bool batchLayers(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);
bool programMDP(hwc_context_t *ctx, hwc_display_contents_1_t* list);
bool programYUV(hwc_context_t *ctx, hwc_display_contents_1_t* list);
void reset(const int& numAppLayers, hwc_display_contents_1_t* list);
+ bool isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer);
int mDpy;
static bool sEnabled;
static bool sEnableMixedMode;
+ /* Enables Partial frame composition */
+ static bool sEnablePartialFrameUpdate;
static bool sDebugLogs;
static bool sIdleFallBack;
static int sMaxPipesPerMixer;
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 9837bd1..aa18abf 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -708,6 +708,10 @@
char property[PROPERTY_VALUE_MAX];
ctx->listStats[dpy].extOnlyLayerIndex = -1;
ctx->listStats[dpy].isDisplayAnimating = false;
+ ctx->listStats[dpy].roi = ovutils::Dim(0, 0,
+ (int)ctx->dpyAttr[dpy].xres, (int)ctx->dpyAttr[dpy].yres);
+
+ optimizeLayerRects(ctx, list, dpy);
for (size_t i = 0; i < (size_t)ctx->listStats[dpy].numAppLayers; i++) {
hwc_layer_1_t const* layer = &list->hwLayers[i];
@@ -915,6 +919,115 @@
crop_b -= crop_h * bottomCutRatio;
}
+bool isValidRect(const hwc_rect& rect)
+{
+ return ((rect.bottom > rect.top) && (rect.right > rect.left)) ;
+}
+
+/* computes the intersection of two rects */
+hwc_rect_t getIntersection(const hwc_rect_t& rect1, const hwc_rect_t& rect2)
+{
+ hwc_rect_t res;
+
+ if(!isValidRect(rect1) || !isValidRect(rect2)){
+ return (hwc_rect_t){0, 0, 0, 0};
+ }
+
+
+ res.left = max(rect1.left, rect2.left);
+ res.top = max(rect1.top, rect2.top);
+ res.right = min(rect1.right, rect2.right);
+ res.bottom = min(rect1.bottom, rect2.bottom);
+
+ if(!isValidRect(res))
+ return (hwc_rect_t){0, 0, 0, 0};
+
+ return res;
+}
+
+/* computes the union of two rects */
+hwc_rect_t getUnion(const hwc_rect &rect1, const hwc_rect &rect2)
+{
+ hwc_rect_t res;
+
+ if(!isValidRect(rect1)){
+ return rect2;
+ }
+
+ if(!isValidRect(rect2)){
+ return rect1;
+ }
+
+ res.left = min(rect1.left, rect2.left);
+ res.top = min(rect1.top, rect2.top);
+ res.right = max(rect1.right, rect2.right);
+ res.bottom = max(rect1.bottom, rect2.bottom);
+
+ return res;
+}
+
+/* deducts given rect from layers display-frame and source crop.
+ also it avoid hole creation.*/
+void deductRect(const hwc_layer_1_t* layer, hwc_rect_t& irect) {
+ hwc_rect_t& disprect = (hwc_rect_t&)layer->displayFrame;
+ hwc_rect_t& srcrect = (hwc_rect_t&)layer->sourceCrop;
+ int irect_w = irect.right - irect.left;
+ int irect_h = irect.bottom - irect.top;
+
+ if((disprect.left == irect.left) && (disprect.right == irect.right)) {
+ if((disprect.top == irect.top) && (irect.bottom <= disprect.bottom)) {
+ disprect.top = irect.bottom;
+ srcrect.top += irect_h;
+ }
+ else if((disprect.bottom == irect.bottom)
+ && (irect.top >= disprect.top)) {
+ disprect.bottom = irect.top;
+ srcrect.bottom -= irect_h;
+ }
+ }
+ else if((disprect.top == irect.top) && (disprect.bottom == irect.bottom)) {
+ if((disprect.left == irect.left) && (irect.right <= disprect.right)) {
+ disprect.left = irect.right;
+ srcrect.left += irect_w;
+ }
+ else if((disprect.right == irect.right)
+ && (irect.left >= disprect.left)) {
+ disprect.right = irect.left;
+ srcrect.right -= irect_w;
+ }
+ }
+}
+
+void optimizeLayerRects(hwc_context_t *ctx,
+ const hwc_display_contents_1_t *list, const int& dpy) {
+ int i=list->numHwLayers-2;
+ hwc_rect_t irect;
+ while(i > 0) {
+
+ //see if there is no blending required.
+ //If it is opaque see if we can substract this region from below layers.
+ if(list->hwLayers[i].blending == HWC_BLENDING_NONE) {
+ int j= i-1;
+ hwc_rect_t& topframe =
+ (hwc_rect_t&)list->hwLayers[i].displayFrame;
+ while(j >= 0) {
+ if(!needsScaling(ctx, &list->hwLayers[j], dpy)) {
+ hwc_rect_t& bottomframe =
+ (hwc_rect_t&)list->hwLayers[j].displayFrame;
+
+ hwc_rect_t irect = getIntersection(bottomframe, topframe);
+ if(isValidRect(irect)) {
+ //if intersection is valid rect, deduct it
+ deductRect(&list->hwLayers[j], irect);
+ }
+ }
+ j--;
+ }
+ }
+ i--;
+ }
+}
+
void getNonWormholeRegion(hwc_display_contents_1_t* list,
hwc_rect_t& nwr)
{
@@ -928,18 +1041,11 @@
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);
+ nwr = getUnion(nwr, displayFrame);
}
//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);
-
+ nwr = getIntersection(nwr, fbDisplayFrame);
}
bool isExternalActive(hwc_context_t* ctx) {
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index cb6d091..8822af0 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -101,11 +101,12 @@
// Notifies hwcomposer about the start and end of animation
// This will be set to true during animation, otherwise false.
bool isDisplayAnimating;
+ ovutils::Dim roi;
};
struct LayerProp {
uint32_t mFlags; //qcom specific layer flags
- LayerProp():mFlags(0) {};
+ LayerProp():mFlags(0){};
};
struct VsyncState {
@@ -185,6 +186,13 @@
int getExtOrientation(hwc_context_t* ctx);
+bool isValidRect(const hwc_rect_t& rect);
+void deductRect(const hwc_layer_1_t* layer, hwc_rect_t& irect);
+hwc_rect_t getIntersection(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
+hwc_rect_t getUnion(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
+void optimizeLayerRects(hwc_context_t *ctx,
+ const hwc_display_contents_1_t *list, const int& dpy);
+
/* Calculates the destination position based on the action safe rectangle */
void getActionSafePosition(hwc_context_t *ctx, int dpy, hwc_rect_t& dst);
@@ -396,6 +404,11 @@
static inline bool isYuvPresent (hwc_context_t *ctx, int dpy) {
return ctx->listStats[dpy].yuvCount;
}
+
+static inline bool has90Transform(hwc_layer_1_t *layer) {
+ return (layer->transform & HWC_TRANSFORM_ROT_90);
+}
+
};
#endif //HWC_UTILS_H
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index afe62e2..b095e9e 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -321,13 +321,23 @@
}
bool Overlay::displayCommit(const int& fd) {
+ utils::Dim roi;
+ return displayCommit(fd, roi);
+}
+
+bool Overlay::displayCommit(const int& fd, const utils::Dim& roi) {
//Commit
struct mdp_display_commit info;
memset(&info, 0, sizeof(struct mdp_display_commit));
info.flags = MDP_DISPLAY_COMMIT_OVERLAY;
+ info.roi.x = roi.x;
+ info.roi.y = roi.y;
+ info.roi.w = roi.w;
+ info.roi.h = roi.h;
+
if(!mdp_wrapper::displayCommit(fd, info)) {
- ALOGE("%s: commit failed", __func__);
- return false;
+ ALOGE("%s: commit failed", __func__);
+ return false;
}
return true;
}
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index 9d7f5c8..c16f6e6 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -109,6 +109,7 @@
static int getDMAMode();
/* Returns the framebuffer node backing up the display */
static int getFbForDpy(const int& dpy);
+ static bool displayCommit(const int& fd, const utils::Dim& roi);
static bool displayCommit(const int& fd);
private:
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index 927e7e9..df2c09e 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -114,6 +114,10 @@
return MDP_Y_CBCR_H2V2;
case HAL_PIXEL_FORMAT_YCrCb_422_SP:
return MDP_Y_CRCB_H2V1;
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ return MDP_YCBYCR_H2V1;
+ case HAL_PIXEL_FORMAT_YCrCb_422_I:
+ return MDP_YCRYCB_H2V1;
case HAL_PIXEL_FORMAT_YCbCr_444_SP:
return MDP_Y_CBCR_H1V1;
case HAL_PIXEL_FORMAT_YCrCb_444_SP:
@@ -128,7 +132,6 @@
//---graphics.h--------
//HAL_PIXEL_FORMAT_RGBA_5551
//HAL_PIXEL_FORMAT_RGBA_4444
- //HAL_PIXEL_FORMAT_YCbCr_422_I
//---gralloc_priv.h-----
//HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO = 0x7FA30C01
//HAL_PIXEL_FORMAT_R_8 = 0x10D
@@ -169,7 +172,11 @@
return HAL_PIXEL_FORMAT_YCbCr_420_SP;
case MDP_Y_CRCB_H2V1:
return HAL_PIXEL_FORMAT_YCrCb_422_SP;
- case MDP_Y_CBCR_H1V1:
+ case MDP_YCBYCR_H2V1:
+ return HAL_PIXEL_FORMAT_YCbCr_422_I;
+ case MDP_YCRYCB_H2V1:
+ return HAL_PIXEL_FORMAT_YCrCb_422_I;
+ case MDP_Y_CBCR_H1V1:
return HAL_PIXEL_FORMAT_YCbCr_444_SP;
case MDP_Y_CRCB_H1V1:
return HAL_PIXEL_FORMAT_YCrCb_444_SP;
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index a9b7e6a..c854975 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -488,6 +488,8 @@
case MDP_Y_CR_CB_H2V2:
case MDP_Y_CR_CB_GH2V2:
case MDP_Y_CBCR_H2V2_VENUS:
+ case MDP_YCBYCR_H2V1:
+ case MDP_YCRYCB_H2V1:
return true;
default:
return false;
@@ -518,6 +520,7 @@
formats[MDP_ARGB_8888] = STR(MDP_ARGB_8888);
formats[MDP_RGB_888] = STR(MDP_RGB_888);
formats[MDP_Y_CRCB_H2V2] = STR(MDP_Y_CRCB_H2V2);
+ formats[MDP_YCBYCR_H2V1] = STR(MDP_YCBYCR_H2V1);
formats[MDP_YCRYCB_H2V1] = STR(MDP_YCRYCB_H2V1);
formats[MDP_CBYCRY_H2V1] = STR(MDP_CBYCRY_H2V1);
formats[MDP_Y_CRCB_H2V1] = STR(MDP_Y_CRCB_H2V1);
diff --git a/libvirtual/virtual.cpp b/libvirtual/virtual.cpp
index c94a5c6..342044c 100644
--- a/libvirtual/virtual.cpp
+++ b/libvirtual/virtual.cpp
@@ -55,6 +55,9 @@
#define MAX_SYSFS_FILE_PATH 255
+/* Max. resolution assignable to virtual display. */
+#define SUPPORTED_VIRTUAL_AREA (1920*1080)
+
int VirtualDisplay::configure() {
if(!openFrameBuffer())
return -1;
@@ -94,47 +97,85 @@
closeFrameBuffer();
}
+/* Initializes the resolution attributes of the virtual display
+ that are reported to SurfaceFlinger.
+ Cases:
+ 1. ONLINE event - initialize to frame buffer resolution
+ 2. RESUME event - retain original resolution
+*/
+void VirtualDisplay::initResolution(uint32_t &extW, uint32_t &extH) {
+ // On ONLINE event, display resolution attributes are 0.
+ if(extW == 0 || extH == 0){
+ extW = mVInfo.xres;
+ extH = mVInfo.yres;
+ }
+}
+
+/* Sets the virtual resolution to match that of the primary
+ display in the event that the virtual display currently
+ connected has a lower resolution. NB: we always report the
+ highest available resolution to SurfaceFlinger.
+*/
+void VirtualDisplay::setToPrimary(uint32_t maxArea,
+ uint32_t priW,
+ uint32_t priH,
+ uint32_t &extW,
+ uint32_t &extH) {
+ // for eg., primary in 1600p and WFD in 1080p
+ // we wont use downscale feature because MAX MDP
+ // writeback resolution supported is 1080p (tracked
+ // by SUPPORTED_VIRTUAL_AREA).
+ if((maxArea == (priW * priH))
+ && (maxArea <= SUPPORTED_VIRTUAL_AREA)) {
+ extW = priW;
+ extH = priH;
+ // If WFD is in landscape, assign the higher dimension
+ // to WFD's xres.
+ if(priH > priW) {
+ extW = priH;
+ extH = priW;
+ }
+ }
+}
+
+/* Set External Display MDP Downscale mode indicator. Only set to
+ TRUE for the following scenarios:
+ 1. Valid DRC scenarios i.e. when the original WFD resolution
+ is greater than the new/requested resolution in mVInfo.
+ 2. WFD down scale path i.e. when WFD resolution is lower than
+ primary resolution.
+ Furthermore, downscale mode is only valid when downscaling from
+ SUPPORTED_VIRTUAL_AREA to a lower resolution.
+ (SUPPORTED_VIRTUAL_AREA represents the maximum resolution that
+ we can configure to the virtual display)
+*/
+void VirtualDisplay::setDownScaleMode(uint32_t maxArea) {
+ if((maxArea > (mVInfo.xres * mVInfo.yres))
+ && (maxArea <= SUPPORTED_VIRTUAL_AREA)) {
+ mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = true;
+ }else {
+ mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = false;
+ }
+}
+
void VirtualDisplay::setAttributes() {
if(mHwcContext) {
- unsigned int &w = mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres;
- unsigned int &h = mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres;
+ uint32_t &extW = mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres;
+ uint32_t &extH = mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres;
+ uint32_t priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+ uint32_t priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
- // Always set dpyAttr res to mVInfo res, only on an ONLINE event. Keep
- // the original configuration to cater for DRC initiated RESUME events
- if(w == 0 || h == 0){
- w = mVInfo.xres;
- h = mVInfo.yres;
- }
- mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = false;
+ initResolution(extW, extH);
if(!qdutils::MDPVersion::getInstance().is8x26()) {
- uint32_t priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
- uint32_t priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
- // Find the maximum resolution between primary and virtual
- uint32_t maxArea = max((w * h), (priW * priH));
+ // maxArea represents the maximum resolution between
+ // primary and virtual display.
+ uint32_t maxArea = max((extW * extH), (priW * priH));
- // If primary resolution is more than the wfd resolution
- // configure dpy attr to primary resolution and set
- // downscale mode.
- // DRC is only valid when the original resolution on the WiFi
- // display is greater than the new resolution in mVInfo.
- if(maxArea > (mVInfo.xres * mVInfo.yres)) {
- if(maxArea == (priW * priH)) {
- // Here we account for the case when primary resolution is
- // greater than that of the WiFi display
- w = priW;
- h = priH;
- // WFD is always in landscape, so always assign the higher
- // dimension to wfd's xres
- if(priH > priW) {
- w = priH;
- h = priW;
- }
- }
- // Set External Display MDP Downscale mode indicator
- mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = true;
- }
+ setToPrimary(maxArea, priW, priH, extW, extH);
+
+ setDownScaleMode(maxArea);
}
mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].vsync_period =
1000000000l /60;
diff --git a/libvirtual/virtual.h b/libvirtual/virtual.h
index 8003e23..a6aec40 100644
--- a/libvirtual/virtual.h
+++ b/libvirtual/virtual.h
@@ -52,6 +52,10 @@
bool openFrameBuffer();
bool closeFrameBuffer();
void setAttributes();
+ void initResolution(uint32_t &extW, uint32_t &extH);
+ void setToPrimary(uint32_t maxArea, uint32_t priW, uint32_t priH,
+ uint32_t &extW, uint32_t &extH);
+ void setDownScaleMode(uint32_t maxArea);
int mFd;
hwc_context_t *mHwcContext;