在《Android 源码 图形系统之硬件渲染器绘制》一节中没有分析 nSyncAndDrawFrame(…) 同步和绘制帧,这一节继续分析。
frameworks/base/core/java/android/view/ThreadedRenderer.java
public class ThreadedRenderer extends HardwareRenderer {
......
@Override
void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
......
final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
// 3. 同步和绘制帧
int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
......
}
......
private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
......
}
- proxyPtr 强转为 RenderProxy* 指针
- 将 frameInfo jlongArray 复制到缓冲区(proxy->frameInfo())中
- 调用 RenderProxy syncAndDrawFrame() 方法
frameworks/base/core/jni/android_view_ThreadedRenderer.cpp
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
"Mismatched size expectations, given %d expected %d",
frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
return proxy->syncAndDrawFrame();
}
syncAndDrawFrame() 内调用了 DrawFrameTask 的 drawFrame() 方法。
frameworks/base/libs/hwui/renderthread/RenderProxy.cpp
int RenderProxy::syncAndDrawFrame() {
return mDrawFrameTask.drawFrame();
}
这里主要调用了 postAndWait(),从方法名不难推测出是将任务推到队列并等待。
frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
int DrawFrameTask::drawFrame() {
LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
mSyncResult = kSync_OK;
mSyncQueued = systemTime(CLOCK_MONOTONIC);
postAndWait();
return mSyncResult;
}
原来推到了 RenderThread 的队列了。
frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
void DrawFrameTask::postAndWait() {
AutoMutex _lock(mLock);
mRenderThread->queue(this);
mSignal.wait(mLock);
}
- 将 RenderTask 推到任务队列 TaskQueue 中
- 如果任务运行时间点小于下次唤醒点,调用 Looper wake() 方法进行唤醒
frameworks/base/libs/hwui/renderthread/RenderThread.cpp
void RenderThread::queue(RenderTask* task) {
AutoMutex _lock(mLock);
mQueue.queue(task);
if (mNextWakeup && task->mRunAt < mNextWakeup) {
mNextWakeup = 0;
mLooper->wake();
}
}
入队方法很简单,根据任务运行时间点,在队列中从小到大进行排列。
frameworks/base/libs/hwui/renderthread/RenderThread.cpp
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;
}
}
假设 Looper 之前在 RenderThread 类 threadLoop() 中 pollOnce(…) 方法上睡眠,则入队渲染任务(RenderTask)以后立马会唤醒。接着就会调用 nextTask(…) 从队列中取出渲染任务。接着就会调用其 run() 方法执行。
frameworks/base/libs/hwui/renderthread/RenderThread.cpp
bool RenderThread::threadLoop() {
......
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
}
......
}
return false;
}
- 调用 syncFrameState(…) 同步帧状态
- 调用 CanvasContext 类 draw() 方法绘制帧
frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
void DrawFrameTask::run() {
ATRACE_NAME("DrawFrame");
bool canUnblockUiThread;
bool canDrawThisFrame;
{
TreeInfo info(TreeInfo::MODE_FULL, mRenderThread->renderState());
canUnblockUiThread = syncFrameState(info);
canDrawThisFrame = info.out.canDrawThisFrame;
}
// Grab a copy of everything we need
CanvasContext* context = mContext;
// From this point on anything in "this" is *UNSAFE TO ACCESS*
if (canUnblockUiThread) {
unblockUiThread();
}
if (CC_LIKELY(canDrawThisFrame)) {
context->draw();
}
if (!canUnblockUiThread) {
unblockUiThread();
}
}
- 调用 CanvasContext 类 makeCurrent() 方法创建 EGL 渲染上下文等
- 处理层更新
- 通过 CanvasContext 的 prepareTree() 继而调用 RenderNode 的 prepareTree() 同步渲染信息。最后会输出 TreeInfo 结构,其中的 prepareTextures 代表纹理上传是否成功。如果为 false,说明纹理缓存空间用完了。这样为了防止渲染线程在渲染过程中使用的资源和主线程竞争
frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
bool DrawFrameTask::syncFrameState(TreeInfo& info) {
ATRACE_CALL();
int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
mRenderThread->timeLord().vsyncReceived(vsync);
mContext->makeCurrent();
Caches::getInstance().textureCache.resetMarkInUse(mContext);
for (size_t i = 0; i < mLayers.size(); i++) {
mContext->processLayerUpdate(mLayers[i].get());
}
mLayers.clear();
mContext->prepareTree(info, mFrameInfo, mSyncQueued);
// 这是在 prepareTree 之后,这样任何挂起的操作(RenderNode tree状态,预抓取的层等等)都将被刷新。
if (CC_UNLIKELY(!mContext->hasSurface())) {
mSyncResult |= kSync_LostSurfaceRewardIfFound;
}
if (info.out.hasAnimations) {
if (info.out.requiresUiRedraw) {
mSyncResult |= kSync_UIRedrawRequired;
}
}
// 如果 prepareTextures 为 false,我们就用完了纹理缓存空间
return info.prepareTextures;
}
此方法实际调用了 EglManager 类 makeCurrent(…) 完成实际工作。
frameworks/base/libs/hwui/renderthread/CanvasContext.cpp
void CanvasContext::makeCurrent() {
// TODO: Figure out why this workaround is needed, see b/13913604
// In the meantime this matches the behavior of GLRenderer, so it is not a regression
EGLint error = 0;
mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface, &error);
if (error) {
setSurface(nullptr);
}
}
如果当前 Surface 已改变,则返回 true;如果已经是当前 Surface,则返回 false。主要调用 eglMakeCurrent(…) 完成创建 EGL 渲染上下文等动作, eglMakeCurrent(…) 函数位于 opengl 库中。
frameworks/base/libs/hwui/renderthread/EglManager.cpp
bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut) {
if (isCurrent(surface)) return false;
if (surface == EGL_NO_SURFACE) {
// 确保我们总是有一个有效的 Surface 和上下文
surface = mPBufferSurface;
}
if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
if (errOut) {
*errOut = eglGetError();
ALOGW("Failed to make current on surface %p, error=%s",
(void*)surface, egl_error_str(*errOut));
} else {
LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
(void*)surface, egl_error_str());
}
}
mCurrentSurface = surface;
return true;
}
处理层更新。
- 调用 DeferredLayerUpdater 类 apply() 处理
- 获取 DeferredLayerUpdater 的 backingLayer() ,也就是 Layer。如果需要延迟安排处理,调用 OpenGLRenderer 类 pushLayerUpdate(…) 方法将层添加到容器(Vector< sp >,它代表在一个帧的开始要更新的层的列表)中
frameworks/base/libs/hwui/renderthread/CanvasContext.cpp
void CanvasContext::processLayerUpdate(DeferredLayerUpdater* layerUpdater) {
bool success = layerUpdater->apply();
LOG_ALWAYS_FATAL_IF(!success, "Failed to update layer!");
if (layerUpdater->backingLayer()->deferredUpdateScheduled) {
mCanvas->pushLayerUpdate(layerUpdater->backingLayer());
}
}
DeferredLayerUpdater 类代表一个容器,用于保存应在渲染过程开始时将图层设置为的属性。
apply 有应用的意思,也就是将某些属性应用的层上。另外,还调用了 SurfaceTexture 类 attachToContext(…) 方法将层的 TextureId attach 到上下文;更新了 Texture Image;加载了 Transform。
frameworks/base/libs/hwui/DeferredLayerUpdater.cpp
bool DeferredLayerUpdater::apply() {
bool success = true;
// 这些属性对这两种层类型应用相同
mLayer->setColorFilter(mColorFilter);
mLayer->setAlpha(mAlpha, mMode);
if (mSurfaceTexture.get()) {
if (mNeedsGLContextAttach) {
mNeedsGLContextAttach = false;
mSurfaceTexture->attachToContext(mLayer->getTextureId());
}
if (mUpdateTexImage) {
mUpdateTexImage = false;
doUpdateTexImage();
}
if (mTransform) {
mLayer->getTransform().load(*mTransform);
setTransform(nullptr);
}
}
return success;
}
进一步调用 RenderNode 类 prepareTree(…) 准备树信息(TreeInfo)。mRootRenderNode 是 RenderNode 类型。
frameworks/base/libs/hwui/renderthread/CanvasContext.cpp
void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued) {
mRenderThread.removeFrameCallback(this);
// 如果前一帧被丢弃,我们不需要保留它,所以只要继续使用前一帧的结构即可
if (!wasSkipped(mCurrentFrameInfo)) {
mCurrentFrameInfo = &mFrames.next();
}
mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued;
mCurrentFrameInfo->markSyncStart();
info.damageAccumulator = &mDamageAccumulator;
info.renderer = mCanvas;
info.canvasContext = this;
mAnimationContext->startFrame(info.mode);
mRootRenderNode->prepareTree(info);
mAnimationContext->runRemainingAnimations(info);
......
}
在 RenderNode 类 prepareTree() 方法内具体实现是靠 prepareTreeImpl(…) 方法。
frameworks/base/libs/hwui/RenderNode.cpp
void RenderNode::prepareTree(TreeInfo& info) {
ATRACE_CALL();
LOG_ALWAYS_FATAL_IF(!info.damageAccumulator, "DamageAccumulator missing");
// Functors don't correctly handle stencil usage of overdraw debugging - shove 'em in a layer.
bool functorsNeedLayer = Properties::debugOverdraw;
prepareTreeImpl(info, functorsNeedLayer);
}
遍历绘制树以准备帧。
MODE_FULL = UI线程驱动(因此必须同步属性),否则 RT 驱动。
遍历树时,如果可能需要使用模版缓冲区的任何内容,则 functorsNeedLayer 标志设置为 true。使用仿函数(functor )绘制的 View 将被强制放置在 Layer 上。
下面重点来分析一下 prepareSubTree(…) 和 pushLayerUpdate(…)。
frameworks/base/libs/hwui/RenderNode.cpp
void RenderNode::prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer) {
info.damageAccumulator->pushTransform(this);
if (info.mode == TreeInfo::MODE_FULL) {
pushStagingPropertiesChanges(info);
}
uint32_t animatorDirtyMask = 0;
if (CC_LIKELY(info.runAnimations)) {
animatorDirtyMask = mAnimatorManager.animate(info);
}
bool willHaveFunctor = false;
if (info.mode == TreeInfo::MODE_FULL && mStagingDisplayListData) {
willHaveFunctor = !mStagingDisplayListData->functors.isEmpty();
} else if (mDisplayListData) {
willHaveFunctor = !mDisplayListData->functors.isEmpty();
}
bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence(
willHaveFunctor, functorsNeedLayer);
prepareLayer(info, animatorDirtyMask);
if (info.mode == TreeInfo::MODE_FULL) {
pushStagingDisplayListChanges(info);
}
prepareSubTree(info, childFunctorsNeedLayer, mDisplayListData);
pushLayerUpdate(info);
info.damageAccumulator->popTransform();
}
prepareSubTree(…) 内部递归调用 prepareTreeImpl(…) 准备树信息。
frameworks/base/libs/hwui/RenderNode.cpp
void RenderNode::prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayListData* subtree) {
if (subtree) {
TextureCache& cache = Caches::getInstance().textureCache;
info.out.hasFunctors |= subtree->functors.size();
for (size_t i = 0; info.prepareTextures && i < subtree->bitmapResources.size(); i++) {
info.prepareTextures = cache.prefetchAndMarkInUse(
info.canvasContext, subtree->bitmapResources[i]);
}
for (size_t i = 0; i < subtree->children().size(); i++) {
DrawRenderNodeOp* op = subtree->children()[i];
RenderNode* childNode = op->mRenderNode;
info.damageAccumulator->pushTransform(&op->mTransformFromParent);
bool childFunctorsNeedLayer = functorsNeedLayer
// Recorded with non-rect clip, or canvas-rotated by parent
|| op->mRecordedWithPotentialStencilClip;
childNode->prepareTreeImpl(info, childFunctorsNeedLayer);
info.damageAccumulator->popTransform();
}
}
}
pushLayerUpdate(…) 创建了图层。
frameworks/base/libs/hwui/RenderNode.cpp
void RenderNode::pushLayerUpdate(TreeInfo& info) {
LayerType layerType = properties().effectiveLayerType();
// 如果我们不是图层,或者无法渲染(例如,视图已分离),则需要销毁以前可能拥有的所有图层
if (CC_LIKELY(layerType != LayerType::RenderLayer) || CC_UNLIKELY(!isRenderable())) {
if (CC_UNLIKELY(mLayer)) {
LayerRenderer::destroyLayer(mLayer);
mLayer = nullptr;
}
return;
}
bool transformUpdateNeeded = false;
if (!mLayer) {
// 创建图层
mLayer = LayerRenderer::createRenderLayer(info.renderState, getWidth(), getHeight());
applyLayerPropertiesToLayer(info);
damageSelf(info);
transformUpdateNeeded = true;
} else if (mLayer->layer.getWidth() != getWidth() || mLayer->layer.getHeight() != getHeight()) {
// 图层尺寸变化
if (!LayerRenderer::resizeLayer(mLayer, getWidth(), getHeight())) {
LayerRenderer::destroyLayer(mLayer);
mLayer = nullptr;
}
damageSelf(info);
transformUpdateNeeded = true;
}
SkRect dirty;
info.damageAccumulator->peekAtDirty(&dirty);
......
if (transformUpdateNeeded) {
// 更新图层窗口中的变换,重置其原始 wrt 光源的位置
Matrix4 windowTransform;
info.damageAccumulator->computeCurrentTransform(&windowTransform);
mLayer->setWindowTransform(windowTransform);
}
if (dirty.intersect(0, 0, getWidth(), getHeight())) {
dirty.roundOut(&dirty);
mLayer->updateDeferred(this, dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom);
}
// 如果因为我们可能在没有渲染器的先前准备过程中调用了 updateDeferred,则不在上述内容之内
if (info.renderer && mLayer->deferredUpdateScheduled) {
info.renderer->pushLayerUpdate(mLayer);
}
if (info.canvasContext) {
// 可能存在需要考虑的预取层。
// 告诉 CanvasContext 这层在树中,不应该被销毁。
info.canvasContext->markLayerInUse(this);
}
}
最后来分析调用 CanvasContext 类 draw() 方法绘制帧。mCanvas 指向 OpenGLRenderer 对象。
- 如果帧大小发生了变化,则更改 OpenGLRenderer 视图端口大小
- OpenGLRenderer 准备脏区大小
- 调用 OpenGLRenderer drawRenderNode(…) 绘制节点
- 调用 swapBuffers 方法绘制完成后交换 Buffer
frameworks/base/libs/hwui/renderthread/CanvasContext.cpp
void CanvasContext::draw() {
LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
"drawRenderNode called on a context with no canvas or surface!");
SkRect dirty;
mDamageAccumulator.finish(&dirty);
mCurrentFrameInfo->markIssueDrawCommandsStart();
EGLint width, height;
mEglManager.beginFrame(mEglSurface, &width, &height);
if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
mCanvas->setViewport(width, height);
dirty.setEmpty();
} else if (!mBufferPreserved || mHaveNewSurface) {
dirty.setEmpty();
} else {
if (!dirty.isEmpty() && !dirty.intersect(0, 0, width, height)) {
ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?",
SK_RECT_ARGS(dirty), width, height);
dirty.setEmpty();
}
profiler().unionDirty(&dirty);
}
if (!dirty.isEmpty()) {
mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,
dirty.fRight, dirty.fBottom, mOpaque);
} else {
mCanvas->prepare(mOpaque);
}
Rect outBounds;
mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);
profiler().draw(mCanvas);
bool drew = mCanvas->finish();
// 即使我们决定取消这个帧,从 jank 度量的角度来看,这个帧在此时已经被交换了
mCurrentFrameInfo->markSwapBuffers();
if (drew) {
swapBuffers(dirty, width, height);
}
// TODO: Use a fence for real completion?
mCurrentFrameInfo->markFrameCompleted();
mJankTracker.addFrame(*mCurrentFrameInfo);
mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo);
}
后面 OpenGL 接管后,才真正使用 GPU 进行了绘制。