longrecordDuration=0; if (mProfilingEnabled) { recordDuration = System.nanoTime(); }
updateRootDisplayList(view, callbacks);
if (mProfilingEnabled) { recordDuration = System.nanoTime() - recordDuration; }
attachInfo.mIgnoreDirtyState = false;
// register animating rendernodes which started animating prior to renderer // creation, which is typical for animators started prior to first draw if (attachInfo.mPendingAnimatingRenderNodes != null) { finalintcount= attachInfo.mPendingAnimatingRenderNodes.size(); for (inti=0; i < count; i++) { registerAnimatingRenderNode( attachInfo.mPendingAnimatingRenderNodes.get(i)); } attachInfo.mPendingAnimatingRenderNodes.clear(); // We don't need this anymore as subsequent calls to // ViewRootImpl#attachRenderNodeAnimator will go directly to us. attachInfo.mPendingAnimatingRenderNodes = null; }
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; } }
接着看 RenderThread 之前的 queue 方法,
1 2 3 4 5 6 7 8 9 10 11 12
voidLooper::wake(){ ssize_t nWrite; do { nWrite = write(mWakeWritePipeFd, "W", 1); } while (nWrite == -1 && errno == EINTR);
if (nWrite != 1) { if (errno != EAGAIN) { ALOGW("Could not write wake signal, errno=%d", errno); } } }
wake 函数则更为简单,仅仅向管道的写端写入一个字符“W”,这样管道的读端就会因为有数据可读而从等待状态中醒来。
// Start the thread in threadLoop() which needs to be implemented. virtualstatus_trun( constchar* name = 0, int32_t priority = PRIORITY_DEFAULT, size_t stack = 0);
int timeoutMillis = -1; for (;;) { int result = mLooper->pollOnce(timeoutMillis); LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, "RenderThread Looper POLL_ERROR!");
nsecs_t nextWakeup; // Process our queue, if we have anything while (RenderTask* task = nextTask(&nextWakeup)) { 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; } }
for (size_t i = 0; i < mLayers.size(); i++) { mContext->processLayerUpdate(mLayers[i].get()); } mLayers.clear(); mContext->prepareTree(info);
if (info.out.hasAnimations) { if (info.out.requiresUiRedraw) { mSyncResult |= kSync_UIRedrawRequired; } } //If prepareTextures is false, we ran out of texture cache space return info.prepareTextures; }
voidCanvasContext::makeCurrent() { // In the meantime this matches the behavior of GLRenderer, so it is not a regression mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface); }
bool EglManager::makeCurrent(EGLSurface surface) { if (isCurrent(surface)) returnfalse;
if (surface == EGL_NO_SURFACE) { // If we are setting EGL_NO_SURFACE we don't care about any of the potential // returnerrors, which would only happen if mEglDisplay had already been // destroyed in which case the current contextis already NO_CONTEXT TIME_LOG("eglMakeCurrent", eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); } else { EGLBoolean success; TIME_LOG("eglMakeCurrent", success = eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)); if (!success) { LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s", (void*)surface, egl_error_str()); } } mCurrentSurface = surface; returntrue; }
if (info.canvasContext) { freePrefetechedLayers(); }
int runningBehind = 0; // TODO: This query is moderately expensive, investigate adding some sort // of fast-path based off when we last called eglSwapBuffers() as well as // last vsync time. Or something. TIME_LOG("nativeWindowQuery", mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind)); info.out.canDrawThisFrame = !runningBehind;
if (info.out.hasAnimations || !info.out.canDrawThisFrame) { if (!info.out.requiresUiRedraw) { // If animationsNeedsRedraw is set don't bother posting for an RT anim // as we will just end up fighting the UI thread. mRenderThread.postFrameCallback(this); } } }
// dirty is an out parameter and should not be recorded, // it matters only when replaying the display list DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *currentTransform()); addRenderNodeOp(op);
// Layer renderers will start the frame immediately // The framebuffer renderer will first defer the display list // for each layer and wait until the first drawing command // to start the frame if (currentSnapshot()->fbo == 0) { syncState(); updateLayers(); } else { return startFrame(); }
return DrawGlInfo::kStatusDone; }
2.3 drawRenderNode
1 2
Rect outBounds; status |= mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);