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 "../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