diff options
Diffstat (limited to 'services/surfaceflinger/EventThread.cpp')
-rw-r--r-- | services/surfaceflinger/EventThread.cpp | 184 |
1 files changed, 88 insertions, 96 deletions
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index 3833f48..a39b7d8 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -19,6 +19,8 @@ #include <stdint.h> #include <sys/types.h> +#include <cutils/compiler.h> + #include <gui/BitTube.h> #include <gui/IDisplayEventConnection.h> #include <gui/DisplayEventReceiver.h> @@ -58,14 +60,6 @@ status_t EventThread::registerDisplayEventConnection( return NO_ERROR; } -status_t EventThread::unregisterDisplayEventConnection( - const wp<EventThread::Connection>& connection) { - Mutex::Autolock _l(mLock); - mDisplayEventConnections.remove(connection); - mCondition.broadcast(); - return NO_ERROR; -} - void EventThread::removeDisplayEventConnection( const wp<EventThread::Connection>& connection) { Mutex::Autolock _l(mLock); @@ -120,118 +114,115 @@ void EventThread::onVSyncReceived(int, nsecs_t timestamp) { } bool EventThread::threadLoop() { + DisplayEventReceiver::Event vsync; + Vector< sp<EventThread::Connection> > signalConnections; + signalConnections = waitForEvent(&vsync); + + // dispatch vsync events to listeners... + const size_t count = signalConnections.size(); + for (size_t i=0 ; i<count ; i++) { + const sp<Connection>& conn(signalConnections[i]); + // now see if we still need to report this VSYNC event + 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(signalConnections[i]); + } + } + return true; +} + +Vector< sp<EventThread::Connection> > EventThread::waitForEvent( + DisplayEventReceiver::Event* event) +{ + Mutex::Autolock _l(mLock); - nsecs_t timestamp; size_t vsyncCount; - size_t activeEvents; - DisplayEventReceiver::Event vsync; - Vector< sp<EventThread::Connection> > activeConnections; + nsecs_t timestamp; + Vector< sp<EventThread::Connection> > signalConnections; do { - Mutex::Autolock _l(mLock); // latch VSYNC event if any + bool waitForVSync = false; + vsyncCount = mVSyncCount; timestamp = mVSyncTimestamp; mVSyncTimestamp = 0; - // check if we should be waiting for VSYNC events - activeEvents = 0; - bool waitForNextVsync = false; + // find out connections waiting for events size_t count = mDisplayEventConnections.size(); for (size_t i=0 ; i<count ; i++) { sp<Connection> 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; + // we need vsync events because at least + // one connection is waiting for it + waitForVSync = true; + if (timestamp) { + // we consume the event only if it's time + // (ie: we received a vsync event) + if (connection->count == 0) { + // fired this time around + connection->count = -1; + signalConnections.add(connection); + } else if (connection->count == 1 || + (vsyncCount % connection->count) == 0) { + // continuous event, and time to report it + signalConnections.add(connection); + } + } } + } else { + // we couldn't promote this reference, the connection has + // died, so clean-up! + mDisplayEventConnections.removeAt(i); + --i; --count; } } - 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(); - } + // Here we figure out if we need to enable or disable vsyncs + if (timestamp && !waitForVSync) { + // we received a VSYNC but we have no clients + // don't report it, and disable VSYNC events + disableVSyncLocked(); + } else if (!timestamp && waitForVSync) { + 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++; + // note: !timestamp implies signalConnections.isEmpty() + if (!timestamp) { + // wait for something to happen + if (CC_UNLIKELY(mUseSoftwareVSync && waitForVSync)) { + // 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 { + // This is where we spend most of our time, waiting + // for a vsync events and registered clients + mCondition.wait(mLock); } - } else { - mCondition.wait(mLock); } - vsyncCount = mVSyncCount; - } while (!activeConnections.size()); + } while (signalConnections.isEmpty()); - 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; - } + // here we're guaranteed to have a timestamp and some connections to signal // dispatch vsync events to listeners... - vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; - vsync.header.timestamp = timestamp; - vsync.vsync.count = vsyncCount; + event->header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; + event->header.timestamp = timestamp; + event->vsync.count = vsyncCount; - const size_t count = activeConnections.size(); - for (size_t i=0 ; i<count ; i++) { - const sp<Connection>& 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]); - } - } - } - } - - return true; + return signalConnections; } void EventThread::enableVSyncLocked() { @@ -279,7 +270,8 @@ EventThread::Connection::Connection( } EventThread::Connection::~Connection() { - mEventThread->unregisterDisplayEventConnection(this); + // do nothing here -- clean-up will happen automatically + // when the main thread wakes up } void EventThread::Connection::onFirstRef() { |