RenderThread.cpp revision 12efa55094b2fe38ef5ce232f3d8f02e78b71621
1dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo/* 2dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * Copyright (C) 2013 The Android Open Source Project 3a3c6f62775506c95afd556e617f14d7a28839f01Luke Drummond * 4dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * Licensed under the Apache License, Version 2.0 (the "License"); 5dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * you may not use this file except in compliance with the License. 6dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * You may obtain a copy of the License at 7dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * 8dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * http://www.apache.org/licenses/LICENSE-2.0 9dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * 10dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * Unless required by applicable law or agreed to in writing, software 11dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * distributed under the License is distributed on an "AS IS" BASIS, 12dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * See the License for the specific language governing permissions and 14dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo * limitations under the License. 15dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo */ 16dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo 17dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "RenderThread.h" 18dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo 19dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "../renderstate/RenderState.h" 20dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "CanvasContext.h" 21dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "EglManager.h" 22dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "RenderProxy.h" 23dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "VulkanManager.h" 24dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include "utils/FatVector.h" 25dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo 26dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include <gui/DisplayEventReceiver.h> 27dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include <gui/ISurfaceComposer.h> 28dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include <gui/SurfaceComposerClient.h> 29dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include <sys/resource.h> 30dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include <utils/Condition.h> 31dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo#include <utils/Log.h> 32a3c6f62775506c95afd556e617f14d7a28839f01Luke Drummond#include <utils/Mutex.h> 33dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo 34dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leonamespace android { 35dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leonamespace uirenderer { 36dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leonamespace renderthread { 37dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo 38dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo// Number of events to read at a time from the DisplayEventReceiver pipe. 39dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo// The value should be large enough that we can quickly drain the pipe 40dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo// using just a few large reads. 41dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leostatic const size_t EVENT_BUFFER_SIZE = 100; 42dcecc0c8d22e894525e25a122ce25129b51338f2Dean De Leo 43// Slight delay to give the UI time to push us a new frame before we replay 44static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4); 45 46TaskQueue::TaskQueue() : mHead(nullptr), mTail(nullptr) {} 47 48RenderTask* TaskQueue::next() { 49 RenderTask* ret = mHead; 50 if (ret) { 51 mHead = ret->mNext; 52 if (!mHead) { 53 mTail = nullptr; 54 } 55 ret->mNext = nullptr; 56 } 57 return ret; 58} 59 60RenderTask* TaskQueue::peek() { 61 return mHead; 62} 63 64void TaskQueue::queue(RenderTask* task) { 65 // Since the RenderTask itself forms the linked list it is not allowed 66 // to have the same task queued twice 67 LOG_ALWAYS_FATAL_IF(task->mNext || mTail == task, "Task is already in the queue!"); 68 if (mTail) { 69 // Fast path if we can just append 70 if (mTail->mRunAt <= task->mRunAt) { 71 mTail->mNext = task; 72 mTail = task; 73 } else { 74 // Need to find the proper insertion point 75 RenderTask* previous = nullptr; 76 RenderTask* next = mHead; 77 while (next && next->mRunAt <= task->mRunAt) { 78 previous = next; 79 next = next->mNext; 80 } 81 if (!previous) { 82 task->mNext = mHead; 83 mHead = task; 84 } else { 85 previous->mNext = task; 86 if (next) { 87 task->mNext = next; 88 } else { 89 mTail = task; 90 } 91 } 92 } 93 } else { 94 mTail = mHead = task; 95 } 96} 97 98void TaskQueue::queueAtFront(RenderTask* task) { 99 if (mTail) { 100 task->mNext = mHead; 101 mHead = task; 102 } else { 103 mTail = mHead = task; 104 } 105} 106 107void TaskQueue::remove(RenderTask* task) { 108 // TaskQueue is strict here to enforce that users are keeping track of 109 // their RenderTasks due to how their memory is managed 110 LOG_ALWAYS_FATAL_IF(!task->mNext && mTail != task, 111 "Cannot remove a task that isn't in the queue!"); 112 113 // If task is the head we can just call next() to pop it off 114 // Otherwise we need to scan through to find the task before it 115 if (peek() == task) { 116 next(); 117 } else { 118 RenderTask* previous = mHead; 119 while (previous->mNext != task) { 120 previous = previous->mNext; 121 } 122 previous->mNext = task->mNext; 123 if (mTail == task) { 124 mTail = previous; 125 } 126 } 127} 128 129class DispatchFrameCallbacks : public RenderTask { 130private: 131 RenderThread* mRenderThread; 132public: 133 explicit DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {} 134 135 virtual void run() override { 136 mRenderThread->dispatchFrameCallbacks(); 137 } 138}; 139 140static bool gHasRenderThreadInstance = false; 141 142bool RenderThread::hasInstance() { 143 return gHasRenderThreadInstance; 144} 145 146RenderThread& RenderThread::getInstance() { 147 // This is a pointer because otherwise __cxa_finalize 148 // will try to delete it like a Good Citizen but that causes us to crash 149 // because we don't want to delete the RenderThread normally. 150 static RenderThread* sInstance = new RenderThread(); 151 gHasRenderThreadInstance = true; 152 return *sInstance; 153} 154 155RenderThread::RenderThread() : Thread(true) 156 , mNextWakeup(LLONG_MAX) 157 , mDisplayEventReceiver(nullptr) 158 , mVsyncRequested(false) 159 , mFrameCallbackTaskPending(false) 160 , mFrameCallbackTask(nullptr) 161 , mRenderState(nullptr) 162 , mEglManager(nullptr) 163 , mVkManager(nullptr) { 164 Properties::load(); 165 mFrameCallbackTask = new DispatchFrameCallbacks(this); 166 mLooper = new Looper(false); 167 run("RenderThread"); 168} 169 170RenderThread::~RenderThread() { 171 LOG_ALWAYS_FATAL("Can't destroy the render thread"); 172} 173 174void RenderThread::initializeDisplayEventReceiver() { 175 LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?"); 176 mDisplayEventReceiver = new DisplayEventReceiver(); 177 status_t status = mDisplayEventReceiver->initCheck(); 178 LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver " 179 "failed with status: %d", status); 180 181 // Register the FD 182 mLooper->addFd(mDisplayEventReceiver->getFd(), 0, 183 Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this); 184} 185 186void RenderThread::initThreadLocals() { 187 sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay( 188 ISurfaceComposer::eDisplayIdMain)); 189 status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo); 190 LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n"); 191 nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps); 192 mTimeLord.setFrameInterval(frameIntervalNanos); 193 initializeDisplayEventReceiver(); 194 mEglManager = new EglManager(*this); 195 mRenderState = new RenderState(*this); 196 mJankTracker = new JankTracker(mDisplayInfo); 197 mVkManager = new VulkanManager(*this); 198} 199 200int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) { 201 if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { 202 ALOGE("Display event receiver pipe was closed or an error occurred. " 203 "events=0x%x", events); 204 return 0; // remove the callback 205 } 206 207 if (!(events & Looper::EVENT_INPUT)) { 208 ALOGW("Received spurious callback for unhandled poll event. " 209 "events=0x%x", events); 210 return 1; // keep the callback 211 } 212 213 reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue(); 214 215 return 1; // keep the callback 216} 217 218static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) { 219 DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; 220 nsecs_t latest = 0; 221 ssize_t n; 222 while ((n = receiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { 223 for (ssize_t i = 0; i < n; i++) { 224 const DisplayEventReceiver::Event& ev = buf[i]; 225 switch (ev.header.type) { 226 case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: 227 latest = ev.header.timestamp; 228 break; 229 } 230 } 231 } 232 if (n < 0) { 233 ALOGW("Failed to get events from display event receiver, status=%d", status_t(n)); 234 } 235 return latest; 236} 237 238void RenderThread::drainDisplayEventQueue() { 239 ATRACE_CALL(); 240 nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver); 241 if (vsyncEvent > 0) { 242 mVsyncRequested = false; 243 if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) { 244 ATRACE_NAME("queue mFrameCallbackTask"); 245 mFrameCallbackTaskPending = true; 246 nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY); 247 queueAt(mFrameCallbackTask, runAt); 248 } 249 } 250} 251 252void RenderThread::dispatchFrameCallbacks() { 253 ATRACE_CALL(); 254 mFrameCallbackTaskPending = false; 255 256 std::set<IFrameCallback*> callbacks; 257 mFrameCallbacks.swap(callbacks); 258 259 if (callbacks.size()) { 260 // Assume one of them will probably animate again so preemptively 261 // request the next vsync in case it occurs mid-frame 262 requestVsync(); 263 for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) { 264 (*it)->doFrame(); 265 } 266 } 267} 268 269void RenderThread::requestVsync() { 270 if (!mVsyncRequested) { 271 mVsyncRequested = true; 272 status_t status = mDisplayEventReceiver->requestNextVsync(); 273 LOG_ALWAYS_FATAL_IF(status != NO_ERROR, 274 "requestNextVsync failed with status: %d", status); 275 } 276} 277 278bool RenderThread::threadLoop() { 279 setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY); 280 initThreadLocals(); 281 282 int timeoutMillis = -1; 283 for (;;) { 284 int result = mLooper->pollOnce(timeoutMillis); 285 LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, 286 "RenderThread Looper POLL_ERROR!"); 287 288 nsecs_t nextWakeup; 289 { 290 FatVector<RenderTask*, 10> workQueue; 291 // Process our queue, if we have anything. By first acquiring 292 // all the pending events then processing them we avoid vsync 293 // starvation if more tasks are queued while we are processing tasks. 294 while (RenderTask* task = nextTask(&nextWakeup)) { 295 workQueue.push_back(task); 296 } 297 for (auto task : workQueue) { 298 task->run(); 299 // task may have deleted itself, do not reference it again 300 } 301 } 302 if (nextWakeup == LLONG_MAX) { 303 timeoutMillis = -1; 304 } else { 305 nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC); 306 timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos); 307 if (timeoutMillis < 0) { 308 timeoutMillis = 0; 309 } 310 } 311 312 if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) { 313 drainDisplayEventQueue(); 314 mFrameCallbacks.insert( 315 mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end()); 316 mPendingRegistrationFrameCallbacks.clear(); 317 requestVsync(); 318 } 319 320 if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) { 321 // TODO: Clean this up. This is working around an issue where a combination 322 // of bad timing and slow drawing can result in dropping a stale vsync 323 // on the floor (correct!) but fails to schedule to listen for the 324 // next vsync (oops), so none of the callbacks are run. 325 requestVsync(); 326 } 327 } 328 329 return false; 330} 331 332void RenderThread::queue(RenderTask* task) { 333 AutoMutex _lock(mLock); 334 mQueue.queue(task); 335 if (mNextWakeup && task->mRunAt < mNextWakeup) { 336 mNextWakeup = 0; 337 mLooper->wake(); 338 } 339} 340 341void RenderThread::queueAndWait(RenderTask* task) { 342 // These need to be local to the thread to avoid the Condition 343 // signaling the wrong thread. The easiest way to achieve that is to just 344 // make this on the stack, although that has a slight cost to it 345 Mutex mutex; 346 Condition condition; 347 SignalingRenderTask syncTask(task, &mutex, &condition); 348 349 AutoMutex _lock(mutex); 350 queue(&syncTask); 351 condition.wait(mutex); 352} 353 354void RenderThread::queueAtFront(RenderTask* task) { 355 AutoMutex _lock(mLock); 356 mQueue.queueAtFront(task); 357 mLooper->wake(); 358} 359 360void RenderThread::queueAt(RenderTask* task, nsecs_t runAtNs) { 361 task->mRunAt = runAtNs; 362 queue(task); 363} 364 365void RenderThread::remove(RenderTask* task) { 366 AutoMutex _lock(mLock); 367 mQueue.remove(task); 368} 369 370void RenderThread::postFrameCallback(IFrameCallback* callback) { 371 mPendingRegistrationFrameCallbacks.insert(callback); 372} 373 374bool RenderThread::removeFrameCallback(IFrameCallback* callback) { 375 size_t erased; 376 erased = mFrameCallbacks.erase(callback); 377 erased |= mPendingRegistrationFrameCallbacks.erase(callback); 378 return erased; 379} 380 381void RenderThread::pushBackFrameCallback(IFrameCallback* callback) { 382 if (mFrameCallbacks.erase(callback)) { 383 mPendingRegistrationFrameCallbacks.insert(callback); 384 } 385} 386 387RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { 388 AutoMutex _lock(mLock); 389 RenderTask* next = mQueue.peek(); 390 if (!next) { 391 mNextWakeup = LLONG_MAX; 392 } else { 393 mNextWakeup = next->mRunAt; 394 // Most tasks won't be delayed, so avoid unnecessary systemTime() calls 395 if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) { 396 next = mQueue.next(); 397 } else { 398 next = nullptr; 399 } 400 } 401 if (nextWakeup) { 402 *nextWakeup = mNextWakeup; 403 } 404 return next; 405} 406 407} /* namespace renderthread */ 408} /* namespace uirenderer */ 409} /* namespace android */ 410