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 #if defined(HAVE_PTHREADS) 20 #include <sys/resource.h> 21 #endif 22 #include <gui/DisplayEventReceiver.h> 23 #include <utils/Log.h> 24 25 #include "../RenderState.h" 26 #include "CanvasContext.h" 27 #include "EglManager.h" 28 #include "RenderProxy.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 int DISPATCH_FRAME_CALLBACKS_DELAY = 4; 44 45 TaskQueue::TaskQueue() : mHead(0), mTail(0) {} 46 47 RenderTask* TaskQueue::next() { 48 RenderTask* ret = mHead; 49 if (ret) { 50 mHead = ret->mNext; 51 if (!mHead) { 52 mTail = 0; 53 } 54 ret->mNext = 0; 55 } 56 return ret; 57 } 58 59 RenderTask* TaskQueue::peek() { 60 return mHead; 61 } 62 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 = 0; 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 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 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: 132 DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {} 133 134 virtual void run() { 135 mRenderThread->dispatchFrameCallbacks(); 136 } 137 }; 138 139 RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>() 140 , mNextWakeup(LLONG_MAX) 141 , mDisplayEventReceiver(0) 142 , mVsyncRequested(false) 143 , mFrameCallbackTaskPending(false) 144 , mFrameCallbackTask(0) 145 , mRenderState(NULL) 146 , mEglManager(NULL) { 147 mFrameCallbackTask = new DispatchFrameCallbacks(this); 148 mLooper = new Looper(false); 149 run("RenderThread"); 150 } 151 152 RenderThread::~RenderThread() { 153 LOG_ALWAYS_FATAL("Can't destroy the render thread"); 154 } 155 156 void RenderThread::initializeDisplayEventReceiver() { 157 LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?"); 158 mDisplayEventReceiver = new DisplayEventReceiver(); 159 status_t status = mDisplayEventReceiver->initCheck(); 160 LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver " 161 "failed with status: %d", status); 162 163 // Register the FD 164 mLooper->addFd(mDisplayEventReceiver->getFd(), 0, 165 Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this); 166 } 167 168 void RenderThread::initThreadLocals() { 169 initializeDisplayEventReceiver(); 170 mEglManager = new EglManager(*this); 171 mRenderState = new RenderState(); 172 } 173 174 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) { 175 if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { 176 ALOGE("Display event receiver pipe was closed or an error occurred. " 177 "events=0x%x", events); 178 return 0; // remove the callback 179 } 180 181 if (!(events & Looper::EVENT_INPUT)) { 182 ALOGW("Received spurious callback for unhandled poll event. " 183 "events=0x%x", events); 184 return 1; // keep the callback 185 } 186 187 reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue(); 188 189 return 1; // keep the callback 190 } 191 192 static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) { 193 DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; 194 nsecs_t latest = 0; 195 ssize_t n; 196 while ((n = receiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { 197 for (ssize_t i = 0; i < n; i++) { 198 const DisplayEventReceiver::Event& ev = buf[i]; 199 switch (ev.header.type) { 200 case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: 201 latest = ev.header.timestamp; 202 break; 203 } 204 } 205 } 206 if (n < 0) { 207 ALOGW("Failed to get events from display event receiver, status=%d", status_t(n)); 208 } 209 return latest; 210 } 211 212 void RenderThread::drainDisplayEventQueue(bool skipCallbacks) { 213 ATRACE_CALL(); 214 nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver); 215 if (vsyncEvent > 0) { 216 mVsyncRequested = false; 217 mTimeLord.vsyncReceived(vsyncEvent); 218 if (!skipCallbacks && !mFrameCallbackTaskPending) { 219 ATRACE_NAME("queue mFrameCallbackTask"); 220 mFrameCallbackTaskPending = true; 221 queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY); 222 } 223 } 224 } 225 226 void RenderThread::dispatchFrameCallbacks() { 227 ATRACE_CALL(); 228 mFrameCallbackTaskPending = false; 229 230 std::set<IFrameCallback*> callbacks; 231 mFrameCallbacks.swap(callbacks); 232 233 for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) { 234 (*it)->doFrame(); 235 } 236 } 237 238 void RenderThread::requestVsync() { 239 if (!mVsyncRequested) { 240 mVsyncRequested = true; 241 status_t status = mDisplayEventReceiver->requestNextVsync(); 242 LOG_ALWAYS_FATAL_IF(status != NO_ERROR, 243 "requestNextVsync failed with status: %d", status); 244 } 245 } 246 247 bool RenderThread::threadLoop() { 248 #if defined(HAVE_PTHREADS) 249 setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY); 250 #endif 251 initThreadLocals(); 252 253 int timeoutMillis = -1; 254 for (;;) { 255 int result = mLooper->pollOnce(timeoutMillis); 256 LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, 257 "RenderThread Looper POLL_ERROR!"); 258 259 nsecs_t nextWakeup; 260 // Process our queue, if we have anything 261 while (RenderTask* task = nextTask(&nextWakeup)) { 262 task->run(); 263 // task may have deleted itself, do not reference it again 264 } 265 if (nextWakeup == LLONG_MAX) { 266 timeoutMillis = -1; 267 } else { 268 nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC); 269 timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos); 270 if (timeoutMillis < 0) { 271 timeoutMillis = 0; 272 } 273 } 274 275 if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) { 276 drainDisplayEventQueue(true); 277 mFrameCallbacks.insert( 278 mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end()); 279 mPendingRegistrationFrameCallbacks.clear(); 280 requestVsync(); 281 } 282 } 283 284 return false; 285 } 286 287 void RenderThread::queue(RenderTask* task) { 288 AutoMutex _lock(mLock); 289 mQueue.queue(task); 290 if (mNextWakeup && task->mRunAt < mNextWakeup) { 291 mNextWakeup = 0; 292 mLooper->wake(); 293 } 294 } 295 296 void RenderThread::queueAtFront(RenderTask* task) { 297 AutoMutex _lock(mLock); 298 mQueue.queueAtFront(task); 299 mLooper->wake(); 300 } 301 302 void RenderThread::queueDelayed(RenderTask* task, int delayMs) { 303 nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); 304 task->mRunAt = now + milliseconds_to_nanoseconds(delayMs); 305 queue(task); 306 } 307 308 void RenderThread::remove(RenderTask* task) { 309 AutoMutex _lock(mLock); 310 mQueue.remove(task); 311 } 312 313 void RenderThread::postFrameCallback(IFrameCallback* callback) { 314 mPendingRegistrationFrameCallbacks.insert(callback); 315 } 316 317 void RenderThread::removeFrameCallback(IFrameCallback* callback) { 318 mFrameCallbacks.erase(callback); 319 mPendingRegistrationFrameCallbacks.erase(callback); 320 } 321 322 void RenderThread::pushBackFrameCallback(IFrameCallback* callback) { 323 if (mFrameCallbacks.erase(callback)) { 324 mPendingRegistrationFrameCallbacks.insert(callback); 325 } 326 } 327 328 RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { 329 AutoMutex _lock(mLock); 330 RenderTask* next = mQueue.peek(); 331 if (!next) { 332 mNextWakeup = LLONG_MAX; 333 } else { 334 mNextWakeup = next->mRunAt; 335 // Most tasks won't be delayed, so avoid unnecessary systemTime() calls 336 if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) { 337 next = mQueue.next(); 338 } else { 339 next = 0; 340 } 341 } 342 if (nextWakeup) { 343 *nextWakeup = mNextWakeup; 344 } 345 return next; 346 } 347 348 } /* namespace renderthread */ 349 } /* namespace uirenderer */ 350 } /* namespace android */ 351