Merge "hwc: Empty first read to avoid stale data at boot"
diff --git a/libexternal/Android.mk b/libexternal/Android.mk
index f723113..3df6984 100644
--- a/libexternal/Android.mk
+++ b/libexternal/Android.mk
@@ -6,7 +6,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
-LOCAL_SHARED_LIBRARIES := $(common_libs) liboverlay
+LOCAL_SHARED_LIBRARIES := $(common_libs) liboverlay libqdutils
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdexternal\"
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
LOCAL_SRC_FILES := external.cpp
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index b247dfb..89d63e9 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -34,6 +34,7 @@
#include "external.h"
#include "overlayUtils.h"
#include "overlay.h"
+#include "mdp_version.h"
using namespace android;
@@ -65,6 +66,11 @@
return 0;
}
+void ExternalDisplay::getAttributes(int& width, int& height) {
+ int fps = 0;
+ getAttrForMode(width, height, fps);
+}
+
int ExternalDisplay::teardown() {
closeFrameBuffer();
resetInfo();
@@ -564,15 +570,38 @@
return ret;
}
+
void ExternalDisplay::setAttributes() {
int width = 0, height = 0, fps = 0;
getAttrForMode(width, height, fps);
-
ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
- mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
- mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
- mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
- 1000000000l / fps;
+ if(mHwcContext) {
+ // Always set dpyAttr res to mVInfo res
+ mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
+ mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
+ mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode = false;
+ if(!qdutils::MDPVersion::getInstance().is8x26()) {
+ int priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+ int priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+ // if primary resolution is more than the hdmi resolution
+ // configure dpy attr to primary resolution and set
+ // downscale mode
+ if((priW * priH) > (width * height)) {
+ mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priW;
+ mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priH;
+ // HDMI is always in landscape, so always assign the higher
+ // dimension to hdmi's xres
+ if(priH > priW) {
+ mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priH;
+ mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priW;
+ }
+ // Set External Display MDP Downscale mode indicator
+ mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode =true;
+ }
+ }
+ mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
+ 1000000000l / fps;
+ }
}
void ExternalDisplay::getAttrForMode(int& width, int& height, int& fps) {
diff --git a/libexternal/external.h b/libexternal/external.h
index 2fbb027..1a3602d 100644
--- a/libexternal/external.h
+++ b/libexternal/external.h
@@ -45,6 +45,7 @@
void setActionSafeDimension(int w, int h);
bool isCEUnderscanSupported() { return mUnderscanSupported; }
int configure();
+ void getAttributes(int& width, int& height);
int teardown();
bool isConnected() {
return mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].connected;
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 6c7f26d..113e916 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -141,18 +141,6 @@
}
}
-static int display_commit(hwc_context_t *ctx, int dpy) {
- struct mdp_display_commit commit_info;
- memset(&commit_info, 0, sizeof(struct mdp_display_commit));
- commit_info.flags = MDP_DISPLAY_COMMIT_OVERLAY;
- if(ioctl(ctx->dpyAttr[dpy].fd, MSMFB_DISPLAY_COMMIT, &commit_info) < 0){
- ALOGE("%s: MSMFB_DISPLAY_COMMIT for dpy %d failed", __FUNCTION__,
- dpy);
- return -errno;
- }
- return 0;
-}
-
static int hwc_prepare_primary(hwc_composer_device_1 *dev,
hwc_display_contents_1_t *list) {
hwc_context_t* ctx = (hwc_context_t*)(dev);
@@ -373,14 +361,22 @@
* activate/deactive VIRTUAL DISPLAY */
if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) {
- if(blank)
- display_commit(ctx, HWC_DISPLAY_VIRTUAL);
+ if(blank) {
+ int dpy = HWC_DISPLAY_VIRTUAL;
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail for virtual!", __FUNCTION__);
+ ret = -1;
+ }
+ }
ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
}
break;
case HWC_DISPLAY_EXTERNAL:
if(blank) {
- display_commit(ctx, HWC_DISPLAY_EXTERNAL);
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail for external!", __FUNCTION__);
+ ret = -1;
+ }
}
break;
default:
@@ -391,7 +387,7 @@
ALOGD_IF(BLANK_DEBUG, "%s: Done %s display: %d", __FUNCTION__,
blank ? "blanking":"unblanking", dpy);
- return 0;
+ return ret;
}
static int hwc_query(struct hwc_composer_device_1* dev,
@@ -455,8 +451,8 @@
}
}
- if (display_commit(ctx, dpy) < 0) {
- ALOGE("%s: display commit fail!", __FUNCTION__);
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
ret = -1;
}
}
@@ -475,49 +471,47 @@
if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
- ctx->dpyAttr[dpy].connected) {
+ ctx->dpyAttr[dpy].connected &&
+ !ctx->dpyAttr[dpy].isPause) {
+ 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])
+ copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
- if(!ctx->dpyAttr[dpy].isPause) {
- 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])
- copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
+ if(list->numHwLayers > 1)
+ hwc_sync(ctx, list, dpy, fd);
- if(list->numHwLayers > 1)
- hwc_sync(ctx, list, dpy, fd);
+ // Dump the layers for external
+ if(ctx->mHwcDebug[dpy])
+ ctx->mHwcDebug[dpy]->dumpLayers(list);
- // Dump the layers for external
- if(ctx->mHwcDebug[dpy])
- ctx->mHwcDebug[dpy]->dumpLayers(list);
+ if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+ ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+ ret = -1;
+ }
- if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
- ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+ int extOnlyLayerIndex =
+ ctx->listStats[dpy].extOnlyLayerIndex;
+
+ private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
+ if(extOnlyLayerIndex!= -1) {
+ hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
+ hnd = (private_handle_t *)extLayer->handle;
+ } else if(copybitDone) {
+ hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
+ }
+
+ if(hnd && !isYuvBuffer(hnd)) {
+ if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
+ ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
ret = -1;
}
-
- int extOnlyLayerIndex =
- ctx->listStats[dpy].extOnlyLayerIndex;
-
- private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
- if(extOnlyLayerIndex!= -1) {
- hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
- hnd = (private_handle_t *)extLayer->handle;
- } else if(copybitDone) {
- hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
- }
-
- if(hnd && !isYuvBuffer(hnd)) {
- if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
- ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
- ret = -1;
- }
- }
}
- if (display_commit(ctx, dpy) < 0) {
- ALOGE("%s: display commit fail!", __FUNCTION__);
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
ret = -1;
}
}
@@ -574,15 +568,15 @@
}
}
- if (display_commit(ctx, dpy) < 0) {
- ALOGE("%s: display commit fail!", __FUNCTION__);
+ if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
ret = -1;
}
}
closeAcquireFds(list);
- if (list && !ctx->mVirtualonExtActive) {
+ if (list && !ctx->mVirtualonExtActive && (list->retireFenceFd < 0) ) {
// SF assumes HWC waits for the acquire fence and returns a new fence
// that signals when we're done. Since we don't wait, and also don't
// touch the buffer, we can just handle the acquire fence back to SF
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 068e28a..a395ee0 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -127,6 +127,20 @@
return renderArea;
}
+bool checkNonWormholeRegion(private_handle_t* hnd, hwc_rect_t& rect)
+{
+ unsigned int height = rect.bottom - rect.top;
+ unsigned int width = rect.right - rect.left;
+ copybit_image_t buf;
+ buf.w = ALIGN(hnd->width, 32);
+ buf.h = hnd->height;
+
+ if (buf.h != height || buf.w != width)
+ return false;
+
+ return true;
+}
+
bool CopyBit::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy) {
@@ -181,6 +195,15 @@
if (layer->planeAlpha != 0xFF)
return true;
}
+ /*
+ * Fallback to GPU in MDP3 when NonWormholeRegion is not of frame buffer
+ * size as artifact is seen in WormholeRegion of previous frame.
+ */
+ hwc_rect_t nonWormHoleRegion;
+ getNonWormholeRegion(list, nonWormHoleRegion);
+ if(!checkNonWormholeRegion(fbHnd, nonWormHoleRegion))
+ return true;
+
}
//Allocate render buffers if they're not allocated
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index ac2650c..ab3561f 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -26,10 +26,12 @@
#include "hwc_fbupdate.h"
#include "mdp_version.h"
#include "external.h"
+#include "virtual.h"
using namespace qdutils;
using namespace overlay;
using overlay::Rotator;
+using namespace overlay::utils;
namespace qhwc {
@@ -114,34 +116,42 @@
ovutils::eTransform orient =
static_cast<ovutils::eTransform>(transform);
+ // use ext orientation if any
+ int extOrient = ctx->mExtOrientation;
+ if(ctx->mBufferMirrorMode)
+ extOrient = getMirrorModeOrientation(ctx);
// Do not use getNonWormholeRegion() function to calculate the
// sourceCrop during animation on external display and
// Dont do wormhole calculation when extorientation is set on External
+ // Dont do wormhole calculation when extDownscale is enabled on External
if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
sourceCrop = layer->displayFrame;
displayFrame = sourceCrop;
- } else if((!mDpy || (mDpy && !ctx->mExtOrientation))
- && extOnlyLayerIndex == -1) {
+ } else if((!mDpy ||
+ (mDpy && !extOrient
+ && !ctx->dpyAttr[mDpy].mDownScaleMode))
+ && (extOnlyLayerIndex == -1)) {
if(!qdutils::MDPVersion::getInstance().is8x26()) {
getNonWormholeRegion(list, sourceCrop);
displayFrame = sourceCrop;
}
}
-
if(mDpy && !qdutils::MDPVersion::getInstance().is8x26()) {
- if(ctx->mExtOrientation) {
- calcExtDisplayPosition(ctx, mDpy, displayFrame);
+ if(extOrient || ctx->dpyAttr[mDpy].mDownScaleMode) {
+ calcExtDisplayPosition(ctx, mDpy, sourceCrop, displayFrame);
// If there is a external orientation set, use that
- transform = ctx->mExtOrientation;
- orient = static_cast<ovutils::eTransform >(ctx->mExtOrientation);
+ if(extOrient) {
+ transform = extOrient;
+ orient = static_cast<ovutils::eTransform >(extOrient);
+ }
}
// Calculate the actionsafe dimensions for External(dpy = 1 or 2)
getActionSafePosition(ctx, mDpy, displayFrame);
- }
+ }
setMdpFlags(layer, mdpFlags, 0, transform);
// For External use rotator if there is a rotation value set
- if(mDpy && (ctx->mExtOrientation & HWC_TRANSFORM_ROT_90)) {
+ if(mDpy && (extOrient & HWC_TRANSFORM_ROT_90)) {
mRot = ctx->mRotMgr->getNext();
if(mRot == NULL) return -1;
//Configure rotator for pre-rotation
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 81ccfed..f2217b9 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -55,6 +55,9 @@
void MDPComp::dump(android::String8& buf)
{
+ if(mCurrentFrame.layerCount > MAX_NUM_APP_LAYERS)
+ return;
+
dumpsys_log(buf,"HWC Map for Dpy: %s \n",
(mDpy == 0) ? "\"PRIMARY\"" :
(mDpy == 1) ? "\"EXTERNAL\"" : "\"VIRTUAL\"");
@@ -439,11 +442,15 @@
hwc_layer_1_t* layer = &list->hwLayers[i];
private_handle_t *hnd = (private_handle_t *)layer->handle;
- if((layer->transform & HWC_TRANSFORM_ROT_90) && !isYuvBuffer(hnd)) {
- ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__);
- return false;
+ 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__);
+ return false;
+ }
}
-
if(!isValidDimension(ctx,layer)) {
ALOGD_IF(isDebug(), "%s: Buffer is of invalid width",
__FUNCTION__);
@@ -557,6 +564,11 @@
return false;
}
+ if(layer->transform & HWC_TRANSFORM_ROT_90 && !canUseRotator(ctx,mDpy)) {
+ ALOGD_IF(isDebug(), "%s: no free DMA pipe",__FUNCTION__);
+ return false;
+ }
+
if(isSecuring(ctx, layer)) {
ALOGD_IF(isDebug(), "%s: MDP securing is active", __FUNCTION__);
return false;
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 45c82fd..12a9f32 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -64,6 +64,9 @@
case IQService::EXTERNAL_ORIENTATION:
setExtOrientation(value);
break;
+ case IQService::BUFFER_MIRRORMODE:
+ setBufferMirrorMode(value);
+ break;
default:
return NO_ERROR;
}
@@ -118,4 +121,8 @@
mHwcContext->mExtOrientation = orientation;
}
+void QClient::setBufferMirrorMode(uint32_t enable) {
+ mHwcContext->mBufferMirrorMode = enable;
+}
+
}
diff --git a/libhwcomposer/hwc_qclient.h b/libhwcomposer/hwc_qclient.h
index 4cbabef..848d8d2 100644
--- a/libhwcomposer/hwc_qclient.h
+++ b/libhwcomposer/hwc_qclient.h
@@ -61,6 +61,7 @@
void unsecuring(uint32_t startEnd);
android::status_t screenRefresh();
void setExtOrientation(uint32_t orientation);
+ void setBufferMirrorMode(uint32_t enable);
hwc_context_t *mHwcContext;
const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier;
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 916b346..5590798 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -33,7 +33,7 @@
#include "external.h"
#include "virtual.h"
#include "mdp_version.h"
-
+using namespace overlay;
namespace qhwc {
#define HWC_UEVENT_SWITCH_STR "change@/devices/virtual/switch/"
#define HWC_UEVENT_THREAD_NAME "hwcUeventThread"
@@ -233,7 +233,6 @@
* surface for the same. */
ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = true;
}
-
if(dpy == HWC_DISPLAY_EXTERNAL ||
ctx->mVirtualonExtActive) {
ALOGE_IF(UEVENT_DEBUG, "%s: Sending EXTERNAL_OFFLINE ONLINE"
@@ -243,33 +242,51 @@
}
break;
}
- case EXTERNAL_PAUSE:
- {
- ctx->dpyAttr[dpy].isActive = true;
- ctx->dpyAttr[dpy].isPause = true;
- break;
- }
- case EXTERNAL_RESUME:
- {
- //Treat Resume as Online event
- //Since external didnt have any pipes, force primary to give up
- //its pipes; we don't allow inter-mixer pipe transfers.
- {
- Locker::Autolock _l(ctx->mDrawLock);
- ctx->dpyAttr[dpy].isConfiguring = true;
- ctx->dpyAttr[dpy].isActive = true;
- ctx->proc->invalidate(ctx->proc);
+ case EXTERNAL_PAUSE:
+ { // pause case
+ ALOGD("%s Received Pause event",__FUNCTION__);
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ ctx->dpyAttr[dpy].isActive = true;
+ ctx->dpyAttr[dpy].isPause = true;
+ ctx->proc->invalidate(ctx->proc);
+ }
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+ // At this point all the pipes used by External have been
+ // marked as UNSET.
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ // Perform commit to unstage the pipes.
+ if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+ ALOGE("%s: display commit fail! for %d dpy",
+ __FUNCTION__, dpy);
+ }
+ }
+ break;
}
- usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
- * 2 / 1000);
- {
- //At this point external has all the pipes it would need.
- Locker::Autolock _l(ctx->mDrawLock);
- ctx->dpyAttr[dpy].isPause = false;
- ctx->proc->invalidate(ctx->proc);
+ case EXTERNAL_RESUME:
+ { // resume case
+ ALOGD("%s Received resume event",__FUNCTION__);
+ //Treat Resume as Online event
+ //Since external didnt have any pipes, force primary to give up
+ //its pipes; we don't allow inter-mixer pipe transfers.
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ ctx->dpyAttr[dpy].isConfiguring = true;
+ ctx->dpyAttr[dpy].isActive = true;
+ ctx->proc->invalidate(ctx->proc);
+ }
+ usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+ * 2 / 1000);
+ //At this point external has all the pipes it would need.
+ {
+ Locker::Autolock _l(ctx->mDrawLock);
+ ctx->dpyAttr[dpy].isPause = false;
+ ctx->proc->invalidate(ctx->proc);
+ }
+ break;
}
- break;
- }
default:
{
ALOGE("%s: Invalid state to swtich:%d", __FUNCTION__, switch_state);
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 34ed842..d0909a6 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -159,6 +159,9 @@
ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected = false;
ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = false;
ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected = false;
+ ctx->dpyAttr[HWC_DISPLAY_PRIMARY].mDownScaleMode= false;
+ ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode = false;
+ ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = false;
ctx->mMDPComp[HWC_DISPLAY_PRIMARY] =
MDPComp::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres,
@@ -193,6 +196,8 @@
ctx->mPrevDestVideo.right = ctx->mPrevDestVideo.bottom = 0;
ctx->mPrevTransformVideo = 0;
+ ctx->mBufferMirrorMode = false;
+
ALOGI("Initializing Qualcomm Hardware Composer");
ALOGI("MDP version: %d", ctx->mMDP.version);
}
@@ -294,7 +299,11 @@
float fbHeight = ctx->dpyAttr[dpy].yres;
// Since external is rotated 90, need to swap width/height
- if(ctx->mExtOrientation & HWC_TRANSFORM_ROT_90)
+ int extOrient = ctx->mExtOrientation;
+ if(ctx->mBufferMirrorMode)
+ extOrient = getMirrorModeOrientation(ctx);
+
+ if(extOrient & HWC_TRANSFORM_ROT_90)
swap(fbWidth, fbHeight);
float asX = 0;
@@ -414,6 +423,56 @@
"y = %d w = %d h = %d", __FUNCTION__, outPos.x, outPos.y,
outPos.w, outPos.h);
+ // For sidesync, the dest fb will be in portrait orientation, and the crop
+ // will be updated to avoid the black side bands, and it will be upscaled
+ // to fit the dest RB, so recalculate
+ // the position based on the new width and height
+ if ((extOrientation & HWC_TRANSFORM_ROT_90) &&
+ isOrientationPortrait(ctx)) {
+ hwc_rect_t r;
+ //Calculate the position
+ xRatio = (outPos.x - xPos)/width;
+ // GetaspectRatio -- tricky to get the correct aspect ratio
+ // But we need to do this.
+ getAspectRatioPosition(width, height, width, height, r);
+ xPos = r.left;
+ yPos = r.top;
+ float tempWidth = r.right - r.left;
+ float tempHeight = r.bottom - r.top;
+ yRatio = yPos/height;
+ wRatio = outPos.w/width;
+ hRatio = tempHeight/height;
+
+ //Map the coordinates back to Framebuffer domain
+ outPos.x = (xRatio * fbWidth);
+ outPos.y = (yRatio * fbHeight);
+ outPos.w = wRatio * fbWidth;
+ outPos.h = hRatio * fbHeight;
+
+ ALOGD_IF(HWC_UTILS_DEBUG, "%s: Calculated AspectRatio for device in"
+ "portrait: x = %d,y = %d w = %d h = %d", __FUNCTION__,
+ outPos.x, outPos.y,
+ outPos.w, outPos.h);
+ }
+ if(ctx->dpyAttr[dpy].mDownScaleMode) {
+ int extW, extH;
+ if(dpy == HWC_DISPLAY_EXTERNAL)
+ ctx->mExtDisplay->getAttributes(extW, extH);
+ else
+ ctx->mVirtualDisplay->getAttributes(extW, extH);
+ fbWidth = ctx->dpyAttr[dpy].xres;
+ fbHeight = ctx->dpyAttr[dpy].yres;
+ //Calculate the position...
+ xRatio = outPos.x/fbWidth;
+ yRatio = outPos.y/fbHeight;
+ wRatio = outPos.w/fbWidth;
+ hRatio = outPos.h/fbHeight;
+
+ outPos.x = xRatio * extW;
+ outPos.y = yRatio * extH;
+ outPos.w = wRatio * extW;
+ outPos.h = hRatio * extH;
+ }
// Convert Dim to hwc_rect_t
outRect.left = outPos.x;
outRect.top = outPos.y;
@@ -432,20 +491,82 @@
return false;
}
-void calcExtDisplayPosition(hwc_context_t *ctx,
- int dpy, hwc_rect_t& displayFrame) {
- int dstWidth = ctx->dpyAttr[dpy].xres;
- int dstHeight = ctx->dpyAttr[dpy].yres;;
- int srcWidth = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
- int srcHeight = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+bool isOrientationPortrait(hwc_context_t *ctx) {
+ if(isPrimaryPortrait(ctx)) {
+ return !(ctx->deviceOrientation & 0x1);
+ }
+ return (ctx->deviceOrientation & 0x1);
+}
+
+void calcExtDisplayPosition(hwc_context_t *ctx, int dpy,
+ hwc_rect_t& sourceCrop,
+ hwc_rect_t& displayFrame) {
// Swap width and height when there is a 90deg transform
- if(ctx->mExtOrientation & HWC_TRANSFORM_ROT_90) {
+ int extOrient = ctx->mExtOrientation;
+ if(ctx->mBufferMirrorMode)
+ extOrient = getMirrorModeOrientation(ctx);
+ if(extOrient & HWC_TRANSFORM_ROT_90) {
+ int dstWidth = ctx->dpyAttr[dpy].xres;
+ int dstHeight = ctx->dpyAttr[dpy].yres;;
+ int srcWidth = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+ int srcHeight = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
if(!isPrimaryPortrait(ctx)) {
swap(srcWidth, srcHeight);
} // Get Aspect Ratio for external
getAspectRatioPosition(dstWidth, dstHeight, srcWidth,
srcHeight, displayFrame);
+ // Crop - this is needed, because for sidesync, the dest fb will
+ // be in portrait orientation, so update the crop to not show the
+ // black side bands.
+ if (isOrientationPortrait(ctx)) {
+ sourceCrop = displayFrame;
+ displayFrame.left = 0;
+ displayFrame.top = 0;
+ displayFrame.right = dstWidth;
+ displayFrame.bottom = dstHeight;
+ }
}
+ if(ctx->dpyAttr[dpy].mDownScaleMode) {
+ int extW, extH;
+ // if downscale is enabled, map the co-ordinates to new
+ // domain(downscaled)
+ float fbWidth = ctx->dpyAttr[dpy].xres;
+ float fbHeight = ctx->dpyAttr[dpy].yres;
+ // query MDP configured attributes
+ if(dpy == HWC_DISPLAY_EXTERNAL)
+ ctx->mExtDisplay->getAttributes(extW, extH);
+ else
+ ctx->mVirtualDisplay->getAttributes(extW, extH);
+ //Calculate the ratio...
+ float wRatio = ((float)extW)/fbWidth;
+ float hRatio = ((float)extH)/fbHeight;
+
+ //convert Dim to hwc_rect_t
+ displayFrame.left *= wRatio;
+ displayFrame.top *= hRatio;
+ displayFrame.right *= wRatio;
+ displayFrame.bottom *= hRatio;
+ }
+}
+
+/* Returns the orientation which needs to be set on External for
+ * SideSync/Buffer Mirrormode
+ */
+int getMirrorModeOrientation(hwc_context_t *ctx) {
+ int extOrientation = 0;
+ int deviceOrientation = ctx->deviceOrientation;
+ if(!isPrimaryPortrait(ctx))
+ deviceOrientation = (deviceOrientation + 1) % 4;
+ if (deviceOrientation == 0)
+ extOrientation = HWC_TRANSFORM_ROT_270;
+ else if (deviceOrientation == 1)//90
+ extOrientation = 0;
+ else if (deviceOrientation == 2)//180
+ extOrientation = HWC_TRANSFORM_ROT_90;
+ else if (deviceOrientation == 3)//270
+ extOrientation = HWC_TRANSFORM_FLIP_V | HWC_TRANSFORM_FLIP_H;
+
+ return extOrientation;
}
bool needsScaling(hwc_context_t* ctx, hwc_layer_1_t const* layer,
@@ -530,8 +651,9 @@
yuvCount++;
if((layer->transform & HWC_TRANSFORM_ROT_90) &&
- canUseRotator(ctx)) {
- if(ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
+ canUseRotator(ctx, dpy)) {
+ if( (dpy == HWC_DISPLAY_PRIMARY) &&
+ ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
ctx->isPaddingRound = true;
}
Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
@@ -570,9 +692,10 @@
ctx->mExtOrientation = atoi(value); */
// Assuming the orientation value is in terms of HAL_TRANSFORM,
// This needs mapping to HAL, if its in different convention
- if(ctx->mExtOrientation) {
- ALOGD_IF(HWC_UTILS_DEBUG, "%s: ext orientation = %d",
- __FUNCTION__, ctx->mExtOrientation);
+ if(ctx->mExtOrientation || ctx->mBufferMirrorMode) {
+ ALOGD_IF(HWC_UTILS_DEBUG, "%s: ext orientation = %d"
+ "BufferMirrorMode = %d", __FUNCTION__,
+ ctx->mExtOrientation, ctx->mBufferMirrorMode);
if(ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
ctx->isPaddingRound = true;
}
@@ -960,10 +1083,16 @@
}
}
-int configRotator(Rotator *rot, const Whf& whf,
+int configRotator(Rotator *rot, Whf& whf,
hwc_rect_t& crop, const eMdpFlags& mdpFlags,
const eTransform& orient, const int& downscale) {
+ // Fix alignments for TILED format
+ if(whf.format == MDP_Y_CRCB_H2V2_TILE ||
+ whf.format == MDP_Y_CBCR_H2V2_TILE) {
+ whf.w = utils::alignup(whf.w, 64);
+ whf.h = utils::alignup(whf.h, 32);
+ }
rot->setSource(whf);
if (qdutils::MDPVersion::getInstance().getMDPVersion() >=
@@ -1084,10 +1213,17 @@
}
}
if(dpy) {
+ int extOrient = ctx->mExtOrientation;
+ if(ctx->mBufferMirrorMode)
+ extOrient = getMirrorModeOrientation(ctx);
// Just need to set the position to portrait as the transformation
// will already be set to required orientation on TV
- if(ctx->mExtOrientation) {
- getAspectRatioPosition(ctx, dpy, ctx->mExtOrientation, dst, dst);
+ if(extOrient || ctx->dpyAttr[dpy].mDownScaleMode) {
+ getAspectRatioPosition(ctx, dpy, extOrient, dst, dst);
+ if(extOrient) {
+ transform = extOrient;
+ orient = static_cast<eTransform>(transform);
+ }
}
// Calculate the actionsafe dimensions for External(dpy = 1 or 2)
getActionSafePosition(ctx, dpy, dst);
@@ -1295,10 +1431,15 @@
return 0;
}
-bool canUseRotator(hwc_context_t *ctx) {
+bool canUseRotator(hwc_context_t *ctx, int dpy) {
if(qdutils::MDPVersion::getInstance().is8x26() &&
- ctx->mVirtualDisplay->isConnected()) {
- return false;
+ ctx->mVirtualDisplay->isConnected() &&
+ !ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause) {
+ // Allow if YUV needs rotation and DMA is configured to BLOCK mode for
+ // primary. For portrait videos usecase on WFD, Driver supports
+ // multiplexing of DMA pipe in LINE and BLOCK mode.
+ if(dpy == HWC_DISPLAY_PRIMARY)
+ return false;
}
if(ctx->mMDP.version == qdutils::MDP_V3_0_4)
return false;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 50c6a7a..1c54942 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -83,6 +83,8 @@
// To trigger padding round to clean up mdp
// pipes
bool isConfiguring;
+ // External Display is in MDP Downscale mode indicator
+ bool mDownScaleMode;
};
struct ListStats {
@@ -186,8 +188,15 @@
bool isPrimaryPortrait(hwc_context_t *ctx);
+bool isOrientationPortrait(hwc_context_t *ctx);
+
void calcExtDisplayPosition(hwc_context_t *ctx,
- int dpy, hwc_rect_t& displayFrame);
+ int dpy,
+ hwc_rect_t& sourceCrop,
+ hwc_rect_t& displayFrame);
+// Returns the orientation that needs to be set on external for
+// BufferMirrirMode(Sidesync)
+int getMirrorModeOrientation(hwc_context_t *ctx);
//Close acquireFenceFds of all layers of incoming list
void closeAcquireFds(hwc_display_contents_1_t* list);
@@ -205,7 +214,7 @@
ovutils::eMdpFlags &mdpFlags,
int rotDownscale, int transform);
-int configRotator(overlay::Rotator *rot, const ovutils::Whf& whf,
+int configRotator(overlay::Rotator *rot, ovutils::Whf& whf,
hwc_rect_t& crop, const ovutils::eMdpFlags& mdpFlags,
const ovutils::eTransform& orient, const int& downscale);
@@ -235,7 +244,7 @@
//extreme unavailability of pipes. This can also be done via hybrid calculations
//also involving many more variables like number of write-back interfaces etc,
//but the variety of scenarios is too high to warrant that.
-bool canUseRotator(hwc_context_t *ctx);
+bool canUseRotator(hwc_context_t *ctx, int dpy);
int getLeftSplit(hwc_context_t *ctx, const int& dpy);
@@ -356,6 +365,11 @@
int mExtOrientation;
//Flags the transition of a video session
bool mVideoTransFlag;
+
+ //Used for SideSync feature
+ //which overrides the mExtOrientation
+ bool mBufferMirrorMode;
+
qhwc::LayerRotMap *mLayerRotMap[HWC_NUM_DISPLAY_TYPES];
};
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index ea25358..afe62e2 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -63,8 +63,6 @@
}
void Overlay::configDone() {
- if(PipeBook::pipeUsageUnchanged()) return;
-
for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
if(PipeBook::isNotUsed(i)) {
//Forces UNSET on pipes, flushes rotator memory and session, closes
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index c3d00f1..927e7e9 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -119,6 +119,9 @@
case HAL_PIXEL_FORMAT_YCrCb_444_SP:
return MDP_Y_CRCB_H1V1;
case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+ case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+ //NV12 encodeable format maps to the venus format on
+ //B-Family targets
return MDP_Y_CBCR_H2V2_VENUS;
default:
//Unsupported by MDP
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index a3ff150..e45f42e 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -78,6 +78,13 @@
data.writeInt32(orientation);
remote()->transact(EXTERNAL_ORIENTATION, data, &reply);
}
+
+ virtual void setBufferMirrorMode(uint32_t enable) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IQService::getInterfaceDescriptor());
+ data.writeInt32(enable);
+ remote()->transact(BUFFER_MIRRORMODE, data, &reply);
+ }
};
IMPLEMENT_META_INTERFACE(QService, "android.display.IQService");
@@ -160,6 +167,18 @@
setExtOrientation(orientation);
return NO_ERROR;
} break;
+ case BUFFER_MIRRORMODE: {
+ CHECK_INTERFACE(IQService, data, reply);
+ if(callerUid != AID_SYSTEM) {
+ ALOGE("display.qservice BUFFER_MIRRORMODE access denied: \
+ pid=%d uid=%d process=%s",callerPid,
+ callerUid, callingProcName);
+ return PERMISSION_DENIED;
+ }
+ uint32_t enable = data.readInt32();
+ setBufferMirrorMode(enable);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index ff034be..149cd8b 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -42,6 +42,7 @@
CONNECT,
SCREEN_REFRESH,
EXTERNAL_ORIENTATION,
+ BUFFER_MIRRORMODE,
};
enum {
END = 0,
@@ -52,6 +53,7 @@
virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
virtual android::status_t screenRefresh() = 0;
virtual void setExtOrientation(uint32_t orientation) = 0;
+ virtual void setBufferMirrorMode(uint32_t enable) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index f780a75..a8c5dca 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -77,6 +77,12 @@
}
}
+void QService::setBufferMirrorMode(uint32_t enable) {
+ if(mClient.get()) {
+ mClient->notifyCallback(BUFFER_MIRRORMODE, enable);
+ }
+}
+
void QService::init()
{
if(!sQService) {
diff --git a/libqservice/QService.h b/libqservice/QService.h
index 8eefa21..a241d44 100644
--- a/libqservice/QService.h
+++ b/libqservice/QService.h
@@ -50,6 +50,7 @@
virtual void connect(const android::sp<qClient::IQClient>& client);
virtual android::status_t screenRefresh();
virtual void setExtOrientation(uint32_t orientation);
+ virtual void setBufferMirrorMode(uint32_t enable);
static void init();
private:
QService();
diff --git a/libvirtual/Android.mk b/libvirtual/Android.mk
index 1231f8d..beeef25 100644
--- a/libvirtual/Android.mk
+++ b/libvirtual/Android.mk
@@ -6,7 +6,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
-LOCAL_SHARED_LIBRARIES := $(common_libs) liboverlay
+LOCAL_SHARED_LIBRARIES := $(common_libs) liboverlay libqdutils
LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"qdvirtual\"
LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
LOCAL_SRC_FILES := virtual.cpp
diff --git a/libvirtual/virtual.cpp b/libvirtual/virtual.cpp
index e2f239a..8e96a56 100644
--- a/libvirtual/virtual.cpp
+++ b/libvirtual/virtual.cpp
@@ -47,6 +47,7 @@
#include "virtual.h"
#include "overlayUtils.h"
#include "overlay.h"
+#include "mdp_version.h"
using namespace android;
@@ -67,6 +68,11 @@
return 0;
}
+void VirtualDisplay::getAttributes(int& width, int& height) {
+ width = mVInfo.xres;
+ height = mVInfo.yres;
+}
+
int VirtualDisplay::teardown() {
closeFrameBuffer();
memset(&mVInfo, 0, sizeof(mVInfo));
@@ -85,12 +91,35 @@
}
void VirtualDisplay::setAttributes() {
- mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = mVInfo.xres;
- mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = mVInfo.yres;
- mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].vsync_period =
- 1000000000l /60;
- ALOGD_IF(DEBUG,"%s: Setting Virtual Attr: res(%d x %d)",__FUNCTION__,
- mVInfo.xres, mVInfo.yres);
+ if(mHwcContext) {
+ // Always set dpyAttr res to mVInfo res
+ mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = mVInfo.xres;
+ mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = mVInfo.yres;
+ mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = false;
+ if(!qdutils::MDPVersion::getInstance().is8x26()) {
+ uint32_t priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+ uint32_t priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+ // if primary resolution is more than the wfd resolution
+ // configure dpy attr to primary resolution and set
+ // downscale mode
+ if((priW * priH) > (mVInfo.xres * mVInfo.yres)) {
+ mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = priW;
+ mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = priH;
+ // WFD is always in landscape, so always assign the higher
+ // dimension to wfd's xres
+ if(priH > priW) {
+ mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = priH;
+ mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = priW;
+ }
+ // Set External Display MDP Downscale mode indicator
+ mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = true;
+ }
+ }
+ mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].vsync_period =
+ 1000000000l /60;
+ ALOGD_IF(DEBUG,"%s: Setting Virtual Attr: res(%d x %d)",__FUNCTION__,
+ mVInfo.xres, mVInfo.yres);
+ }
}
bool VirtualDisplay::openFrameBuffer()
diff --git a/libvirtual/virtual.h b/libvirtual/virtual.h
index cd0e7da..8003e23 100644
--- a/libvirtual/virtual.h
+++ b/libvirtual/virtual.h
@@ -43,6 +43,7 @@
VirtualDisplay(hwc_context_t* ctx);
~VirtualDisplay();
int configure();
+ void getAttributes(int& width, int& height);
int teardown();
bool isConnected() {
return mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].connected;