Android软件渲染流程

news2024/11/18 11:59:54

Android软件渲染流程

  • 一.渲染流程
    • 1.VSync信号的监听
    • 2.VSync信号触发绘制
  • 二.渲染原理
    • 1.画布的获取
      • 1.1 渲染缓存的初始化
      • 1.2 graphics::Canvas的创建
      • 1.3 graphics::Canvas与渲染缓存的绑定
        • 1.3.1 SkBitmap的初始化
        • 1.3.2 SkiaCanvas与SkBitmap的绑定
        • 1.3.3 SkCanvas的创建
    • 2.矩形的绘制
    • 3.绘制的提交
      • 3.1 图像缓存消费回调
      • 3.2 图像缓存事务的处理
        • 3.2.1 图像缓存与图像缓存事务的绑定
        • 3.2.2 layer_state_t的获取
        • 3.2.3 图像缓存事务的提交
  • 三.总结
    • 1.图像缓存的四种状态
      • 1.1 状态转化的过程
      • 1.2 ANativeWindow_Buffer
    • 2.Canvas的初始化
      • 2.1 概述
      • 2.2 过程
    • 3.软件绘制
    • 4.绘制提交

一.渲染流程

1.VSync信号的监听

    在Android中,App的渲染流程是从ViewRootImpl开始的。在回调Activity的onResume方法后,会调用ViewRootImpl的requestLayout方法触发页面中View的测量与绘制。

    在ViewRootImpl的requestLayout方法中,首先会调用checkThread方法检查当前线程是否为UI线程,如果不是,则抛出异常。接下来会调用scheduleTraversals方法。
0
    在ViewRootImpl的scheduleTraversals方法中,主要做了两件事:

1)向主线程的消息队列发送一个同步信息屏障。

2)提交callbackType类型为CALLBACK_TRAVERSAL的TraversalRunnable。
1

2.VSync信号触发绘制

    当VSync信号到来时,会执行TraversalRunnable的run方法,该方法内部会调用ViewRootImpl的doTraversal方法。
2
    在ViewRootImpl的doTraversal方法中,主要做了两件事:

1)移除主线程消息队列的同步信息屏障。

2)调用performTraversals方法。
3
    在ViewRootImpl的performDraw方法中,会调用draw方法。在ViewRootImpl的draw方法中,如果没有开启硬件渲染,会调用drawSoftware方法。
4
    在ViewRootImpl的drawSoftware方法中,主要做了三件事:

1)调用Surface的lockCanvas方法获取Canvas。

2)调用DecorView的draw方法开始绘制,draw方法内部会递归调用所有View的draw方法。

3)调用Surface的unlockCanvasAndPost方法完成绘制。
5

二.渲染原理

1.画布的获取

    在Surface创建时,会触发Canvas的创建。在Surface的lockCanvas方法中,会对Canvas进行初始化。在Surface的lockCanvas方法中,会调用最终会调用nativeLockCanvas方法。
6
    Surface的nativeLockCanvas方法对应的实现为android_view_Surface的nativeLockCanvas函数。在nativeLockCanvas函数中,主要做了五件事:

1)获取Native层Surface。

2)声明用于渲染的Buffer。

3)使用Surface对用于渲染的Buffer进行赋值与初始化。

4)创建graphics::Canvas,graphics::Canvas是对Native层Canvas的封装。

5)绑定Canvas和Buffer。
7

1.1 渲染缓存的初始化

    在Surface的lock方法中,主要做了四件事:

1)从IGraphicBufferProducer中获取一块内存ANativeWindowBuffer。

2)将ANativeWindowBuffer封装成GraphicBuffer。

3)锁定GraphicBuffer,获取存放绘制数据的虚拟地址的指针,用于后续Canvas的绘制。

4)将GraphicBuffer中的变量赋值到ANativeWindow_Buffer中。ANativeWindow_Buffer是ANativeWindowBuffer对外的屏蔽封装,用于指导Canvas在多大的长宽范围内以什么样的格式进行绘制,并提供提交绘制数据的指针。

