Android应用程序UI硬件加速渲染的Display List构建过程分析

上传人:m**** 文档编号:168594607 上传时间:2022-11-11 格式:DOCX 页数:44 大小:175KB
收藏 版权申诉 举报 下载
Android应用程序UI硬件加速渲染的Display List构建过程分析_第1页
第1页 / 共44页
Android应用程序UI硬件加速渲染的Display List构建过程分析_第2页
第2页 / 共44页
Android应用程序UI硬件加速渲染的Display List构建过程分析_第3页
第3页 / 共44页
资源描述:

《Android应用程序UI硬件加速渲染的Display List构建过程分析》由会员分享,可在线阅读,更多相关《Android应用程序UI硬件加速渲染的Display List构建过程分析(44页珍藏版)》请在装配图网上搜索。

1、Android 应用程序 UI 硬件加速渲染的Display List 构建过程分析在硬件加速渲染环境中,Android应用程序窗口的UI渲染是分两步进行的。第一步是构建 Display List,发生在应用程序进程的Main Thread中;第二步是渲染Display List,发生在应 用程序进程的 Render Thread 中。 Display List 是以视图为单位进行构建的,因此每一个视图 都对应有一个Display List。本文详细分析这些Display List的构建过程。这里说的 Display List 与 Open GL 里面的 Display List 在概念上是类

2、似的,不过是两个不同 的实现。 Display List 的本质是一个缓冲区,它里面记录了即将要执行的绘制命令序列。这 些绘制命令最终会转化为Open GL命令由GPU执行。这意味着我们在调用Canvas API绘制 UI时,实际上只是将Canvas API调用及其参数记录在Display List 中,然后等到下一个Vsync 信号到来时,记录在Display List里面的绘制命令才会转化为Open GL命令由GPU执行。 与直接执行绘制命令相比,先将绘制命令记录在Display List中然后再执行有两个好处。第 一个好处是在绘制窗口的下一帧时,若某一个视图的UI没有发生变化,那么就不必

3、执行与 它相关的Canvas API,即不用执行它的成员函数onDraw,而是直接复用上次构建的Display List即可。第二个好处是在绘制窗口的下一帧时,若某一个视图的UI发生了变化,但是只 是一些简单属性发生了变化,例如位置和透明度等简单属性,那么也不必重建它的 Display List,而是直接修改上次构建的Display List的相关属性即可,这样也可以省去执行它的成员 函数 onDraw。Android应用程序窗口视图是树形结构的,因此它们的Display List是从根视图开始 构建的,并且子视图的 Display List 包含在父视图的 Display List 中。这意

4、味着根视图的 Display List包含了 Android应用程序窗口 UI所有的绘制命令,因此最后我们只需要对根视 图的Display List进行渲染即可得到 Android应用程序窗口的 UI,如图1所示:Android应用程序窗口的根视图是虚拟的,抽象为一个Root Render Node。此外,一个视图 如果设置有Background,那么这个Background也会抽象为一个Background Render Node。Root Render Node、Background Render Node和其它真实的子视图,除了 TextureView和软件 渲染的子视图之外,都具有Di

5、splay List,并且是通过一个称为Display List Renderer的对象 进行构建的。TextureView不具有Display List,它们是通过一个称为Layer Renderer的对象 以 Open GL 纹理的形式来绘制的,不过这个纹理也不是直接就进行渲染的,而是先记录在 父视图的Display List中以后再进行渲染的。同样,软件渲染的子视图也不具有Display List, 它们先绘制在一个Bitmap上,然后这个Bitmap再记录在父视图的Display List中以后再进 行渲染的。最后,Root Render Node 的 Display List 被一个

6、称为 Open GL Renderer 的对象进行渲 染,就得到Android应用程序窗口的UI 了。接下来我们就结合源代码来分析Android应用 程序窗口视图的Display List的构建过程。在前面一文提到,Android应用程序窗口 UI的绘制过程是从ViewRootImpl类的成 员函数 performDraw 开始的,它的实现如下所示:java view plain copy public final class ViewRootImpl implements ViewParent,View.AttachInfo.Callbacks, HardwareRenderer.Hardw

