RenderThread.cpp revision 2d5b8d73929a38b019c6b6276d4a19542b990f0c
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#include "RenderThread.h"
18
19#include "../renderstate/RenderState.h"
20#include "CanvasContext.h"
21#include "EglManager.h"
22#include "RenderProxy.h"
23
24#include <gui/DisplayEventReceiver.h>
25#include <gui/ISurfaceComposer.h>
26#include <gui/SurfaceComposerClient.h>
27#include <sys/resource.h>
28#include <utils/Condition.h>
29#include <utils/Log.h>
30#include <utils/Mutex.h>
31
32namespace android {
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 nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4);
43
44TaskQueue::TaskQueue() : mHead(nullptr), mTail(nullptr) {}
45
46RenderTask* TaskQueue::next() {
47    RenderTask* ret = mHead;
48    if (ret) {
49        mHead = ret->mNext;
50        if (!mHead) {
51            mTail = nullptr;
52        }
53        ret->mNext = nullptr;
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 = nullptr;
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() override {
134        mRenderThread->dispatchFrameCallbacks();
135    }
136};
137
138static bool gHasRenderThreadInstance = false;
139
140bool RenderThread::hasInstance() {
141    return gHasRenderThreadInstance;
142}
143
144RenderThread& RenderThread::getInstance() {
145    // This is a pointer because otherwise __cxa_finalize
146    // will try to delete it like a Good Citizen but that causes us to crash
147    // because we don't want to delete the RenderThread normally.
148    static RenderThread* sInstance = new RenderThread();
149    gHasRenderThreadInstance = true;
150    return *sInstance;
151}
152
153RenderThread::RenderThread() : Thread(true)
154        , mNextWakeup(LLONG_MAX)
155        , mDisplayEventReceiver(nullptr)
156        , mVsyncRequested(false)
157        , mFrameCallbackTaskPending(false)
158        , mFrameCallbackTask(nullptr)
159        , mRenderState(nullptr)
160        , mEglManager(nullptr) {
161    Properties::load();
162    mFrameCallbackTask = new DispatchFrameCallbacks(this);
163    mLooper = new Looper(false);
164    run("RenderThread");
165}
166
167RenderThread::~RenderThread() {
168    LOG_ALWAYS_FATAL("Can't destroy the render thread");
169}
170
171void RenderThread::initializeDisplayEventReceiver() {
172    LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?");
173    mDisplayEventReceiver = new DisplayEventReceiver();
174    status_t status = mDisplayEventReceiver->initCheck();
175    LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver "
176            "failed with status: %d", status);
177
178    // Register the FD
179    mLooper->addFd(mDisplayEventReceiver->getFd(), 0,
180            Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this);
181}
182
183void RenderThread::initThreadLocals() {
184    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
185            ISurfaceComposer::eDisplayIdMain));
186    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
187    LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
188    nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
189    mTimeLord.setFrameInterval(frameIntervalNanos);
190    initializeDisplayEventReceiver();
191    mEglManager = new EglManager(*this);
192    mRenderState = new RenderState(*this);
193    mJankTracker = new JankTracker(mDisplayInfo);
194}
195
196int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
197    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
198        ALOGE("Display event receiver pipe was closed or an error occurred.  "
199                "events=0x%x", events);
200        return 0; // remove the callback
201    }
202
203    if (!(events & Looper::EVENT_INPUT)) {
204        ALOGW("Received spurious callback for unhandled poll event.  "
205                "events=0x%x", events);
206        return 1; // keep the callback
207    }
208
209    reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();
210
211    return 1; // keep the callback
212}
213
214static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) {
215    DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
216    nsecs_t latest = 0;
217    ssize_t n;
218    while ((n = receiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
219        for (ssize_t i = 0; i < n; i++) {
220            const DisplayEventReceiver::Event& ev = buf[i];
221            switch (ev.header.type) {
222            case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
223                latest = ev.header.timestamp;
224                break;
225            }
226        }
227    }
228    if (n < 0) {
229        ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
230    }
231    return latest;
232}
233
234void RenderThread::drainDisplayEventQueue() {
235    ATRACE_CALL();
236    nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
237    if (vsyncEvent > 0) {
238        mVsyncRequested = false;
239        if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) {
240            ATRACE_NAME("queue mFrameCallbackTask");
241            mFrameCallbackTaskPending = true;
242            nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY);
243            queueAt(mFrameCallbackTask, runAt);
244        }
245    }
246}
247
248void RenderThread::dispatchFrameCallbacks() {
249    ATRACE_CALL();
250    mFrameCallbackTaskPending = false;
251
252    std::set<IFrameCallback*> callbacks;
253    mFrameCallbacks.swap(callbacks);
254
255    if (callbacks.size()) {
256        // Assume one of them will probably animate again so preemptively
257        // request the next vsync in case it occurs mid-frame
258        requestVsync();
259        for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
260            (*it)->doFrame();
261        }
262    }
263}
264
265void RenderThread::requestVsync() {
266    if (!mVsyncRequested) {
267        mVsyncRequested = true;
268        status_t status = mDisplayEventReceiver->requestNextVsync();
269        LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
270                "requestNextVsync failed with status: %d", status);
271    }
272}
273
274bool RenderThread::threadLoop() {
275    setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
276    initThreadLocals();
277
278    int timeoutMillis = -1;
279    for (;;) {
280        int result = mLooper->pollOnce(timeoutMillis);
281        LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
282                "RenderThread Looper POLL_ERROR!");
283
284        nsecs_t nextWakeup;
285        // Process our queue, if we have anything
286        while (RenderTask* task = nextTask(&nextWakeup)) {
287            task->run();
288            // task may have deleted itself, do not reference it again
289        }
290        if (nextWakeup == LLONG_MAX) {
291            timeoutMillis = -1;
292        } else {
293            nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC);
294            timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos);
295            if (timeoutMillis < 0) {
296                timeoutMillis = 0;
297            }
298        }
299
300        if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
301            drainDisplayEventQueue();
302            mFrameCallbacks.insert(
303                    mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end());
304            mPendingRegistrationFrameCallbacks.clear();
305            requestVsync();
306        }
307
308        if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) {
309            // TODO: Clean this up. This is working around an issue where a combination
310            // of bad timing and slow drawing can result in dropping a stale vsync
311            // on the floor (correct!) but fails to schedule to listen for the
312            // next vsync (oops), so none of the callbacks are run.
313            requestVsync();
314        }
315    }
316
317    return false;
318}
319
320void RenderThread::queue(RenderTask* task) {
321    AutoMutex _lock(mLock);
322    mQueue.queue(task);
323    if (mNextWakeup && task->mRunAt < mNextWakeup) {
324        mNextWakeup = 0;
325        mLooper->wake();
326    }
327}
328
329void RenderThread::queueAndWait(RenderTask* task) {
330    // These need to be local to the thread to avoid the Condition
331    // signaling the wrong thread. The easiest way to achieve that is to just
332    // make this on the stack, although that has a slight cost to it
333    Mutex mutex;
334    Condition condition;
335    SignalingRenderTask syncTask(task, &mutex, &condition);
336
337    AutoMutex _lock(mutex);
338    queue(&syncTask);
339    condition.wait(mutex);
340}
341
342void RenderThread::queueAtFront(RenderTask* task) {
343    AutoMutex _lock(mLock);
344    mQueue.queueAtFront(task);
345    mLooper->wake();
346}
347
348void RenderThread::queueAt(RenderTask* task, nsecs_t runAtNs) {
349    task->mRunAt = runAtNs;
350    queue(task);
351}
352
353void RenderThread::remove(RenderTask* task) {
354    AutoMutex _lock(mLock);
355    mQueue.remove(task);
356}
357
358void RenderThread::postFrameCallback(IFrameCallback* callback) {
359    mPendingRegistrationFrameCallbacks.insert(callback);
360}
361
362bool RenderThread::removeFrameCallback(IFrameCallback* callback) {
363    size_t erased;
364    erased = mFrameCallbacks.erase(callback);
365    erased |= mPendingRegistrationFrameCallbacks.erase(callback);
366    return erased;
367}
368
369void RenderThread::pushBackFrameCallback(IFrameCallback* callback) {
370    if (mFrameCallbacks.erase(callback)) {
371        mPendingRegistrationFrameCallbacks.insert(callback);
372    }
373}
374
375RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
376    AutoMutex _lock(mLock);
377    RenderTask* next = mQueue.peek();
378    if (!next) {
379        mNextWakeup = LLONG_MAX;
380    } else {
381        mNextWakeup = next->mRunAt;
382        // Most tasks won't be delayed, so avoid unnecessary systemTime() calls
383        if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
384            next = mQueue.next();
385        } else {
386            next = nullptr;
387        }
388    }
389    if (nextWakeup) {
390        *nextWakeup = mNextWakeup;
391    }
392    return next;
393}
394
395} /* namespace renderthread */
396} /* namespace uirenderer */
397} /* namespace android */
398