8

1.2 graphics::Canvas的创建

    在graphics::Canvas的构造方法中,会调用android_canvas的ACanvas_getNativeHandleFromJava函数,将Native层对应的Canvas转换为ACanvas,并保存到graphics::Canvas的mCanvas字段中。

    ACanvas是对Native层Canvas的代理,ACanvas是一个没有任何方法的结构体,当需要调用Native层Canvas时,会再将ACanvas强转为Canvas。
9
    在ACanvas_getNativeHandleFromJava函数中,主要做了两件事:

1)获取Native层Canvas,实际是SkiaCanvas,SkiaCanvas是对SkCanvas的封装。

2)将Canvas转换为ACanvas。
10

1.3 graphics::Canvas与渲染缓存的绑定

    在graphics::Canvas的setBuffer方法中,会调用android_canvas的ACanvas_setBuffer函数。
11
    在ACanvas_setBuffer函数中,主要做了四件事:
1)声明SkBitmap。SKBitmap是对ANativeWindow_Buffer的封装,SKBitmap会根据ANativeWindow_Buffer的指导,按照指定的大小和格式,向指定的绘制地址写入绘制数据。

2)对SkBitmap进行初始化。

3)通过ACanvas获取Canvas,实际是SkiaCanvas。

4)将SkiaCanvas和SkBitmap绑定。
12

1.3.1 SkBitmap的初始化

    在convert函数中,主要做了三件事:

1)将ANativeWindow_Buffer封装成SkImageInfo。

2)绑定SkImageInfo到SkBitmap中。

3)设置用于存放绘制数据的虚拟地址的指针。
13

1.3.2 SkiaCanvas与SkBitmap的绑定

    在SkiaCanvas的setBitmap方法中,主要做了三件事:

1)将SkBitmap封装成SkCanvas。

2)保存SkCanvas对应的指针。

3)通过SkCanvas指针获取SkCanvas并保存。

14

1.3.3 SkCanvas的创建

    在SkCanvas的构造方法中,主要做了两件事:

1)将SkBitmap封装为SkBitmapDevice。

2)保存SkBitmapDevice。
15

2.矩形的绘制

    在软件绘制过程中,会调用Canvas的drawRect方法。在Canvas的drawRect方法中,会调用nDrawRect方法。
16
    Canvas的nDrawRect方法对应的Native实现为android_graphics_Canvas的drawRect函数。在drawRect函数中,主要做了两件事:

1)获取Native层Canvas。

2)通过Canvas绘制矩形。
17
    在SkiaCanvas的drawRect方法中,会调用SkCanvas的drawRect方法。最终会绘制到SKBitmap上。SKBitmap封装了图像绘制缓冲,实际会绘制到图像缓冲上。
18

3.绘制的提交

    在软件渲染中,当调用Surface的unlockCanvasAndPost方法时,会将渲染好的图像缓冲提交到SurafceFlinger中。

    在Surface的unlockCanvasAndPost方法中,会调用unlockSwCanvasAndPost方法。在Surface的unlockSwCanvasAndPost方法中,又回调用nativeUnlockCanvasAndPost方法。
19
    Surface的nativeUnlockCanvasAndPost方法对应的Native实现为android_view_Surface的nativeUnlockCanvasAndPost函数。在nativeUnlockCanvasAndPost函数中,主要做了四件事:

1)获取Native层Surface。

2)创建graphics::Canvas,graphics::Canvas是对Native层Canvas的封装。

3)解除Canvas与Surface的关联。

4)提交图像缓冲。
20
    在Surface的unlockAndPost方法中,主要做了三件事:

1)解除GraphicBuffer锁定。

2)将渲染完的图像缓冲添加到IGraphicBufferProducer中。

3)清除对GraphicBuffer的引用。
21
    在Surface的queueBuffer方法中,主要做了两件事:

1)获取缓存位置。

