diff options
author | John Reck <jreck@google.com> | 2017-10-23 13:10:41 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2017-10-27 13:39:55 -0700 |
commit | f8441e65526cd1721f1ad77dad21b1a1e2743d76 (patch) | |
tree | a783f7ce274943c1fc919ba746662b962738af42 /libs/hwui/renderthread/RenderThread.cpp | |
parent | 68533018e748ae7fa881cdb933ec18f9273cfc1e (diff) |
Switch to a fancy new queue
Test: unit tests & benchmarks pass/faster
Change-Id: I9521432172d6dd6039c5280b1265479a36a86247
Diffstat (limited to 'libs/hwui/renderthread/RenderThread.cpp')
-rw-r--r-- | libs/hwui/renderthread/RenderThread.cpp | 199 |
1 files changed, 8 insertions, 191 deletions
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 51e937485fab..f3bb120cc0fd 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -49,101 +49,6 @@ static const size_t EVENT_BUFFER_SIZE = 100; // Slight delay to give the UI time to push us a new frame before we replay static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4); -TaskQueue::TaskQueue() : mHead(nullptr), mTail(nullptr) {} - -RenderTask* TaskQueue::next() { - RenderTask* ret = mHead; - if (ret) { - mHead = ret->mNext; - if (!mHead) { - mTail = nullptr; - } - ret->mNext = nullptr; - } - 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 = nullptr; - 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; - } -} - -void TaskQueue::queueAtFront(RenderTask* task) { - LOG_ALWAYS_FATAL_IF(task->mNext || mHead == task, "Task is already in the queue!"); - if (mTail) { - task->mNext = mHead; - mHead = task; - } else { - mTail = mHead = task; - } -} - -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; - } - } -} - -class DispatchFrameCallbacks : public RenderTask { -private: - RenderThread* mRenderThread; -public: - explicit DispatchFrameCallbacks(RenderThread* rt) : mRenderThread(rt) {} - - virtual void run() override { - mRenderThread->dispatchFrameCallbacks(); - } -}; - static bool gHasRenderThreadInstance = false; bool RenderThread::hasInstance() { @@ -159,19 +64,15 @@ RenderThread& RenderThread::getInstance() { return *sInstance; } -RenderThread::RenderThread() : Thread(true) - , mNextWakeup(LLONG_MAX) +RenderThread::RenderThread() : ThreadBase() , mDisplayEventReceiver(nullptr) , mVsyncRequested(false) , mFrameCallbackTaskPending(false) - , mFrameCallbackTask(nullptr) , mRenderState(nullptr) , mEglManager(nullptr) , mVkManager(nullptr) { Properties::load(); - mFrameCallbackTask = new DispatchFrameCallbacks(this); - mLooper = new Looper(false); - run("RenderThread"); + start("RenderThread"); } RenderThread::~RenderThread() { @@ -321,7 +222,9 @@ void RenderThread::drainDisplayEventQueue() { ATRACE_NAME("queue mFrameCallbackTask"); mFrameCallbackTaskPending = true; nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY); - queueAt(mFrameCallbackTask, runAt); + queue().postAt(runAt, [this]() { + dispatchFrameCallbacks(); + }); } } } @@ -356,35 +259,9 @@ bool RenderThread::threadLoop() { setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY); initThreadLocals(); - int timeoutMillis = -1; - for (;;) { - int result = mLooper->pollOnce(timeoutMillis); - LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, - "RenderThread Looper POLL_ERROR!"); - - nsecs_t nextWakeup; - { - FatVector<RenderTask*, 10> workQueue; - // Process our queue, if we have anything. By first acquiring - // all the pending events then processing them we avoid vsync - // starvation if more tasks are queued while we are processing tasks. - while (RenderTask* task = nextTask(&nextWakeup)) { - workQueue.push_back(task); - } - for (auto task : workQueue) { - task->run(); - // task may have deleted itself, do not reference it again - } - } - if (nextWakeup == LLONG_MAX) { - timeoutMillis = -1; - } else { - nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC); - timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos); - if (timeoutMillis < 0) { - timeoutMillis = 0; - } - } + while (true) { + waitForWork(); + processQueue(); if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) { drainDisplayEventQueue(); @@ -406,46 +283,6 @@ bool RenderThread::threadLoop() { return false; } -void RenderThread::queue(RenderTask* task) { - AutoMutex _lock(mLock); - mQueue.queue(task); - if (mNextWakeup && task->mRunAt < mNextWakeup) { - mNextWakeup = 0; - mLooper->wake(); - } -} - -void RenderThread::queueAndWait(RenderTask* task) { - // These need to be local to the thread to avoid the Condition - // signaling the wrong thread. The easiest way to achieve that is to just - // make this on the stack, although that has a slight cost to it - Mutex mutex; - Condition condition; - SignalingRenderTask syncTask(task, &mutex, &condition); - - AutoMutex _lock(mutex); - queue(&syncTask); - while (!syncTask.hasRun()) { - condition.wait(mutex); - } -} - -void RenderThread::queueAtFront(RenderTask* task) { - AutoMutex _lock(mLock); - mQueue.queueAtFront(task); - mLooper->wake(); -} - -void RenderThread::queueAt(RenderTask* task, nsecs_t runAtNs) { - task->mRunAt = runAtNs; - queue(task); -} - -void RenderThread::remove(RenderTask* task) { - AutoMutex _lock(mLock); - mQueue.remove(task); -} - void RenderThread::postFrameCallback(IFrameCallback* callback) { mPendingRegistrationFrameCallbacks.insert(callback); } @@ -463,26 +300,6 @@ void RenderThread::pushBackFrameCallback(IFrameCallback* callback) { } } -RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { - AutoMutex _lock(mLock); - RenderTask* next = mQueue.peek(); - if (!next) { - mNextWakeup = LLONG_MAX; - } else { - mNextWakeup = next->mRunAt; - // Most tasks won't be delayed, so avoid unnecessary systemTime() calls - if (next->mRunAt <= 0 || next->mRunAt <= systemTime(SYSTEM_TIME_MONOTONIC)) { - next = mQueue.next(); - } else { - next = nullptr; - } - } - if (nextWakeup) { - *nextWakeup = mNextWakeup; - } - return next; -} - sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) { auto renderType = Properties::getRenderPipelineType(); switch (renderType) { |