hwc/overlay: Implement rotator caching

* A non-updating layer requiring rotation, can make use of
the older rotator buffer written when the layer got first
updated, rather than invoking a new rotator cycle.

* A rotator play is avoided in cases where incoming layer
buffer fd, offset, whf, src-rect, dst-rect, etc are similar
to that of the previous input layer to the rotator.

* For ex: In a usecase where video layer updates happen at
30fps and all other asynchrous UI updates happen at 60fps,
instead of the traditional 60 calls of rotator play per sec,
we now do only 30 thereby saving rotator bandwidth.

* Property "debug.rotcache.disable" can be used to disable
this feature.

Change-Id: I1d1c352c63007b7e0b4fee40882086ccd2f5a4aa
This commit is contained in:
Raj Kamal
2014-08-05 18:52:49 +05:30
committed by Gerrit - the friendly Code Review server
parent ee75c10fa6
commit bd3bdc6d03
6 changed files with 143 additions and 17 deletions

View File

@@ -1324,7 +1324,9 @@ int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy,
rotData.acq_fen_fd_cnt = 1; //1 ioctl call per rot session
}
int ret = 0;
if(not ctx->mLayerRotMap[dpy]->isRotCached(i))
ret = ioctl(rotFd, MSMFB_BUFFER_SYNC, &rotData);
if(ret < 0) {
ALOGE("%s: ioctl MSMFB_BUFFER_SYNC failed for rot sync, err=%s",
__FUNCTION__, strerror(errno));
@@ -2260,9 +2262,27 @@ void LayerRotMap::clear() {
reset();
}
bool LayerRotMap::isRotCached(uint32_t index) const {
overlay::Rotator* rot = getRot(index);
hwc_layer_1_t* layer = getLayer(index);
if(rot and layer and layer->handle) {
private_handle_t *hnd = (private_handle_t *)(layer->handle);
return (rot->isRotCached(hnd->fd,(uint32_t)(hnd->offset)));
}
return false;
}
void LayerRotMap::setReleaseFd(const int& fence) {
for(uint32_t i = 0; i < mCount; i++) {
mRot[i]->setReleaseFd(dup(fence));
if(mRot[i] and mLayer[i] and mLayer[i]->handle) {
/* Ensure that none of the above (Rotator-instance,
* layer and layer-handle) are NULL*/
if(isRotCached(i))
mRot[i]->setPrevBufReleaseFd(dup(fence));
else
mRot[i]->setCurrBufReleaseFd(dup(fence));
}
}
}

View File

@@ -201,6 +201,7 @@ public:
uint32_t getCount() const;
hwc_layer_1_t* getLayer(uint32_t index) const;
overlay::Rotator* getRot(uint32_t index) const;
bool isRotCached(uint32_t index) const;
void setReleaseFd(const int& fence);
private:
hwc_layer_1_t* mLayer[overlay::RotMgr::MAX_ROT_SESS];

View File

@@ -37,10 +37,18 @@ bool MdpRot::enabled() const { return mRotImgInfo.enable; }
void MdpRot::setRotations(uint32_t r) { mRotImgInfo.rotations = (uint8_t)r; }
int MdpRot::getSrcMemId() const {
return mRotDataInfo.src.memory_id;
}
int MdpRot::getDstMemId() const {
return mRotDataInfo.dst.memory_id;
}
uint32_t MdpRot::getSrcOffset() const {
return mRotDataInfo.src.offset;
}
uint32_t MdpRot::getDstOffset() const {
return mRotDataInfo.dst.offset;
}
@@ -147,7 +155,6 @@ bool MdpRot::commit() {
mRotImgInfo.enable = 0;
return false;
}
save();
mRotDataInfo.session_id = mRotImgInfo.session_id;
}
return true;
@@ -238,7 +245,10 @@ void MdpRot::reset() {
}
bool MdpRot::queueBuffer(int fd, uint32_t offset) {
if(enabled()) {
if(enabled() and (not isRotCached(fd,offset))) {
int prev_fd = getSrcMemId();
uint32_t prev_offset = getSrcOffset();
mRotDataInfo.src.memory_id = fd;
mRotDataInfo.src.offset = offset;
@@ -249,14 +259,17 @@ bool MdpRot::queueBuffer(int fd, uint32_t offset) {
mRotDataInfo.dst.offset =
mMem.mRotOffset[mMem.mCurrIndex];
mMem.mCurrIndex =
(mMem.mCurrIndex + 1) % mMem.mem.numBufs();
if(!overlay::mdp_wrapper::rotate(mFd.getFD(), mRotDataInfo)) {
ALOGE("MdpRot failed rotate");
dump();
mRotDataInfo.src.memory_id = prev_fd;
mRotDataInfo.src.offset = prev_offset;
return false;
}
save();
mMem.mCurrIndex =
(mMem.mCurrIndex + 1) % mMem.mem.numBufs();
}
return true;
}

View File

@@ -51,10 +51,18 @@ bool MdssRot::enabled() const { return mEnabled; }
void MdssRot::setRotations(uint32_t flags) { mRotInfo.flags |= flags; }
int MdssRot::getSrcMemId() const {
return mRotData.data.memory_id;
}
int MdssRot::getDstMemId() const {
return mRotData.dst_data.memory_id;
}
uint32_t MdssRot::getSrcOffset() const {
return mRotData.data.offset;
}
uint32_t MdssRot::getDstOffset() const {
return mRotData.dst_data.offset;
}
@@ -81,6 +89,19 @@ utils::Dim MdssRot::getDstDimensions() const {
uint32_t MdssRot::getSessId() const { return mRotInfo.id; }
void MdssRot::save() {
mLSRotInfo = mRotInfo;
}
bool MdssRot::rotConfChanged() const {
// 0 means same
if(0 == ::memcmp(&mRotInfo, &mLSRotInfo,
sizeof (mdp_overlay))) {
return false;
}
return true;
}
bool MdssRot::init() {
if(!utils::openDev(mFd, 0, Res::fbPath, O_RDWR)) {
ALOGE("MdssRot failed to init fb0");
@@ -164,7 +185,10 @@ bool MdssRot::commit() {
}
bool MdssRot::queueBuffer(int fd, uint32_t offset) {
if(enabled()) {
if(enabled() and (not isRotCached(fd,offset))) {
int prev_fd = getSrcMemId();
uint32_t prev_offset = getSrcOffset();
mRotData.data.memory_id = fd;
mRotData.data.offset = offset;
@@ -175,14 +199,17 @@ bool MdssRot::queueBuffer(int fd, uint32_t offset) {
mRotData.dst_data.offset =
mMem.mRotOffset[mMem.mCurrIndex];
mMem.mCurrIndex =
(mMem.mCurrIndex + 1) % mMem.mem.numBufs();
if(!overlay::mdp_wrapper::play(mFd.getFD(), mRotData)) {
ALOGE("MdssRot play failed!");
dump();
mRotData.data.memory_id = prev_fd;
mRotData.data.offset = prev_offset;
return false;
}
save();
mMem.mCurrIndex =
(mMem.mCurrIndex + 1) % mMem.mem.numBufs();
}
return true;
}
@@ -260,6 +287,7 @@ bool MdssRot::close() {
void MdssRot::reset() {
ovutils::memset0(mRotInfo);
ovutils::memset0(mLSRotInfo);
ovutils::memset0(mRotData);
mRotData.data.memory_id = -1;
mRotInfo.id = MSMFB_NEW_REQUEST;

View File

@@ -29,6 +29,17 @@ namespace overlay {
//============Rotator=========================
Rotator::Rotator() {
char property[PROPERTY_VALUE_MAX];
mRotCacheDisabled = false;
if((property_get("debug.rotcache.disable", property, NULL) > 0) &&
(!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
(!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
/* Used in debugging to turnoff rotator caching */
mRotCacheDisabled = true;
}
}
Rotator::~Rotator() {}
Rotator* Rotator::getRotator() {
@@ -70,6 +81,20 @@ int Rotator::getRotatorHwType() {
return TYPE_MDP;
}
bool Rotator::isRotCached(int fd, uint32_t offset) const {
if(mRotCacheDisabled or rotConfChanged() or rotDataChanged(fd,offset))
return false;
return true;
}
bool Rotator::rotDataChanged(int fd, uint32_t offset) const {
/* fd and offset are the attributes of the current rotator input buffer.
* At this instance, getSrcMemId() and getSrcOffset() return the
* attributes of the previous rotator input buffer */
if( (fd == getSrcMemId()) and (offset == getSrcOffset()) )
return false;
return true;
}
//============RotMem=========================
@@ -98,7 +123,7 @@ RotMem::~RotMem() {
}
}
void RotMem::setReleaseFd(const int& fence) {
void RotMem::setCurrBufReleaseFd(const int& fence) {
int ret = 0;
if(mRelFence[mCurrIndex] >= 0) {
@@ -116,6 +141,20 @@ void RotMem::setReleaseFd(const int& fence) {
mRelFence[mCurrIndex] = fence;
}
void RotMem::setPrevBufReleaseFd(const int& fence) {
uint32_t numRotBufs = mem.numBufs();
uint32_t prevIndex = (mCurrIndex + numRotBufs - 1) % (numRotBufs);
if(mRelFence[prevIndex] >= 0) {
/* No need of any wait as nothing will be written into this
* buffer by the rotator (this func is called when rotator is
* in cache mode) */
::close(mRelFence[prevIndex]);
}
mRelFence[prevIndex] = fence;
}
//============RotMgr=========================
RotMgr * RotMgr::sRotMgr = NULL;

View File

@@ -52,7 +52,8 @@ struct RotMem {
bool close();
bool valid() { return mem.valid(); }
uint32_t size() const { return mem.bufSz(); }
void setReleaseFd(const int& fence);
void setCurrBufReleaseFd(const int& fence);
void setPrevBufReleaseFd(const int& fence);
// rotator data info dst offset
uint32_t mRotOffset[ROT_NUM_BUFS];
@@ -72,9 +73,20 @@ public:
virtual void setFlags(const utils::eMdpFlags& flags) = 0;
virtual void setTransform(const utils::eTransform& rot) = 0;
virtual bool commit() = 0;
/* return true if the current rotator state is cached */
virtual bool isRotCached(int fd, uint32_t offset) const;
/* return true if current rotator config is same as the last round*/
virtual bool rotConfChanged() const = 0;
/* return true if the current rotator input buffer fd and offset
* are same as the last round */
virtual bool rotDataChanged(int fd, uint32_t offset) const;
virtual void setDownscale(int ds) = 0;
/* returns the src buffer of the rotator for the previous/current round,
* depending on when it is called(before/after the queuebuffer)*/
virtual int getSrcMemId() const = 0;
//Mem id and offset should be retrieved only after rotator kickoff
virtual int getDstMemId() const = 0;
virtual uint32_t getSrcOffset() const = 0;
virtual uint32_t getDstOffset() const = 0;
//Destination width, height, format, position should be retrieved only after
//rotator configuration is committed via commit API
@@ -85,7 +97,12 @@ public:
virtual bool queueBuffer(int fd, uint32_t offset) = 0;
virtual void dump() const = 0;
virtual void getDump(char *buf, size_t len) const = 0;
void setReleaseFd(const int& fence) { mMem.setReleaseFd(fence); }
inline void setCurrBufReleaseFd(const int& fence) {
mMem.setCurrBufReleaseFd(fence);
}
inline void setPrevBufReleaseFd(const int& fence) {
mMem.setPrevBufReleaseFd(fence);
}
static Rotator *getRotator();
/* Returns downscale by successfully applying constraints
* Returns 0 if target doesnt support rotator downscaling
@@ -98,10 +115,11 @@ public:
protected:
/* Rotator memory manager */
RotMem mMem;
explicit Rotator() {}
Rotator();
static uint32_t calcOutputBufSize(const utils::Whf& destWhf);
private:
bool mRotCacheDisabled;
/*Returns rotator h/w type */
static int getRotatorHwType();
friend class RotMgr;
@@ -119,8 +137,11 @@ public:
virtual void setFlags(const utils::eMdpFlags& flags);
virtual void setTransform(const utils::eTransform& rot);
virtual bool commit();
virtual bool rotConfChanged() const;
virtual void setDownscale(int ds);
virtual int getSrcMemId() const;
virtual int getDstMemId() const;
virtual uint32_t getSrcOffset() const;
virtual uint32_t getDstOffset() const;
virtual uint32_t getDstFormat() const;
virtual utils::Whf getDstWhf() const;
@@ -143,9 +164,6 @@ private:
void doTransform();
/* reset underlying data, basically memset 0 */
void reset();
/* return true if current rotator config is different
* than last known config */
bool rotConfChanged() const;
/* save mRotImgInfo to be last known good config*/
void save();
/* Calculates the rotator's o/p buffer size post the transform calcs and
@@ -191,8 +209,11 @@ public:
virtual void setFlags(const utils::eMdpFlags& flags);
virtual void setTransform(const utils::eTransform& rot);
virtual bool commit();
virtual bool rotConfChanged() const;
virtual void setDownscale(int ds);
virtual int getSrcMemId() const;
virtual int getDstMemId() const;
virtual uint32_t getSrcOffset() const;
virtual uint32_t getDstOffset() const;
virtual uint32_t getDstFormat() const;
virtual utils::Whf getDstWhf() const;
@@ -215,6 +236,8 @@ private:
void doTransform();
/* reset underlying data, basically memset 0 */
void reset();
/* save mRotInfo to be last known good config*/
void save();
/* Calculates the rotator's o/p buffer size post the transform calcs and
* knowing the o/p format depending on whether fastYuv is enabled or not */
uint32_t calcOutputBufSize();
@@ -242,6 +265,8 @@ private:
/* MdssRot info structure */
mdp_overlay mRotInfo;
/* Last saved MdssRot info structure*/
mdp_overlay mLSRotInfo;
/* MdssRot data structure */
msmfb_overlay_data mRotData;
/* Orientation */