hwc: enable dual display on hwc 1.1
Enable dual display on HWC 1.1; video uses overlay.
Bug: 7124159
Change-Id: I8333e46cfc74072f6259fba2b82368f0dd52b6df
Signed-off-by: Iliyan Malchev <malchev@google.com>
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 92a129b..c4f9aeb 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -382,23 +382,6 @@
}
mCurrentMode = ID;
}
- //Powerup
- ret = ioctl(mFd, FBIOBLANK, FB_BLANK_UNBLANK);
- if(ret < 0) {
- ALOGD("In %s: FBIOBLANK failed Err Str = %s", __FUNCTION__,
- strerror(errno));
- }
- ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
- if(ret < 0) {
- ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
- strerror(errno));
- }
- //Pan_Display
- ret = ioctl(mFd, FBIOPAN_DISPLAY, &mVInfo);
- if(ret < 0) {
- ALOGD("In %s: FBIOPAN_DISPLAY failed Err Str = %s", __FUNCTION__,
- strerror(errno));
- }
}
void ExternalDisplay::setExternalDisplay(int connected)
@@ -411,7 +394,7 @@
if(connected) {
readResolution();
//Get the best mode and set
- // TODO: DO NOT call this for WFD
+ // TODO: Move this to activate
setResolution(getBestMode());
setDpyAttr();
//enable hdmi vsync
@@ -422,17 +405,16 @@
}
// Store the external display
mExternalDisplay = connected;
- ALOGD_IF(DEBUG, "In %s: mExternalDisplay = %d", __FUNCTION__,
- mExternalDisplay);
const char* prop = (connected) ? "1" : "0";
// set system property
property_set("hw.hdmiON", prop);
- //Inform SF
+ ALOGD("%s sending hotplug: connected = %d", __FUNCTION__,connected);
+ //Inform SF. Disabled until SF calls unblank
ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false;
- //TODO remove invalidate send hotplug
- //ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL, connected);
- ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = connected;
- ctx->proc->invalidate(ctx->proc);
+ ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected = connected;
+
+ //TODO ideally should be done on "connected" not "online"
+ ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL, connected);
}
return;
}
@@ -484,10 +466,11 @@
int width = 0, height = 0, fps = 0;
getAttrForMode(width, height, fps);
if(mHwcContext) {
+ 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;
+ mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
+ 1000000000l / fps;
}
}
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index f8f7f13..c72d882 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -86,18 +86,17 @@
static int hwc_prepare_primary(hwc_composer_device_1 *dev,
hwc_display_contents_1_t *list) {
hwc_context_t* ctx = (hwc_context_t*)(dev);
+ ctx->overlayInUse[HWC_DISPLAY_PRIMARY] = false;
if (LIKELY(list && list->numHwLayers)) {
uint32_t last = list->numHwLayers - 1;
hwc_layer_1_t *fblayer = &list->hwLayers[last];
setListStats(ctx, list, HWC_DISPLAY_PRIMARY);
if(VideoOverlay::prepare(ctx, list, HWC_DISPLAY_PRIMARY)) {
- ctx->overlayInUse = true;
- } else if(UIMirrorOverlay::prepare(ctx, fblayer)) {
- ctx->overlayInUse = true;
+ ctx->overlayInUse[HWC_DISPLAY_PRIMARY] = true;
} else if(MDPComp::configure(ctx, list)) {
- ctx->overlayInUse = true;
+ ctx->overlayInUse[HWC_DISPLAY_PRIMARY] = true;
} else {
- ctx->overlayInUse = false;
+ ctx->overlayInUse[HWC_DISPLAY_PRIMARY] = false;
}
}
return 0;
@@ -107,9 +106,25 @@
hwc_display_contents_1_t *list) {
hwc_context_t* ctx = (hwc_context_t*)(dev);
- if (LIKELY(list && list->numHwLayers)) {
- //setListStats(ctx, list, HWC_DISPLAY_EXTERNAL);
- //Nothing to do for now
+ ctx->overlayInUse[HWC_DISPLAY_EXTERNAL] = false;
+
+ if (LIKELY(list && list->numHwLayers) &&
+ ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive &&
+ ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected) {
+
+ setListStats(ctx, list, HWC_DISPLAY_EXTERNAL);
+
+ uint32_t last = list->numHwLayers - 1;
+ hwc_layer_1_t *fblayer = &list->hwLayers[last];
+ if(UIMirrorOverlay::prepare(ctx, fblayer)) {
+ ctx->overlayInUse[HWC_DISPLAY_EXTERNAL] = true;
+ }
+
+ if(VideoOverlay::prepare(ctx, list, HWC_DISPLAY_EXTERNAL)) {
+ ctx->overlayInUse[HWC_DISPLAY_EXTERNAL] = true;
+ } else {
+ ctx->mOverlay[HWC_DISPLAY_EXTERNAL]->setState(ovutils::OV_UI_MIRROR);
+ }
}
return 0;
}
@@ -119,7 +134,6 @@
{
int ret = 0;
hwc_context_t* ctx = (hwc_context_t*)(dev);
- ctx->overlayInUse = false;
reset(ctx, numDisplays);
@@ -200,7 +214,7 @@
case HWC_DISPLAY_PRIMARY:
if(blank) {
Locker::Autolock _l(ctx->mBlankLock);
- ctx->mOverlay->setState(ovutils::OV_CLOSED);
+ ctx->mOverlay[dpy]->setState(ovutils::OV_CLOSED);
ret = ioctl(m->framebuffer->fd, FBIOBLANK, FB_BLANK_POWERDOWN);
} else {
ret = ioctl(m->framebuffer->fd, FBIOBLANK, FB_BLANK_UNBLANK);
@@ -244,9 +258,8 @@
ALOGI("fps: %d", value[0]);
break;
case HWC_DISPLAY_TYPES_SUPPORTED:
- //TODO Enable later
- //if(ctx->mMDP.hasOverlay)
- //supported |= HWC_DISPLAY_EXTERNAL_BIT;
+ if(ctx->mMDP.hasOverlay)
+ supported |= HWC_DISPLAY_EXTERNAL_BIT;
value[0] = supported;
break;
default:
@@ -257,24 +270,22 @@
}
static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+ if(!ctx->overlayInUse[HWC_DISPLAY_PRIMARY])
+ ctx->mOverlay[HWC_DISPLAY_PRIMARY]->setState(ovutils::OV_CLOSED);
+
if (LIKELY(list && list->numHwLayers)) {
- ctx->mFbDev->compositionComplete(ctx->mFbDev);
+ uint32_t last = list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+
hwc_sync(ctx, list, HWC_DISPLAY_PRIMARY);
VideoOverlay::draw(ctx, list, HWC_DISPLAY_PRIMARY);
MDPComp::draw(ctx, list);
- uint32_t last = list->numHwLayers - 1;
- hwc_layer_1_t *fblayer = &list->hwLayers[last];
- if(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive) {
- UIMirrorOverlay::draw(ctx, fblayer);
- }
- if(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive) {
- ctx->mExtDisplay->post();
- }
+
//TODO We dont check for SKIP flag on this layer because we need PAN
//always. Last layer is always FB
if(list->hwLayers[last].compositionType == HWC_FRAMEBUFFER_TARGET) {
- ctx->mFbDev->post(ctx->mFbDev, list->hwLayers[last].handle);
+ ctx->mFbDev->post(ctx->mFbDev, fbLayer->handle);
}
}
return 0;
@@ -282,17 +293,49 @@
static int hwc_set_external(hwc_context_t *ctx,
hwc_display_contents_1_t* list) {
- if (LIKELY(list && list->numHwLayers)) {
- //hwc_sync(ctx, list, HWC_DISPLAY_EXTERNAL);
+
+ if(!ctx->overlayInUse[HWC_DISPLAY_EXTERNAL])
+ ctx->mOverlay[HWC_DISPLAY_EXTERNAL]->setState(ovutils::OV_CLOSED);
+
+ if (LIKELY(list && list->numHwLayers) &&
+ ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive &&
+ ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected) {
uint32_t last = list->numHwLayers - 1;
- if(list->hwLayers[last].compositionType == HWC_FRAMEBUFFER_TARGET &&
- ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive) {
- //ctx->mExtDisplay->post(list->hwLayers[last].handle);
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+
+ hwc_sync(ctx, list, HWC_DISPLAY_EXTERNAL);
+
+ VideoOverlay::draw(ctx, list, HWC_DISPLAY_EXTERNAL);
+
+ private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
+ if(fbLayer->compositionType == HWC_FRAMEBUFFER_TARGET && hnd) {
+ UIMirrorOverlay::draw(ctx, fbLayer);
+ ctx->mExtDisplay->post();
}
}
return 0;
}
+static bool isGpuUsed(hwc_context_t *ctx,
+ size_t numDisplays,
+ hwc_display_contents_1_t** displays)
+{
+ bool isUsed = false;
+ for (uint32_t i = 0; i < numDisplays; i++) {
+ hwc_display_contents_1_t* list = displays[i];
+ if (list && list->numHwLayers) {
+ uint32_t last = list->numHwLayers - 1;
+ hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+ if(!(fbLayer->flags & HWC_SKIP_LAYER)) {
+ isUsed = true;
+ break;
+ }
+
+ }
+ }
+ return isUsed;
+}
+
static int hwc_set(hwc_composer_device_1 *dev,
size_t numDisplays,
hwc_display_contents_1_t** displays)
@@ -300,16 +343,21 @@
int ret = 0;
hwc_context_t* ctx = (hwc_context_t*)(dev);
Locker::Autolock _l(ctx->mBlankLock);
- if(!ctx->overlayInUse)
- ctx->mOverlay->setState(ovutils::OV_CLOSED);
+
+ if(isGpuUsed(ctx, numDisplays, displays)) {
+ //Call glFinish, only if gpu is used
+ ctx->mFbDev->compositionComplete(ctx->mFbDev);
+ }
for (uint32_t i = 0; i < numDisplays; i++) {
hwc_display_contents_1_t* list = displays[i];
switch(i) {
case HWC_DISPLAY_PRIMARY:
ret = hwc_set_primary(ctx, list);
+ break;
case HWC_DISPLAY_EXTERNAL:
ret = hwc_set_external(ctx, list);
+ break;
default:
ret = -EINVAL;
}
@@ -320,18 +368,26 @@
int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp,
uint32_t* configs, size_t* numConfigs) {
int ret = 0;
+ hwc_context_t* ctx = (hwc_context_t*)(dev);
//in 1.1 there is no way to choose a config, report as config id # 0
//This config is passed to getDisplayAttributes. Ignore for now.
- if(*numConfigs == 1)
- *configs = 0;
switch(disp) {
case HWC_DISPLAY_PRIMARY:
- ret = 0;
+ if(*numConfigs > 0) {
+ configs[0] = 0;
+ *numConfigs = 1;
+ }
+ ret = 0; //NO_ERROR
break;
case HWC_DISPLAY_EXTERNAL:
- //Hack until hotplug is supported.
- //This makes framework ignore external display.
- ret = -1;
+ ret = -1; //Not connected
+ if(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected) {
+ ret = 0; //NO_ERROR
+ if(*numConfigs > 0) {
+ configs[0] = 0;
+ *numConfigs = 1;
+ }
+ }
break;
}
return ret;
@@ -341,6 +397,11 @@
uint32_t config, const uint32_t* attributes, int32_t* values) {
hwc_context_t* ctx = (hwc_context_t*)(dev);
+ //If hotpluggable displays are inactive return error
+ if(disp == HWC_DISPLAY_EXTERNAL && !ctx->dpyAttr[disp].connected) {
+ return -1;
+ }
+
//From HWComposer
static const uint32_t DISPLAY_ATTRIBUTES[] = {
HWC_DISPLAY_VSYNC_PERIOD,
@@ -361,11 +422,13 @@
break;
case HWC_DISPLAY_WIDTH:
values[i] = ctx->dpyAttr[disp].xres;
- ALOGD("%s width = %d",__FUNCTION__, ctx->dpyAttr[disp].xres);
+ ALOGD("%s disp = %d, width = %d",__FUNCTION__, disp,
+ ctx->dpyAttr[disp].xres);
break;
case HWC_DISPLAY_HEIGHT:
values[i] = ctx->dpyAttr[disp].yres;
- ALOGD("%s height = %d",__FUNCTION__, ctx->dpyAttr[disp].yres);
+ ALOGD("%s disp = %d, height = %d",__FUNCTION__, disp,
+ ctx->dpyAttr[disp].yres);
break;
case HWC_DISPLAY_DPI_X:
values[i] = (int32_t) (ctx->dpyAttr[disp].xdpi*1000.0);
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 6d40741..4c4a9a0 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -191,7 +191,7 @@
private_handle_t *hnd = (private_handle_t *)layer->handle;
- overlay::Overlay& ov = *(ctx->mOverlay);
+ overlay::Overlay& ov = *(ctx->mOverlay[HWC_DISPLAY_PRIMARY]);
if(!hnd) {
ALOGE("%s: layer handle is NULL", __FUNCTION__);
@@ -610,7 +610,7 @@
configure_var_pipe(ctx);
#endif
- overlay::Overlay& ov = *(ctx->mOverlay);
+ overlay::Overlay& ov = *(ctx->mOverlay[HWC_DISPLAY_PRIMARY]);
ovutils::eOverlayState state = ov.getState();
if (current_frame.count == 1) {
@@ -667,7 +667,7 @@
return -1;
}
- overlay::Overlay& ov = *(ctx->mOverlay);
+ overlay::Overlay& ov = *(ctx->mOverlay[HWC_DISPLAY_PRIMARY]);
int numHwLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
for(int i = 0; i < numHwLayers; i++ )
diff --git a/libhwcomposer/hwc_uimirror.cpp b/libhwcomposer/hwc_uimirror.cpp
index 1b81421..62b7efd 100644
--- a/libhwcomposer/hwc_uimirror.cpp
+++ b/libhwcomposer/hwc_uimirror.cpp
@@ -26,30 +26,6 @@
namespace qhwc {
-
-// Function to get the orientation of UI on primary.
-// When external display is connected, the primary UI is
-// fixed to landscape by the phone window manager.
-// Return the landscape orientation based on w and hw of primary
-int getDeviceOrientation() {
- int orientation = 0;
- //Calculate the rect for primary based on whether the supplied
- //position
- //is within or outside bounds.
- const int fbWidth =
- ovutils::FrameBufferInfo::getInstance()->getWidth();
- const int fbHeight =
- ovutils::FrameBufferInfo::getInstance()->getHeight();
- if(fbWidth >= fbHeight) {
- // landscape panel
- orientation = overlay::utils::OVERLAY_TRANSFORM_0;
- } else {
- // portrait panel
- orientation = overlay::utils::OVERLAY_TRANSFORM_ROT_90;
- }
- return orientation;
-}
-
//Static Members
ovutils::eOverlayState UIMirrorOverlay::sState = ovutils::OV_CLOSED;
bool UIMirrorOverlay::sIsUiMirroringOn = false;
@@ -61,83 +37,75 @@
//Prepare the overlay for the UI mirroring
bool UIMirrorOverlay::prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer) {
- sState = ovutils::OV_CLOSED;
- sIsUiMirroringOn = false;
+ reset();
if(!ctx->mMDP.hasOverlay) {
ALOGD_IF(HWC_UI_MIRROR, "%s, this hw doesnt support mirroring",
__FUNCTION__);
return false;
}
- // If external display is active
- if(isExternalActive(ctx)) {
- sState = ovutils::OV_UI_MIRROR;
- configure(ctx, fblayer);
+
+ sState = ovutils::OV_UI_MIRROR;
+ ovutils::eOverlayState newState = ctx->mOverlay[HWC_DISPLAY_EXTERNAL]->getState();
+ if(newState == ovutils::OV_UI_VIDEO_TV) {
+ sState = newState;
}
+
+ configure(ctx, fblayer);
return sIsUiMirroringOn;
}
// Configure
bool UIMirrorOverlay::configure(hwc_context_t *ctx, hwc_layer_1_t *layer)
{
- if (LIKELY(ctx->mOverlay)) {
- overlay::Overlay& ov = *(ctx->mOverlay);
+ if (LIKELY(ctx->mOverlay[HWC_DISPLAY_EXTERNAL])) {
+ overlay::Overlay& ov = *(ctx->mOverlay[HWC_DISPLAY_EXTERNAL]);
// Set overlay state
ov.setState(sState);
- framebuffer_device_t *fbDev = ctx->mFbDev;
- if(fbDev) {
- private_handle_t *hnd = (private_handle_t *)layer->handle;
- ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
- // Determine the RGB pipe for UI depending on the state
- ovutils::eDest dest = ovutils::OV_PIPE_ALL;
- if (sState == ovutils::OV_2D_TRUE_UI_MIRROR) {
- // True UI mirroring state: external RGB pipe is OV_PIPE2
- dest = ovutils::OV_PIPE2;
- } else if (sState == ovutils::OV_UI_MIRROR) {
- // UI-only mirroring state: external RGB pipe is OV_PIPE0
- dest = ovutils::OV_PIPE0;
- }
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
+ // Determine the RGB pipe for UI depending on the state
+ ovutils::eDest dest = ovutils::OV_PIPE0;
- ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
- if(ctx->mSecureMode) {
- ovutils::setMdpFlags(mdpFlags,
- ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
- }
+ ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
+ if(ctx->mSecureMode) {
+ ovutils::setMdpFlags(mdpFlags,
+ ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
+ }
- ovutils::PipeArgs parg(mdpFlags,
- info,
- ovutils::ZORDER_0,
- ovutils::IS_FG_OFF,
- ovutils::ROT_FLAG_ENABLED);
- ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
- ov.setSource(pargs, dest);
+ ovutils::PipeArgs parg(mdpFlags,
+ info,
+ ovutils::ZORDER_0,
+ ovutils::IS_FG_OFF,
+ ovutils::ROT_FLAG_DISABLED);
+ ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
+ ov.setSource(pargs, dest);
- hwc_rect_t sourceCrop = layer->sourceCrop;
- // x,y,w,h
- ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
+ hwc_rect_t sourceCrop = layer->sourceCrop;
+ // x,y,w,h
+ ovutils::Dim dcrop(sourceCrop.left, sourceCrop.top,
sourceCrop.right - sourceCrop.left,
sourceCrop.bottom - sourceCrop.top);
- ov.setCrop(dcrop, dest);
+ ov.setCrop(dcrop, dest);
- //Get the current orientation on primary panel
- int transform = getDeviceOrientation();
- ovutils::eTransform orient =
- static_cast<ovutils::eTransform>(transform);
- ov.setTransform(orient, dest);
+ int transform = layer->transform;
+ ovutils::eTransform orient =
+ static_cast<ovutils::eTransform>(transform);
+ ov.setTransform(orient, dest);
- hwc_rect_t displayFrame = layer->displayFrame;
- ovutils::Dim dpos(displayFrame.left,
+ hwc_rect_t displayFrame = layer->displayFrame;
+ ovutils::Dim dpos(displayFrame.left,
displayFrame.top,
displayFrame.right - displayFrame.left,
displayFrame.bottom - displayFrame.top);
- ov.setPosition(dpos, dest);
+ ov.setPosition(dpos, dest);
- if (!ov.commit(dest)) {
- ALOGE("%s: commit fails", __FUNCTION__);
- return false;
- }
- sIsUiMirroringOn = true;
+ if (!ov.commit(dest)) {
+ ALOGE("%s: commit fails", __FUNCTION__);
+ sIsUiMirroringOn = false;
+ return false;
}
+ sIsUiMirroringOn = true;
}
return sIsUiMirroringOn;
}
@@ -148,36 +116,20 @@
return true;
}
bool ret = true;
- overlay::Overlay& ov = *(ctx->mOverlay);
+ overlay::Overlay& ov = *(ctx->mOverlay[HWC_DISPLAY_EXTERNAL]);
ovutils::eOverlayState state = ov.getState();
- ovutils::eDest dest = ovutils::OV_PIPE_ALL;
- framebuffer_device_t *fbDev = ctx->mFbDev;
- if(fbDev) {
- private_module_t* m = reinterpret_cast<private_module_t*>(
- fbDev->common.module);
- private_handle_t *hnd = (private_handle_t *)layer->handle;
- switch (state) {
- case ovutils::OV_UI_MIRROR:
- //TODO why is this primary fd
- if (!ov.queueBuffer(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd,
- hnd->offset, //div by line_length like in PAN?
- ovutils::OV_PIPE0)) {
- ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
- ret = false;
- }
- break;
- case ovutils::OV_2D_TRUE_UI_MIRROR:
- if (!ov.queueBuffer(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd,
- hnd->offset,
- ovutils::OV_PIPE2)) {
- ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
- ret = false;
- }
- break;
-
+ ovutils::eDest dest = ovutils::OV_PIPE0;
+ private_handle_t *hnd = (private_handle_t *)layer->handle;
+ switch (state) {
+ case ovutils::OV_UI_MIRROR:
+ case ovutils::OV_UI_VIDEO_TV:
+ if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) {
+ ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
+ ret = false;
+ }
+ break;
default:
break;
- }
}
return ret;
}
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index e198de3..ee9cc54 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -51,7 +51,10 @@
void initContext(hwc_context_t *ctx)
{
openFramebufferDevice(ctx);
- ctx->mOverlay = overlay::Overlay::getInstance();
+ overlay::Overlay::initOverlay();
+ for(uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
+ ctx->mOverlay[i] = overlay::Overlay::getInstance(i);
+ }
ctx->mQService = qService::QService::getInstance(ctx);
ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion();
ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay();
@@ -69,9 +72,11 @@
void closeContext(hwc_context_t *ctx)
{
- if(ctx->mOverlay) {
- delete ctx->mOverlay;
- ctx->mOverlay = NULL;
+ for(uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
+ if(ctx->mOverlay[i]) {
+ delete ctx->mOverlay[i];
+ ctx->mOverlay[i] = NULL;
+ }
}
if(ctx->mFbDev) {
@@ -111,6 +116,9 @@
ctx->listStats[dpy].numAppLayers = list->numHwLayers - 1;
ctx->listStats[dpy].fbLayerIndex = list->numHwLayers - 1;
+ ctx->listStats[dpy].yuvCount = 0;
+ ctx->listStats[dpy].yuvIndex = -1;
+ ctx->listStats[dpy].skipCount = 0;
for (size_t i = 0; i < list->numHwLayers; i++) {
private_handle_t *hnd =
@@ -198,7 +206,7 @@
int count = 0;
int releaseFd = -1;
int fbFd = -1;
- data.flags = 0;
+ data.flags = MDP_BUF_SYNC_FLAG_WAIT;
data.acq_fen_fd = acquireFd;
data.rel_fen_fd = &releaseFd;
//Accumulate acquireFenceFds
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 0bde003..37708e6 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -60,6 +60,9 @@
float xdpi;
float ydpi;
int fd;
+ bool connected; //Applies only to pluggable disp.
+ //Connected does not mean it ready to use.
+ //It should be active also. (UNBLANKED)
bool isActive;
};
@@ -166,13 +169,13 @@
hwc_composer_device_1_t device;
const hwc_procs_t* proc;
int numHwLayers;
- int overlayInUse;
+ int overlayInUse[HWC_NUM_DISPLAY_TYPES];
//Framebuffer device
framebuffer_device_t *mFbDev;
//Overlay object - NULL for non overlay devices
- overlay::Overlay *mOverlay;
+ overlay::Overlay *mOverlay[HWC_NUM_DISPLAY_TYPES];
//QService object
qService::QService *mQService;
diff --git a/libhwcomposer/hwc_video.cpp b/libhwcomposer/hwc_video.cpp
index 2e4342a..7bbfaf9 100644
--- a/libhwcomposer/hwc_video.cpp
+++ b/libhwcomposer/hwc_video.cpp
@@ -25,19 +25,22 @@
#define FINAL_TRANSFORM_MASK 0x000F
//Static Members
-ovutils::eOverlayState VideoOverlay::sState = ovutils::OV_CLOSED;
-bool VideoOverlay::sIsModeOn = false;
+ovutils::eOverlayState VideoOverlay::sState[] = {ovutils::OV_CLOSED};
+bool VideoOverlay::sIsModeOn[] = {false};
//Cache stats, figure out the state, config overlay
bool VideoOverlay::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy) {
+
int yuvIndex = ctx->listStats[dpy].yuvIndex;
+ sIsModeOn[dpy] = false;
if(!ctx->mMDP.hasOverlay) {
ALOGD_IF(VIDEO_DEBUG,"%s, this hw doesnt support overlay", __FUNCTION__);
return false;
}
- if(yuvIndex == -1) {
+
+ if(yuvIndex == -1 || ctx->listStats[dpy].yuvCount != 1) {
return false;
}
@@ -55,16 +58,16 @@
chooseState(ctx, dpy, yuvLayer);
if(configure(ctx, dpy, yuvLayer)) {
markFlags(yuvLayer);
- sIsModeOn = true;
+ sIsModeOn[dpy] = true;
}
- return sIsModeOn;
+ return sIsModeOn[dpy];
}
void VideoOverlay::chooseState(hwc_context_t *ctx, int dpy,
hwc_layer_1_t *yuvLayer) {
ALOGD_IF(VIDEO_DEBUG, "%s: old state = %s", __FUNCTION__,
- ovutils::getStateString(sState));
+ ovutils::getStateString(sState[dpy]));
private_handle_t *hnd = NULL;
if(yuvLayer) {
@@ -74,38 +77,27 @@
switch(dpy) {
case HWC_DISPLAY_PRIMARY:
if(ctx->listStats[dpy].yuvCount == 1) {
- newState = isExternalActive(ctx) ?
- ovutils::OV_2D_VIDEO_ON_PANEL_TV : ovutils::OV_2D_VIDEO_ON_PANEL;
+ newState = ovutils::OV_2D_VIDEO_ON_PANEL;
if(isSkipLayer(yuvLayer) && !isSecureBuffer(hnd)) {
- newState = isExternalActive(ctx) ?
- ovutils::OV_2D_VIDEO_ON_TV : ovutils::OV_CLOSED;
+ newState = ovutils::OV_CLOSED;
}
}
break;
case HWC_DISPLAY_EXTERNAL:
- //TODO needs overlay state change for UI also
- newState = sState; //Previously set by HWC_DISPLAY_PRIMARY
- /*if(ctx->listStats[dpy].yuvCount == 1 && isExternalActive(ctx)) {
+ newState = ctx->mOverlay[HWC_DISPLAY_EXTERNAL]->getState(); //If we are here, external is active
+ if(ctx->listStats[dpy].yuvCount == 1) {
if(!isSkipLayer(yuvLayer) || isSecureBuffer(hnd)) {
- switch(sState) { //set by primary chooseState
- case ovutils::OV_2D_VIDEO_ON_PANEL:
- //upgrade
- sState = ovutils::OV_2D_VIDEO_PANEL_TV;
- break;
- case ovutils::OV_CLOSED:
- sState = ovutils::OV_2D_VIDEO_ON_TV;
- break;
- }
+ newState = ovutils::OV_UI_VIDEO_TV;
}
- }*/
+ }
break;
default:
break;
}
- sState = newState;
+ sState[dpy] = newState;
ALOGD_IF(VIDEO_DEBUG, "%s: new chosen state = %s", __FUNCTION__,
- ovutils::getStateString(sState));
+ ovutils::getStateString(sState[dpy]));
}
void VideoOverlay::markFlags(hwc_layer_1_t *yuvLayer) {
@@ -117,7 +109,7 @@
/* Helpers */
bool configPrimVid(hwc_context_t *ctx, hwc_layer_1_t *layer) {
- overlay::Overlay& ov = *(ctx->mOverlay);
+ overlay::Overlay& ov = *(ctx->mOverlay[HWC_DISPLAY_PRIMARY]);
private_handle_t *hnd = (private_handle_t *)layer->handle;
ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
@@ -184,7 +176,7 @@
}
bool configExtVid(hwc_context_t *ctx, hwc_layer_1_t *layer) {
- overlay::Overlay& ov = *(ctx->mOverlay);
+ overlay::Overlay& ov = *(ctx->mOverlay[HWC_DISPLAY_EXTERNAL]);
private_handle_t *hnd = (private_handle_t *)layer->handle;
ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
@@ -201,10 +193,9 @@
ovutils::PipeArgs parg(mdpFlags,
info,
- ovutils::ZORDER_0,
+ ovutils::ZORDER_1,
isFgFlag,
- ovutils::ROT_FLAG_ENABLED); //TODO remove this hack when sync for
- //ext is done
+ ovutils::ROT_FLAG_DISABLED);
ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
ov.setSource(pargs, ovutils::OV_PIPE1);
@@ -216,9 +207,10 @@
//Only for External
ov.setCrop(dcrop, ovutils::OV_PIPE1);
- // FIXME: Use source orientation for TV when source is portrait
- //Only for External
- ov.setTransform(0, ovutils::OV_PIPE1);
+ int transform = layer->transform;
+ ovutils::eTransform orient =
+ static_cast<ovutils::eTransform>(transform);
+ ov.setTransform(orient, ovutils::OV_PIPE1);
ovutils::Dim dpos;
hwc_rect_t displayFrame = layer->displayFrame;
@@ -240,31 +232,23 @@
bool VideoOverlay::configure(hwc_context_t *ctx, int dpy,
hwc_layer_1_t *yuvLayer) {
bool ret = true;
- overlay::Overlay& ov = *(ctx->mOverlay);
+ overlay::Overlay& ov = *(ctx->mOverlay[dpy]);
switch(dpy) {
case HWC_DISPLAY_PRIMARY:
// Set overlay state
- ov.setState(sState);
- switch(sState) {
+ ov.setState(sState[dpy]);
+ switch(sState[dpy]) {
case ovutils::OV_2D_VIDEO_ON_PANEL:
ret &= configPrimVid(ctx, yuvLayer);
break;
- case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
- ret &= configPrimVid(ctx, yuvLayer);
- ret &= configExtVid(ctx, yuvLayer);
- break;
- case ovutils::OV_2D_VIDEO_ON_TV:
- ret &= configExtVid(ctx, yuvLayer);
- break;
default:
return false;
}
break;
case HWC_DISPLAY_EXTERNAL:
- ov.setState(sState);
- switch(sState) {
- case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
- case ovutils::OV_2D_VIDEO_ON_TV:
+ ov.setState(sState[dpy]);
+ switch(sState[dpy]) {
+ case ovutils::OV_UI_VIDEO_TV:
ret = configExtVid(ctx, yuvLayer);
break;
default:
@@ -278,8 +262,12 @@
bool VideoOverlay::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy)
{
+ if(!sIsModeOn[dpy]) {
+ return true;
+ }
+
int yuvIndex = ctx->listStats[dpy].yuvIndex;
- if(!sIsModeOn || yuvIndex == -1) {
+ if(yuvIndex == -1) {
return true;
}
@@ -287,7 +275,7 @@
list->hwLayers[yuvIndex].handle;
bool ret = true;
- overlay::Overlay& ov = *(ctx->mOverlay);
+ overlay::Overlay& ov = *(ctx->mOverlay[dpy]);
ovutils::eOverlayState state = ov.getState();
switch(dpy) {
@@ -300,24 +288,6 @@
ret = false;
}
break;
- case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
- if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) {
- ALOGE("%s: queueBuffer failed for primary", __FUNCTION__);
- ret = false;
- }
- // Play external
- if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE1)) {
- ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
- ret = false;
- }
- break;
- case ovutils::OV_2D_VIDEO_ON_TV:
- // Play external
- if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE1)) {
- ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
- ret = false;
- }
- break;
default:
ret = false;
break;
@@ -325,8 +295,7 @@
break;
case HWC_DISPLAY_EXTERNAL:
switch(state) {
- case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
- case ovutils::OV_2D_VIDEO_ON_TV:
+ case ovutils::OV_UI_VIDEO_TV:
// Play external
if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE1)) {
ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
diff --git a/libhwcomposer/hwc_video.h b/libhwcomposer/hwc_video.h
index f5a9709..dbfc236 100644
--- a/libhwcomposer/hwc_video.h
+++ b/libhwcomposer/hwc_video.h
@@ -43,14 +43,16 @@
//Marks layer flags if this feature is used
static void markFlags(hwc_layer_1_t *yuvLayer);
//The chosen overlay state.
- static ovutils::eOverlayState sState;
+ static ovutils::eOverlayState sState[HWC_NUM_DISPLAY_TYPES];
//Flags if this feature is on.
- static bool sIsModeOn;
+ static bool sIsModeOn[HWC_NUM_DISPLAY_TYPES];
};
inline void VideoOverlay::reset() {
- sIsModeOn = false;
- sState = ovutils::OV_CLOSED;
+ for(uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
+ sIsModeOn[i] = false;
+ sState[i] = ovutils::OV_CLOSED;
+ }
}
}; //namespace qhwc
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index 37e99df..170b8a9 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -53,6 +53,7 @@
case utils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV:
case utils::OV_UI_MIRROR:
case utils::OV_2D_TRUE_UI_MIRROR:
+ case utils::OV_UI_VIDEO_TV:
case utils::OV_BYPASS_1_LAYER:
case utils::OV_BYPASS_2_LAYER:
case utils::OV_BYPASS_3_LAYER:
@@ -187,16 +188,19 @@
return mState.state();
}
-Overlay *Overlay::sInstance = 0;
+Overlay *Overlay::sInstance[] = {0};
-Overlay* Overlay::getInstance() {
- if(sInstance == NULL) {
- if(utils::initOverlay() == -1) {
- ALOGE("utils::initOverlay() ERROR!!");
- }
- sInstance = new Overlay();
+Overlay* Overlay::getInstance(int disp) {
+ if(sInstance[disp] == NULL) {
+ sInstance[disp] = new Overlay();
}
- return sInstance;
+ return sInstance[disp];
+}
+
+void Overlay::initOverlay() {
+ if(utils::initOverlay() == -1) {
+ ALOGE("utils::initOverlay() ERROR!!");
+ }
}
} // overlay
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index 12b3883..f8f9c34 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -66,8 +66,11 @@
/* expose state */
utils::eOverlayState getState() const;
- /* Returns the singleton instance of overlay */
- static Overlay* getInstance();
+ /* Closes open pipes */
+ static void initOverlay();
+
+ /* Returns the per-display singleton instance of overlay */
+ static Overlay* getInstance(int disp);
private:
/* Ctor setup */
@@ -84,8 +87,8 @@
/* Holds the actual overlay impl, set when changing state*/
OverlayImplBase *mOv;
- /* Singleton Instance*/
- static Overlay *sInstance;
+ /* Per-display Singleton Instance HWC_NUM_DISPLAY_TYPES */
+ static Overlay *sInstance[2];
};
} // overlay
diff --git a/liboverlay/overlayState.h b/liboverlay/overlayState.h
index e4fbece..85d61d5 100644
--- a/liboverlay/overlayState.h
+++ b/liboverlay/overlayState.h
@@ -145,6 +145,19 @@
typedef overlay::OverlayImpl<pipe0, pipe1, pipe2> ovimpl;
};
+template <> struct StateTraits<utils::OV_UI_VIDEO_TV>
+{
+ typedef overlay::GenericPipe<utils::EXTERNAL> pipe0; //ext UI
+ typedef overlay::GenericPipe<utils::EXTERNAL> pipe1; //ext video
+ typedef overlay::NullPipe pipe2;
+
+ typedef Rotator rot0;
+ typedef Rotator rot1;
+ typedef NullRotator rot2;
+
+ typedef overlay::OverlayImpl<pipe0, pipe1, pipe2> ovimpl;
+};
+
template <> struct StateTraits<utils::OV_3D_VIDEO_ON_2D_PANEL>
{
typedef overlay::M3DPrimaryPipe<utils::OV_PIPE0> pipe0;
@@ -199,7 +212,7 @@
template <> struct StateTraits<utils::OV_UI_MIRROR>
{
- typedef overlay::UIMirrorPipe pipe0;
+ typedef overlay::GenericPipe<ovutils::EXTERNAL> pipe0; //Ext UI
typedef overlay::NullPipe pipe1; // place holder
typedef overlay::NullPipe pipe2; // place holder
@@ -212,9 +225,9 @@
template <> struct StateTraits<utils::OV_2D_TRUE_UI_MIRROR>
{
- typedef overlay::GenericPipe<utils::PRIMARY> pipe0;
+ typedef overlay::GenericPipe<utils::PRIMARY> pipe0; //Vid prim
typedef overlay::VideoExtPipe pipe1;
- typedef overlay::UIMirrorPipe pipe2;
+ typedef overlay::GenericPipe<ovutils::EXTERNAL> pipe2; //EXT UI
typedef Rotator rot0;
typedef Rotator rot1;
@@ -335,6 +348,9 @@
case utils::OV_2D_TRUE_UI_MIRROR:
newov = handle_from<utils::OV_2D_TRUE_UI_MIRROR>(toState, ov);
break;
+ case utils::OV_UI_VIDEO_TV:
+ newov = handle_from<utils::OV_UI_VIDEO_TV>(toState, ov);
+ break;
case utils::OV_BYPASS_1_LAYER:
newov = handle_from<utils::OV_BYPASS_1_LAYER>(toState, ov);
break;
@@ -391,6 +407,9 @@
case utils::OV_2D_TRUE_UI_MIRROR:
ov = handle_from_to<FROM_STATE, utils::OV_2D_TRUE_UI_MIRROR>(ov);
break;
+ case utils::OV_UI_VIDEO_TV:
+ ov = handle_from_to<FROM_STATE, utils::OV_UI_VIDEO_TV>(ov);
+ break;
case utils::OV_BYPASS_1_LAYER:
ov = handle_from_to<FROM_STATE, utils::OV_BYPASS_1_LAYER>(ov);
break;
@@ -580,6 +599,69 @@
return newov;
}
+/* Transition from OV_UI_MIRROR to OV_UI_VIDEO_TV */
+template<>
+inline OverlayImplBase* OverlayState::handle_from_to<
+ utils::OV_UI_MIRROR,
+ utils::OV_UI_VIDEO_TV>(
+ OverlayImplBase* ov) {
+ OVASSERT(ov, "%s: ov is null", __FUNCTION__);
+ ALOGD("FROM_STATE = %s TO_STATE = %s",
+ utils::getStateString(utils::OV_UI_MIRROR),
+ utils::getStateString(utils::OV_UI_VIDEO_TV));
+
+ // Create new ovimpl based on new state
+ typedef StateTraits<utils::OV_UI_VIDEO_TV> NewState;
+ OverlayImplBase* newov = new NewState::ovimpl;
+
+ //copy pipe0/rot0 (ext video)
+ newov->copyOvPipe(ov, utils::OV_PIPE0);
+
+ ov->closePipe(utils::OV_PIPE1);
+ RotatorBase* rot1 = new NewState::rot1;
+ newov->initPipe(rot1, utils::OV_PIPE1);
+
+ ov->closePipe(utils::OV_PIPE2);
+ RotatorBase* rot2 = new NewState::rot2;
+ newov->initPipe(rot2, utils::OV_PIPE2);
+
+ // All pipes are copied or deleted so no more need for previous ovimpl
+ delete ov;
+ ov = 0;
+ return newov;
+}
+
+/* Transition from OV_UI_VIDEO_TV to OV_UI_MIRROR */
+template<>
+inline OverlayImplBase* OverlayState::handle_from_to<
+ utils::OV_UI_VIDEO_TV,
+ utils::OV_UI_MIRROR>(
+ OverlayImplBase* ov) {
+ OVASSERT(ov, "%s: ov is null", __FUNCTION__);
+ ALOGD("FROM_STATE = %s TO_STATE = %s",
+ utils::getStateString(utils::OV_UI_VIDEO_TV),
+ utils::getStateString(utils::OV_UI_MIRROR));
+
+ // Create new ovimpl based on new state
+ typedef StateTraits<utils::OV_UI_MIRROR> NewState;
+ OverlayImplBase* newov = new NewState::ovimpl;
+
+ //copy pipe0/rot0 (ext video)
+ newov->copyOvPipe(ov, utils::OV_PIPE0);
+
+ ov->closePipe(utils::OV_PIPE1);
+ RotatorBase* rot1 = new NewState::rot1;
+ newov->initPipe(rot1, utils::OV_PIPE1);
+
+ ov->closePipe(utils::OV_PIPE2);
+ RotatorBase* rot2 = new NewState::rot2;
+ newov->initPipe(rot2, utils::OV_PIPE2);
+
+ // All pipes are copied or deleted so no more need for previous ovimpl
+ delete ov;
+ ov = 0;
+ return newov;
+}
} // overlay
#endif // OVERLAY_STATE_H
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index f308b95..8db37c5 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -402,6 +402,8 @@
/* UI Mirroring */
OV_UI_MIRROR,
OV_2D_TRUE_UI_MIRROR,
+ /* Dual display with video */
+ OV_UI_VIDEO_TV,
/* Composition Bypass */
OV_BYPASS_1_LAYER,
@@ -648,6 +650,8 @@
return "OV_UI_MIRROR";
case OV_2D_TRUE_UI_MIRROR:
return "OV_2D_TRUE_UI_MIRROR";
+ case OV_UI_VIDEO_TV:
+ return "OV_UI_VIDEO_TV";
case OV_BYPASS_1_LAYER:
return "OV_BYPASS_1_LAYER";
case OV_BYPASS_2_LAYER: