Android SurfaceFlinger做Layer合成时,如何与HAL层进行交互

news2024/11/17 16:36:44

目录

  • 零、本文讨论问题的范围
  • 一、问题:SurfaceFlinger图层合成选择实现方式的两难
    • 1.1 从OpenGL ES、HWC本身来讲
    • 1.2 以HWC为主导的判断逻辑
  • 二、SurfaceFlinger与HAL层进行交互的具体实现框架
    • 2.1 SurfaceFlinger 调用 OpenGL ES 流程
    • 2.2 FrameBuffer
    • 2.3 SurfaceFlinger 调用 HWC 的流程
  • 三、通过HAL定义,理解上述概念
    • 3.1 hwcomposer.h
    • 3.2 fb.h
    • 3.3 gralloc.h

零、本文讨论问题的范围

Surface 如何被渲染图
上图表示了,Surface 如何被渲染。
借用官网的一段话:“无论开发者使用什么渲染 API,一切内容都会渲染到 Surface 上。Surface 表示缓冲区队列中的生产方,而缓冲区队列通常会被 SurfaceFlinger 消耗。在 Android 平台上创建的每个窗口都由 Surface 提供支持。所有被渲染的可见 Surface 都被 SurfaceFlinger 合成到屏幕。”

本文关注的范围是上图红框中部分,SurfaceFlinger做Layer合成时,如何与HAL层的交互?

一、问题:SurfaceFlinger图层合成选择实现方式的两难

在处理Layer合成时,SurfaceFlinger会与OpenGL ES、HWC进行交互。对于HWC,由于各OEM的实现不一样,所支持的能力也不一样,很难直接用API表示硬件设备支持合成的Layer数量,Layer是否可以进行旋转和混合模式操作,以及对图层定位和硬件合成的限制等。这就导致了SurfaceFlinger作为调用端,很难做决策:根据当前的要合成的Layer数量,数据量大小,我该选择使用OpenGL ES?还是HWC?

1.1 从OpenGL ES、HWC本身来讲

在Android系统中,相对于HWC,OpenGL ES并不很擅长Layer的合成。
因为OpenGL ES主要是为游戏开发和图形渲染而设计的,它并不针对图层合成进行优化。如果使用OpenGL ES进行图层合成,会占用大量的GPU资源,导致应用程序无法使用GPU进行自己的渲染。因此,在需要进行高效图层合成的场景下,HWC更适合使用。

1.2 以HWC为主导的判断逻辑

既然各OEM提供的HWC的能力是不同的,有强、有弱,但Layer合成任务又想优先使用HWC,那么SurfaceFlinger的选择策略就交给HWC判断好了:
SurfaceFlinger根据HWC硬件能力决定使用OpenGL ES还是使用HWC来处理Layer合成任务。

具体逻辑如下:
SurfaceFlinger向HWC提供所有Layer的完整列表,让HWC根据其硬件能力决定如何处理这些Layer。
HWC会为每个Layer标注合成方式,是通过GPU还是通过HWC合成。
SurfaceFlinger负责先把所有注明GPU合成的Layer合成(使用OpenGL ES)到一个输出Buffer,然后把这个输出Buffer和其他注明HWC合成的Layer一起交给HWC,让HWC完成剩余Layer的合成和显示。

二、SurfaceFlinger与HAL层进行交互的具体实现框架

2.1 SurfaceFlinger 调用 OpenGL ES 流程

SurfaceFlinger 与 OpenGL ES
Gralloc 即 Graphics Alloc 图形分配 。 Android 系统在HAL层中提供了一个 Gralloc 模块,封装了对 Framebuffer 的所有访问操作。
Gralloc 模块包含 fb 和 gralloc 两个设备:fb 负责打开内核中的 Framebuffer 、初始化配置,以及提供 post, setSwapInterval 等操作,它是底层显卡的HAL层抽象;gralloc 则管理帧缓冲区的分配和释放,上层应用只能通过 Gralloc 访问 fb。

