Merge "qdutils: Refactor idletimeout fallback mechanism."
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 438c9d2..469ffba 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -38,6 +38,7 @@
IdleInvalidator *MDPComp::idleInvalidator = NULL;
bool MDPComp::sIdleFallBack = false;
+bool MDPComp::sHandleTimeout = false;
bool MDPComp::sDebugLogs = false;
bool MDPComp::sEnabled = false;
bool MDPComp::sEnableMixedMode = true;
@@ -171,7 +172,12 @@
ALOGE("%s: received empty data in timer callback", __FUNCTION__);
return;
}
-
+ Locker::Autolock _l(ctx->mDrawLock);
+ // Handle timeout event only if the previous composition is MDP or MIXED.
+ if(!sHandleTimeout) {
+ ALOGD_IF(isDebug(), "%s:Do not handle this timeout", __FUNCTION__);
+ return;
+ }
if(!ctx->proc) {
ALOGE("%s: HWC proc not registered", __FUNCTION__);
return;
@@ -1616,9 +1622,10 @@
return true;
}
- /* reset Invalidator */
- if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
- idleInvalidator->handleUpdateEvent();
+ // Set the Handle timeout to true for MDP or MIXED composition.
+ if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
+ sHandleTimeout = true;
+ }
overlay::Overlay& ov = *ctx->mOverlay;
LayerProp *layerProp = ctx->layerProp[mDpy];
@@ -1862,9 +1869,10 @@
return true;
}
- /* reset Invalidator */
- if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
- idleInvalidator->handleUpdateEvent();
+ // Set the Handle timeout to true for MDP or MIXED composition.
+ if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
+ sHandleTimeout = true;
+ }
overlay::Overlay& ov = *ctx->mOverlay;
LayerProp *layerProp = ctx->layerProp[mDpy];
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index c941bd5..4215881 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -52,7 +52,7 @@
/* Initialize MDP comp*/
static bool init(hwc_context_t *ctx);
static void resetIdleFallBack() { sIdleFallBack = false; }
- static void reset() { sBwClaimed = 0.0; };
+ static void reset() { sBwClaimed = 0.0; sHandleTimeout = false; };
protected:
enum { MAX_SEC_LAYERS = 1 }; //TODO add property support
@@ -231,6 +231,8 @@
static bool sEnablePartialFrameUpdate;
static bool sDebugLogs;
static bool sIdleFallBack;
+ /* Handles the timeout event from kernel, if the value is set to true */
+ static bool sHandleTimeout;
static int sMaxPipesPerMixer;
//Max bandwidth. Value is in GBPS. For ex: 2.3 means 2.3GBPS
static double sMaxBw;
diff --git a/libqdutils/idle_invalidator.cpp b/libqdutils/idle_invalidator.cpp
index b53f1a3..d30375e 100644
--- a/libqdutils/idle_invalidator.cpp
+++ b/libqdutils/idle_invalidator.cpp
@@ -29,91 +29,99 @@
#include "idle_invalidator.h"
#include <unistd.h>
+#include <poll.h>
+#include <string.h>
+#include <fcntl.h>
#define II_DEBUG 0
+#define IDLE_NOTIFY_PATH "/sys/devices/virtual/graphics/fb0/idle_notify"
+#define IDLE_TIME_PATH "/sys/devices/virtual/graphics/fb0/idle_time"
-static const char *threadName = "Invalidator";
+
+static const char *threadName = "IdleInvalidator";
InvalidatorHandler IdleInvalidator::mHandler = NULL;
android::sp<IdleInvalidator> IdleInvalidator::sInstance(0);
IdleInvalidator::IdleInvalidator(): Thread(false), mHwcContext(0),
- mSleepAgain(false), mSleepTime(0) {
- ALOGD_IF(II_DEBUG, "%s", __func__);
- }
+ mTimeoutEventFd(-1) {
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
+}
int IdleInvalidator::init(InvalidatorHandler reg_handler, void* user_data,
- unsigned int idleSleepTime) {
- ALOGD_IF(II_DEBUG, "%s", __func__);
-
- Locker::Autolock _l(mLock);
- /* store registered handler */
+ unsigned int idleSleepTime) {
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s idleSleepTime %d",
+ __FUNCTION__, idleSleepTime);
mHandler = reg_handler;
mHwcContext = user_data;
- mSleepTime = idleSleepTime; //Time in millis
+
+ // Open a sysfs node to receive the timeout notification from driver.
+ mTimeoutEventFd = open(IDLE_NOTIFY_PATH, O_RDONLY);
+ if (mTimeoutEventFd < 0) {
+ ALOGE ("%s:not able to open %s node %s",
+ __FUNCTION__, IDLE_NOTIFY_PATH, strerror(errno));
+ return -1;
+ }
+
+ // Open a sysfs node to send the timeout value to driver.
+ int fd = open(IDLE_TIME_PATH, O_WRONLY);
+ if (fd < 0) {
+ ALOGE ("%s:not able to open %s node %s",
+ __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
+ close(mTimeoutEventFd);
+ mTimeoutEventFd = -1;
+ return -1;
+ }
+ char strSleepTime[64];
+ snprintf(strSleepTime, sizeof(strSleepTime), "%d", idleSleepTime);
+ // Notify driver about the timeout value
+ ssize_t len = pwrite(fd, strSleepTime, strlen(strSleepTime), 0);
+ if(len < -1) {
+ ALOGE ("%s:not able to write into %s node %s",
+ __FUNCTION__, IDLE_TIME_PATH, strerror(errno));
+ close(mTimeoutEventFd);
+ mTimeoutEventFd = -1;
+ close(fd);
+ return -1;
+ }
+ close(fd);
+
+ //Triggers the threadLoop to run, if not already running.
+ run(threadName, android::PRIORITY_LOWEST);
return 0;
}
bool IdleInvalidator::threadLoop() {
- struct timeval lastUpdateTime;
- ALOGD_IF(II_DEBUG, "%s", __func__);
-
- {
- //If we are here, update(s) happened, i.e mSleepAgain is set
- Locker::Autolock _l(mLock);
- mSleepAgain = false;
- lastUpdateTime = mLastUpdateTime;
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
+ struct pollfd pFd;
+ pFd.fd = mTimeoutEventFd;
+ if (pFd.fd >= 0)
+ pFd.events = POLLPRI | POLLERR;
+ // Poll for an timeout event from driver
+ int err = poll(&pFd, 1, -1);
+ if(err > 0) {
+ if (pFd.revents & POLLPRI) {
+ char data[64];
+ // Consume the node by reading it
+ ssize_t len = pread(pFd.fd, data, 64, 0);
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s Idle Timeout fired len %zu",
+ __FUNCTION__, len);
+ mHandler((void*)mHwcContext);
+ }
}
-
- struct timeval currentTime;
- gettimeofday(¤tTime, NULL);
- int timeSinceUpdateUs = (currentTime.tv_sec - lastUpdateTime.tv_sec) *
- 1000000 + (currentTime.tv_usec - lastUpdateTime.tv_usec);
- int sleepDurationUs = mSleepTime * 1000 - timeSinceUpdateUs;
-
- //Sleep only if the duration required is > 1ms, otherwise its not worth it.
- if(sleepDurationUs > 1000) {
- usleep(sleepDurationUs);
- ALOGD_IF(II_DEBUG, "Slept for %d ms", sleepDurationUs / 1000);
- }
-
- Locker::Autolock _l(mLock);
- //If an update happened while we were asleep, sleep again
- if(mSleepAgain) {
- //We need to sleep again!
- mSleepAgain = false;
- return true;
- }
-
-#if II_DEBUG
- gettimeofday(¤tTime, NULL);
- timeSinceUpdateUs = (currentTime.tv_sec - lastUpdateTime.tv_sec) *
- 1000000 + (currentTime.tv_usec - lastUpdateTime.tv_usec);
- ALOGD("Idle refresh after %dms", timeSinceUpdateUs / 1000);
-#endif
-
- mHandler((void*)mHwcContext);
- return false;
+ return true;
}
int IdleInvalidator::readyToRun() {
- ALOGD_IF(II_DEBUG, "%s", __func__);
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
return 0; /*NO_ERROR*/
}
void IdleInvalidator::onFirstRef() {
- ALOGD_IF(II_DEBUG, "%s", __func__);
-}
-
-void IdleInvalidator::handleUpdateEvent() {
- Locker::Autolock _l(mLock);
- gettimeofday(&mLastUpdateTime, NULL);
- mSleepAgain = true;
- //Triggers the threadLoop to run, if not already running.
- run(threadName, android::PRIORITY_AUDIO);
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
}
IdleInvalidator *IdleInvalidator::getInstance() {
- ALOGD_IF(II_DEBUG, "%s", __func__);
+ ALOGD_IF(II_DEBUG, "IdleInvalidator::%s", __FUNCTION__);
if(sInstance.get() == NULL)
sInstance = new IdleInvalidator();
return sInstance.get();
diff --git a/libqdutils/idle_invalidator.h b/libqdutils/idle_invalidator.h
index f41c15e..a881c4b 100644
--- a/libqdutils/idle_invalidator.h
+++ b/libqdutils/idle_invalidator.h
@@ -38,19 +38,15 @@
class IdleInvalidator : public android::Thread {
void *mHwcContext;
- struct timeval mLastUpdateTime;
- bool mSleepAgain;
- unsigned int mSleepTime;
+ int mTimeoutEventFd;
static InvalidatorHandler mHandler;
static android::sp<IdleInvalidator> sInstance;
- mutable Locker mLock;
public:
IdleInvalidator();
/* init timer obj */
int init(InvalidatorHandler reg_handler, void* user_data, unsigned int
idleSleepTime);
- void handleUpdateEvent();
/*Overrides*/
virtual bool threadLoop();
virtual int readyToRun();