Android图形显示系统——下层显示4:图层合成下(硬件合成器)

简介: 硬件合成器-HwComposer使用3D合成,需要大面积的像素混合计算和大量的内存传输(GPU读写GraphicBuffer所需),对GPU和DDR来说是一个巨大的负担。在GPU/DDR重度使用的场景(比如玩游戏),会造成发热、卡顿等。 为了提升性能,减少功耗,可以将合成这个过程交由另一个芯片完成,减轻GPU负担。进一步,直接让这个芯片连LCD,在LCD需要显示某一行时

硬件合成器-HwComposer

使用3D合成,需要大面积的像素混合计算和大量的内存传输(GPU读写GraphicBuffer所需),对GPU和DDR来说是一个巨大的负担。在GPU/DDR重度使用的场景(比如玩游戏),会造成发热、卡顿等。
为了提升性能,减少功耗,可以将合成这个过程交由另一个芯片完成,减轻GPU负担。进一步,直接让这个芯片连LCD,在LCD需要显示某一行时在线合成。
HwComposer便是这一个/多个专用合成芯片的驱动HAL层。
驱动由集成芯片系统的厂商自行设计,但需要遵循一定的标准,这个标准就是Android规定的HwComposer接口。

接口定义

hwcomposer的接口定义位于此文件:
hardware/libhardware/include/hardware/hwcomposer.h
其中部分宏定义在:
hardware/libhardware/include/hardware/hwcomposer_defs.h

Layer

在SurfaceFlinger中,Layer对应于window表示一个Buffer循环体系,对HwComposer而言,Layer仅指代当前Buffer,也即SurfaceFlinger中的Layer的当前帧。

typedef struct hwc_layer_1 {
    int32_t compositionType;//合成类型,SurfaceFlinger将合成目标Framebuffer的合成类型设为HWC_FRAMEBUFFER_TARGET,其他hwcomposer在prepare时根据实际情况修改
    /*
     * HWC_FRAMEBUFFER_TARGET:该Layer是3D合成的目标Layer
     * HWC_FRAMEBUFFER:hwcomposer无法处理此Layer,该Layer需要走3D合成流程,用OpenGL绘制
     * HWC_OVERLAY:该Layer为硬件合成器所处理,不需要OpenGLES去渲染
     * HWC_SIDEBAND:该Layer为视频的边频带,需要硬件合成器作特殊处理,若不支持,OpenGL方式只能以一个色块替代,这个标志是外界(应用/驱动)调用窗口系统的perform方法配置的
     * HWC_CURSOR_OVERLAY:该Layer可通过setCursorPositionAsync 方法改变坐标
     */

    uint32_t hints;//hwcomposer设置,通知SurfaceFlinger需要修改的配置
    /*
    HWC_HINT_TRIPLE_BUFFER  = 0x00000001:表示需要SurfaceFlinger将此Layer改成3Buffer循环
    HWC_HINT_CLEAR_FB       = 0x00000002:要求SurfaceFlinger清空该Layer位置的FrameBuffer数据(即置0)
    */

    uint32_t flags;//SurfaceFlinger设置,hwcomposer作处理
    /*
    HWC_SKIP_LAYER = 0x00000001:此Layer不参与合成,应当忽略
    HWC_IS_CURSOR_LAYER = 0x00000002:此Layer建议设定为一个CURSOR_LAYER,hwcomposer能处理的话将其合成类型改为HWC_CURSOR_OVERLAY
    */

    /*该Layer的颜色/Buffer信息*/
    union {
        hwc_color_t backgroundColor;//背景颜色,适用于纯色Layer,hwc_color_t 为一个 argb 结构体

        struct {
            union {
                buffer_handle_t handle;//此即之间提到的GraphicBuffer
                const native_handle_t* sidebandStream;//HWC_SIDEBAND类型Layer的buffer
            };

            uint32_t transform;//该Layer所需要作的变换,具体为:
            /*
        HWC_TRANSFORM_FLIP_H = HAL_TRANSFORM_FLIP_H//水平翻转
        HWC_TRANSFORM_FLIP_V = HAL_TRANSFORM_FLIP_V//垂直翻转
        HWC_TRANSFORM_ROT_90 = HAL_TRANSFORM_ROT_90,//需要旋转90度
        HWC_TRANSFORM_ROT_180 = HAL_TRANSFORM_ROT_180,//需要旋转180度
        HWC_TRANSFORM_ROT_270 = HAL_TRANSFORM_ROT_270,//需要旋转270度
            */

            int32_t blending;//当前Layer绘制时,和底色/目标色的混合方式
            //HWC_BLENDING_NONE = 0x100:不混合,直接覆盖
            //HWC_BLENDING_PREMULT = 0x105:该Layer的颜色已经做过alpha预乘,因此混合方式为 src + (1-src.a)*dst
            //HWC_BLENDING_COVERAGE = 0x405:该Layer的颜色未做过预乘,按 src.a * src + (1-src.a) * dst 的方式混合

            union {
                // crop rectangle in integer (pre HWC_DEVICE_API_VERSION_1_3)
                hwc_rect_t sourceCropi;
                hwc_rect_t sourceCrop; // just for source compatibility
                // crop rectangle in floats (as of HWC_DEVICE_API_VERSION_1_3)
                hwc_frect_t sourceCropf;
            };//该Layer取哪一个区域进行合成

            hwc_rect_t displayFrame;//该Layer合成的目标区域

            hwc_region_t visibleRegionScreen;//该Layer的可见区域,该区域必然是displayFrame的子集。这个区域由SurfaceFlinger计算而得,用于提示hwcomposer不去合成该Layer的不可见区域,hwcomposer中应当以这个为基准,对应计算该Layer相应的sourcecrop。

            int acquireFenceFd;//由Buffer生产者创建,SurfaceFlinger传递进来,hwcomposer在使用该Layer的Buffer之前,需要等这个fence
            int releaseFenceFd;//由hwcomposer创建,生产者在使用该Buffer之前需要等此fence

            uint8_t planeAlpha;//整个Layer的alpha值,在取Layer的像素作运算之前,需要先乘 planeAlpha/255。

            /* Pad to 32 bits */
            uint8_t _pad[3];//用于结构体对齐,占位用

            hwc_region_t surfaceDamage;//记录相对上一次合成而言,发生了改变的source区域
        };
    };

//保留位,用于驱动层自行设计
#ifdef __LP64__
    uint8_t reserved[120 - 112];
#else
    uint8_t reserved[96 - 84];
#endif

} hwc_layer_1_t;

这里面最难理解和最易出错的是 SourceCrop、DisplayFrame和VisibleRegion,在处理SOC上的显示问题时,这往往是首先考虑的因素:
source_displayframe
如图所示,该Layer的显示区域部分被L2完全挡住,source crop 为该Layer参与合成的范围,display frame 为该Layer合成的目标区域,visibleRegion为该Layer被挡住后,剩余的可见区域集。

看完了这个结构体,上一篇
http://blog.csdn.net/jxt1234and2010/article/details/46057267
所提到的adb shell dumpsys SurfaceFlinger 所得到的表格,各参数表示什么意思自然一下就清楚了。

Display

typedef struct hwc_display_contents_1 {
    /* hwcomposer设置,surfaceflinger去等的fence。对于物理屏(实际上是使用在线合成方式的物理屏),对于虚拟屏/离线合成,此fence在离线合成的目标buffer完成全部写入后解除。
     */
    int retireFenceFd;

    union {
        struct {
            /* HWC_DEVICE_VERSION_1_0 使用,dpy和sur对应于EGLDisplay 和 EGLSurface
             */
            hwc_display_t dpy;
            hwc_surface_t sur;
        };//HWC_DEVICE_VERSION_1_0

        struct {
            /*HWC_DEVICE_VERSION_1_3 之后支持 hwcomposer合成多屏,这里是指虚拟屏的输出buffer和对应的fence*/
            buffer_handle_t outbuf;
            int outbufAcquireFenceFd;
        };
    };

    /*合成该显示屏的所有Layer*/
    uint32_t flags;
    size_t numHwLayers;
    hwc_layer_1_t hwLayers[0];

} hwc_display_contents_1_t;

关于物理显示屏(physical display)和虚拟显示屏(virtual display)

物理显示屏表示连接实际的显示仪器如LCD,目的是产生显示效果,可以使用在线合成。
虚拟显示屏表示目的是合成一个Buffer,不需要理会这个Buffer后续如何产生显示效果,这时需要把所有图层合成到指定的Buffer上。这种情况下必须离线合成。典型场景是手机连WFD/hdmi,手机合成好的Buffer通过wifi/hdmi传输到电视上显示。

Device

最后是device的函数指针定义

