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