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