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; }
intDrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos){ LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
voidTaskQueue::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; } }
// 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); }
mEglManager是一个EglManager对象,其实现为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
boolEglManager::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 // return errors, which would only happen if mEglDisplay had already been // destroyed in which case the current context is already NO_CONTEXT eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } elseif (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) { 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. 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);
voidCanvasContext::draw(){ LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE, "drawRenderNode called on a context with no canvas or surface!");
// 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 { returnstartFrame(); }
return DrawGlInfo::kStatusDone; }
2.3 drawRenderNode
1 2
Rect outBounds; status |= mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);
status_tOpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags){ status_t status; // All the usual checks and setup operations (quickReject, setupDraw, etc.) // will be performed by the display list itself if (renderNode && renderNode->isRenderable()) { // compute 3d ordering renderNode->computeOrdering(); if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { status = startFrame(); ReplayStateStruct replayStruct(*this, dirty, replayFlags); renderNode->replay(replayStruct, 0); return status | replayStruct.mDrawGlStatus; }