Android 源码 图形系统之硬件渲染器绘制

2024-05-01 21:08

本文主要是介绍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 {......}}......}......
}
  1. 更新 RootDisplayList( DisplayList 用于保存属性并在渲染器上执行回放)
  2. 注册动画渲染节点
  3. 同步和绘制帧

先着重分析 1。

frameworks/base/core/java/android/view/ThreadedRenderer.java

public class ThreadedRenderer extends HardwareRenderer {......@Overridevoid draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {attachInfo.mIgnoreDirtyState = true;final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;choreographer.mFrameInfo.markDrawStart();// 1. 更新 RootDisplayListupdateRootDisplayList(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();}}......
}
  1. 调用 updateViewTreeDisplayList(…) 更新 View 树 DisplayList
  2. 调用渲染节点(RenderNode 类) start(…) 方法获取 DisplayListCanvas 对象
  3. 调用 drawRenderNode(…) 绘制渲染节点
  4. 调用渲染节点 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 为 trueview.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(如果需要和支持)。

  1. 调用 dispatchGetDisplayList() 分发获取 DisplayList
  2. 调用 dispatchDraw(…) 派发绘制或者直接调用 draw(…) 绘制

tips:

层类型是 LAYER_TYPE_SOFTWARE 时指示 View 具有软件层。软件层是由位图支持的,即使启用了硬件加速,也可以使用 Android 的软件渲染管道来渲染 View。

软件层有各种各样的用途

当应用程序不使用硬件加速,软件层是有用的应用一个特定的颜色滤镜和/或混合模式和/或半透明的一个 View 和它的所有子 View。

当应用程序使用硬件加速时,软件层用于渲染硬件加速管道不支持的绘图原语。它还可以用于将复杂的视图树缓存到纹理中,并降低绘图操作的复杂性。例如,当一个复杂的视图树被转换成动画时,一个软件层只能用于渲染视图树一次。

当受影响的视图树经常更新时,应该避免软件层。每次更新都需要重新渲染软件层,这可能会很慢(特别是在打开硬件加速时,因为在每次更新后,软件层都要上传到硬件纹理中)。

frameworks/base/core/java/android/view/View.java

@UiThread
public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource {......@NonNullpublic RenderNode updateDisplayListIfDirty() {final RenderNode renderNode = mRenderNode;if (!canHaveDisplayList()) {// 不能填充 RenderNodereturn 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}// 重新创建 DisplayListmRecreateDisplayList = 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

@UiThread
public 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

@UiThread
public abstract class ViewGroup extends View implements ViewParent, ViewManager {......@Overrideprotected 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 DisplayListrecreateChildDisplayList(child);}}......}......
}

子 View 调用 updateDisplayListIfDirty() 更新自己的 DisplayList。

frameworks/base/core/java/android/view/ViewGroup.java

@UiThread
public 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

@UiThread
public abstract class ViewGroup extends View implements ViewParent, ViewManager {......@Overrideprotected 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

@UiThread
public 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) 绘制。

绘制执行几个绘制步骤,这些步骤必须以适当的顺序执行:

  1. 绘制背景
  2. 如有必要,保存画布的图层以准备 fading
  3. 绘制视图的内容
  4. 绘制孩子
  5. 如有必要,绘制 fading 边缘并恢复图层
  6. 绘制装饰(例如滚动条)

frameworks/base/core/java/android/view/View.java

@UiThread
public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource {......@CallSuperpublic 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 artifactsif (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) 为止。只能重放有效的渲染节点。

  1. 调用 DisplayListCanvas 类静态 obtain(…) 方法返回 DisplayListCanvas 对象
  2. 设置视图端口大小
  3. 绘制前动作,执行任何绘制操作之前调用。对于 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);......
}
  1. 将 Java 层保存的 DisplayListCanvas 引用取出
  2. 调用 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);......
}
  1. 获取 DisplayListCanvas 对象
  2. 获取 RenderNode 对象
  3. 调用 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);
}
  1. 创建 DrawRenderNodeOp 对象
  2. 调用 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<DrawRenderNodeOp*> 中。

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 源码 图形系统之硬件渲染器绘制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/952676

相关文章

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

【WebGPU Unleashed】1.1 绘制三角形

一部2024新的WebGPU教程,作者Shi Yan。内容很好,翻译过来与大家共享,内容上会有改动,加上自己的理解。更多精彩内容尽在 dt.sim3d.cn ,关注公众号【sky的数孪技术】,技术交流、源码下载请添加微信号:digital_twin123 在 3D 渲染领域,三角形是最基本的绘制元素。在这里,我们将学习如何绘制单个三角形。接下来我们将制作一个简单的着色器来定义三角形内的像素

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存