hwc: hwc 1.1 implementation

Bug: 7124159

--External disabled
--MDP comp coded but disabled.
--Videos via overlay, so that secure videos can work.

Change-Id: Ie48b264143d5e4237ab9724e28930e3f68ba49ee
Signed-off-by: Iliyan Malchev <malchev@google.com>
This commit is contained in:
Saurabh Shah
2012-09-17 16:53:21 -07:00
committed by Iliyan Malchev
parent 52fc4cdb4d
commit 3e858ebde3
15 changed files with 557 additions and 593 deletions

View File

@@ -94,11 +94,6 @@ void ExternalDisplay::getEDIDModes(int *out) const {
} }
} }
int ExternalDisplay::getExternalDisplay() const {
Mutex::Autolock lock(mExtDispLock);
return mExternalDisplay;
}
ExternalDisplay::~ExternalDisplay() ExternalDisplay::~ExternalDisplay()
{ {
closeFrameBuffer(); closeFrameBuffer();
@@ -249,6 +244,9 @@ bool ExternalDisplay::openFramebuffer()
if (mFd < 0) if (mFd < 0)
ALOGE("%s: /dev/graphics/fb1 not available", __FUNCTION__); ALOGE("%s: /dev/graphics/fb1 not available", __FUNCTION__);
} }
if(mHwcContext) {
mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
}
return (mFd > 0); return (mFd > 0);
} }
@@ -259,6 +257,9 @@ bool ExternalDisplay::closeFrameBuffer()
ret = close(mFd); ret = close(mFd);
mFd = -1; mFd = -1;
} }
if(mHwcContext) {
mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
}
return (ret == 0); return (ret == 0);
} }
@@ -411,11 +412,10 @@ void ExternalDisplay::setExternalDisplay(int connected)
//Get the best mode and set //Get the best mode and set
// TODO: DO NOT call this for WFD // TODO: DO NOT call this for WFD
setResolution(getBestMode()); setResolution(getBestMode());
setDpyAttr();
//enable hdmi vsync //enable hdmi vsync
enableHDMIVsync(connected);
} else { } else {
// Disable the hdmi vsync // Disable the hdmi vsync
enableHDMIVsync(connected);
closeFrameBuffer(); closeFrameBuffer();
resetInfo(); resetInfo();
} }
@@ -424,9 +424,9 @@ void ExternalDisplay::setExternalDisplay(int connected)
const char* prop = (connected) ? "1" : "0"; const char* prop = (connected) ? "1" : "0";
// set system property // set system property
property_set("hw.hdmiON", prop); property_set("hw.hdmiON", prop);
/* Trigger redraw */ //Inform SF
ALOGD_IF(DEBUG, "%s: Invalidate !!", __FUNCTION__); ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false;
ctx->proc->invalidate(ctx->proc); ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL, connected);
} }
return; return;
} }
@@ -458,7 +458,7 @@ bool ExternalDisplay::writeHPDOption(int userOption) const
return ret; return ret;
} }
bool ExternalDisplay::commit() bool ExternalDisplay::post()
{ {
if(mFd == -1) { if(mFd == -1) {
return false; return false;
@@ -470,16 +470,73 @@ bool ExternalDisplay::commit()
return true; return true;
} }
int ExternalDisplay::enableHDMIVsync(int enable) void ExternalDisplay::setDpyAttr() {
{ int width = 0, height = 0, fps = 0;
if(mFd > 0) { getAttrForMode(width, height, fps);
int ret = ioctl(mFd, MSMFB_OVERLAY_VSYNC_CTRL, &enable); if(mHwcContext) {
if (ret<0) { mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
ALOGE("%s: enabling HDMI vsync failed, str: %s", __FUNCTION__, mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
strerror(errno)); mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period = 1000000000l /
} fps;
}
}
void ExternalDisplay::getAttrForMode(int& width, int& height,
int& fps) {
switch (mCurrentMode) {
case m640x480p60_4_3:
width = 640;
height = 480;
fps = 60;
break;
case m720x480p60_4_3:
case m720x480p60_16_9:
width = 720;
height = 480;
fps = 60;
break;
case m720x576p50_4_3:
case m720x576p50_16_9:
width = 720;
height = 576;
fps = 50;
break;
case m1280x720p50_16_9:
width = 1280;
height = 720;
fps = 50;
break;
case m1280x720p60_16_9:
width = 1280;
height = 720;
fps = 60;
break;
case m1920x1080p24_16_9:
width = 1920;
height = 1080;
fps = 24;
break;
case m1920x1080p25_16_9:
width = 1920;
height = 1080;
fps = 25;
break;
case m1920x1080p30_16_9:
width = 1920;
height = 1080;
fps = 30;
break;
case m1920x1080p50_16_9:
width = 1920;
height = 1080;
fps = 50;
break;
case m1920x1080p60_16_9:
width = 1920;
height = 1080;
fps = 60;
break;
} }
return -errno;
} }
}; };

View File

@@ -30,27 +30,13 @@ namespace qhwc {
class ExternalDisplay class ExternalDisplay
{ {
//Type of external display - OFF, HDMI, WFD
enum external_display_type {
EXT_TYPE_NONE,
EXT_TYPE_HDMI,
EXT_TYPE_WIFI
};
// Mirroring state
enum external_mirroring_state {
EXT_MIRRORING_OFF,
EXT_MIRRORING_ON,
};
public: public:
ExternalDisplay(hwc_context_t* ctx); ExternalDisplay(hwc_context_t* ctx);
~ExternalDisplay(); ~ExternalDisplay();
int getModeCount() const; int getModeCount() const;
void getEDIDModes(int *out) const; void getEDIDModes(int *out) const;
int getExternalDisplay() const;
void setExternalDisplay(int connected); void setExternalDisplay(int connected);
bool commit(); bool post();
int enableHDMIVsync(int enable);
void setHPD(uint32_t startEnd); void setHPD(uint32_t startEnd);
void setEDIDMode(int resMode); void setEDIDMode(int resMode);
void setActionSafeDimension(int w, int h); void setActionSafeDimension(int w, int h);
@@ -67,6 +53,8 @@ private:
int getModeOrder(int mode); int getModeOrder(int mode);
int getBestMode(); int getBestMode();
void resetInfo(); void resetInfo();
void setDpyAttr();
void getAttrForMode(int& width, int& height, int& fps);
mutable android::Mutex mExtDispLock; mutable android::Mutex mExtDispLock;
int mFd; int mFd;

View File

@@ -100,51 +100,22 @@ static int fb_setUpdateRect(struct framebuffer_device_t* dev,
static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer)
{ {
if (private_handle_t::validate(buffer) < 0)
return -EINVAL;
fb_context_t* ctx = (fb_context_t*) dev; fb_context_t* ctx = (fb_context_t*) dev;
private_handle_t *hnd = static_cast<private_handle_t*> private_handle_t *hnd = static_cast<private_handle_t*>
(const_cast<native_handle_t*>(buffer)); (const_cast<native_handle_t*>(buffer));
private_module_t* m = private_module_t* m =
reinterpret_cast<private_module_t*>(dev->common.module); reinterpret_cast<private_module_t*>(dev->common.module);
if (hnd && hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) {
if (hnd->flags & private_handle_t::PRIV_FLAGS_FRAMEBUFFER) { m->info.activate = FB_ACTIVATE_VBL | FB_ACTIVATE_FORCE;
genlock_lock_buffer(hnd, GENLOCK_READ_LOCK, GENLOCK_MAX_TIMEOUT); m->info.yoffset = hnd->offset / m->finfo.line_length;
if (m->currentBuffer) {
genlock_unlock_buffer(m->currentBuffer);
m->currentBuffer = 0;
}
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) { if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
ALOGE("FBIOPUT_VSCREENINFO failed"); ALOGE("%s: FBIOPUT_VSCREENINFO failed for external, err: %s", __FUNCTION__,
genlock_unlock_buffer(hnd); strerror(errno));
return -errno; return -errno;
} }
//Signals the composition thread to unblock and loop over if necessary
pthread_mutex_lock(&m->fbPanLock);
m->fbPanDone = true;
pthread_cond_signal(&m->fbPanCond);
pthread_mutex_unlock(&m->fbPanLock);
CALC_FPS();
m->currentBuffer = hnd;
} }
return 0; return 0;
} }
@@ -387,7 +358,9 @@ static int fb_close(struct hw_device_t *dev)
{ {
fb_context_t* ctx = (fb_context_t*)dev; fb_context_t* ctx = (fb_context_t*)dev;
if (ctx) { if (ctx) {
free(ctx); //Hack until fbdev is removed. Framework could close this causing hwc a
//pain.
//free(ctx);
} }
return 0; return 0;
} }

View File

@@ -14,10 +14,7 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
LOCAL_SRC_FILES := hwc.cpp \ LOCAL_SRC_FILES := hwc.cpp \
hwc_video.cpp \ hwc_video.cpp \
hwc_utils.cpp \ hwc_utils.cpp \
hwc_uimirror.cpp \
hwc_uevents.cpp \ hwc_uevents.cpp \
hwc_copybit.cpp \
hwc_mdpcomp.cpp \ hwc_mdpcomp.cpp \
hwc_extonly.cpp
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)

View File

