RenderThread.cpp 11.1 KB
Newer Older
John Reck's avatar
John Reck committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "RenderThread.h"

John Reck's avatar
John Reck committed
19 20 21
#if defined(HAVE_PTHREADS)
#include <sys/resource.h>
#endif
John Reck's avatar
John Reck committed
22 23 24
#include <gui/DisplayEventReceiver.h>
#include <utils/Log.h>

John Reck's avatar
John Reck committed
25
#include "../RenderState.h"
John Reck's avatar
John Reck committed
26
#include "CanvasContext.h"
John Reck's avatar
John Reck committed
27
#include "EglManager.h"
John Reck's avatar
John Reck committed
28
#include "RenderProxy.h"
John Reck's avatar
John Reck committed
29 30 31 32 33 34 35 36

namespace android {
using namespace uirenderer::renderthread;
ANDROID_SINGLETON_STATIC_INSTANCE(RenderThread);

namespace uirenderer {
namespace renderthread {

John Reck's avatar
John Reck committed
37 38 39 40 41 42
// Number of events to read at a time from the DisplayEventReceiver pipe.
// The value should be large enough that we can quickly drain the pipe
// using just a few large reads.
static const size_t EVENT_BUFFER_SIZE = 100;

// Slight delay to give the UI time to push us a new frame before we replay
John Reck's avatar
John Reck committed
43
static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4);
John Reck's avatar
John Reck committed
44

John Reck's avatar
John Reck committed
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
TaskQueue::TaskQueue() : mHead(0), mTail(0) {}

RenderTask* TaskQueue::next() {
    RenderTask* ret = mHead;
    if (ret) {
        mHead = ret->mNext;
        if (!mHead) {
            mTail = 0;
        }
        ret->mNext = 0;
    }
    return ret;
}

RenderTask* TaskQueue::peek() {
    return mHead;
}

void TaskQueue::queue(RenderTask* task) {
    // Since the RenderTask itself forms the linked list it is not allowed
    // to have the same task queued twice
    LOG_ALWAYS_FATAL_IF(task->mNext || mTail == task, "Task is already in the queue!");
    if (mTail) {
        // Fast path if we can just append
        if (mTail->mRunAt <= task->mRunAt) {
            mTail->mNext = task;
            mTail = task;
        } else {
            // Need to find the proper insertion point
            RenderTask* previous = 0;
            RenderTask* next = mHead;
            while (next && next->mRunAt <= task->mRunAt) {
                previous = next;
                next = next->mNext;
            }
            if (!previous) {
                task->mNext = mHead;
                mHead = task;
            } else {
                previous->mNext = task;
                if (next) {
                    task->mNext = next;
                } else {
                    mTail = task;
                }
            }
        }
    } else {
        mTail = mHead = task;
    }
}

John Reck's avatar
John Reck committed
97 98 99 100 101 102 103 104 105
void TaskQueue::queueAtFront(RenderTask* task) {
    if (mTail) {
        task->mNext = mHead;
        mHead = task;
    } else {
        mTail = mHead = task;
    }
}

John Reck's avatar
John Reck committed
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
void TaskQueue::remove(RenderTask* task) {
    // TaskQueue is strict here to enforce that users are keeping track of
    // their RenderTasks due to how their memory is managed
    LOG_ALWAYS_FATAL_IF(!task->mNext && mTail != task,
            "Cannot remove a task that isn't in the queue!");

    // If task is the head we can just call next() to pop it off
    // Otherwise we need to scan through to find the task before it
    if (peek() == task) {
        next();
    } else {
        RenderTask* previous = mHead;
        while (previous->mNext != task) {
            previous = previous->mNext;
        }
        previous->mNext = task->mNext;
        if (mTail == task) {
            mTail = previous;
        }
    }
}

John Reck's avatar
John Reck committed
128 129 130 131 132 133 134 135 136 137 138
class DispatchFrameCallbacks : public RenderTask {
private:
    RenderThread* mRenderThread;
public:
    DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {}

