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