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