RenderThread.cpp revision a5b7b8916622d44661b6e7936c9b738655a06f3b
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#include "utils/FatVector.h" 24 25#include <gui/DisplayEventReceiver.h> 26#include <gui/ISurfaceComposer.h> 27#include <gui/SurfaceComposerClient.h> 28#include <sys/resource.h> 29#include <utils/Condition.h> 30#include <utils/Log.h> 31#include <utils/Mutex.h> 32 33namespace android { 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(nullptr), mTail(nullptr) {} 46 47RenderTask* 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 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 = 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 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 explicit DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {} 133 134 virtual void run() override { 135 mRenderThread->dispatchFrameCallbacks(); 136 } 137}; 138 139static bool gHasRenderThreadInstance = false; 140 141bool RenderThread::hasInstance() { 142 return gHasRenderThreadInstance; 143} 144 145RenderThread& RenderThread::getInstance() { 146 // This is a pointer because otherwise __cxa_finalize 147 // will try to delete it like a Good Citizen but that causes us to crash 148 // because we don't want to delete the RenderThread normally. 149 static RenderThread* sInstance = new RenderThread(); 150 gHasRenderThreadInstance = true; 151 return *sInstance; 152} 153 154RenderThread::RenderThread() : Thread(true) 155 , mNextWakeup(LLONG_MAX) 156 , mDisplayEventReceiver(nullptr) 157 , mVsyncRequested(false) 158 , mFrameCallbackTaskPending(false) 159 , mFrameCallbackTask(nullptr) 160 , mRenderState(nullptr) 161 , mEglManager(nullptr) { 162 Properties::load(); 163 mFrameCallbackTask = new DispatchFrameCallbacks(this); 164 mLooper = new Looper(false); 165 run("RenderThread"); 166} 167 168RenderThread::~RenderThread() { 169 LOG_ALWAYS_FATAL("Can't destroy the render thread"); 170} 171 172void RenderThread::initializeDisplayEventReceiver() { 173 LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?"); 174 mDisplayEventReceiver = new DisplayEventReceiver(); 175 status_t status = mDisplayEventReceiver->initCheck(); 176 LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver " 177 "failed with status: %d", status); 178 179 // Register the FD 180 mLooper->addFd(mDisplayEventReceiver->getFd(), 0, 181 Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this); 182} 183 184void RenderThread::initThreadLocals() { 185 sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay( 186 ISurfaceComposer::eDisplayIdMain)); 187 status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo); 188 LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n"); 189 nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps); 190 mTimeLord.setFrameInterval(frameIntervalNanos); 191 initializeDisplayEventReceiver(); 192 mEglManager = new EglManager(*this); 193 mRenderState = new RenderState(*this); 194 mJankTracker = new JankTracker(frameIntervalNanos); 195} 196 197int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) { 198 if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { 199 ALOGE("Display event receiver pipe was closed or an error occurred. " 200 "events=0x%x", events); 201 return 0; // remove the callback 202 } 203 204 if (!(events & Looper::EVENT_INPUT)) { 205 ALOGW("Received spurious callback for unhandled poll event. " 206 "events=0x%x", events); 207 return 1; // keep the callback 208 } 209 210 reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue(); 211 212 return 1; // keep the callback 213} 214 215static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) { 216 DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; 217 nsecs_t latest = 0; 218 ssize_t n; 219 while ((n = receiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { 220 for (ssize_t i = 0; i < n; i++) { 221 const DisplayEventReceiver::Event& ev = buf[i]; 222 switch (ev.header.type) { 223 case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: 224 latest = ev.header.timestamp; 225 break; 226 } 227 } 228 } 229 if (n < 0) { 230 ALOGW("Failed to get events from display event receiver, status=%d", status_t(n)); 231 } 232 return latest; 233} 234 235void RenderThread::drainDisplayEventQueue() { 236 ATRACE_CALL(); 237 nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver); 238 if (vsyncEvent > 0) { 239 mVsyncRequested = false; 240 if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) { 241 ATRACE_NAME("queue mFrameCallbackTask"); 242 mFrameCallbackTaskPending = true; 243 nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY); 244 queueAt(mFrameCallbackTask, runAt); 245 } 246 } 247} 248 249void RenderThread::dispatchFrameCallbacks() { 250 ATRACE_CALL(); 251 mFrameCallbackTaskPending = false; 252 253 std::set<IFrameCallback*> callbacks; 254 mFrameCallbacks.swap(callbacks); 255 256 if (callbacks.size()) { 257 // Assume one of them will probably animate again so preemptively 258 // request the next vsync in case it occurs mid-frame 259 requestVsync(); 260 for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) { 261 (*it)->doFrame(); 262 } 263 } 264} 265 266void RenderThread::requestVsync() { 267 if (!mVsyncRequested) { 268 mVsyncRequested = true; 269 status_t status = mDisplayEventReceiver->requestNextVsync(); 270 LOG_ALWAYS_FATAL_IF(status != NO_ERROR, 271 "requestNextVsync failed with status: %d", status); 272 } 273} 274 275bool RenderThread::threadLoop() { 276 setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY); 277 initThreadLocals(); 278 279 int timeoutMillis = -1; 280 for (;;) { 281 int result = mLooper->pollOnce(timeoutMillis); 282 LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, 283 "RenderThread Looper POLL_ERROR!"); 284 285 nsecs_t nextWakeup; 286 { 287 FatVector<RenderTask*, 10> workQueue; 288 // Process our queue, if we have anything. By first acquiring 289 // all the pending events then processing them we avoid vsync 290 // starvation if more tasks are queued while we are processing tasks. 291 while (RenderTask* task = nextTask(&nextWakeup)) { 292 workQueue.push_back(task); 293 } 294 for (auto task : workQueue) { 295 task->run(); 296 // task may have deleted itself, do not reference it again 297 } 298 } 299 if (nextWakeup == LLONG_MAX) { 300 timeoutMillis = -1; 301 } else { 302 nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC); 303 timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos); 304 if (timeoutMillis < 0) { 305 timeoutMillis = 0; 306 } 307 } 308 309 if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) { 310 drainDisplayEventQueue(); 311 mFrameCallbacks.insert( 312 mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end()); 313 mPendingRegistrationFrameCallbacks.clear(); 314 requestVsync(); 315 } 316 317 if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) { 318 // TODO: Clean this up. This is working around an issue where a combination 319 // of bad timing and slow drawing can result in dropping a stale vsync 320 // on the floor (correct!) but fails to schedule to listen for the 321 // next vsync (oops), so none of the callbacks are run. 322 requestVsync(); 323 } 324 } 325 326 return false; 327} 328 329void RenderThread::queue(RenderTask* task) { 330 AutoMutex _lock(mLock); 331 mQueue.queue(task); 332 if (mNextWakeup && task->mRunAt < mNextWakeup) { 333 mNextWakeup = 0; 334 mLooper->wake(); 335 } 336} 337 338void RenderThread::queueAndWait(RenderTask* task) { 339 // These need to be local to the thread to avoid the Condition 340 // signaling the wrong thread. The easiest way to achieve that is to just 341 // make this on the stack, although that has a slight cost to it 342 Mutex mutex; 343 Condition condition; 344 SignalingRenderTask syncTask(task, &mutex, &condition); 345 346 AutoMutex _lock(mutex); 347 queue(&syncTask); 348 condition.wait(mutex); 349} 350 351void RenderThread::queueAtFront(RenderTask* task) { 352 AutoMutex _lock(mLock); 353 mQueue.queueAtFront(task); 354 mLooper->wake(); 355} 356 357void RenderThread::queueAt(RenderTask* task, nsecs_t runAtNs) { 358 task->mRunAt = runAtNs; 359 queue(task); 360} 361 362void RenderThread::remove(RenderTask* task) { 363 AutoMutex _lock(mLock); 364 mQueue.remove(task); 365} 366 367void RenderThread::postFrameCallback(IFrameCallback* callback) { 368 mPendingRegistrationFrameCallbacks.insert(callback); 369} 370 371bool RenderThread::removeFrameCallback(IFrameCallback* callback) { 372 size_t erased; 373 erased = mFrameCallbacks.erase(callback); 374 erased |= mPendingRegistrationFrameCallbacks.erase(callback); 375 return erased; 376} 377 378void RenderThread::pushBackFrameCallback(IFrameCallback* callback) { 379 if (mFrameCallbacks.erase(callback)) { 380 mPendingRegistrationFrameCallbacks.insert(callback); 381 } 382} 383 384RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { 385 AutoMutex _lock(mLock); 386 RenderTask* next = mQueue.peek(); 387 if (!next) { 388 mNextWakeup = LLONG_MAX; 389 } else { 390 mNextWakeup = next->mRunAt; 391 // Most tasks won't be delayed, so avoid unnecessary systemTime() calls 392 if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) { 393 next = mQueue.next(); 394 } else { 395 next = nullptr; 396 } 397 } 398 if (nextWakeup) { 399 *nextWakeup = mNextWakeup; 400 } 401 return next; 402} 403 404} /* namespace renderthread */ 405} /* namespace uirenderer */ 406} /* namespace android */ 407