Android Graphics 显示系统 - 计算FPS的原理与探秘Present Fence

news2025/1/16 7:55:53

“ 最近忙着新房子装修的事情,这篇计划内的文章拖了好久一直没有足够的时间来写作,终于挤出些儿时间来继续研究学习了。

整了四个晚上终于拼凑出一篇文章,虽说是讲FPS计算原理,但该文涉及的知识点还是蛮多的,特别是对于present fence的来龙去脉重点做了分析,还牵涉到一些合成&HWC的逻辑。全文5000多字,内容丰满。一个业余爱好者的拙劣认知,请大家审慎阅读!

01

前言

FPS即Frames Per Second,表示每秒显示的帧数。作为衡量UI流畅度、视频播放性能、游戏性能的基础指标,开发者通常会观察FPS来评价应用是否有掉帧/卡顿等性能问题。前面我们分享了两篇计算FPS的文章:

Android Graphics 显示系统 - 监测、计算FPS的工具及设计分析

Android Graphics 显示系统 - 通过dumpsys SurfaceFlinger --latency计算FPS

那这些方法计算FPS的原理是什么呢?本篇我们就着手探索下利用dumpsys SurfaceFlinger --latency计算FPS的原理

02

Fence的概念

在介绍FPS计算原理前,需要先理解Android中Fence的概念。在前面的文章中我们有对Fence做过讲解,这里我们就简略赘述。

Android Graphics 显示系统 - GraphicBuffer同步机制-Fence(二十)

Fence是什么呢?

Fence,直译为“栅栏”,用来把某个东西拦截住。顾名思义,它是一种同步机制:把东西拦截住,又在合适的时机放行,达到同步的效果。

CPU、GPU、HWC是异步工作的,所以需要Fence这种同步机制来协调他们的工作。

那么Fence要拦住什么东西呢?

就是GraphicBuffer。GraphicBuffer中存放了应用绘制好的待要显示的数据,GraphicBuffer在整个绘制、合成、显示的过程中一直在 CPU、GPU 和 HWC 之前传递,某一方要使用GraphicBuffer之前,需要先检查上一个使用者是否已经移交了GraphicBuffer的“使用权”。而这里的“使用权”,就是Fence。当Fence 释放(即signal)的时候,说明GraphicBuffer的上一个使用者已经交出了使用权,此时对于GraphicBuffer 进行操作(read or write)是安全的。

Android中有哪些Fence呢?

在Android里面,总共有3类Fence:

  • acquire fence

    生产者(App)将GraphicBuffer通过queueBuffer()还给BufferQueue的时候,此时异步工作的GPU可能还没有完成绘制,此时会带上一个Fence,这个 Fence就是acquire fence。当消费者(SurfaceFlinger/HWC)要读取GraphicBuffer以进行合成操作的时候,需要等acquire fence释放之后才行。

    acquire fence就是生产者用来告诉消费者生产数据完成的同步信号!

  • release fence

    当生产者(App)通过dequeueBuffer()从BufferQueue申请到一块GraphicBuffer,要对GraphicBuffer进行绘制(写操作)的时候,需要保证消费者(上一个使用者)已经不再使用这个GraphicBuffer了,即需要等release fence signal才能对这块GraphicBuffer进行写操作。

    acquire fence就是消费者用来告诉生产者Buffer中的数据我已消费完毕的信号!

  • present fence 

    当前帧成功显示到屏幕的时候,present fence就会signal。

解释比较简略,建议大家阅读Android官网的英文解读,从不同角度并结合API理解

https://source.android.com/docs/core/graphics/sync

图片

03

计算Layer FPS的方法

计算Layer FPS的方法我们前面提供了两种方法,本篇我们主要分析利用dumpsys命令计算FPS的原理:

dumpsys SurfaceFlinger --latency Layer-name

让我们看看这条命令执行后会输出什么内容呢?

以播放Youtube视频时抓取信息为例:

首先,看看当前可见图层的状况

$ adb shell dumpsys SurfaceFlinger --hwclayers
Display 4629995505126966272 (active) HWC layers:
---------------------------------------------------------------------------------------------------------------------------------------------------------------
 Layer name
           Z |  Window Type |  Comp Type |  Transform |   Disp Frame (LTRB) |          Source Crop (LTRB) |     Frame Rate (Explicit) (Seamlessness) [Focused]
---------------------------------------------------------------------------------------------------------------------------------------------------------------
 SurfaceView[com.google.android.youtu[...].tv.activity.MainActivity](BLAST)#99
  rel      0 |            0 |     DEVICE |          0 |    0    0 1920 1080 |    0.0    0.0 1920.0 1080.0 |                                              [*]
---------------------------------------------------------------------------------------------------------------------------------------------------------------
 com.google.android.youtube.tv/com.go[...].youtube.tv.activity.MainActivity#96
  rel      0 |            1 |     CLIENT |          0 |    0    0 1920 1080 |    0.0    0.0 1920.0 1080.0 |                                              [*]
