Android软件渲染流程

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.mzph.cn/pingmian/13846.shtml

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

相关文章

C++ (week4):Linux基础

文章目录 零、Linux简介1.配置环境2.Linux历史3.Linux模型 一、vim二、Linux命令行 (shell命令)1.常用命令与快捷键(1)常用命令①man命令:查看帮助手册 (2)快捷键 2.用户子系统(1)Linux用户(2)用户命令 3.文件子系统命令(1)目录命令1.创建文件:mkdir2.删…

【AI绘画Stable Diffusion】单人LoRA模型训练,打造你的专属模型,新手入门宝典请收藏!

大家好,我是灵魂画师向阳 本期我将教大家如何进行LoRA模型训练,打造你的专属模型,内容比较干,还请耐心看完! 随着AIGC的发展,许多传统工作岗位正逐渐被AI取代。同时,AI变革也在创造前所未有的…

ftp是什么,ftp能做什么,ftp有什么用 -----ftp介绍

大家好,我是风屿,今天开始我会给大家介绍一些关于网络方面的配置以及介绍等等,今天是ftp FTP中文名字叫做文件传输协议,英文名字叫做File Transfer Protocol(简称为ftp) FTP 是因特网网络上历史最悠久的网…

JS 实战 贪吃蛇游戏

一、css 部分 1. 居中 想要开始和暂停两个按钮居中,可以将盒子设置为弹性盒 也可以使用其他方法 【代码】 2. 将父元素设置为相对定位,偏于之后贪吃蛇长长的身子,是以父元素为基点的绝对定位,通过 left 和 top 来控制位置 二、…

富甲美国---沃尔玛创始人山姆·沃尔顿

富甲美国---沃尔玛创始人山姆沃尔顿_山姆沃尔顿是犹太人吗?-CSDN博客文章浏览阅读786次。​1.不断地检讨回顾我们做得好不好或需要改进的,我们从没有对现况满足过。我们会短暂地大肆庆祝成功,然后认真地检讨下次如何能做得更好---不断改进与创新。2我们…

数据挖掘导致直接路径读(direct path read)耗尽了IO

一大早就有喊业务卡的,检查等待事件源头,均为oracle写等待 查看IO负载持续维持在100%繁忙 后台有两个并行rman备份在,停止备份io繁忙没有好转,检查最近ash报告,发现DDTEK ODBC Oracle程序模块占用最高 检查该模块&…

阿里云、百度云和移动云的对象存储横向性能对比

文章目录 前言一、对比测试的方法和标准A. 测试环境的设置 二、对比测试的结果A、阿里云OSS测试结果2.B. 百度云结果C. 移动云结果分析与结论 总结 前言 在企业的数字化转型进程中,我们观察到越来越多的公司将其IT基础设施迁移到云端。随着企业业务的持续运营&…

音视频安卓主板记录仪手持终端定制开发_基于MT6762平台解决方案

音视频安卓主板采用了基于MT6762高性能处理器芯片的设计,其中包括4个主频高达2.0GHz的Cortex-A53核心和4个主频1.5GHz的Cortex-A53高效聚焦核心,可提供无比流畅的体验。搭载Android 12操作系统,系统版本进行了全新的优化,进一步确…

linux 错误记录(三)

这里的内核源码路径: cd /usr/src/linux-headers-5.4.0-150-generic/ 内核版本: $ uname -r 5.4.0-150-generic 错误现象 ./include/uapi/asm-generic/int-ll64.h:12:10: fatal error: asm/bitsperlong.h: No such file or directory 搜索后是有的 …

向上调整建堆与向下调整建堆的时间复杂度 AND TopK问题

目录 前言建堆的时间复杂度TOPK问题总结 前言 本篇旨在介绍使用向上调整建堆与向下调整建堆的时间复杂度. 以及topk问题 博客主页: 酷酷学!!! 感谢关注~ 建堆的时间复杂度 堆排序是一种优于冒泡排序的算法, 那么在进行堆排序之前, 我们需要先创建堆, 为什么说堆排序的是优于…

Backend - postgresSQL DB 存储过程(数据库存储过程)

目录 一、存储过程的特性 (一)作用 (二)特点 (三)编码结构的区别 二、定时执行存储过程 三、2种编码结构 (一)函数结构 1. SQL代码 2. 举例 (1)例1-循…

考场作弊行为自动抓拍分析系统

考场作弊行为自动抓拍分析系统采用了AI神经网络和深度学习算法,考场作弊行为自动抓拍分析系统通过人形检测和骨架勾勒等技术,实时计算判断考生的异常动作行为。通过肢体动作识别技术,系统可以详细分析考生的头部和手部肢体动作,进…

乡村振兴的乡村旅游新模式:挖掘乡村旅游资源,创新旅游开发方式,打造乡村旅游新品牌,助力美丽乡村建设

目录 一、引言 二、乡村旅游资源挖掘 1、自然景观资源 2、人文历史资源 3、农业产业资源 三、旅游开发方式创新 1、多元化旅游产品 2、体验式旅游模式 3、智慧旅游建设 四、乡村旅游新品牌打造 1、品牌定位与策划 2、品牌传播与推广 3、品牌维护与提升 五、助力美…

当代家庭教育杂志社《当代家庭教育》杂志社24年第6期目录

家庭教育资讯 《家庭教育蓝皮书2024:中国家庭养育环境报告》出炉 4 2024年4月至7月北京市将开展“双减”专项行动 5 小学生玩“烟卡”到底该不该禁? 5 家庭教育理论探索 新时代家长家庭教育素养:意涵、关键要素及其培育 周起煌; 6-10 …

轻松上手ClickHouse:ClickHouse入门

引言 在数字化时代,大数据处理和分析已经成为了各行各业不可或缺的一环。而ClickHouse,作为一款高性能的列式数据库管理系统,以其卓越的查询性能和灵活的扩展性,赢得了众多企业和开发者的青睐。本文将带领大家走进ClickHouse的世…

Kubernetes常用命令

目录 一.资源管理办法 1.陈述式资源管理方法 (1)kubernetes 集群管理集群资源的唯一入口是通过相应的方法调用 apiserver 的接口 (2)kubectl 是官方的CLI命令行工具,用于与 apiserver 进行通信,将用户在…

VC++学习(3)——认识MFC框架,新建项目,添加按钮

目录 引出第三讲 MFC框架新建项目Windows搜索【包含内容的搜索】如何加按钮添加成员变量添加成功 添加按钮2杂项 总结 引出 VC学习(3)——认识MFC框架,新建项目,添加按钮 MFC(Microsoft Foundation Classes),是微软公…

零基础小白撸空投攻略:空投流程是什么样的? 如何操作?

在Web3的世界中,空投(Airdrop)是一种常见的营销和推广策略,通过向特定用户群体免费分发代币,项目方希望能够吸引更多的用户和关注。对于许多刚刚接触加密货币和区块链的新手来说,都会疑惑空投的流程究竟是什…

LeetCode-Pow(x, n)【递归 数学】

[TOC](LeetCode-Pow(x, n)【递归 数学】) 题目描述: 实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xn )。 示例 1: 输入:x 2.00000, n 10 输出:1024.00000 示例 2&#xf…

HTML | 在IDEA中配置Tomcat时遇到的一些问题的解决办法

目录 IDEA中没有web文件夹目录 Tomcat在哪里配置服务器 IDEA中没有web文件夹目录 首先说在IDEA中没有web这个文件夹的解决办法 在菜单栏中帮助中点击查找操作搜索添加框架支持(因为我的IDEA会出现无法点击这个操作,所以我对该操作添加了快捷键&#xf…