Home | History | Annotate | Download | only in surfaceflinger
      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