7、areDrawCallbacks private void performDraw() try draw(fullRedrawNeeded); finally 这个函数定义在文件 frameworks/base/core/java/android/view/ViewRootImpl.java 中。 ViewRootImpl 类的成员函数 performDraw 主要是调用了另外一个成员函数 draw 执 行 UI 绘制工作,后者的实现如下所示:java view plain copy public final class ViewRootImpl implements ViewParent,V

8、iew.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks private void draw(boolean fullRedrawNeeded) final Rect dirty = mDirty;if (!dirty.isEmpty() | mIsAnimating) if (mAttachInfo.mHardwareRenderer != null & mAttachInfo.mHardwareRenderer.isEnabled() mAttachInfo.mHardwareRenderer.draw(mView,

9、mAttachInfo, this); else if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty) return;这个函数定义在文件 frameworks/base/core/java/android/view/ViewRootImpl.java 中。 经过一些滚动相关的处理之后,在两种情况下,需要真正地重绘窗口的下一帧。第 一种情况是当前需要更新的区域,即ViewRootImpI类的成员变量mDirty描述的脏区域不为 空。第二种情况下窗口当前有动画需要执行,即ViewRootI

10、mpI类的成员变量mIsAnimating 的值等于 true。在上述两种情况下,如果 ViewRootImpl 类的成员变量 mAttachInfo 指向的一个 AttachInfo对象的成员变量 mHardwareRenderer的值不为 null,并且调用它指向的一个 HardwareRenderer 对 象的 成员 函数 isEnabled 的 返回值 为 true, 那么就调用这个 HardwareRenderer对象的另外一个成员函数draw执行渲染工作。从前面一文可以知道,当 使用硬件加速渲染时,ViewRootImpl类的成员变量mAttachInfo指向的一个AttachIn

11、fo对象 的成员变量mHardwareRenderer的值不为null,并且它指向的是一个ThreadedRenderer对象。 如果该ThreadedRenderer对象也设置了支持硬件加速渲染,那么调用它的成员函数isEnabled 的返回值就为true。这意味着当使用硬件加速渲染时,ViewRootImpl类的成员函数draw调 用的是ThreadedRenderer类的成员函数draw。另一方面,当使用软件渲染时,ViewRootImpl 类的成员函数draw调用的是另外一个成员函数drawSoftware。软件渲染的执行过程可以参考前面一文。这里我们只关注硬件渲染的执行过程,因此接下

12、来我们继续分析ThreadedRenderer类的成员函数draw的实现,如下所示:java view plain copypublic class ThreadedRenderer extends HardwareRenderer Overridevoid draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) updateRootDisplayList(view, callbacks);if (attachInfo.mPendingAnimatingRenderNodes != null) final

13、int count = attachInfo.mPendingAnimatingRenderNodes.size(); for (int i = 0; i count; i+) registerAnimatingRenderNode( attachInfo.mPendingAnimatingRenderNodes.get(i);attachInfo.mPendingAnimatingRenderNodes.clear();/ We dont need this anymore as subsequent calls to/ ViewRootImpl#attachRenderNodeAnimat

14、or will go directly to us. attachInfo.mPendingAnimatingRenderNodes = null;int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos, recordDuration, view.getResources().getDisplayMetrics().density);if (syncResult & SYNC_INVALIDATE_REQUIRED) != 0) attachInfo.mViewRootImpl.invalidate();这个函数定义在文件

15、 frameworks/base/core/Java/android/view/ThreadedRenderer.java 中。ThreadedRenderer 类的成员函数 draw 主要是完成以下四件事情:1. 调用成员函数 updateRootDisplayList 构建参数 view 描述的视图的 Display List, 该视图即为图1所示的 Decor View。2. 调用成员函数 registerAnimatingRenderNode 将保存在参数 attachInfo 指向的一个 AttachInfo 对象的成员变量 mPendingAnimatingRenderNodes