    virtual void run() {
        mRenderThread->dispatchFrameCallbacks();
    }
};

John Reck's avatar
John Reck committed
139
RenderThread::RenderThread() : Thread(true), Singleton<RenderThread>()
John Reck's avatar
John Reck committed
140 141 142 143
        , mNextWakeup(LLONG_MAX)
        , mDisplayEventReceiver(0)
        , mVsyncRequested(false)
        , mFrameCallbackTaskPending(false)
John Reck's avatar
John Reck committed
144 145
        , mFrameCallbackTask(0)
        , mRenderState(NULL)
146
        , mEglManager(NULL) {
John Reck's avatar
John Reck committed
147
    mFrameCallbackTask = new DispatchFrameCallbacks(this);
John Reck's avatar
John Reck committed
148 149 150 151 152
    mLooper = new Looper(false);
    run("RenderThread");
}

RenderThread::~RenderThread() {
John Reck's avatar
John Reck committed
153
    LOG_ALWAYS_FATAL("Can't destroy the render thread");
John Reck's avatar
John Reck committed
154 155
}

John Reck's avatar
John Reck committed
156 157 158 159 160 161 162 163 164 165 166 167
void RenderThread::initializeDisplayEventReceiver() {
    LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?");
    mDisplayEventReceiver = new DisplayEventReceiver();
    status_t status = mDisplayEventReceiver->initCheck();
    LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver "
            "failed with status: %d", status);

    // Register the FD
    mLooper->addFd(mDisplayEventReceiver->getFd(), 0,
            Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this);
}

John Reck's avatar
John Reck committed
168 169 170
void RenderThread::initThreadLocals() {
    initializeDisplayEventReceiver();
    mEglManager = new EglManager(*this);
John Reck's avatar
John Reck committed
171
    mRenderState = new RenderState(*this);
John Reck's avatar
John Reck committed
172 173
}

John Reck's avatar
John Reck committed
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
        ALOGE("Display event receiver pipe was closed or an error occurred.  "
                "events=0x%x", events);
        return 0; // remove the callback
    }

    if (!(events & Looper::EVENT_INPUT)) {
        ALOGW("Received spurious callback for unhandled poll event.  "
                "events=0x%x", events);
        return 1; // keep the callback
    }

    reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();

    return 1; // keep the callback
}

static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) {
    DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
    nsecs_t latest = 0;
    ssize_t n;
    while ((n = receiver->getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
        for (ssize_t i = 0; i < n; i++) {
            const DisplayEventReceiver::Event& ev = buf[i];
            switch (ev.header.type) {
            case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
                latest = ev.header.timestamp;
                break;
            }
        }
    }
    if (n < 0) {
        ALOGW("Failed to get events from display event receiver, status=%d", status_t(n));
    }
    return latest;
}

John Reck's avatar
John Reck committed
212
void RenderThread::drainDisplayEventQueue() {
John Reck's avatar
John Reck committed
213
    ATRACE_CALL();
John Reck's avatar
John Reck committed
214 215 216
    nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver);
    if (vsyncEvent > 0) {
        mVsyncRequested = false;
John Reck's avatar
John Reck committed
217
        if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) {
John Reck's avatar
John Reck committed
218
            ATRACE_NAME("queue mFrameCallbackTask");
John Reck's avatar
John Reck committed
219
            mFrameCallbackTaskPending = true;
John Reck's avatar
John Reck committed
220 221
            nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY);
            queueAt(mFrameCallbackTask, runAt);
John Reck's avatar
John Reck committed
222 223 224 225 226
        }
    }
}

void RenderThread::dispatchFrameCallbacks() {
John Reck's avatar
John Reck committed
227
    ATRACE_CALL();
John Reck's avatar
John Reck committed
228 229 230 231 232
    mFrameCallbackTaskPending = false;

    std::set<IFrameCallback*> callbacks;
    mFrameCallbacks.swap(callbacks);

John Reck's avatar
John Reck committed
233 234 235 236 237 238 239
    if (callbacks.size()) {
        // Assume one of them will probably animate again so preemptively
        // request the next vsync in case it occurs mid-frame
        requestVsync();
        for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
            (*it)->doFrame();
        }
John Reck's avatar
John Reck committed
240 241 242
    }
}

John Reck's avatar
John Reck committed
243 244 245 246 247 248 249 250 251
void RenderThread::requestVsync() {
    if (!mVsyncRequested) {
        mVsyncRequested = true;
        status_t status = mDisplayEventReceiver->requestNextVsync();
        LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
                "requestNextVsync failed with status: %d", status);
    }
}

