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