---------------------------------------------------------------------------------------------------------------------------------------------------------------

可知,Youtube播放时是有一个SurfaceView来显示video画面的,我们要监测的图层也是这个SurfaceView,它的id是#99

然后要获取这个layer的完整名字

$ adb shell dumpsys SurfaceFlinger --list
Display 0 name="Built-in Screen"#3

63cfece ActivityRecordInputSink com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity#102
ActivityRecord{eef71ef u0 com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity#94
e145d51 com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity#95
Background for SurfaceView[com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity]#100
SurfaceView[com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity]#98
SurfaceView[com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity](BLAST)#99

最后执行dumpsys SurfaceFlinger --latency看看到底会输出什么内容:

$ adb shell dumpsys SurfaceFlinger --latency "SurfaceView[com.google.android.youtube.tv/com.google.android.apps.youtube.tv.activity.MainActivity]\(BLAST\)#99"
16683294
6870189659137   6870202006496   6870189659137
6870206342431   6870218689941   6870206342431
6870223025725   6870235371015   6870223025725
6870239709019   6870252064348   6870239709019
6870256392313   6870268737385   6870256392313
6870273075607   6870285421718   6870273075607
6870289758901   6870302111163   6870289758901
6870306442195   6870318792718   6870306442195
6870323125489   6870335474904   6870323125489
6870339808783   6870352160978   6870339808783
6870356492077   6870368841496   6870356492077
6870373175371   6870385524422   6870373175371
......

一坨一坨的数字到底是啥意思呢?

  • 第一行的数字

    代表当前的VSYNC间隔,单位是纳秒。例如现在的屏幕刷新率是60Hz的,因此就是16.6ms

  • 后面 3列127行 的数字

    每一行有 3 个数字,每个数字都是时间戳,单位是纳秒,分别表示 desiredPresentTime,actualPresentTime,frameReadyTime,在计算FPS的时候,使用的是第二个时间戳。

actualPresentTime就是present fence signal的时间,根据获取的这127个actualPresentTime数据,就可以计算一秒内有多少个present fence signal了,也即多少帧刷新到屏幕了。

计算公式

更多信息阅读原文

Android Graphics 显示系统 - 计算FPS的原理与探秘Present Fence

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

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

相关文章

webpack的loader机制

webpack的loader机制 loader本质上就是导出函数的JavaScript模块。导出的函数,可以用来实现内容的转换。 /* * param{string|Buffer} content 源文件的内容 * param{object} [map] SourceMap数据 * param{any} [meta] meta数据,可以是任何数据 * */ fu…

黑马头条vue2.0项目实战(五)——首页—频道编辑

目录 1. 使用页面弹出层 1.1 页面弹出层简单使用 1.2 创建频道编辑组件 1.3 页面布局 2. 展示我的频道 3. 展示推荐频道列表 3.1 获取所有频道 3.2 处理展示推荐频道 4. 添加频道 5. 编辑频道 5.1 处理编辑状态 5.2 切换频道 5.3 让激活频道高亮 5.4 删除频道 6.…

K8S Docker搭建RocketMQ Dledger高可用集群

本篇文章回顾在华润基于K8S和Docker云设施搭建初步高可用具备failover的RocketMQ集群。RocketMQ版本是5.0.0。 目前现状 采用Dledger模式部署集群,3台namesrv,3台broker,namesrv每台1g的Docker部署,broker每台2g的Docker部署。测…

Hyper-V创建虚拟机安装OpenEulerOS

文章目录 下载OpenEulerHyper-V创建虚拟机 下载OpenEuler 进入官网下载,我选择的是 openEuler 24.03 LTS ,选择第一个版本即可: Hyper-V创建虚拟机 点击新建->虚拟机: 点击下一步: 输入虚拟机名称&#xff0c…

AMD Product Specifications - AMD 产品规格汇总

AMD Product Specifications - AMD 产品规格汇总 1. Desktop, Laptop and Workstation Processor Specifications (台式处理器、笔记本电脑处理器和工作站处理器规格)2. Server Processor Specifications (服务器处理器规格)3. Embedded Processor Specifications (嵌入式处理器…

element-ui表格1.0.0.1,表格的属性

前言:基于vue2element-ui的理论转实践的使用 第一组:数据显示 利用v-bind:data在table绑定数据源,将数据利用prop的属性传入到table-column,渲染到表格中 正片开始 首先,常用的属性(作者常用&#xff09…

书生大模型_InternLM + LlamaIndex RAG 实践

1.任务要求 基于 LlamaIndex 构建自己的 RAG 知识库,寻找一个问题 A 在使用 LlamaIndex 之前InternLM2-Chat-1.8B模型不会回答,借助 LlamaIndex 后 InternLM2-Chat-1.8B 模型具备回答 A 的能力,截图保存。 来源: https://github.…

鸿蒙媒体开发【媒体会话-提供方】音频和视频

媒体会话-提供方 介绍 本示例主要展示了媒体会话(媒体提供方)的相关功能,使用ohos.multimedia.avsession等接口实现媒体提供方与媒体播控中心自定义信息的交互功能。 注意: 此示例仅展示媒体提供方的相关功能,如果需…

2024 年华数杯全国大学生数学建模竞赛C 题 老外游中国 完整成品文章分享

最近,“city 不 city”这一网络流行语在外国网红的推动下备受关注。随着我国过境免签政策的落实,越来越多外国游客来到中国,通过网络平台展示他们在华旅行的见闻,这不仅推动了中国旅游业的发展,更是在国际舞台上展现了…

大模型学习笔记 - LLM 解码与部署

LLM 解码与部署 LLM 解码与部署 1. 解码策略 1.1 背景 1.1 贪心搜所1.2 概率采样 1.2 贪心搜所改进 1.2.1 束搜索 (保留前n个高概率的句子,最终选取整体概率高的生成)1.2.2 长度惩罚 (估计生成更长句子)1.2.3 重复惩罚…

stm32入门-----硬件I2C读写MPU6050

目录 前言 一、stm32中I2C库函数介绍(stm32f10x_i2c.h) 1.初始化 2.使能操作 3.生成起始位和结束位标志 4.发送I2C从机地址 5.发送数据和接收数据 6.发送应答位 7.状态检测 二、硬件I2C读取MPU6050 1.电路连线图 2.主要工程文件 3.MPU6050.…

WordPress网站被入侵,劫持收录事件分析

7.15,网站被入侵,但是直到7月17日,我才发现被入侵。 16日,17日正常更新文章,17日查询网站收录数据时,在站长资源平台【流量与关键词】查询上,我发现了比较奇怪的关键词。 乱码关键词排名 起初…

案例分享:如何使用原生的NodeJs下载视频网站上的视频资源到本地生成MP4文件

如何使用原生的NodeJs下载视频网站上的视频资源到本地生成MP4文件 1、当下视频网站的视频资源无法通过常规手段下载的原因2、什么是M3U8是什么视频文件?3、如何下载M3U8文件中的TS文件并在本地合并为MP4文件?3.1 FFmpeg 是什么工具?3.2 安装 FFmpeg 工具3.3 使用 FFmpeg 工具…

每天五分钟深度学习:向量化方式完成逻辑回归模型的参数更新

本文重点 上一节课程中,我们学习了m个样本的前向传播的向量化,我们可以同时完成m个样本的前向传播,也就是m个样本z的计算,然后a的计算。本节课程我们将学习dw和db参数更新的向量化,最终得到整个逻辑回归算法的参数更新的向量化表示。 非向量化的逻辑回归梯度下降算法 如…

学习日志8.4--DHCP攻击防范

目录 DHCP饿死攻击 DHCP Sever仿冒攻击 DHCP攻击防范 DHCP动态主机配置协议,是给主机提供自动获取IP地址等配置信息的服务。在主机对DHCP服务器发送DHCP Discover请求之后,服务器回复offer,主机再回复request,最后服务器回复AC…

uni-app开发打包成H5部署到服务器

1. 点击发行 2. 点击进入manifest.json的h5配置里,根据自己的情况配置一些信息。一定要注意配置 “运行的基础路径”,如果出现空白页面或者静态文件404的情况,可能是因为这个路径没有配置好。 3. 填写域名 4. 点击发行后,控制台后…

如何让左右两个div各占50%,并且高度相同?

如何设置两个div各占一半,并且高度随着内容增加,而且两边div的高度一致呢?默认会发现高度不一致,改用flex就可以了,另外发现传统的table也可以轻易实现。不知道不用flex的话是否可以实现。 方法1(div实现&a…

二分+dp,CF 1993D - Med-imize

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 D - Med-imize 二、解题报告 1、思路分析 对于n < k的情况直接排序就行 对于n > k的情况 最终的序列长度一定是 (n - 1) % k 1 这个序列是原数组的一个子序列 对于该序列的第一个元素&#xff0…

Spring中使用Async进行异步功能开发实战-以大文件上传为例

目录 前言 一、场景再现 1、Event的同步机制 二、性能优化 1、异步支持配置 2、自定义处理线程池扩展 3、将线程池配置类绑定到异步方法 三、总结 前言 在之前的博客中&#xff0c;曾将讲了在SpringBoot中如何使用Event来进行大文件上传的解耦&#xff0c;原文地址&…

算法回忆录(2)

6.输入一个非递减排列的整数数组nums,和一个目标值target。请找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值target,则输出0&#xff0c;0。请设计一个时间复杂度为0(log n)的算法解决此问题。 输入包括两行&#xff0c;第一行输入两个整数&#xff0c…