Merge "simplify further vsync handling" into jb-mr1-dev

This commit is contained in:
Mathias Agopian 2012-08-23 15:27:09 -07:00 committed by Android (Google) Code Review
commit 7c9e82633c
2 changed files with 91 additions and 98 deletions

View File

@ -60,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);
@ -122,97 +114,11 @@ void EventThread::onVSyncReceived(int, nsecs_t timestamp) {
}
bool EventThread::threadLoop() {
nsecs_t timestamp;
size_t vsyncCount;
DisplayEventReceiver::Event vsync;
Vector< sp<EventThread::Connection> > activeConnections;
Vector< sp<EventThread::Connection> > signalConnections;
do {
// release our references
signalConnections.clear();
activeConnections.clear();
Mutex::Autolock _l(mLock);
// latch VSYNC event if any
bool waitForVSync = false;
vsyncCount = mVSyncCount;
timestamp = mVSyncTimestamp;
mVSyncTimestamp = 0;
// find out connections waiting for VSYNC 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) {
// we need vsync events because at least
// one connection is waiting for it
waitForVSync = true;
if (connection->count == 0) {
// fired this time around
if (timestamp) {
// only "consume" this event if we're going to
// report it
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);
}
}
}
}
if (timestamp) {
// we have a vsync event we can dispatch
if (!waitForVSync) {
// 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 (waitForVSync) {
// enable
enableVSyncLocked();
}
}
// 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 {
if (!timestamp || signalConnections.isEmpty()) {
// This is where we spend most of our time, waiting
// for a vsync events and registered clients
mCondition.wait(mLock);
}
}
} while (!timestamp || signalConnections.isEmpty());
signalConnections = waitForEvent(&vsync);
// dispatch vsync events to listeners...
vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
vsync.header.timestamp = timestamp;
vsync.vsync.count = vsyncCount;
const size_t count = signalConnections.size();
for (size_t i=0 ; i<count ; i++) {
const sp<Connection>& conn(signalConnections[i]);
@ -231,10 +137,94 @@ bool EventThread::threadLoop() {
removeDisplayEventConnection(signalConnections[i]);
}
}
return true;
}
Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
DisplayEventReceiver::Event* event)
{
Mutex::Autolock _l(mLock);
size_t vsyncCount;
nsecs_t timestamp;
Vector< sp<EventThread::Connection> > signalConnections;
do {
// latch VSYNC event if any
bool waitForVSync = false;
vsyncCount = mVSyncCount;
timestamp = mVSyncTimestamp;
mVSyncTimestamp = 0;
// 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) {
if (connection->count >= 0) {
// 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;
}
}
// 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();
}
// 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);
}
}
} while (signalConnections.isEmpty());
// here we're guaranteed to have a timestamp and some connections to signal
// dispatch vsync events to listeners...
event->header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
event->header.timestamp = timestamp;
event->vsync.count = vsyncCount;
return signalConnections;
}
void EventThread::enableVSyncLocked() {
if (!mUseSoftwareVSync) {
// never enable h/w VSYNC when screen is off
@ -280,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() {

View File

@ -65,7 +65,6 @@ public:
sp<Connection> createEventConnection() const;
status_t registerDisplayEventConnection(const sp<Connection>& connection);
status_t unregisterDisplayEventConnection(const wp<Connection>& connection);
void setVsyncRate(uint32_t count, const sp<Connection>& connection);
void requestNextVsync(const sp<Connection>& connection);
@ -79,6 +78,9 @@ public:
// called when receiving a vsync event
void onVSyncReceived(int display, nsecs_t timestamp);
Vector< sp<EventThread::Connection> > waitForEvent(
DisplayEventReceiver::Event* event);
void dump(String8& result, char* buffer, size_t SIZE) const;
private: