blob: e4ec164ff02ba36bfd1a32af0073ce73555d0df2 [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 Reck4f02bf42014-01-03 18:09:17 -080021#include "CanvasContext.h"
22#include "RenderProxy.h"
John Reckcec24ae2013-11-05 13:27:50 -080023#include <utils/Log.h>
24
25namespace android {
26using namespace uirenderer::renderthread;
27ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread);
28
29namespace uirenderer {
30namespace renderthread {
31
John Reck4f02bf42014-01-03 18:09:17 -080032TaskQueue::TaskQueue() : mHead(0), mTail(0) {}
33
34RenderTask* TaskQueue::next() {
35 RenderTask* ret = mHead;
36 if (ret) {
37 mHead = ret->mNext;
38 if (!mHead) {
39 mTail = 0;
40 }
41 ret->mNext = 0;
42 }
43 return ret;
44}
45
46RenderTask* TaskQueue::peek() {
47 return mHead;
48}
49
50void TaskQueue::queue(RenderTask* task) {
51 // Since the RenderTask itself forms the linked list it is not allowed
52 // to have the same task queued twice
53 LOG_ALWAYS_FATAL_IF(task->mNext || mTail == task, "Task is already in the queue!");
54 if (mTail) {
55 // Fast path if we can just append
56 if (mTail->mRunAt <= task->mRunAt) {
57 mTail->mNext = task;
58 mTail = task;
59 } else {
60 // Need to find the proper insertion point
61 RenderTask* previous = 0;
62 RenderTask* next = mHead;
63 while (next && next->mRunAt <= task->mRunAt) {
64 previous = next;
65 next = next->mNext;
66 }
67 if (!previous) {
68 task->mNext = mHead;
69 mHead = task;
70 } else {
71 previous->mNext = task;
72 if (next) {
73 task->mNext = next;
74 } else {
75 mTail = task;
76 }
77 }
78 }
79 } else {
80 mTail = mHead = task;
81 }
82}
83
84void TaskQueue::remove(RenderTask* task) {
85 // TaskQueue is strict here to enforce that users are keeping track of
86 // their RenderTasks due to how their memory is managed
87 LOG_ALWAYS_FATAL_IF(!task->mNext && mTail != task,
88 "Cannot remove a task that isn't in the queue!");
89
90 // If task is the head we can just call next() to pop it off
91 // Otherwise we need to scan through to find the task before it
92 if (peek() == task) {
93 next();
94 } else {
95 RenderTask* previous = mHead;
96 while (previous->mNext != task) {
97 previous = previous->mNext;
98 }
99 previous->mNext = task->mNext;
100 if (mTail == task) {
101 mTail = previous;
102 }
103 }
104}
105
John Reckcec24ae2013-11-05 13:27:50 -0800106RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>()
John Reck4f02bf42014-01-03 18:09:17 -0800107 , mNextWakeup(LLONG_MAX) {
John Reckcec24ae2013-11-05 13:27:50 -0800108 mLooper = new Looper(false);
109 run("RenderThread");
110}
111
112RenderThread::~RenderThread() {
113}
114
115bool RenderThread::threadLoop() {
John Reck4f02bf42014-01-03 18:09:17 -0800116 int timeoutMillis = -1;
John Reckcec24ae2013-11-05 13:27:50 -0800117 for (;;) {
John Reck4f02bf42014-01-03 18:09:17 -0800118 int result = mLooper->pollAll(timeoutMillis);
119 LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
120 "RenderThread Looper POLL_ERROR!");
121
122 nsecs_t nextWakeup;
John Reckcec24ae2013-11-05 13:27:50 -0800123 // Process our queue, if we have anything
John Reck4f02bf42014-01-03 18:09:17 -0800124 while (RenderTask* task = nextTask(&nextWakeup)) {
John Reckcec24ae2013-11-05 13:27:50 -0800125 task->run();
John Reck4f02bf42014-01-03 18:09:17 -0800126 // task may have deleted itself, do not reference it again
127 }
128 if (nextWakeup == LLONG_MAX) {
129 timeoutMillis = -1;
130 } else {
131 timeoutMillis = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC);
132 if (timeoutMillis < 0) {
133 timeoutMillis = 0;
134 }
John Reckcec24ae2013-11-05 13:27:50 -0800135 }
136 }
137
138 return false;
139}
140
141void RenderThread::queue(RenderTask* task) {
142 AutoMutex _lock(mLock);
John Reck4f02bf42014-01-03 18:09:17 -0800143 mQueue.queue(task);
144 if (mNextWakeup && task->mRunAt < mNextWakeup) {
145 mNextWakeup = 0;
John Reckcec24ae2013-11-05 13:27:50 -0800146 mLooper->wake();
147 }
148}
149
John Reck4f02bf42014-01-03 18:09:17 -0800150void RenderThread::queueDelayed(RenderTask* task, int delayMs) {
151 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
152 task->mRunAt = now + delayMs;
153 queue(task);
154}
155
156void RenderThread::remove(RenderTask* task) {
John Reckcec24ae2013-11-05 13:27:50 -0800157 AutoMutex _lock(mLock);
John Reck4f02bf42014-01-03 18:09:17 -0800158 mQueue.remove(task);
159}
160
161RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
162 AutoMutex _lock(mLock);
163 RenderTask* next = mQueue.peek();
164 if (!next) {
165 mNextWakeup = LLONG_MAX;
166 } else {
167 // Most tasks won't be delayed, so avoid unnecessary systemTime() calls
168 if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
169 next = mQueue.next();
John Reckcec24ae2013-11-05 13:27:50 -0800170 }
John Reck4f02bf42014-01-03 18:09:17 -0800171 mNextWakeup = next->mRunAt;
John Reckcec24ae2013-11-05 13:27:50 -0800172 }
John Reck4f02bf42014-01-03 18:09:17 -0800173 if (nextWakeup) {
174 *nextWakeup = mNextWakeup;
175 }
176 return next;
John Reckcec24ae2013-11-05 13:27:50 -0800177}
178
179} /* namespace renderthread */
180} /* namespace uirenderer */
181} /* namespace android */