From ca1d2bab60d728c5458b00872361b1f3d28b4769 Mon Sep 17 00:00:00 2001 From: "Arun Kumar K.R" Date: Tue, 6 Dec 2011 22:18:21 -0800 Subject: [PATCH] qcom/display: add true mirroring support on HDMI Change-Id: I7e884e5dde2a08048a28610eb88760fcdd24d558 CRs-fixed: 316397 --- libgralloc/framebuffer.cpp | 96 +++++++---- libgralloc/gralloc_priv.h | 10 ++ libhwcomposer/hwcomposer.cpp | 14 +- liboverlay/overlayLib.cpp | 297 +++++++++++++++++++++++++++++------ liboverlay/overlayLib.h | 96 ++++++++++- 5 files changed, 434 insertions(+), 79 deletions(-) diff --git a/libgralloc/framebuffer.cpp b/libgralloc/framebuffer.cpp index 6f8594f..78fc144 100644 --- a/libgralloc/framebuffer.cpp +++ b/libgralloc/framebuffer.cpp @@ -212,6 +212,14 @@ static void *disp_loop(void *ptr) } #if defined(HDMI_DUAL_DISPLAY) +static int closeHDMIChannel(private_module_t* m) +{ + Overlay* pTemp = m->pobjOverlay; + if(pTemp != NULL) + pTemp->closeChannel(); + return 0; +} + static void *hdmi_ui_loop(void *ptr) { private_module_t* m = reinterpret_cast( @@ -227,12 +235,13 @@ static void *hdmi_ui_loop(void *ptr) } float asWidthRatio = m->actionsafeWidthRatio/100.0f; float asHeightRatio = m->actionsafeHeightRatio/100.0f; + bool waitForVsync = true; if (m->pobjOverlay) { Overlay* pTemp = m->pobjOverlay; - if (!m->enableHDMIOutput) - pTemp->closeChannel(); - else if (m->enableHDMIOutput && !m->videoOverlay) { + if (m->hdmiMirroringState == HDMI_NO_MIRRORING) + closeHDMIChannel(m); + else if(m->hdmiMirroringState == HDMI_UI_MIRRORING) { if (!pTemp->isChannelUP()) { int alignedW = ALIGN(m->info.xres, 32); @@ -244,12 +253,15 @@ static void *hdmi_ui_loop(void *ptr) info.format = hnd->format; info.size = hnd->size; - if (pTemp->startChannel(info, 1, - false, true, 0, VG0_PIPE, true)) { + if (m->trueMirrorSupport) + waitForVsync = false; + + if (pTemp->startChannel(info, FRAMEBUFFER_1, + false, true, 0, VG0_PIPE, waitForVsync)) { pTemp->setFd(m->framebuffer->fd); pTemp->setCrop(0, 0, m->info.xres, m->info.yres); } else - pTemp->closeChannel(); + closeHDMIChannel(m); } if (pTemp->isChannelUP()) { @@ -259,21 +271,23 @@ static void *hdmi_ui_loop(void *ptr) int asX = 0, asY = 0; // Action safe x, y co-ordinates int fbwidth = m->info.xres, fbheight = m->info.yres; float defaultASWidthRatio = 0.0f, defaultASHeightRatio = 0.0f; - if(HEIGHT_1080P == height) { - defaultASHeightRatio = AS_1080_RATIO_H; - defaultASWidthRatio = AS_1080_RATIO_W; - } else if(HEIGHT_720P == height) { - defaultASHeightRatio = AS_720_RATIO_H; - defaultASWidthRatio = AS_720_RATIO_W; - } else if(HEIGHT_480P == height) { - defaultASHeightRatio = AS_480_RATIO_H; - defaultASWidthRatio = AS_480_RATIO_W; + // TODO: disable OverScan for now + if(!m->trueMirrorSupport) { + if(HEIGHT_1080P == height) { + defaultASHeightRatio = AS_1080_RATIO_H; + defaultASWidthRatio = AS_1080_RATIO_W; + } else if(HEIGHT_720P == height) { + defaultASHeightRatio = AS_720_RATIO_H; + defaultASWidthRatio = AS_720_RATIO_W; + } else if(HEIGHT_480P == height) { + defaultASHeightRatio = AS_480_RATIO_H; + defaultASWidthRatio = AS_480_RATIO_W; + } + if(asWidthRatio <= 0.0f) + asWidthRatio = defaultASWidthRatio; + if(asHeightRatio <= 0.0f) + asHeightRatio = defaultASHeightRatio; } - if(asWidthRatio <= 0.0f) - asWidthRatio = defaultASWidthRatio; - if(asHeightRatio <= 0.0f) - asHeightRatio = defaultASHeightRatio; - aswidth = (int)((float)width - (float)(width * asWidthRatio)); asheight = (int)((float)height - (float)(height * asHeightRatio)); asX = (width - aswidth) / 2; @@ -348,11 +362,16 @@ static void *hdmi_ui_loop(void *ptr) pTemp->setPosition(asX, asY, aswidth, asheight); } } + if (m->trueMirrorSupport) { + // if video is started the UI channel should be NO_WAIT. + waitForVsync = !m->videoOverlay; + pTemp->updateWaitForVsyncFlags(waitForVsync); + } pTemp->queueBuffer(m->currentOffset); } } else - pTemp->closeChannel(); + closeHDMIChannel(m); } pthread_mutex_unlock(&m->overlayLock); } @@ -366,16 +385,16 @@ static int fb_videoOverlayStarted(struct framebuffer_device_t* dev, int started) pthread_mutex_lock(&m->overlayLock); Overlay* pTemp = m->pobjOverlay; if(started != m->videoOverlay) { - m->hdmiStateChanged = true; - if (started && pTemp) { - pTemp->closeChannel(); - m->videoOverlay = true; + m->videoOverlay = started; + if (!m->trueMirrorSupport) { + m->hdmiStateChanged = true; + if (started && pTemp) { + m->hdmiMirroringState = HDMI_NO_MIRRORING; + closeHDMIChannel(m); + } else if (m->enableHDMIOutput) + m->hdmiMirroringState = HDMI_UI_MIRRORING; pthread_cond_signal(&(m->overlayPost)); } - else { - m->videoOverlay = false; - pthread_cond_signal(&(m->overlayPost)); - } } pthread_mutex_unlock(&m->overlayLock); return 0; @@ -387,15 +406,25 @@ static int fb_enableHDMIOutput(struct framebuffer_device_t* dev, int enable) dev->common.module); pthread_mutex_lock(&m->overlayLock); Overlay* pTemp = m->pobjOverlay; - if (!enable && pTemp) - pTemp->closeChannel(); m->enableHDMIOutput = enable; + if(enable) { + if (m->trueMirrorSupport) { + m->hdmiMirroringState = HDMI_UI_MIRRORING; + } else { + if(!m->videoOverlay) + m->hdmiMirroringState = HDMI_UI_MIRRORING; + } + } else if (!enable && pTemp) { + m->hdmiMirroringState = HDMI_NO_MIRRORING; + closeHDMIChannel(m); + } m->hdmiStateChanged = true; pthread_cond_signal(&(m->overlayPost)); pthread_mutex_unlock(&m->overlayLock); return 0; } + static int fb_setActionSafeWidthRatio(struct framebuffer_device_t* dev, float asWidthRatio) { private_module_t* m = reinterpret_cast( @@ -409,12 +438,13 @@ static int fb_setActionSafeWidthRatio(struct framebuffer_device_t* dev, float as static int fb_setActionSafeHeightRatio(struct framebuffer_device_t* dev, float asHeightRatio) { private_module_t* m = reinterpret_cast( - dev->common.module); + dev->common.module); pthread_mutex_lock(&m->overlayLock); m->actionsafeHeightRatio = asHeightRatio; pthread_mutex_unlock(&m->overlayLock); return 0; } + static int fb_orientationChanged(struct framebuffer_device_t* dev, int orientation) { private_module_t* m = reinterpret_cast( @@ -805,6 +835,8 @@ int mapFrameBufferLocked(struct private_module_t* module) module->hdmiStateChanged = false; pthread_t hdmiUIThread; pthread_create(&hdmiUIThread, NULL, &hdmi_ui_loop, (void *) module); + module->hdmiMirroringState = HDMI_NO_MIRRORING; + module->trueMirrorSupport = FrameBufferInfo::getInstance()->canSupportTrueMirroring(); #endif return 0; diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h index 0b3fe76..d7f67f9 100644 --- a/libgralloc/gralloc_priv.h +++ b/libgralloc/gralloc_priv.h @@ -214,6 +214,14 @@ enum { BUFFER_TYPE_UI = 0, BUFFER_TYPE_VIDEO }; + +#if defined(HDMI_DUAL_DISPLAY) +enum hdmi_mirroring_state { + HDMI_NO_MIRRORING, + HDMI_UI_MIRRORING, + HDMI_ORIGINAL_RESOLUTION_MIRRORING +}; +#endif /*****************************************************************************/ struct private_module_t; @@ -277,10 +285,12 @@ struct private_module_t { bool videoOverlay; uint32_t currentOffset; bool enableHDMIOutput; + bool trueMirrorSupport; bool exitHDMIUILoop; float actionsafeWidthRatio; float actionsafeHeightRatio; bool hdmiStateChanged; + hdmi_mirroring_state hdmiMirroringState; pthread_mutex_t overlayLock; pthread_cond_t overlayPost; #endif diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index 0e20ad9..4bc7e70 100644 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -307,7 +307,19 @@ static int prepareOverlay(hwc_context_t *ctx, hwc_layer_t *layer, const bool wai LOGE("prepareOverlay setCrop failed"); return -1; } - +#if defined HDMI_DUAL_DISPLAY + // Send the device orientation to overlayLib + if(hwcModule) { + framebuffer_device_t *fbDev = reinterpret_cast + (hwcModule->fbDevice); + if(fbDev) { + private_module_t* m = reinterpret_cast( + fbDev->common.module); + if(m) + ovLibObject->setDeviceOrientation(m->orientation); + } + } +#endif if (layer->flags & HWC_USE_ORIGINAL_RESOLUTION) { framebuffer_device_t* fbDev = hwcModule->fbDevice; ret = ovLibObject->setPosition(0, 0, diff --git a/liboverlay/overlayLib.cpp b/liboverlay/overlayLib.cpp index addebc2..3e26d3a 100755 --- a/liboverlay/overlayLib.cpp +++ b/liboverlay/overlayLib.cpp @@ -37,6 +37,13 @@ bool Overlay::sHDMIAsPrimary = true; bool Overlay::sHDMIAsPrimary = false; #endif +template +void swapWidthHeight(Type& width, Type& height) { + Type tmp = width; + width = height; + height = tmp; +} + int overlay::get_mdp_format(int format) { switch (format) { case HAL_PIXEL_FORMAT_RGBA_8888 : @@ -183,6 +190,66 @@ const char* overlay::getFormatString(int format){ }; return formats[format]; } +ZOrderManager* ZOrderManager::sInstance = 0; +FrameBufferInfo* FrameBufferInfo::sFBInfoInstance = 0; + +int ZOrderManager::getZ(int fbnum){ + int zorder = NO_PIPE;; + Mutex::Autolock objLock(mObjMutex); + if(mPipesInuse == mMaxPipes) { + LOGE("No free pipes available.. inUse = %d ", mPipesInuse); + return NO_PIPE; + } + switch(fbnum) { + case FRAMEBUFFER_0: + for (int i = 0;i < NUM_CHANNELS; i++) { + if(mFB0Pipes[i] == false) { + mFB0Pipes[i]= true; + zorder = i; + break; + } + } + break; + case FRAMEBUFFER_1: + for (int i = 0;i < mMaxPipes; i++) { + if(mFB1Pipes[i] == false) { + mFB1Pipes[i]= true; + zorder = i; + break; + } + } + break; + default: + LOGE("getZ: Invalid framebuffer.."); + break; + } + mPipesInuse++; + LOGE("getZ: return zorder = %d for fbdev = %d, pipesinUse = %d", + zorder, fbnum, mPipesInuse); + return zorder; +} + +void ZOrderManager::decZ(int fbnum, int zorder){ + Mutex::Autolock objLock(mObjMutex); + switch(fbnum) { + case FRAMEBUFFER_0: + LOG_ASSERT(!mFB0Pipes[zorder],"channel with ZOrder does not exist"); + LOGE("decZ: freeing the pipe with zorder = %d for fbdev = %d", zorder, fbnum); + mFB0Pipes[zorder] = false; + break; + case FRAMEBUFFER_1: + LOG_ASSERT(!mFB1Pipes[zorder],"channel with ZOrder does not exist"); + LOGE("decZ: freeing the pipe with zorder = %d for fbdev = %d", zorder, fbnum); + mFB1Pipes[zorder] = false; + break; + default: + LOGE("decZ: Invalid framebuffer "); + break; + } + if(mPipesInuse > 0) + mPipesInuse--; + LOGE("decZ: Pipes in use = %d", mPipesInuse); +} bool overlay::isHDMIConnected () { char value[PROPERTY_VALUE_MAX]; @@ -387,55 +454,77 @@ bool Overlay::getOrientation(int& orientation, int channel) const { return objOvCtrlChannel[channel].getOrientation(orientation); } +bool Overlay::setDeviceOrientation(int orientation) { + // Use this to calculate the position on HDMI + mDevOrientation = orientation; + return true; +} + bool Overlay::setPosition(int x, int y, uint32_t w, uint32_t h) { bool ret = false; overlay_rect rect; - switch (mState) { - case OV_UI_MIRROR_TV: - case OV_2D_VIDEO_ON_PANEL: - case OV_3D_VIDEO_2D_PANEL: - return setChannelPosition(x, y, w, h, VG0_PIPE); - break; - case OV_2D_VIDEO_ON_TV: - objOvCtrlChannel[VG1_PIPE].getAspectRatioPosition(mCroppedSrcWidth, - mCroppedSrcHeight, &rect); - setChannelPosition(rect.x, rect.y, rect.w, rect.h, VG1_PIPE); - return setChannelPosition(x, y, w, h, VG0_PIPE); - break; - case OV_3D_VIDEO_3D_PANEL: - for (int i = 0; i < NUM_CHANNELS; i++) { - if (sHDMIAsPrimary) - objOvCtrlChannel[i].getPositionS3D(i, mS3DFormat, &rect); - else { - if (!objOvCtrlChannel[i].useVirtualFB()) { - LOGE("%s: failed virtual fb for channel %d", __FUNCTION__, i); + overlay_rect inrect; + int currX, currY; + uint32_t currW, currH; + // Set even destination co-ordinates + EVEN_OUT(x); EVEN_OUT(y); + EVEN_OUT(w); EVEN_OUT(h); + objOvCtrlChannel[VG0_PIPE].getPosition(currX, currY, currW, currH); + inrect.x = x, inrect.y = y; + inrect.w = w, inrect.h = h; + if(x != currX || y != currY || w != currW || h != currH) { + switch (mState) { + case OV_UI_MIRROR_TV: + case OV_2D_VIDEO_ON_PANEL: + case OV_3D_VIDEO_2D_PANEL: + return setChannelPosition(x, y, w, h, VG0_PIPE); + break; + case OV_2D_VIDEO_ON_TV: + if (FrameBufferInfo::getInstance()->canSupportTrueMirroring()) { + objOvCtrlChannel[VG1_PIPE].getAspectRatioPosition(mCroppedSrcWidth, + mCroppedSrcHeight, mDevOrientation, &inrect, &rect); + } else { + objOvCtrlChannel[VG1_PIPE].getAspectRatioPosition(mCroppedSrcWidth, + mCroppedSrcHeight, &rect); + } + setChannelPosition(rect.x, rect.y, rect.w, rect.h, VG1_PIPE); + return setChannelPosition(x, y, w, h, VG0_PIPE); + break; + case OV_3D_VIDEO_3D_PANEL: + for (int i = 0; i < NUM_CHANNELS; i++) { + if (sHDMIAsPrimary) + objOvCtrlChannel[i].getPositionS3D(i, mS3DFormat, &rect); + else { + if (!objOvCtrlChannel[i].useVirtualFB()) { + LOGE("%s: failed virtual fb for channel %d", __FUNCTION__, i); + return false; + } + objOvCtrlChannel[i].getPositionS3D(i, 0x1, &rect); + } + if(!setChannelPosition(rect.x, rect.y, rect.w, rect.h, i)) { + LOGE("%s: failed for channel %d", __FUNCTION__, i); return false; } - objOvCtrlChannel[i].getPositionS3D(i, 0x1, &rect); } - if(!setChannelPosition(rect.x, rect.y, rect.w, rect.h, i)) { - LOGE("%s: failed for channel %d", __FUNCTION__, i); - return false; + break; + case OV_3D_VIDEO_2D_TV: + case OV_3D_VIDEO_3D_TV: + for (int i = 0; i < NUM_CHANNELS; i++) { + ret = objOvCtrlChannel[i].getPositionS3D(i, mS3DFormat, &rect); + if (!ret) + ret = setChannelPosition(x, y, w, h, i); + else + ret = setChannelPosition(rect.x, rect.y, rect.w, rect.h, i); + if (!ret) { + LOGE("%s: failed for channel %d", __FUNCTION__, i); + return ret; + } } - } - break; - case OV_3D_VIDEO_2D_TV: - case OV_3D_VIDEO_3D_TV: - for (int i = 0; i < NUM_CHANNELS; i++) { - ret = objOvCtrlChannel[i].getPositionS3D(i, mS3DFormat, &rect); - if (!ret) - ret = setChannelPosition(x, y, w, h, i); - else - ret = setChannelPosition(rect.x, rect.y, rect.w, rect.h, i); - if (!ret) { - LOGE("%s: failed for channel %d", __FUNCTION__, i); - return ret; - } - } - break; - default: - LOGE("%s:Unknown state %d", __FUNCTION__, mState); - break; + break; + default: + LOGE("%s:Unknown state %d", __FUNCTION__, mState); + break; + } } return true; } @@ -606,9 +695,7 @@ bool Overlay::setSource(const overlay_buffer_info& info, int orientation, return false; } } - overlay_rect rect; - objOvCtrlChannel[VG1_PIPE].getAspectRatioPosition(info.width, info.height, &rect); - return setChannelPosition(rect.x, rect.y, rect.w, rect.h, VG1_PIPE); + return true; break; case OV_3D_VIDEO_3D_TV: for (int i=0; igetWidth(); + float priHeight = FrameBufferInfo::getInstance()->getHeight(); + float fbWidth = getFBWidth(); + float fbHeight = getFBHeight(); + float wRatio = 1.0; + float hRatio = 1.0; + float xRatio = 1.0; + float yRatio = 1.0; + + int xPos = 0; + int tmp = 0; + float actualWidth = fbWidth; + if(priWidth < priHeight) { + switch(orientation) { + case MDP_ROT_NOP: + actualWidth = (fbHeight * priWidth) / priHeight; + xPos = (fbWidth - actualWidth) / 2; + break; + case MDP_ROT_180: + actualWidth = (fbHeight * priWidth) / priHeight; + xPos = (fbWidth - actualWidth) / 2; + inRect->x = priWidth - (inRect->x + inRect->w); + inRect->y = priHeight - (inRect->y + inRect->h); + break; + case MDP_ROT_90: + tmp = inRect->y; + inRect->y = priWidth - (inRect->x + inRect->w); + inRect->x = tmp; + // Swap width/height for primary + swapWidthHeight(priWidth, priHeight); + //Swap the destination width/height + swapWidthHeight(inRect->w, inRect->h); + break; + case MDP_ROT_270: + tmp = inRect->x; + inRect->x = priHeight - (inRect->y + inRect->h); + inRect->y = tmp; + // Swap width/height for primary + swapWidthHeight(priWidth, priHeight); + //Swap the destination width/height + swapWidthHeight(inRect->w, inRect->h); + break; + default: + LOGE("In %s: Portrait: Unknown Orientation", __FUNCTION__); + break; + } + } else { + switch(orientation) { + case MDP_ROT_NOP: + break; + case MDP_ROT_180: + inRect->x = priWidth - (inRect->x + inRect->w); + inRect->y = priHeight - (inRect->y + inRect->h); + break; + case MDP_ROT_90: + case MDP_ROT_270: + // Swap width/height for primary + swapWidthHeight(priWidth, priHeight); + //Swap the destination width/height + swapWidthHeight(inRect->w, inRect->h); + actualWidth = ( fbHeight * priWidth) / priHeight; + xPos = (fbWidth - actualWidth) / 2; + if(orientation == MDP_ROT_90) { + tmp = inRect->y; + inRect->y = priWidth - (inRect->x + inRect->w); + inRect->x = tmp; + } + else if(orientation == MDP_ROT_270) { + tmp = inRect->x; + inRect->x = priHeight - (inRect->y + inRect->h); + inRect->y = tmp; + } + break; + default: + LOGE("In %s: Landscape: Unknown Orientation", __FUNCTION__); + break; + } + } + //Calculate the position... + xRatio = inRect->x/priWidth; + yRatio = inRect->y/priHeight; + + wRatio = inRect->w/priWidth; + hRatio = inRect->h/priHeight; + outRect->x = (xRatio * fbWidth) + xPos; + outRect->y = yRatio * fbHeight; + + outRect->w = (wRatio * actualWidth); + outRect->h = hRatio * fbHeight; + LOGE("Calculated AS Position for HDMI: X= %d, y = %d w = %d h = %d", + outRect->x, outRect->y,outRect->w, outRect->h); + return true; +} + + bool OverlayControlChannel::getPositionS3D(int channel, int format, overlay_rect *rect) { int wDisp = getFBWidth(); int hDisp = getFBHeight(); @@ -1090,6 +1281,7 @@ bool OverlayControlChannel::startControlChannel(int w, int h, mNoRot = norot; mFormat = format; mUIChannel = uichannel; + mFBNum = fbnum; fb_fix_screeninfo finfo; fb_var_screeninfo vinfo; int hw_format; @@ -1114,9 +1306,18 @@ bool OverlayControlChannel::startControlChannel(int w, int h, // Set the share bit for sharing the VG pipe flags |= MDP_OV_PIPE_SHARE; } + //do not set the PIPE SHARE bit for true mirroring + if(uichannel && FrameBufferInfo::getInstance()->canSupportTrueMirroring()) + flags &= ~MDP_OV_PIPE_SHARE; if (!openDevices(fbnum)) return false; + //get Z order + zorder = ZOrderManager::getInstance()->getZ(fbnum); + if (zorder == NO_PIPE) + return false; + + int orientation = mNoRot ? 0: 1; overlay_buffer_info ovBufInfo; ovBufInfo.width = w; @@ -1146,9 +1347,15 @@ bool OverlayControlChannel::closeControlChannel() { } close(mFD); + + if(NO_PIPE != mOVInfo.z_order){ + ZOrderManager::getInstance()->decZ(mFBNum, mOVInfo.z_order); + } memset(&mOVInfo, 0, sizeof(mOVInfo)); memset(&mRotInfo, 0, sizeof(mRotInfo)); memset(&m3DOVInfo, 0, sizeof(m3DOVInfo)); + + mOVInfo.z_order = NO_PIPE; mFD = -1; return true; diff --git a/liboverlay/overlayLib.h b/liboverlay/overlayLib.h index 580ad55..bf0cecc 100755 --- a/liboverlay/overlayLib.h +++ b/liboverlay/overlayLib.h @@ -39,6 +39,7 @@ #include #include +#include #include #include #include @@ -47,6 +48,7 @@ #define HW_OVERLAY_MINIFICATION_LIMIT HW_OVERLAY_MAGNIFICATION_LIMIT #define EVEN_OUT(x) if (x & 0x0001) {x--;} +#define NO_PIPE -1 #define VG0_PIPE 0 #define VG1_PIPE 1 #define NUM_CHANNELS 2 @@ -125,7 +127,58 @@ enum { OVERLAY_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270 }; +using android::Mutex; namespace overlay { + //Utility Class to query the framebuffer info + class FrameBufferInfo { + int mFBWidth; + int mFBHeight; + bool mBorderFillSupported; + static FrameBufferInfo *sFBInfoInstance; + + FrameBufferInfo():mFBWidth(0),mFBHeight(0), mBorderFillSupported(false) { + char const * const device_name = + "/dev/graphics/fb0"; + int fd = open(device_name, O_RDWR, 0); + mdp_overlay ov; + memset(&ov, 0, sizeof(ov)); + if (fd < 0) { + LOGE("FrameBufferInfo: Cant open framebuffer "); + return; + } + fb_var_screeninfo vinfo; + if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1) { + LOGE("FrameBufferInfo: FBIOGET_VSCREENINFO on fb0 failed"); + close(fd); + fd = -1; + return; + } + ov.id = 1; + if(ioctl(fd, MSMFB_OVERLAY_GET, &ov)) { + LOGE("FrameBufferInfo: MSMFB_OVERLAY_GET on fb0 failed"); + close(fd); + fd = -1; + return; + } + close(fd); + fd = -1; + mFBWidth = vinfo.xres; + mFBHeight = vinfo.yres; + mBorderFillSupported = (ov.flags & MDP_BORDERFILL_SUPPORTED) ? + true : false; + } + public: + static FrameBufferInfo* getInstance(){ + if (!sFBInfoInstance){ + sFBInfoInstance = new FrameBufferInfo; + } + return sFBInfoInstance; + } + int getWidth() const { return mFBWidth; } + int getHeight() const { return mFBHeight; } + bool canSupportTrueMirroring() const { + return mBorderFillSupported; } + }; enum { OV_UI_MIRROR_TV = 0, @@ -158,13 +211,46 @@ void dump(msm_rotator_img_info& mRotInfo); void dump(mdp_overlay& mOvInfo); const char* getFormatString(int format); + //singleton class to decide the z order of new overlay surfaces + class ZOrderManager { + bool mFB0Pipes[NUM_CHANNELS]; + bool mFB1Pipes[NUM_CHANNELS+1]; //FB1 can have 3 pipes + int mPipesInuse; // Holds the number of pipes in use + int mMaxPipes; // Max number of pipes + static ZOrderManager *sInstance; + Mutex *mObjMutex; + ZOrderManager(){ + mPipesInuse = 0; + // for true mirroring support there can be 3 pipes on secondary + mMaxPipes = FrameBufferInfo::getInstance()->canSupportTrueMirroring()? + NUM_CHANNELS+1 : NUM_CHANNELS; + for (int i = 0; i < NUM_CHANNELS; i++) + mFB0Pipes[i] = false; + for (int j = 0; j < mMaxPipes; j++) + mFB1Pipes[j] = false; + mObjMutex = new Mutex(); + } + ~ZOrderManager() { + delete sInstance; + delete mObjMutex; + } + public: + static ZOrderManager* getInstance(){ + if (!sInstance){ + sInstance = new ZOrderManager; + } + return sInstance; + } + int getZ(int fbnum); + void decZ(int fbnum, int zorder); + }; const int max_num_buffers = 3; typedef struct mdp_rect overlay_rect; class OverlayControlChannel { bool mNoRot; - + int mFBNum; int mFBWidth; int mFBHeight; int mFBbpp; @@ -210,6 +296,10 @@ public: bool getOrientation(int& orientation) const; bool updateWaitForVsyncFlags(bool waitForVsync); bool getAspectRatioPosition(int w, int h, overlay_rect *rect); + // Calculates the aspect ratio for video on HDMI based on primary + // aspect ratio used in case of true mirroring + bool getAspectRatioPosition(int w, int h, int orientation, + overlay_rect *inRect, overlay_rect *outRect); bool getPositionS3D(int channel, int format, overlay_rect *rect); bool updateOverlaySource(const overlay_buffer_info& info, int orientation, bool waitForVsync); bool getFormat() const { return mFormat; } @@ -274,6 +364,8 @@ class Overlay { int mCroppedSrcHeight; overlay_buffer_info mOVBufferInfo; int mState; + // Stores the current device orientation + int mDevOrientation; OverlayControlChannel objOvCtrlChannel[2]; OverlayDataChannel objOvDataChannel[2]; @@ -287,6 +379,7 @@ public: int channel = 0, bool ignoreFB = false, int num_buffers = 2); bool closeChannel(); + bool setDeviceOrientation(int orientation); bool setPosition(int x, int y, uint32_t w, uint32_t h); bool setTransform(int value); bool setOrientation(int value, int channel = 0); @@ -301,6 +394,7 @@ public: bool setSource(const overlay_buffer_info& info, int orientation, bool hdmiConnected, bool ignoreFB = false, int numBuffers = 2); bool setCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h); + bool updateWaitForVsyncFlags(bool waitForVsync); bool waitForHdmiVsync(int channel); int getChannelStatus() const { return (mChannelUP ? OVERLAY_CHANNEL_UP: OVERLAY_CHANNEL_DOWN); } void setHDMIStatus (bool isHDMIConnected) { mHDMIConnected = isHDMIConnected; mState = -1; }