18. 显示与相机联动:预览画面显示功耗、降低屏幕刷新率、局部刷新策略
相机预览功耗里,屏幕显示这块经常被忽视。很多人把精力都放在ISP、算法、Sensor上,结果一测整机功耗,屏幕占了将近一半。我早期做过一个项目,相机预览功耗死活降不下来,最后发现屏幕刷新率一直在跑满——说白了,屏幕在“空转”。
今天我们就聊聊显示与相机联动的几个关键点。怎么让屏幕不白费电,怎么在保证流畅的前提下降低刷新率,以及局部刷新到底靠不靠谱。
18.1 预览画面的显示链路
先理清一条线:相机数据是怎么到屏幕上的?
Camera Sensor → ISP → GPU/Display Processor → FrameBuffer → Panel
这条链路里,每一级都可能产生功耗浪费。我见过最典型的问题:ISP输出60fps,屏幕也跑60fps,但用户看到的画面其实只有30fps的有效内容——中间帧全是重复的。这不是白费电吗?
所以,显示功耗优化的核心思路就两条:
- 减少无效帧的传输和渲染
- 降低屏幕面板的实际刷新率
关键认知:相机预览的显示功耗,不是由“相机输出帧率”决定的,而是由“屏幕实际刷新次数”决定的。你相机输出再高,屏幕不刷新就不耗电。
18.2 降低屏幕刷新率:从硬件到软件
降低刷新率是最直接的手段。但这里有个坑:不能简单地把屏幕设为30Hz就完事。为什么?因为Android的VSync机制是全局的,你改了刷新率,整个系统的UI动画、触摸响应都会受影响。
我建议的做法是分场景处理:
| 场景 | 推荐刷新率 | 说明 |
|---|---|---|
| 普通预览(静止场景) | 30Hz | 人眼对静态画面不敏感,30Hz足够 |
| 快速预览(运动场景) | 60Hz | 避免画面撕裂和卡顿感 |
| 录像中预览 | 匹配录像帧率 | 录像30fps,预览就30Hz |
| 高帧率录像(如120fps) | 60Hz或120Hz | 取决于面板能力和功耗预算 |
具体怎么实现?在Android里,我们可以通过 SurfaceControl.setDisplayRefreshRate() 来动态调整。嗯,这里要注意:这个API需要系统权限,普通App用不了。如果你是做系统层开发的,可以走这条路。
// 动态设置屏幕刷新率
SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.setDisplayRefreshRate(displayToken, 30.0f); // 设为30Hz
t.apply();
小技巧:我习惯在Camera HAL层加一个帧率检测器。如果连续10帧的画面变化量小于某个阈值,就认为场景是静止的,自动通知上层降低刷新率。这样既省电,又不会影响用户体验。
18.3 局部刷新策略:只更新变化区域
降低刷新率是“全局”手段。但很多时候,预览画面只有一小块区域在变化——比如你在拍一个静止的文档,只有手指移动时那一小块在变。这时候全局刷新就是浪费。
局部刷新(Partial Update)的思路很简单:只刷新画面中发生变化的那部分区域。这个技术在电子墨水屏(E-Ink)上用得很多,但在普通LCD/OLED上也有应用空间。
实现方式有两种:
- 硬件级局部刷新:通过Display Processor的Dirty Region机制,只更新指定区域的buffer。这个需要芯片支持,高通和MTK的中高端平台基本都有。
- 软件级局部刷新:在GPU合成时,只合成变化区域,然后通过SurfaceFlinger的Partial Update机制提交。这个兼容性更好,但省电效果弱一些。
我曾经在一个低端平板上试过软件级局部刷新。相机预览时,画面大部分是静止的,只有取景框里的对焦图标在闪烁。我们只更新了那个图标区域,屏幕功耗降了大约15%。虽然不多,但对于低端设备来说,15%已经很可观了。
注意:局部刷新不是万能的。如果画面变化区域太大(比如超过屏幕面积的50%),局部刷新的收益就很小了,甚至可能因为额外的计算开销而更耗电。建议设置一个阈值,超过阈值就回退到全局刷新。
18.4 显示与相机联动的架构图
下面这张图展示了相机预览时,显示链路中各个模块的功耗优化点。我把它画成了流程图,方便你理解整体逻辑。
18.5 实战中的避坑指南
讲几个我踩过的坑,希望能帮你少走弯路。
坑一:降低刷新率导致触摸延迟
我曾经在一个项目里把预览刷新率降到30Hz,结果用户反馈触摸对焦有明显延迟。排查后发现,触摸采样率和屏幕刷新率是绑定的。降低刷新率后,触摸采样率也跟着降了。解决办法:把触摸采样率和显示刷新率解耦,或者单独提高触摸IC的采样频率。
坑二:局部刷新导致画面残留
局部刷新如果实现得不好,会出现“鬼影”——上一帧的内容还残留在屏幕上。这通常是因为Dirty Region计算不准确,或者Panel的像素响应时间不够。我建议在启用局部刷新前,先做一次全屏刷新来“清屏”,然后再切到局部模式。
坑三:帧率不匹配导致卡顿
相机输出30fps,屏幕设成60Hz,看起来没问题。但如果屏幕是60Hz,相机输出是24fps,就会出现帧率不匹配,画面一卡一卡的。解决办法:让屏幕刷新率是相机帧率的整数倍(比如30fps配60Hz,或24fps配120Hz),或者启用帧率转换(FRC)来插帧。
我的经验:做显示功耗优化,一定要先拿到屏幕面板的功耗曲线。不同面板在不同刷新率下的功耗差异很大。有的面板60Hz和30Hz只差10%,有的能差30%。没有数据支撑的优化,都是瞎优化。
18.6 总结
显示与相机联动的功耗优化,说白了就是三件事:
- 降低刷新率——根据场景动态调整,别让屏幕空转
- 局部刷新——只更新变化区域,减少无效刷新
- 链路协同——从Sensor到Panel,每一级都要匹配,别让某一级成为瓶颈
嗯,这些方法单独用效果有限,组合起来才能看到明显收益。我建议你在项目里先做一轮基线测试,看看屏幕功耗占整机功耗的比例,再决定从哪里入手。别一上来就搞局部刷新,可能你降个刷新率就解决了80%的问题。
公众号:蓝海资料掘金营,微信deep3321