2)提交缓存。
22
    通过Surface的初始化流程,可以知道这里Surface的实际类型为BBQSurface,因此IGraphicBufferProducer对应的类型为BBQBufferQueueProducer。

    在BBQBufferQueueProducer的queueBuffer方法中,主要做了四件事:

1)创建FenceTime。

2)创建渲染帧BufferItem。

3)对BufferItem进行初始化设置。

4)通知消费者消费渲染帧。
23

3.1 图像缓存消费回调

    通过Surface的初始化流程,可以知道这里的mCore的类型为BufferQueueCore。BufferQueueCore的IConsumerListener的类型为BufferQueue::ProxyConsumerListener。

    调用BufferQueue::ProxyConsumerListener的onFrameAvailable方法,最终会调用BLASTBufferQueue的onFrameAvailable方法。
24

3.2 图像缓存事务的处理

    在BLASTBufferQueue的onFrameAvailable方法中,如果需要提交本次绘制,会调用acquireNextBufferLocked方法。

    在BLASTBufferQueue中,所有向SurfacaeFlinger的请求都被抽象成了Transaction。通过Transaction,BLASTBufferQueue可以将多次绘制的缓冲进行合并提交。
25
    在BLASTBufferQueue的acquireNextBufferLocked方法中,主要做了四件事:

1)获取渲染帧BufferItem。

2)通过BufferItem获取绘制缓冲GraphicBuffer。

3)设置Transaction的属性。

4)提交本次Transaction到SurfaceFlinger中等待合成。
26

3.2.1 图像缓存与图像缓存事务的绑定

    在Transaction的setBuffer方法中,主要做了三件事:

1)获取layer_state_t,layer_state_t用于保存记录当前Layer的信息。

2)创建BufferData,保存GraphicBuffer。

3)保存BufferData到layer_state_t中。
27

3.2.2 layer_state_t的获取

    在Transaction的getLayerState方法中,主要做了两件事:

1)获取LayerHandle。

2)通过LayerHandle获取ComposerState,通过ComposerState获取layer_state_t。如果layer_state_t不存在(首次获取),则创建一个新的ComposerState并保存,ComposerState内部持有layer_state_t。
28

3.2.3 图像缓存事务的提交

    在Transaction的apply方法中,主要做了三件事:

1)创建ComposeState列表,收集ComposerState,ComposerState中保存了layer_state_t。

2)获取远端服务ISurfaceComposer。

3)提交到远端服务。
29
    ComposerService是一个单例类,持有ISurfaceComposer。ISurfaceComposer是一个Binder类,它的Bp端实现为BpSurfaceComposer,Bn端的最终实现为SurfaceFlinger。
30
    最终会调用SurfaceFlinger的setTransactionState方法,提交本次的图像缓存。

三.总结

1.图像缓存的四种状态

  • 生产消费模型中的图像缓存:ANativeWindowBuffer
  • Surface中管理的图像缓存:GraphicBuffer
  • Surface暴露给Canvas的图像缓存:ANativeWindow_Buffer
  • 提交给消费者处理的图像缓存:BufferItem

1.1 状态转化的过程

    ANativeWindowBuffer是生产消费模型中最原始的图像缓存。在从生产消费模型获取后,为了方便管理,Surface会将ANativeWindowBuffer封装成GraphicBuffer。当需要暴露给Canvas时,Surface会将GraphicBuffer中重要的参数封装成ANativeWindow_Buffer。在绘制完成后,GraphicBuffer会被生产消费模型封装成BufferItem交给消费者处理。

1.2 ANativeWindow_Buffer

    ANativeWindow_Buffer是Surface为了防止外部直接操作图像缓存而对外提供的协议,这个协议规定了要在多长多宽的区域内,按照什么样的格式,向哪一个地址去写入绘制数据。

2.Canvas的初始化

2.1 概述

    Canvas是对Surface提供的图像缓存的抽象封装。

    Surface对Canvas初始化的过程,就是Surface从生产消费模型中为Canvas分配一块图像缓存的过程。一个Surface同一时间只能提供一个图像缓存。

