RenderThread.cpp revision 3b20251a355c88193c439f928a84ae69483fb488
1/*
2 * Copyright (C) 2013 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 LOG_TAG "RenderThread"
18
19#include "RenderThread.h"
20
21#include <gui/DisplayEventReceiver.h>
22#include <utils/Log.h>
23
24#include "../RenderState.h"
25#include "CanvasContext.h"
26#include "EglManager.h"
27#include "RenderProxy.h"
28
29namespace android {
30using namespace uirenderer::renderthread;
31ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread);
32
33namespace uirenderer {
34namespace renderthread {
35
36// Number of events to read at a time from the DisplayEventReceiver pipe.
37// The value should be large enough that we can quickly drain the pipe
38// using just a few large reads.
39static const size_t EVENT_BUFFER_SIZE = 100;
40
41// Slight delay to give the UI time to push us a new frame before we replay
42static const int DISPATCH_FRAME_CALLBACKS_DELAY = 4;
43
44TaskQueue::TaskQueue() : mHead(0), mTail(0) {}
45
46RenderTask* TaskQueue::next() {
47    RenderTask* ret = mHead;
48    if (ret) {
49        mHead = ret->mNext;
50        if (!mHead) {
51            mTail = 0;
52        }
53        ret->mNext = 0;
54    }
55    return ret;
56}
57
58RenderTask* TaskQueue::peek() {
59    return mHead;
60}
61
62void TaskQueue::queue(RenderTask* task) {
63    // Since the RenderTask itself forms the linked list it is not allowed
64    // to have the same task queued twice
65    LOG_ALWAYS_FATAL_IF(task->mNext || mTail == task, "Task is already in the queue!");
66    if (mTail) {
67        // Fast path if we can just append
68        if (mTail->mRunAt <= task->mRunAt) {
69            mTail->mNext = task;
70            mTail = task;
71        } else {
72            // Need to find the proper insertion point
73            RenderTask* previous = 0;
74            RenderTask* next = mHead;
75            while (next && next->mRunAt <= task->mRunAt) {
76                previous = next;
77                next = next->mNext;
78            }
79            if (!previous) {
80                task->mNext = mHead;
81                mHead = task;
82            } else {
83                previous->mNext = task;
84                if (next) {
85                    task->mNext = next;
86                } else {
87                    mTail = task;
88                }
89            }
90        }
91    } else {
92        mTail = mHead = task;
93    }
94}
95
96void TaskQueue::queueAtFront(RenderTask* task) {
97    if (mTail) {
98        task->mNext = mHead;
99        mHead = task;
100    } else {
101        mTail = mHead = task;
102    }
103}
104
105void TaskQueue::remove(RenderTask* task) {
106    // TaskQueue is strict here to enforce that users are keeping track of
107    // their RenderTasks due to how their memory is managed
108    LOG_ALWAYS_FATAL_IF(!task->mNext && mTail != task,
109            "Cannot remove a task that isn't in the queue!");
110
111    // If task is the head we can just call next() to pop it off
112    // Otherwise we need to scan through to find the task before it
113    if (peek() == task) {
114        next();
115    } else {
116        RenderTask* previous = mHead;
117        while (previous->mNext != task) {
118            previous = previous->mNext;
119        }
120        previous->mNext = task->mNext;
121        if (mTail == task) {
122            mTail = previous;
123        }
124    }
125}
126
127class DispatchFrameCallbacks : public RenderTask {
128private:
129    RenderThread* mRenderThread;
130public:
131    DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {}
132
133    virtual void run() {
134        mRenderThread->dispatchFrameCallbacks();
135    }
136};
137
138RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>()
139        , mNextWakeup(LLONG_MAX)
140        , mDisplayEventReceiver(0)
141        , mVsyncRequested(false)
142        , mFrameCallbackTaskPending(false)
143        , mFrameCallbackTask(0)
144        , mRenderState(NULL)
145        , mEglManager(NULL) {
146    mFrameCallbackTask = new DispatchFrameCallbacks(this);
147    mLooper = new Looper(false);
148    run("RenderThread");
149}
150
151RenderThread::~RenderThread() {
152    LOG_ALWAYS_FATAL("Can't destroy the render thread");
153}
154
155void RenderThread::initializeDisplayEventReceiver() {
156    LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?");
157    mDisplayEventReceiver = new DisplayEventReceiver();
158    status_t status = mDisplayEventReceiver->initCheck();
159    LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver "
160            "failed with status: %d", status);
161
162    // Register the FD
163    mLooper->addFd(mDisplayEventReceiver->getFd(), 0,
164            Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this);
165}
166
167void RenderThread::initThreadLocals() {
168    initializeDisplayEventReceiver();
169    mEglManager = new EglManager(*this);
170    mRenderState = new RenderState();
171}
172
173int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
174    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
175        ALOGE("Display event receiver pipe was closed or an error occurred.  "
176                "events=0x%x", events);
177        return 0; // remove the callback
178    }
179
180    if (!(events & Looper::EVENT_INPUT)) {
181        ALOGW("Received spurious callback for unhandled poll event.  "
182                "events=0x%x", events);
183        return 1; // keep the callback
184    }
185
186    reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();
187
188    return 1; // keep the callback
189}
190
191static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) {
192    DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
193    nsecs_t latest = 0;
194    ssize_t n;
195    while ((n = receiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
196        for (ssize_t i = 0; i < n; i++) {
197            const DisplayEventReceiver::Event& ev = buf[i];
198            switch (ev.header.type) {
199            case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
200                latest = ev.header.timestamp;
201                break;
202            }
203        }
204    }
205    if (n < 0) {
206        ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
207    }
208    return latest;
209}
210
211void RenderThread::drainDisplayEventQueue(bool skipCallbacks) {
212    ATRACE_CALL();
213    nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
214    if (vsyncEvent > 0) {
215        mVsyncRequested = false;
216        mTimeLord.vsyncReceived(vsyncEvent);
217        if (!skipCallbacks && !mFrameCallbackTaskPending) {
218            ATRACE_NAME("queue mFrameCallbackTask");
219            mFrameCallbackTaskPending = true;
220            queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY);
221        }
222    }
223}
224
225void RenderThread::dispatchFrameCallbacks() {
226    ATRACE_CALL();
227    mFrameCallbackTaskPending = false;
228
229    std::set<IFrameCallback*> callbacks;
230    mFrameCallbacks.swap(callbacks);
231
232    for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
233        (*it)->doFrame();
234    }
235}
236
237void RenderThread::requestVsync() {
238    if (!mVsyncRequested) {
239        mVsyncRequested = true;
240        status_t status = mDisplayEventReceiver->requestNextVsync();
241        LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
242                "requestNextVsync failed with status: %d", status);
243    }
244}
245
246bool RenderThread::threadLoop() {
247    initThreadLocals();
248
249    int timeoutMillis = -1;
250    for (;;) {
251        int result = mLooper->pollOnce(timeoutMillis);
252        LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
253                "RenderThread Looper POLL_ERROR!");
254
255        nsecs_t nextWakeup;
256        // Process our queue, if we have anything
257        while (RenderTask* task = nextTask(&nextWakeup)) {
258            task->run();
259            // task may have deleted itself, do not reference it again
260        }
261        if (nextWakeup == LLONG_MAX) {
262            timeoutMillis = -1;
263        } else {
264            nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC);
265            timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos);
266            if (timeoutMillis < 0) {
267                timeoutMillis = 0;
268            }
269        }
270
271        if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
272            drainDisplayEventQueue(true);
273            mFrameCallbacks.insert(
274                    mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end());
275            mPendingRegistrationFrameCallbacks.clear();
276            requestVsync();
277        }
278    }
279
280    return false;
281}
282
283void RenderThread::queue(RenderTask* task) {
284    AutoMutex _lock(mLock);
285    mQueue.queue(task);
286    if (mNextWakeup && task->mRunAt < mNextWakeup) {
287        mNextWakeup = 0;
288        mLooper->wake();
289    }
290}
291
292void RenderThread::queueAtFront(RenderTask* task) {
293    AutoMutex _lock(mLock);
294    mQueue.queueAtFront(task);
295    mLooper->wake();
296}
297
298void RenderThread::queueDelayed(RenderTask* task, int delayMs) {
299    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
300    task->mRunAt = now + milliseconds_to_nanoseconds(delayMs);
301    queue(task);
302}
303
304void RenderThread::remove(RenderTask* task) {
305    AutoMutex _lock(mLock);
306    mQueue.remove(task);
307}
308
309void RenderThread::postFrameCallback(IFrameCallback* callback) {
310    mPendingRegistrationFrameCallbacks.insert(callback);
311}
312
313void RenderThread::removeFrameCallback(IFrameCallback* callback) {
314    mFrameCallbacks.erase(callback);
315    mPendingRegistrationFrameCallbacks.erase(callback);
316}
317
318void RenderThread::pushBackFrameCallback(IFrameCallback* callback) {
319    if (mFrameCallbacks.erase(callback)) {
320        mPendingRegistrationFrameCallbacks.insert(callback);
321    }
322}
323
324RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
325    AutoMutex _lock(mLock);
326    RenderTask* next = mQueue.peek();
327    if (!next) {
328        mNextWakeup = LLONG_MAX;
329    } else {
330        mNextWakeup = next->mRunAt;
331        // Most tasks won't be delayed, so avoid unnecessary systemTime() calls
332        if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
333            next = mQueue.next();
334        } else {
335            next = 0;
336        }
337    }
338    if (nextWakeup) {
339        *nextWakeup = mNextWakeup;
340    }
341    return next;
342}
343
344} /* namespace renderthread */
345} /* namespace uirenderer */
346} /* namespace android */
347