Android12 的源码中,HAL层头文件定义的路径在:源码根目录/hardware/libhardware/include/hardware/*.h

2.2 FrameBuffer

FrameBuffer 机制模仿显卡的功能,是显卡硬件的抽象,可以将 FrameBuffer 看成是显存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,简单理解就是一段内存。用户应用不停的向这段内存中写入数据,显示控制器不停地从中读取数据并显示出来。

2.3 SurfaceFlinger 调用 HWC 的流程

SurfaceFlinger 与 HWC

三、通过HAL定义,理解上述概念

3.1 hwcomposer.h

上面我们提到HWC会为每个Layer标注合成方式

typedef struct hwc_layer_1 {
	int32_t compositionType;
}

结构体 hwc_layer_1 中,定义了一个 compositionType 变量,表示当前Layer 的合成类型。可选的常量有 HWC_BACKGROUND、HWC_FRAMEBUFFER_TARGET、HWC_FRAMEBUFFER、HWC_OVERLAY、HWC_SIDEBAND、HWC_CURSOR_OVERLAY。
其中:HWC_FRAMEBUFFER,是这么注释的(节选):

     *   Set by the HWC implementation during (*prepare)(), this indicates
     *   that the layer will be drawn into the framebuffer using OpenGL ES.

HWC在准备阶段,可能会将Layer的类型设置成 HWC_FRAMEBUFFER,表示这个Layer会使用OpenGL ES画到 framebuffer 中。
再看 HWC_BACKGROUND

     *   Always set by the caller before calling (*prepare)(), this value
     *   indicates this is a special "background" layer. The only valid field
     *   is backgroundColor.
     *   The HWC can toggle this value to HWC_FRAMEBUFFER to indicate it CANNOT
     *   handle the background color.

总是由调用者在调用(*prepare)()之前设置这个值,表示这是一个特殊的“背景”图层。唯一有效的字段 backgroundColor。HWC可以将此值切换为HWC_FRAMEBUFFER来表示它不能处理背景颜色(HWC处理不了,就只能是用OpenGl ES来处理)。这里的调用者应该就是SurfaceFlinger了。

Hardware Composer 必须支持事件,其中之一是 VSYNC(另一个是支持即插即用 HDMI 的热插拔)

3.2 fb.h

我们抽出几个属性,有个大体印象

typedef struct framebuffer_device_t {
    /* dimensions of the framebuffer in pixels */
    const uint32_t  width;
    const uint32_t  height;

    /* framebuffer pixel format */
    const int       format;

    /* resolution of the framebuffer's display panel in pixel per inch*/
    const float     xdpi;
    const float     ydpi;

    /* framebuffer's display panel refresh rate in frames per second */
    const float     fps;
    ......
}

FrameBuffer设备的属性有:宽高、像素格式、以dip为单位的分辨率、fps。
再看一个方法:

    /*
     * Post <buffer> to the display (display it on the screen)
     * The buffer must have been allocated with the
     *   GRALLOC_USAGE_HW_FB usage flag.
     * buffer must be the same width and height as the display and must NOT
     * be locked.
     *
     * The buffer is shown during the next VSYNC.
     *
     * Returns 0 on success or -errno on error.
     */
    int (*post)(struct framebuffer_device_t* dev, buffer_handle_t buffer);

post函数会将 buffer post到display上,显示在屏幕上。
buffer的宽度要与fb设备宽高一致,不能被锁。
在下一个VSYNC信号到来时,buffer会显示出来。

3.3 gralloc.h

/**
 * Name of the graphics device to open
 */
#define GRALLOC_HARDWARE_GPU0 "gpu0"

看出 gralloc操作的设备就是GPU

enum {
    /* buffer will be used as an OpenGL ES texture */
    GRALLOC_USAGE_HW_TEXTURE            = 0x00000100U,
    /* buffer will be used as an OpenGL ES render target */
    GRALLOC_USAGE_HW_RENDER             = 0x00000200U,
    /* buffer will be used by the 2D hardware blitter */
    GRALLOC_USAGE_HW_2D                 = 0x00000400U,
    /* buffer will be used by the HWComposer HAL module */
    GRALLOC_USAGE_HW_COMPOSER           = 0x00000800U,
    /* buffer will be used with the framebuffer device */
    GRALLOC_USAGE_HW_FB                 = 0x00001000U,
    /* buffer may be used as a cursor */
    GRALLOC_USAGE_CURSOR                = 0x00008000U,
    /* buffer will be used with the HW video encoder */
    GRALLOC_USAGE_HW_VIDEO_ENCODER      = 0x00010000U,
    /* buffer will be written by the HW camera pipeline */
    GRALLOC_USAGE_HW_CAMERA_WRITE       = 0x00020000U,
    /* buffer will be read by the HW camera pipeline */
    GRALLOC_USAGE_HW_CAMERA_READ        = 0x00040000U,
    ......
}

