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 rotData.acq_fen_fd_cnt = 1; //1 ioctl call per rot session
} }
int ret = 0; int ret = 0;
if(not ctx->mLayerRotMap[dpy]->isRotCached(i))
ret = ioctl(rotFd, MSMFB_BUFFER_SYNC, &rotData); ret = ioctl(rotFd, MSMFB_BUFFER_SYNC, &rotData);
if(ret < 0) { if(ret < 0) {
ALOGE("%s: ioctl MSMFB_BUFFER_SYNC failed for rot sync, err=%s", ALOGE("%s: ioctl MSMFB_BUFFER_SYNC failed for rot sync, err=%s",
__FUNCTION__, strerror(errno)); __FUNCTION__, strerror(errno));
@@ -2260,9 +2262,27 @@ void LayerRotMap::clear() {
reset(); 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) { void LayerRotMap::setReleaseFd(const int& fence) {
for(uint32_t i = 0; i < mCount; i++) { 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; uint32_t getCount() const;
hwc_layer_1_t* getLayer(uint32_t index) const; hwc_layer_1_t* getLayer(uint32_t index) const;
overlay::Rotator* getRot(uint32_t index) const; overlay::Rotator* getRot(uint32_t index) const;
bool isRotCached(uint32_t index) const;
void setReleaseFd(const int& fence); void setReleaseFd(const int& fence);
private: private:
hwc_layer_1_t* mLayer[overlay::RotMgr::MAX_ROT_SESS]; 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; } void MdpRot::setRotations(uint32_t r) { mRotImgInfo.rotations = (uint8_t)r; }
int MdpRot::getSrcMemId() const {
return mRotDataInfo.src.memory_id;
}
int MdpRot::getDstMemId() const { int MdpRot::getDstMemId() const {
return mRotDataInfo.dst.memory_id; return mRotDataInfo.dst.memory_id;
} }
uint32_t MdpRot::getSrcOffset() const {
return mRotDataInfo.src.offset;
}
uint32_t MdpRot::getDstOffset() const { uint32_t MdpRot::getDstOffset() const {
return mRotDataInfo.dst.offset; return mRotDataInfo.dst.offset;
} }
@@ -147,7 +155,6 @@ bool MdpRot::commit() {
mRotImgInfo.enable = 0; mRotImgInfo.enable = 0;
return false; return false;
} }
save();
mRotDataInfo.session_id = mRotImgInfo.session_id; mRotDataInfo.session_id = mRotImgInfo.session_id;
} }
return true; return true;
@@ -238,7 +245,10 @@ void MdpRot::reset() {
} }
bool MdpRot::queueBuffer(int fd, uint32_t offset) { 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.memory_id = fd;
mRotDataInfo.src.offset = offset; mRotDataInfo.src.offset = offset;
@@ -249,14 +259,17 @@ bool MdpRot::queueBuffer(int fd, uint32_t offset) {
mRotDataInfo.dst.offset = mRotDataInfo.dst.offset =
mMem.mRotOffset[mMem.mCurrIndex]; mMem.mRotOffset[mMem.mCurrIndex];
mMem.mCurrIndex =
(mMem.mCurrIndex + 1) % mMem.mem.numBufs();
if(!overlay::mdp_wrapper::rotate(mFd.getFD(), mRotDataInfo)) { if(!overlay::mdp_wrapper::rotate(mFd.getFD(), mRotDataInfo)) {
ALOGE("MdpRot failed rotate"); ALOGE("MdpRot failed rotate");
dump(); dump();
mRotDataInfo.src.memory_id = prev_fd;
mRotDataInfo.src.offset = prev_offset;
return false; return false;
} }
save();
mMem.mCurrIndex =
(mMem.mCurrIndex + 1) % mMem.mem.numBufs();
} }
return true; return true;
} }

View File

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

View File

@@ -29,6 +29,17 @@ namespace overlay {
//============Rotator========================= //============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() {}
Rotator* Rotator::getRotator() { Rotator* Rotator::getRotator() {
@@ -70,6 +81,20 @@ int Rotator::getRotatorHwType() {
return TYPE_MDP; 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========================= //============RotMem=========================
@@ -98,7 +123,7 @@ RotMem::~RotMem() {
} }
} }
void RotMem::setReleaseFd(const int& fence) { void RotMem::setCurrBufReleaseFd(const int& fence) {
int ret = 0; int ret = 0;
if(mRelFence[mCurrIndex] >= 0) { if(mRelFence[mCurrIndex] >= 0) {
@@ -116,6 +141,20 @@ void RotMem::setReleaseFd(const int& fence) {
mRelFence[mCurrIndex] = 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 * RotMgr::sRotMgr = NULL; RotMgr * RotMgr::sRotMgr = NULL;

View File

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