2.2 过程

    在软件绘制中,Java层Canvas对应的Native层结构为SkiaCanvas。

    在从Surface获取到ANativeWindow_Buffer后,ANativeWindow_Buffer会被封装成SkBitmap。SkBitmap会与
SkiaCanvas进行关联。SkiaCanvas会将SkBitmap封装成SkCanvas来进行管理。

3.软件绘制

    软件绘制就是通过Canvas向SkBitmap中写入数据,SkBitmap按照ANativeWindow_Buffer的要求将绘制数据发送到提供存放绘制数据的地址。

4.绘制提交

    绘制提交的本质就是将Canvas与SkBitmap断开,然后将绘制数据提交到生产消费模型中处理,最后有消费者提交到SurfaceFlinger中进行合成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1683757.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Day7:JAVA面向对象的初级使用】

目录 1、类和对象1.1 类的介绍1.2 类和对象的关系1.3 类的组成 2、对象内存图2.1 单个对象内存图2.2 两个对象内存图2.3 两个引用指向相同内存图 3、成员变量和局部变量3.1 成员变量和局部变量的区别 4、this关键字4.1 this可以解决的问题4.2 this介绍4.3 this内存图4.4 this总…

BOM..

区别:

验证码识别插件-captcha-killer

前言 想必大家都会使用burp进行爆破,当遇到带验证码的登录表单进行爆破时,基本尝试抓包后观察验证码是否主动更新,或者进行验证码绕过(我是十八期萌新,听风风说的有这个方法,但我还没学到),机缘巧合下我接触到了captcha-killer这个插件,可以提供给大家第三种爆破思路&#xff…

线程数据共享必学的3个工具类: ThreadLocal InheritableThreadLocal TransmittableThreadLocal

线程数据共享必学的3个工具类: ThreadLocal InheritableThreadLocal TransmittableThreadLocal 1.ThreadLocal:在当前线程中共享数据的,JUC 中提供的 2.InheritableThreadLocal:也是JUC中的一个工具类,解决 ThreadLocal 难以解决的问题 3.Tra…

MPLS原理与配置

