RenderThread.cpp revision a733f89c05567c97359169832f41389b939baaad
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 30namespace android { 31using namespace uirenderer::renderthread; 32ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread); 33 34namespace uirenderer { 35namespace 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. 40static 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 43static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4); 44 45TaskQueue::TaskQueue() : mHead(0), mTail(0) {} 46 47RenderTask* 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 59RenderTask* TaskQueue::peek() { 60 return mHead; 61} 62 63void 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 97void TaskQueue::queueAtFront(RenderTask* task) { 98 if (mTail) { 99 task->mNext = mHead; 100 mHead = task; 101 } else { 102 mTail = mHead = task; 103 } 104} 105 106void 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 128class DispatchFrameCallbacks : public RenderTask { 129private: 130 RenderThread* mRenderThread; 131public: 132 DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {} 133 134 virtual void run() { 135 mRenderThread->dispatchFrameCallbacks(); 136 } 137}; 138 139RenderThread::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 152RenderThread::~RenderThread() { 153 LOG_ALWAYS_FATAL("Can't destroy the render thread"); 154} 155 156void 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 168void RenderThread::initThreadLocals() { 169 initializeDisplayEventReceiver(); 170 mEglManager = new EglManager(*this); 171 mRenderState = new RenderState(*this); 172} 173 174int 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 192static 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 212void RenderThread::drainDisplayEventQueue() { 213 ATRACE_CALL(); 214 nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver); 215 if (vsyncEvent > 0) { 216 mVsyncRequested = false; 217 if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) { 218 ATRACE_NAME("queue mFrameCallbackTask"); 219 mFrameCallbackTaskPending = true; 220 nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY); 221 queueAt(mFrameCallbackTask, runAt); 222 } 223 } 224} 225 226void RenderThread::dispatchFrameCallbacks() { 227 ATRACE_CALL(); 228 mFrameCallbackTaskPending = false; 229 230 std::set<IFrameCallback*> callbacks; 231 mFrameCallbacks.swap(callbacks); 232 233 if (callbacks.size()) { 234 // Assume one of them will probably animate again so preemptively 235 // request the next vsync in case it occurs mid-frame 236 requestVsync(); 237 for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) { 238 (*it)->doFrame(); 239 } 240 } 241} 242 243void RenderThread::requestVsync() { 244 if (!mVsyncRequested) { 245 mVsyncRequested = true; 246 status_t status = mDisplayEventReceiver->requestNextVsync(); 247 LOG_ALWAYS_FATAL_IF(status != NO_ERROR, 248 "requestNextVsync failed with status: %d", status); 249 } 250} 251 252bool RenderThread::threadLoop() { 253#if defined(HAVE_PTHREADS) 254 setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY); 255#endif 256 initThreadLocals(); 257 258 int timeoutMillis = -1; 259 for (;;) { 260 int result = mLooper->pollOnce(timeoutMillis); 261 LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, 262 "RenderThread Looper POLL_ERROR!"); 263 264 nsecs_t nextWakeup; 265 // Process our queue, if we have anything 266 while (RenderTask* task = nextTask(&nextWakeup)) { 267 task->run(); 268 // task may have deleted itself, do not reference it again 269 } 270 if (nextWakeup == LLONG_MAX) { 271 timeoutMillis = -1; 272 } else { 273 nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC); 274 timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos); 275 if (timeoutMillis < 0) { 276 timeoutMillis = 0; 277 } 278 } 279 280 if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) { 281 drainDisplayEventQueue(); 282 mFrameCallbacks.insert( 283 mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end()); 284 mPendingRegistrationFrameCallbacks.clear(); 285 requestVsync(); 286 } 287 } 288 289 return false; 290} 291 292void RenderThread::queue(RenderTask* task) { 293 AutoMutex _lock(mLock); 294 mQueue.queue(task); 295 if (mNextWakeup && task->mRunAt < mNextWakeup) { 296 mNextWakeup = 0; 297 mLooper->wake(); 298 } 299} 300 301void RenderThread::queueAtFront(RenderTask* task) { 302 AutoMutex _lock(mLock); 303 mQueue.queueAtFront(task); 304 mLooper->wake(); 305} 306 307void RenderThread::queueAt(RenderTask* task, nsecs_t runAtNs) { 308 task->mRunAt = runAtNs; 309 queue(task); 310} 311 312void RenderThread::remove(RenderTask* task) { 313 AutoMutex _lock(mLock); 314 mQueue.remove(task); 315} 316 317void RenderThread::postFrameCallback(IFrameCallback* callback) { 318 mPendingRegistrationFrameCallbacks.insert(callback); 319} 320 321bool RenderThread::removeFrameCallback(IFrameCallback* callback) { 322 size_t erased; 323 erased = mFrameCallbacks.erase(callback); 324 erased |= mPendingRegistrationFrameCallbacks.erase(callback); 325 return erased; 326} 327 328void RenderThread::pushBackFrameCallback(IFrameCallback* callback) { 329 if (mFrameCallbacks.erase(callback)) { 330 mPendingRegistrationFrameCallbacks.insert(callback); 331 } 332} 333 334RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { 335 AutoMutex _lock(mLock); 336 RenderTask* next = mQueue.peek(); 337 if (!next) { 338 mNextWakeup = LLONG_MAX; 339 } else { 340 mNextWakeup = next->mRunAt; 341 // Most tasks won't be delayed, so avoid unnecessary systemTime() calls 342 if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) { 343 next = mQueue.next(); 344 } else { 345 next = 0; 346 } 347 } 348 if (nextWakeup) { 349 *nextWakeup = mNextWakeup; 350 } 351 return next; 352} 353 354} /* namespace renderthread */ 355} /* namespace uirenderer */ 356} /* namespace android */ 357