Android 源码 图形系统之硬件渲染器绘制
硬件渲染器绘制从调用 HardwareRenderer 类 draw 方法实现 View 绘制开始。
frameworks/base/core/java/android/view/ViewRootImpl.java
public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { ...... private void draw(boolean fullRedrawNeeded) { ...... if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) { if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) { ...... mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this); } else { ...... } } ...... } ......}
- 更新 RootDisplayList( DisplayList 用于保存属性并在渲染器上执行回放)
- 注册动画渲染节点
- 同步和绘制帧
先着重分析 1。
frameworks/base/core/java/android/view/ThreadedRenderer.java
public class ThreadedRenderer extends HardwareRenderer { ...... @Override void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) { attachInfo.mIgnoreDirtyState = true; final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer; choreographer.mFrameInfo.markDrawStart(); // 1. 更新 RootDisplayList updateRootDisplayList(view, callbacks); attachInfo.mIgnoreDirtyState = false; // 2. 注册动画渲染节点 if (attachInfo.mPendingAnimatingRenderNodes != null) { final int count = attachInfo.mPendingAnimatingRenderNodes.size(); for (int i = 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; } final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo; // 3. 同步和绘制帧 int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length); if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) { setEnabled(false); attachInfo.mViewRootImpl.mSurface.release(); // 由于绘制失败,因此无效。如果仍然需要,则应该获取一个 Surface; // 如果不再绘制,则不执行任何操作 attachInfo.mViewRootImpl.invalidate(); } if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) { attachInfo.mViewRootImpl.invalidate(); } } ......}
- 调用 updateViewTreeDisplayList(…) 更新 View 树 DisplayList
- 调用渲染节点(RenderNode 类) start(…) 方法获取 DisplayListCanvas 对象
- 调用 drawRenderNode(…) 绘制渲染节点
- 调用渲染节点 end 方法
frameworks/base/core/java/android/view/ThreadedRenderer.java
public class ThreadedRenderer extends HardwareRenderer { ...... private void updateRootDisplayList(View view, HardwareDrawCallbacks callbacks) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()"); updateViewTreeDisplayList(view); if (mRootNodeNeedsUpdate || !mRootNode.isValid()) { DisplayListCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight); try { final int saveCount = canvas.save(); canvas.translate(mInsetLeft, mInsetTop); // 在绘制之前回调 onHardwarePreDraw 方法 callbacks.onHardwarePreDraw(canvas); // 插入 Reorder 屏障 canvas.insertReorderBarrier(); // 绘制渲染节点 canvas.drawRenderNode(view.updateDisplayListIfDirty()); // 插入 Inorder 屏障 canvas.insertInorderBarrier(); // 在绘制后回调 onHardwarePostDraw 方法 callbacks.onHardwarePostDraw(canvas); canvas.restoreToCount(saveCount); mRootNodeNeedsUpdate = false; } finally { // 调用渲染节点 end 方法 mRootNode.end(canvas); } } Trace.traceEnd(Trace.TRACE_TAG_VIEW); } ......}
updateViewTreeDisplayList(…) 设置、清除了一些 flag,然后调用了 View 类 updateDisplayListIfDirty() 方法,如果 View 是脏的更新 DisplayList。
frameworks/base/core/java/android/view/ThreadedRenderer.java
public class ThreadedRenderer extends HardwareRenderer { ...... private void updateViewTreeDisplayList(View view) { // 设置 PFLAG_DRAWN 已绘制标志 view.mPrivateFlags |= View.PFLAG_DRAWN; // 如果设置了 PFLAG_INVALIDATED 无效标志,则赋值 mRecreateDisplayList 为 true view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED) == View.PFLAG_INVALIDATED; // 清除 PFLAG_INVALIDATED 标志 view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; view.updateDisplayListIfDirty(); view.mRecreateDisplayList = false; } ......}
updateDisplayListIfDirty() 获取 View 的 RenderNode,并更新它的 DisplayList(如果需要和支持)。
- 调用 dispatchGetDisplayList() 分发获取 DisplayList
- 调用 dispatchDraw(…) 派发绘制或者直接调用 draw(…) 绘制
tips:
层类型是 LAYER_TYPE_SOFTWARE 时指示 View 具有软件层。软件层是由位图支持的,即使启用了硬件加速,也可以使用 Android 的软件渲染管道来渲染 View。
软件层有各种各样的用途
当应用程序不使用硬件加速,软件层是有用的应用一个特定的颜色滤镜和/或混合模式和/或半透明的一个 View 和它的所有子 View。
当应用程序使用硬件加速时,软件层用于渲染硬件加速管道不支持的绘图原语。它还可以用于将复杂的视图树缓存到纹理中,并降低绘图操作的复杂性。例如,当一个复杂的视图树被转换成动画时,一个软件层只能用于渲染视图树一次。
当受影响的视图树经常更新时,应该避免软件层。每次更新都需要重新渲染软件层,这可能会很慢(特别是在打开硬件加速时,因为在每次更新后,软件层都要上传到硬件纹理中)。
frameworks/base/core/java/android/view/View.java
@UiThreadpublic class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource { ...... @NonNull public RenderNode updateDisplayListIfDirty() { final RenderNode renderNode = mRenderNode; if (!canHaveDisplayList()) { // 不能填充 RenderNode return renderNode; } if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || !renderNode.isValid() || (mRecreateDisplayList)) { // 不需要重新创建 DisplayList,只需要告诉孩子 恢复/重新创建 他们的 if (renderNode.isValid() && !mRecreateDisplayList) { mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; dispatchGetDisplayList(); return renderNode; // no work needed } // 重新创建 DisplayList mRecreateDisplayList = true; int width = mRight - mLeft; int height = mBottom - mTop; // 获取层类型 int layerType = getLayerType(); // 调用 RenderNode 类 start(...) 方法获取 DisplayListCanvas 对象 final DisplayListCanvas canvas = renderNode.start(width, height); canvas.setHighContrastText(mAttachInfo.mHighContrastText); try { // 获取 HardwareLayer 对象 final HardwareLayer layer = getHardwareLayer(); if (layer != null && layer.isValid()) { // 调用 DisplayListCanvas 类 drawHardwareLayer 绘制硬件层 canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint); } else if (layerType == LAYER_TYPE_SOFTWARE) { // 如果层类型是 LAYER_TYPE_SOFTWARE // 创建绘制缓存 buildDrawingCache(true); Bitmap cache = getDrawingCache(true); if (cache != null) { // 绘制位图 canvas.drawBitmap(cache, 0, 0, mLayerPaint); } } else { // 一般进入此分支 // 计算滚动 computeScroll(); // 应用平移 canvas.translate(-mScrollX, -mScrollY); mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; // 无背景布局的快速路径 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { // 派发绘制 dispatchDraw(canvas); if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().draw(canvas); } } else { draw(canvas); } } } finally { // 调用渲染节点 end 方法 renderNode.end(canvas); setDisplayListProperties(renderNode); } } else { mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; mPrivateFlags &= ~PFLAG_DIRTY_MASK; } return renderNode; } ......}
dispatchGetDisplayList() 在 View 中是个空方法,根据前面分析,我们传入的是 DecorView。
frameworks/base/core/java/android/view/View.java
@UiThreadpublic class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource { ...... protected void dispatchGetDisplayList() {} ......}
转入 DecorView 类 dispatchGetDisplayList() 方法实现。实际上也没有重写,最终在 ViewGroup 中找到对应实现,DecorView 继承自 FrameLayout ,FrameLayout 继承自 ViewGroup。
frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
public class PhoneWindow extends Window implements MenuBuilder.Callback { ...... private final class DecorView extends FrameLayout implements RootViewSurfaceTaker { ...... } ......}
此方法用于使此 ViewGroup 的子 View 恢复或重新创建它们的 DisplayList。当父 ViewGroup 不需要重新创建自己的 DisplayList 时,getDisplayList() 调用它,如果它通过常规的 draw/dispatchDraw 机制,就会发生这种情况。
frameworks/base/core/java/android/view/ViewGroup.java
@UiThreadpublic abstract class ViewGroup extends View implements ViewParent, ViewManager { ...... @Override protected void dispatchGetDisplayList() { final int count = mChildrenCount; final View[] children = mChildren; for (int i = 0; i < count; i++) { final View child = children[i]; if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) { // 重新创建子 View DisplayList recreateChildDisplayList(child); } } ...... } ......}
子 View 调用 updateDisplayListIfDirty() 更新自己的 DisplayList。
frameworks/base/core/java/android/view/ViewGroup.java
@UiThreadpublic abstract class ViewGroup extends View implements ViewParent, ViewManager { ...... private void recreateChildDisplayList(View child) { child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED) != 0; child.mPrivateFlags &= ~PFLAG_INVALIDATED; child.updateDisplayListIfDirty(); child.mRecreateDisplayList = false; } ......}
现在回到 updateDisplayListIfDirty() 方法。layerType 等于 0,即为 LAYER_TYPE_NONE(指示 View 没有层)。首先调用 dispatchDraw(…) 开始派发绘制。这个方法实现在 ViewGroup 中。这里调用了 drawChild(…) 绘制孩子。
frameworks/base/core/java/android/view/ViewGroup.java
@UiThreadpublic abstract class ViewGroup extends View implements ViewParent, ViewManager { ...... @Override protected void dispatchDraw(Canvas canvas) { boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode); final int childrenCount = mChildrenCount; final View[] children = mChildren; int flags = mGroupFlags; ...... if (usingRenderNodeProperties) canvas.insertReorderBarrier(); final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size(); int transientIndex = transientCount != 0 ? 0 : -1; // 如果没有 HW 加速,只使用预先排序的列表,因为 HW 管道将在内部做绘制重新排序 final ArrayList<View> preorderedList = usingRenderNodeProperties ? null : buildOrderedChildList(); final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled(); for (int i = 0; i < childrenCount; i++) { while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) { final View transientChild = mTransientViews.get(transientIndex); if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE || transientChild.getAnimation() != null) { // 绘制孩子 more |= drawChild(canvas, transientChild, drawingTime); } transientIndex++; if (transientIndex >= transientCount) { transientIndex = -1; } } int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i; final View child = (preorderedList == null) ? children[childIndex] : preorderedList.get(childIndex); if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) { // 绘制孩子 more |= drawChild(canvas, child, drawingTime); } } while (transientIndex >= 0) { // 在正常视图之后可能会有其他的临时视图 final View transientChild = mTransientViews.get(transientIndex); if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE || transientChild.getAnimation() != null) { // 绘制孩子 more |= drawChild(canvas, transientChild, drawingTime); } transientIndex++; if (transientIndex >= transientCount) { break; } } ...... } ......}
绘制此 ViewGroup 的一个子 View。此方法负责将画布置于正确的状态。其内部实现调用了 View 的 draw(…) 方法。
frameworks/base/core/java/android/view/ViewGroup.java
@UiThreadpublic abstract class ViewGroup extends View implements ViewParent, ViewManager { ...... protected boolean drawChild(Canvas canvas, View child, long drawingTime) { return child.draw(canvas, this, drawingTime); } ......}
View 最终会调用 draw(Canvas canvas) 绘制。
绘制执行几个绘制步骤,这些步骤必须以适当的顺序执行:
- 绘制背景
- 如有必要,保存画布的图层以准备 fading
- 绘制视图的内容
- 绘制孩子
- 如有必要,绘制 fading 边缘并恢复图层
- 绘制装饰(例如滚动条)
frameworks/base/core/java/android/view/View.java
@UiThreadpublic class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource { ...... @CallSuper public void draw(Canvas canvas) { final int privateFlags = mPrivateFlags; final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; // 1.绘制背景 int saveCount; if (!dirtyOpaque) { drawBackground(canvas); } // 如果可能的话跳过第2步和第5步(一般情况) final int viewFlags = mViewFlags; boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; if (!verticalEdges && !horizontalEdges) { // 3.绘制视图的内容,自定义 View 一般会实现 onDraw 方法 if (!dirtyOpaque) onDraw(canvas); // 4.绘制孩子 dispatchDraw(canvas); // Overlay 是内容的一部分,在前景下面绘制 if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } // 6.绘制装饰(前景、滚动条) onDrawForeground(canvas); // we're done... return; } /* * 在这里,我们做完整的例行公事...... * (在这种情况下,速度并不重要,这就是为什么我们重复上面做过的一些测试) */ boolean drawTop = false; boolean drawBottom = false; boolean drawLeft = false; boolean drawRight = false; float topFadeStrength = 0.0f; float bottomFadeStrength = 0.0f; float leftFadeStrength = 0.0f; float rightFadeStrength = 0.0f; // 2.保存画布的图层 int paddingLeft = mPaddingLeft; final boolean offsetRequired = isPaddingOffsetRequired(); if (offsetRequired) { paddingLeft += getLeftPaddingOffset(); } int left = mScrollX + paddingLeft; int right = left + mRight - mLeft - mPaddingRight - paddingLeft; int top = mScrollY + getFadeTop(offsetRequired); int bottom = top + getFadeHeight(offsetRequired); if (offsetRequired) { right += getRightPaddingOffset(); bottom += getBottomPaddingOffset(); } final ScrollabilityCache scrollabilityCache = mScrollCache; final float fadeHeight = scrollabilityCache.fadingEdgeLength; int length = (int) fadeHeight; // clip the fade length if top and bottom fades overlap // overlapping fades produce odd-looking artifacts if (verticalEdges && (top + length > bottom - length)) { length = (bottom - top) / 2; } // 如果需要,还可以剪切水平渐变 if (horizontalEdges && (left + length > right - length)) { length = (right - left) / 2; } if (verticalEdges) { topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); drawTop = topFadeStrength * fadeHeight > 1.0f; bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); drawBottom = bottomFadeStrength * fadeHeight > 1.0f; } if (horizontalEdges) { leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); drawLeft = leftFadeStrength * fadeHeight > 1.0f; rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); drawRight = rightFadeStrength * fadeHeight > 1.0f; } saveCount = canvas.getSaveCount(); int solidColor = getSolidColor(); if (solidColor == 0) { final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; if (drawTop) { canvas.saveLayer(left, top, right, top + length, null, flags); } if (drawBottom) { canvas.saveLayer(left, bottom - length, right, bottom, null, flags); } if (drawLeft) { canvas.saveLayer(left, top, left + length, bottom, null, flags); } if (drawRight) { canvas.saveLayer(right - length, top, right, bottom, null, flags); } } else { scrollabilityCache.setFadeColor(solidColor); } // 3.绘制内容 if (!dirtyOpaque) onDraw(canvas); // 4.绘制孩子 dispatchDraw(canvas); // 5.绘制 fade 效果并恢复图层 final Paint p = scrollabilityCache.paint; final Matrix matrix = scrollabilityCache.matrix; final Shader fade = scrollabilityCache.shader; if (drawTop) { matrix.setScale(1, fadeHeight * topFadeStrength); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, top, right, top + length, p); } if (drawBottom) { matrix.setScale(1, fadeHeight * bottomFadeStrength); matrix.postRotate(180); matrix.postTranslate(left, bottom); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, bottom - length, right, bottom, p); } if (drawLeft) { matrix.setScale(1, fadeHeight * leftFadeStrength); matrix.postRotate(-90); matrix.postTranslate(left, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(left, top, left + length, bottom, p); } if (drawRight) { matrix.setScale(1, fadeHeight * rightFadeStrength); matrix.postRotate(90); matrix.postTranslate(right, top); fade.setLocalMatrix(matrix); p.setShader(fade); canvas.drawRect(right - length, top, right, bottom, p); } canvas.restoreToCount(saveCount); // Overlay 是内容的一部分,在前景下面绘制 if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } // 6.绘制装饰(前景、滚动条) onDrawForeground(canvas); } ......}
现在继续分析 RootNode 类 start(…) 方法。
开始为渲染节点记录 DisplayList。在返回的画布上执行的所有操作都被记录并存储在这个 DisplayList 中。调用此方法将标记渲染节点无效,直到调用 end(DisplayListCanvas) 为止。只能重放有效的渲染节点。
- 调用 DisplayListCanvas 类静态 obtain(…) 方法返回 DisplayListCanvas 对象
- 设置视图端口大小
- 绘制前动作,执行任何绘制操作之前调用。对于 DisplayList,dirty 区域应该始终为 null。
frameworks/base/core/java/android/view/RenderNode.java
public class RenderNode { ...... public DisplayListCanvas start(int width, int height) { DisplayListCanvas canvas = DisplayListCanvas.obtain(this); // 设置视图端口大小 canvas.setViewport(width, height); // 对于 DisplayList,dirty 区域应该始终为 null。 // 绘制前动作,执行任何绘制操作之前调用 canvas.onPreDraw(null); return canvas; } ......}
DisplayListCanvas 类记录绘图操作的 GL 画布的实现。它用于 DisplayList。这个类保存了它所绘制的所有绘制和位图对象的列表,防止当 DisplayList 仍然持有对内存的本地引用时位图的后备内存被释放。
假设画布池中没有 DisplayListCanvas 对象,现在就会 new 一个出来。
frameworks/base/core/java/android/view/DisplayListCanvas.java
public class DisplayListCanvas extends Canvas { // 记录画布池应该大到足以处理深度嵌套的视图层次结构,因为 DisplayList 是递归生成的。 private static final int POOL_LIMIT = 25; private static final SynchronizedPool<DisplayListCanvas> sPool = new SynchronizedPool<DisplayListCanvas>(POOL_LIMIT); RenderNode mNode; private int mWidth; private int mHeight; static DisplayListCanvas obtain(@NonNull RenderNode node) { if (node == null) throw new IllegalArgumentException("node cannot be null"); DisplayListCanvas canvas = sPool.acquire(); if (canvas == null) { canvas = new DisplayListCanvas(); } canvas.mNode = node; return canvas; } ......}
调用 nCreateDisplayListCanvas() jni 方法并将返回值作为入参传入父类 Canvas 构造器。
frameworks/base/core/java/android/view/DisplayListCanvas.java
public class DisplayListCanvas extends Canvas { ...... private DisplayListCanvas() { super(nCreateDisplayListCanvas()); mDensity = 0; // 禁用位图密度缩放 } private static native long nCreateDisplayListCanvas(); ......}
Canvas 构造函数中仅仅将入参保存在了成员变量 mNativeCanvasWrapper 中。
frameworks/base/graphics/java/android/graphics/Canvas.java
public class DisplayListCanvas extends Canvas { ...... /** * 应该只在构造函数中分配(或者在软件画布调用 setBitmap 中分配),在终结器中释放。 * @hide */ protected long mNativeCanvasWrapper; ...... public Canvas(long nativeCanvas) { if (nativeCanvas == 0) { throw new IllegalStateException(); } mNativeCanvasWrapper = nativeCanvas; ...... } ......}
现在来继续分析 nCreateDisplayListCanvas() 函数本地实现。new 了 DisplayListCanvas 对象,然后将其强转为 jlong 返回,这样就将 Native 层 DisplayListCanvas 对象的引用传回了 Java 层。
frameworks/base/core/jni/android_view_DisplayListCanvas.cpp
static jlong android_view_DisplayListCanvas_createDisplayListCanvas(JNIEnv* env, jobject clazz) { return reinterpret_cast<jlong>(new DisplayListCanvas);}
mDisplayListData 成员变量初始化为空指针。
frameworks/base/libs/hwui/DisplayListCanvas.cpp
DisplayListCanvas::DisplayListCanvas() : mState(*this) , mResourceCache(ResourceCache::getInstance()) , mDisplayListData(nullptr) , mTranslateX(0.0f) , mTranslateY(0.0f) , mHasDeferredTranslate(false) , mDeferredBarrierType(kBarrier_None) , mHighContrastText(false) , mRestoreSaveCount(-1) {}
onPreDraw(…) 入参是 null,因此会走 else 分支。
frameworks/base/core/java/android/view/DisplayListCanvas.java
public class DisplayListCanvas extends Canvas { ...... public void onPreDraw(Rect dirty) { if (dirty != null) { ...... } else { nPrepare(mNativeCanvasWrapper); } } private static native void nPrepare(long renderer); ......}
- 将 Java 层保存的 DisplayListCanvas 引用取出
- 调用 DisplayListCanvas 对象的 prepare() 方法
frameworks/base/core/jni/android_view_DisplayListCanvas.cpp
static void android_view_DisplayListCanvas_prepare(JNIEnv* env, jobject clazz, jlong rendererPtr) { DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr); renderer->prepare();}
prepare() 内部实际调用了 prepareDirty(…),只不过入参固定了(见名知其意)。
frameworks/base/libs/hwui/DisplayListCanvas.h
class ANDROID_API DisplayListCanvas: public Canvas, public CanvasStateClient {public: ......// ----------------------------------------------------------------------------// HWUI 帧状态操作// ---------------------------------------------------------------------------- void prepareDirty(float left, float top, float right, float bottom); void prepare() { prepareDirty(0.0f, 0.0f, width(), height()); } ......}
prepareDirty(…) 方法中创建了 DisplayListData 对象,回顾一下,它是用于保存实际数据的(保存 DisplayList 流中使用的命令列表的数据结构)。
frameworks/base/libs/hwui/DisplayListCanvas.cpp
void DisplayListCanvas::prepareDirty(float left, float top, float right, float bottom) { LOG_ALWAYS_FATAL_IF(mDisplayListData, "prepareDirty called a second time during a recording!"); mDisplayListData = new DisplayListData(); ......}
projectionReceiveIndex —— DisplayListOp 的索引。
frameworks/base/libs/hwui/DisplayList.cpp
DisplayListData::DisplayListData() : projectionReceiveIndex(-1) , hasDrawOps(false) {}
最后来看 DisplayListCanvas 类 drawRenderNode(…) 方法。此方法表示在此画布上绘制指定的 DisplayList。只有当 android.view.RenderNode#isValid() 返回 true 时,才能绘制 DisplayList。
frameworks/base/core/java/android/view/DisplayListCanvas.java
public class DisplayListCanvas extends Canvas { ...... public void drawRenderNode(RenderNode renderNode) { nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList()); } private static native void nDrawRenderNode(long renderer, long renderNode); ......}
- 获取 DisplayListCanvas 对象
- 获取 RenderNode 对象
- 调用 DisplayListCanvas 类 drawRenderNode 方法绘制渲染节点
frameworks/base/core/jni/android_view_DisplayListCanvas.cpp
static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong renderNodePtr) { DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr); RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr); renderer->drawRenderNode(renderNode);}
- 创建 DrawRenderNodeOp 对象
- 调用 addRenderNodeOp(…) 将 DrawRenderNodeOp 添加到列表
frameworks/base/libs/hwui/DisplayListCanvas.cpp
void DisplayListCanvas::drawRenderNode(RenderNode* renderNode) { LOG_ALWAYS_FATAL_IF(!renderNode, "missing rendernode"); DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp( renderNode, *mState.currentTransform(), mState.clipIsSimple()); addRenderNodeOp(op);}
将 DrawRenderNodeOp 对象添加到 DisplayListData 类 Vector
frameworks/base/libs/hwui/DisplayListCanvas.cpp
size_t DisplayListCanvas::addRenderNodeOp(DrawRenderNodeOp* op) { int opIndex = addDrawOp(op); int childIndex = mDisplayListData->addChild(op); // 更新块的子索引 DisplayListData::Chunk& chunk = mDisplayListData->chunks.editTop(); chunk.endChildIndex = childIndex + 1; if (op->renderNode()->stagingProperties().isProjectionReceiver()) { // 使用暂存属性,因为在 UI 线程上记录 mDisplayListData->projectionReceiveIndex = opIndex; } return opIndex;}
最后画时序图总结一下。
更多相关文章
- Android获取窗体信息的Util方法
- Android 几种加密解密的方法(仅代码)
- Android 实现模拟按键方法一
- Android两种轮询的实现方法
- Android MonkeyRunner调用方法总结
- android home 键的监听方法记录
- Android 四种获取屏幕宽度的方法总结