Android 渲染机制——Display List

2024-06-12 10:18

本文主要是介绍Android 渲染机制——Display List,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Display List


Android 需要把 XML 布局文件转换成 GPU 能够识别并绘制的对象。这个操作是在 DisplayList 的帮助下完成的。DisplayList 持有所有将要交给 GPU 绘制到屏幕上的数据信息。

Display List 是什么?

Display List 是一个缓存绘制命令的 Buffer,Display List 的本质是一个缓冲区,它里面记录了即将要执行的绘制命令序列。

Display List 是视图的基本绘制元素,包含元素原始属性(位置、尺寸、角度、透明度等),对应 Canvas 的 drawXxx()方法。

视图信息传递流程:Canvas(Java API) —> OpenGL(C/C++ Lib) —> 驱动程序 —> GPU。

在硬件加速渲染环境中,Android 应用程序窗口的 UI 渲染是分两步进行的:
  1. 第一步是构建 Display List,发生在应用程序进程的 Main Thread 中。
  2. 第二步是渲染 Display List,发生在应用程序进程的 Render Thread 中。增加 Render Thread 线程,也是为了避免 UI 线程任务过重,用于提高渲染性能。

这些绘制命令最终会转化为 Open GL 命令由 GPU 执行。这意味着我们在调用 Canvas API 绘制 UI 时,实际上只是将 Canvas API 调用及其参数记录在 Display List 中,然后等到下一个 VSYNC 信号到来时,记录在 Display List 里面的绘制命令才会转化为 Open GL 命令由 GPU 执行。

Display List 的构建

Display List 是以视图为单位进行构建的,因此每一个视图都对应有一个 Display List。

Android 应用程序窗口视图是树形结构的,因此它们的 Display List 是从根视图开始构建的,并且子视图的 Display List 包含在父视图的 Display List 中。这意味着根视图的 Display List 包含了 Android 应用程序窗口 UI 所有的绘制命令,因此最后我们只需要对根视图的 Display List 进行渲染即可得到 Android 应用程序窗口的 UI。

Android 应用程序窗口的根视图是虚拟的,抽象为一个 Root Render Node。此外,一个视图如果设置有 Background,那么这个 Background 也会抽象为一个 Background Render Node。Root Render Node、Background Render Node 和其它真实的子视图,除了 TextureView 和软件渲染的子视图之外,都具有 Display List,并且是通过一个称为 Display List Renderer 的对象进行构建的。最后,Root Render Node 的 Display List 被一个称为 Open GL Renderer 的对象进行渲染,就得到 Android 应用程序窗口的UI了。

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

Display List 的使用和优势

在某个 View 第一次需要被渲染时,Display List 会因此被创建,当这个 View 要显示到屏幕上时,我们会执行 GPU 的绘制指令来进行渲染。

如果 View 的属性发生了改变(例如移动位置),我们就仅仅需要 Execute Display List 就够了。

在这里插入图片描述

但是,如果我们修改了 View 中的某些可见组件的内容,那么之前的 DisplayList 就无法继续使用了,我们需要重新创建一个 DisplayList 并重新执行渲染指令更新到屏幕上。

在这里插入图片描述

注意:任何时候 View 中的绘制内容发生变化时,都会需要重新创建 DisplayList,渲染 DisplayList,更新到屏幕上等一系列操作。这个流程的表现性能取决于你的 View 的复杂程度,View 的状态变化以及渲染管道的执行性能。举个例子,假设某个 Button 的大小需要增大到目前的两倍,在增大 Button 大小之前,需要通过父 View 重新计算并摆放其他子 View 的位置。修改 View 的大小会触发整个视图树的重新计算大小的操作。如果是修改 View 的位置则会触发视图树重新计算其他 View 的位置。如果布局很复杂,这就会很容易导致严重的性能问题。

完整过程如下:

在这里插入图片描述

这里总结下,使用 DisplayList 的优势:

  1. 第一个好处是在绘制窗口的下一帧时,若某一个视图的 UI 没有发生变化,那么就不必执行与它相关的 Canvas API,即不用执行它的成员函数 onDraw,而是直接复用上次构建的 Display List 即可。
  2. 第二个好处是在绘制窗口的下一帧时,若某一个视图的 UI 发生了变化,但是只是一些简单属性发生了变化,例如位置和透明度等简单属性,那么也不必重建它的 Display List,而是直接修改上次构建的 Display List 的相关属性即可,这样也可以省去执行它的成员函数 onDraw。

硬件加速条件下,CPU 用于控制复杂绘制逻辑、构建或更新 DisplayList;GPU 用于完成图形计算、渲染 DisplayList。在硬件加速条件下,刷新界面尤其是播放动画时,CPU 只重建或更新必要的 DisplayList,进一步提高渲染效率。实现同样效果,应尽量使用更简单的 DisplayList,从而达到更好的性能(例如:Shape 代替 Bitmap 等)。

