EventThread.cpp revision 921e6ac4b7610a178285898d191eb0e3afe906c0
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 : mHw(const_cast<DisplayHardware&>(flinger->getDefaultDisplayHardware())), // XXX: eventthread will need rework 40 mLastVSyncTimestamp(0), 41 mVSyncTimestamp(0), 42 mUseSoftwareVSync(false), 43 mDeliveredEvents(0), 44 mDebugVsyncEnabled(false) { 45} 46 47void EventThread::onFirstRef() { 48 mHw.setVSyncHandler(this); 49 run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE); 50} 51 52sp<EventThread::Connection> EventThread::createEventConnection() const { 53 return new Connection(const_cast<EventThread*>(this)); 54} 55 56status_t EventThread::registerDisplayEventConnection( 57 const sp<EventThread::Connection>& connection) { 58 Mutex::Autolock _l(mLock); 59 mDisplayEventConnections.add(connection); 60 mCondition.broadcast(); 61 return NO_ERROR; 62} 63 64status_t EventThread::unregisterDisplayEventConnection( 65 const wp<EventThread::Connection>& connection) { 66 Mutex::Autolock _l(mLock); 67 mDisplayEventConnections.remove(connection); 68 mCondition.broadcast(); 69 return NO_ERROR; 70} 71 72void EventThread::removeDisplayEventConnection( 73 const wp<EventThread::Connection>& connection) { 74 Mutex::Autolock _l(mLock); 75 mDisplayEventConnections.remove(connection); 76} 77 78void EventThread::setVsyncRate(uint32_t count, 79 const sp<EventThread::Connection>& connection) { 80 if (int32_t(count) >= 0) { // server must protect against bad params 81 Mutex::Autolock _l(mLock); 82 const int32_t new_count = (count == 0) ? -1 : count; 83 if (connection->count != new_count) { 84 connection->count = new_count; 85 mCondition.broadcast(); 86 } 87 } 88} 89 90void EventThread::requestNextVsync( 91 const sp<EventThread::Connection>& connection) { 92 Mutex::Autolock _l(mLock); 93 if (connection->count < 0) { 94 connection->count = 0; 95 mCondition.broadcast(); 96 } 97} 98 99void EventThread::onScreenReleased() { 100 Mutex::Autolock _l(mLock); 101 if (!mUseSoftwareVSync) { 102 // disable reliance on h/w vsync 103 mUseSoftwareVSync = true; 104 mCondition.broadcast(); 105 } 106} 107 108void EventThread::onScreenAcquired() { 109 Mutex::Autolock _l(mLock); 110 if (mUseSoftwareVSync) { 111 // resume use of h/w vsync 112 mUseSoftwareVSync = false; 113 mCondition.broadcast(); 114 } 115} 116 117 118void EventThread::onVSyncReceived(int, nsecs_t timestamp) { 119 Mutex::Autolock _l(mLock); 120 mVSyncTimestamp = timestamp; 121 mCondition.broadcast(); 122} 123 124bool EventThread::threadLoop() { 125 126 nsecs_t timestamp; 127 DisplayEventReceiver::Event vsync; 128 Vector< wp<EventThread::Connection> > displayEventConnections; 129 130 do { 131 Mutex::Autolock _l(mLock); 132 do { 133 // latch VSYNC event if any 134 timestamp = mVSyncTimestamp; 135 mVSyncTimestamp = 0; 136 137 // check if we should be waiting for VSYNC events 138 bool waitForNextVsync = false; 139 size_t count = mDisplayEventConnections.size(); 140 for (size_t i=0 ; i<count ; i++) { 141 sp<Connection> connection = 142 mDisplayEventConnections.itemAt(i).promote(); 143 if (connection!=0 && connection->count >= 0) { 144 // at least one continuous mode or active one-shot event 145 waitForNextVsync = true; 146 break; 147 } 148 } 149 150 if (timestamp) { 151 if (!waitForNextVsync) { 152 // we received a VSYNC but we have no clients 153 // don't report it, and disable VSYNC events 154 disableVSyncLocked(); 155 } else { 156 // report VSYNC event 157 break; 158 } 159 } else { 160 // never disable VSYNC events immediately, instead 161 // we'll wait to receive the event and we'll 162 // reevaluate whether we need to dispatch it and/or 163 // disable VSYNC events then. 164 if (waitForNextVsync) { 165 // enable 166 enableVSyncLocked(); 167 } 168 } 169 170 // wait for something to happen 171 if (mUseSoftwareVSync && waitForNextVsync) { 172 // h/w vsync cannot be used (screen is off), so we use 173 // a timeout instead. it doesn't matter how imprecise this 174 // is, we just need to make sure to serve the clients 175 if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) { 176 mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC); 177 } 178 } else { 179 mCondition.wait(mLock); 180 } 181 } while(true); 182 183 // process vsync event 184 mDeliveredEvents++; 185 mLastVSyncTimestamp = timestamp; 186 187 // now see if we still need to report this VSYNC event 188 const size_t count = mDisplayEventConnections.size(); 189 for (size_t i=0 ; i<count ; i++) { 190 bool reportVsync = false; 191 sp<Connection> connection = 192 mDisplayEventConnections.itemAt(i).promote(); 193 if (connection == 0) 194 continue; 195 196 const int32_t count = connection->count; 197 if (count >= 1) { 198 if (count==1 || (mDeliveredEvents % count) == 0) { 199 // continuous event, and time to report it 200 reportVsync = true; 201 } 202 } else if (count >= -1) { 203 if (count == 0) { 204 // fired this time around 205 reportVsync = true; 206 } 207 connection->count--; 208 } 209 if (reportVsync) { 210 displayEventConnections.add(connection); 211 } 212 } 213 } while (!displayEventConnections.size()); 214 215 // dispatch vsync events to listeners... 216 vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; 217 vsync.header.timestamp = timestamp; 218 vsync.vsync.count = mDeliveredEvents; 219 220 const size_t count = displayEventConnections.size(); 221 for (size_t i=0 ; i<count ; i++) { 222 sp<Connection> conn(displayEventConnections[i].promote()); 223 // make sure the connection didn't die 224 if (conn != NULL) { 225 status_t err = conn->postEvent(vsync); 226 if (err == -EAGAIN || err == -EWOULDBLOCK) { 227 // The destination doesn't accept events anymore, it's probably 228 // full. For now, we just drop the events on the floor. 229 // Note that some events cannot be dropped and would have to be 230 // re-sent later. Right-now we don't have the ability to do 231 // this, but it doesn't matter for VSYNC. 232 } else if (err < 0) { 233 // handle any other error on the pipe as fatal. the only 234 // reasonable thing to do is to clean-up this connection. 235 // The most common error we'll get here is -EPIPE. 236 removeDisplayEventConnection(displayEventConnections[i]); 237 } 238 } else { 239 // somehow the connection is dead, but we still have it in our list 240 // just clean the list. 241 removeDisplayEventConnection(displayEventConnections[i]); 242 } 243 } 244 245 // clear all our references without holding mLock 246 displayEventConnections.clear(); 247 248 return true; 249} 250 251void EventThread::enableVSyncLocked() { 252 if (!mUseSoftwareVSync) { 253 // never enable h/w VSYNC when screen is off 254 mHw.eventControl(DisplayHardware::EVENT_VSYNC, true); 255 } 256 mDebugVsyncEnabled = true; 257} 258 259void EventThread::disableVSyncLocked() { 260 mHw.eventControl(DisplayHardware::EVENT_VSYNC, 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