Rockchip双屏异显旋转调试实战:从原理到避坑指南
双屏异显在嵌入式设备上早就不是什么新鲜需求,但真正落到调试阶段,旋转方向这一关卡住的人不在少数。我最近在基于Rockchip平台做一款双屏产品的显示调试,一块主屏横放、一块副屏竖放,两块屏各自跑独立应用,结果光是让副屏"转对方向"就折腾了整整两天。这个过程中踩的坑、试出来的门道,值得单独拎出来讲一讲。这篇内容主要面向已经上手Rockchip平台、正在做或准备做双屏显示调试的嵌入式工程师,也会照顾到刚接触显示子系统、想搞清楚旋转链路底层逻辑的读者。我会把双屏旋转方向调试的整体设计思路、核心原理、实操步骤和排查经验完整拆开,重点讲清楚"旋转到底发生在哪一层""为什么改了配置没生效""双屏场景下旋转为什么会互相干扰"这几个最容易卡人的问题。看完之后,你应该能独立完成一套双屏旋转方向的配置与验证,少走我走过的弯路。
1. 双屏旋转调试的整体设计思路拆解
1.1 先搞清楚旋转发生在哪一层
很多人一上来就去改应用层的方向参数,改完发现副屏纹丝不动,然后开始怀疑驱动、怀疑硬件。我一开始也犯过这个毛病。实际上在Rockchip这套显示体系里,旋转方向的控制是分层存在的,从下往上大致可以分成这么几层:最底层是显示控制器(VOP)硬件层面的旋转能力,中间是内核DRM框架里的旋转属性配置,再往上是合成器(比如SurfaceFlinger或者Weston)的变换处理,最上层才是应用自己声明的方向。
这几层的关系不是简单的"改哪层都行",而是有优先级的。硬件旋转能力如果支持,走VOP的旋转单元是最省资源的,几乎不占CPU和GPU;硬件不支持或者格式受限的时候,才会退到GPU合成阶段做旋转,这时候性能和功耗都会受影响。所以调试的第一步不是急着改参数,而是先确认你的平台VOP到底支持哪些旋转角度、支持哪些像素格式下的旋转。这个信息在芯片的显示子系统手册里有明确说明,不同型号的VOP能力差异挺大,有的支持90/180/270全角度,有的只支持180度镜像,这个前提不搞清楚,后面全是白费功夫。
我当时的做法是先查手册确认VOP能力,再用内核日志确认当前走的是哪条旋转路径。这一步看起来慢,实际上省了大量瞎试的时间。你可以把旋转理解成"照片翻正"这件事:如果相机本身能转,那拍出来就是正的;如果相机不能转,就得后期用软件把照片转过来。硬件旋转就是"相机自己转",软件旋转就是"后期修图",前者快且省电,后者灵活但费资源。双屏场景下,两块屏可能一块走硬件旋转、一块走软件旋转,这种混合路径最容易出方向不一致的问题。
1.2 双屏场景为什么比单屏复杂
单屏旋转调试,你只需要关心一条显示链路。双屏就不一样了,两块屏各自有独立的CRTC、独立的图层、独立的旋转属性,但它们又共享同一套VOP资源。Rockchip的VOP通常有多个显示通道(比如一个主通道加若干叠加通道),双屏异显的时候,两块屏的图层怎么分配到这些通道上,直接决定了旋转能不能用硬件来做。
举个我实际遇到的例子:主屏横屏正常显示,副屏要竖屏。副屏的图层如果被分配到了一个不支持旋转的叠加通道上,那你在DRM里怎么设旋转属性都没用,内核会默默回退到软件旋转,而软件旋转在某些合成器配置下又不会自动生效,表现出来就是"副屏方向完全没变"。这种问题的隐蔽性在于,日志里不一定有明确报错,你得主动去查图层和通道的绑定关系才能发现。
所以双屏旋转调试的核心思路,我总结成一句话:先定资源分配,再定旋转路径,最后才是参数配置。资源分配指的是两块屏的图层分别走哪个VOP通道,这个在设备树里配置;旋转路径指的是每块屏的旋转由硬件还是软件承担;参数配置才是最后在DRM属性或者合成器配置里填角度。顺序反了,就会陷入"改了没反应、不知道改哪"的死循环。
1.3 方案选型的取舍逻辑
旋转方案大致有三种:纯硬件旋转、纯软件旋转、硬件优先加软件兜底。纯硬件旋转性能最好,但受限于VOP能力和像素格式,不是所有场景都能用;纯软件旋转最灵活,任何角度任何格式都能转,但双屏同时软件旋转对GPU压力不小,帧率容易掉;硬件优先加软件兜底是大多数产品的实际选择,配置上稍微复杂一点,但兼顾了性能和兼容性。
我这款产品最终选的是硬件优先加软件兜底。原因很实际:主屏横屏不需要旋转,副屏竖屏优先走硬件旋转,万一某些特殊格式(比如某些YUV格式)硬件转不了,再退到软件旋转保证功能可用。这个取舍的关键在于,你得接受"不同内容格式可能走不同旋转路径"这个事实,并在测试阶段把各种格式都覆盖到,否则容易出现"看图片正常、播视频方向反了"这种诡异现象。
提示:选型阶段一定要把产品实际会用到的像素格式列全,逐个确认硬件旋转支持情况,不要只拿一种格式测通了就以为万事大吉。
2. 旋转方向的核心原理与关键配置细节
2.1 DRM旋转属性的底层含义
Rockchip内核走的是DRM框架,旋转在DRM里是通过plane的rotation属性来表达的。这个属性不是简单的"转多少度",而是一组变换标志的组合,包括旋转角度(0/90/180/270)和镜像(水平翻转、垂直翻转)。这里有个特别容易搞混的点:DRM里的旋转角度是相对于"原始图层内容"而言的,而最终显示出来的方向还跟CRTC的显示模式、屏幕的物理安装方向有关。
我打个比方帮你理解:DRM的rotation属性相当于告诉系统"把这个图层的内容怎么摆",但"摆好之后贴到哪块画布上、画布本身是不是歪的"是另一回事。所以你会遇到这种情况:rotation设成90度,结果屏幕上的画面转了但方向不对,可能是因为屏幕物理上就是竖装的,你需要的其实是270度而不是90度。这个"差90度"的问题在双屏调试里极其常见,因为两块屏的物理安装方向往往不一样。
具体到配置上,rotation属性接受的值是位掩码组合,常见的有这几种:
| 变换需求 | 对应标志组合 | 说明 |
|---|---|---|
| 不旋转 | rotate-0 | 默认值,原始方向 |
| 顺时针90度 | rotate-90 | 竖屏常用 |
| 180度 | rotate-180 | 倒装屏常用 |
| 顺时针270度 | rotate-270 | 竖屏反向安装常用 |
| 水平镜像 | reflect-x | 常与旋转组合 |
| 垂直镜像 | reflect-y | 常与旋转组合 |
需要强调的是,旋转方向和镜像可以叠加,比如"旋转90度加水平镜像"就是一个组合值。双屏调试时如果发现画面方向对了但内容是镜像的,就是镜像标志没配对。
2.2 设备树里的双屏通道分配
设备树是双屏旋转调试的第一现场。两块屏对应两个显示接口(比如一个HDMI加一个MIPI,或者两个MIPI),每个接口在设备树里绑定到特定的VOP和通道。这里的关键配置项是每个显示接口的rockchip,grf相关属性和VOP的端口映射。
我当时的配置思路是这样的:先确认两块屏分别接在哪个显示接口上,再查这个接口默认绑定到哪个VOP的哪个通道,然后确认这个通道是否具备旋转能力。如果默认通道不支持旋转,就得调整通道分配,把需要旋转的那块屏挪到支持旋转的通道上。这个调整不是随便改的,因为通道分配还牵扯到带宽和图层数量限制,挪了通道可能影响另一块屏的图层叠加能力。
&vop { status = "okay"; }; &vop_mmu { status = "okay"; }; &hdmi { status = "okay"; /* 主屏,横屏,不旋转 */ }; &mipi_dsi { status = "okay"; /* 副屏,竖屏,需要旋转 */ };上面只是示意性的框架,实际配置里每个接口的端口绑定、时钟、分辨率都要写全。我想强调的是,通道分配这一步做完之后,一定要用内核日志确认绑定结果,别假设配置写了就生效了。查看VOP通道和图层绑定关系的日志通常在启动阶段就会打印,搜关键字能看到每个通道当前挂了哪些图层。
2.3 旋转与像素格式的兼容性约束
这是最容易被忽略、也最容易在测试后期爆雷的一点。硬件旋转对像素格式是有要求的,不是所有格式都能转。RGB格式一般支持得比较全,YUV格式就要看具体VOP型号了,某些格式只支持180度旋转,90度和270度转不了。
我在调试时就遇到过:副屏显示UI界面(RGB格式)旋转正常,一播视频(YUV格式)方向就错了。查下来是视频图层用的YUV格式在当前通道上不支持90度硬件旋转,系统回退到了软件路径,但软件路径的旋转配置没跟上,结果就是方向错乱。解决办法有两个:要么把视频图层的格式转换成支持的格式再送显示,要么确保软件旋转兜底路径的配置正确。前者增加转换开销,后者增加GPU负担,得根据产品实际负载来选。
注意:测试阶段务必把产品会用到的所有像素格式都跑一遍旋转验证,尤其是视频、相机预览这类YUV来源的内容,别等量产前才发现问题。
2.4 合成器层的方向处理
如果你的系统跑的是Android,那SurfaceFlinger这一层也会参与方向处理;跑Linux加Weston的话,Weston的output transform配置同样会影响最终方向。这一层的坑在于,它和DRM层的旋转可能叠加,也可能冲突。
举个典型场景:应用声明自己要以竖屏显示,合成器据此做了一次变换,同时DRM层又配了旋转,两次变换叠加,结果画面转了180度而不是90度。这种"转多了"的问题,根源就是没理清哪一层该负责旋转。我的经验是,双屏场景下尽量让旋转职责单一化:要么统一在DRM层做,合成器层保持默认;要么统一在合成器层做,DRM层不设旋转。两边都设,调试时极难定位。
3. 双屏旋转方向的完整实操流程
3.1 环境确认与能力摸底
动手改配置之前,先把家底摸清楚。第一步确认平台型号和VOP版本,这个决定了硬件旋转的能力边界。第二步确认两块屏的物理安装方向,是横装还是竖装,有没有倒装,这个决定了每块屏需要的目标旋转角度。第三步确认系统软件栈,是纯Linux还是Android,合成器是什么,这决定了旋转配置该往哪写。
我当时的摸底清单是这样的:主屏物理横装、目标0度;副屏物理竖装、目标90度;系统是Linux加Weston;VOP确认支持90度硬件旋转但仅限RGB格式。这个清单列出来之后,配置方向就非常明确了。
# 查看当前显示设备与连接状态 cat /sys/class/drm/card0-*/status # 查看plane支持的旋转属性 cat /sys/kernel/debug/dri/0/planes 2>/dev/null | head -50上面这类命令能帮你快速确认当前系统识别到了哪些显示接口、每个plane暴露了哪些属性。不同内核版本路径可能略有差异,找不到就顺着/sys/kernel/debug/dri/往下翻。
3.2 单屏旋转先跑通再上双屏
这一步是我强烈建议的:别一上来就双屏一起调,先把副屏单独点亮并旋转正确,再接入主屏做双屏。原因很简单,双屏同时调的时候,变量太多,出了问题分不清是旋转配置错了还是通道分配冲突了。单屏跑通相当于建立了一个"已知正确"的基线,后面双屏出问题,可以拿单屏配置做对照。
单屏旋转的验证方法很直接:显示一张有明显方向特征的测试图(比如带文字和箭头的图),确认文字方向、箭头指向都符合预期。别用纯色或者对称图形测,那种图转没转根本看不出来。我一般用一张带"上"字和向上箭头的图,一眼就能判断方向对不对。
3.3 双屏通道分配与旋转属性配置
单屏基线有了之后,接入第二块屏。这时候重点看两件事:两块屏的图层是否分配到了预期的VOP通道,以及每块屏的旋转属性是否独立生效。
配置上,如果走DRM属性控制,可以通过修改plane的rotation属性来设定每块屏的旋转。如果走Weston,则在Weston配置里为每个output单独指定transform。关键是两块屏的配置要分开写,别用全局配置一把梭,否则两块屏会互相干扰。
# Weston 配置示意:为不同 output 指定不同 transform [output] name=HDMI-A-1 transform=normal [output] name=DSI-1 transform=rotate-90上面这种按output分别配置的方式,是双屏异向显示的正确姿势。我见过有人图省事在全局配置里写transform,结果两块屏一起转了,主屏反而歪了。
3.4 旋转生效的验证与记录
配置写完,重启显示服务或者重启设备,然后逐项验证:主屏方向是否正确、副屏方向是否正确、两块屏内容是否独立、旋转后是否有画面撕裂或性能异常。验证时把每块屏的当前transform值、实际显示效果、以及内核日志里对应的旋转路径都记录下来,形成一份配置-效果对照表。
这份记录在后续排查问题时价值极高。因为双屏旋转的问题往往不是"完全不对",而是"某个格式下不对""某个应用下不对",有了基线记录,才能快速判断是配置回退还是应用层干扰。
| 验证项 | 主屏预期 | 副屏预期 | 实测结果 | 备注 |
|---|---|---|---|---|
| 静态图方向 | 正常 | 旋转90度 | 待填 | 用带方向特征图 |
| 视频播放方向 | 正常 | 旋转90度 | 待填 | 注意YUV格式 |
| 双屏独立内容 | 互不干扰 | 互不干扰 | 待填 | 同时跑不同应用 |
| 旋转后帧率 | 稳定 | 稳定 | 待填 | 关注软件旋转回退 |
4. 常见问题排查与避坑经验实录
4.1 改了配置完全没反应
这是最高频的问题。排查顺序我总结成"三查":一查配置是否真的被加载(设备树改了就确认内核是不是用的新dtb,Weston配置改了就确认服务是不是重启了);二查旋转路径是否走了硬件(看日志确认有没有回退到软件);三查图层是否在支持旋转的通道上(查通道绑定关系)。
我遇到过一次,设备树改了但没重新编译dtb,设备跑的还是旧配置,白折腾半天。还有一次是Weston配置改了但服务没重启,配置根本没生效。这类"低级错误"在调试紧张的时候特别容易犯,所以养成"改完必确认生效"的习惯很重要。
4.2 方向差90度或180度
方向偏差基本是角度算错了或者叠加了额外变换。先确认屏幕物理安装方向,再确认DRM层设的角度,最后确认合成器层有没有额外变换。三者对齐之后,方向就对了。差90度通常是物理方向和配置角度没对应上,差180度多半是两层变换叠加了。
4.3 双屏旋转互相干扰
两块屏旋转互相干扰,根源几乎都是配置没隔离。检查是不是用了全局transform配置,是不是两块屏共用了同一个plane或者通道。双屏异向显示的前提是每块屏有独立的配置入口,这个不满足,干扰是必然的。
4.4 特定格式下旋转失效
前面提过,YUV格式的硬件旋转支持有限。排查方法是确认当前图层的像素格式,对照VOP能力表看是否支持该格式的旋转。不支持就考虑格式转换或者确保软件兜底路径正确。
| 问题现象 | 可能原因 | 排查动作 | 解决方向 |
|---|---|---|---|
| 配置无反应 | 配置未加载/未重启 | 确认dtb版本、服务状态 | 重新编译部署并重启 |
| 方向差90度 | 物理方向与角度不匹配 | 核对屏幕安装方向 | 调整旋转角度 |
| 方向差180度 | 多层变换叠加 | 检查DRM与合成器配置 | 旋转职责单一化 |
| 双屏互相干扰 | 配置未隔离 | 检查是否全局配置 | 按output独立配置 |
| 特定格式失效 | 硬件不支持该格式旋转 | 查VOP格式能力表 | 格式转换或软件兜底 |
| 旋转后卡顿 | 回退到软件旋转 | 查日志确认旋转路径 | 优化通道分配走硬件 |
4.5 实操心得与独家技巧
分享几个文档里不会写、但实际调试中特别管用的经验。第一,调试旋转时把内核日志的显示相关模块日志级别调高,旋转路径的选择、回退的原因都会打出来,比盲猜高效得多。第二,准备一套"方向测试图",包含文字、箭头、非对称图形,每次改配置都用同一套图验证,排除测试素材本身的干扰。第三,双屏调试时给两块屏用明显不同的测试内容(比如一块显示红色背景、一块显示蓝色背景),这样一眼就能看出哪块屏的配置生效了、哪块没生效,避免看错屏。
还有一个小技巧:如果怀疑是软件旋转兜底路径的问题,可以临时强制走软件旋转(通过配置禁用硬件旋转),看方向是否正确。如果强制软件旋转方向对了,说明问题出在硬件旋转路径的格式或通道上;如果强制软件旋转也不对,说明是角度配置本身错了。这个二分法能快速缩小问题范围。
提示:调试期间保留一份"已知可用"的配置备份,每次大改之前先备份,改崩了能快速回滚,别在错误配置上越陷越深。
双屏旋转方向调试这件事,说到底是对"旋转链路"的理解深度问题。链路理清了,配置就是填空题;链路没理清,配置就是猜谜语。我这两天的折腾,大部分时间花在理链路上,真正改配置的时间反而不多。后面如果还要做多屏或者更复杂的异向显示,这套"先定资源、再定路径、最后配参数"的思路依然适用。