diff options
author | John Reck <jreck@google.com> | 2014-05-22 15:43:54 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2014-05-23 12:56:38 -0700 |
commit | a5dda645da738da7b4ae15e28fa7d93d3b04b94f (patch) | |
tree | 5ce51af907c91030662b69c37e8ece7a63e041ed /libs/hwui/renderthread/RenderThread.cpp | |
parent | d30241541c3adcb126bb263ad8596e7902a6b5ae (diff) |
Bag of scheduling tweaks
Bug: 15118640
* Prevent over-stuffing the queue by dropping frames
* Prevent double-drawing in one pulse by RT by deferring
vsync registration until post-draw so that it catches
the next vsync pulse instead of the current one
* Bias vsync race condition towards the UI thread
* Fix queueDelay to actually work
Change-Id: Ibf584258bd93ebcbba058bd976dc8b307f1c6155
Diffstat (limited to 'libs/hwui/renderthread/RenderThread.cpp')
-rw-r--r-- | libs/hwui/renderthread/RenderThread.cpp | 63 |
1 files changed, 50 insertions, 13 deletions
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index 35a3eabce925..4a4e2540dd6f 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -37,7 +37,7 @@ namespace renderthread { 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 int DISPATCH_FRAME_CALLBACKS_DELAY = 0; +static const int DISPATCH_FRAME_CALLBACKS_DELAY = 4; TaskQueue::TaskQueue() : mHead(0), mTail(0) {} @@ -91,6 +91,15 @@ void TaskQueue::queue(RenderTask* task) { } } +void TaskQueue::queueAtFront(RenderTask* task) { + 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 @@ -188,20 +197,22 @@ static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) { return latest; } -void RenderThread::drainDisplayEventQueue() { +void RenderThread::drainDisplayEventQueue(bool skipCallbacks) { + ATRACE_CALL(); nsecs_t vsyncEvent = latestVsyncEvent(mDisplayEventReceiver); if (vsyncEvent > 0) { mVsyncRequested = false; mTimeLord.vsyncReceived(vsyncEvent); - if (!mFrameCallbackTaskPending) { + if (!skipCallbacks && !mFrameCallbackTaskPending) { + ATRACE_NAME("queue mFrameCallbackTask"); mFrameCallbackTaskPending = true; - //queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY); - queue(mFrameCallbackTask); + queueDelayed(mFrameCallbackTask, DISPATCH_FRAME_CALLBACKS_DELAY); } } } void RenderThread::dispatchFrameCallbacks() { + ATRACE_CALL(); mFrameCallbackTaskPending = false; std::set<IFrameCallback*> callbacks; @@ -212,6 +223,15 @@ void RenderThread::dispatchFrameCallbacks() { } } +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); + } +} + bool RenderThread::threadLoop() { initializeDisplayEventReceiver(); @@ -236,6 +256,14 @@ bool RenderThread::threadLoop() { timeoutMillis = 0; } } + + if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) { + drainDisplayEventQueue(true); + mFrameCallbacks.insert( + mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end()); + mPendingRegistrationFrameCallbacks.clear(); + requestVsync(); + } } return false; @@ -250,6 +278,12 @@ void RenderThread::queue(RenderTask* task) { } } +void RenderThread::queueAtFront(RenderTask* task) { + AutoMutex _lock(mLock); + mQueue.queueAtFront(task); + mLooper->wake(); +} + void RenderThread::queueDelayed(RenderTask* task, int delayMs) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); task->mRunAt = now + milliseconds_to_nanoseconds(delayMs); @@ -262,17 +296,18 @@ void RenderThread::remove(RenderTask* task) { } void RenderThread::postFrameCallback(IFrameCallback* callback) { - mFrameCallbacks.insert(callback); - if (!mVsyncRequested) { - mVsyncRequested = true; - status_t status = mDisplayEventReceiver->requestNextVsync(); - LOG_ALWAYS_FATAL_IF(status != NO_ERROR, - "requestNextVsync failed with status: %d", status); - } + mPendingRegistrationFrameCallbacks.insert(callback); } void RenderThread::removeFrameCallback(IFrameCallback* callback) { mFrameCallbacks.erase(callback); + mPendingRegistrationFrameCallbacks.erase(callback); +} + +void RenderThread::pushBackFrameCallback(IFrameCallback* callback) { + if (mFrameCallbacks.erase(callback)) { + mPendingRegistrationFrameCallbacks.insert(callback); + } } RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { @@ -281,11 +316,13 @@ RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) { 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 = 0; } - mNextWakeup = next->mRunAt; } if (nextWakeup) { *nextWakeup = mNextWakeup; |