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/Log.h>
29 
30 namespace android {
31 using namespace uirenderer::renderthread;
32 ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread);
33 
34 namespace uirenderer {
35 namespace 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.
40 static 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
43 static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4);
44 
TaskQueue()45 TaskQueue::TaskQueue() : mHead(nullptr), mTail(nullptr) {}
46 
next()47 RenderTask* TaskQueue::next() {
48     RenderTask* ret = mHead;
49     if (ret) {
50         mHead = ret->mNext;
51         if (!mHead) {
52             mTail = nullptr;
53         }
54         ret->mNext = nullptr;
55     }
56     return ret;
57 }
58 
peek()59 RenderTask* TaskQueue::peek() {
60     return mHead;
61 }
62 
queue(RenderTask * task)63 void 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 = nullptr;
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 
queueAtFront(RenderTask * task)97 void TaskQueue::queueAtFront(RenderTask* task) {
98     if (mTail) {
99         task->mNext = mHead;
100         mHead = task;
101     } else {
102         mTail = mHead = task;
103     }
104 }
105 
remove(RenderTask * task)106 void 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 
128 class DispatchFrameCallbacks : public RenderTask {
129 private:
130     RenderThread* mRenderThread;
131 public:
DispatchFrameCallbacks(RenderThread * rt)132     DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {}
133 
run()134     virtual void run() override {
135         mRenderThread->dispatchFrameCallbacks();
136     }
137 };
138 
RenderThread()139 RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>()
140         , mNextWakeup(LLONG_MAX)
141         , mDisplayEventReceiver(nullptr)
142         , mVsyncRequested(false)
143         , mFrameCallbackTaskPending(false)
144         , mFrameCallbackTask(nullptr)
145         , mRenderState(nullptr)
146         , mEglManager(nullptr) {
147     Properties::load();
148     mFrameCallbackTask = new DispatchFrameCallbacks(this);
149     mLooper = new Looper(false);
150     run("RenderThread");
151 }
152 
~RenderThread()153 RenderThread::~RenderThread() {
154     LOG_ALWAYS_FATAL("Can't destroy the render thread");
155 }
156 
initializeDisplayEventReceiver()157 void 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 
initThreadLocals()169 void RenderThread::initThreadLocals() {
170     sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
171             ISurfaceComposer::eDisplayIdMain));
172     status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
173     LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
174     nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
175     mTimeLord.setFrameInterval(frameIntervalNanos);
176     initializeDisplayEventReceiver();
177     mEglManager = new EglManager(*this);
178     mRenderState = new RenderState(*this);
179     mJankTracker = new JankTracker(frameIntervalNanos);
180 }
181 
displayEventReceiverCallback(int fd,int events,void * data)182 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
183     if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
184         ALOGE("Display event receiver pipe was closed or an error occurred.  "
185                 "events=0x%x", events);
186         return 0; // remove the callback
187     }
188 
189     if (!(events & Looper::EVENT_INPUT)) {
190         ALOGW("Received spurious callback for unhandled poll event.  "
191                 "events=0x%x", events);
192         return 1; // keep the callback
193     }
194 
195     reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();
196 
197     return 1; // keep the callback
198 }
199 
latestVsyncEvent(DisplayEventReceiver * receiver)200 static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) {
201     DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
202     nsecs_t latest = 0;
203     ssize_t n;
204     while ((n = receiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
205         for (ssize_t i = 0; i < n; i++) {
206             const DisplayEventReceiver::Event& ev = buf[i];
207             switch (ev.header.type) {
208             case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
209                 latest = ev.header.timestamp;
210                 break;
211             }
212         }
213     }
214     if (n < 0) {
215         ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
216     }
217     return latest;
218 }
219 
drainDisplayEventQueue()220 void RenderThread::drainDisplayEventQueue() {
221     ATRACE_CALL();
222     nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
223     if (vsyncEvent > 0) {
224         mVsyncRequested = false;
225         if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) {
226             ATRACE_NAME("queue mFrameCallbackTask");
227             mFrameCallbackTaskPending = true;
228             nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY);
229             queueAt(mFrameCallbackTask, runAt);
230         }
231     }
232 }
233 
dispatchFrameCallbacks()234 void RenderThread::dispatchFrameCallbacks() {
235     ATRACE_CALL();
236     mFrameCallbackTaskPending = false;
237 
238     std::set<IFrameCallback*> callbacks;
239     mFrameCallbacks.swap(callbacks);
240 
241     if (callbacks.size()) {
242         // Assume one of them will probably animate again so preemptively
243         // request the next vsync in case it occurs mid-frame
244         requestVsync();
245         for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
246             (*it)->doFrame();
247         }
248     }
249 }
250 
requestVsync()251 void RenderThread::requestVsync() {
252     if (!mVsyncRequested) {
253         mVsyncRequested = true;
254         status_t status = mDisplayEventReceiver->requestNextVsync();
255         LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
256                 "requestNextVsync failed with status: %d", status);
257     }
258 }
259 
threadLoop()260 bool RenderThread::threadLoop() {
261     setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
262     initThreadLocals();
263 
264     int timeoutMillis = -1;
265     for (;;) {
266         int result = mLooper->pollOnce(timeoutMillis);
267         LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
268                 "RenderThread Looper POLL_ERROR!");
269 
270         nsecs_t nextWakeup;
271         // Process our queue, if we have anything
272         while (RenderTask* task = nextTask(&nextWakeup)) {
273             task->run();
274             // task may have deleted itself, do not reference it again
275         }
276         if (nextWakeup == LLONG_MAX) {
277             timeoutMillis = -1;
278         } else {
279             nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC);
280             timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos);
281             if (timeoutMillis < 0) {
282                 timeoutMillis = 0;
283             }
284         }
285 
286         if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
287             drainDisplayEventQueue();
288             mFrameCallbacks.insert(
289                     mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end());
290             mPendingRegistrationFrameCallbacks.clear();
291             requestVsync();
292         }
293 
294         if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) {
295             // TODO: Clean this up. This is working around an issue where a combination
296             // of bad timing and slow drawing can result in dropping a stale vsync
297             // on the floor (correct!) but fails to schedule to listen for the
298             // next vsync (oops), so none of the callbacks are run.
299             requestVsync();
300         }
301     }
302 
303     return false;
304 }
305 
queue(RenderTask * task)306 void RenderThread::queue(RenderTask* task) {
307     AutoMutex _lock(mLock);
308     mQueue.queue(task);
309     if (mNextWakeup && task->mRunAt < mNextWakeup) {
310         mNextWakeup = 0;
311         mLooper->wake();
312     }
313 }
314 
queueAtFront(RenderTask * task)315 void RenderThread::queueAtFront(RenderTask* task) {
316     AutoMutex _lock(mLock);
317     mQueue.queueAtFront(task);
318     mLooper->wake();
319 }
320 
queueAt(RenderTask * task,nsecs_t runAtNs)321 void RenderThread::queueAt(RenderTask* task, nsecs_t runAtNs) {
322     task->mRunAt = runAtNs;
323     queue(task);
324 }
325 
remove(RenderTask * task)326 void RenderThread::remove(RenderTask* task) {
327     AutoMutex _lock(mLock);
328     mQueue.remove(task);
329 }
330 
postFrameCallback(IFrameCallback * callback)331 void RenderThread::postFrameCallback(IFrameCallback* callback) {
332     mPendingRegistrationFrameCallbacks.insert(callback);
333 }
334 
removeFrameCallback(IFrameCallback * callback)335 bool RenderThread::removeFrameCallback(IFrameCallback* callback) {
336     size_t erased;
337     erased = mFrameCallbacks.erase(callback);
338     erased |= mPendingRegistrationFrameCallbacks.erase(callback);
339     return erased;
340 }
341 
pushBackFrameCallback(IFrameCallback * callback)342 void RenderThread::pushBackFrameCallback(IFrameCallback* callback) {
343     if (mFrameCallbacks.erase(callback)) {
344         mPendingRegistrationFrameCallbacks.insert(callback);
345     }
346 }
347 
nextTask(nsecs_t * nextWakeup)348 RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
349     AutoMutex _lock(mLock);
350     RenderTask* next = mQueue.peek();
351     if (!next) {
352         mNextWakeup = LLONG_MAX;
353     } else {
354         mNextWakeup = next->mRunAt;
355         // Most tasks won't be delayed, so avoid unnecessary systemTime() calls
356         if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
357             next = mQueue.next();
358         } else {
359             next = nullptr;
360         }
361     }
362     if (nextWakeup) {
363         *nextWakeup = mNextWakeup;
364     }
365     return next;
366 }
367 
368 } /* namespace renderthread */
369 } /* namespace uirenderer */
370 } /* namespace android */
371