EventThread.cpp revision ae2cfb5746e87f1bf17c446e20274c41ce0a57ce
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 <cutils/compiler.h>
23
24#include <gui/BitTube.h>
25#include <gui/IDisplayEventConnection.h>
26#include <gui/DisplayEventReceiver.h>
27
28#include <utils/Errors.h>
29#include <utils/String8.h>
30#include <utils/Trace.h>
31
32#include "EventThread.h"
33#include "SurfaceFlinger.h"
34
35// ---------------------------------------------------------------------------
36namespace android {
37// ---------------------------------------------------------------------------
38
39EventThread::EventThread(const sp<SurfaceFlinger>& flinger)
40    : mFlinger(flinger),
41      mVSyncTimestamp(0),
42      mUseSoftwareVSync(false),
43      mVSyncCount(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
63void EventThread::removeDisplayEventConnection(
64        const wp<EventThread::Connection>& connection) {
65    Mutex::Autolock _l(mLock);
66    mDisplayEventConnections.remove(connection);
67}
68
69void EventThread::setVsyncRate(uint32_t count,
70        const sp<EventThread::Connection>& connection) {
71    if (int32_t(count) >= 0) { // server must protect against bad params
72        Mutex::Autolock _l(mLock);
73        const int32_t new_count = (count == 0) ? -1 : count;
74        if (connection->count != new_count) {
75            connection->count = new_count;
76            mCondition.broadcast();
77        }
78    }
79}
80
81void EventThread::requestNextVsync(
82        const sp<EventThread::Connection>& connection) {
83    Mutex::Autolock _l(mLock);
84    if (connection->count < 0) {
85        connection->count = 0;
86        mCondition.broadcast();
87    }
88}
89
90void EventThread::onScreenReleased() {
91    Mutex::Autolock _l(mLock);
92    if (!mUseSoftwareVSync) {
93        // disable reliance on h/w vsync
94        mUseSoftwareVSync = true;
95        mCondition.broadcast();
96    }
97}
98
99void EventThread::onScreenAcquired() {
100    Mutex::Autolock _l(mLock);
101    if (mUseSoftwareVSync) {
102        // resume use of h/w vsync
103        mUseSoftwareVSync = false;
104        mCondition.broadcast();
105    }
106}
107
108
109void EventThread::onVSyncReceived(const wp<IBinder>&, nsecs_t timestamp) {
110    Mutex::Autolock _l(mLock);
111    mVSyncTimestamp = timestamp;
112    mVSyncCount++;
113    mCondition.broadcast();
114}
115
116bool EventThread::threadLoop() {
117    DisplayEventReceiver::Event vsync;
118    Vector< sp<EventThread::Connection> > signalConnections;
119    signalConnections = waitForEvent(&vsync);
120
121    // dispatch vsync events to listeners...
122    const size_t count = signalConnections.size();
123    for (size_t i=0 ; i<count ; i++) {
124        const sp<Connection>& conn(signalConnections[i]);
125        // now see if we still need to report this VSYNC event
126        status_t err = conn->postEvent(vsync);
127        if (err == -EAGAIN || err == -EWOULDBLOCK) {
128            // The destination doesn't accept events anymore, it's probably
129            // full. For now, we just drop the events on the floor.
130            // Note that some events cannot be dropped and would have to be
131            // re-sent later. Right-now we don't have the ability to do
132            // this, but it doesn't matter for VSYNC.
133        } else if (err < 0) {
134            // handle any other error on the pipe as fatal. the only
135            // reasonable thing to do is to clean-up this connection.
136            // The most common error we'll get here is -EPIPE.
137            removeDisplayEventConnection(signalConnections[i]);
138        }
139    }
140    return true;
141}
142
143// This will return when (1) a vsync event has been received, and (2) there was
144// at least one connection interested in receiving it when we started waiting.
145Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
146        DisplayEventReceiver::Event* event)
147{
148    Mutex::Autolock _l(mLock);
149
150    size_t vsyncCount;
151    nsecs_t timestamp;
152    Vector< sp<EventThread::Connection> > signalConnections;
153
154    do {
155        // latch VSYNC event if any
156        bool waitForVSync = false;
157        vsyncCount = mVSyncCount;
158        timestamp = mVSyncTimestamp;
159        mVSyncTimestamp = 0;
160
161        // find out connections waiting for events
162        size_t count = mDisplayEventConnections.size();
163        for (size_t i=0 ; i<count ; i++) {
164            sp<Connection> connection(mDisplayEventConnections[i].promote());
165            if (connection != NULL) {
166                if (connection->count >= 0) {
167                    // we need vsync events because at least
168                    // one connection is waiting for it
169                    waitForVSync = true;
170                    if (timestamp) {
171                        // we consume the event only if it's time
172                        // (ie: we received a vsync event)
173                        if (connection->count == 0) {
174                            // fired this time around
175                            connection->count = -1;
176                            signalConnections.add(connection);
177                        } else if (connection->count == 1 ||
178                                (vsyncCount % connection->count) == 0) {
179                            // continuous event, and time to report it
180                            signalConnections.add(connection);
181                        }
182                    }
183                }
184            } else {
185                // we couldn't promote this reference, the connection has
186                // died, so clean-up!
187                mDisplayEventConnections.removeAt(i);
188                --i; --count;
189            }
190        }
191
192        // Here we figure out if we need to enable or disable vsyncs
193        if (timestamp && !waitForVSync) {
194            // we received a VSYNC but we have no clients
195            // don't report it, and disable VSYNC events
196            disableVSyncLocked();
197        } else if (!timestamp && waitForVSync) {
198            // we have at least one client, so we want vsync enabled
199            // (TODO: this function is called right after we finish
200            // notifying clients of a vsync, so this call will be made
201            // at the vsync rate, e.g. 60fps.  If we can accurately
202            // track the current state we could avoid making this call
203            // so often.)
204            enableVSyncLocked();
205        }
206
207        // note: !timestamp implies signalConnections.isEmpty(), because we
208        // don't populate signalConnections if there's no vsync pending
209        if (!timestamp) {
210            // wait for something to happen
211            if (waitForVSync) {
212                // This is where we spend most of our time, waiting
213                // for vsync events and new client registrations.
214                //
215                // If the screen is off, we can't use h/w vsync, so we
216                // use a 16ms timeout instead.  It doesn't need to be
217                // precise, we just need to keep feeding our clients.
218                //
219                // We don't want to stall if there's a driver bug, so we
220                // use a (long) timeout when waiting for h/w vsync, and
221                // generate fake events when necessary.
222                bool softwareSync = mUseSoftwareVSync;
223                nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
224                if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
225                    if (!softwareSync) {
226                        ALOGW("Timed out waiting for hw vsync; faking it");
227                    }
228                    mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
229                    mVSyncCount++;
230                }
231            } else {
232                // Nobody is interested in vsync, so we just want to sleep.
233                // h/w vsync should be disabled, so this will wait until we
234                // get a new connection, or an existing connection becomes
235                // interested in receiving vsync again.
236                mCondition.wait(mLock);
237            }
238        }
239    } while (signalConnections.isEmpty());
240
241    // here we're guaranteed to have a timestamp and some connections to signal
242    // (The connections might have dropped out of mDisplayEventConnections
243    // while we were asleep, but we'll still have strong references to them.)
244
245    // fill in vsync event info
246    event->header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
247    event->header.timestamp = timestamp;
248    event->vsync.count = vsyncCount;
249
250    return signalConnections;
251}
252
253void EventThread::enableVSyncLocked() {
254    if (!mUseSoftwareVSync) {
255        // never enable h/w VSYNC when screen is off
256        mFlinger->eventControl(SurfaceFlinger::EVENT_VSYNC, true);
257        mPowerHAL.vsyncHint(true);
258    }
259    mDebugVsyncEnabled = true;
260}
261
262void EventThread::disableVSyncLocked() {
263    mFlinger->eventControl(SurfaceFlinger::EVENT_VSYNC, false);
264    mPowerHAL.vsyncHint(false);
265    mDebugVsyncEnabled = false;
266}
267
268void EventThread::dump(String8& result, char* buffer, size_t SIZE) const {
269    Mutex::Autolock _l(mLock);
270    result.appendFormat("VSYNC state: %s\n",
271            mDebugVsyncEnabled?"enabled":"disabled");
272    result.appendFormat("  soft-vsync: %s\n",
273            mUseSoftwareVSync?"enabled":"disabled");
274    result.appendFormat("  numListeners=%u,\n  events-delivered: %u\n",
275            mDisplayEventConnections.size(), mVSyncCount);
276    for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) {
277        sp<Connection> connection =
278                mDisplayEventConnections.itemAt(i).promote();
279        result.appendFormat("    %p: count=%d\n",
280                connection.get(), connection!=NULL ? connection->count : 0);
281    }
282}
283
284// ---------------------------------------------------------------------------
285
286EventThread::Connection::Connection(
287        const sp<EventThread>& eventThread)
288    : count(-1), mEventThread(eventThread), mChannel(new BitTube())
289{
290}
291
292EventThread::Connection::~Connection() {
293    // do nothing here -- clean-up will happen automatically
294    // when the main thread wakes up
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