16、描述的一个列表中的 Render Node注册到Native层中去。这些Render Node描述的是当前窗口设置的动画。3. 调用成员函数 nSyncAndDrawFrame 通知 Render Thread 绘制下一帧。4. 如 果 成 员 函 数 nSyncAndDrawFrame 的 返 回 值 syncResult 的 SYNC_INVALIDATE_REQUIRED立不等于 0,就表明 Render Thread 可能需要与 Main Thread 进行信息同步,这时候就时候向Main Thread发送一个INVALIDATE消息,以便Main Thread 可以进行信息同步。这种

17、情况一般发生在当前绘制的一帧包含有同步动画时。例如,同步动 画显示到一半,需要中止,这个中止的操作就是由Main Thread发出的,然后由Render Thread 检测到这个中止操作。这里我们只关注第一件事情,其余三件事情在接下来的两篇文章中再详细分析。ThreadedRenderer 类的成员函数 updateRootDisplayList 的实现如下所示:java view plain copypublic class ThreadedRenderer extends HardwareRenderer private void updateRootDisplayList(View vi

18、ew, HardwareDrawCallbacks callbacks) updateViewTreeDisplayList(view);if (mRootNodeNeedsUpdate | !mRootNode.isValid() HardwareCanvas canvas = mRootNode.start(mSurfaceWidth, mSurfaceHeight); try final int saveCount = canvas.save();canvas.insertReorderBarrier(); canvas.drawRenderNode(view.getDisplayLis

19、t(); canvas.insertInorderBarrier();canvas.restoreToCount(saveCount);mRootNodeNeedsUpdate = false; finally mRootNode.end(canvas);这个函数定义在文件 frameworks/base/core/java/android/view/ThreadedRenderer.java中。ThreadedRenderer 类的成员函数 updateRootDisplayList 通过调用另一个成员函数 updateViewTreeDisplayList来构建参数 view 描述的视图的

20、 Display List,即图 1 中的 Decor View的Display List。构建好的这个Display List可以通过调用参数view描述的视图的成员 函数 getDisplayList 获得的一个 Render Node 来描述。ThreadedRenderer 类的成员变量 mRootNodeNeedsUpdate 是 一个布尔变量,当它的值 等于true的时候,就表示要更新另外一个成员变量mRootNode描述的一个Render Node的 Display List。另外,如果 ThreadedRenderer 类的成员变量 mRootNode 描述的 Render N

21、ode 还未构建过Display List,那么这时候调用它的成员函数isValid的返回值为true,这种情况 也表示要更新它的 Display List。从前面一文可以知道, ThreadedRenderer 类的成员变量 mRootNode 描述的 Render Node即为即为当前窗口的Root Node,更新它的Display List实际上就是要将参数view描述 的视图的Display List记录到它里面去,具体方法如下所示:1. 调用ThreadedRenderer类的成员变量mRootNode描述的Render Node的成员函数 start 获得一个 Hardware C

22、anvas。2. 调用上面获得的Hardware Canvas的成员函数drawRenderNode将参数view描述 的视图的Display List绘制在它里面。在绘制参数view描述的视图的Display List的前后, 会调用 Hardware Canvas 的成员函数 insertReorderBarrier和 insertInorderBarrier分别设置一个 Reorder Barrier 和一个 Inorder Barrier。后面我们在分析Display List 绘制在 Hardware Canvas 的过程时就会看到,插入这些Barrier是为了将一个View的所有的

23、Draw Op及其子View对 应的Draw Op记录在一个Chunk中。其中,Reorder Barrier表明在真正渲染这些Chunck记 录的Draw Op时,需要考虑按照Z轴坐标值重新排列子View的渲染顺序。3. 调用ThreadedRenderer类的成员变量mRootNode描述的Render Node的成员函数 end 取出上述已经绘制好的 Hardware Canvas 的数据,并且作为上述 Render Node 的新的 Display List。接下来,我们首先分析 ThreadedRenderer 类的成员变量 mRootNode 描述的 Render Node的Dis

24、play List的更新过程,即RootNode类的成员函数start、HardwareCanvas类的成 员函数 drawRenderNode 和 RootNode 类的成员函数 end 的实现,然后再回过头来分析参数 view 描 述 的 视 图 的 Display List 的 构 建 过 程 , 即 ThreadedRenderer 类 的 成 员 函 数 updateViewTreeDisplayList 的实现。RootNode类的成员函数start的实现如下所示:java view plain copy public class RenderNode public Hardwar

25、eCanvas start(int width, int height) HardwareCanvas canvas = GLES20RecordingCanvas.obtain(this); canvas.setViewport(width, height);return canvas;这个函数定义在文件 frameworks/base/core/java/android/view/RenderNode.java 中。RootNode 类的成员函数 start 的核心是调用 GLES20RecordingCanvas 类的静态成员 函数 obtain 一个类型为 GLES20Recordin

26、gCanvas 的 Hardware Canvas,然后在设置了该 Hardware Canvas 的 View Port 之后,返回给调用者。GLES20RecordingCanvas类的静态成员函数obtain的实现如下所示:java view plain copyjava view plain copyclass GLES20RecordingCanvas extends GLES20Canvas private static final int POOL_LIMIT = 25;private static final SynchronizedPool sPool = new Synch

27、ronizedPool(POOL_LIMIT);RenderNode mNode;private GLES20RecordingCanvas() super();static GLES20RecordingCanvas obtain(NonNull RenderNode node) GLES20RecordingCanvas canvas = sPool.acquire();if (canvas = null) canvas = new GLES20RecordingCanvas();canvas.mNode = node;return canvas;这个函数定义在文件 frameworks/

28、base/core/java/android/view/GLES20RecordingCanvas.java 中。GLES20RecordingCanvas 类 的 静 态 成 员 函 数 obtain 首 先 是 从 一 个 GLES20RecordingCanvas对象池中请求一个GLES20RecordingCanvas对象。如果获取失败, 再直接创建一个 GLES20RecordingCanvas 对象。在将获取到的 GLES20RecordingCanvas 对 象返回给调用者之前,还会将参数node描述的Render Node保存在其成员变量mNode中。接 下 来 我 们 继 续

29、 关 注 GLES20RecordingCanvas 对 象 的 创 建 过 程 , 即 GLES20RecordingCanvas类的构造函数的实现。GLES20RecordingCanvas类的构造函数只是 简单调用了父类GLES20Canvas的构造函数,它的实现如下所示:java view plain copy 在 CODE 上查看代码片派生到我的代码片class GLES20Canvas extends HardwareCanvas protected long mRenderer;protected GLES20Canvas() mRenderer = nCreateDisplay

30、ListRenderer();这个函数定义在文件 frameworks/base/core/java/android/view/GLES20Canvas.java 中。GLES20Canvas 类的构造函数最主要做的事情就是调用另外一个成员函数 nCreateDisplayListRenderer 在 Native 层创建了一个 Display List Renderer,并且将它的地址保 存在成员变量 mRenderer 中。GLES20Canvas 类的成员函数 nCreateDisplayListRenderer 是一个 JNI 函数,由 Native 层的函数 android_view

31、_GLES20Canvas_createDisplayListRenderer 实现,如下所示:cpp view plain copy 在 CODE 上查看代码片派生到我的代码片static jlong android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env, jobject clazz) return reinterpret_cast(new DisplayListRenderer);这个函数定义在文件 frameworks/base/core/jni/android_view_GLES20Canvas.cpp 中。 从

32、这里就可以看到,函数 android_view_GLES20Canvas_createDisplayListRenderer 创 建了一个DisplayListRenderer对象之后,就将它的地址返回给调用者。从上面分析的过程就可以知道,调用 RenderNode 类的成员函数 start 获得的一个 Hardware Canvas 的具体类型为 GLES20RecordingCanvas,它通过父类 GLES20Canvas 在 Native 层创建了一个 DisplayListRenderer 对象。因此当我们调用上述Hardware Canvas的成员函数drawRenderNode绘

33、制一个Display List时,调用的实际上是GLES20RecordingCanvas类的成员函数drawRenderNode,不过这 个成员函数是从其父类GLES20Canvas继承下来的,它的实现如下:java view plain copy 在 CODE 上查看代码片派生到我的代码片 class GLES20Canvas extends HardwareCanvas Overridepublic int drawRenderNode(RenderNode renderNode, Rect dirty, int flags) return nDrawRenderNode(mRender

34、er, renderNode.getNativeDisplayList(), dirty, flags); 这个函数定义在文件 frameworks/base/core/java/android/view/GLES20Canvas.java 中。GLES20Canvas类的成员函数drawRenderNode首先是调用参数renderNode指向的一 个 RenderNode 对象的成员函数 getNativeDisplayList 获得其在 Native 层对应的 Display List, 接着再调用另外一个成员函数nDrawRenderNode将获得的Native Display Lis

35、t通过成员变量 mRenderer描述的一个在Native层的 Display List Renderer绘制在当前的 GLES20 Canvas 中。 Native层的Display List实际上是通过Native层的Render Node来描述的。GLES20Canvas类的成员函数nDrawRenderNode是一个JNI函数,由Native层的函 数 android_view_GLES20Canvas_drawRenderNode 实现,如下所示:cpp view plain copy 在 CODE 上查看代码片派生到我的代码片 static jint android_view_GL

36、ES20Canvas_drawRenderNode(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong renderNodePtr, jobject dirty, jint flags) DisplayListRenderer* renderer = reinterpret_cast(rendererPtr); RenderNode* renderNode = reinterpret_cast(renderNodePtr); android:uirenderer:Rect bounds;status_t status = renderer-

37、drawRenderNode(renderNode, bounds, flags);return status;这个函数定义在文件 frameworks/base/core/jni/android_view_GLES20Canvas.cpp 中。 由前面的分析可以知道,参数rendererPtr和renderNodePtr描述的分别是Native层的一个 DisplayListRenderer 和 RenderNode 对象, 现在要做的事情就是将参数 renderNodePtr 描述的 Render Node 绘制在参数 rendererPtr 的 Display List Renderer

38、 的内部,这是通过调用 DisplayListRenderer 类的成员函数 drawRenderNode 实现的。DisplayListRenderer 类的成员函数 drawRenderNode 的实现如下所示:cpp view plain copy 在 CODE 上查看代码片派生到我的代码片status_t DisplayListRenderer:drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t flags) / dirty is an out parameter and should not be recorded,

