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