diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index 9b61fa9a6..3833f4839 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -36,10 +36,9 @@ namespace android { EventThread::EventThread(const sp& flinger) : mFlinger(flinger), - mLastVSyncTimestamp(0), mVSyncTimestamp(0), mUseSoftwareVSync(false), - mDeliveredEvents(0), + mVSyncCount(0), mDebugVsyncEnabled(false) { } @@ -116,133 +115,122 @@ void EventThread::onScreenAcquired() { void EventThread::onVSyncReceived(int, nsecs_t timestamp) { Mutex::Autolock _l(mLock); mVSyncTimestamp = timestamp; + mVSyncCount++; mCondition.broadcast(); } bool EventThread::threadLoop() { nsecs_t timestamp; + size_t vsyncCount; + size_t activeEvents; DisplayEventReceiver::Event vsync; - Vector< wp > displayEventConnections; + Vector< sp > activeConnections; do { Mutex::Autolock _l(mLock); - do { - // latch VSYNC event if any - timestamp = mVSyncTimestamp; - mVSyncTimestamp = 0; + // latch VSYNC event if any + timestamp = mVSyncTimestamp; + mVSyncTimestamp = 0; - // check if we should be waiting for VSYNC events - bool waitForNextVsync = false; - size_t count = mDisplayEventConnections.size(); - for (size_t i=0 ; i connection = - mDisplayEventConnections.itemAt(i).promote(); - if (connection!=0 && connection->count >= 0) { + // check if we should be waiting for VSYNC events + activeEvents = 0; + bool waitForNextVsync = false; + size_t count = mDisplayEventConnections.size(); + for (size_t i=0 ; i connection(mDisplayEventConnections[i].promote()); + if (connection != NULL) { + activeConnections.add(connection); + if (connection->count >= 0) { // at least one continuous mode or active one-shot event waitForNextVsync = true; + activeEvents++; break; } } - - if (timestamp) { - if (!waitForNextVsync) { - // we received a VSYNC but we have no clients - // don't report it, and disable VSYNC events - disableVSyncLocked(); - } else { - // report VSYNC event - break; - } - } else { - // never disable VSYNC events immediately, instead - // we'll wait to receive the event and we'll - // reevaluate whether we need to dispatch it and/or - // disable VSYNC events then. - if (waitForNextVsync) { - // enable - enableVSyncLocked(); - } - } - - // wait for something to happen - if (mUseSoftwareVSync && waitForNextVsync) { - // h/w vsync cannot be used (screen is off), so we use - // a timeout instead. it doesn't matter how imprecise this - // is, we just need to make sure to serve the clients - if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) { - mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); - } - } else { - mCondition.wait(mLock); - } - } while(true); - - // process vsync event - mDeliveredEvents++; - mLastVSyncTimestamp = timestamp; - - // now see if we still need to report this VSYNC event - const size_t count = mDisplayEventConnections.size(); - for (size_t i=0 ; i connection = - mDisplayEventConnections.itemAt(i).promote(); - if (connection == 0) - continue; - - const int32_t count = connection->count; - if (count >= 1) { - if (count==1 || (mDeliveredEvents % count) == 0) { - // continuous event, and time to report it - reportVsync = true; - } - } else if (count >= -1) { - if (count == 0) { - // fired this time around - reportVsync = true; - } - connection->count--; - } - if (reportVsync) { - displayEventConnections.add(connection); - } } - } while (!displayEventConnections.size()); + + if (timestamp) { + if (!waitForNextVsync) { + // we received a VSYNC but we have no clients + // don't report it, and disable VSYNC events + disableVSyncLocked(); + } else { + // report VSYNC event + break; + } + } else { + // never disable VSYNC events immediately, instead + // we'll wait to receive the event and we'll + // reevaluate whether we need to dispatch it and/or + // disable VSYNC events then. + if (waitForNextVsync) { + // enable + enableVSyncLocked(); + } + } + + // wait for something to happen + if (mUseSoftwareVSync && waitForNextVsync) { + // h/w vsync cannot be used (screen is off), so we use + // a timeout instead. it doesn't matter how imprecise this + // is, we just need to make sure to serve the clients + if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) { + mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); + mVSyncCount++; + } + } else { + mCondition.wait(mLock); + } + vsyncCount = mVSyncCount; + } while (!activeConnections.size()); + + if (!activeEvents) { + // no events to return. start over. + // (here we make sure to exit the scope of this function + // so that we release our Connection references) + return true; + } // dispatch vsync events to listeners... vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; vsync.header.timestamp = timestamp; - vsync.vsync.count = mDeliveredEvents; + vsync.vsync.count = vsyncCount; - const size_t count = displayEventConnections.size(); + const size_t count = activeConnections.size(); for (size_t i=0 ; i conn(displayEventConnections[i].promote()); - // make sure the connection didn't die - if (conn != NULL) { - status_t err = conn->postEvent(vsync); - if (err == -EAGAIN || err == -EWOULDBLOCK) { - // The destination doesn't accept events anymore, it's probably - // full. For now, we just drop the events on the floor. - // Note that some events cannot be dropped and would have to be - // re-sent later. Right-now we don't have the ability to do - // this, but it doesn't matter for VSYNC. - } else if (err < 0) { - // handle any other error on the pipe as fatal. the only - // reasonable thing to do is to clean-up this connection. - // The most common error we'll get here is -EPIPE. - removeDisplayEventConnection(displayEventConnections[i]); + const sp& conn(activeConnections[i]); + // now see if we still need to report this VSYNC event + const int32_t vcount = conn->count; + if (vcount >= 0) { + bool reportVsync = false; + if (vcount == 0) { + // fired this time around + conn->count = -1; + reportVsync = true; + } else if (vcount == 1 || (vsyncCount % vcount) == 0) { + // continuous event, and time to report it + reportVsync = true; + } + + if (reportVsync) { + status_t err = conn->postEvent(vsync); + if (err == -EAGAIN || err == -EWOULDBLOCK) { + // The destination doesn't accept events anymore, it's probably + // full. For now, we just drop the events on the floor. + // Note that some events cannot be dropped and would have to be + // re-sent later. Right-now we don't have the ability to do + // this, but it doesn't matter for VSYNC. + } else if (err < 0) { + // handle any other error on the pipe as fatal. the only + // reasonable thing to do is to clean-up this connection. + // The most common error we'll get here is -EPIPE. + removeDisplayEventConnection(activeConnections[i]); + } } - } else { - // somehow the connection is dead, but we still have it in our list - // just clean the list. - removeDisplayEventConnection(displayEventConnections[i]); } } - // clear all our references without holding mLock - displayEventConnections.clear(); - return true; } @@ -273,7 +261,7 @@ void EventThread::dump(String8& result, char* buffer, size_t SIZE) const { result.appendFormat(" soft-vsync: %s\n", mUseSoftwareVSync?"enabled":"disabled"); result.appendFormat(" numListeners=%u,\n events-delivered: %u\n", - mDisplayEventConnections.size(), mDeliveredEvents); + mDisplayEventConnections.size(), mVSyncCount); for (size_t i=0 ; i connection = mDisplayEventConnections.itemAt(i).promote(); diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h index a71d98567..d23b9fad9 100644 --- a/services/surfaceflinger/EventThread.h +++ b/services/surfaceflinger/EventThread.h @@ -100,12 +100,9 @@ private: // protected by mLock SortedVector< wp > mDisplayEventConnections; - nsecs_t mLastVSyncTimestamp; nsecs_t mVSyncTimestamp; bool mUseSoftwareVSync; - - // main thread only - size_t mDeliveredEvents; + size_t mVSyncCount; // for debugging bool mDebugVsyncEnabled;