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