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 #if defined(HAVE_PTHREADS)
     20 #include <sys/resource.h>
     21 #endif
     22 #include <gui/DisplayEventReceiver.h>
     23 #include <utils/Log.h>
     24 
     25 #include "../RenderState.h"
     26 #include "CanvasContext.h"
     27 #include "EglManager.h"
     28 #include "RenderProxy.h"
     29 
     30 namespace android {
     31 using namespace uirenderer::renderthread;
     32 ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread);
     33 
     34 namespace uirenderer {
     35 namespace renderthread {
     36 
     37 // Number of events to read at a time from the DisplayEventReceiver pipe.
     38 // The value should be large enough that we can quickly drain the pipe
     39 // using just a few large reads.
     40 static const size_t EVENT_BUFFER_SIZE = 100;
     41 
     42 // Slight delay to give the UI time to push us a new frame before we replay
     43 static const int DISPATCH_FRAME_CALLBACKS_DELAY = 4;
     44 
     45 TaskQueue::TaskQueue() : mHead(0), mTail(0) {}
     46 
     47 RenderTask* TaskQueue::next() {
     48     RenderTask* ret = mHead;
     49     if (ret) {
     50         mHead = ret->mNext;
     51         if (!mHead) {
     52             mTail = 0;
     53         }
     54         ret->mNext = 0;
     55     }
     56     return ret;
     57 }
     58 
     59 RenderTask* TaskQueue::peek() {
     60     return mHead;
     61 }
     62 
     63 void TaskQueue::queue(RenderTask* task) {
     64     // Since the RenderTask itself forms the linked list it is not allowed
     65     // to have the same task queued twice
     66     LOG_ALWAYS_FATAL_IF(task->mNext || mTail == task, "Task is already in the queue!");
     67     if (mTail) {
     68         // Fast path if we can just append
     69         if (mTail->mRunAt <= task->mRunAt) {
     70             mTail->mNext = task;
     71             mTail = task;
     72         } else {
     73             // Need to find the proper insertion point
     74             RenderTask* previous = 0;
     75             RenderTask* next = mHead;
     76             while (next && next->mRunAt <= task->mRunAt) {
     77                 previous = next;
     78                 next = next->mNext;
     79             }
     80             if (!previous) {
     81                 task->mNext = mHead;
     82                 mHead = task;
     83             } else {
     84                 previous->mNext = task;
     85                 if (next) {
     86                     task->mNext = next;
     87                 } else {
     88                     mTail = task;
     89                 }
     90             }
     91         }
     92     } else {
     93         mTail = mHead = task;
     94     }
     95 }
     96 
     97 void TaskQueue::queueAtFront(RenderTask* task) {
     98     if (mTail) {
     99         task->mNext = mHead;
    100         mHead = task;
    101     } else {
    102         mTail = mHead = task;
    103     }
    104 }
    105 
    106 void TaskQueue::remove(RenderTask* task) {
    107     // TaskQueue is strict here to enforce that users are keeping track of
    108     // their RenderTasks due to how their memory is managed
    109     LOG_ALWAYS_FATAL_IF(!task->mNext && mTail != task,
    110             "Cannot remove a task that isn't in the queue!");
    111 
    112     // If task is the head we can just call next() to pop it off
    113     // Otherwise we need to scan through to find the task before it
    114     if (peek() == task) {
    115         next();
    116     } else {
    117         RenderTask* previous = mHead;
    118         while (previous->mNext != task) {
    119             previous = previous->mNext;
    120         }
    121         previous->mNext = task->mNext;
    122         if (mTail == task) {
    123             mTail = previous;
    124         }
    125     }
    126 }
    127 
    128 class DispatchFrameCallbacks : public RenderTask {
    129 private:
    130     RenderThread* mRenderThread;
    131 public:
    132     DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {}
    133 
    134     virtual void run() {
    135         mRenderThread->dispatchFrameCallbacks();
    136     }
    137 };
    138 
    139 RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>()
    140         , mNextWakeup(LLONG_MAX)
    141         , mDisplayEventReceiver(0)
    142         , mVsyncRequested(false)
    143         , mFrameCallbackTaskPending(false)
    144         , mFrameCallbackTask(0)
    145         , mRenderState(NULL)
    146         , mEglManager(NULL) {
    147     mFrameCallbackTask = new DispatchFrameCallbacks(this);
    148     mLooper = new Looper(false);
    149     run("RenderThread");
    150 }
    151 
    152 RenderThread::~RenderThread() {
    153     LOG_ALWAYS_FATAL("Can't destroy the render thread");
    154 }
    155 
    156 void RenderThread::initializeDisplayEventReceiver() {
    157     LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?");
    158     mDisplayEventReceiver = new DisplayEventReceiver();
    159     status_t status = mDisplayEventReceiver->initCheck();
    160     LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver "
    161             "failed with status: %d", status);
    162 
    163     // Register the FD
    164     mLooper->addFd(mDisplayEventReceiver->getFd(), 0,
    165             Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this);
    166 }
    167 
    168 void RenderThread::initThreadLocals() {
    169     initializeDisplayEventReceiver();
    170     mEglManager = new EglManager(*this);
    171     mRenderState = new RenderState();
    172 }
    173 
    174 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
    175     if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
    176         ALOGE("Display event receiver pipe was closed or an error occurred.  "
    177                 "events=0x%x", events);
    178         return 0; // remove the callback
    179     }
    180 
    181     if (!(events & Looper::EVENT_INPUT)) {
    182         ALOGW("Received spurious callback for unhandled poll event.  "
    183                 "events=0x%x", events);
    184         return 1; // keep the callback
    185     }
    186 
    187     reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();
    188 
    189     return 1; // keep the callback
    190 }
    191 
    192 static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) {
    193     DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
    194     nsecs_t latest = 0;
    195     ssize_t n;
    196     while ((n = receiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
    197         for (ssize_t i = 0; i < n; i++) {
    198             const DisplayEventReceiver::Event& ev = buf[i];
    199             switch (ev.header.type) {
    200             case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
    201                 latest = ev.header.timestamp;
    202                 break;
    203             }
    204         }
    205     }
    206     if (n < 0) {
    207         ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
    208     }
    209     return latest;
    210 }
    211 
    212 void RenderThread::drainDisplayEventQueue(bool skipCallbacks) {
    213     ATRACE_CALL();
    214     nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
    215     if (vsyncEvent > 0) {
    216         mVsyncRequested = false;
    217         mTimeLord.vsyncReceived(vsyncEvent);
    218         if (!skipCallbacks && !mFrameCallbackTaskPending) {
    219             ATRACE_NAME("queue mFrameCallbackTask");
    220             mFrameCallbackTaskPending = true;
    221             queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY);
    222         }
    223     }
    224 }
    225 
    226 void RenderThread::dispatchFrameCallbacks() {
    227     ATRACE_CALL();
    228     mFrameCallbackTaskPending = false;
    229 
    230     std::set<IFrameCallback*> callbacks;
    231     mFrameCallbacks.swap(callbacks);
    232 
    233     for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
    234         (*it)->doFrame();
    235     }
    236 }
    237 
    238 void RenderThread::requestVsync() {
    239     if (!mVsyncRequested) {
    240         mVsyncRequested = true;
    241         status_t status = mDisplayEventReceiver->requestNextVsync();
    242         LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
    243                 "requestNextVsync failed with status: %d", status);
    244     }
    245 }
    246 
    247 bool RenderThread::threadLoop() {
    248 #if defined(HAVE_PTHREADS)
    249     setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
    250 #endif
    251     initThreadLocals();
    252 
    253     int timeoutMillis = -1;
    254     for (;;) {
    255         int result = mLooper->pollOnce(timeoutMillis);
    256         LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
    257                 "RenderThread Looper POLL_ERROR!");
    258 
    259         nsecs_t nextWakeup;
    260         // Process our queue, if we have anything
    261         while (RenderTask* task = nextTask(&nextWakeup)) {
    262             task->run();
    263             // task may have deleted itself, do not reference it again
    264         }
    265         if (nextWakeup == LLONG_MAX) {
    266             timeoutMillis = -1;
    267         } else {
    268             nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC);
    269             timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos);
    270             if (timeoutMillis < 0) {
    271                 timeoutMillis = 0;
    272             }
    273         }
    274 
    275         if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
    276             drainDisplayEventQueue(true);
    277             mFrameCallbacks.insert(
    278                     mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end());
    279             mPendingRegistrationFrameCallbacks.clear();
    280             requestVsync();
    281         }
    282     }
    283 
    284     return false;
    285 }
    286 
    287 void RenderThread::queue(RenderTask* task) {
    288     AutoMutex _lock(mLock);
    289     mQueue.queue(task);
    290     if (mNextWakeup && task->mRunAt < mNextWakeup) {
    291         mNextWakeup = 0;
    292         mLooper->wake();
    293     }
    294 }
    295 
    296 void RenderThread::queueAtFront(RenderTask* task) {
    297     AutoMutex _lock(mLock);
    298     mQueue.queueAtFront(task);
    299     mLooper->wake();
    300 }
    301 
    302 void RenderThread::queueDelayed(RenderTask* task, int delayMs) {
    303     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
    304     task->mRunAt = now + milliseconds_to_nanoseconds(delayMs);
    305     queue(task);
    306 }
    307 
    308 void RenderThread::remove(RenderTask* task) {
    309     AutoMutex _lock(mLock);
    310     mQueue.remove(task);
    311 }
    312 
    313 void RenderThread::postFrameCallback(IFrameCallback* callback) {
    314     mPendingRegistrationFrameCallbacks.insert(callback);
    315 }
    316 
    317 void RenderThread::removeFrameCallback(IFrameCallback* callback) {
    318     mFrameCallbacks.erase(callback);
    319     mPendingRegistrationFrameCallbacks.erase(callback);
    320 }
    321 
    322 void RenderThread::pushBackFrameCallback(IFrameCallback* callback) {
    323     if (mFrameCallbacks.erase(callback)) {
    324         mPendingRegistrationFrameCallbacks.insert(callback);
    325     }
    326 }
    327 
    328 RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
    329     AutoMutex _lock(mLock);
    330     RenderTask* next = mQueue.peek();
    331     if (!next) {
    332         mNextWakeup = LLONG_MAX;
    333     } else {
    334         mNextWakeup = next->mRunAt;
    335         // Most tasks won't be delayed, so avoid unnecessary systemTime() calls
    336         if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
    337             next = mQueue.next();
    338         } else {
    339             next = 0;
    340         }
    341     }
    342     if (nextWakeup) {
    343         *nextWakeup = mNextWakeup;
    344     }
    345     return next;
    346 }
    347 
    348 } /* namespace renderthread */
    349 } /* namespace uirenderer */
    350 } /* namespace android */
    351