1.MPLS概述 (1)传统IP路由转发 (2)MPLS基本概念 ⦁ MPLS起源于IPv4(Internet Protocol version 4),其核心技术可扩展到多种网络协议,包括IPv6(Internet Protocol ver…

WPF中CommandParameter用法

1. 界面样式 2. XAML中代码部分 <ButtonGrid.Row"0"Grid.Column"1"Command"{Binding BtnClick_Number}"CommandParameter"7"Content"7"Style"{StaticResource BtnStyle_Num}" /> <ButtonGrid.Row"…

我的第一个JAVA程序IDEA版

目录 第一步 新建一个空项目第二步 新建模块第三步 新建包第四步 新建类第五步 新建main方法 第一步 新建一个空项目 第二步 新建模块 第三步 新建包 第四步 新建类 然后在包文件夹下新建类 第五步 新建main方法

xlrd.biffh.XLRDError: Excel xlsx file; not supported报错原因

xlrd库读取xlsx文件时报错 xlrd.biffh.XLRDError: Excel xlsx file; not supported报错原因&#xff1a; xlrd版本为2.1版本&#xff0c;需要读取xlsx文件需要安装xlrd低一些版本1.2.0版本&#xff0c;重新安装重试即可 更换xlrd版本 重新运行

如何使用ffmpeg 实现10种特效

相关特效的名字 特效id 特效名 1 向上移动 2 向左移动 3 向下移动 4 颤抖 5 摇摆 6 雨刷 7 弹入 8 弹簧 9 轻微跳动 10 跳动 特效展示(同时汇总相关命令) pad背景显示 pad背景透明 相关命令(一会再讲这些命令&#xff0c;先往下看) # 合成特效语音 ffmpeg -y -loglevel erro…

【Linux】Linux信号产生,接受与处理机制

理解Linux信号产生&#xff0c;接受与处理机制 信号是Linux操作系统中一种用于进程间通信和异步事件处理的机制。在本文中&#xff0c;我们将结合Linux的源码&#xff0c;深入分析信号的产生、发送、接收和处理的底层原理。 文章目录 理解Linux信号产生&#xff0c;接受与处理…

Elasticsearch集群和Logstash、Kibana部署

1、 Elasticsearch集群部署 服务器 安装软件主机名IP地址系统版本配置ElasticsearchElk10.3.145.14centos7.5.18042核4GElasticsearchEs110.3.145.56centos7.5.18042核3GElasticsearchEs210.3.145.57centos7.5.18042核3G 软件版本&#xff1a;elasticsearch-7.13.2.tar.gz 示…

asp.net core接入prometheus

安装prometheus和Grafana 参考之前的文章->安装prometheus和Grafana教程 源代码 dotnet源代码 新建.net core7 web项目 修改Program.cs using Prometheus;namespace PrometheusStu01;public class Program {public static void Main(string[] args){var builder We…

Linux中ftp配置

一、ftp协议 1、端口 ftp默认使用20、21端口 20端口用于建立数据连接 21端口用于建立控制连接 2、ftp数据连接模式 主动模式&#xff1a;服务器主动发起数据连接 被动模式&#xff1a;服务器被动等待数据连接 二、ftp安装 yum install -y vsftpd #---下…

4. Java多线程面试题汇总

Java全栈面试题汇总目录-CSDN博客 1. 为什么要使用并发编程 充分利用多核CPU的计算能力&#xff1a;通过并发编程的形式可以将多核CPU的计算能力发挥到极致&#xff0c;性能得到提升方便进行业务拆分&#xff0c;提升系统并发能力和性能&#xff1a;在特殊的业务场景下&#…

cnpm 安装失败

安装淘宝镜像 //旧 证书已过期 npm config set registry https://registry.npm.taobao.org/ //运行这个会报错 //npm ERR! code CERT_HAS_EXPIRED //npm ERR! errno CERT_HAS_EXPIRED //用下边最新的安装 //新 npm config set registry https://registry.npmmirror.com这里安装…

SSE 与 SASE哪个云原生安全框架更加适合

近年来&#xff0c;随着云计算和网络技术的不断发展&#xff0c;出现了一种新的网络安全解决方案——SASE&#xff08;安全访问服务边缘&#xff09;。SASE是一种将网络和安全功能融合到单个基于云的服务中的框架&#xff0c;旨在提供更加安全、高效和便捷的网络访问体验。SASE…

【机器学习与实现】支持向量机SVM

目录 一、SVM (Support Vector Machine) 概述&#xff08;一&#xff09;支持向量机SVM的主要特点&#xff08;二&#xff09;支持向量与间隔最大化&#xff08;三&#xff09;线性可分/不可分&#xff08;四&#xff09;软间隔 (soft margin) 与核技巧 (kernel trick)&#xf…

web前端学习笔记11

11. CSS3高级特效 11.1 CSS3变形 CSS3变形是一些效果的集合, 如平移、旋转、缩放、倾斜效果 每个效果都可以称为变形(transform),它们可以分别操控元素发生平移、旋转、缩放、倾斜等变化 语法 transform:[transform-function] ; /* 设置变形函数,可以是一个,也可以是多…

vscode插件-07Java

文章目录 Extension Pack for JavaSpring Initializr Java SupportCodeSwingJdk下载JDK安装jdkWindows安装jdkLinux安装jdk&#xff08;以Ubuntu为例&#xff09; jdk环境变量在VScode中配置Windows系统中配置Linux系统中配置&#xff08;以Ubuntu为例&#xff09; Extension P…

arcgis 10.6 工具栏操作error 001143 后台服务器抛出异常

arcgis 10.6 工具栏操作error 001143 后台服务器抛出异常 环境 win10arcgis 10.6 问题 执行定义投影要素转线出现 Error: 001143:后台服务器抛出异常&#xff08;差点重装10.6&#xff09; 如下图所示&#xff1a; 解决方法 通过在菜单工具条上单击地理处理 > 地理处…