EventThread.cpp revision 10125f00a50d3edd05deef9fcd2d368cf2766683
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 "EventThread.h"
31#include "SurfaceFlinger.h"
32
33// ---------------------------------------------------------------------------
34namespace android {
35// ---------------------------------------------------------------------------
36
37EventThread::EventThread(const sp<SurfaceFlinger>& flinger)
38    : mFlinger(flinger),
39      mVSyncTimestamp(0),
40      mUseSoftwareVSync(false),
41      mVSyncCount(0),
42      mDebugVsyncEnabled(false) {
43}
44
45void EventThread::onFirstRef() {
46    run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
47}
48
49sp<EventThread::Connection> EventThread::createEventConnection() const {
50    return new Connection(const_cast<EventThread*>(this));
51}
52
53status_t EventThread::registerDisplayEventConnection(
54        const sp<EventThread::Connection>& connection) {
55    Mutex::Autolock _l(mLock);
56    mDisplayEventConnections.add(connection);
57    mCondition.broadcast();
58    return NO_ERROR;
59}
60
61status_t EventThread::unregisterDisplayEventConnection(
62        const wp<EventThread::Connection>& connection) {
63    Mutex::Autolock _l(mLock);
64    mDisplayEventConnections.remove(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
114
115void EventThread::onVSyncReceived(int, nsecs_t timestamp) {
116    Mutex::Autolock _l(mLock);
117    mVSyncTimestamp = timestamp;
118    mVSyncCount++;
119    mCondition.broadcast();
120}
121
122bool EventThread::threadLoop() {
123
124    nsecs_t timestamp;
125    size_t vsyncCount;
126    size_t activeEvents;
127    DisplayEventReceiver::Event vsync;
128    Vector< sp<EventThread::Connection> > activeConnections;
129
130    do {
131        Mutex::Autolock _l(mLock);
132        // latch VSYNC event if any
133        timestamp = mVSyncTimestamp;
134        mVSyncTimestamp = 0;
135
136        // check if we should be waiting for VSYNC events
137        activeEvents = 0;
138        bool waitForNextVsync = false;
139        size_t count = mDisplayEventConnections.size();
140        for (size_t i=0 ; i<count ; i++) {
141            sp<Connection> connection(mDisplayEventConnections[i].promote());
142            if (connection != NULL) {
143                activeConnections.add(connection);
144                if (connection->count >= 0) {
145                    // at least one continuous mode or active one-shot event
146                    waitForNextVsync = true;
147                    activeEvents++;
148                    break;
149                }
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                mVSyncCount++;
181            }
182        } else {
183            mCondition.wait(mLock);
184        }
185        vsyncCount = mVSyncCount;
186    } while (!activeConnections.size());
187
188    if (!activeEvents) {
189        // no events to return. start over.
190        // (here we make sure to exit the scope of this function
191        //  so that we release our Connection references)
192        return true;
193    }
194
195    // dispatch vsync events to listeners...
196    vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
197    vsync.header.timestamp = timestamp;
198    vsync.vsync.count = vsyncCount;
199
200    const size_t count = activeConnections.size();
201    for (size_t i=0 ; i<count ; i++) {
202        const sp<Connection>& conn(activeConnections[i]);
203        // now see if we still need to report this VSYNC event
204        const int32_t vcount = conn->count;
205        if (vcount >= 0) {
206            bool reportVsync = false;
207            if (vcount == 0) {
208                // fired this time around
209                conn->count = -1;
210                reportVsync = true;
211            } else if (vcount == 1 || (vsyncCount % vcount) == 0) {
212                // continuous event, and time to report it
213                reportVsync = true;
214            }
215
216            if (reportVsync) {
217                status_t err = conn->postEvent(vsync);
218                if (err == -EAGAIN || err == -EWOULDBLOCK) {
219                    // The destination doesn't accept events anymore, it's probably
220                    // full. For now, we just drop the events on the floor.
221                    // Note that some events cannot be dropped and would have to be
222                    // re-sent later. Right-now we don't have the ability to do
223                    // this, but it doesn't matter for VSYNC.
224                } else if (err < 0) {
225                    // handle any other error on the pipe as fatal. the only
226                    // reasonable thing to do is to clean-up this connection.
227                    // The most common error we'll get here is -EPIPE.
228                    removeDisplayEventConnection(activeConnections[i]);
229                }
230            }
231        }
232    }
233
234    return true;
235}
236
237void EventThread::enableVSyncLocked() {
238    if (!mUseSoftwareVSync) {
239        // never enable h/w VSYNC when screen is off
240        mFlinger->eventControl(SurfaceFlinger::EVENT_VSYNC, true);
241        mPowerHAL.vsyncHint(true);
242    }
243    mDebugVsyncEnabled = true;
244}
245
246void EventThread::disableVSyncLocked() {
247    mFlinger->eventControl(SurfaceFlinger::EVENT_VSYNC, false);
248    mPowerHAL.vsyncHint(false);
249    mDebugVsyncEnabled = false;
250}
251
252status_t EventThread::readyToRun() {
253    ALOGI("EventThread ready to run.");
254    return NO_ERROR;
255}
256
257void EventThread::dump(String8& result, char* buffer, size_t SIZE) const {
258    Mutex::Autolock _l(mLock);
259    result.appendFormat("VSYNC state: %s\n",
260            mDebugVsyncEnabled?"enabled":"disabled");
261    result.appendFormat("  soft-vsync: %s\n",
262            mUseSoftwareVSync?"enabled":"disabled");
263    result.appendFormat("  numListeners=%u,\n  events-delivered: %u\n",
264            mDisplayEventConnections.size(), mVSyncCount);
265    for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) {
266        sp<Connection> connection =
267                mDisplayEventConnections.itemAt(i).promote();
268        result.appendFormat("    %p: count=%d\n",
269                connection.get(), connection!=NULL ? connection->count : 0);
270    }
271}
272
273// ---------------------------------------------------------------------------
274
275EventThread::Connection::Connection(
276        const sp<EventThread>& eventThread)
277    : count(-1), mEventThread(eventThread), mChannel(new BitTube())
278{
279}
280
281EventThread::Connection::~Connection() {
282    mEventThread->unregisterDisplayEventConnection(this);
283}
284
285void EventThread::Connection::onFirstRef() {
286    // NOTE: mEventThread doesn't hold a strong reference on us
287    mEventThread->registerDisplayEventConnection(this);
288}
289
290sp<BitTube> EventThread::Connection::getDataChannel() const {
291    return mChannel;
292}
293
294void EventThread::Connection::setVsyncRate(uint32_t count) {
295    mEventThread->setVsyncRate(count, this);
296}
297
298void EventThread::Connection::requestNextVsync() {
299    mEventThread->requestNextVsync(this);
300}
301
302status_t EventThread::Connection::postEvent(
303        const DisplayEventReceiver::Event& event) {
304    ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);
305    return size < 0 ? status_t(size) : status_t(NO_ERROR);
306}
307
308// ---------------------------------------------------------------------------
309
310}; // namespace android
311