EventThread.cpp revision cb9732a951d20cacb7ebe2dab132b5738226b1b6
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 35namespace android { 36 37// --------------------------------------------------------------------------- 38 39EventThread::EventThread(const sp<SurfaceFlinger>& flinger) 40 : mFlinger(flinger), 41 mHw(flinger->graphicPlane(0).displayHardware()), 42 mLastVSyncTimestamp(0), 43 mDeliveredEvents(0) 44{ 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 55nsecs_t EventThread::getLastVSyncTimestamp() const { 56 Mutex::Autolock _l(mLock); 57 return mLastVSyncTimestamp; 58} 59 60nsecs_t EventThread::getVSyncPeriod() const { 61 return mHw.getRefreshPeriod(); 62 63} 64 65status_t EventThread::registerDisplayEventConnection( 66 const sp<EventThread::Connection>& connection) { 67 Mutex::Autolock _l(mLock); 68 mDisplayEventConnections.add(connection); 69 mCondition.signal(); 70 return NO_ERROR; 71} 72 73status_t EventThread::unregisterDisplayEventConnection( 74 const wp<EventThread::Connection>& connection) { 75 Mutex::Autolock _l(mLock); 76 mDisplayEventConnections.remove(connection); 77 mCondition.signal(); 78 return NO_ERROR; 79} 80 81void EventThread::removeDisplayEventConnection( 82 const wp<EventThread::Connection>& connection) { 83 Mutex::Autolock _l(mLock); 84 mDisplayEventConnections.remove(connection); 85} 86 87void EventThread::setVsyncRate(uint32_t count, 88 const sp<EventThread::Connection>& connection) { 89 if (int32_t(count) >= 0) { // server must protect against bad params 90 Mutex::Autolock _l(mLock); 91 const int32_t new_count = (count == 0) ? -1 : count; 92 if (connection->count != new_count) { 93 connection->count = new_count; 94 mCondition.signal(); 95 } 96 } 97} 98 99void EventThread::requestNextVsync( 100 const sp<EventThread::Connection>& connection) { 101 Mutex::Autolock _l(mLock); 102 if (connection->count < 0) { 103 connection->count = 0; 104 mCondition.signal(); 105 } 106} 107 108bool EventThread::threadLoop() { 109 110 nsecs_t timestamp; 111 DisplayEventReceiver::Event vsync; 112 Vector< wp<EventThread::Connection> > displayEventConnections; 113 114 { // scope for the lock 115 Mutex::Autolock _l(mLock); 116 do { 117 // see if we need to wait for the VSYNC at all 118 do { 119 bool waitForNextVsync = false; 120 size_t count = mDisplayEventConnections.size(); 121 for (size_t i=0 ; i<count ; i++) { 122 sp<Connection> connection = 123 mDisplayEventConnections.itemAt(i).promote(); 124 if (connection!=0 && connection->count >= 0) { 125 // at least one continuous mode or active one-shot event 126 waitForNextVsync = true; 127 break; 128 } 129 } 130 131 if (waitForNextVsync) 132 break; 133 134 mCondition.wait(mLock); 135 } while(true); 136 137 // at least one listener requested VSYNC 138 mLock.unlock(); 139 timestamp = mHw.waitForRefresh(); 140 ATRACE_INT("VSYNC", mDeliveredEvents&1); 141 mLock.lock(); 142 mDeliveredEvents++; 143 mLastVSyncTimestamp = timestamp; 144 145 // now see if we still need to report this VSYNC event 146 const size_t count = mDisplayEventConnections.size(); 147 for (size_t i=0 ; i<count ; i++) { 148 bool reportVsync = false; 149 sp<Connection> connection = 150 mDisplayEventConnections.itemAt(i).promote(); 151 if (connection == 0) 152 continue; 153 154 const int32_t count = connection->count; 155 if (count >= 1) { 156 if (count==1 || (mDeliveredEvents % count) == 0) { 157 // continuous event, and time to report it 158 reportVsync = true; 159 } 160 } else if (count >= -1) { 161 if (count == 0) { 162 // fired this time around 163 reportVsync = true; 164 } 165 connection->count--; 166 } 167 if (reportVsync) { 168 displayEventConnections.add(connection); 169 } 170 } 171 } while (!displayEventConnections.size()); 172 173 // dispatch vsync events to listeners... 174 vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; 175 vsync.header.timestamp = timestamp; 176 vsync.vsync.count = mDeliveredEvents; 177 } 178 179 const size_t count = displayEventConnections.size(); 180 for (size_t i=0 ; i<count ; i++) { 181 sp<Connection> conn(displayEventConnections[i].promote()); 182 // make sure the connection didn't die 183 if (conn != NULL) { 184 status_t err = conn->postEvent(vsync); 185 if (err == -EAGAIN || err == -EWOULDBLOCK) { 186 // The destination doesn't accept events anymore, it's probably 187 // full. For now, we just drop the events on the floor. 188 // Note that some events cannot be dropped and would have to be 189 // re-sent later. Right-now we don't have the ability to do 190 // this, but it doesn't matter for VSYNC. 191 } else if (err < 0) { 192 // handle any other error on the pipe as fatal. the only 193 // reasonable thing to do is to clean-up this connection. 194 // The most common error we'll get here is -EPIPE. 195 removeDisplayEventConnection(displayEventConnections[i]); 196 } 197 } else { 198 // somehow the connection is dead, but we still have it in our list 199 // just clean the list. 200 removeDisplayEventConnection(displayEventConnections[i]); 201 } 202 } 203 204 // clear all our references without holding mLock 205 displayEventConnections.clear(); 206 207 return true; 208} 209 210status_t EventThread::readyToRun() { 211 ALOGI("EventThread ready to run."); 212 return NO_ERROR; 213} 214 215void EventThread::dump(String8& result, char* buffer, size_t SIZE) const { 216 Mutex::Autolock _l(mLock); 217 result.append("VSYNC state:\n"); 218 snprintf(buffer, SIZE, " numListeners=%u, events-delivered: %u\n", 219 mDisplayEventConnections.size(), mDeliveredEvents); 220 result.append(buffer); 221} 222 223// --------------------------------------------------------------------------- 224 225EventThread::Connection::Connection( 226 const sp<EventThread>& eventThread) 227 : count(-1), mEventThread(eventThread), mChannel(new BitTube()) 228{ 229} 230 231EventThread::Connection::~Connection() { 232 mEventThread->unregisterDisplayEventConnection(this); 233} 234 235void EventThread::Connection::onFirstRef() { 236 // NOTE: mEventThread doesn't hold a strong reference on us 237 mEventThread->registerDisplayEventConnection(this); 238} 239 240sp<BitTube> EventThread::Connection::getDataChannel() const { 241 return mChannel; 242} 243 244void EventThread::Connection::setVsyncRate(uint32_t count) { 245 mEventThread->setVsyncRate(count, this); 246} 247 248void EventThread::Connection::requestNextVsync() { 249 mEventThread->requestNextVsync(this); 250} 251 252status_t EventThread::Connection::postEvent( 253 const DisplayEventReceiver::Event& event) { 254 ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1); 255 return size < 0 ? status_t(size) : status_t(NO_ERROR); 256} 257 258// --------------------------------------------------------------------------- 259 260}; // namespace android 261