Merge "hwc: Add assertive display support."

This commit is contained in:
Linux Build Service Account
2013-08-14 01:08:09 -07:00
committed by Gerrit - the friendly Code Review server
9 changed files with 395 additions and 2 deletions

View File

@@ -22,6 +22,7 @@ LOCAL_SRC_FILES := hwc.cpp \
hwc_mdpcomp.cpp \ hwc_mdpcomp.cpp \
hwc_copybit.cpp \ hwc_copybit.cpp \
hwc_qclient.cpp \ hwc_qclient.cpp \
hwc_dump_layers.cpp hwc_dump_layers.cpp \
hwc_ad.cpp
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)

View File

@@ -36,6 +36,7 @@
#include "hwc_dump_layers.h" #include "hwc_dump_layers.h"
#include "external.h" #include "external.h"
#include "hwc_copybit.h" #include "hwc_copybit.h"
#include "hwc_ad.h"
#include "profiler.h" #include "profiler.h"
using namespace qhwc; using namespace qhwc;
@@ -107,6 +108,8 @@ static void reset(hwc_context_t *ctx, int numDisplays,
if(ctx->mCopyBit[i]) if(ctx->mCopyBit[i])
ctx->mCopyBit[i]->reset(); ctx->mCopyBit[i]->reset();
} }
ctx->mAD->reset();
} }
//clear prev layer prop flags and realloc for current frame //clear prev layer prop flags and realloc for current frame

261
libhwcomposer/hwc_ad.cpp Normal file
View File

