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