EventThread.cpp revision a4cb35a2864d58e9a764a17623e15ab25a9964a0
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
63status_t EventThread::unregisterDisplayEventConnection(
64        const wp<EventThread::Connection>& connection) {
65    Mutex::Autolock _l(mLock);
66    mDisplayEventConnections.remove(connection);
67    mCondition.broadcast();
68    return NO_ERROR;
69}
70
71void EventThread::removeDisplayEventConnection(
72        const wp<EventThread::Connection>& connection) {
73    Mutex::Autolock _l(mLock);
74    mDisplayEventConnections.remove(connection);
75}
76
77void EventThread::setVsyncRate(uint32_t count,
78        const sp<EventThread::Connection>& connection) {
79    if (int32_t(count) >= 0) { // server must protect against bad params
80        Mutex::Autolock _l(mLock);
81        const int32_t new_count = (count == 0) ? -1 : count;
82        if (connection->count != new_count) {
83            connection->count = new_count;
84            mCondition.broadcast();
85        }
86    }
87}
88
89void EventThread::requestNextVsync(
90        const sp<EventThread::Connection>& connection) {
91    Mutex::Autolock _l(mLock);
92    if (connection->count < 0) {
93        connection->count = 0;
94        mCondition.broadcast();
95    }
96}
97
98void EventThread::onScreenReleased() {
99    Mutex::Autolock _l(mLock);
100    if (!mUseSoftwareVSync) {
101        // disable reliance on h/w vsync
102        mUseSoftwareVSync = true;
103        mCondition.broadcast();
104    }
105}
106
107void EventThread::onScreenAcquired() {
108    Mutex::Autolock _l(mLock);
109    if (mUseSoftwareVSync) {
110        // resume use of h/w vsync
111        mUseSoftwareVSync = false;
112        mCondition.broadcast();
113    }
114}
115
116
117void EventThread::onVSyncReceived(int, nsecs_t timestamp) {
118    Mutex::Autolock _l(mLock);
119    mVSyncTimestamp = timestamp;
120    mVSyncCount++;
121    mCondition.broadcast();
122}
123
124bool EventThread::threadLoop() {
125
126    nsecs_t timestamp;
127    size_t vsyncCount;
128    DisplayEventReceiver::Event vsync;
129    Vector< sp<EventThread::Connection> > activeConnections;
130    Vector< sp<EventThread::Connection> > signalConnections;
131
132    do {
133        // release our references
134        signalConnections.clear();
135        activeConnections.clear();
136
137        Mutex::Autolock _l(mLock);
138
139        // latch VSYNC event if any
140        bool waitForVSync = false;
141        vsyncCount = mVSyncCount;
142        timestamp = mVSyncTimestamp;
143        mVSyncTimestamp = 0;
144
145        // find out connections waiting for VSYNC events
146        size_t count = mDisplayEventConnections.size();
147        for (size_t i=0 ; i<count ; i++) {
148            sp<Connection> connection(mDisplayEventConnections[i].promote());
149            if (connection != NULL) {
150                activeConnections.add(connection);
151                if (connection->count >= 0) {
152                    // we need vsync events because at least
153                    // one connection is waiting for it
154                    waitForVSync = true;
155                    if (connection->count == 0) {
156                        // fired this time around
157                        if (timestamp) {
158                            // only "consume" this event if we're going to
159                            // report it
160                            connection->count = -1;
161                        }
162                        signalConnections.add(connection);
163                    } else if (connection->count == 1 ||
164                            (vsyncCount % connection->count) == 0) {
165                        // continuous event, and time to report it
166                        signalConnections.add(connection);
167                    }
168                }
169            }
170        }
171
172        if (timestamp) {
173            // we have a vsync event we can dispatch
174            if (!waitForVSync) {
175                // we received a VSYNC but we have no clients
176                // don't report it, and disable VSYNC events
177                disableVSyncLocked();
178            } else {
179                // report VSYNC event
180                break;
181            }
182        } else {
183            // never disable VSYNC events immediately, instead
184            // we'll wait to receive the event and we'll
185            // reevaluate whether we need to dispatch it and/or
186            // disable VSYNC events then.
187            if (waitForVSync) {
188                // enable
189                enableVSyncLocked();
190            }
191        }
192
193        // wait for something to happen
194        if (CC_UNLIKELY(mUseSoftwareVSync && waitForVSync)) {
195            // h/w vsync cannot be used (screen is off), so we use
196            // a  timeout instead. it doesn't matter how imprecise this
197            // is, we just need to make sure to serve the clients
198            if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) {
199                mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
200                mVSyncCount++;
201            }
202        } else {
203            if (!timestamp || signalConnections.isEmpty()) {
204                // This is where we spend most of our time, waiting
205                // for a vsync events and registered clients
206                mCondition.wait(mLock);
207            }
208        }
209    } while (!timestamp || signalConnections.isEmpty());
210
211    // dispatch vsync events to listeners...
212    vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
213    vsync.header.timestamp = timestamp;
214    vsync.vsync.count = vsyncCount;
215
216    const size_t count = signalConnections.size();
217    for (size_t i=0 ; i<count ; i++) {
218        const sp<Connection>& conn(signalConnections[i]);
219        // now see if we still need to report this VSYNC event
220        status_t err = conn->postEvent(vsync);
221        if (err == -EAGAIN || err == -EWOULDBLOCK) {
222            // The destination doesn't accept events anymore, it's probably
223            // full. For now, we just drop the events on the floor.
224            // Note that some events cannot be dropped and would have to be
225            // re-sent later. Right-now we don't have the ability to do
226            // this, but it doesn't matter for VSYNC.
227        } else if (err < 0) {
228            // handle any other error on the pipe as fatal. the only
229            // reasonable thing to do is to clean-up this connection.
230            // The most common error we'll get here is -EPIPE.
231            removeDisplayEventConnection(signalConnections[i]);
232        }
233    }
234
235    return true;
236}
237
238void EventThread::enableVSyncLocked() {
239    if (!mUseSoftwareVSync) {
240        // never enable h/w VSYNC when screen is off
241        mFlinger->eventControl(SurfaceFlinger::EVENT_VSYNC, true);
242        mPowerHAL.vsyncHint(true);
243    }
244    mDebugVsyncEnabled = true;
245}
246
247void EventThread::disableVSyncLocked() {
248    mFlinger->eventControl(SurfaceFlinger::EVENT_VSYNC, false);
249    mPowerHAL.vsyncHint(false);
250    mDebugVsyncEnabled = false;
251}
252
253status_t EventThread::readyToRun() {
254    ALOGI("EventThread ready to run.");
255    return NO_ERROR;
256}
257
258void EventThread::dump(String8& result, char* buffer, size_t SIZE) const {
259    Mutex::Autolock _l(mLock);
260    result.appendFormat("VSYNC state: %s\n",
261            mDebugVsyncEnabled?"enabled":"disabled");
262    result.appendFormat("  soft-vsync: %s\n",
263            mUseSoftwareVSync?"enabled":"disabled");
264    result.appendFormat("  numListeners=%u,\n  events-delivered: %u\n",
265            mDisplayEventConnections.size(), mVSyncCount);
266    for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) {
267        sp<Connection> connection =
268                mDisplayEventConnections.itemAt(i).promote();
269        result.appendFormat("    %p: count=%d\n",
270                connection.get(), connection!=NULL ? connection->count : 0);
271    }
272}
273
274// ---------------------------------------------------------------------------
275
276EventThread::Connection::Connection(
277        const sp<EventThread>& eventThread)
278    : count(-1), mEventThread(eventThread), mChannel(new BitTube())
279{
280}
281
282EventThread::Connection::~Connection() {
283    mEventThread->unregisterDisplayEventConnection(this);
284}
285
286void EventThread::Connection::onFirstRef() {
287    // NOTE: mEventThread doesn't hold a strong reference on us
288    mEventThread->registerDisplayEventConnection(this);
289}
290
291sp<BitTube> EventThread::Connection::getDataChannel() const {
292    return mChannel;
293}
294
295void EventThread::Connection::setVsyncRate(uint32_t count) {
296    mEventThread->setVsyncRate(count, this);
297}
298
299void EventThread::Connection::requestNextVsync() {
300    mEventThread->requestNextVsync(this);
301}
302
303status_t EventThread::Connection::postEvent(
304        const DisplayEventReceiver::Event& event) {
305    ssize_t size = DisplayEventReceiver::sendEvents(mChannel, &event, 1);
306    return size < 0 ? status_t(size) : status_t(NO_ERROR);
307}
308
309// ---------------------------------------------------------------------------
310
311}; // namespace android
312