@@ -0,0 +1,261 @@
/*
* Copyright (c) 2013 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <unistd.h>
#include <overlay.h>
#include <overlayUtils.h>
#include <overlayWriteback.h>
#include <mdp_version.h>
#include "hwc_ad.h"
#include "hwc_utils.h"
#include "external.h"
#define DEBUG 0
using namespace overlay;
using namespace overlay::utils;
namespace qhwc {
//Opens writeback framebuffer and returns fd.
static int openWbFb() {
int wbFd = -1;
//Check opening which FB would connect LM to WB
const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
if(wbFbNum >= 0) {
char wbFbPath[256];
snprintf (wbFbPath, sizeof(wbFbPath),
"/sys/class/graphics/fb%d", wbFbNum);
//Opening writeback fb first time would create ad node if the device
//supports adaptive display
wbFd = open(wbFbPath, O_RDONLY);
if(wbFd < 0) {
ALOGE("%s: Failed to open /sys/class/graphics/fb%d with error %s",
__func__, wbFbNum, strerror(errno));
}
} else {
ALOGD_IF(DEBUG, "%s: No writeback available", __func__);
}
return wbFd;
}
static inline void closeWbFb(int& fd) {
if(fd >= 0) {
close(fd);
fd = -1;
} else {
ALOGE("%s: Invalid fd %d", __func__, fd);
}
}
//Helper to write data to ad node
static void adWrite(const int& value) {
const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
char wbFbPath[256];
snprintf (wbFbPath, sizeof(wbFbPath),
"/sys/class/graphics/fb%d/ad", wbFbNum);
int adFd = open(wbFbPath, O_WRONLY);
if(adFd >= 0) {
char opStr[4] = "";
snprintf(opStr, sizeof(opStr), "%d", value);
int ret = write(adFd, opStr, strlen(opStr));
if(ret < 0) {
ALOGE("%s: Failed to write %d with error %s",
__func__, value, strerror(errno));
} else if (ret == 0){
ALOGE("%s Nothing written to ad", __func__);
} else {
ALOGD_IF(DEBUG, "%s: Wrote %d to ad", __func__, value);
}
close(adFd);
} else {
ALOGE("%s: Failed to open /sys/class/graphics/fb%d/ad with error %s",
__func__, wbFbNum, strerror(errno));
}
}
//Helper to read data from ad node
static int adRead() {
const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
int ret = -1;
char wbFbPath[256];
snprintf (wbFbPath, sizeof(wbFbPath),
"/sys/class/graphics/fb%d/ad", wbFbNum);
int adFd = open(wbFbPath, O_RDONLY);
if(adFd >= 0) {
char opStr[4] = {'\0'};
if(read(adFd, opStr, strlen(opStr)) >= 0) {
//Should return -1, 0 or 1
ret = atoi(opStr);
ALOGD_IF(DEBUG, "%s: Read %d from ad", __func__, ret);
} else {
ALOGE("%s: Read from ad node failed with error %s", __func__,
strerror(errno));
}
close(adFd);
} else {
ALOGE("%s: Failed to open /sys/class/graphics/fb%d/ad with error %s",
__func__, wbFbNum, strerror(errno));
}
return ret;
}
AssertiveDisplay::AssertiveDisplay() :mWbFd(-1), mDoable(false),
mFeatureEnabled(false), mDest(overlay::utils::OV_INVALID) {
int fd = openWbFb();
if(fd >= 0) {
//-1 means feature is disabled on device
// 0 means feature exists but turned off, will be turned on by hwc
// 1 means feature is turned on by hwc
if(adRead() >= 0) {
ALOGD_IF(DEBUG, "Assertive display feature supported");
mFeatureEnabled = true;
}
closeWbFb(fd);
}
}
void AssertiveDisplay::markDoable(hwc_context_t *ctx,
const hwc_display_contents_1_t* list) {
mDoable = false;
if(mFeatureEnabled &&
!ctx->mExtDisplay->isExternalConnected() &&
ctx->listStats[HWC_DISPLAY_PRIMARY].yuvCount == 1) {
int nYuvIndex = ctx->listStats[HWC_DISPLAY_PRIMARY].yuvIndices[0];
const hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
private_handle_t *hnd = (private_handle_t *)layer->handle;
if(hnd && hnd->width <= qdutils::MAX_DISPLAY_DIM) {
mDoable = true;
}
}
}
bool AssertiveDisplay::prepare(hwc_context_t *ctx,
const hwc_rect_t& crop,
const Whf& whf,
const private_handle_t *hnd) {
if(!isDoable()) {
if(isModeOn()) {
//Cleanup one time during this switch
const int off = 0;
adWrite(off);
closeWbFb(mWbFd);
}
return false;
}
ovutils::eDest dest = ctx->mOverlay->nextPipe(ovutils::OV_MDP_PIPE_VG,
overlay::Overlay::DPY_WRITEBACK, Overlay::MIXER_DEFAULT);
if(dest == OV_INVALID) {
ALOGE("%s failed: No VG pipe available", __func__);
mDoable = false;
return false;
}
overlay::Writeback *wb = overlay::Writeback::getInstance();
if(!wb->configureDpyInfo(hnd->width, hnd->height)) {
ALOGE("%s: config display failed", __func__);
mDoable = false;
return false;
}
int tmpW, tmpH, size;
int format = ovutils::getHALFormat(wb->getOutputFormat());
if(format < 0) {
ALOGE("%s invalid format %d", __func__, format);
mDoable = false;
return false;
}
size = getBufferSizeAndDimensions(hnd->width, hnd->height,
format, tmpW, tmpH);
if(!wb->configureMemory(size, isSecureBuffer(hnd))) {
ALOGE("%s: config memory failed", __func__);
mDoable = false;
return false;
}
eMdpFlags mdpFlags = OV_MDP_FLAGS_NONE;
if(isSecureBuffer(hnd)) {
ovutils::setMdpFlags(mdpFlags,
ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
}
PipeArgs parg(mdpFlags, whf, ZORDER_0, IS_FG_OFF,
ROT_FLAGS_NONE);
hwc_rect_t dst = crop; //input same as output
if(configMdp(ctx->mOverlay, parg, OVERLAY_TRANSFORM_0, crop, dst, NULL,
dest) < 0) {
ALOGE("%s: configMdp failed", __func__);
mDoable = false;
return false;
}
mDest = dest;
if(!isModeOn()) {
mWbFd = openWbFb();
if(mWbFd >= 0) {
//write to sysfs, one time during this switch
const int on = 1;
adWrite(on);
}
}
return true;
}
bool AssertiveDisplay::draw(hwc_context_t *ctx, int fd, uint32_t offset) {
if(!isDoable() || !isModeOn()) {
return false;
}
if (!ctx->mOverlay->queueBuffer(fd, offset, mDest)) {
ALOGE("%s: queueBuffer failed", __func__);
return false;
}
overlay::Writeback *wb = overlay::Writeback::getInstance();
if(!wb->writeSync()) {
return false;
}
return true;
}
int AssertiveDisplay::getDstFd(hwc_context_t *ctx) const {
overlay::Writeback *wb = overlay::Writeback::getInstance();
return wb->getDstFd();
}
uint32_t AssertiveDisplay::getDstOffset(hwc_context_t *ctx) const {
overlay::Writeback *wb = overlay::Writeback::getInstance();
return wb->getOffset();
}
}

67
libhwcomposer/hwc_ad.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2013 The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef HWC_AD_H
#define HWC_AD_H
#include <overlayUtils.h>
#include <hwc_utils.h>
struct hwc_context_t;
namespace qhwc {
class AssertiveDisplay {
public:
AssertiveDisplay();
void markDoable(hwc_context_t *ctx, const hwc_display_contents_1_t* list);
bool prepare(hwc_context_t *ctx, const hwc_rect_t& crop,
const overlay::utils::Whf& whf,
const private_handle_t *hnd);
bool draw(hwc_context_t *ctx, int fd, uint32_t offset);
//Resets a few members on each draw round
void reset() { mDoable = false;
mDest = overlay::utils::OV_INVALID;
}
bool isDoable() const { return mDoable; }
bool isModeOn() const { return (mWbFd >= 0); }
int getDstFd(hwc_context_t *ctx) const;
uint32_t getDstOffset(hwc_context_t *ctx) const;
private:
//State of feature turned on and off
int mWbFd;
bool mDoable;
//State of feature existence on certain devices and configs.
bool mFeatureEnabled;
overlay::utils::eDest mDest;
};
}
#endif

View File

@@ -23,6 +23,7 @@
#include "qdMetaData.h" #include "qdMetaData.h"
#include "mdp_version.h" #include "mdp_version.h"
#include "hwc_fbupdate.h" #include "hwc_fbupdate.h"
#include "hwc_ad.h"
#include <overlayRotator.h> #include <overlayRotator.h>
using namespace overlay; using namespace overlay;
@@ -453,6 +454,10 @@ bool MDPComp::isFullFrameDoable(hwc_context_t *ctx,
return false; return false;
} }
if(ctx->mAD->isDoable()) {
return false;
}
//If all above hard conditions are met we can do full or partial MDP comp. //If all above hard conditions are met we can do full or partial MDP comp.
bool ret = false; bool ret = false;
if(fullMDPComp(ctx, list)) { if(fullMDPComp(ctx, list)) {
@@ -955,6 +960,14 @@ bool MDPCompLowRes::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
int fd = hnd->fd; int fd = hnd->fd;
uint32_t offset = hnd->offset; uint32_t offset = hnd->offset;
if(ctx->mAD->isModeOn()) {
if(ctx->mAD->draw(ctx, fd, offset)) {
fd = ctx->mAD->getDstFd(ctx);
offset = ctx->mAD->getDstOffset(ctx);
}
}
Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot; Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
if(rot) { if(rot) {
if(!rot->queueBuffer(fd, offset)) if(!rot->queueBuffer(fd, offset))
@@ -1150,6 +1163,13 @@ bool MDPCompHighRes::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
int fd = hnd->fd; int fd = hnd->fd;
int offset = hnd->offset; int offset = hnd->offset;
if(ctx->mAD->isModeOn()) {
if(ctx->mAD->draw(ctx, fd, offset)) {
fd = ctx->mAD->getDstFd(ctx);
offset = ctx->mAD->getDstOffset(ctx);
}
}
if(rot) { if(rot) {
rot->queueBuffer(fd, offset); rot->queueBuffer(fd, offset);
fd = rot->getDstMemId(); fd = rot->getDstMemId();

View File

@@ -27,9 +27,11 @@
#include <gralloc_priv.h> #include <gralloc_priv.h>
#include <overlay.h> #include <overlay.h>
#include <overlayRotator.h> #include <overlayRotator.h>
#include <overlayWriteback.h>
#include "hwc_utils.h" #include "hwc_utils.h"
#include "hwc_mdpcomp.h" #include "hwc_mdpcomp.h"
#include "hwc_fbupdate.h" #include "hwc_fbupdate.h"
#include "hwc_ad.h"
#include "mdp_version.h" #include "mdp_version.h"
#include "hwc_copybit.h" #include "hwc_copybit.h"
#include "hwc_dump_layers.h" #include "hwc_dump_layers.h"
@@ -161,6 +163,7 @@ void initContext(hwc_context_t *ctx)
} }
MDPComp::init(ctx); MDPComp::init(ctx);
ctx->mAD = new AssertiveDisplay();
ctx->vstate.enable = false; ctx->vstate.enable = false;
ctx->vstate.fakevsync = false; ctx->vstate.fakevsync = false;
@@ -234,6 +237,10 @@ void closeContext(hwc_context_t *ctx)
ctx->mLayerRotMap[i] = NULL; ctx->mLayerRotMap[i] = NULL;
} }
} }
if(ctx->mAD) {
delete ctx->mAD;
ctx->mAD = NULL;
}
} }
@@ -475,6 +482,9 @@ void setListStats(hwc_context_t *ctx,
if(prevYuvCount != ctx->listStats[dpy].yuvCount) { if(prevYuvCount != ctx->listStats[dpy].yuvCount) {
ctx->mVideoTransFlag = true; ctx->mVideoTransFlag = true;
} }
if(dpy == HWC_DISPLAY_PRIMARY) {
ctx->mAD->markDoable(ctx, list);
}
} }
@@ -991,6 +1001,13 @@ int configureLowRes(hwc_context_t *ctx, hwc_layer_1_t *layer,
setMdpFlags(layer, mdpFlags, downscale, transform); setMdpFlags(layer, mdpFlags, downscale, transform);
trimLayer(ctx, dpy, transform, crop, dst); trimLayer(ctx, dpy, transform, crop, dst);
//Will do something only if feature enabled and conditions suitable
//hollow call otherwise
if(ctx->mAD->prepare(ctx, crop, whf, hnd)) {
overlay::Writeback *wb = overlay::Writeback::getInstance();
whf.format = wb->getOutputFormat();
}
if(isYuvBuffer(hnd) && //if 90 component or downscale, use rot if(isYuvBuffer(hnd) && //if 90 component or downscale, use rot
((transform & HWC_TRANSFORM_ROT_90) || downscale)) { ((transform & HWC_TRANSFORM_ROT_90) || downscale)) {
*rot = ctx->mRotMgr->getNext(); *rot = ctx->mRotMgr->getNext();
@@ -1069,6 +1086,13 @@ int configureHighRes(hwc_context_t *ctx, hwc_layer_1_t *layer,
setMdpFlags(layer, mdpFlagsL, 0, transform); setMdpFlags(layer, mdpFlagsL, 0, transform);
trimLayer(ctx, dpy, transform, crop, dst); trimLayer(ctx, dpy, transform, crop, dst);
//Will do something only if feature enabled and conditions suitable
//hollow call otherwise
if(ctx->mAD->prepare(ctx, crop, whf, hnd)) {
overlay::Writeback *wb = overlay::Writeback::getInstance();
whf.format = wb->getOutputFormat();
}
if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) { if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
(*rot) = ctx->mRotMgr->getNext(); (*rot) = ctx->mRotMgr->getNext();
if((*rot) == NULL) return -1; if((*rot) == NULL) return -1;

View File

@@ -55,6 +55,7 @@ class IVideoOverlay;
class MDPComp; class MDPComp;
class CopyBit; class CopyBit;
class HwcDebug; class HwcDebug;
class AssertiveDisplay;
struct MDPInfo { struct MDPInfo {
@@ -321,6 +322,7 @@ struct hwc_context_t {
qhwc::LayerProp *layerProp[HWC_NUM_DISPLAY_TYPES]; qhwc::LayerProp *layerProp[HWC_NUM_DISPLAY_TYPES];
qhwc::MDPComp *mMDPComp[HWC_NUM_DISPLAY_TYPES]; qhwc::MDPComp *mMDPComp[HWC_NUM_DISPLAY_TYPES];
qhwc::HwcDebug *mHwcDebug[HWC_NUM_DISPLAY_TYPES]; qhwc::HwcDebug *mHwcDebug[HWC_NUM_DISPLAY_TYPES];
qhwc::AssertiveDisplay *mAD;
// No animation on External display feature // No animation on External display feature
// Notifies hwcomposer about the device orientation before animation. // Notifies hwcomposer about the device orientation before animation.

View File

@@ -73,12 +73,13 @@ bool WritebackMem::dealloc() {
} }
//=========== class Writeback ================================================= //=========== class Writeback =================================================
Writeback::Writeback() : mXres(0), mYres(0) { Writeback::Writeback() : mXres(0), mYres(0), mOpFmt(-1) {
int fbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK); int fbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
if(!utils::openDev(mFd, fbNum, Res::fbPath, O_RDWR)) { if(!utils::openDev(mFd, fbNum, Res::fbPath, O_RDWR)) {
ALOGE("%s failed to init %s", __func__, Res::fbPath); ALOGE("%s failed to init %s", __func__, Res::fbPath);
return; return;
} }
queryOutputFormat();
startSession(); startSession();
} }
@@ -184,6 +185,17 @@ bool Writeback::writeSync() {
return writeSync(mWbMem.getDstFd(), mWbMem.getOffset()); return writeSync(mWbMem.getDstFd(), mWbMem.getOffset());
} }
void Writeback::queryOutputFormat() {
struct msmfb_metadata metadata;
memset(&metadata, 0 , sizeof(metadata));
metadata.op = metadata_op_wb_format;
if (ioctl(mFd.getFD(), MSMFB_METADATA_GET, &metadata) < 0) {
ALOGE("Error retrieving MDP Writeback format");
return;
}
mOpFmt = metadata.data.mixer_cfg.writeback_format;
}
//static //static
Writeback *Writeback::getInstance() { Writeback *Writeback::getInstance() {

View File

@@ -81,6 +81,7 @@ public:
bool queueBuffer(int opFd, uint32_t opOffset); bool queueBuffer(int opFd, uint32_t opOffset);
uint32_t getOffset() const { return mWbMem.getOffset(); } uint32_t getOffset() const { return mWbMem.getOffset(); }
int getDstFd() const { return mWbMem.getDstFd(); } int getDstFd() const { return mWbMem.getDstFd(); }
int getOutputFormat() const { return mOpFmt; }
static Writeback* getInstance(); static Writeback* getInstance();
static void configBegin() { sUsed = false; } static void configBegin() { sUsed = false; }
@@ -93,11 +94,13 @@ private:
bool stopSession(); bool stopSession();
//Actually block_until_write_done for the usage here. //Actually block_until_write_done for the usage here.
bool dequeueBuffer(); bool dequeueBuffer();
void queryOutputFormat();
OvFD mFd; OvFD mFd;
WritebackMem mWbMem; WritebackMem mWbMem;
struct msmfb_data mFbData; struct msmfb_data mFbData;
int mXres; int mXres;
int mYres; int mYres;
int mOpFmt;
static bool sUsed; static bool sUsed;
static Writeback *sWb; static Writeback *sWb;