Home | History | Annotate | Download | only in renderthread
      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