RenderThread.cpp revision 12efa55094b2fe38ef5ce232f3d8f02e78b71621
1dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo/*
2dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * Copyright (C) 2013 The Android Open Source Project
3a3c6f62775506c95afd556e617f14d7a28839f01Luke Drummond *
4dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * Licensed under the Apache License, Version 2.0 (the "License");
5dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * you may not use this file except in compliance with the License.
6dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * You may obtain a copy of the License at
7dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo *
8dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo *      http://www.apache.org/licenses/LICENSE-2.0
9dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo *
10dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * Unless required by applicable law or agreed to in writing, software
11dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * distributed under the License is distributed on an "AS IS" BASIS,
12dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * See the License for the specific language governing permissions and
14dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * limitations under the License.
15dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo */
16dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo
17dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "RenderThread.h"
18dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo
19dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "../renderstate/RenderState.h"
20dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "CanvasContext.h"
21dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "EglManager.h"
22dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "RenderProxy.h"
23dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "VulkanManager.h"
24dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "utils/FatVector.h"
25dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo
26dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include <gui/DisplayEventReceiver.h>
27dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include <gui/ISurfaceComposer.h>
28dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include <gui/SurfaceComposerClient.h>
29dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include <sys/resource.h>
30dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include <utils/Condition.h>
31dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include <utils/Log.h>
32a3c6f62775506c95afd556e617f14d7a28839f01Luke Drummond#include <utils/Mutex.h>
33dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo
34dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leonamespace android {
35dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leonamespace uirenderer {
36dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leonamespace renderthread {
37dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo
38dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo// Number of events to read at a time from the DisplayEventReceiver pipe.
39dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo// The value should be large enough that we can quickly drain the pipe
40dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo// using just a few large reads.
41dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leostatic const size_t EVENT_BUFFER_SIZE = 100;
42dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo
43// Slight delay to give the UI time to push us a new frame before we replay
44static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4);
45
46TaskQueue::TaskQueue() : mHead(nullptr), mTail(nullptr) {}
47
48RenderTask* TaskQueue::next() {
49    RenderTask* ret = mHead;
50    if (ret) {
51        mHead = ret->mNext;
52        if (!mHead) {
53            mTail = nullptr;
54        }
55        ret->mNext = nullptr;
56    }
57    return ret;
58}
59
60RenderTask* TaskQueue::peek() {
61    return mHead;
62}
63
64void TaskQueue::queue(RenderTask* task) {
65    // Since the RenderTask itself forms the linked list it is not allowed
66    // to have the same task queued twice
67    LOG_ALWAYS_FATAL_IF(task->mNext || mTail == task, "Task is already in the queue!");
68    if (mTail) {
69        // Fast path if we can just append
70        if (mTail->mRunAt <= task->mRunAt) {
71            mTail->mNext = task;
72            mTail = task;
73        } else {
74            // Need to find the proper insertion point
75            RenderTask* previous = nullptr;
76            RenderTask* next = mHead;
77            while (next && next->mRunAt <= task->mRunAt) {
78                previous = next;
79                next = next->mNext;
80            }
81            if (!previous) {
82                task->mNext = mHead;
83                mHead = task;
84            } else {
85                previous->mNext = task;
86                if (next) {
87                    task->mNext = next;
88                } else {
89                    mTail = task;
90                }
91            }
92        }
93    } else {
94        mTail = mHead = task;
95    }
96}
97
98void TaskQueue::queueAtFront(RenderTask* task) {
99    if (mTail) {
100        task->mNext = mHead;
101        mHead = task;
102    } else {
103        mTail = mHead = task;
104    }
105}
106
107void TaskQueue::remove(RenderTask* task) {
108    // TaskQueue is strict here to enforce that users are keeping track of
109    // their RenderTasks due to how their memory is managed
110    LOG_ALWAYS_FATAL_IF(!task->mNext && mTail != task,
111            "Cannot remove a task that isn't in the queue!");
112
113    // If task is the head we can just call next() to pop it off
114    // Otherwise we need to scan through to find the task before it
115    if (peek() == task) {
116        next();
117    } else {
118        RenderTask* previous = mHead;
119        while (previous->mNext != task) {
120            previous = previous->mNext;
121        }
122        previous->mNext = task->mNext;
123        if (mTail == task) {
124            mTail = previous;
125        }
126    }
127}
128
129class DispatchFrameCallbacks : public RenderTask {
130private:
131    RenderThread* mRenderThread;
132public:
133    explicit DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {}
134
135    virtual void run() override {
136        mRenderThread->dispatchFrameCallbacks();
137    }
138};
139
140static bool gHasRenderThreadInstance = false;
141
142bool RenderThread::hasInstance() {
143    return gHasRenderThreadInstance;
144}
145
146RenderThread& RenderThread::getInstance() {
147    // This is a pointer because otherwise __cxa_finalize
148    // will try to delete it like a Good Citizen but that causes us to crash
149    // because we don't want to delete the RenderThread normally.
150    static RenderThread* sInstance = new RenderThread();
151    gHasRenderThreadInstance = true;
152    return *sInstance;
153}
154
155RenderThread::RenderThread() : Thread(true)
156        , mNextWakeup(LLONG_MAX)
157        , mDisplayEventReceiver(nullptr)
158        , mVsyncRequested(false)
159        , mFrameCallbackTaskPending(false)
160        , mFrameCallbackTask(nullptr)
161        , mRenderState(nullptr)
162        , mEglManager(nullptr)
163        , mVkManager(nullptr) {
164    Properties::load();
165    mFrameCallbackTask = new DispatchFrameCallbacks(this);
166    mLooper = new Looper(false);
167    run("RenderThread");
168}
169
170RenderThread::~RenderThread() {
171    LOG_ALWAYS_FATAL("Can't destroy the render thread");
172}
173
174void RenderThread::initializeDisplayEventReceiver() {
175    LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?");
176    mDisplayEventReceiver = new DisplayEventReceiver();
177    status_t status = mDisplayEventReceiver->initCheck();
178    LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver "
179            "failed with status: %d", status);
180
181    // Register the FD
182    mLooper->addFd(mDisplayEventReceiver->getFd(), 0,
183            Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this);
184}
185
186void RenderThread::initThreadLocals() {
187    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
188            ISurfaceComposer::eDisplayIdMain));
189    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
190    LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
191    nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
192    mTimeLord.setFrameInterval(frameIntervalNanos);
193    initializeDisplayEventReceiver();
194    mEglManager = new EglManager(*this);
195    mRenderState = new RenderState(*this);
196    mJankTracker = new JankTracker(mDisplayInfo);
197    mVkManager = new VulkanManager(*this);
198}
199
200int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
201    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
202        ALOGE("Display event receiver pipe was closed or an error occurred.  "
203                "events=0x%x", events);
204        return 0; // remove the callback
205    }
206
207    if (!(events & Looper::EVENT_INPUT)) {
208        ALOGW("Received spurious callback for unhandled poll event.  "
209                "events=0x%x", events);
210        return 1; // keep the callback
211    }
212
213    reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();
214
215    return 1; // keep the callback
216}
217
218static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) {
219    DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
220    nsecs_t latest = 0;
221    ssize_t n;
222    while ((n = receiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
223        for (ssize_t i = 0; i < n; i++) {
224            const DisplayEventReceiver::Event& ev = buf[i];
225            switch (ev.header.type) {
226            case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
227                latest = ev.header.timestamp;
228                break;
229            }
230        }
231    }
232    if (n < 0) {
233        ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
234    }
235    return latest;
236}
237
238void RenderThread::drainDisplayEventQueue() {
239    ATRACE_CALL();
240    nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
241    if (vsyncEvent > 0) {
242        mVsyncRequested = false;
243        if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) {
244            ATRACE_NAME("queue mFrameCallbackTask");
245            mFrameCallbackTaskPending = true;
246            nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY);
247            queueAt(mFrameCallbackTask, runAt);
248        }
249    }
250}
251
252void RenderThread::dispatchFrameCallbacks() {
253    ATRACE_CALL();
254    mFrameCallbackTaskPending = false;
255
256    std::set<IFrameCallback*> callbacks;
257    mFrameCallbacks.swap(callbacks);
258
259    if (callbacks.size()) {
260        // Assume one of them will probably animate again so preemptively
261        // request the next vsync in case it occurs mid-frame
262        requestVsync();
263        for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
264            (*it)->doFrame();
265        }
266    }
267}
268
269void RenderThread::requestVsync() {
270    if (!mVsyncRequested) {
271        mVsyncRequested = true;
272        status_t status = mDisplayEventReceiver->requestNextVsync();
273        LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
274                "requestNextVsync failed with status: %d", status);
275    }
276}
277
278bool RenderThread::threadLoop() {
279    setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
280    initThreadLocals();
281
282    int timeoutMillis = -1;
283    for (;;) {
284        int result = mLooper->pollOnce(timeoutMillis);
285        LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
286                "RenderThread Looper POLL_ERROR!");
287
288        nsecs_t nextWakeup;
289        {
290            FatVector<RenderTask*, 10> workQueue;
291            // Process our queue, if we have anything. By first acquiring
292            // all the pending events then processing them we avoid vsync
293            // starvation if more tasks are queued while we are processing tasks.
294            while (RenderTask* task = nextTask(&nextWakeup)) {
295                workQueue.push_back(task);
296            }
297            for (auto task : workQueue) {
298                task->run();
299                // task may have deleted itself, do not reference it again
300            }
301        }
302        if (nextWakeup == LLONG_MAX) {
303            timeoutMillis = -1;
304        } else {
305            nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC);
306            timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos);
307            if (timeoutMillis < 0) {
308                timeoutMillis = 0;
309            }
310        }
311
312        if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
313            drainDisplayEventQueue();
314            mFrameCallbacks.insert(
315                    mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end());
316            mPendingRegistrationFrameCallbacks.clear();
317            requestVsync();
318        }
319
320        if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) {
321            // TODO: Clean this up. This is working around an issue where a combination
322            // of bad timing and slow drawing can result in dropping a stale vsync
323            // on the floor (correct!) but fails to schedule to listen for the
324            // next vsync (oops), so none of the callbacks are run.
325            requestVsync();
326        }
327    }
328
329    return false;
330}
331
332void RenderThread::queue(RenderTask* task) {
333    AutoMutex _lock(mLock);
334    mQueue.queue(task);
335    if (mNextWakeup && task->mRunAt < mNextWakeup) {
336        mNextWakeup = 0;
337        mLooper->wake();
338    }
339}
340
341void RenderThread::queueAndWait(RenderTask* task) {
342    // These need to be local to the thread to avoid the Condition
343    // signaling the wrong thread. The easiest way to achieve that is to just
344    // make this on the stack, although that has a slight cost to it
345    Mutex mutex;
346    Condition condition;
347    SignalingRenderTask syncTask(task, &mutex, &condition);
348
349    AutoMutex _lock(mutex);
350    queue(&syncTask);
351    condition.wait(mutex);
352}
353
354void RenderThread::queueAtFront(RenderTask* task) {
355    AutoMutex _lock(mLock);
356    mQueue.queueAtFront(task);
357    mLooper->wake();
358}
359
360void RenderThread::queueAt(RenderTask* task, nsecs_t runAtNs) {
361    task->mRunAt = runAtNs;
362    queue(task);
363}
364
365void RenderThread::remove(RenderTask* task) {
366    AutoMutex _lock(mLock);
367    mQueue.remove(task);
368}
369
370void RenderThread::postFrameCallback(IFrameCallback* callback) {
371    mPendingRegistrationFrameCallbacks.insert(callback);
372}
373
374bool RenderThread::removeFrameCallback(IFrameCallback* callback) {
375    size_t erased;
376    erased = mFrameCallbacks.erase(callback);
377    erased |= mPendingRegistrationFrameCallbacks.erase(callback);
378    return erased;
379}
380
381void RenderThread::pushBackFrameCallback(IFrameCallback* callback) {
382    if (mFrameCallbacks.erase(callback)) {
383        mPendingRegistrationFrameCallbacks.insert(callback);
384    }
385}
386
387RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
388    AutoMutex _lock(mLock);
389    RenderTask* next = mQueue.peek();
390    if (!next) {
391        mNextWakeup = LLONG_MAX;
392    } else {
393        mNextWakeup = next->mRunAt;
394        // Most tasks won't be delayed, so avoid unnecessary systemTime() calls
395        if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
396            next = mQueue.next();
397        } else {
398            next = nullptr;
399        }
400    }
401    if (nextWakeup) {
402        *nextWakeup = mNextWakeup;
403    }
404    return next;
405}
406
407} /* namespace renderthread */
408} /* namespace uirenderer */
409} /* namespace android */
410