@@ -26,13 +26,9 @@
#include <fb_priv.h> #include <fb_priv.h>
#include <mdp_version.h> #include <mdp_version.h>
#include "hwc_utils.h" #include "hwc_utils.h"
#include "hwc_qbuf.h"
#include "hwc_video.h" #include "hwc_video.h"
#include "hwc_uimirror.h"
#include "hwc_copybit.h"
#include "external.h" #include "external.h"
#include "hwc_mdpcomp.h" #include "hwc_mdpcomp.h"
#include "hwc_extonly.h"
using namespace qhwc; using namespace qhwc;
@@ -76,56 +72,66 @@ static void hwc_registerProcs(struct hwc_composer_device_1* dev,
} }
//Helper //Helper
static void reset() { static void reset(hwc_context_t *ctx, int numDisplays) {
//reset for this draw round memset(ctx->listStats, 0, sizeof(ctx->listStats));
VideoOverlay::reset(); for(int i = 0; i < numDisplays; i++){
ExtOnly::reset(); ctx->listStats[i].yuvIndex = -1;
UIMirrorOverlay::reset(); }
ExtOnly::reset(); }
//TODO MDPComp
static int hwc_prepare_primary(hwc_composer_device_1 *dev,
hwc_display_contents_1_t *list) {
hwc_context_t* ctx = (hwc_context_t*)(dev);
if (LIKELY(list && list->numHwLayers)) {
setListStats(ctx, list, HWC_DISPLAY_PRIMARY);
if(VideoOverlay::prepare(ctx, list, HWC_DISPLAY_PRIMARY)) {
ctx->overlayInUse = true;
} else if(MDPComp::configure(ctx, list)) {
ctx->overlayInUse = true;
} else {
ctx->overlayInUse = false;
}
}
return 0;
}
static int hwc_prepare_external(hwc_composer_device_1 *dev,
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
}
return 0;
} }
static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays, static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays,
hwc_display_contents_1_t** displays) hwc_display_contents_1_t** displays)
{ {
int ret = 0;
hwc_context_t* ctx = (hwc_context_t*)(dev); hwc_context_t* ctx = (hwc_context_t*)(dev);
ctx->overlayInUse = false; ctx->overlayInUse = false;
reset(); reset(ctx, numDisplays);
//If securing of h/w in progress skip comp using overlay. //If securing of h/w in progress skip comp using overlay.
if(ctx->mSecuring == true) return 0; if(ctx->mSecuring == true) return 0;
for (uint32_t i = 0; i < numDisplays; i++) { for (uint32_t i = 0; i < numDisplays; i++) {
hwc_display_contents_1_t *list = displays[i]; hwc_display_contents_1_t *list = displays[i];
//XXX: Actually handle the multiple displays switch(i) {
if (LIKELY(list && list->numHwLayers)) { case HWC_DISPLAY_PRIMARY:
ctx->dpys[i] = list->dpy; ret = hwc_prepare_primary(dev, list);
break;
if(ctx->isPoweredDown) case HWC_DISPLAY_EXTERNAL:
ALOGW("SF called %s after a POWERDOWN", __FUNCTION__); ret = hwc_prepare_external(dev, list);
break;
getLayerStats(ctx, list); default:
if(VideoOverlay::prepare(ctx, list)) { ret = -EINVAL;
ctx->overlayInUse = true;
//Nothing here
} else if(ExtOnly::prepare(ctx, list)) {
ctx->overlayInUse = true;
} else if(UIMirrorOverlay::prepare(ctx, list)) {
ctx->overlayInUse = true;
} else if(MDPComp::configure(dev, list)) {
ctx->overlayInUse = true;
} else if (0) {
//Other features
ctx->overlayInUse = true;
} else { // Else set this flag to false, otherwise video cases
// fail in non-overlay targets.
ctx->overlayInUse = false;
}
} }
} }
return ret;
return 0;
} }
static int hwc_eventControl(struct hwc_composer_device_1* dev, int dpy, static int hwc_eventControl(struct hwc_composer_device_1* dev, int dpy,
@@ -135,16 +141,15 @@ static int hwc_eventControl(struct hwc_composer_device_1* dev, int dpy,
hwc_context_t* ctx = (hwc_context_t*)(dev); hwc_context_t* ctx = (hwc_context_t*)(dev);
private_module_t* m = reinterpret_cast<private_module_t*>( private_module_t* m = reinterpret_cast<private_module_t*>(
ctx->mFbDev->common.module); ctx->mFbDev->common.module);
//XXX: Handle dpy
switch(event) { switch(event) {
case HWC_EVENT_VSYNC: case HWC_EVENT_VSYNC:
if(ioctl(m->framebuffer->fd, MSMFB_OVERLAY_VSYNC_CTRL, &enabled) < 0) if(ioctl(ctx->dpyAttr[dpy].fd, MSMFB_OVERLAY_VSYNC_CTRL,
&enabled) < 0) {
ALOGE("%s: vsync control failed. Dpy=%d, enabled=%d : %s",
__FUNCTION__, dpy, enabled, strerror(errno));
ret = -errno; ret = -errno;
if(ctx->mExtDisplay->getExternalDisplay()) {
ret = ctx->mExtDisplay->enableHDMIVsync(enabled);
} }
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
} }
@@ -153,23 +158,37 @@ static int hwc_eventControl(struct hwc_composer_device_1* dev, int dpy,
static int hwc_blank(struct hwc_composer_device_1* dev, int dpy, int blank) static int hwc_blank(struct hwc_composer_device_1* dev, int dpy, int blank)
{ {
//XXX: Handle based on dpy
hwc_context_t* ctx = (hwc_context_t*)(dev); hwc_context_t* ctx = (hwc_context_t*)(dev);
private_module_t* m = reinterpret_cast<private_module_t*>( private_module_t* m = reinterpret_cast<private_module_t*>(
ctx->mFbDev->common.module); ctx->mFbDev->common.module);
if(blank) { int ret = 0;
ctx->mOverlay->setState(ovutils::OV_CLOSED); ALOGD("%s: Doing Dpy=%d, blank=%d", __FUNCTION__, dpy, blank);
ctx->qbuf->unlockAllPrevious(); switch(dpy) {
ALOGD("HWC Calling POWERDOWN ..."); case HWC_DISPLAY_PRIMARY:
ioctl(m->framebuffer->fd, FBIOBLANK, FB_BLANK_POWERDOWN); if(blank) {
ALOGD("HWC Done POWERDOWN ..."); ctx->mOverlay->setState(ovutils::OV_CLOSED);
ctx->isPoweredDown = true; ret = ioctl(m->framebuffer->fd, FBIOBLANK, FB_BLANK_POWERDOWN);
} else { } else {
ALOGD("HWC Calling UNBLANK ..."); ret = ioctl(m->framebuffer->fd, FBIOBLANK, FB_BLANK_UNBLANK);
ioctl(m->framebuffer->fd, FBIOBLANK, FB_BLANK_UNBLANK); }
ALOGD("HWC Done UNBLANK ..."); break;
ctx->isPoweredDown = false; case HWC_DISPLAY_EXTERNAL:
if(blank) {
//TODO actual
} else {
}
break;
default:
return -EINVAL;
} }
if(ret < 0) {
ALOGE("%s: failed. Dpy=%d, blank=%d : %s",
__FUNCTION__, dpy, blank, strerror(errno));
return ret;
}
ALOGD("%s: Done Dpy=%d, blank=%d", __FUNCTION__, dpy, blank);
ctx->dpyAttr[dpy].isActive = !blank;
return 0; return 0;
} }
@@ -179,16 +198,23 @@ static int hwc_query(struct hwc_composer_device_1* dev,
hwc_context_t* ctx = (hwc_context_t*)(dev); hwc_context_t* ctx = (hwc_context_t*)(dev);
private_module_t* m = reinterpret_cast<private_module_t*>( private_module_t* m = reinterpret_cast<private_module_t*>(
ctx->mFbDev->common.module); ctx->mFbDev->common.module);
int supported = HWC_DISPLAY_PRIMARY_BIT;
switch (param) { switch (param) {
case HWC_BACKGROUND_LAYER_SUPPORTED: case HWC_BACKGROUND_LAYER_SUPPORTED:
// Not supported for now // Not supported for now
value[0] = 0; value[0] = 0;
break; break;
case HWC_VSYNC_PERIOD: case HWC_VSYNC_PERIOD: //Not used for hwc > 1.1
value[0] = m->fps; value[0] = m->fps;
ALOGI("fps: %d", value[0]); ALOGI("fps: %d", value[0]);
break; break;
case HWC_DISPLAY_TYPES_SUPPORTED:
//Enable later
//if(ctx->mMDP.hasOverlay)
//supported |= HWC_DISPLAY_EXTERNAL_BIT;
value[0] = supported;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@@ -196,45 +222,122 @@ static int hwc_query(struct hwc_composer_device_1* dev,
} }
static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
if (LIKELY(list && list->numHwLayers)) {
VideoOverlay::draw(ctx, list, HWC_DISPLAY_PRIMARY);
MDPComp::draw(ctx, list);
hwc_sync(ctx, list, HWC_DISPLAY_PRIMARY);
//TODO We dont check for SKIP flag on this layer because we need PAN
//always. Last layer is always FB
uint32_t last = list->numHwLayers - 1;
if(list->hwLayers[last].compositionType == HWC_FRAMEBUFFER_TARGET) {
ctx->mFbDev->post(ctx->mFbDev, list->hwLayers[last].handle);
}
}
return 0;
}
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);
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);
}
}
return 0;
}
static int hwc_set(hwc_composer_device_1 *dev, static int hwc_set(hwc_composer_device_1 *dev,
size_t numDisplays, size_t numDisplays,
hwc_display_contents_1_t** displays) hwc_display_contents_1_t** displays)
{ {
int ret = 0; int ret = 0;
hwc_context_t* ctx = (hwc_context_t*)(dev); hwc_context_t* ctx = (hwc_context_t*)(dev);
for (uint32_t i = 0; i <numDisplays; i++) { for (uint32_t i = 0; i < numDisplays; i++) {
hwc_display_contents_1_t* list = displays[i]; hwc_display_contents_1_t* list = displays[i];
//XXX: Actually handle the multiple displays switch(i) {
if (LIKELY(list)) { case HWC_DISPLAY_PRIMARY:
VideoOverlay::draw(ctx, list); ret = hwc_set_primary(ctx, list);
ExtOnly::draw(ctx, list); case HWC_DISPLAY_EXTERNAL:
MDPComp::draw(ctx, list); ret = hwc_set_external(ctx, list);
default:
//Sync TODO better error handling. ret = -EINVAL;
hwc_sync(list);
EGLBoolean success = eglSwapBuffers((EGLDisplay)list->dpy,
(EGLSurface)list->sur);
wait4fbPost(ctx);
//Can draw to HDMI only when fb_post is reached
UIMirrorOverlay::draw(ctx);
//HDMI commit and primary commit (PAN) happening in parallel
if(ctx->mExtDisplay->getExternalDisplay())
ctx->mExtDisplay->commit();
//Virtual barrier for threads to finish
wait4Pan(ctx);
} else {
ctx->mOverlay->setState(ovutils::OV_CLOSED);
ctx->qbuf->unlockAll();
} }
if(!ctx->overlayInUse)
ctx->mOverlay->setState(ovutils::OV_CLOSED);
} }
ctx->qbuf->unlockAllPrevious(); if(!ctx->overlayInUse)
ctx->mOverlay->setState(ovutils::OV_CLOSED);
return ret; return ret;
} }
int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp,
uint32_t* configs, size_t* numConfigs) {
int ret = 0;
//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;
break;
case HWC_DISPLAY_EXTERNAL:
//Hack until hotplug is supported.
//This makes framework ignore external display.
ret = -1;
break;
}
return ret;
}
int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp,
uint32_t config, const uint32_t* attributes, int32_t* values) {
hwc_context_t* ctx = (hwc_context_t*)(dev);
//From HWComposer
static const uint32_t DISPLAY_ATTRIBUTES[] = {
HWC_DISPLAY_VSYNC_PERIOD,
HWC_DISPLAY_WIDTH,
HWC_DISPLAY_HEIGHT,
HWC_DISPLAY_DPI_X,
HWC_DISPLAY_DPI_Y,
HWC_DISPLAY_NO_ATTRIBUTE,
};
const int NUM_DISPLAY_ATTRIBUTES = (sizeof(DISPLAY_ATTRIBUTES) /
sizeof(DISPLAY_ATTRIBUTES)[0]);
for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) {
switch (attributes[i]) {
case HWC_DISPLAY_VSYNC_PERIOD:
values[i] = ctx->dpyAttr[disp].vsync_period;
break;
case HWC_DISPLAY_WIDTH:
values[i] = ctx->dpyAttr[disp].xres;
ALOGD("%s width = %d",__FUNCTION__, ctx->dpyAttr[disp].xres);
break;
case HWC_DISPLAY_HEIGHT:
values[i] = ctx->dpyAttr[disp].yres;
ALOGD("%s height = %d",__FUNCTION__, ctx->dpyAttr[disp].yres);
break;
case HWC_DISPLAY_DPI_X:
values[i] = ctx->dpyAttr[disp].xdpi;
break;
case HWC_DISPLAY_DPI_Y:
values[i] = ctx->dpyAttr[disp].ydpi;
break;
default:
ALOGE("Unknown display attribute %d",
attributes[i]);
return -EINVAL;
}
}
return 0;
}
static int hwc_device_close(struct hw_device_t *dev) static int hwc_device_close(struct hw_device_t *dev)
{ {
if(!dev) { if(!dev) {
@@ -261,17 +364,20 @@ static int hwc_device_open(const struct hw_module_t* module, const char* name,
initContext(dev); initContext(dev);
//Setup HWC methods //Setup HWC methods
dev->device.common.tag = HARDWARE_DEVICE_TAG; dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = HWC_DEVICE_API_VERSION_1_0; dev->device.common.version = HWC_DEVICE_API_VERSION_1_1;
dev->device.common.module = const_cast<hw_module_t*>(module); dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = hwc_device_close; dev->device.common.close = hwc_device_close;
dev->device.prepare = hwc_prepare; dev->device.prepare = hwc_prepare;
dev->device.set = hwc_set; dev->device.set = hwc_set;
dev->device.eventControl = hwc_eventControl; dev->device.eventControl = hwc_eventControl;
dev->device.blank = hwc_blank; dev->device.blank = hwc_blank;
dev->device.query = hwc_query; dev->device.query = hwc_query;
dev->device.registerProcs = hwc_registerProcs; dev->device.registerProcs = hwc_registerProcs;
*device = &dev->device.common; dev->device.dump = NULL;
dev->device.getDisplayConfigs = hwc_getDisplayConfigs;
dev->device.getDisplayAttributes = hwc_getDisplayAttributes;
*device = &dev->device.common;
status = 0; status = 0;
} }
return status; return status;

View File

@@ -17,7 +17,6 @@
#include "hwc_extonly.h" #include "hwc_extonly.h"
#include "external.h" #include "external.h"
#include "hwc_qbuf.h"
namespace qhwc { namespace qhwc {
@@ -130,8 +129,6 @@ bool ExtOnly::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list)
private_handle_t *hnd = (private_handle_t *) private_handle_t *hnd = (private_handle_t *)
list->hwLayers[sExtIndex].handle; list->hwLayers[sExtIndex].handle;
// Lock this buffer for read.
ctx->qbuf->lockAndAdd(hnd);
bool ret = true; bool ret = true;
overlay::Overlay& ov = *(ctx->mOverlay); overlay::Overlay& ov = *(ctx->mOverlay);
ovutils::eOverlayState state = ov.getState(); ovutils::eOverlayState state = ov.getState();

View File

@@ -17,7 +17,6 @@
*/ */
#include "hwc_mdpcomp.h" #include "hwc_mdpcomp.h"
#include "hwc_qbuf.h"
#include "external.h" #include "external.h"
#define SUPPORT_4LAYER 0 #define SUPPORT_4LAYER 0
@@ -332,23 +331,16 @@ int MDPComp::prepare(hwc_context_t *ctx, hwc_layer_1_t *layer,
* 5. Overlay in use * 5. Overlay in use
*/ */
bool MDPComp::is_doable(hwc_composer_device_1_t *dev, bool MDPComp::is_doable(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
hwc_display_contents_1_t* list) {
hwc_context_t* ctx = (hwc_context_t*)(dev);
if(!ctx) {
ALOGE("%s: hwc context is NULL", __FUNCTION__);
return false;
}
//Number of layers //Number of layers
if(list->numHwLayers < 1 || list->numHwLayers > (uint32_t)sMaxLayers) { int numAppLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
if(numAppLayers < 1 || numAppLayers > (uint32_t)sMaxLayers) {
ALOGD_IF(isDebug(), "%s: Unsupported number of layers",__FUNCTION__); ALOGD_IF(isDebug(), "%s: Unsupported number of layers",__FUNCTION__);
return false; return false;
} }
//Disable MDPComp when ext display connected //Disable MDPComp when ext display connected
if(ctx->mExtDisplay->getExternalDisplay()) { if(isExternalActive(ctx)) {
ALOGD_IF(isDebug(), "%s: External display connected.", __FUNCTION__); ALOGD_IF(isDebug(), "%s: External display connected.", __FUNCTION__);
return false; return false;
} }
@@ -360,7 +352,7 @@ bool MDPComp::is_doable(hwc_composer_device_1_t *dev,
} }
//MDP composition is not efficient if rotation is needed. //MDP composition is not efficient if rotation is needed.
for(unsigned int i = 0; i < list->numHwLayers; ++i) { for(int i = 0; i < numAppLayers; ++i) {
if(list->hwLayers[i].transform) { if(list->hwLayers[i].transform) {
ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__); ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__);
return false; return false;
@@ -410,10 +402,11 @@ void MDPComp::get_layer_info(hwc_layer_1_t* layer, int& flags) {
} }
} }
int MDPComp::mark_layers(hwc_display_contents_1_t* list, layer_mdp_info* layer_info, int MDPComp::mark_layers(hwc_context_t *ctx,
frame_info& current_frame) { hwc_display_contents_1_t* list, layer_mdp_info* layer_info,
frame_info& current_frame) {
int layer_count = list->numHwLayers; int layer_count = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
if(layer_count > sMaxLayers) { if(layer_count > sMaxLayers) {
if(!sPipeMgr.req_for_pipe(PIPE_REQ_FB)) { if(!sPipeMgr.req_for_pipe(PIPE_REQ_FB)) {
@@ -476,10 +469,11 @@ void MDPComp::reset_layer_mdp_info(layer_mdp_info* layer_info, int count) {
} }
} }
bool MDPComp::alloc_layer_pipes(hwc_display_contents_1_t* list, bool MDPComp::alloc_layer_pipes(hwc_context_t *ctx,
layer_mdp_info* layer_info, frame_info& current_frame) { hwc_display_contents_1_t* list,
layer_mdp_info* layer_info, frame_info& current_frame) {
int layer_count = list->numHwLayers; int layer_count = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
int mdp_count = current_frame.count; int mdp_count = current_frame.count;
int fallback_count = layer_count - mdp_count; int fallback_count = layer_count - mdp_count;
int frame_pipe_count = 0; int frame_pipe_count = 0;
@@ -518,10 +512,10 @@ bool MDPComp::alloc_layer_pipes(hwc_display_contents_1_t* list,
} }
//returns array of layers and their allocated pipes //returns array of layers and their allocated pipes
bool MDPComp::parse_and_allocate(hwc_context_t* ctx, hwc_display_contents_1_t* list, bool MDPComp::parse_and_allocate(hwc_context_t* ctx,
frame_info& current_frame ) { hwc_display_contents_1_t* list, frame_info& current_frame ) {
int layer_count = list->numHwLayers; int layer_count = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
/* clear pipe status */ /* clear pipe status */
sPipeMgr.reset(); sPipeMgr.reset();
@@ -532,7 +526,7 @@ bool MDPComp::parse_and_allocate(hwc_context_t* ctx, hwc_display_contents_1_t* l
reset_layer_mdp_info(bp_layer_info, layer_count); reset_layer_mdp_info(bp_layer_info, layer_count);
/* iterate through layer list to mark candidate */ /* iterate through layer list to mark candidate */
if(mark_layers(list, bp_layer_info, current_frame) == MDPCOMP_ABORT) { if(mark_layers(ctx, list, bp_layer_info, current_frame) == MDPCOMP_ABORT) {
free(bp_layer_info); free(bp_layer_info);
current_frame.count = 0; current_frame.count = 0;
ALOGE_IF(isDebug(), "%s:mark_layers failed!!", __FUNCTION__); ALOGE_IF(isDebug(), "%s:mark_layers failed!!", __FUNCTION__);
@@ -542,7 +536,7 @@ bool MDPComp::parse_and_allocate(hwc_context_t* ctx, hwc_display_contents_1_t* l
malloc(sizeof(pipe_layer_pair) * current_frame.count); malloc(sizeof(pipe_layer_pair) * current_frame.count);
/* allocate MDP pipes for marked layers */ /* allocate MDP pipes for marked layers */
alloc_layer_pipes( list, bp_layer_info, current_frame); alloc_layer_pipes(ctx, list, bp_layer_info, current_frame);
free(bp_layer_info); free(bp_layer_info);
return true; return true;
@@ -586,7 +580,7 @@ int MDPComp::configure_var_pipe(hwc_context_t* ctx) {
bool MDPComp::setup(hwc_context_t* ctx, hwc_display_contents_1_t* list) { bool MDPComp::setup(hwc_context_t* ctx, hwc_display_contents_1_t* list) {
int nPipeIndex, vsync_wait, isFG; int nPipeIndex, vsync_wait, isFG;
int numHwLayers = list->numHwLayers; int numHwLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
frame_info &current_frame = sCurrentFrame; frame_info &current_frame = sCurrentFrame;
current_frame.count = 0; current_frame.count = 0;
@@ -649,9 +643,6 @@ bool MDPComp::setup(hwc_context_t* ctx, hwc_display_contents_1_t* list) {
void MDPComp::unsetMDPCompLayerFlags(hwc_context_t* ctx, hwc_display_contents_1_t* list) void MDPComp::unsetMDPCompLayerFlags(hwc_context_t* ctx, hwc_display_contents_1_t* list)
{ {
if (!list)
return;
for (int index = 0 ; index < sCurrentFrame.count; index++) { for (int index = 0 ; index < sCurrentFrame.count; index++) {
int l_index = sCurrentFrame.pipe_layer[index].layer_index; int l_index = sCurrentFrame.pipe_layer[index].layer_index;
if(list->hwLayers[l_index].flags & HWC_MDPCOMP) { if(list->hwLayers[l_index].flags & HWC_MDPCOMP) {
@@ -678,7 +669,8 @@ int MDPComp::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
overlay::Overlay& ov = *(ctx->mOverlay); overlay::Overlay& ov = *(ctx->mOverlay);
for(unsigned int i = 0; i < list->numHwLayers; i++ ) int numHwLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
for(int i = 0; i < numHwLayers; i++ )
{ {
hwc_layer_1_t *layer = &list->hwLayers[i]; hwc_layer_1_t *layer = &list->hwLayers[i];
@@ -719,10 +711,6 @@ int MDPComp::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
return -1; return -1;
} }
//lock buffer before queue
//XXX: Handle lock failure
ctx->qbuf->lockAndAdd(hnd);
ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \ ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
using pipe: %d", __FUNCTION__, layer, using pipe: %d", __FUNCTION__, layer,
hnd, index ); hnd, index );
@@ -793,17 +781,15 @@ bool MDPComp::init(hwc_context_t *dev) {
return true; return true;
} }
bool MDPComp::configure(hwc_composer_device_1_t *dev, hwc_display_contents_1_t* list) { bool MDPComp::configure(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
if(!isEnabled()) { if(!isEnabled()) {
ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__); ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
return false; return false;
} }
hwc_context_t* ctx = (hwc_context_t*)(dev);
bool isMDPCompUsed = true; bool isMDPCompUsed = true;
bool doable = is_doable(dev, list); bool doable = is_doable(ctx, list);
if(doable) { if(doable) {
if(setup(ctx, list)) { if(setup(ctx, list)) {

View File

@@ -154,7 +154,7 @@ public:
static bool deinit(); static bool deinit();
/*sets up mdp comp for the current frame */ /*sets up mdp comp for the current frame */
static bool configure(hwc_composer_device_1_t *ctx, hwc_display_contents_1_t* list); static bool configure(hwc_context_t *ctx, hwc_display_contents_1_t* list);
/* draw */ /* draw */
static int draw(hwc_context_t *ctx, hwc_display_contents_1_t *list); static int draw(hwc_context_t *ctx, hwc_display_contents_1_t *list);
@@ -180,8 +180,7 @@ private:
mdp_pipe_info& mdp_info); mdp_pipe_info& mdp_info);
/* checks for conditions where mdpcomp is not possible */ /* checks for conditions where mdpcomp is not possible */
static bool is_doable(hwc_composer_device_1_t *dev, static bool is_doable(hwc_context_t *ctx, hwc_display_contents_1_t* list);
hwc_display_contents_1_t* list);
static bool setup(hwc_context_t* ctx, hwc_display_contents_1_t* list); static bool setup(hwc_context_t* ctx, hwc_display_contents_1_t* list);
@@ -189,8 +188,9 @@ private:
static void get_layer_info(hwc_layer_1_t* layer, int& flags); static void get_layer_info(hwc_layer_1_t* layer, int& flags);
/* iterates through layer list to choose candidate to use overlay */ /* iterates through layer list to choose candidate to use overlay */
static int mark_layers(hwc_display_contents_1_t* list, layer_mdp_info* layer_info, static int mark_layers(hwc_context_t *ctx, hwc_display_contents_1_t* list,
frame_info& current_frame); layer_mdp_info* layer_info, frame_info& current_frame);
static bool parse_and_allocate(hwc_context_t* ctx, hwc_display_contents_1_t* list, static bool parse_and_allocate(hwc_context_t* ctx, hwc_display_contents_1_t* list,
frame_info& current_frame ); frame_info& current_frame );
@@ -198,9 +198,10 @@ private:
static void reset_layer_mdp_info(layer_mdp_info* layer_mdp_info,int count); static void reset_layer_mdp_info(layer_mdp_info* layer_mdp_info,int count);
/* allocates pipes to selected candidates */ /* allocates pipes to selected candidates */
static bool alloc_layer_pipes(hwc_display_contents_1_t* list, static bool alloc_layer_pipes(hwc_context_t *ctx,
layer_mdp_info* layer_info, hwc_display_contents_1_t* list,
frame_info& current_frame); layer_mdp_info* layer_info,
frame_info& current_frame);
/* updates variable pipe mode for the current frame */ /* updates variable pipe mode for the current frame */
static int configure_var_pipe(hwc_context_t* ctx); static int configure_var_pipe(hwc_context_t* ctx);

View File

@@ -38,26 +38,30 @@ static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
char* hdmi; char* hdmi;
int64_t timestamp = 0; int64_t timestamp = 0;
const char *str = udata; const char *str = udata;
int hdmiconnected = ctx->mExtDisplay->getExternalDisplay(); int display = HWC_DISPLAY_PRIMARY;
if(!strcasestr(str, "@/devices/virtual/graphics/fb")) { if(!strcasestr(str, "@/devices/virtual/graphics/fb")) {
ALOGD_IF(UEVENT_DEBUG, "%s: Not Ext Disp Event ", __FUNCTION__); ALOGD_IF(UEVENT_DEBUG, "%s: Not Ext Disp Event ", __FUNCTION__);
return; return;
} }
if(hdmiconnected) //Check if its primary vsync
vsync = !strncmp(str, MSMFB_DEVICE_FB0, strlen(MSMFB_DEVICE_FB0));
//If not primary vsync, see if its an external vsync
if(isExternalActive(ctx) && !vsync) {
vsync = !strncmp(str, MSMFB_DEVICE_FB1, strlen(MSMFB_DEVICE_FB1)); vsync = !strncmp(str, MSMFB_DEVICE_FB1, strlen(MSMFB_DEVICE_FB1));
else display = HWC_DISPLAY_EXTERNAL;
vsync = !strncmp(str, MSMFB_DEVICE_FB0, strlen(MSMFB_DEVICE_FB0)); }
hdmi = strcasestr(str, MSMFB_HDMI_NODE); hdmi = strcasestr(str, MSMFB_HDMI_NODE);
if(vsync) { if(vsync) {
str += strlen(str) + 1; str += strlen(str) + 1;
while(*str) { while(*str) {
if (!strncmp(str, "VSYNC=", strlen("VSYNC="))) { if (!strncmp(str, "VSYNC=", strlen("VSYNC="))) {
timestamp = strtoull(str + strlen("VSYNC="), NULL, 0); timestamp = strtoull(str + strlen("VSYNC="), NULL, 0);
//XXX: Handle vsync from multiple displays //XXX: Handle vsync from multiple displays
ctx->proc->vsync(ctx->proc, (int)ctx->dpys[0], timestamp); ctx->proc->vsync(ctx->proc, display, timestamp);
} }
str += strlen(str) + 1; str += strlen(str) + 1;
if(str - udata >= len) if(str - udata >= len)

View File

@@ -60,25 +60,25 @@ void UIMirrorOverlay::reset() {
} }
//Prepare the overlay for the UI mirroring //Prepare the overlay for the UI mirroring
bool UIMirrorOverlay::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list) { bool UIMirrorOverlay::prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer) {
sState = ovutils::OV_CLOSED; sState = ovutils::OV_CLOSED;
sIsUiMirroringOn = false; sIsUiMirroringOn = false;
if(!ctx->mMDP.hasOverlay) { if(!ctx->mMDP.hasOverlay) {
ALOGD_IF(HWC_UI_MIRROR, "%s, this hw doesnt support mirroring", ALOGD_IF(HWC_UI_MIRROR, "%s, this hw doesnt support mirroring",
__FUNCTION__); __FUNCTION__);
return false; return false;
} }
// If external display is connected // If external display is active
if(ctx->mExtDisplay->getExternalDisplay()) { if(isExternalActive(ctx)) {
sState = ovutils::OV_UI_MIRROR; sState = ovutils::OV_UI_MIRROR;
configure(ctx, list); configure(ctx, fblayer);
} }
return sIsUiMirroringOn; return sIsUiMirroringOn;
} }
// Configure // Configure
bool UIMirrorOverlay::configure(hwc_context_t *ctx, hwc_display_contents_1_t *list) bool UIMirrorOverlay::configure(hwc_context_t *ctx, hwc_layer_1_t *layer)
{ {
if (LIKELY(ctx->mOverlay)) { if (LIKELY(ctx->mOverlay)) {
overlay::Overlay& ov = *(ctx->mOverlay); overlay::Overlay& ov = *(ctx->mOverlay);
@@ -86,14 +86,8 @@ bool UIMirrorOverlay::configure(hwc_context_t *ctx, hwc_display_contents_1_t *li
ov.setState(sState); ov.setState(sState);
framebuffer_device_t *fbDev = ctx->mFbDev; framebuffer_device_t *fbDev = ctx->mFbDev;
if(fbDev) { if(fbDev) {
private_module_t* m = reinterpret_cast<private_module_t*>( private_handle_t *hnd = (private_handle_t *)layer->handle;
fbDev->common.module); ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
int alignedW = ALIGN_TO(m->info.xres, 32);
private_handle_t const* hnd =
reinterpret_cast<private_handle_t const*>(m->framebuffer);
unsigned int size = hnd->size/m->numBuffers;
ovutils::Whf info(alignedW, hnd->height, hnd->format, size);
// Determine the RGB pipe for UI depending on the state // Determine the RGB pipe for UI depending on the state
ovutils::eDest dest = ovutils::OV_PIPE_ALL; ovutils::eDest dest = ovutils::OV_PIPE_ALL;
if (sState == ovutils::OV_2D_TRUE_UI_MIRROR) { if (sState == ovutils::OV_2D_TRUE_UI_MIRROR) {
@@ -118,21 +112,26 @@ bool UIMirrorOverlay::configure(hwc_context_t *ctx, hwc_display_contents_1_t *li
ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg }; ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
ov.setSource(pargs, dest); ov.setSource(pargs, dest);
hwc_rect_t sourceCrop = layer->sourceCrop;
// x,y,w,h // x,y,w,h
ovutils::Dim dcrop(0, 0, m->info.xres, m->info.yres); 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 //Get the current orientation on primary panel
int transform = getDeviceOrientation(); int transform = getDeviceOrientation();
ovutils::eTransform orient = ovutils::eTransform orient =
static_cast<ovutils::eTransform>(transform); static_cast<ovutils::eTransform>(transform);
ov.setTransform(orient, dest); ov.setTransform(orient, dest);
ovutils::Dim dim; hwc_rect_t displayFrame = layer->displayFrame;
dim.x = 0; ovutils::Dim dpos(displayFrame.left,
dim.y = 0; displayFrame.top,
dim.w = m->info.xres; displayFrame.right - displayFrame.left,
dim.h = m->info.yres; displayFrame.bottom - displayFrame.top);
ov.setPosition(dim, dest); ov.setPosition(dpos, dest);
if (!ov.commit(dest)) { if (!ov.commit(dest)) {
ALOGE("%s: commit fails", __FUNCTION__); ALOGE("%s: commit fails", __FUNCTION__);
return false; return false;
@@ -143,7 +142,7 @@ bool UIMirrorOverlay::configure(hwc_context_t *ctx, hwc_display_contents_1_t *li
return sIsUiMirroringOn; return sIsUiMirroringOn;
} }
bool UIMirrorOverlay::draw(hwc_context_t *ctx) bool UIMirrorOverlay::draw(hwc_context_t *ctx, hwc_layer_1_t *layer)
{ {
if(!sIsUiMirroringOn) { if(!sIsUiMirroringOn) {
return true; return true;
@@ -156,17 +155,21 @@ bool UIMirrorOverlay::draw(hwc_context_t *ctx)
if(fbDev) { if(fbDev) {
private_module_t* m = reinterpret_cast<private_module_t*>( private_module_t* m = reinterpret_cast<private_module_t*>(
fbDev->common.module); fbDev->common.module);
private_handle_t *hnd = (private_handle_t *)layer->handle;
switch (state) { switch (state) {
case ovutils::OV_UI_MIRROR: case ovutils::OV_UI_MIRROR:
if (!ov.queueBuffer(m->framebuffer->fd, m->currentOffset, //TODO why is this primary fd
ovutils::OV_PIPE0)) { 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__); ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
ret = false; ret = false;
} }
break; break;
case ovutils::OV_2D_TRUE_UI_MIRROR: case ovutils::OV_2D_TRUE_UI_MIRROR:
if (!ov.queueBuffer(m->framebuffer->fd, m->currentOffset, if (!ov.queueBuffer(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd,
ovutils::OV_PIPE2)) { hnd->offset,
ovutils::OV_PIPE2)) {
ALOGE("%s: queueBuffer failed for external", __FUNCTION__); ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
ret = false; ret = false;
} }

View File

@@ -30,14 +30,14 @@ namespace qhwc {
class UIMirrorOverlay { class UIMirrorOverlay {
public: public:
// Sets up members and prepares overlay if conditions are met // Sets up members and prepares overlay if conditions are met
static bool prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list); static bool prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
// Draws layer if this feature is on // Draws layer if this feature is on
static bool draw(hwc_context_t *ctx); static bool draw(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
//Reset values //Reset values
static void reset(); static void reset();
private: private:
//Configures overlay //Configures overlay
static bool configure(hwc_context_t *ctx, hwc_display_contents_1_t *list); static bool configure(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
//The chosen overlay state. //The chosen overlay state.
static ovutils::eOverlayState sState; static ovutils::eOverlayState sState;
//Flags if this feature is on. //Flags if this feature is on.

View File

@@ -23,11 +23,8 @@
#include "hwc_utils.h" #include "hwc_utils.h"
#include "mdp_version.h" #include "mdp_version.h"
#include "hwc_video.h" #include "hwc_video.h"
#include "hwc_qbuf.h"
#include "hwc_copybit.h"
#include "external.h" #include "external.h"
#include "hwc_mdpcomp.h" #include "hwc_mdpcomp.h"
#include "hwc_extonly.h"
#include "QService.h" #include "QService.h"
namespace qhwc { namespace qhwc {
@@ -38,6 +35,16 @@ static void openFramebufferDevice(hwc_context_t *ctx)
hw_module_t const *module; hw_module_t const *module;
if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) { if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
framebuffer_open(module, &(ctx->mFbDev)); framebuffer_open(module, &(ctx->mFbDev));
private_module_t* m = reinterpret_cast<private_module_t*>(
ctx->mFbDev->common.module);
//xres, yres may not be 32 aligned
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres = m->info.xres;
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres = m->info.yres;
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = ctx->mFbDev->xdpi;
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ctx->mFbDev->ydpi;
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period =
1000000000l / ctx->mFbDev->fps;
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = openFb(HWC_DISPLAY_PRIMARY);
} }
} }
@@ -46,12 +53,10 @@ void initContext(hwc_context_t *ctx)
openFramebufferDevice(ctx); openFramebufferDevice(ctx);
ctx->mOverlay = overlay::Overlay::getInstance(); ctx->mOverlay = overlay::Overlay::getInstance();
ctx->mQService = qService::QService::getInstance(ctx); ctx->mQService = qService::QService::getInstance(ctx);
ctx->qbuf = new QueuedBufferStore();
ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion(); ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion();
ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay(); ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay();
ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType(); ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType();
ctx->mExtDisplay = new ExternalDisplay(ctx); ctx->mExtDisplay = new ExternalDisplay(ctx);
memset(ctx->dpys,(int)EGL_NO_DISPLAY, MAX_NUM_DISPLAYS);
MDPComp::init(ctx); MDPComp::init(ctx);
ALOGI("Initializing Qualcomm Hardware Composer"); ALOGI("Initializing Qualcomm Hardware Composer");
@@ -65,19 +70,11 @@ void closeContext(hwc_context_t *ctx)
ctx->mOverlay = NULL; ctx->mOverlay = NULL;
} }
if(ctx->mCopybitEngine) {
delete ctx->mCopybitEngine;
ctx->mCopybitEngine = NULL;
}
if(ctx->mFbDev) { if(ctx->mFbDev) {
framebuffer_close(ctx->mFbDev); framebuffer_close(ctx->mFbDev);
ctx->mFbDev = NULL; ctx->mFbDev = NULL;
} close(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd);
ctx->dpyAttr[HWC_DISPLAY_PRIMARY].fd = -1;
if(ctx->qbuf) {
delete ctx->qbuf;
ctx->qbuf = NULL;
} }
if(ctx->mExtDisplay) { if(ctx->mExtDisplay) {
@@ -101,56 +98,28 @@ void dumpLayer(hwc_layer_1_t const* l)
l->displayFrame.bottom); l->displayFrame.bottom);
} }
void getLayerStats(hwc_context_t *ctx, const hwc_display_contents_1_t *list) void setListStats(hwc_context_t *ctx,
{ const hwc_display_contents_1_t *list, int dpy) {
//Video specific stats
int yuvCount = 0; ctx->listStats[dpy].numAppLayers = list->numHwLayers - 1;
int yuvLayerIndex = -1; ctx->listStats[dpy].fbLayerIndex = list->numHwLayers - 1;
bool isYuvLayerSkip = false;
int skipCount = 0;
int ccLayerIndex = -1; //closed caption
int extLayerIndex = -1; //ext-only or block except closed caption
int extCount = 0; //ext-only except closed caption
bool isExtBlockPresent = false; //is BLOCK layer present
bool yuvSecure = false;
for (size_t i = 0; i < list->numHwLayers; i++) { for (size_t i = 0; i < list->numHwLayers; i++) {
private_handle_t *hnd = private_handle_t *hnd =
(private_handle_t *)list->hwLayers[i].handle; (private_handle_t *)list->hwLayers[i].handle;
if (UNLIKELY(isYuvBuffer(hnd))) { if(list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
yuvCount++; continue;
yuvLayerIndex = i; //We disregard FB being skip for now! so the else if
yuvSecure = isSecureBuffer(hnd);
//Animating
//Do not mark as SKIP if it is secure buffer
if (isSkipLayer(&list->hwLayers[i]) && !yuvSecure) {
isYuvLayerSkip = true;
skipCount++;
}
} else if(UNLIKELY(isExtCC(hnd))) {
ccLayerIndex = i;
} else if(UNLIKELY(isExtBlock(hnd))) {
extCount++;
extLayerIndex = i;
isExtBlockPresent = true;
} else if(UNLIKELY(isExtOnly(hnd))) {
extCount++;
//If BLOCK layer present, dont cache index, display BLOCK only.
if(isExtBlockPresent == false) extLayerIndex = i;
} else if (isSkipLayer(&list->hwLayers[i])) { } else if (isSkipLayer(&list->hwLayers[i])) {
skipCount++; ctx->listStats[dpy].skipCount++;
}
if (UNLIKELY(isYuvBuffer(hnd))) {
ctx->listStats[dpy].yuvCount++;
ctx->listStats[dpy].yuvIndex = i;
} }
} }
VideoOverlay::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip,
ccLayerIndex);
ExtOnly::setStats(extCount, extLayerIndex, isExtBlockPresent);
CopyBit::setStats(yuvCount, yuvLayerIndex, isYuvLayerSkip);
MDPComp::setStats(skipCount);
ctx->numHwLayers = list->numHwLayers;
return;
} }
//Crops source buffer against destination and FB boundaries //Crops source buffer against destination and FB boundaries
@@ -209,41 +178,15 @@ void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
} }
} }
void wait4fbPost(hwc_context_t* ctx) { bool isExternalActive(hwc_context_t* ctx) {
framebuffer_device_t *fbDev = ctx->mFbDev; return ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive;
if(fbDev) {
private_module_t* m = reinterpret_cast<private_module_t*>(
fbDev->common.module);
//wait for the fb_post to be called
pthread_mutex_lock(&m->fbPostLock);
while(m->fbPostDone == false) {
pthread_cond_wait(&(m->fbPostCond), &(m->fbPostLock));
}
m->fbPostDone = false;
pthread_mutex_unlock(&m->fbPostLock);
}
} }
void wait4Pan(hwc_context_t* ctx) { int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy) {
framebuffer_device_t *fbDev = ctx->mFbDev;
if(fbDev) {
private_module_t* m = reinterpret_cast<private_module_t*>(
fbDev->common.module);
//wait for the fb_post's PAN to finish
pthread_mutex_lock(&m->fbPanLock);
while(m->fbPanDone == false) {
pthread_cond_wait(&(m->fbPanCond), &(m->fbPanLock));
}
m->fbPanDone = false;
pthread_mutex_unlock(&m->fbPanLock);
}
}
int hwc_sync(hwc_display_contents_1_t* list) {
int ret = 0; int ret = 0;
#ifdef USE_FENCE_SYNC #ifdef USE_FENCE_SYNC
struct mdp_buf_sync data; struct mdp_buf_sync data;
int acquireFd[10]; int acquireFd[4];
int count = 0; int count = 0;
int releaseFd = -1; int releaseFd = -1;
int fbFd = -1; int fbFd = -1;
@@ -252,7 +195,8 @@ int hwc_sync(hwc_display_contents_1_t* list) {
data.rel_fen_fd = &releaseFd; data.rel_fen_fd = &releaseFd;
//Accumulate acquireFenceFds //Accumulate acquireFenceFds
for(uint32_t i = 0; i < list->numHwLayers; i++) { for(uint32_t i = 0; i < list->numHwLayers; i++) {
if(list->hwLayers[i].compositionType == HWC_OVERLAY && if((list->hwLayers[i].compositionType == HWC_OVERLAY ||
list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) &&
list->hwLayers[i].acquireFenceFd != -1) { list->hwLayers[i].acquireFenceFd != -1) {
acquireFd[count++] = list->hwLayers[i].acquireFenceFd; acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
} }
@@ -260,13 +204,7 @@ int hwc_sync(hwc_display_contents_1_t* list) {
if (count) { if (count) {
data.acq_fen_fd_cnt = count; data.acq_fen_fd_cnt = count;
fbFd = ctx->dpyAttr[dpy].fd;
//Open fb0 for ioctl
fbFd = open("/dev/graphics/fb0", O_RDWR);
if (fbFd < 0) {
ALOGE("%s: /dev/graphics/fb0 not available", __FUNCTION__);
return -1;
}
//Waits for acquire fences, returns a release fence //Waits for acquire fences, returns a release fence
ret = ioctl(fbFd, MSMFB_BUFFER_SYNC, &data); ret = ioctl(fbFd, MSMFB_BUFFER_SYNC, &data);
@@ -274,22 +212,20 @@ int hwc_sync(hwc_display_contents_1_t* list) {
ALOGE("ioctl MSMFB_BUFFER_SYNC failed, err=%s", ALOGE("ioctl MSMFB_BUFFER_SYNC failed, err=%s",
strerror(errno)); strerror(errno));
} }
close(fbFd);
for(uint32_t i = 0; i < list->numHwLayers; i++) { for(uint32_t i = 0; i < list->numHwLayers; i++) {
if(list->hwLayers[i].compositionType == HWC_OVERLAY) { if((list->hwLayers[i].compositionType == HWC_OVERLAY ||
list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET)) {
//Close the acquireFenceFds //Close the acquireFenceFds
if(list->hwLayers[i].acquireFenceFd > 0) { if(list->hwLayers[i].acquireFenceFd > 0) {
close(list->hwLayers[i].acquireFenceFd); close(list->hwLayers[i].acquireFenceFd);
list->hwLayers[i].acquireFenceFd = -1; list->hwLayers[i].acquireFenceFd = -1;
} }
//Populate releaseFenceFds. //Populate releaseFenceFds.
if (releaseFd != -1) list->hwLayers[i].releaseFenceFd = dup(releaseFd);
list->hwLayers[i].releaseFenceFd = dup(releaseFd);
} }
} }
if (releaseFd != -1) list->retireFenceFd = releaseFd;
close(releaseFd);
} }
#endif #endif
return ret; return ret;

View File

@@ -19,6 +19,7 @@
#define HWC_UTILS_H #define HWC_UTILS_H
#define HWC_REMOVE_DEPRECATED_VERSIONS 1 #define HWC_REMOVE_DEPRECATED_VERSIONS 1
#include <fcntl.h>
#include <hardware/hwcomposer.h> #include <hardware/hwcomposer.h>
#include <gralloc_priv.h> #include <gralloc_priv.h>
@@ -44,7 +45,6 @@ namespace qhwc {
//fwrd decl //fwrd decl
class QueuedBufferStore; class QueuedBufferStore;
class ExternalDisplay; class ExternalDisplay;
class CopybitEngine;
struct MDPInfo { struct MDPInfo {
int version; int version;
@@ -52,16 +52,23 @@ struct MDPInfo {
bool hasOverlay; bool hasOverlay;
}; };
enum external_display_type { struct DisplayAttributes {
EXT_TYPE_NONE, uint32_t vsync_period; //nanos
EXT_TYPE_HDMI, uint32_t xres;
EXT_TYPE_WIFI uint32_t yres;
uint32_t xdpi;
uint32_t ydpi;
int fd;
bool isActive;
}; };
enum HWCCompositionType {
HWC_USE_GPU = HWC_FRAMEBUFFER, // This layer is to be handled by struct ListStats {
// Surfaceflinger int numAppLayers; //Total - 1, excluding FB layer.
HWC_USE_OVERLAY = HWC_OVERLAY, // This layer is to be handled by the overlay int skipCount;
HWC_USE_COPYBIT // This layer is to be handled by copybit int fbLayerIndex; //Always last for now. = numAppLayers
//Video specific
int yuvCount;
int yuvIndex;
}; };
enum { enum {
@@ -74,21 +81,18 @@ enum {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Utility functions - implemented in hwc_utils.cpp // Utility functions - implemented in hwc_utils.cpp
void dumpLayer(hwc_layer_1_t const* l); void dumpLayer(hwc_layer_1_t const* l);
void getLayerStats(hwc_context_t *ctx, const hwc_display_contents_1_t *list); void setListStats(hwc_context_t *ctx, const hwc_display_contents_1_t *list,
int dpy);
void initContext(hwc_context_t *ctx); void initContext(hwc_context_t *ctx);
void closeContext(hwc_context_t *ctx); void closeContext(hwc_context_t *ctx);
//Crops source buffer against destination and FB boundaries //Crops source buffer against destination and FB boundaries
void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst, void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
const int fbWidth, const int fbHeight); const int fbWidth, const int fbHeight);
// Waits for the fb_post to be called bool isExternalActive(hwc_context_t* ctx);
void wait4fbPost(hwc_context_t* ctx);
// Waits for the fb_post to finish PAN (primary commit)
void wait4Pan(hwc_context_t* ctx);
//Sync point impl. //Sync point impl.
int hwc_sync(hwc_display_contents_1_t* list); int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy);
// Inline utility functions // Inline utility functions
static inline bool isSkipLayer(const hwc_layer_1_t* l) { static inline bool isSkipLayer(const hwc_layer_1_t* l) {
@@ -134,6 +138,16 @@ inline void getLayerResolution(const hwc_layer_1_t* layer,
width = displayFrame.right - displayFrame.left; width = displayFrame.right - displayFrame.left;
height = displayFrame.bottom - displayFrame.top; height = displayFrame.bottom - displayFrame.top;
} }
static inline int openFb(int dpy) {
int fd = -1;
const char *devtmpl = "/dev/graphics/fb%u";
char name[64] = {0};
snprintf(name, 64, devtmpl, dpy);
fd = open(name, O_RDWR);
return fd;
}
}; //qhwc namespace }; //qhwc namespace
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -144,20 +158,13 @@ struct hwc_context_t {
const hwc_procs_t* proc; const hwc_procs_t* proc;
int numHwLayers; int numHwLayers;
int overlayInUse; int overlayInUse;
hwc_display_t dpys[MAX_NUM_DISPLAYS];
//Framebuffer device //Framebuffer device
framebuffer_device_t *mFbDev; framebuffer_device_t *mFbDev;
//Copybit Engine
qhwc::CopybitEngine* mCopybitEngine;
//Overlay object - NULL for non overlay devices //Overlay object - NULL for non overlay devices
overlay::Overlay *mOverlay; overlay::Overlay *mOverlay;
//QueuedBufferStore to hold buffers for overlay
qhwc::QueuedBufferStore *qbuf;
//QService object //QService object
qService::QService *mQService; qService::QService *mQService;
@@ -166,7 +173,9 @@ struct hwc_context_t {
qhwc::MDPInfo mMDP; qhwc::MDPInfo mMDP;
bool isPoweredDown; qhwc::DisplayAttributes dpyAttr[HWC_NUM_DISPLAY_TYPES];
qhwc::ListStats listStats[HWC_NUM_DISPLAY_TYPES];
//Securing in progress indicator //Securing in progress indicator
bool mSecuring; bool mSecuring;

View File

@@ -17,9 +17,8 @@
#define VIDEO_DEBUG 0 #define VIDEO_DEBUG 0
#include <overlay.h> #include <overlay.h>
#include "hwc_qbuf.h"
#include "hwc_video.h" #include "hwc_video.h"
#include "external.h" #include "hwc_utils.h"
namespace qhwc { namespace qhwc {
@@ -27,88 +26,81 @@ namespace qhwc {
//Static Members //Static Members
ovutils::eOverlayState VideoOverlay::sState = ovutils::OV_CLOSED; ovutils::eOverlayState VideoOverlay::sState = ovutils::OV_CLOSED;
int VideoOverlay::sYuvCount = 0;
int VideoOverlay::sYuvLayerIndex = -1;
bool VideoOverlay::sIsYuvLayerSkip = false;
int VideoOverlay::sCCLayerIndex = -1;
bool VideoOverlay::sIsModeOn = false; bool VideoOverlay::sIsModeOn = false;
//Cache stats, figure out the state, config overlay //Cache stats, figure out the state, config overlay
bool VideoOverlay::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list) { bool VideoOverlay::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
sIsModeOn = false; int dpy) {
int yuvIndex = ctx->listStats[dpy].yuvIndex;
if(!ctx->mMDP.hasOverlay) { if(!ctx->mMDP.hasOverlay) {
ALOGD_IF(VIDEO_DEBUG,"%s, this hw doesnt support overlay", __FUNCTION__); ALOGD_IF(VIDEO_DEBUG,"%s, this hw doesnt support overlay", __FUNCTION__);
return false; return false;
} }
if(sYuvLayerIndex == -1) { if(yuvIndex == -1) {
return false; return false;
} }
chooseState(ctx);
//if the state chosen above is CLOSED, skip this block.
if(sState != ovutils::OV_CLOSED) {
hwc_layer_1_t *yuvLayer = &list->hwLayers[sYuvLayerIndex];
hwc_layer_1_t *ccLayer = NULL;
if(sCCLayerIndex != -1)
ccLayer = &list->hwLayers[sCCLayerIndex];
if(configure(ctx, yuvLayer, ccLayer)) { //index guaranteed to be not -1 at this point
markFlags(yuvLayer, ccLayer); hwc_layer_1_t *yuvLayer = &list->hwLayers[yuvIndex];
sIsModeOn = true; chooseState(ctx, dpy, yuvLayer);
} if(configure(ctx, dpy, yuvLayer)) {
markFlags(yuvLayer);
sIsModeOn = true;
} }
ALOGD_IF(VIDEO_DEBUG, "%s: stats: yuvCount = %d, yuvIndex = %d,"
"IsYuvLayerSkip = %d, ccLayerIndex = %d, IsModeOn = %d",
__FUNCTION__, sYuvCount, sYuvLayerIndex,
sIsYuvLayerSkip, sCCLayerIndex, sIsModeOn);
return sIsModeOn; return sIsModeOn;
} }
void VideoOverlay::chooseState(hwc_context_t *ctx) { void VideoOverlay::chooseState(hwc_context_t *ctx, int dpy,
hwc_layer_1_t *yuvLayer) {
ALOGD_IF(VIDEO_DEBUG, "%s: old state = %s", __FUNCTION__, ALOGD_IF(VIDEO_DEBUG, "%s: old state = %s", __FUNCTION__,
ovutils::getStateString(sState)); ovutils::getStateString(sState));
ovutils::eOverlayState newState = ovutils::OV_CLOSED; private_handle_t *hnd = NULL;
if(yuvLayer) {
//Support 1 video layer hnd = (private_handle_t *)yuvLayer->handle;
if(sYuvCount == 1) {
//Skip on primary, display on ext.
if(sIsYuvLayerSkip && ctx->mExtDisplay->getExternalDisplay()) {
newState = ovutils::OV_2D_VIDEO_ON_TV;
} else if(sIsYuvLayerSkip) { //skip on primary, no ext
newState = ovutils::OV_CLOSED;
} else if(ctx->mExtDisplay->getExternalDisplay()) {
//display on both
newState = ovutils::OV_2D_VIDEO_ON_PANEL_TV;
} else { //display on primary only
newState = ovutils::OV_2D_VIDEO_ON_PANEL;
}
} }
ovutils::eOverlayState newState = ovutils::OV_CLOSED;
switch(dpy) {
case HWC_DISPLAY_PRIMARY:
if(ctx->listStats[dpy].yuvCount == 1) {
newState = ovutils::OV_2D_VIDEO_ON_PANEL;
if(isSkipLayer(yuvLayer) && !isSecureBuffer(hnd)) {
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)) {
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;
}
}
}*/
break;
default:
break;
}
sState = newState; sState = newState;
ALOGD_IF(VIDEO_DEBUG, "%s: new chosen state = %s", __FUNCTION__, ALOGD_IF(VIDEO_DEBUG, "%s: new chosen state = %s", __FUNCTION__,
ovutils::getStateString(sState)); ovutils::getStateString(sState));
} }
void VideoOverlay::markFlags(hwc_layer_1_t *yuvLayer, hwc_layer_1_t *ccLayer) { void VideoOverlay::markFlags(hwc_layer_1_t *yuvLayer) {
switch(sState) { if(yuvLayer) {
case ovutils::OV_2D_VIDEO_ON_PANEL: yuvLayer->compositionType = HWC_OVERLAY;
case ovutils::OV_2D_VIDEO_ON_PANEL_TV: yuvLayer->hints |= HWC_HINT_CLEAR_FB;
if(yuvLayer) {
yuvLayer->compositionType = HWC_OVERLAY;
yuvLayer->hints |= HWC_HINT_CLEAR_FB;
}
if(ccLayer) {
ccLayer->compositionType = HWC_OVERLAY;
}
break;
case ovutils::OV_2D_VIDEO_ON_TV:
if(ccLayer) {
ccLayer->compositionType = HWC_OVERLAY;
}
break; //dont update video layer flags.
default:
break;
} }
} }
@@ -119,7 +111,7 @@ bool configPrimVid(hwc_context_t *ctx, hwc_layer_1_t *layer) {
ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { if (isSecureBuffer(hnd)) {
ovutils::setMdpFlags(mdpFlags, ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_SECURE_OVERLAY_SESSION); ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
} }
@@ -161,7 +153,7 @@ bool configPrimVid(hwc_context_t *ctx, hwc_layer_1_t *layer) {
//Only for Primary //Only for Primary
ov.setCrop(dcrop, ovutils::OV_PIPE0); ov.setCrop(dcrop, ovutils::OV_PIPE0);
int transform = layer->transform & FINAL_TRANSFORM_MASK; int transform = layer->transform;
ovutils::eTransform orient = ovutils::eTransform orient =
static_cast<ovutils::eTransform>(transform); static_cast<ovutils::eTransform>(transform);
ov.setTransform(orient, ovutils::OV_PIPE0); ov.setTransform(orient, ovutils::OV_PIPE0);
@@ -186,7 +178,7 @@ bool configExtVid(hwc_context_t *ctx, hwc_layer_1_t *layer) {
ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size); ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE; ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
if (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) { if (isSecureBuffer(hnd)) {
ovutils::setMdpFlags(mdpFlags, ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_SECURE_OVERLAY_SESSION); ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
} }
@@ -233,144 +225,83 @@ bool configExtVid(hwc_context_t *ctx, hwc_layer_1_t *layer) {
return true; return true;
} }
bool configExtCC(hwc_context_t *ctx, hwc_layer_1_t *layer) { bool VideoOverlay::configure(hwc_context_t *ctx, int dpy,
if(layer == NULL) hwc_layer_1_t *yuvLayer) {
return true;
overlay::Overlay& ov = *(ctx->mOverlay);
private_handle_t *hnd = (private_handle_t *)layer->handle;
ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
ovutils::eIsFg isFgFlag = ovutils::IS_FG_OFF;
ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
ovutils::PipeArgs parg(mdpFlags,
info,
ovutils::ZORDER_1,
isFgFlag,
ovutils::ROT_FLAG_DISABLED);
ovutils::PipeArgs pargs[ovutils::MAX_PIPES] = { parg, parg, parg };
ov.setSource(pargs, ovutils::OV_PIPE2);
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);
//Only for External
ov.setCrop(dcrop, ovutils::OV_PIPE2);
// FIXME: Use source orientation for TV when source is portrait
//Only for External
ov.setTransform(0, ovutils::OV_PIPE2);
//Setting position same as crop
//FIXME stretch to full screen
ov.setPosition(dcrop, ovutils::OV_PIPE2);
if (!ov.commit(ovutils::OV_PIPE2)) {
ALOGE("%s: commit fails", __FUNCTION__);
return false;
}
return true;
}
bool VideoOverlay::configure(hwc_context_t *ctx, hwc_layer_1_t *yuvLayer,
hwc_layer_1_t *ccLayer) {
bool ret = true; bool ret = true;
if (LIKELY(ctx->mOverlay)) { overlay::Overlay& ov = *(ctx->mOverlay);
overlay::Overlay& ov = *(ctx->mOverlay); switch(dpy) {
// Set overlay state case HWC_DISPLAY_PRIMARY:
ov.setState(sState); // Set overlay state
switch(sState) { ov.setState(sState);
case ovutils::OV_2D_VIDEO_ON_PANEL: switch(sState) {
ret &= configPrimVid(ctx, yuvLayer); case ovutils::OV_2D_VIDEO_ON_PANEL:
break; ret &= configPrimVid(ctx, yuvLayer);
case ovutils::OV_2D_VIDEO_ON_PANEL_TV: break;
ret &= configExtVid(ctx, yuvLayer); default:
ret &= configExtCC(ctx, ccLayer); return false;
ret &= configPrimVid(ctx, yuvLayer); }
break; break;
case ovutils::OV_2D_VIDEO_ON_TV: case HWC_DISPLAY_EXTERNAL:
ret &= configExtVid(ctx, yuvLayer); ov.setState(sState);
ret &= configExtCC(ctx, ccLayer); switch(sState) {
break; case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
default: case ovutils::OV_2D_VIDEO_ON_TV:
return false; ret = configExtVid(ctx, yuvLayer);
} break;
} else { default:
//Ov null return false;
return false; }
break;
} }
return ret; return ret;
} }
bool VideoOverlay::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list) bool VideoOverlay::draw(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy)
{ {
if(!sIsModeOn || sYuvLayerIndex == -1) { int yuvIndex = ctx->listStats[dpy].yuvIndex;
if(!sIsModeOn || yuvIndex == -1) {
return true; return true;
} }
private_handle_t *hnd = (private_handle_t *) private_handle_t *hnd = (private_handle_t *)
list->hwLayers[sYuvLayerIndex].handle; list->hwLayers[yuvIndex].handle;
private_handle_t *cchnd = NULL;
if(sCCLayerIndex != -1) {
cchnd = (private_handle_t *)list->hwLayers[sCCLayerIndex].handle;
ctx->qbuf->lockAndAdd(cchnd);
}
// Lock this buffer for read.
ctx->qbuf->lockAndAdd(hnd);
bool ret = true; bool ret = true;
overlay::Overlay& ov = *(ctx->mOverlay); overlay::Overlay& ov = *(ctx->mOverlay);
ovutils::eOverlayState state = ov.getState(); ovutils::eOverlayState state = ov.getState();
switch (state) { switch(dpy) {
case ovutils::OV_2D_VIDEO_ON_PANEL_TV: case HWC_DISPLAY_PRIMARY:
// Play external switch (state) {
if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE1)) { case ovutils::OV_2D_VIDEO_ON_PANEL:
ALOGE("%s: queueBuffer failed for external", __FUNCTION__); // Play primary
ret = false; if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) {
} ALOGE("%s: queueBuffer failed for primary", __FUNCTION__);
//Play CC on external ret = false;
if (cchnd && !ov.queueBuffer(cchnd->fd, cchnd->offset, }
ovutils::OV_PIPE2)) { break;
ALOGE("%s: queueBuffer failed for cc external", __FUNCTION__); default:
ret = false; ret = false;
} break;
// Play primary
if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) {
ALOGE("%s: queueBuffer failed for primary", __FUNCTION__);
ret = false;
} }
break; break;
case ovutils::OV_2D_VIDEO_ON_PANEL: case HWC_DISPLAY_EXTERNAL:
// Play primary switch(state) {
if (!ov.queueBuffer(hnd->fd, hnd->offset, ovutils::OV_PIPE0)) { case ovutils::OV_2D_VIDEO_ON_PANEL_TV:
ALOGE("%s: queueBuffer failed for primary", __FUNCTION__); case ovutils::OV_2D_VIDEO_ON_TV:
ret = false; // 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;
} }
break; 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;
}
//Play CC on external
if (cchnd && !ov.queueBuffer(cchnd->fd, cchnd->offset,
ovutils::OV_PIPE2)) {
ALOGE("%s: queueBuffer failed for cc external", __FUNCTION__);
ret = false;
}
break;
default:
ALOGE("%s Unused state %s", __FUNCTION__,
ovutils::getStateString(state));
break;
} }
return ret; return ret;
} }

View File

@@ -26,53 +26,29 @@ namespace qhwc {
class VideoOverlay { class VideoOverlay {
public: public:
//Sets up members and prepares overlay if conditions are met //Sets up members and prepares overlay if conditions are met
static bool prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list); static bool prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
int dpy);
//Draws layer if this feature is on //Draws layer if this feature is on
static bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list); static bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list,
//Receives data from hwc int dpy);
static void setStats(int yuvCount, int yuvLayerIndex, bool isYuvLayerSkip,
int ccLayerIndex);
//resets values //resets values
static void reset(); static void reset();
private: private:
//Choose an appropriate overlay state based on conditions //Choose an appropriate overlay state based on conditions
static void chooseState(hwc_context_t *ctx); static void chooseState(hwc_context_t *ctx, int dpy,
hwc_layer_1_t *yuvLayer);
//Configures overlay for video prim and ext //Configures overlay for video prim and ext
static bool configure(hwc_context_t *ctx, hwc_layer_1_t *yuvlayer, static bool configure(hwc_context_t *ctx, int dpy,
hwc_layer_1_t *ccLayer); hwc_layer_1_t *yuvlayer);
//Marks layer flags if this feature is used //Marks layer flags if this feature is used
static void markFlags(hwc_layer_1_t *yuvLayer, hwc_layer_1_t *ccLayer); static void markFlags(hwc_layer_1_t *yuvLayer);
//returns yuv count
static int getYuvCount();
//The chosen overlay state. //The chosen overlay state.
static ovutils::eOverlayState sState; static ovutils::eOverlayState sState;
//Number of yuv layers in this drawing round
static int sYuvCount;
//Index of YUV layer, relevant only if count is 1
static int sYuvLayerIndex;
//Flags if a yuv layer is animating or below something that is animating
static bool sIsYuvLayerSkip;
//Holds the closed caption layer index, -1 by default
static int sCCLayerIndex;
//Flags if this feature is on. //Flags if this feature is on.
static bool sIsModeOn; static bool sIsModeOn;
}; };
inline void VideoOverlay::setStats(int yuvCount, int yuvLayerIndex,
bool isYuvLayerSkip, int ccLayerIndex) {
sYuvCount = yuvCount;
sYuvLayerIndex = yuvLayerIndex;
sIsYuvLayerSkip = isYuvLayerSkip;
sCCLayerIndex = ccLayerIndex;
}
inline int VideoOverlay::getYuvCount() { return sYuvCount; }
inline void VideoOverlay::reset() { inline void VideoOverlay::reset() {
sYuvCount = 0;
sYuvLayerIndex = -1;
sIsYuvLayerSkip = false;
sCCLayerIndex = -1;
sIsModeOn = false; sIsModeOn = false;
sState = ovutils::OV_CLOSED; sState = ovutils::OV_CLOSED;
} }