10、显示系统移植:SurfaceFlinger原理、HWC实现、DRM/KMS驱动适配、显示帧率与性能调优
显示系统,说白了就是Android的“脸面”。用户第一眼看到的就是屏幕,如果这块出问题,那体验直接归零。我在做i.MX平台移植时,最头疼的往往不是内核启动,而是屏幕亮起来之后——要么花屏,要么卡顿,要么干脆黑着。嗯,今天我们就来把这套东西彻底捋清楚。
10.1 SurfaceFlinger原理:Android显示的中枢神经
SurfaceFlinger是Android图形系统的核心服务。它负责把所有应用的“图层”合成到一起,然后交给显示硬件。你可以把它想象成一个导演——每个App是一个演员,SurfaceFlinger决定谁在前、谁在后、谁透明、谁不透明。
我个人习惯把SurfaceFlinger的工作流程拆成三步:
- 接收图层:App通过BufferQueue把渲染好的图形缓冲区交给SurfaceFlinger。
- 合成决策:SurfaceFlinger决定是用GPU合成,还是交给HWC硬件合成。
- 送显:最终合成结果通过HAL层送到显示器。
这里有个关键点——Vsync信号。SurfaceFlinger依赖Vsync来同步合成和显示。如果没有Vsync,就会出现撕裂(tearing)。我在项目中遇到过,某款屏幕的Vsync信号不稳定,导致界面像波浪一样抖动。后来查了半天,发现是DRM驱动里Vsync中断配置错了。
核心要点:SurfaceFlinger的合成策略是“尽量用HWC,不行再找GPU”。因为HWC是硬件合成,功耗低、性能好。GPU合成虽然灵活,但费电。
10.2 HWC(Hardware Composer)实现:硬件加速的秘密
HWC是Android显示HAL层的关键模块。它直接操作显示硬件,把多个图层合成一帧。说白了,HWC就是SurfaceFlinger的“打手”——SurfaceFlinger说“你帮我合成这3个图层”,HWC就去做。
在i.MX平台上,HWC的实现通常基于DRM(Direct Rendering Manager)。我建议你直接复用Android开源的 drm_hwcomposer 项目,然后针对i.MX的GPU和显示控制器做适配。
HWC的核心接口就几个:
prepare():SurfaceFlinger询问HWC“你能合成哪些图层?”set():SurfaceFlinger把图层交给HWC,HWC开始干活。presentDisplay():HWC把合成结果送到屏幕。
我曾经踩过一个坑:HWC的 prepare() 返回了错误的能力标记,导致SurfaceFlinger以为HWC不能处理某个图层,结果所有图层都走GPU合成,帧率直接掉到20fps。嗯,这个问题排查了整整两天。
实战技巧:调试HWC时,可以打开SurfaceFlinger的dump信息:adb shell dumpsys SurfaceFlinger。里面会显示每个图层是由HWC合成还是GPU合成。如果全是GPU,说明HWC没正常工作。
10.3 DRM/KMS驱动适配:打通内核到显示的最后一步
DRM/KMS是Linux内核的显示框架。i.MX平台的显示控制器(如DCSS、LCDIF)都通过DRM驱动暴露给用户空间。HWC就是通过DRM的atomic API来配置显示管线的。
适配DRM驱动时,我建议你重点关注这几个点:
| 组件 | 说明 | 常见问题 |
|---|---|---|
| CRTC | 显示控制器,负责生成时序信号 | 时序参数配错,屏幕无显示 |
| Plane | 硬件图层,每个plane对应一个图层 | plane数量不够,导致合成失败 |
| Connector | 物理接口,如HDMI、DSI、LVDS | EDID读取失败,分辨率不对 |
| Encoder | 编码器,把像素数据转换成接口信号 | 编码器模式不匹配 |
我记得在适配i.MX8M Plus的DCSS驱动时,发现CRTC的时钟源配置有问题。明明设了148.5MHz,实际输出只有74.25MHz。后来发现是驱动里PLL的divider算错了。你想想看,这种问题光看代码很难发现,必须用示波器量一下像素时钟才能定位。
避坑指南:我曾经在移植时直接用了参考设计的设备树,结果屏幕死活不亮。后来发现是panel的时序参数跟实际屏幕不匹配。记住:设备树里的display-timings必须跟屏幕规格书完全一致,差一个像素都不行。
10.4 显示帧率与性能调优:让画面丝般顺滑
帧率是用户体验的硬指标。60fps是底线,30fps就会觉得卡。在i.MX平台上,影响帧率的因素主要有三个:
- 合成效率:HWC是否正常工作?有没有走GPU合成?
- 缓冲区延迟:BufferQueue是否经常被填满?App渲染速度够不够?
- Vsync稳定性:Vsync信号是否抖动?
我常用的调优手段:
- 用
adb shell dumpsys gfxinfo查看App的渲染帧率。 - 用
adb shell dumpsys SurfaceFlinger --latency查看SurfaceFlinger的合成延迟。 - 打开
sysfs里的DRM debug:echo 0x1ff > /sys/module/drm/parameters/debug,看内核日志里有没有atomic commit失败。
有一次,我发现帧率突然从60fps掉到45fps。查了一圈,发现是GPU频率被降了。因为i.MX的DVFS(动态电压频率调整)在温度高时会自动降频。解决办法是调整thermal zone的阈值,或者给GPU一个固定的最高频率。
性能调优口诀:先看HWC,再看GPU,最后查Vsync。硬件能干的,别让软件干。硬件干不了的,优化软件干。
10.5 知识体系总览
下面这张图是我自己总结的显示系统移植知识体系。你可以把它当作一个检查清单——每完成一项,就打个勾。
这张图从下往上展示了显示系统的完整链路。硬件层在最底下,内核驱动层负责抽象硬件,合成层做图层合并,应用层最终把画面呈现给用户。调优工作贯穿每一层,缺一不可。
好了,显示系统移植的核心内容就这些。记住:屏幕亮起来只是第一步,跑得流畅才是真本事。多动手、多打log、多看dumpsys,问题总会找到的。
公众号:蓝海资料掘金营,微信deep3321