John Reck's avatar
John Reck committed
252
bool RenderThread::threadLoop() {
John Reck's avatar
John Reck committed
253 254 255
#if defined(HAVE_PTHREADS)
    setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
#endif
John Reck's avatar
John Reck committed
256
    initThreadLocals();
John Reck's avatar
John Reck committed
257

John Reck's avatar
John Reck committed
258
    int timeoutMillis = -1;
John Reck's avatar
John Reck committed
259
    for (;;) {
John Reck's avatar
John Reck committed
260
        int result = mLooper->pollOnce(timeoutMillis);
John Reck's avatar
John Reck committed
261 262 263 264
        LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
                "RenderThread Looper POLL_ERROR!");

        nsecs_t nextWakeup;
John Reck's avatar
John Reck committed
265
        // Process our queue, if we have anything
John Reck's avatar
John Reck committed
266
        while (RenderTask* task = nextTask(&nextWakeup)) {
John Reck's avatar
John Reck committed
267
            task->run();
John Reck's avatar
John Reck committed
268 269 270 271 272
            // task may have deleted itself, do not reference it again
        }
        if (nextWakeup == LLONG_MAX) {
            timeoutMillis = -1;
        } else {
John Reck's avatar
John Reck committed
273 274
            nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos);
John Reck's avatar
John Reck committed
275 276 277
            if (timeoutMillis < 0) {
                timeoutMillis = 0;
            }
John Reck's avatar
John Reck committed
278
        }
John Reck's avatar
John Reck committed
279 280

        if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
John Reck's avatar
John Reck committed
281
            drainDisplayEventQueue();
John Reck's avatar
John Reck committed
282 283 284 285 286
            mFrameCallbacks.insert(
                    mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end());
            mPendingRegistrationFrameCallbacks.clear();
            requestVsync();
        }
John Reck's avatar
John Reck committed
287 288 289 290 291 292 293 294

        if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) {
            // TODO: Clean this up. This is working around an issue where a combination
            // of bad timing and slow drawing can result in dropping a stale vsync
            // on the floor (correct!) but fails to schedule to listen for the
            // next vsync (oops), so none of the callbacks are run.
            requestVsync();
        }
John Reck's avatar
John Reck committed
295 296 297 298 299 300 301
    }

    return false;
}

void RenderThread::queue(RenderTask* task) {
    AutoMutex _lock(mLock);
John Reck's avatar
John Reck committed
302 303 304
    mQueue.queue(task);
    if (mNextWakeup && task->mRunAt < mNextWakeup) {
        mNextWakeup = 0;
John Reck's avatar
John Reck committed
305 306 307 308
        mLooper->wake();
    }
}

John Reck's avatar
John Reck committed
309 310 311 312 313 314
void RenderThread::queueAtFront(RenderTask* task) {
    AutoMutex _lock(mLock);
    mQueue.queueAtFront(task);
    mLooper->wake();
}

John Reck's avatar
John Reck committed
315 316
void RenderThread::queueAt(RenderTask* task, nsecs_t runAtNs) {
    task->mRunAt = runAtNs;
John Reck's avatar
John Reck committed
317 318 319 320
    queue(task);
}

void RenderThread::remove(RenderTask* task) {
John Reck's avatar
John Reck committed
321
    AutoMutex _lock(mLock);
John Reck's avatar
John Reck committed
322 323 324
    mQueue.remove(task);
}

John Reck's avatar
John Reck committed
325
void RenderThread::postFrameCallback(IFrameCallback* callback) {
John Reck's avatar
John Reck committed
326
    mPendingRegistrationFrameCallbacks.insert(callback);
John Reck's avatar
John Reck committed
327 328
}

329 330 331 332 333
bool RenderThread::removeFrameCallback(IFrameCallback* callback) {
    size_t erased;
    erased = mFrameCallbacks.erase(callback);
    erased |= mPendingRegistrationFrameCallbacks.erase(callback);
    return erased;
John Reck's avatar
John Reck committed
334 335 336 337 338 339
}

void RenderThread::pushBackFrameCallback(IFrameCallback* callback) {
    if (mFrameCallbacks.erase(callback)) {
        mPendingRegistrationFrameCallbacks.insert(callback);
    }
John Reck's avatar
John Reck committed
340 341
}

John Reck's avatar
John Reck committed
342 343 344 345 346 347
RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
    AutoMutex _lock(mLock);
    RenderTask* next = mQueue.peek();
    if (!next) {
        mNextWakeup = LLONG_MAX;
    } else {
John Reck's avatar
John Reck committed
348
        mNextWakeup = next->mRunAt;
John Reck's avatar
John Reck committed
349 350 351
        // Most tasks won't be delayed, so avoid unnecessary systemTime() calls
        if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) {
            next = mQueue.next();
John Reck's avatar
John Reck committed
352 353
        } else {
            next = 0;
John Reck's avatar
John Reck committed
354 355
        }
    }
John Reck's avatar
John Reck committed
356 357 358 359
    if (nextWakeup) {
        *nextWakeup = mNextWakeup;
    }
    return next;
John Reck's avatar
John Reck committed
360 361 362 363 364
}

} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */