
帧率控制别让屏幕跑得比系统快帧率控制说白了就是让显示输出和内容生成保持同步。你想想看如果GPU拼命画图但屏幕刷新跟不上或者反过来屏幕刷新太快但内容没准备好都会出现撕裂或卡顿。在MTK8678上我习惯用动态帧率调整策略。核心思路是根据当前场景动态决定显示帧率。核心原则静态画面用低帧率30fps甚至更低动态画面用高帧率60fps或120fps。具体怎么实现看代码// 帧率控制核心逻辑 static int mtk_drm_adjust_fps(struct drm_crtc *crtc, int target_fps) { struct mtk_drm_crtc *mtk_crtc to_mtk_crtc(crtc); int current_fps mtk_crtc-fps; // 检查硬件能力 if (target_fps mtk_crtc-max_fps) { DRM_WARN(Target FPS %d exceeds max %d, clamping\n, target_fps, mtk_crtc-max_fps); target_fps mtk_crtc-max_fps; } // 设置VBLANK间隔 mtk_crtc-vblank_interval DIV_ROUND_CLOSEST(1000000, target_fps); // 更新硬件寄存器 mtk_dsi_set_fps(mtk_crtc-dsi, target_fps); return 0; }这里有个坑我曾经遇到过帧率切换太快会导致屏幕闪烁。所以我在项目中加了个平滑过渡机制每次帧率变化不超过10fps效果好了很多。我的经验在车载多屏场景下副屏比如后排娱乐屏用30fps就够了主屏保持60fps。这样能省不少带宽和功耗。GPU合成 vs 硬件合成选对工具干对活这个问题说白了就是「谁来做图层叠加」的选择题。GPU合成灵活但费电硬件合成省电但有限制。MTK8678的硬件合成器HWC支持最多4个图层的硬件叠加。超过这个数就得走GPU合成。合成方式优点缺点适用场景GPU合成灵活支持任意图层数功耗高带宽占用大复杂UI、游戏硬件合成功耗低延迟小图层数有限格式限制视频播放、简单UI我建议的切换策略是这样的静态场景桌面、设置界面强制走硬件合成动态场景视频、动画根据图层数动态切换游戏场景直接走GPU合成保证帧率代码实现上我习惯在SurfaceFlinger层面做判断// 合成方式选择逻辑 static int choose_composition_mode(struct display_device *ddev, int layer_count) { // 硬件合成能力检查 if (layer_count ddev-hwc_max_layers) { // 检查图层格式是否支持 if (check_hwc_compatible(ddev)) { return COMPOSITION_HWC; // 硬件合成 } } // 回退到GPU合成 return COMPOSITION_GPU; }注意硬件合成不支持旋转和缩放操作。如果你的图层做了旋转哪怕只有1个图层也得走GPU合成。我曾经因为这个bug排查了三天...带宽优化别让数据堵在路上多屏显示最大的瓶颈就是带宽。MTK8678的显示子系统带宽是有限的三个屏幕同时跑4K60fps带宽直接爆掉。我常用的带宽优化手段压缩传输使用DSC显示流压缩技术压缩比可达3:1分时传输不同屏幕的刷新错开避免同时请求带宽缓存复用相同内容只传输一次多个屏幕共享来看一个带宽计算的例子// 带宽计算示例 static unsigned long calc_display_bandwidth(struct display_config *cfg) { unsigned long bw 0; // 每个屏幕的带宽 分辨率 × 色深 × 帧率 for (int i 0; i cfg-screen_count; i) { struct screen_info *screen cfg-screens[i]; unsigned long screen_bw; screen_bw screen-width * screen-height * screen-bpp * screen-fps; // 如果启用DSC压缩 if (screen-dsc_enabled) { screen_bw / 3; // 3:1压缩比 } bw screen_bw; } return bw; }我的建议在项目初期就做好带宽预算。我曾经有个项目三个屏幕加起来带宽需求超过总线带宽的80%结果一跑就卡。后来通过分时刷新和DSC压缩降到了60%以下问题解决。低功耗显示策略省电就是省钱低功耗显示说白了就是「不该亮的时候别亮该亮的时候少亮」。MTK8678在这方面做了不少硬件支持。我常用的低功耗策略局部刷新只更新变化区域静态区域不刷新背光调节根据环境光自动调节背光亮度帧率降级无操作时自动降帧屏幕关闭副屏长时间无操作自动关闭来看一个局部刷新的实现// 局部刷新区域计算 static struct drm_clip_rect calc_damage_region(struct drm_plane *plane) { struct drm_clip_rect damage {0}; // 获取当前帧和上一帧的差异 damage.x1 min(plane-state-src_x, plane-old_state-src_x); damage.y1 min(plane-state-src_y, plane-old_state-src_y); damage.x2 max(plane-state-src_x plane-state-src_w, plane-old_state-src_x plane-old_state-src_w); damage.y2 max(plane-state-src_y plane-state-src_h, plane-old_state-src_y plane-old_state-src_h); return damage; }关键数据在我测试的项目中启用局部刷新后静态场景功耗降低了40%。如果配合帧率降级整体功耗可以降低50%以上。嗯最后说一句。性能优化不是一蹴而就的事需要反复调优和验证。我建议你在开发板上先跑通基础功能然后用perfetto或systrace抓取性能数据找到瓶颈再针对性优化。别一上来就想着把所有优化都加上那样反而容易出问题。好了今天就聊到这里。下一章我们讲多屏同步与帧缓冲管理到时候见。