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