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
This commit is contained in:
Naomi Luis 2011-05-02 13:46:44 -07:00 committed by Govind Surti
parent 56a78ad233
commit 9c2ba115fd
5 changed files with 148 additions and 18 deletions

View File

@ -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 {

View File

@ -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:

View File

@ -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);

View File

@ -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,

View File

@ -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 {