gralloc graphics allocation字面意思图形分配,其实就是开辟一段内存,操作的是GPU那就是显存。
这里定义了一个枚举,为分配出的 buffer 标记了分类,按使用用途分出的类别。
这里有做为 OpenGL ES texture 使用的、被 HWComposer HAL module 使用的、被硬件视频编码器使用的、被摄像头管道写入/读出的。还发现一个有意思的是,GRALLOC_USAGE_CURSOR 光标竟然是单独一种类型的 buffer。

核心方法:

typedef struct alloc_device_t {
    struct hw_device_t common;
    /* 
     * (*alloc)() Allocates a buffer in graphic memory with the requested
     * parameters and returns a buffer_handle_t and the stride in pixels to
     * allow the implementation to satisfy hardware constraints on the width
     * of a pixmap (eg: it may have to be multiple of 8 pixels). 
     * The CALLER TAKES OWNERSHIP of the buffer_handle_t.
     *
     * If format is HAL_PIXEL_FORMAT_YCbCr_420_888, the returned stride must be
     * 0, since the actual strides are available from the android_ycbcr
     * structure.
     * 
     * Returns 0 on success or -errno on error.
     */
    
    int (*alloc)(struct alloc_device_t* dev,
            int w, int h, int format, int usage,
            buffer_handle_t* handle, int* stride);

这个方法就是分配显存,传入参数 宽、高、格式、使用用途。返回 buffer_handle_t、步长。

上述对 HAL层头文件简单浏览,有助于我们对这几个概念有更深的印象。

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

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

相关文章

c语言从入门到实战——数组

数组 前言1. 数组的概念2. 一维数组的创建和初始化2.1 数组创建2.2 数组的初始化2.3 数组的类型 3. 一维数组的使用3.1 数组下标3.2 数组元素的打印3.3 数组的输入 4. 一维数组在内存中的存储5. sizeof计算数组元素个数6. 二维数组的创建6.1 二维数组得概念6.2 二维数组的创建 …

Java集成腾讯云OCR身份证识别接口

一、背景 项目用到身份证识别获取人员信息的功能&#xff0c;于是想到了腾讯云提供这样的API。在整合代码过程都很顺利&#xff0c;利用腾讯云官方SDK很快集成进来。但是在上测试环境部署时有了新的问题&#xff0c;通过Nginx代理后的环境无法访问到目标腾讯云接口&#xff0c;…

buuctf_练[CSCCTF 2019 Qual]FlaskLight

[CSCCTF 2019 Qual]FlaskLight 文章目录 [CSCCTF 2019 Qual]FlaskLight掌握知识解题思路关键paylaod 掌握知识 内置函数的过滤&#xff0c;globals变量的过滤&#xff0c;调用内部变量或函数的OS函数进行命令执行 解题思路 打开题目链接&#xff0c;很明显看标题和内容是fla…

【动态基础】从暴力递归到动态规划

C面经汇总 系列综述&#xff1a; 目的&#xff1a;本系列是个人整理为了秋招和实习面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡背诵量与深入程度。 来源&#xff1a;材料主要源于算法大神&#xff08;左程云&#xff09;教你从暴力递归到动态规划进行的&#xf…

vue实现连接线

效果展示 实现代码 下载插件npm install --save leader-line-vue <template><div class"wrap"><div ref"start" class"start">start</div><div ref"end" class"end">end</div></d…

数据结构时间复杂度(补充)和空间复杂度

Hello&#xff0c;今天事10月27日&#xff0c;距离刚开始写博客已经过去挺久了&#xff0c;我也不知道是什么让我坚持这么久&#xff0c;但是学校的课真的很多&#xff0c;很少有时间多出来再学习&#xff0c;有些科目马上要考试了&#xff0c;我还不知道我呢不能过哈哈哈&…

Django 全局配置 settings 详解

文章目录 1 概述1.1 Django 目录结构 2 常用配置&#xff1a;settings.py2.1 注册 APP&#xff1a;INSTALLED_APPS2.2 模板路径&#xff1a;TEMPLATES2.3 静态文件&#xff1a;STATICFILES_DIRS2.4 数据库&#xff1a;DATABASES2.5 允许访问的主机&#xff1a;ALLOWED_HOSTS 1 …

[SQL开发笔记]UPDATE 语句:更新表中的记录

一、功能描述&#xff1a; UPDATE 语句&#xff1a;用于更新表中的记录 二、UPDATE 语句语法详解&#xff1a; UPDATE 语法 UPDATE table_nameSET column1value1,column2value2,...WHERE some_columnsome_value; 参数说明&#xff1a; 1.table_name&#xff1a;要修改的表…

【Docker】github Actions自动构建

通过github的Actions 实现代码push仓库后自动构建容器并发布到DockerHub. 创建项目 首先我们创建一个项目,这里我就用Vue项目进行演示. npm init vuelatest Actions-demo-swback进去项目&#xff0c;按照提示执行 npm install npm run dev 启动项目. 首先保证项目的正常启动…

DAY36 738.单调递增的数字 + 968.监控二叉树

738.单调递增的数字 题目要求&#xff1a;给定一个非负整数 N&#xff0c;找出小于或等于 N 的最大的整数&#xff0c;同时这个整数需要满足其各个位数上的数字是单调递增。 &#xff08;当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单…

Python机器学习基础(一)---数据集加载的方法

几个数据集加载的方式 鸢尾花练习资源(这个资源有瑕疵&#xff0c;index列和Species 都是带”“的字符串 导致一些加载现实问题&#xff0c;从而验证 还是pandas最好用) "index","Sepal.Length","Sepal.Width","Petal.Length","…

echarts中横向柱状图的数字在条纹上方

实现效果&#xff1a; 数字在条纹的上方 实现方法&#xff1a;这些数字是用新添加一个坐标轴来实现的 直接添加坐标轴数字显示是在条纹的正右边 所以需要配置一下偏移 完整代码 var option {grid: {left: "3%",right: "4%",bottom: "3%",cont…

FreeROTS 任务通知和实操 详解

目录 什么是任务通知&#xff1f; 任务通知值的更新方式 任务通知的优势和劣势 任务通知的优势 任务通知的劣势 任务通知相关 API 函数 1. 发送通知 2. 等待通知 任务通知实操 1. 模拟二值信号量 2. 模拟计数型信号量 3. 模拟事件标志组 4. 模拟消息邮箱 什么是任务…

高防CDN:网络攻防的坚强防线

在当今数字化时代&#xff0c;网络攻击已经成为一种常态&#xff0c;对企业和个人的网络资产构成了严重威胁。为了应对这些风险&#xff0c;高防CDN&#xff08;Content Delivery Network&#xff09;已经崭露头角&#xff0c;它不仅提供内容分发&#xff0c;还整合了强大的网络…

电脑上使用的备忘记事软件哪一款好用点?

生活中充斥着大大小小的任务&#xff0c;如工作方面、学习方面、生活方面等&#xff0c;多种事务掺杂交错在一起非常容易忘记&#xff0c;为避免忘记重要的事情&#xff0c;大家可以借助电脑上好用的备忘录工具来进行记事。 支持在电脑上使用的备忘录软件是比较多的&#xff0…

论文阅读 - Learning Human Interactions with the Influence Model

NIPS01 早期模型 要求知识背景&#xff1a; 似然函数&#xff0c;极大似然估计、HMM、期望最大化 目录 1 Introduction 2 The Facilitator Room 3 T h e I n f l u e n c e M o d e l 3 . 1 ( R e ) i n t r o d u c i n g t h e I n f l u e n c e M o d e l 3 . 2 L e…

SpringCloud Alibaba【三】Gateway

Gateway配置与使用 前言新建gateway子项目pom.xml配置文件启动类访问接口方式 测试拓展 前言 在工作中遇到一种情况&#xff0c;一个父项目中有两个子项目。实际使用时&#xff0c;需要外网可以访问&#xff0c;宝信软件只能将一个端口号发布在外网上&#xff0c;所以需要运用…

多线程---线程安全问题及解决

文章目录 一个线程不安全的案例造成线程不安全的原因抢占式执行多个线程修改同一个变量修改操作不是原子的内存可见性问题指令重排序问题 如何让线程变得安全&#xff1f;加锁volatile 一个线程不安全的案例 题目&#xff1a;有较短时间让变量count从0加到10_0000 解决方案&a…

【AD9361 数字接口CMOS LVDS】A CMOS

〇、综述 本章介绍并行数据端口和串行外设接口&#xff08;SPI&#xff09;&#xff0c;用于在AD9361和BBP之间传输数据和控制/状态信息。 下图显示了这些接口&#xff0c;并提供了AD9361和BBP在宽带无线系统中的使用方式的高级视图。数据接口工作在两种模式之一&#xff1a;标…

LeetCode题:70爬楼梯,126斐波那契数

目录 70&#xff1a;爬楼梯 题目要求&#xff1a; 解题思路&#xff1a;&#xff08;类似斐波那契数&#xff09; 递归解法&#xff1a; 非递归解法&#xff1a; 126&#xff1a;斐波那契数 题目要求&#xff1a; 解题思路&#xff1a; 递归解法&#xff1a; 非递归解…