blob: 35a3eabce925a782ecd94987d02a3c060ecf3810 [file] [log] [blame]
John Reckcec24ae2013-11-05 13:27:50 -08001/*
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
John Recke45b1fd2014-04-15 09:50:16 -070021#include <gui/DisplayEventReceiver.h>
22#include <utils/Log.h>
23
John Reck4f02bf42014-01-03 18:09:17 -080024#include "CanvasContext.h"
25#include "RenderProxy.h"
John Reckcec24ae2013-11-05 13:27:50 -080026
27namespace android {
28using namespace uirenderer::renderthread;
29ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread);
30
31namespace uirenderer {
32namespace renderthread {
33
John Recke45b1fd2014-04-15 09:50:16 -070034// Number of events to read at a time from the DisplayEventReceiver pipe.
35// The value should be large enough that we can quickly drain the pipe
36// using just a few large reads.
37static const size_t EVENT_BUFFER_SIZE = 100;
38
39// Slight delay to give the UI time to push us a new frame before we replay
40static const int DISPATCH_FRAME_CALLBACKS_DELAY = 0;
41
John Reck4f02bf42014-01-03 18:09:17 -080042TaskQueue::TaskQueue() : mHead(0), mTail(0) {}
43
44RenderTask* TaskQueue::next() {
45 RenderTask* ret = mHead;
46 if (ret) {
47 mHead = ret->mNext;
48 if (!mHead) {
49 mTail = 0;
50 }
51 ret->mNext = 0;
52 }
53 return ret;
54}
55
56RenderTask* TaskQueue::peek() {
57 return mHead;
58}
59
60void TaskQueue::queue(RenderTask* task) {
61 // Since the RenderTask itself forms the linked list it is not allowed
62 // to have the same task queued twice
63 LOG_ALWAYS_FATAL_IF(task->mNext || mTail == task, "Task is already in the queue!");
64 if (mTail) {
65 // Fast path if we can just append
66 if (mTail->mRunAt <= task->mRunAt) {
67 mTail->mNext = task;
68 mTail = task;
69 } else {
70 // Need to find the proper insertion point
71 RenderTask* previous = 0;
72 RenderTask* next = mHead;
73 while (next && next->mRunAt <= task->mRunAt) {
74 previous = next;
75 next = next->mNext;
76 }
77 if (!previous) {
78 task->mNext = mHead;
79 mHead = task;
80 } else {
81 previous->mNext = task;
82 if (next) {
83 task->mNext = next;
84 } else {
85 mTail = task;
86 }
87 }
88 }
89 } else {
90 mTail = mHead = task;
91 }
92}
93
94void TaskQueue::remove(RenderTask* task) {
95 // TaskQueue is strict here to enforce that users are keeping track of
96 // their RenderTasks due to how their memory is managed
97 LOG_ALWAYS_FATAL_IF(!task->mNext && mTail != task,
98 "Cannot remove a task that isn't in the queue!");
99
100 // If task is the head we can just call next() to pop it off
101 // Otherwise we need to scan through to find the task before it
102 if (peek() == task) {
103 next();
104 } else {
105 RenderTask* previous = mHead;
106 while (previous->mNext != task) {
107 previous = previous->mNext;
108 }
109 previous->mNext = task->mNext;
110 if (mTail == task) {
111 mTail = previous;
112 }
113 }
114}
115
John Recke45b1fd2014-04-15 09:50:16 -0700116class DispatchFrameCallbacks : public RenderTask {
117private:
118 RenderThread* mRenderThread;
119public:
120 DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {}
121
122 virtual void run() {
123 mRenderThread->dispatchFrameCallbacks();
124 }
125};
126
John Reckcec24ae2013-11-05 13:27:50 -0800127RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>()
John Recke45b1fd2014-04-15 09:50:16 -0700128 , mNextWakeup(LLONG_MAX)
129 , mDisplayEventReceiver(0)
130 , mVsyncRequested(false)
131 , mFrameCallbackTaskPending(false)
John Reck18f16e62014-05-02 16:46:41 -0700132 , mFrameCallbackTask(0) {
John Recke45b1fd2014-04-15 09:50:16 -0700133 mFrameCallbackTask = new DispatchFrameCallbacks(this);
John Reckcec24ae2013-11-05 13:27:50 -0800134 mLooper = new Looper(false);
135 run("RenderThread");
136}
137
138RenderThread::~RenderThread() {
139}
140
John Recke45b1fd2014-04-15 09:50:16 -0700141void RenderThread::initializeDisplayEventReceiver() {
142 LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?");
143 mDisplayEventReceiver = new DisplayEventReceiver();
144 status_t status = mDisplayEventReceiver->initCheck();
145 LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver "
146 "failed with status: %d", status);
147
148 // Register the FD
149 mLooper->addFd(mDisplayEventReceiver->getFd(), 0,
150 Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this);
151}
152
153int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
154 if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
155 ALOGE("Display event receiver pipe was closed or an error occurred. "
156 "events=0x%x", events);
157 return 0; // remove the callback
158 }
159
160 if (!(events & Looper::EVENT_INPUT)) {
161 ALOGW("Received spurious callback for unhandled poll event. "
162 "events=0x%x", events);
163 return 1; // keep the callback
164 }
165
166 reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();
167
168 return 1; // keep the callback
169}
170
171static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) {
172 DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
173 nsecs_t latest = 0;
174 ssize_t n;
175 while ((n = receiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
176 for (ssize_t i = 0; i < n; i++) {
177 const DisplayEventReceiver::Event& ev = buf[i];
178 switch (ev.header.type) {
179 case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
180 latest = ev.header.timestamp;
181 break;
182 }
183 }
184 }
185 if (n < 0) {
186 ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
187 }
188 return latest;
189}
190
191void RenderThread::drainDisplayEventQueue() {
192 nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
193 if (vsyncEvent > 0) {
194 mVsyncRequested = false;
John Reck18f16e62014-05-02 16:46:41 -0700195 mTimeLord.vsyncReceived(vsyncEvent);
John Recke45b1fd2014-04-15 09:50:16 -0700196 if (!mFrameCallbackTaskPending) {
197 mFrameCallbackTaskPending = true;
198 //queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY);
199 queue(mFrameCallbackTask);
200 }
201 }
202}
203
204void RenderThread::dispatchFrameCallbacks() {
205 mFrameCallbackTaskPending = false;
206
207 std::set<IFrameCallback*> callbacks;
208 mFrameCallbacks.swap(callbacks);
209
210 for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
John Reck18f16e62014-05-02 16:46:41 -0700211 (*it)->doFrame();
John Recke45b1fd2014-04-15 09:50:16 -0700212 }
213}
214
John Reckcec24ae2013-11-05 13:27:50 -0800215bool RenderThread::threadLoop() {
John Recke45b1fd2014-04-15 09:50:16 -0700216 initializeDisplayEventReceiver();
217
John Reck4f02bf42014-01-03 18:09:17 -0800218 int timeoutMillis = -1;
John Reckcec24ae2013-11-05 13:27:50 -0800219 for (;;) {
John Recke45b1fd2014-04-15 09:50:16 -0700220 int result = mLooper->pollOnce(timeoutMillis);
John Reck4f02bf42014-01-03 18:09:17 -0800221 LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
222 "RenderThread Looper POLL_ERROR!");
223
224 nsecs_t nextWakeup;
John Reckcec24ae2013-11-05 13:27:50 -0800225 // Process our queue, if we have anything
John Reck4f02bf42014-01-03 18:09:17 -0800226 while (RenderTask* task = nextTask(&nextWakeup)) {
John Reckcec24ae2013-11-05 13:27:50 -0800227 task->run();
John Reck4f02bf42014-01-03 18:09:17 -0800228 // task may have deleted itself, do not reference it again
229 }
230 if (nextWakeup == LLONG_MAX) {
231 timeoutMillis = -1;
232 } else {
John Recka6260b82014-01-29 18:31:51 -0800233 nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC);
234 timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos);
John Reck4f02bf42014-01-03 18:09:17 -0800235 if (timeoutMillis < 0) {
236 timeoutMillis = 0;
237 }
John Reckcec24ae2013-11-05 13:27:50 -0800238 }
239 }
240
241 return false;
242}
243
244void RenderThread::queue(RenderTask* task) {
245 AutoMutex _lock(mLock);
John Reck4f02bf42014-01-03 18:09:17 -0800246 mQueue.queue(task);
247 if (mNextWakeup && task->mRunAt < mNextWakeup) {
248 mNextWakeup = 0;
John Reckcec24ae2013-11-05 13:27:50 -0800249 mLooper->wake();
250 }
251}
252
John Reck4f02bf42014-01-03 18:09:17 -0800253void RenderThread::queueDelayed(RenderTask* task, int delayMs) {
254 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
John Recka6260b82014-01-29 18:31:51 -0800255 task->mRunAt = now + milliseconds_to_nanoseconds(delayMs);
John Reck4f02bf42014-01-03 18:09:17 -0800256 queue(task);
257}
258
259void RenderThread::remove(RenderTask* task) {
John Reckcec24ae2013-11-05 13:27:50 -0800260 AutoMutex _lock(mLock);
John Reck4f02bf42014-01-03 18:09:17 -0800261 mQueue.remove(task);
262}
263
John Recke45b1fd2014-04-15 09:50:16 -0700264void RenderThread::postFrameCallback(IFrameCallback* callback) {
265 mFrameCallbacks.insert(callback);
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
274void RenderThread::removeFrameCallback(IFrameCallback* callback) {
275 mFrameCallbacks.erase(callback);
276}
277
John Reck4f02bf42014-01-03 18:09:17 -0800278RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
279 AutoMutex _lock(mLock);
280 RenderTask* next = mQueue.peek();
281 if (!next) {
282 mNextWakeup = LLONG_MAX;
283 } else {
284 // Most tasks won't be delayed, so avoid unnecessary systemTime() calls
285 if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
286 next = mQueue.next();
John Reckcec24ae2013-11-05 13:27:50 -0800287 }
John Reck4f02bf42014-01-03 18:09:17 -0800288 mNextWakeup = next->mRunAt;
John Reckcec24ae2013-11-05 13:27:50 -0800289 }
John Reck4f02bf42014-01-03 18:09:17 -0800290 if (nextWakeup) {
291 *nextWakeup = mNextWakeup;
292 }
293 return next;
John Reckcec24ae2013-11-05 13:27:50 -0800294}
295
296} /* namespace renderthread */
297} /* namespace uirenderer */
298} /* namespace android */