总结


  1. Android 需要把 XML 布局文件转换成 GPU 能够识别并绘制的对象。这个操作是在 DisplayList 的帮助下完成的。DisplayList 持有所有将要交给 GPU 绘制到屏幕上的数据信息。

  2. Display List 是一个缓存绘制命令的 Buffer,Display List 的本质是一个缓冲区,它里面记录了即将要执行的绘制命令序列。

  3. Display List 是视图的基本绘制元素,包含元素原始属性(位置、尺寸、角度、透明度等),对应 Canvas 的 drawXxx()方法。

  4. 渲染 Display List,发生在应用程序进程的 Render Thread 中。增加 Render Thread 线程,也是为了避免 UI 线程任务过重,用于提高渲染性能。

  5. Display List 是以视图为单位进行构建的,因此每一个视图都对应有一个 Display List。

  6. 在某个 View 第一次需要被渲染时,Display List 会因此被创建,当这个 View 要显示到屏幕上时,我们会执行 GPU 的绘制指令来进行渲染。

  7. 在绘制窗口的下一帧时,若某一个视图的 UI 没有发生变化,那么就不必执行与它相关的 Canvas API,即不用执行它的成员函数 onDraw,而是直接复用上次构建的 Display List 即可。

  8. 在绘制窗口的下一帧时,若某一个视图的 UI 发生了变化,但是只是一些简单属性发生了变化,例如位置和透明度等简单属性,那么也不必重建它的 Display List,而是直接修改上次构建的 Display List 的相关属性即可,这样也可以省去执行它的成员函数 onDraw。

  9. 硬件加速条件下,CPU 用于控制复杂绘制逻辑、构建或更新 DisplayList;GPU 用于完成图形计算、渲染 DisplayList。


**PS:更多精彩内容,请查看 --> 《Android 性能优化》
**PS:更多精彩内容,请查看 --> 《Android 性能优化》
**PS:更多精彩内容,请查看 --> 《Android 性能优化》

这篇关于Android 渲染机制——Display List的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg

Maven 配置中的 <mirror>绕过 HTTP 阻断机制的方法

《Maven配置中的<mirror>绕过HTTP阻断机制的方法》:本文主要介绍Maven配置中的<mirror>绕过HTTP阻断机制的方法,本文给大家分享问题原因及解决方案,感兴趣的朋友一... 目录一、问题场景:升级 Maven 后构建失败二、解决方案:通过 <mirror> 配置覆盖默认行为1. 配置示

Redis过期删除机制与内存淘汰策略的解析指南

《Redis过期删除机制与内存淘汰策略的解析指南》在使用Redis构建缓存系统时,很多开发者只设置了EXPIRE但却忽略了背后Redis的过期删除机制与内存淘汰策略,下面小编就来和大家详细介绍一下... 目录1、简述2、Redis http://www.chinasem.cn的过期删除策略(Key Expir

Go语言中Recover机制的使用

《Go语言中Recover机制的使用》Go语言的recover机制通过defer函数捕获panic,实现异常恢复与程序稳定性,具有一定的参考价值,感兴趣的可以了解一下... 目录引言Recover 的基本概念基本代码示例简单的 Recover 示例嵌套函数中的 Recover项目场景中的应用Web 服务器中

C#之List集合去重复对象的实现方法

《C#之List集合去重复对象的实现方法》:本文主要介绍C#之List集合去重复对象的实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C# List集合去重复对象方法1、测试数据2、测试数据3、知识点补充总结C# List集合去重复对象方法1、测试数据

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

Jvm sandbox mock机制的实践过程

《Jvmsandboxmock机制的实践过程》:本文主要介绍Jvmsandboxmock机制的实践过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、背景二、定义一个损坏的钟1、 Springboot工程中创建一个Clock类2、 添加一个Controller

Python中合并列表(list)的六种方法小结

《Python中合并列表(list)的六种方法小结》本文主要介绍了Python中合并列表(list)的六种方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录一、直接用 + 合并列表二、用 extend() js方法三、用 zip() 函数交叉合并四、用

Dubbo之SPI机制的实现原理和优势分析

《Dubbo之SPI机制的实现原理和优势分析》:本文主要介绍Dubbo之SPI机制的实现原理和优势,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Dubbo中SPI机制的实现原理和优势JDK 中的 SPI 机制解析Dubbo 中的 SPI 机制解析总结Dubbo中

Java 的 Condition 接口与等待通知机制详解

《Java的Condition接口与等待通知机制详解》在Java并发编程里,实现线程间的协作与同步是极为关键的任务,本文将深入探究Condition接口及其背后的等待通知机制,感兴趣的朋友一起看... 目录一、引言二、Condition 接口概述2.1 基本概念2.2 与 Object 类等待通知方法的区别