Add timeout when waiting for HW vsync

This way we don't get stuck if, say, the driver decides not
to send us vsync events.

Change-Id: I4af6358b3a1f304eaae5fd926ed3403fa1091827
This commit is contained in:
Andy McFadden 2012-08-30 16:34:41 -07:00
parent 72f096fb1a
commit 6bf552ee02

View File

@ -140,6 +140,8 @@ bool EventThread::threadLoop() {
return true; return true;
} }
// This will return when (1) a vsync event has been received, and (2) there was
// at least one connection interested in receiving it when we started waiting.
Vector< sp<EventThread::Connection> > EventThread::waitForEvent( Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
DisplayEventReceiver::Event* event) DisplayEventReceiver::Event* event)
{ {
@ -193,31 +195,54 @@ Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
// don't report it, and disable VSYNC events // don't report it, and disable VSYNC events
disableVSyncLocked(); disableVSyncLocked();
} else if (!timestamp && waitForVSync) { } else if (!timestamp && waitForVSync) {
// we have at least one client, so we want vsync enabled
// (TODO: this function is called right after we finish
// notifying clients of a vsync, so this call will be made
// at the vsync rate, e.g. 60fps. If we can accurately
// track the current state we could avoid making this call
// so often.)
enableVSyncLocked(); enableVSyncLocked();
} }
// note: !timestamp implies signalConnections.isEmpty() // note: !timestamp implies signalConnections.isEmpty(), because we
// don't populate signalConnections if there's no vsync pending
if (!timestamp) { if (!timestamp) {
// wait for something to happen // wait for something to happen
if (CC_UNLIKELY(mUseSoftwareVSync && waitForVSync)) { if (waitForVSync) {
// h/w vsync cannot be used (screen is off), so we use // This is where we spend most of our time, waiting
// a timeout instead. it doesn't matter how imprecise this // for vsync events and new client registrations.
// is, we just need to make sure to serve the clients //
if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) { // If the screen is off, we can't use h/w vsync, so we
// use a 16ms timeout instead. It doesn't need to be
// precise, we just need to keep feeding our clients.
//
// We don't want to stall if there's a driver bug, so we
// use a (long) timeout when waiting for h/w vsync, and
// generate fake events when necessary.
bool softwareSync = mUseSoftwareVSync;
nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
if (!softwareSync) {
ALOGW("Timed out waiting for hw vsync; faking it");
}
mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
mVSyncCount++; mVSyncCount++;
} }
} else { } else {
// This is where we spend most of our time, waiting // Nobody is interested in vsync, so we just want to sleep.
// for a vsync events and registered clients // h/w vsync should be disabled, so this will wait until we
// get a new connection, or an existing connection becomes
// interested in receiving vsync again.
mCondition.wait(mLock); mCondition.wait(mLock);
} }
} }
} while (signalConnections.isEmpty()); } while (signalConnections.isEmpty());
// here we're guaranteed to have a timestamp and some connections to signal // here we're guaranteed to have a timestamp and some connections to signal
// (The connections might have dropped out of mDisplayEventConnections
// while we were asleep, but we'll still have strong references to them.)
// dispatch vsync events to listeners... // fill in vsync event info
event->header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; event->header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
event->header.timestamp = timestamp; event->header.timestamp = timestamp;
event->vsync.count = vsyncCount; event->vsync.count = vsyncCount;