hwcomposer: Add support for UI mirroring
- Uevent observer as part of Hwcomposer
- HPD, enabling/disabling external display from HWC
Change-Id: I52b4f30c78e98c5b52c86722046389f458c2dbee
diff --git a/libgralloc/framebuffer.cpp b/libgralloc/framebuffer.cpp
index f689d52..31978f0 100644
--- a/libgralloc/framebuffer.cpp
+++ b/libgralloc/framebuffer.cpp
@@ -43,9 +43,6 @@
#include <cutils/properties.h>
#include <profiler.h>
-#include "overlay.h"
-namespace ovutils = overlay::utils;
-
#define EVEN_OUT(x) if (x & 0x0001) {x--;}
/** min of int a, b */
static inline int min(int a, int b) {
@@ -101,402 +98,6 @@
return 0;
}
-#if defined(HDMI_DUAL_DISPLAY)
-static int closeHDMIChannel(private_module_t* m)
-{
- // XXX - when enabling HDMI
-#if 0
- Overlay* pTemp = m->pobjOverlay;
- if(pTemp != NULL)
- pTemp->closeChannel();
-#endif
- return 0;
-}
-
-// XXX - Complete when enabling HDMI
-#if 0
-static void getSecondaryDisplayDestinationInfo(private_module_t* m, overlay_rect&
- rect, int& orientation)
-{
- Overlay* pTemp = m->pobjOverlay;
- int width = pTemp->getFBWidth();
- int height = pTemp->getFBHeight();
- int fbwidth = m->info.xres, fbheight = m->info.yres;
- rect.x = 0; rect.y = 0;
- rect.w = width; rect.h = height;
- int rot = m->orientation;
- switch(rot) {
- // ROT_0
- case 0:
- // ROT_180
- case HAL_TRANSFORM_ROT_180:
- pTemp->getAspectRatioPosition(fbwidth, fbheight,
- &rect);
- if(rot == HAL_TRANSFORM_ROT_180)
- orientation = HAL_TRANSFORM_ROT_180;
- else
- orientation = 0;
- break;
- // ROT_90
- case HAL_TRANSFORM_ROT_90:
- // ROT_270
- case HAL_TRANSFORM_ROT_270:
- //Calculate the Aspectratio for the UI
- //in the landscape mode
- //Width and height will be swapped as there
- //is rotation
- pTemp->getAspectRatioPosition(fbheight, fbwidth,
- &rect);
-
- if(rot == HAL_TRANSFORM_ROT_90)
- orientation = HAL_TRANSFORM_ROT_270;
- else if(rot == HAL_TRANSFORM_ROT_270)
- orientation = HAL_TRANSFORM_ROT_90;
- break;
- }
- return;
-}
-#endif
-
-/* Determine overlay state based on whether hardware supports true UI
- mirroring and whether video is playing or not */
-static ovutils::eOverlayState getOverlayState(struct private_module_t* module)
-{
- overlay2::Overlay& ov = *(Overlay::getInstance());
-
- // Default to existing state
- ovutils::eOverlayState state = ov.getState();
-
- // Sanity check
- if (!module) {
- ALOGE("%s: NULL module", __FUNCTION__);
- return state;
- }
-
- // Check if video is playing or not
- if (module->videoOverlay) {
- // Video is playing, check if hardware supports true UI mirroring
- if (module->trueMirrorSupport) {
- // True UI mirroring is supported by hardware
- if (ov.getState() == ovutils::OV_2D_VIDEO_ON_PANEL) {
- // Currently playing 2D video
- state = ovutils::OV_2D_TRUE_UI_MIRROR;
- } else if (ov.getState() == ovutils::OV_3D_VIDEO_ON_2D_PANEL) {
- // Currently playing M3D video
- // FIXME: Support M3D true UI mirroring
- state = ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV;
- }
- } else {
- // True UI mirroring is not supported by hardware
- if (ov.getState() == ovutils::OV_2D_VIDEO_ON_PANEL) {
- // Currently playing 2D video
- state = ovutils::OV_2D_VIDEO_ON_PANEL_TV;
- } else if (ov.getState() == ovutils::OV_3D_VIDEO_ON_2D_PANEL) {
- // Currently playing M3D video
- state = ovutils::OV_3D_VIDEO_ON_2D_PANEL_2D_TV;
- }
- }
- } else {
- // Video is not playing, true UI mirroring support is irrelevant
- state = ovutils::OV_UI_MIRROR;
- }
-
- return state;
-}
-
-/* Set overlay state */
-static void setOverlayState(ovutils::eOverlayState state)
-{
- overlay2::Overlay& ov = *(Overlay::getInstance());
- ov.setState(state);
-}
-
-static void *hdmi_ui_loop(void *ptr)
-{
- private_module_t* m = reinterpret_cast<private_module_t*>(ptr);
- while (1) {
- pthread_mutex_lock(&m->overlayLock);
- while(!(m->hdmiStateChanged))
- pthread_cond_wait(&(m->overlayPost), &(m->overlayLock));
-
- m->hdmiStateChanged = false;
- if (m->exitHDMIUILoop) {
- pthread_mutex_unlock(&m->overlayLock);
- return NULL;
- }
-
- // No need to mirror UI if HDMI is not on
- if (!m->enableHDMIOutput) {
- ALOGE_IF(FB_DEBUG, "%s: hdmi not ON", __FUNCTION__);
- pthread_mutex_unlock(&m->overlayLock);
- continue;
- }
-
- overlay2::OverlayMgr* ovMgr =
- overlay2::OverlayMgrSingleton::getOverlayMgr();
- overlay2::Overlay& ov = ovMgr->ov();
-
- // Set overlay state
- ovutils::eOverlayState state = getOverlayState(m);
- setOverlayState(state);
-
- // Determine the RGB pipe for UI depending on the state
- ovutils::eDest dest = ovutils::OV_PIPE_ALL;
- if (state == ovutils::OV_2D_TRUE_UI_MIRROR) {
- // True UI mirroring state: external RGB pipe is OV_PIPE2
- dest = ovutils::OV_PIPE2;
- } else if (state == ovutils::OV_UI_MIRROR) {
- // UI-only mirroring state: external RGB pipe is OV_PIPE0
- dest = ovutils::OV_PIPE0;
- } else {
- // No UI in this case
- pthread_mutex_unlock(&m->overlayLock);
- continue;
- }
-
- if (m->hdmiMirroringState == HDMI_UI_MIRRORING) {
- int alignedW = ALIGN(m->info.xres, 32);
-
- private_handle_t const* hnd =
- reinterpret_cast<private_handle_t const*>(m->framebuffer);
- unsigned int width = alignedW;
- unsigned int height = hnd->height;
- unsigned int format = hnd->format;
- unsigned int size = hnd->size/m->numBuffers;
-
- ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
- // External display connected during secure video playback
- // Open secure UI session
- // NOTE: when external display is already connected and then secure
- // playback is started, we dont have to do anything
- if (m->secureVideoOverlay) {
- ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
- }
-
- ovutils::Whf whf(width, height, format, size);
- ovutils::PipeArgs parg(mdpFlags,
- ovutils::OVERLAY_TRANSFORM_0,
- whf,
- ovutils::ZORDER_0,
- ovutils::IS_FG_OFF,
- ovutils::ROT_FLAG_ENABLED);
- ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
- bool ret = ov.setSource(pargs, dest);
- if (!ret) {
- ALOGE("%s setSource failed", __FUNCTION__);
- }
-
- // we need to communicate m->orientation that will get some
- // modifications within setParameter func.
- // FIXME that is ugly.
- const ovutils::Params prms (ovutils::OVERLAY_TRANSFORM_UI,
- m->orientation);
- ov.setParameter(prms, dest);
- if (!ret) {
- ALOGE("%s setParameter failed transform", __FUNCTION__);
- }
-
- // x,y,w,h
- ovutils::Dim dcrop(0, 0, m->info.xres, m->info.yres);
- ov.setMemoryId(m->framebuffer->fd, dest);
- ret = ov.setCrop(dcrop, dest);
- if (!ret) {
- ALOGE("%s setCrop failed", __FUNCTION__);
- }
-
- ovutils::Dim pdim (m->info.xres,
- m->info.yres,
- 0,
- 0,
- m->orientation);
- ret = ov.setPosition(pdim, dest);
- if (!ret) {
- ALOGE("%s setPosition failed", __FUNCTION__);
- }
-
- if (!ov.commit(dest)) {
- ALOGE("%s commit fails", __FUNCTION__);
- }
-
- ret = ov.queueBuffer(m->currentOffset, dest);
- if (!ret) {
- ALOGE("%s queueBuffer failed", __FUNCTION__);
- }
- } else {
- setOverlayState(ovutils::OV_CLOSED);
- }
- pthread_mutex_unlock(&m->overlayLock);
- }
- return NULL;
-}
-
-static int fb_videoOverlayStarted(struct framebuffer_device_t* dev, int started)
-{
- ALOGE_IF(FB_DEBUG, "%s started=%d", __FUNCTION__, started);
- private_module_t* m = reinterpret_cast<private_module_t*>(
- dev->common.module);
- pthread_mutex_lock(&m->overlayLock);
- if(started != m->videoOverlay) {
- m->videoOverlay = started;
- m->hdmiStateChanged = true;
- if (!m->trueMirrorSupport) {
- if (started) {
- m->hdmiMirroringState = HDMI_NO_MIRRORING;
- ovutils::eOverlayState state = getOverlayState(m);
- setOverlayState(state);
- } else if (m->enableHDMIOutput)
- m->hdmiMirroringState = HDMI_UI_MIRRORING;
- } else {
- if (m->videoOverlay == VIDEO_3D_OVERLAY_STARTED) {
- ALOGE_IF(FB_DEBUG, "3D Video Started, stop mirroring!");
- m->hdmiMirroringState = HDMI_NO_MIRRORING;
- ovutils::eOverlayState state = getOverlayState(m);
- setOverlayState(state);
- }
- else if (m->enableHDMIOutput) {
- m->hdmiMirroringState = HDMI_UI_MIRRORING;
- }
- }
- }
- pthread_mutex_unlock(&m->overlayLock);
- return 0;
-}
-
-static int fb_enableHDMIOutput(struct framebuffer_device_t* dev, int externaltype)
-{
- ALOGE_IF(FB_DEBUG, "%s externaltype=%d", __FUNCTION__, externaltype);
- private_module_t* m = reinterpret_cast<private_module_t*>(
- dev->common.module);
- pthread_mutex_lock(&m->overlayLock);
- //Check if true mirroring can be supported
- m->trueMirrorSupport = ovutils::FrameBufferInfo::getInstance()->supportTrueMirroring();
- m->enableHDMIOutput = externaltype;
- if(externaltype) {
- if (m->trueMirrorSupport) {
- m->hdmiMirroringState = HDMI_UI_MIRRORING;
- } else {
- if(!m->videoOverlay)
- m->hdmiMirroringState = HDMI_UI_MIRRORING;
- }
- } else if (!externaltype) {
- // Either HDMI is disconnected or suspend occurred
- m->hdmiMirroringState = HDMI_NO_MIRRORING;
- ovutils::eOverlayState state = getOverlayState(m);
- setOverlayState(state);
- }
- m->hdmiStateChanged = true;
- pthread_cond_signal(&(m->overlayPost));
- pthread_mutex_unlock(&m->overlayLock);
- return 0;
-}
-
-static int fb_orientationChanged(struct framebuffer_device_t* dev, int orientation)
-{
- private_module_t* m = reinterpret_cast<private_module_t*>(
- dev->common.module);
- pthread_mutex_lock(&m->overlayLock);
- neworientation = orientation;
- pthread_mutex_unlock(&m->overlayLock);
- return 0;
-}
-
-static int handle_open_secure_start(private_module_t* m) {
- pthread_mutex_lock(&m->overlayLock);
- m->hdmiMirroringState = HDMI_NO_MIRRORING;
- m->secureVideoOverlay = true;
- pthread_mutex_unlock(&m->overlayLock);
- return 0;
-}
-
-static int handle_open_secure_end(private_module_t* m) {
- pthread_mutex_lock(&m->overlayLock);
- if (m->enableHDMIOutput) {
- if (m->trueMirrorSupport) {
- m->hdmiMirroringState = HDMI_UI_MIRRORING;
- } else if(!m->videoOverlay) {
- m->hdmiMirroringState = HDMI_UI_MIRRORING;
- }
- m->hdmiStateChanged = true;
- pthread_cond_signal(&(m->overlayPost));
- }
- pthread_mutex_unlock(&m->overlayLock);
- return 0;
-}
-
-static int handle_close_secure_start(private_module_t* m) {
- pthread_mutex_lock(&m->overlayLock);
- m->hdmiMirroringState = HDMI_NO_MIRRORING;
- m->secureVideoOverlay = false;
- pthread_mutex_unlock(&m->overlayLock);
- return 0;
-}
-
-static int handle_close_secure_end(private_module_t* m) {
- pthread_mutex_lock(&m->overlayLock);
- if (m->enableHDMIOutput) {
- if (m->trueMirrorSupport) {
- m->hdmiMirroringState = HDMI_UI_MIRRORING;
- } else if(!m->videoOverlay) {
- m->hdmiMirroringState = HDMI_UI_MIRRORING;
- }
- m->hdmiStateChanged = true;
- pthread_cond_signal(&(m->overlayPost));
- }
- pthread_mutex_unlock(&m->overlayLock);
- return 0;
-}
-#endif
-
-
-
-/* fb_perform - used to add custom event and handle them in fb HAL
- * Used for external display related functions as of now
- */
-static int fb_perform(struct framebuffer_device_t* dev, int event, int value)
-{
- private_module_t* m = reinterpret_cast<private_module_t*>(
- dev->common.module);
- switch(event) {
-#if defined(HDMI_DUAL_DISPLAY)
- case EVENT_EXTERNAL_DISPLAY:
- fb_enableHDMIOutput(dev, value);
- break;
- case EVENT_VIDEO_OVERLAY:
- fb_videoOverlayStarted(dev, value);
- break;
- case EVENT_ORIENTATION_CHANGE:
- fb_orientationChanged(dev, value);
- break;
- case EVENT_OVERLAY_STATE_CHANGE:
- if (value == OVERLAY_STATE_CHANGE_START) {
- // When state change starts, get a lock on overlay
- pthread_mutex_lock(&m->overlayLock);
- } else if (value == OVERLAY_STATE_CHANGE_END) {
- // When state change is complete, unlock overlay
- pthread_mutex_unlock(&m->overlayLock);
- }
- break;
- case EVENT_OPEN_SECURE_START:
- handle_open_secure_start(m);
- break;
- case EVENT_OPEN_SECURE_END:
- handle_open_secure_end(m);
- break;
- case EVENT_CLOSE_SECURE_START:
- handle_close_secure_start(m);
- break;
- case EVENT_CLOSE_SECURE_END:
- handle_close_secure_end(m);
- break;
-#endif
- default:
- ALOGE("In %s: UNKNOWN Event = %d!!!", __FUNCTION__, event);
- break;
- }
- return 0;
-}
-
-
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{
if (private_handle_t::validate(buffer) < 0)
@@ -510,6 +111,7 @@
private_module_t* m =
reinterpret_cast<private_module_t*>(dev->common.module);
+
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
genlock_lock_buffer(hnd, GENLOCK_READ_LOCK, GENLOCK_MAX_TIMEOUT);
@@ -519,6 +121,14 @@
}
const size_t offset = hnd->base - m->framebuffer->base;
+ // frame ready to be posted, signal so that hwc can update External
+ // display
+ pthread_mutex_lock(&m->fbPostLock);
+ m->currentOffset = offset;
+ m->fbPostDone = true;
+ pthread_cond_signal(&m->fbPostCond);
+ pthread_mutex_unlock(&m->fbPostLock);
+
m->info.activate = FB_ACTIVATE_VBL;
m->info.yoffset = offset / m->finfo.line_length;
if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
@@ -579,11 +189,12 @@
info.yoffset = 0;
info.activate = FB_ACTIVATE_NOW;
- /* Interpretation of offset for color fields: All offsets are from the right,
- * inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you
- * can use the offset as right argument to <<). A pixel afterwards is a bit
- * stream and is written to video memory as that unmodified. This implies
- * big-endian byte order if bits_per_pixel is greater than 8.
+ /* Interpretation of offset for color fields: All offsets are from the
+ * right, inside a "pixel" value, which is exactly 'bits_per_pixel' wide
+ * (means: you can use the offset as right argument to <<). A pixel
+ * afterwards is a bit stream and is written to video memory as that
+ * unmodified. This implies big-endian byte order if bits_per_pixel is
+ * greater than 8.
*/
if(info.bits_per_pixel == 32) {
@@ -600,10 +211,11 @@
info.transp.offset = 0;
info.transp.length = 8;
- /* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we do
- * not use the MDP for composition (i.e. hw composition == 0), ask for
- * RGBA instead of RGBX. */
- if (property_get("debug.sf.hw", property, NULL) > 0 && atoi(property) == 0)
+ /* Note: the GL driver does not have a r=8 g=8 b=8 a=0 config, so if we
+ * do not use the MDP for composition (i.e. hw composition == 0), ask
+ * for RGBA instead of RGBX. */
+ if (property_get("debug.sf.hw", property, NULL) > 0 &&
+ atoi(property) == 0)
module->fbFormat = HAL_PIXEL_FORMAT_RGBX_8888;
else if(property_get("debug.composition.type", property, NULL) > 0 &&
(strncmp(property, "mdp", 3) == 0))
@@ -627,7 +239,8 @@
}
//adreno needs 4k aligned offsets. Max hole size is 4096-1
- int size = roundUpToPageSize(info.yres * info.xres * (info.bits_per_pixel/8));
+ int size = roundUpToPageSize(info.yres * info.xres *
+ (info.bits_per_pixel/8));
/*
* Request NUM_BUFFERS screens (at least 2 for page flipping)
@@ -738,9 +351,9 @@
size_t fbSize = roundUpToPageSize(finfo.line_length * info.yres)*
module->numBuffers;
module->framebuffer = new private_handle_t(fd, fbSize,
- private_handle_t::PRIV_FLAGS_USES_PMEM,
- BUFFER_TYPE_UI,
- module->fbFormat, info.xres, info.yres);
+ private_handle_t::PRIV_FLAGS_USES_PMEM,
+ BUFFER_TYPE_UI,
+ module->fbFormat, info.xres, info.yres);
void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (vaddr == MAP_FAILED) {
ALOGE("Error mapping the framebuffer (%s)", strerror(errno));
@@ -748,20 +361,10 @@
}
module->framebuffer->base = intptr_t(vaddr);
memset(vaddr, 0, fbSize);
-
-#if defined(HDMI_DUAL_DISPLAY)
- /* Overlay for HDMI*/
- pthread_mutex_init(&(module->overlayLock), NULL);
- pthread_cond_init(&(module->overlayPost), NULL);
module->currentOffset = 0;
- module->exitHDMIUILoop = false;
- module->hdmiStateChanged = false;
- pthread_t hdmiUIThread;
- pthread_create(&hdmiUIThread, NULL, &hdmi_ui_loop, (void *) module);
- module->hdmiMirroringState = HDMI_NO_MIRRORING;
- module->trueMirrorSupport = false;
-#endif
-
+ module->fbPostDone = false;
+ pthread_mutex_init(&(module->fbPostLock), NULL);
+ pthread_cond_init(&(module->fbPostCond), NULL);
return 0;
}
@@ -778,14 +381,6 @@
static int fb_close(struct hw_device_t *dev)
{
fb_context_t* ctx = (fb_context_t*)dev;
-#if defined(HDMI_DUAL_DISPLAY)
- private_module_t* m = reinterpret_cast<private_module_t*>(
- ctx->device.common.module);
- pthread_mutex_lock(&m->overlayLock);
- m->exitHDMIUILoop = true;
- pthread_cond_signal(&(m->overlayPost));
- pthread_mutex_unlock(&m->overlayLock);
-#endif
if (ctx) {
free(ctx);
}
@@ -828,8 +423,10 @@
const_cast<float&>(dev->device.xdpi) = m->xdpi;
const_cast<float&>(dev->device.ydpi) = m->ydpi;
const_cast<float&>(dev->device.fps) = m->fps;
- const_cast<int&>(dev->device.minSwapInterval) = PRIV_MIN_SWAP_INTERVAL;
- const_cast<int&>(dev->device.maxSwapInterval) = PRIV_MAX_SWAP_INTERVAL;
+ const_cast<int&>(dev->device.minSwapInterval) =
+ PRIV_MIN_SWAP_INTERVAL;
+ const_cast<int&>(dev->device.maxSwapInterval) =
+ PRIV_MAX_SWAP_INTERVAL;
const_cast<int&>(dev->device.numFramebuffers) = m->numBuffers;
if (m->finfo.reserved[0] == 0x5444 &&
m->finfo.reserved[1] == 0x5055) {