EventThread.cpp revision 3cf199aef6250552555344944c3e3a6e4ab05f92
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#include <stdint.h>
18#include <sys/types.h>
19
20#include <gui/IDisplayEventConnection.h>
21#include <gui/DisplayEventReceiver.h>
22
23#include <utils/Errors.h>
24
25#include "DisplayHardware/DisplayHardware.h"
26#include "DisplayEventConnection.h"
27#include "EventThread.h"
28#include "SurfaceFlinger.h"
29
30// ---------------------------------------------------------------------------
31
32namespace android {
33
34// ---------------------------------------------------------------------------
35
36EventThread::EventThread(const sp<SurfaceFlinger>& flinger)
37    : mFlinger(flinger),
38      mHw(flinger->graphicPlane(0).displayHardware()),
39      mLastVSyncTimestamp(0),
40      mDeliveredEvents(0)
41{
42}
43
44void EventThread::onFirstRef() {
45    run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
46}
47
48sp<DisplayEventConnection> EventThread::createEventConnection() const {
49    return new DisplayEventConnection(const_cast<EventThread*>(this));
50}
51
52nsecs_t EventThread::getLastVSyncTimestamp() const {
53    Mutex::Autolock _l(mLock);
54    return mLastVSyncTimestamp;
55}
56
57nsecs_t EventThread::getVSyncPeriod() const {
58    return mHw.getRefreshPeriod();
59
60}
61
62status_t EventThread::registerDisplayEventConnection(
63        const sp<DisplayEventConnection>& connection) {
64    Mutex::Autolock _l(mLock);
65    ConnectionInfo info;
66    mDisplayEventConnections.add(connection, info);
67    mCondition.signal();
68    return NO_ERROR;
69}
70
71status_t EventThread::unregisterDisplayEventConnection(
72        const wp<DisplayEventConnection>& connection) {
73    Mutex::Autolock _l(mLock);
74    mDisplayEventConnections.removeItem(connection);
75    mCondition.signal();
76    return NO_ERROR;
77}
78
79void EventThread::removeDisplayEventConnection(
80        const wp<DisplayEventConnection>& connection) {
81    Mutex::Autolock _l(mLock);
82    mDisplayEventConnections.removeItem(connection);
83}
84
85EventThread::ConnectionInfo* EventThread::getConnectionInfoLocked(
86        const wp<DisplayEventConnection>& connection) {
87    ssize_t index = mDisplayEventConnections.indexOfKey(connection);
88    if (index < 0) return NULL;
89    return &mDisplayEventConnections.editValueAt(index);
90}
91
92void EventThread::setVsyncRate(uint32_t count,
93        const wp<DisplayEventConnection>& connection) {
94    if (int32_t(count) >= 0) { // server must protect against bad params
95        Mutex::Autolock _l(mLock);
96        ConnectionInfo* info = getConnectionInfoLocked(connection);
97        if (info) {
98            const int32_t new_count = (count == 0) ? -1 : count;
99            if (info->count != new_count) {
100                info->count = new_count;
101                mCondition.signal();
102            }
103        }
104    }
105}
106
107void EventThread::requestNextVsync(
108        const wp<DisplayEventConnection>& connection) {
109    Mutex::Autolock _l(mLock);
110    ConnectionInfo* info = getConnectionInfoLocked(connection);
111    if (info && info->count < 0) {
112        info->count = 0;
113        mCondition.signal();
114    }
115}
116
117bool EventThread::threadLoop() {
118
119    nsecs_t timestamp;
120    DisplayEventReceiver::Event vsync;
121    Vector< wp<DisplayEventConnection> > displayEventConnections;
122
123    { // scope for the lock
124        Mutex::Autolock _l(mLock);
125        do {
126            // see if we need to wait for the VSYNC at all
127            do {
128                bool waitForNextVsync = false;
129                size_t count = mDisplayEventConnections.size();
130                for (size_t i=0 ; i<count ; i++) {
131                    const ConnectionInfo& info(
132                            mDisplayEventConnections.valueAt(i));
133                    if (info.count >= 0) {
134                        // at least one continuous mode or active one-shot event
135                        waitForNextVsync = true;
136                        break;
137                    }
138                }
139
140                if (waitForNextVsync)
141                    break;
142
143                mCondition.wait(mLock);
144            } while(true);
145
146            // at least one listener requested VSYNC
147            mLock.unlock();
148            timestamp = mHw.waitForRefresh();
149            mLock.lock();
150            mDeliveredEvents++;
151            mLastVSyncTimestamp = timestamp;
152
153            // now see if we still need to report this VSYNC event
154            const size_t count = mDisplayEventConnections.size();
155            for (size_t i=0 ; i<count ; i++) {
156                bool reportVsync = false;
157                const ConnectionInfo& info(
158                        mDisplayEventConnections.valueAt(i));
159                if (info.count >= 1) {
160                    if (info.count==1 || (mDeliveredEvents % info.count) == 0) {
161                        // continuous event, and time to report it
162                        reportVsync = true;
163                    }
164                } else if (info.count >= -1) {
165                    ConnectionInfo& info(
166                            mDisplayEventConnections.editValueAt(i));
167                    if (info.count == 0) {
168                        // fired this time around
169                        reportVsync = true;
170                    }
171                    info.count--;
172                }
173                if (reportVsync) {
174                    displayEventConnections.add(mDisplayEventConnections.keyAt(i));
175                }
176            }
177        } while (!displayEventConnections.size());
178
179        // dispatch vsync events to listeners...
180        vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
181        vsync.header.timestamp = timestamp;
182        vsync.vsync.count = mDeliveredEvents;
183    }
184
185    const size_t count = displayEventConnections.size();
186    for (size_t i=0 ; i<count ; i++) {
187        sp<DisplayEventConnection> conn(displayEventConnections[i].promote());
188        // make sure the connection didn't die
189        if (conn != NULL) {
190            status_t err = conn->postEvent(vsync);
191            if (err == -EAGAIN || err == -EWOULDBLOCK) {
192                // The destination doesn't accept events anymore, it's probably
193                // full. For now, we just drop the events on the floor.
194                // Note that some events cannot be dropped and would have to be
195                // re-sent later. Right-now we don't have the ability to do
196                // this, but it doesn't matter for VSYNC.
197            } else if (err < 0) {
198                // handle any other error on the pipe as fatal. the only
199                // reasonable thing to do is to clean-up this connection.
200                // The most common error we'll get here is -EPIPE.
201                removeDisplayEventConnection(displayEventConnections[i]);
202            }
203        } else {
204            // somehow the connection is dead, but we still have it in our list
205            // just clean the list.
206            removeDisplayEventConnection(displayEventConnections[i]);
207        }
208    }
209
210    // clear all our references without holding mLock
211    displayEventConnections.clear();
212
213    return true;
214}
215
216status_t EventThread::readyToRun() {
217    ALOGI("EventThread ready to run.");
218    return NO_ERROR;
219}
220
221void EventThread::dump(String8& result, char* buffer, size_t SIZE) const {
222    Mutex::Autolock _l(mLock);
223    result.append("VSYNC state:\n");
224    snprintf(buffer, SIZE, "  numListeners=%u, events-delivered: %u\n",
225            mDisplayEventConnections.size(), mDeliveredEvents);
226    result.append(buffer);
227}
228
229// ---------------------------------------------------------------------------
230
231}; // namespace android
232