hwcomposer: Add support for UI mirroring

- Uevent observer as part of Hwcomposer
- HPD, enabling/disabling external display from HWC

Change-Id: I52b4f30c78e98c5b52c86722046389f458c2dbee
This commit is contained in:
Naseer Ahmed
2012-07-20 09:06:13 -07:00
committed by Brian Muramatsu
parent f48aef64b2
commit 0c8b7b5c84
12 changed files with 812 additions and 469 deletions

View File

@@ -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 @@ static int fb_setUpdateRect(struct framebuffer_device_t* dev,
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 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
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 @@ static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
}
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 @@ int mapFrameBufferLocked(struct private_module_t* module)
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 @@ int mapFrameBufferLocked(struct private_module_t* module)
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 @@ int mapFrameBufferLocked(struct private_module_t* module)
}
//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 @@ int mapFrameBufferLocked(struct private_module_t* module)
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 @@ int mapFrameBufferLocked(struct private_module_t* module)
}
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 mapFrameBuffer(struct private_module_t* module)
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 @@ int fb_device_open(hw_module_t const* module, const char* name,
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) {