39、/ it matters only when replaying the display listDrawRenderNodeOp* op = new (alloc() DrawRenderNodeOp(renderNode, flags, *currentTransform();addRenderNodeOp(op);return DrawGlInfo:kStatusDone;这个函数定义在文件 frameworks/base/libs/hwui/DisplayListRenderer.cpp 中。DisplayListRenderer 类的成员函数 drawRenderNode 首先是将参

40、数 renderNode 描述的 Render Node 封 装 成 一个 DrawRenderNodeOp ,然 后 再通 过 调用 另外 一个成 员 函数 addRenderNode 将上述 DrawRenderNodeOp 记录在内部维护的 Display List Data 中。DisplayListRenderer 类的成员函数 addRenderNodeOp 的实现如下所示:cpp view plain copy 在 CODE 上查看代码片派生到我的代码片 size_t DisplayListRenderer:addRenderNodeOp(DrawRenderNodeOp* op

41、) int opIndex = addDrawOp(op);int childIndex = mDisplayListData-addChild(op);/ update the chunks child indicesDisplayListData:Chunk& chunk = mDisplayListData-chunks.editTop(); chunk.endChildIndex = childIndex + 1;if (op-renderNode()-stagingProperties().isProjectionReceiver() / use staging property,

42、since recording on UI thread mDisplayListData-projectionReceiveIndex = opIndex;return opIndex;这个函数定义在文件 frameworks/base/libs/hwui/DisplayListRenderer.cpp 中。DisplayListRenderer 类 有一 个 成 员变 量 mDisplayListData , 它 指 向 的 是一 个 DisplayListData 对象,用来记录当前正在处理的 DisplayListRenderer 对应的 Render Node 的 绘制命令。Disp

43、layListData类通过三个向量来记录一个Render Node的绘制命令,如图2所示:这三个向量分别是一个Display List Op Vector、Chunk Vector和 Draw Render Node Op Vector, 其中:1. Display List Op Vector包含了一个Render Node的所有绘制命令,每一个绘制命 令用一个 Display List Op 来描述。2. Draw Render Node Op Vector包含了一个 Render Node 的所有子 Render Node,相 当于包含了一个View的所有子View绘制命令,每一个子V

44、iew绘制命令用一个Draw Render Node Op 来描述。3. Chunk Vector将一个 Render Node 的所有 Display List Op 和 Draw Render Node Op 划分成为 Chunk 来管理。一个 Chunk 通过一个 begin op index 和一个 end op index 来记录一 组 Display List Op,并且通过begin child index和 end child index来记录一组Draw Render Node Op。在渲染一个Render Node的时候,是按照Chunk Vector保存的Chunk顺序来

45、渲染所 有的 Display List Op 和 Draw Render Node Op 的。前面提到,Draw Render Node Op 描述的 是一个View的子View绘制命令。子View的Z轴坐标有可能是负的,这意味着子View要 先于父 View 绘制。因此在渲染一个 Chunk 对应的 Display List Op 和 Draw Render Node Op 之前,需要对Draw Render Node Op按照其对应的子View的Z轴坐标由小到大进行排序。 排序完成之后,先渲染Z轴坐标为负的Draw Render Node Op,接着再渲染Display List Op,

46、最后渲染 Z 轴坐标为 0 或者正数的 Draw Render Node Op。从上面的分析就可以推断出,Chunk的存在意义就是将一个View自身的绘制命令及 其子 View 绘制命令组织在一起。这样在渲染一个 View 的 UI 时,就可以很容易地处理子 View的Z轴坐标为负数的情况。这同时也意味着在构建一个View的Display List的时候, 记录的绘制命令有可能是乱序的。这就要求在渲染这些绘制命令的时候,需要对它们按照Z 轴坐标进行排序。有了上述 的背景知识 之后,我 们再 来看 DisplayListRenderer 类的 成员函数 addRenderNodeOp 的实现,它

47、在向成员变量 mDisplayListData 描述的一个 Display List Data 添加一个 Draw Render Node Op 时,需要操作该 Display List Data 里面的三个 Vector。其中,Display List Op 和 Chunk 这两个 Vector 的操作是通过调用 DisplayListRenderer 类的成员函数 addDrawOp 来实现的,如下所示cpp view plain copy 在 CODE 上查看代码片派生到我的代码片size_t DisplayListRenderer:addDrawOp(DrawOp* op) Rect

48、localBounds;if (op-getLocalBounds(localBounds) bool rejected = quickRejectConservative(localBounds.left, localBounds.top, localBounds.right, localBounds.bottom);op-setQuickRejected(rejected);mDisplayListData-hasDrawOps = true;return flushAndAddOp(op);这个函数定义在文件 frameworks/base/libs/hwui/DisplayListRe

49、nderer.cpp 中。DisplayListRenderer 类的成员函数 addDrawOp 首先是判断要添加到 Display List Data去的Draw Op是否设置了绘制区间。如果设置了,就再调用DisplayListRenderer类从 父类StatefulBaseRenderer继承下来的成员函数quickRejectConservative判断该绘制区间是否 不在当前正在处理的 DisplayListRenderer 对象的裁剪区间之内。如果不在,就将该 Draw Op 设置为Quick Rejected,也就是意味着该Draw Op无需要渲染。DisplayListRe

50、nderer 类的成员 函数 addDrawOp 最后调用 另外一个成员 函 数 flushAndAddOp 将参数 op 描述的 DrawOp 添加到成员变量 mDisplayListData 描述的一个 Display List Data的Display List Op Vector中,并且修改对应的Chunk的信息,如下所示:cpp view plain copy 在 CODE 上查看代码片派生到我的代码片 size_t DisplayListRenderer:flushAndAddOp(DisplayListOp* op) flushRestoreToCount();flushTran

51、slate();return addOpAndUpdateChunk(op);这个函数定义在文件 frameworks/base/libs/hwui/DisplayListRenderer.cpp 中。DisplayListRenderer 类 的 成 员 函 数 flushAndAddOp 首 先 是 调 用 成 员 函 数 flushRestoreToCount和 flushTranslate之前是否对当前正在处理的DisplayListRenderer对象对 应的Hardware Canvas调用过成员函数restoreToCount和translate。如果有,并且还没将它们 转化为相

52、应的 Draw Op 记录在 Display List Data 中,那么现在就是时候将它们转化为相应的 Draw Op 记录在 Display List Data 中了。DisplayListRenderer 类的成员函数 flushAndAddOp 最后调用另外一个成员函数 addOpAndUpdateChunk来处理参数op描述的DisplayListOp,如下所示:cpp view plain copy 在 CODE 上查看代码片派生到我的代码片size_t DisplayListRenderer:addOpAndUpdateChunk(DisplayListOp* op) int i

53、nsertIndex = mDisplayListData-displayListOps.add(op);if (mDeferredBarrierType != kBarrier_None) / op is first in new chunkmDisplayListData-chunks.push();DisplayListData:Chunk& newChunk = mDisplayListData-chunks.editTop(); newChunk.beginOpIndex = insertIndex;newChunk.endOpIndex = insertIndex + 1;newC

54、hunk.reorderChildren = (mDeferredBarrierType = kBarrier_OutOfOrder);int nextChildIndex = mDisplayListData-children().size();newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex; mDeferredBarrierType = kBarrier_None; else / standard case - append to existing chunk mDisplayListData-chunk

55、s.editTop().endOpIndex = insertIndex + 1;return insertIndex;这个函数定义在文件 frameworks/base/libs/hwui/DisplayListRenderer.cpp 中。从这里就可以看到, DisplayListRenderer 类的成员函数 flushAndAddOp 首先是将参 数 op 描述的 DisplayListOp 添加到成员变量 mDisplayListData 描述的一个 Display List Data 的Display List Op Vector中,接下来再修改对应的Chunk的信息。如 果 Di

56、splayListRenderer 类 的 成 员 变 量 mDeferredBarrierType 的 值 不 等 于 kBarrier_None,那么要将参数op描述的DisplayListOp记录在一个新的Chunk中。在这种 情况下,DisplayListRenderer 类的成员函数 flushAndAddOp 就会在成员变量 mDisplayListData 描述的一个Display List Data的Chunk Vector中增加一个新的Chunk,并且相应地修改该 Chunk 的 成 员 变 量 beginOpIndex 、 endOpIndex 、 beginChildIn

57、dex 、 endChildIndex 和 reorderChildren。其中,Chunk 类的成员变量 beginOpIndex、endOpIndex、beginChildIndex 和 endChildIndex 的含义可以参考图 2 所示的 begin op index、 end op index、 begin child index 和end child index。另外,Chunk类的成员变量reorderChildren表示一个Chunk包含的Draw Render Node Op 在渲染的时候是否需要排序。回忆前面分析的ThreadedRenderer类的成员函数updateR

58、ootDisplayList,它将应用 程序窗口的 Decor View 的 Display List 绘制在 Root Render Node 的 Hardware Canvas 的前后, 会分别调用该Hardware Canvas 的成员函数insertReorderBarrier和 insertInorderBarrier分别设 置一个 Reorder Barrier 和一个 Inorder Barrier。设置 Reorder Barrier 和 Inorder Barrier 就相当 于将 Hardware Canvas 对应的 DisplayListRenderer 对象的成员变量

59、 mDeferredBarrierType 设 置为 kBarrier_OutOfOrder 和 kBarrier_InOrder。因此,我们就可以看出,Reorder Barrier和Inorder Barrier的设置是发生在将一个 子 View 的 Display List 绘制在父 View 的 Hardware Canvas 的前后的,作用就是为了能够在 父 View 对应的 DisplayListRenderer 对象按 Chunk 来管理绘制命令。同样的,如果我们去分 析ViewGroup的Display List的构建过程,就会发现在将一个ViewGroup的子View的Dis

60、play List 绘制在该 ViewGroup 对应的 Hardware Canvas 的前后,也会分别在该 Hardware Canvas 上设置一个 Reorder Barrier 和一个 Inorder Barriero最后,如果 DisplayListRenderer 类的成员变量 mDeferredBarrierType 的值等于 kBarrier_None,那么就说明参数op描述的DisplayListOp与前面已经添加的DisplayListOp 是位于同一个Chunk中的,因此这时候就不需要往成员变量mDisplayListData描述的一个 Display List Dat

61、a的Chunk Vector增中一个新的Chunk,而只需要修改保存在Chunk Vector 的最后一个Chunk的成员变量endOpIndex即可。这一步执行完成之后,回到DisplayListRenderer类的成员函数addRenderNodeOp中, 这时候参数op描述DrawRenderNodeOp就添加到成员变量mDisplayListData描述的Display List Data的Display List Op Vector中去了,并且对应的Chunk信息也已经设置好,接下来要 做的事情就是再将该DrawRenderNodeOp添加到成员变量mDisplayListData描

62、述的Display List Data 的 Draw Render Node Op Vector中去。本来DisplayListRenderer类的成员函数addRenderNodeOp执行到这里,就已经完成 任务了。但是在 Android 5.0 中,增加了一个新的 APIRippleDrawable。 RippleDrawable 有一个属性,当它没有包含任何的 Layer 时,它将被投影到当前视图的设置有 Background 的最近的一个父视图的 Background 去。这一点可以参考官方文档:。为了达到上述目的,每一个Render Node都具有三个属性:Projection Re

63、ceive Index、 Projection Receiver 和 Projection Backwardso 其中,Projection Receive Index 是一 个整型变量, 而 Projection Receiver 和 Projection Backwards 是两个布尔变量。注意,在一个应用程序窗口 的视图结构中,每一个View及其设置的Background都对应一个Render Node。上述三个属 性构成了 Render Node里面的一个Projection Nodes的概念,如图3所示:TE13 Proiectirin NodesViBl:nfl fttCEwra*

64、 IndK D-阴也:rmrndDti七出色会PgeSiM铳咖刃蛮Trw rPrqecticriiReceSer TruePrqecticxi Bacardfe Fatse Prqetion Receflier TruePj*呵口ERetfnErlndec 0駅抽5自 R tkg fqu nd言 ejv H 口 4lf-fqKtiMi Badcwnncte True 就qgicn Rpcrncr: TruePeniErReeuver ind&e 0BaclrcKind Drawable-3view?PrqeEtion fiaeswinfc F$e PqertionHerewer TruePtfeeLiCn Reefrvtir8 i “dec 0 Rrqectround图3 示意的是一个应用

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!