EventThread.cpp revision a4cb35a2864d58e9a764a17623e15ab25a9964a0
1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define ATRACE_TAG ATRACE_TAG_GRAPHICS 18 19#include <stdint.h> 20#include <sys/types.h> 21 22#include <cutils/compiler.h> 23 24#include <gui/BitTube.h> 25#include <gui/IDisplayEventConnection.h> 26#include <gui/DisplayEventReceiver.h> 27 28#include <utils/Errors.h> 29#include <utils/String8.h> 30#include <utils/Trace.h> 31 32#include "EventThread.h" 33#include "SurfaceFlinger.h" 34 35// --------------------------------------------------------------------------- 36namespace android { 37// --------------------------------------------------------------------------- 38 39EventThread::EventThread(const sp<SurfaceFlinger>& flinger) 40 : mFlinger(flinger), 41 mVSyncTimestamp(0), 42 mUseSoftwareVSync(false), 43 mVSyncCount(0), 44 mDebugVsyncEnabled(false) { 45} 46 47void EventThread::onFirstRef() { 48 run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); 49} 50 51sp<EventThread::Connection> EventThread::createEventConnection() const { 52 return new Connection(const_cast<EventThread*>(this)); 53} 54 55status_t EventThread::registerDisplayEventConnection( 56 const sp<EventThread::Connection>& connection) { 57 Mutex::Autolock _l(mLock); 58 mDisplayEventConnections.add(connection); 59 mCondition.broadcast(); 60 return NO_ERROR; 61} 62 63status_t EventThread::unregisterDisplayEventConnection( 64 const wp<EventThread::Connection>& connection) { 65 Mutex::Autolock _l(mLock); 66 mDisplayEventConnections.remove(connection); 67 mCondition.broadcast(); 68 return NO_ERROR; 69} 70 71void EventThread::removeDisplayEventConnection( 72 const wp<EventThread::Connection>& connection) { 73 Mutex::Autolock _l(mLock); 74 mDisplayEventConnections.remove(connection); 75} 76 77void EventThread::setVsyncRate(uint32_t count, 78 const sp<EventThread::Connection>& connection) { 79 if (int32_t(count) >= 0) { // server must protect against bad params 80 Mutex::Autolock _l(mLock); 81 const int32_t new_count = (count == 0) ? -1 : count; 82 if (connection->count != new_count) { 83 connection->count = new_count; 84 mCondition.broadcast(); 85 } 86 } 87} 88 89void EventThread::requestNextVsync( 90 const sp<EventThread::Connection>& connection) { 91 Mutex::Autolock _l(mLock); 92 if (connection->count < 0) { 93 connection->count = 0; 94 mCondition.broadcast(); 95 } 96} 97 98void EventThread::onScreenReleased() { 99 Mutex::Autolock _l(mLock); 100 if (!mUseSoftwareVSync) { 101 // disable reliance on h/w vsync 102 mUseSoftwareVSync = true; 103 mCondition.broadcast(); 104 } 105} 106 107void EventThread::onScreenAcquired() { 108 Mutex::Autolock _l(mLock); 109 if (mUseSoftwareVSync) { 110 // resume use of h/w vsync 111 mUseSoftwareVSync = false; 112 mCondition.broadcast(); 113 } 114} 115 116 117void EventThread::onVSyncReceived(int, nsecs_t timestamp) { 118 Mutex::Autolock _l(mLock); 119 mVSyncTimestamp = timestamp; 120 mVSyncCount++; 121 mCondition.broadcast(); 122} 123 124bool EventThread::threadLoop() { 125 126 nsecs_t timestamp; 127 size_t vsyncCount; 128 DisplayEventReceiver::Event vsync; 129 Vector< sp<EventThread::Connection> > activeConnections; 130 Vector< sp<EventThread::Connection> > signalConnections; 131 132 do { 133 // release our references 134 signalConnections.clear(); 135 activeConnections.clear(); 136 137 Mutex::Autolock _l(mLock); 138 139 // latch VSYNC event if any 140 bool waitForVSync = false; 141 vsyncCount = mVSyncCount; 142 timestamp = mVSyncTimestamp; 143 mVSyncTimestamp = 0; 144 145 // find out connections waiting for VSYNC events 146 size_t count = mDisplayEventConnections.size(); 147 for (size_t i=0 ; i<count ; i++) { 148 sp<Connection> connection(mDisplayEventConnections[i].promote()); 149 if (connection != NULL) { 150 activeConnections.add(connection); 151 if (connection->count >= 0) { 152 // we need vsync events because at least 153 // one connection is waiting for it 154 waitForVSync = true; 155 if (connection->count == 0) { 156 // fired this time around 157 if (timestamp) { 158 // only "consume" this event if we're going to 159 // report it 160 connection->count = -1; 161 } 162 signalConnections.add(connection); 163 } else if (connection->count == 1 || 164 (vsyncCount % connection->count) == 0) { 165 // continuous event, and time to report it 166 signalConnections.add(connection); 167 } 168 } 169 } 170 } 171 172 if (timestamp) { 173 // we have a vsync event we can dispatch 174 if (!waitForVSync) { 175 // we received a VSYNC but we have no clients 176 // don't report it, and disable VSYNC events 177 disableVSyncLocked(); 178 } else { 179 // report VSYNC event 180 break; 181 } 182 } else { 183 // never disable VSYNC events immediately, instead 184 // we'll wait to receive the event and we'll 185 // reevaluate whether we need to dispatch it and/or 186 // disable VSYNC events then. 187 if (waitForVSync) { 188 // enable 189 enableVSyncLocked(); 190 } 191 } 192 193 // wait for something to happen 194 if (CC_UNLIKELY(mUseSoftwareVSync && waitForVSync)) { 195 // h/w vsync cannot be used (screen is off), so we use 196 // a timeout instead. it doesn't matter how imprecise this 197 // is, we just need to make sure to serve the clients 198 if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) { 199 mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); 200 mVSyncCount++; 201 } 202 } else { 203 if (!timestamp || signalConnections.isEmpty()) { 204 // This is where we spend most of our time, waiting 205 // for a vsync events and registered clients 206 mCondition.wait(mLock); 207 } 208 } 209 } while (!timestamp || signalConnections.isEmpty()); 210 211 // dispatch vsync events to listeners... 212 vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; 213 vsync.header.timestamp = timestamp; 214 vsync.vsync.count = vsyncCount; 215 216 const size_t count = signalConnections.size(); 217 for (size_t i=0 ; i<count ; i++) { 218 const sp<Connection>& conn(signalConnections[i]); 219 // now see if we still need to report this VSYNC event 220 status_t err = conn->postEvent(vsync); 221 if (err == -EAGAIN || err == -EWOULDBLOCK) { 222 // The destination doesn't accept events anymore, it's probably 223 // full. For now, we just drop the events on the floor. 224 // Note that some events cannot be dropped and would have to be 225 // re-sent later. Right-now we don't have the ability to do 226 // this, but it doesn't matter for VSYNC. 227 } else if (err < 0) { 228 // handle any other error on the pipe as fatal. the only 229 // reasonable thing to do is to clean-up this connection. 230 // The most common error we'll get here is -EPIPE. 231 removeDisplayEventConnection(signalConnections[i]); 232 } 233 } 234 235 return true; 236} 237 238void EventThread::enableVSyncLocked() { 239 if (!mUseSoftwareVSync) { 240 // never enable h/w VSYNC when screen is off 241 mFlinger->eventControl(SurfaceFlinger::EVENT_VSYNC, true); 242 mPowerHAL.vsyncHint(true); 243 } 244 mDebugVsyncEnabled = true; 245} 246 247void EventThread::disableVSyncLocked() { 248 mFlinger->eventControl(SurfaceFlinger::EVENT_VSYNC, false); 249 mPowerHAL.vsyncHint(false); 250 mDebugVsyncEnabled = false; 251} 252 253status_t EventThread::readyToRun() { 254 ALOGI("EventThread ready to run."); 255 return NO_ERROR; 256} 257 258void EventThread::dump(String8& result, char* buffer, size_t SIZE) const { 259 Mutex::Autolock _l(mLock); 260 result.appendFormat("VSYNC state: %s\n", 261 mDebugVsyncEnabled?"enabled":"disabled"); 262 result.appendFormat(" soft-vsync: %s\n", 263 mUseSoftwareVSync?"enabled":"disabled"); 264 result.appendFormat(" numListeners=%u,\n events-delivered: %u\n", 265 mDisplayEventConnections.size(), mVSyncCount); 266 for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) { 267 sp<Connection> connection = 268 mDisplayEventConnections.itemAt(i).promote(); 269 result.appendFormat(" %p: count=%d\n", 270 connection.get(), connection!=NULL ? connection->count : 0); 271 } 272} 273 274// --------------------------------------------------------------------------- 275 276EventThread::Connection::Connection( 277 const sp<EventThread>& eventThread) 278 : count(-1), mEventThread(eventThread), mChannel(new BitTube()) 279{ 280} 281 282EventThread::Connection::~Connection() { 283 mEventThread->unregisterDisplayEventConnection(this); 284} 285 286void EventThread::Connection::onFirstRef() { 287 // NOTE: mEventThread doesn't hold a strong reference on us 288 mEventThread->registerDisplayEventConnection(this); 289} 290 291sp<BitTube> EventThread::Connection::getDataChannel() const { 292 return mChannel; 293} 294 295void EventThread::Connection::setVsyncRate(uint32_t count) { 296 mEventThread->setVsyncRate(count, this); 297} 298 299void EventThread::Connection::requestNextVsync() { 300 mEventThread->requestNextVsync(this); 301} 302 303status_t EventThread::Connection::postEvent( 304 const DisplayEventReceiver::Event& event) { 305 ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1); 306 return size < 0 ? status_t(size) : status_t(NO_ERROR); 307} 308 309// --------------------------------------------------------------------------- 310 311}; // namespace android 312