EventThread.cpp revision 86efcc0cbc1d94250b72ef1f2ea8700a04cd2781
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<VSyncSource>& src)
40    : mVSyncSource(src),
41      mUseSoftwareVSync(false),
42      mVsyncEnabled(false),
43      mDebugVsyncEnabled(false) {
44
45    for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
46        mVSyncEvent[i].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
47        mVSyncEvent[i].header.id = 0;
48        mVSyncEvent[i].header.timestamp = 0;
49        mVSyncEvent[i].vsync.count =  0;
50    }
51}
52
53void EventThread::onFirstRef() {
54    run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
55}
56
57sp<EventThread::Connection> EventThread::createEventConnection() const {
58    return new Connection(const_cast<EventThread*>(this));
59}
60
61status_t EventThread::registerDisplayEventConnection(
62        const sp<EventThread::Connection>& connection) {
63    Mutex::Autolock _l(mLock);
64    mDisplayEventConnections.add(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
114void EventThread::onVSyncEvent(nsecs_t timestamp) {
115    Mutex::Autolock _l(mLock);
116    mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
117    mVSyncEvent[0].header.id = 0;
118    mVSyncEvent[0].header.timestamp = timestamp;
119    mVSyncEvent[0].vsync.count++;
120    mCondition.broadcast();
121}
122
123void EventThread::onHotplugReceived(int type, bool connected) {
124    ALOGE_IF(type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
125            "received hotplug event for an invalid display (id=%d)", type);
126
127    Mutex::Autolock _l(mLock);
128    if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
129        DisplayEventReceiver::Event event;
130        event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
131        event.header.id = type;
132        event.header.timestamp = systemTime();
133        event.hotplug.connected = connected;
134        mPendingEvents.add(event);
135        mCondition.broadcast();
136    }
137}
138
139bool EventThread::threadLoop() {
140    DisplayEventReceiver::Event event;
141    Vector< sp<EventThread::Connection> > signalConnections;
142    signalConnections = waitForEvent(&event);
143
144    // dispatch events to listeners...
145    const size_t count = signalConnections.size();
146    for (size_t i=0 ; i<count ; i++) {
147        const sp<Connection>& conn(signalConnections[i]);
148        // now see if we still need to report this event
149        status_t err = conn->postEvent(event);
150        if (err == -EAGAIN || err == -EWOULDBLOCK) {
151            // The destination doesn't accept events anymore, it's probably
152            // full. For now, we just drop the events on the floor.
153            // FIXME: Note that some events cannot be dropped and would have
154            // to be re-sent later.
155            // Right-now we don't have the ability to do this.
156            ALOGW("EventThread: dropping event (%08x) for connection %p",
157                    event.header.type, conn.get());
158        } else if (err < 0) {
159            // handle any other error on the pipe as fatal. the only
160            // reasonable thing to do is to clean-up this connection.
161            // The most common error we'll get here is -EPIPE.
162            removeDisplayEventConnection(signalConnections[i]);
163        }
164    }
165    return true;
166}
167
168// This will return when (1) a vsync event has been received, and (2) there was
169// at least one connection interested in receiving it when we started waiting.
170Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
171        DisplayEventReceiver::Event* event)
172{
173    Mutex::Autolock _l(mLock);
174    Vector< sp<EventThread::Connection> > signalConnections;
175
176    do {
177        bool eventPending = false;
178        bool waitForVSync = false;
179
180        size_t vsyncCount = 0;
181        nsecs_t timestamp = 0;
182        for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
183            timestamp = mVSyncEvent[i].header.timestamp;
184            if (timestamp) {
185                // we have a vsync event to dispatch
186                *event = mVSyncEvent[i];
187                mVSyncEvent[i].header.timestamp = 0;
188                vsyncCount = mVSyncEvent[i].vsync.count;
189                break;
190            }
191        }
192
193        if (!timestamp) {
194            // no vsync event, see if there are some other event
195            eventPending = !mPendingEvents.isEmpty();
196            if (eventPending) {
197                // we have some other event to dispatch
198                *event = mPendingEvents[0];
199                mPendingEvents.removeAt(0);
200            }
201        }
202
203        // find out connections waiting for events
204        size_t count = mDisplayEventConnections.size();
205        for (size_t i=0 ; i<count ; i++) {
206            sp<Connection> connection(mDisplayEventConnections[i].promote());
207            if (connection != NULL) {
208                bool added = false;
209                if (connection->count >= 0) {
210                    // we need vsync events because at least
211                    // one connection is waiting for it
212                    waitForVSync = true;
213                    if (timestamp) {
214                        // we consume the event only if it's time
215                        // (ie: we received a vsync event)
216                        if (connection->count == 0) {
217                            // fired this time around
218                            connection->count = -1;
219                            signalConnections.add(connection);
220                            added = true;
221                        } else if (connection->count == 1 ||
222                                (vsyncCount % connection->count) == 0) {
223                            // continuous event, and time to report it
224                            signalConnections.add(connection);
225                            added = true;
226                        }
227                    }
228                }
229
230                if (eventPending && !timestamp && !added) {
231                    // we don't have a vsync event to process
232                    // (timestamp==0), but we have some pending
233                    // messages.
234                    signalConnections.add(connection);
235                }
236            } else {
237                // we couldn't promote this reference, the connection has
238                // died, so clean-up!
239                mDisplayEventConnections.removeAt(i);
240                --i; --count;
241            }
242        }
243
244        // Here we figure out if we need to enable or disable vsyncs
245        if (timestamp && !waitForVSync) {
246            // we received a VSYNC but we have no clients
247            // don't report it, and disable VSYNC events
248            disableVSyncLocked();
249        } else if (!timestamp && waitForVSync) {
250            // we have at least one client, so we want vsync enabled
251            // (TODO: this function is called right after we finish
252            // notifying clients of a vsync, so this call will be made
253            // at the vsync rate, e.g. 60fps.  If we can accurately
254            // track the current state we could avoid making this call
255            // so often.)
256            enableVSyncLocked();
257        }
258
259        // note: !timestamp implies signalConnections.isEmpty(), because we
260        // don't populate signalConnections if there's no vsync pending
261        if (!timestamp && !eventPending) {
262            // wait for something to happen
263            if (waitForVSync) {
264                // This is where we spend most of our time, waiting
265                // for vsync events and new client registrations.
266                //
267                // If the screen is off, we can't use h/w vsync, so we
268                // use a 16ms timeout instead.  It doesn't need to be
269                // precise, we just need to keep feeding our clients.
270                //
271                // We don't want to stall if there's a driver bug, so we
272                // use a (long) timeout when waiting for h/w vsync, and
273                // generate fake events when necessary.
274                bool softwareSync = mUseSoftwareVSync;
275                nsecs_t timeout = softwareSync ? ms2ns(16) : ms2ns(1000);
276                if (mCondition.waitRelative(mLock, timeout) == TIMED_OUT) {
277                    if (!softwareSync) {
278                        ALOGW("Timed out waiting for hw vsync; faking it");
279                    }
280                    // FIXME: how do we decide which display id the fake
281                    // vsync came from ?
282                    mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
283                    mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY;
284                    mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
285                    mVSyncEvent[0].vsync.count++;
286                }
287            } else {
288                // Nobody is interested in vsync, so we just want to sleep.
289                // h/w vsync should be disabled, so this will wait until we
290                // get a new connection, or an existing connection becomes
291                // interested in receiving vsync again.
292                mCondition.wait(mLock);
293            }
294        }
295    } while (signalConnections.isEmpty());
296
297    // here we're guaranteed to have a timestamp and some connections to signal
298    // (The connections might have dropped out of mDisplayEventConnections
299    // while we were asleep, but we'll still have strong references to them.)
300    return signalConnections;
301}
302
303void EventThread::enableVSyncLocked() {
304    if (!mUseSoftwareVSync) {
305        // never enable h/w VSYNC when screen is off
306        if (!mVsyncEnabled) {
307            mVsyncEnabled = true;
308            mVSyncSource->setCallback(static_cast<VSyncSource::Callback*>(this));
309            mVSyncSource->setVSyncEnabled(true);
310            mPowerHAL.vsyncHint(true);
311        }
312    }
313    mDebugVsyncEnabled = true;
314}
315
316void EventThread::disableVSyncLocked() {
317    if (mVsyncEnabled) {
318        mVsyncEnabled = false;
319        mVSyncSource->setVSyncEnabled(false);
320        mPowerHAL.vsyncHint(false);
321        mDebugVsyncEnabled = false;
322    }
323}
324
325void EventThread::dump(String8& result) const {
326    Mutex::Autolock _l(mLock);
327    result.appendFormat("VSYNC state: %s\n",
328            mDebugVsyncEnabled?"enabled":"disabled");
329    result.appendFormat("  soft-vsync: %s\n",
330            mUseSoftwareVSync?"enabled":"disabled");
331    result.appendFormat("  numListeners=%zu,\n  events-delivered: %u\n",
332            mDisplayEventConnections.size(),
333            mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
334    for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) {
335        sp<Connection> connection =
336                mDisplayEventConnections.itemAt(i).promote();
337        result.appendFormat("    %p: count=%d\n",
338                connection.get(), connection!=NULL ? connection->count : 0);
339    }
340}
341
342// ---------------------------------------------------------------------------
343
344EventThread::Connection::Connection(
345        const sp<EventThread>& eventThread)
346    : count(-1), mEventThread(eventThread), mChannel(new BitTube())
347{
348}
349
350EventThread::Connection::~Connection() {
351    // do nothing here -- clean-up will happen automatically
352    // when the main thread wakes up
353}
354
355void EventThread::Connection::onFirstRef() {
356    // NOTE: mEventThread doesn't hold a strong reference on us
357    mEventThread->registerDisplayEventConnection(this);
358}
359
360sp<BitTube> EventThread::Connection::getDataChannel() const {
361    return mChannel;
362}
363
364void EventThread::Connection::setVsyncRate(uint32_t count) {
365    mEventThread->setVsyncRate(count, this);
366}
367
368void EventThread::Connection::requestNextVsync() {
369    mEventThread->requestNextVsync(this);
370}
371
372status_t EventThread::Connection::postEvent(
373        const DisplayEventReceiver::Event& event) {
374    ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);
375    return size < 0 ? status_t(size) : status_t(NO_ERROR);
376}
377
378// ---------------------------------------------------------------------------
379
380}; // namespace android
381