typedef struct hwc_composer_device_1 {
    struct hw_device_t common;
    //这种方式相当于C语言的继承实现,理解为 hwc_composer_device_1 继承于 hw_device_t 就可以了。
    //hw_device_t 包含一个基本信息 version(版本号),下面会提到

    /*对所有显示屏中所有Layer作合成准备(此时也可以开始发送合成的命令码下去,启动硬件合成,但不需要等待完成),hwcomposer需要正确汇报每个Layer的composetype,以告知SurfaceFlinger是否需要额外处理。
    version 为 1.0 的驱动,只支持一个显示屏
    version 为 1.1 的驱动,只支持物理显示屏
    version 为 1.3 及以上的驱动,支持物理和虚拟显示屏*/
    int (*prepare)(struct hwc_composer_device_1 *dev,
                    size_t numDisplays, hwc_display_contents_1_t** displays);

    /*此方法将完成各个图层的合成与显示,等效于EGL标准里面的eglSwapBuffers,不过eglSwapBuffers是对OpenGL标准/GPU有效,此方法是对硬件合成器有效*/
    int (*set)(struct hwc_composer_device_1 *dev,
                size_t numDisplays, hwc_display_contents_1_t** displays);

    /*这个接口一般只用于开启hwcomposer的vsync,在线合成触发vsync的机制较离线合成的设计会麻烦一些*/
    int (*eventControl)(struct hwc_composer_device_1* dev, int disp,
            int event, int enabled);

    //控制屏幕状态的方法
    union {
        /* HWC 1.3及之前版本,采用 blank 方式,开关某个显示屏 */
        int (*blank)(struct hwc_composer_device_1* dev, int disp, int blank);

        /* HWC 1.4及之后,提供更精细的 setPowerMode ,支持显示屏以较低功耗(但不关)的状态显示*/
        int (*setPowerMode)(struct hwc_composer_device_1* dev, int disp,
                int mode);
    };

    /*查询Hwcomposer的信息*/
    int (*query)(struct hwc_composer_device_1* dev, int what, int* value);

    /*注册
    *invalidate:屏幕刷新时触发
    *vsync:hwcomopser中的vsync事件产生时触发
    *hotplug:显示屏连接/断开时触发
    * 三个回调函数*/
    void (*registerProcs)(struct hwc_composer_device_1* dev,
            hwc_procs_t const* procs);

    /*打印信息,调试用*/
    void (*dump)(struct hwc_composer_device_1* dev, char *buff, int buff_len);

    /*获取显示屏配置、属性*/
    int (*getDisplayConfigs)(struct hwc_composer_device_1* dev, int disp,
            uint32_t* configs, size_t* numConfigs);
    int (*getDisplayAttributes)(struct hwc_composer_device_1* dev, int disp,
            uint32_t config, const uint32_t* attributes, int32_t* values);
    int (*getActiveConfig)(struct hwc_composer_device_1* dev, int disp);
    /*配置属性,index表示有效属性的编号*/
    int (*setActiveConfig)(struct hwc_composer_device_1* dev, int disp,
            int index);

    /*更改游标层的坐标*/
    int (*setCursorPositionAsync)(struct hwc_composer_device_1 *dev, int disp, int x_pos, int y_pos);

    /*自行添加的保留函数*/
    void* reserved_proc[1];

} hwc_composer_device_1_t;
相关实践学习
在云上部署ChatGLM2-6B大模型(GPU版)
ChatGLM2-6B是由智谱AI及清华KEG实验室于2023年6月发布的中英双语对话开源大模型。通过本实验,可以学习如何配置AIGC开发环境,如何部署ChatGLM2-6B大模型。
目录
相关文章
|
9月前
|
Linux 测试技术 语音技术
【车载Android】模拟Android系统的高负载环境
本文介绍如何将Linux压力测试工具Stress移植到Android系统,用于模拟高负载环境下的CPU、内存、IO和磁盘压力,帮助开发者优化车载Android应用在多任务并发时的性能问题,提升系统稳定性与用户体验。
746 6
|
9月前
|
Java 数据库 Android开发
基于Android的电子记账本系统
本项目研究开发一款基于Java与Android平台的开源电子记账系统,采用SQLite数据库和Gradle工具,实现高效、安全、便捷的个人财务管理,顺应数字化转型趋势。
|
安全 搜索推荐 Android开发
Android系统SELinux安全机制详解
如此看来,SELinux对于大家来说,就像那位不眠不休,严阵以待的港口管理员,守护我们安卓系统的平安,维护这片海港的和谐生态。SELinux就这样,默默无闻,却卫士如山,给予Android系统一份厚重的安全保障。
475 18
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
1174 38
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
8月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1452 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
8月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1035 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
8月前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1125 4
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡

热门文章

最新文章