From 9c2ba115fd218b40679999053a68e28694ea6998 Mon Sep 17 00:00:00 2001 From: Naomi Luis Date: Mon, 2 May 2011 13:46:44 -0700 Subject: [PATCH] Add support for dynamic resolution change with overlays Whenever there is a change in the buffer geometry, set a flag in the gralloc handle stating that the buffer geometry has changed. In the HWC, whenever we encounter an update in the geometry, if the channel is already open, we just call the necessary ioctls to update the overlay information and not unnecessarily open/close channels. Change-Id: I27db8fc497ebc514e262d6b7854739f312644714 --- libgralloc-qsd8k/gralloc_priv.h | 1 + libgralloc-qsd8k/mapper.cpp | 5 +- libhwcomposer/hwcomposer.cpp | 28 +++++-- liboverlay/overlayLib.cpp | 129 +++++++++++++++++++++++++++++--- liboverlay/overlayLib.h | 3 + 5 files changed, 148 insertions(+), 18 deletions(-) diff --git a/libgralloc-qsd8k/gralloc_priv.h b/libgralloc-qsd8k/gralloc_priv.h index 04a15ce..7e41906 100755 --- a/libgralloc-qsd8k/gralloc_priv.h +++ b/libgralloc-qsd8k/gralloc_priv.h @@ -257,6 +257,7 @@ struct private_handle_t { PRIV_FLAGS_USES_PMEM_ADSP = 0x00000004, PRIV_FLAGS_NEEDS_FLUSH = 0x00000008, PRIV_FLAGS_USES_ASHMEM = 0x00000010, + PRIV_FLAGS_FORMAT_CHANGED = 0x00000020, }; enum { diff --git a/libgralloc-qsd8k/mapper.cpp b/libgralloc-qsd8k/mapper.cpp index e25a3cd..444a2ff 100755 --- a/libgralloc-qsd8k/mapper.cpp +++ b/libgralloc-qsd8k/mapper.cpp @@ -369,7 +369,10 @@ int gralloc_perform(struct gralloc_module_t const* module, private_handle_t* hnd = (private_handle_t*)handle; hnd->width = w; hnd->height = h; - hnd->format = f; + if (hnd->format != f) { + hnd->format = f; + hnd->flags |= private_handle_t::PRIV_FLAGS_FORMAT_CHANGED; + } break; } default: diff --git a/libhwcomposer/hwcomposer.cpp b/libhwcomposer/hwcomposer.cpp index b33cf97..c21b210 100755 --- a/libhwcomposer/hwcomposer.cpp +++ b/libhwcomposer/hwcomposer.cpp @@ -341,12 +341,31 @@ static int drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer) private_handle_t *hnd = (private_handle_t *)layer->handle; overlay::Overlay *ovLibObject = ctx->mOverlayLibObject; + int orientation = 0; + if (OVERLAY_CHANNEL_UP == ovLibObject->getChannelStatus()) + ovLibObject->getOrientation(orientation); - ret = ovLibObject->setSource(hnd->width, hnd->height, hnd->format, layer->transform, + if ((OVERLAY_CHANNEL_DOWN == ovLibObject->getChannelStatus()) + || (layer->transform != orientation) || + (hnd->flags & private_handle_t::PRIV_FLAGS_FORMAT_CHANGED)) { + // Overlay channel is not started, or we have an orientation change or there is a + // format change, call setSource to open the overlay if necessary + ret = ovLibObject->setSource(hnd->width, hnd->height, hnd->format, layer->transform, (ovLibObject->getHDMIStatus()?true:false), false); - if (!ret) { - LOGE("drawLayerUsingOverlay setSource failed"); - return -1; + if (!ret) { + LOGE("drawLayerUsingOverlay setSource failed"); + return -1; + } + // Reset this flag so that we don't keep opening and closing channels unnecessarily + hnd->flags &= ~private_handle_t::PRIV_FLAGS_FORMAT_CHANGED; + } else { + // The overlay goemetry may have changed, we only need to update the overlay + ret = ovLibObject->updateOverlaySource(hnd->width, hnd->height, hnd->format, + layer->transform); + if (!ret) { + LOGE("drawLayerUsingOverlay updateOverlaySource failed"); + return -1; + } } hwc_rect_t sourceCrop = layer->sourceCrop; @@ -373,7 +392,6 @@ static int drawLayerUsingOverlay(hwc_context_t *ctx, hwc_layer_t *layer) return -1; } - int orientation; ovLibObject->getOrientation(orientation); if (orientation != layer->transform) ret = ovLibObject->setParameter(OVERLAY_TRANSFORM, layer->transform); diff --git a/liboverlay/overlayLib.cpp b/liboverlay/overlayLib.cpp index 39afe4d..8904951 100644 --- a/liboverlay/overlayLib.cpp +++ b/liboverlay/overlayLib.cpp @@ -271,6 +271,37 @@ bool Overlay::setPositionS3D(int x, int y, uint32_t w, uint32_t h) { return ret; } +bool Overlay::updateOverlaySource(uint32_t w, uint32_t h, int format, int orientation) { + if (hasHDMIStatusChanged()) { + return setSource(w, h, format, orientation, mHDMIConnected); + } + + bool ret = true; + // Set the overlay source info + if (objOvCtrlChannel[0].isChannelUP()) { + ret = objOvCtrlChannel[0].updateOverlaySource(w, h); + if (ret && objOvCtrlChannel[1].isChannelUP()) + ret = objOvCtrlChannel[1].updateOverlaySource(w, h); + } + return ret; +} + +int Overlay::hasHDMIStatusChanged() { + int hdmiChanged = 0; + if (mHDMIConnected) { + // If HDMI is connected and both channels are not up, set the status + if (!objOvCtrlChannel[0].isChannelUP() || !objOvCtrlChannel[1].isChannelUP()) { + hdmiChanged = 0x1; + } + } else { + // HDMI is disconnected and both channels are up, set the status + if (objOvCtrlChannel[0].isChannelUP() && objOvCtrlChannel[1].isChannelUP()) { + hdmiChanged = 0x1; + } + } + return hdmiChanged; +} + bool Overlay::setSource(uint32_t w, uint32_t h, int format, int orientation, bool hdmiConnected, bool ignoreFB, int num_buffers) { if (mCloseChannel) @@ -298,19 +329,8 @@ bool Overlay::setSource(uint32_t w, uint32_t h, int format, int orientation, if (format3D != mS3DFormat) s3dChanged = 0x10; - if (mHDMIConnected) { - // If HDMI is connected and both channels are not up, set the status - if (!objOvCtrlChannel[0].isChannelUP() || !objOvCtrlChannel[1].isChannelUP()) { - hdmiChanged = 0x1; - } - } else { - // HDMI is disconnected and both channels are up, set the status - if (objOvCtrlChannel[0].isChannelUP() && objOvCtrlChannel[1].isChannelUP()) { - hdmiChanged = 0x1; - } - } - stateChanged = s3dChanged|hdmiChanged; + stateChanged = s3dChanged|hasHDMIStatusChanged(); if (stateChanged || !objOvCtrlChannel[0].setSource(w, h, colorFormat, orientation, ignoreFB)) { if (mChannelUP && isRGBType(hw_format) && (stateChanged != 0x10)) { mCloseChannel = true; @@ -682,6 +702,91 @@ bool OverlayControlChannel::startOVRotatorSessions(int w, int h, return ret; } +bool OverlayControlChannel::updateOverlaySource(uint32_t w, uint32_t h) +{ + // Set Rotator info + if (mRotFD >=0) { + if(mRotInfo.src.format == MDP_Y_CRCB_H2V2_TILE) { + if ((mRotInfo.src.width == (((w-1)/64 +1)*64)) && + (mRotInfo.src.height == (((h-1)/32 +1)*32))) + return true; + + mRotInfo.src.width = (((w-1)/64 +1)*64); + mRotInfo.src.height = (((h-1)/32 +1)*32); + mRotInfo.src_rect.w = (((w-1)/64 +1)*64); + mRotInfo.src_rect.h = (((h-1)/32 +1)*32); + mRotInfo.dst.height = (((w-1)/64 +1)*64); + mRotInfo.dst.width = (((h-1)/32 +1)*32); + mRotInfo.dst.format = MDP_Y_CRCB_H2V2; + } else { + if ((mRotInfo.src.width == w) && + (mRotInfo.src.height == h)) + return true; + + mRotInfo.src.width = w; + mRotInfo.src.height = h; + mRotInfo.src_rect.w = w; + mRotInfo.src_rect.h = h; + mRotInfo.dst.width = h; + mRotInfo.dst.height = w; + } + + if (mOVInfo.user_data[0] == MDP_ROT_NOP) + mRotInfo.enable = 0; + + if (ioctl(mRotFD, MSM_ROTATOR_IOCTL_START, &mRotInfo)) { + LOGE("updateOverlaySource MSM_ROTATOR_IOCTL_START failed"); + return true; + } + } + + // Set overlay info + switch (mOVInfo.user_data[0]) { + case MDP_ROT_90: + case (MDP_ROT_90 | MDP_FLIP_UD): + case (MDP_ROT_90 | MDP_FLIP_LR): + case MDP_ROT_270: { + if ((mOVInfo.src.height == (((w-1)/64 +1)*64)) && + (mOVInfo.src.width == (((h-1)/32 +1)*32))) + return true; + + mOVInfo.src_rect.w = h; + mOVInfo.src_rect.h = w; + mOVInfo.src.height = (((w-1)/64 +1)*64); + mOVInfo.src.width = (((h-1)/32 +1)*32); + mOVInfo.src_rect.x = 0; + mOVInfo.src_rect.y = 0;; + } break; + case MDP_ROT_180: + case MDP_ROT_NOP: { + if ((mOVInfo.src.width == w) && + (mOVInfo.src.height == h)) + return true; + + mOVInfo.src.width = w; + mOVInfo.src.height = h; + mOVInfo.src_rect.x = 0; + mOVInfo.src_rect.y = 0; + if(mOVInfo.src.format == MDP_Y_CRCB_H2V2_TILE) { + mOVInfo.src_rect.w = w - ( (((w-1)/64 +1)*64) - w); + mOVInfo.src_rect.h = h - ((((h-1)/32 +1)*32) - h); + } else { + mOVInfo.src_rect.w = w; + mOVInfo.src_rect.h = h; + } + } break; + default: + LOGE("updateOverlaySource: Invalid rotation parameter"); + return false; + } + + if (ioctl(mFD, MSMFB_OVERLAY_SET, &mOVInfo)) { + LOGE("updateOverlaySource MSMFB_OVERLAY_SET failed"); + return true; + } + return true; +} + bool OverlayControlChannel::startControlChannel(int w, int h, int format, int fbnum, bool norot, bool uichannel, diff --git a/liboverlay/overlayLib.h b/liboverlay/overlayLib.h index 42760bc..55af19f 100644 --- a/liboverlay/overlayLib.h +++ b/liboverlay/overlayLib.h @@ -139,6 +139,7 @@ public: int orientation, bool ignoreFB); bool getAspectRatioPosition(int w, int h, int format, overlay_rect *rect); bool getPositionS3D(int channel, int format, overlay_rect *rect); + bool updateOverlaySource(uint32_t w, uint32_t h); }; class OverlayDataChannel { @@ -216,6 +217,7 @@ public: int getChannelStatus() const { return (mChannelUP ? OVERLAY_CHANNEL_UP: OVERLAY_CHANNEL_DOWN); } void setHDMIStatus (bool isHDMIConnected) { mHDMIConnected = isHDMIConnected; } int getHDMIStatus() const {return (mHDMIConnected ? HDMI_ON : HDMI_OFF); } + bool updateOverlaySource(uint32_t w, uint32_t h, int format, int orientation); private: bool startChannelHDMI(int w, int h, int format, bool norot); @@ -225,6 +227,7 @@ private: bool setChannelPosition(int x, int y, uint32_t w, uint32_t h, int channel = 0); bool setChannelCrop(uint32_t x, uint32_t y, uint32_t w, uint32_t h, int channel); bool queueBuffer(int fd, uint32_t offset, int channel); + int hasHDMIStatusChanged(); }; struct overlay_shared_data {