ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RK3588 Android12屏幕方向、分辨率与密度配置指南

RK3588 Android12屏幕方向、分辨率与密度配置指南 1. 先把三条链路分清楚方向、分辨率、密度到底各管什么刚把一块新屏接到RK3588的板子上Android12跑起来之后十有八九会遇到下面这几种情况开机logo是横的但系统进去变成竖的图标大得像老年机画面右边被切掉一截手指点左边结果响应在右边。很多人第一反应是去改build.prop或者翻device目录改了半天重启结果方向对了密度又乱了。问题出在没搞清楚这三件事在Android12的显示体系里其实是三条独立的链路改错了层级怎么调都是白费功夫。先说清楚这三个概念各自的作用域。分辨率是底层物理概念指的是显示控制器RK3588上是VOP2实际往屏上扫的像素时序包括hactive/vactive这些timing参数它决定了硬件层面画了多少个点密度是上层逻辑概念指的是Android在渲染UI时把dp换算成px的基准比例它决定了一个按钮画多大方向则是介于两者之间的坐标系变换物理面板的扫描方向是固定的但系统可以把画面整体旋转90度、180度、270度后再送出去。注意这三者不是互相独立的绝对值而是通过一个物理像素 → 逻辑尺寸 → 显示区域的换算链关联起来的。改一个不动另一个很容易出现画面能显示但比例失真的情况。我见过最典型的一个场景一块10.1寸的MIPI屏物理时序是1920x1200客户要求竖屏使用。如果只是简单地把设备树里的width/height换一下表面上看方向变了实际上VOP还在按1920x1200的时序扫描只是把一帧图像硬塞进竖的显存里结果就是画面被拉长、字幕变形。正确做法是保持timing不变通过orientation属性让上层知道这块屏装上去的时候是旋转过的。1.1 为什么必须分三层配置这三条链路之所以要分层根本原因是RK3588的Android12显示栈从上到下至少经过四层应用层 → WMS/SurfaceFlinger → HWCHardware Composer→ DRM/KMS驱动 → VOP2硬件。每一层都有自己的一套参数表达方式。应用层关心的是我要竖屏还是横屏用setRequestedOrientation表达WMS层关心的是旋转和裁剪用DisplayInfo里的rotation和logicalWidth表达HWC/DRM层关心的是物理输出用connector的mode和rotation属性表达VOP2层关心的是具体的timing寄存器和图层分配如果只在应用层改方向那只是告诉某个Activity怎么摆系统UI和开机动画还是原来的方向如果只在设备树改那开机logo和kernel阶段是对的但Android上层拿到的DisplayInfo没同步图标还是会错位。真正稳妥的做法是从设备树一路对齐到frameworks让四层看到的方向描述是同一套。1.2 参数改动的优先级顺序实操上我建议按这个顺序动刀能省大量重复编译的时间顺序层级典型文件影响范围是否需要重新编译1设备树arch/arm64/boot/dts/rockchip/xxx.dts物理时序、panel orientation需要重编kernel和dtb2内核显示驱动drivers/gpu/drm/rockchip/VOP绑定、接口选择需要重编kernel3Android属性device/rockchip/rk3588/xxx/xxx.mkro.sf.lcd_density等需要重编system4frameworks overlaydevice/rockchip/common/overlay/旋转、裁剪相关config需要重编system5运行时命令adb shell wm临时验证用不需要重启失效从上往下改每改一层就先用dumpsys确认这一层的数据对了再往下走不要一口气全改完再重启那样出问题根本定位不到是哪层的锅。2. 屏幕方向配置从设备树到WindowManager的完整落地屏幕方向这块是坑最多的因为它横跨硬件和软件而且很多文档里说的改方向其实改的是不同层的东西说法混在一起很容易让人误解。我在实际项目里踩过的最深的一个坑是客户给的屏模组本身FPC走线就是反的导致物理面板的扫描方向和常规屏完全相反最后绕了很大一圈才发现要在设备树里加rotation 180。2.1 先搞清楚物理面板的原始方向在动任何配置之前先要看清楚这块屏的规格书。大部分MIPI DSI和eDP屏在出厂时都有一个native orientation通常是横屏landscape也就是面板的源极驱动IC沿着长边排布。规格书里会标注扫描方向比如Top-Left to Bottom-Right。这个信息直接决定了设备树里要不要加orientation补偿。物理面板的原始方向可以用一个简单方法验证先不管Android上层让kernel阶段显示一张纯色测试图RK的uboot和kernel都有测试模式看图有没有被旋转。如果测试图是正的那物理方向就是正的如果图是歪的说明需要在设备树里补偿。设备树里RK3588给panel节点提供了orientation属性用法大概是这样panel: panel { compatible simple-panel; status okay; enable-gpios gpio1 RK_PB0 GPIO_ACTIVE_HIGH; reset-gpios gpio1 RK_PB1 GPIO_ACTIVE_LOW; /* 面板物理安装方向单位是度可选 0/90/180/270 */ orientation 90; display-timings { native-mode timing0; timing0: timing0 { clock-frequency 148500000; hactive 1920; vactive 1080; hback-porch 148; hfront-porch 88; hsync-len 44; vback-porch 36; vfront-porch 4; vsync-len 5; hsync-active 0; vsync-active 0; de-active 1; pixelclk-active 0; }; }; };这里orientation 90的含义是面板装到整机上时顺时针转了90度内核会把这个信息通过DRM connector的panel_orientation属性向上传递。注意这个属性和后面Android层的rotation是两码事它只影响kernel/HWC对物理输出的理解不会自动改变Android的UI方向。提示RK3588的部分kernel版本里orientation属性需要驱动里显式解析并设置到drm_connector-display_info.panel_orientation如果驱动没做这个解析写了也没用得先去确认kernel版本对应的驱动是否支持。2.2 HWC与SurfaceFlinger层的方向对齐设备树改完之后下一步是让Android上层知道正确的方向。这一步的关键在HWC的实现里。RK3588 Android12用的是Rockchip自己的HWC2实现位于hardware/rockchip/hwcomposer/目录下。HWC在初始化时会从DRM connector读取panel_orientation然后转换成HWC自己的HWC2DisplayConfig::transform。如果发现HWC没正确读取可以在这几个地方确认dumpsys SurfaceFlinger输出里Display的orientation字段dumpsys display里DisplayDeviceInfo的rotationvendor分区下的HWC日志打开persist.vendor.hwc.debug相关属性看详细输出SurfaceFlinger最终会把方向应用在合成阶段。关键点是SurfaceFlinger的旋转是整帧旋转参与旋转的buffer会走GPU合成带来额外功耗。所以能提前在HWC或者设备树搞定的旋转不要留到SurfaceFlinger。Android12上还有一个DisplayDeviceConfig位于SurfaceFlinger源码里从Android 11引入它支持在设备上用一个XML描述每块屏的density、viewport、rotation等比传统硬编码在源码里的方式灵活很多。RK3588的部分BSP里也接入了这套机制可以在/vendor/etc/display/下放配置文件。2.3 应用层与系统UI的方向控制底层的方向搞定了应用方向还得单独处理。Android系统默认的旋转策略由WMS的WindowOrientationListener决定它会根据sensor如果接了重力感应或者配置来切换。对没有重力感应的设备比如工控平板、一体机需要把旋转功能关掉直接固定方向。固定方向有几种改法按项目性质选产品是单方向固定使用直接改frameworks的默认rotation比如frameworks/base/core/res/res/values/config.xml里的config_defaultDisplayRotation部分BSP有这个字段或者在设备overlay里覆盖需要在出厂配置里改改device/rockchip/rk3588/xxx/下的overlay把SystemUI和Launcher的android:screenOrientation固定只是临时验证adb shell settings put system user_rotation 1然后adb shell settings put system accelerometer_rotation 0关掉自动旋转这里有个坑系统UI和第三方应用的适配不一样。系统UISystemUI、Launcher通常已经预置了横竖屏两套layout改方向都能自适应但一些第三方APK是写死了landscape的你系统转竖屏了它还是横的就会在屏幕中间留一条竖的黑边。这种情况只能靠android:resizeableActivity或者在AndroidManifest.xml里加android:screenOrientationportrait强制改。3. 分辨率设置timing参数、VOP绑定与多屏策略分辨率大概是三个参数里最容易让人头大的因为从物理时序到逻辑尺寸中间有好几层分辨率的概念而且名字都叫resolution实际含义完全不同。我见过不少人把wm size当成物理分辨率改结果改完发现画面变糊了实际上他改的只是framework的逻辑分辨率。3.1 display-timings时序参数逐项拆解物理分辨率的载体就是设备树panel节点里的display-timings。这些参数每一项都要跟屏的规格书一字不差地对齐错一个数字可能就是黑屏或者花屏。我们拿一个1920x108060Hz的常见屏举例逐项说明参数值含义常见取值clock-frequency148500000像素时钟单位Hz由下面各项算出来hactive1920水平有效像素屏的物理宽度vactive1080垂直有效像素屏的物理高度hback-porch148行消隐后肩规格书HSW/HBPhfront-porch88行消隐前肩规格书HFPhsync-len44行同步脉冲宽度规格书HSyncvback-porch36场消隐后肩规格书VBPvfront-porch4场消隐前肩规格书VFPvsync-len5场同步脉冲宽度规格书VSynchsync-active0行同步极性0低有效1高有效vsync-active0场同步极性0低有效1高有效de-active1DE信号极性看规格书pixelclk-active0像素时钟边沿看规格书3.2 pixel clock的计算与校验clock-frequency不是独立抄的而是从上面其他参数算出来的公式是pixel_clock (hactive hfront-porch hback-porch hsync-len) × (vactive vfront-porch vback-porch vsync-len) × refresh_rate代入1920x108060(1920 88 148 44) × (1080 4 36 5) × 60 2200 × 1125 × 60 148,500,000 Hz和上面的clock-frequency完全对得上。实际调试时我建议先用这个公式反推一遍看规格书标的时钟和算出来的是否一致。如果不一致通常有两种原因一是刷新率不是整60可能是59.94或50二是规格书的消隐参数标的是total值而不是porch值。这两种情况都要特别注意。刷新率不是整60时怎么算比如59.94Hz就是148500000 / 2200 / 1125 * 60 59.94反过来clock 2200 × 1125 × 59.94 148.35MHz这种情况下设备树里可以直接写148351000这种近似值内核推荐用整数但也能接受近似。3.3 VOP2绑定与多屏输出策略RK3588的VOP2支持4个VPVideo Port每个VP可以独立绑定到一个显示接口。常见的绑定方式VP0 → HDMI04K60全功能VP1 → MIPI DSI0 或 eDP0VP2 → HDMI1 或 DP0VP3 → DSI1 或 DP1如果只有单屏一般绑到VP0或者离该接口最近的VP。多屏时要考虑VOP的带宽上限VP0的带宽最高其他VP在高分辨率下会有限制。比如要同时输出4K1080p两块屏通常4K那块绑VP01080p那块绑VP1。绑定关系在设备树里通过rockchip,grf和ports节点配置比如dsi0_in_vp2 { status okay; }; hdmi0_in_vp0 { status okay; };如果绑错了VP可能出现接口能初始化但一直黑屏、或者分辨率上不去的情况。判断方法看kernel log里VOP相关打印正常会有vp0: 3840x216060Hz这样的输出信息。3.4 运行时修改逻辑分辨率有时候物理时序是好的但UI需要按不同的逻辑尺寸布局。这时候用framework层的命令最方便# 查看当前逻辑分辨率 adb shell wm size # 临时改成1280x800 adb shell wm size 1280x800 # 恢复默认 adb shell wm size resetwm size改的是ActivityManager拿到的逻辑尺寸底层物理时序不变所以画面会被缩放。这个东西调试阶段用来快速验证UI布局很好用但量产绝对不能依赖它因为它会导致画面模糊并且部分驱动可能不支持任意比例缩放。4. 密度配置从dpi计算到不同尺寸屏的推荐值密度这个参数看起来简单其实很容易配错因为Android的density不是简单的dpi而是分档的。配错了不会黑屏花屏这种硬故障但会让整个UI显得巨丑——要么图标巨大间距离谱要么字小到看不见。客户验收的时候最容易卡在这里。4.1 dpi计算与Android density bucket先算物理dpi公式是对角像素数除以对角英寸数dpi sqrt(hactive² vactive²) / diagonal_inch举例一块10.1寸的1920x1200屏dpi sqrt(1920² 1200²) / 10.1 sqrt(3686400 1440000) / 10.1 sqrt(5126400) / 10.1 ≈ 2264 / 10.1 ≈ 224 dpiAndroid不会直接用224这个值而是会归到最近的density bucket。标准的bucket包括bucketdensity值典型场景ldpi120老式小屏mdpi160基准密度hdpi240常见平板xhdpi320手机主流xxhdpi480高清手机xxxhdpi640旗舰手机224dpi对应的最接近的bucket是hdpi(240)所以ro.sf.lcd_density就设240。设完的效果是1dp 1.5px。4.2 不同尺寸屏的推荐density实际项目里我总结了一套经验值按屏尺寸直接查屏幕尺寸分辨率物理dpi(近似)推荐density说明7寸1024x600170160常用在车机偏小8寸1280x800189160~213213是8寸1280x800的标准值10.1寸1280x800149160大屏低分辨率UI偏大10.1寸1920x1200224240主流平板体验好13.3寸1920x1080166160笔记本级觉得小可以上21315.6寸1920x1080141160一体机常用21.5寸1920x1080102160大屏大间距别设120有个经验如果客户觉得图标太大通常在算出来的dpi基础上往下取一档更保险。比如224dpi的屏用240 UI会显得偏大改成213或者187体感更舒服。这个值不是死的量产之前跟客户UI团队对齐一下体感。4.3 配置位置与优先级ro.sf.lcd_density这个属性的配置位置有好几处优先级从低到高device/rockchip/common/BoardConfig.mk里的默认值一般没有具体的产品mk文件如device/rockchip/rk3588/xxx/xxx.mk系统的build.prop注入客户定制的prebuilt目录里的prop文件最规范的做法是改产品对应的mk文件PRODUCT_PROPERTY_OVERRIDES \ ro.sf.lcd_density240改完之后重新编译system.img刷机生效。注意这个属性是ro.开头只读的运行时改不了别想着用setprop改会直接报错。4.4 运行时动态调试density调试阶段需要快速试不同density用wm density最方便# 查看当前density adb shell wm density # 改成240 adb shell wm density 240 # 临时改成其他值试试 adb shell wm density 213 # 恢复系统默认 adb shell wm density resetwm density改的是ActivityManager里的逻辑density覆盖系统属性里的值重启后失效。验证阶段可以先用它试出最合适的值再反过来写进mk文件。5. 常见问题排查实录与速查表写到这里实际的配置方法基本覆盖了。剩下最实用的部分是排查因为实际项目里遇到的问题千奇百怪这里挑几个我印象最深的记录一下。5.1 黑屏、花屏、偏屏的排查思路黑屏通常有三个原因背光没亮、时序不对、VOP没绑上。排查顺序应该是先量背光使能引脚和PWM引脚的电平确认背光时序是否符合屏规格书要求有些屏要求背光在初始化序列之后再开启用示波器量MIPI DSI或者eDP的时钟和数据信号看波形是否正常看kernel log里的VOP初始化信息正常会有对应的输出timing打印花屏一般是时序参数不对尤其是clock-frequency算错了导致刷新率偏太多。这种情况先按上面3.2的公式反推一遍时序确认porch参数都是从规格书正确搬过来的。另外要注意hsync-active/vsync-active极性极性反了有时不会黑屏但会花。偏屏画面左边或上面被削掉一截多半是porch参数设置方向搞反了把front-porch和back-porch对调试试看。也有些屏要求total时序精确匹配这时候必须把四个porch都算准。5.2 方向错乱和触摸不对应最头疼的是方向和触摸不对应画面转了90度但触摸还是原始坐标。原因是触摸IC的坐标转换没有跟着一起转。解决思路分两种情况屏和触摸是一体的模组触摸IC的坐标转换参数在触摸驱动里需要同步修改屏和触摸分开触摸驱动需要根据screen的rotation做坐标映射RK3588的Android12上触摸坐标转换通常在HAL层或者input子系统的touchscreen驱动里处理。如果触摸IC本身的firmware支持方向配置直接改firmware最干净如果不支持就在kernel的input驱动里加坐标交换逻辑。有个快速验证的方法adb shell getevent -l查看触摸上报的ABS_MT_POSITION_X和Y轴数据同时用adb shell里的示波器应用画一下轨迹看看方向和屏幕是否对应。5.3 密度异常和UI错位density配错的表现一般是图标大小不对过大过小、文字行距诡异、某些布局元素重叠或者跑到屏幕外面。排查方法adb shell wm density看当前生效值adb shell getprop ro.sf.lcd_density看系统属性值两者应该一致如果两者不一致说明wm density被手动覆盖过或者某个应用的Configuration里density被改了还有一种隐蔽情况density对了但某些APK内部写死了Configuration.screenWidthDp跟实际density不匹配导致该应用的UI错位。这种只能反编译APK去看它怎么用这些值或者找APK提供方适配。5.4 排查速查表最后整理一张速查表遇到问题对着查能省很多时间现象可能原因排查命令/方法处理方案开机黑屏但背光亮时序不对或VOP未绑定dmesg | grep -i vop检查display-timings和vp绑定画面被削边porch方向搞反对比规格书交换front/back porch方向错90度panel orientation未配dumpsys SurfaceFlinger设备树加orientation属性触摸不对应坐标转换未同步getevent -l修改触摸驱动的坐标映射图标巨大density设得太低wm density提高density值文字很小density设太高wm density降低density值或换dpi基准分辨率缩放模糊用了wm size硬缩放wm size恢复物理timing改设备树多屏时一块黑VOP带宽超限kernel log看VOP带宽高分辨率换到VP0刷新率不稳clock-frequency算错按公式反推按规格书精确修正时钟竖屏时系统UI仍横frameworks未改看SystemUI布局改overlay或旋转策略注意这张表里的数字和参数都是常见场景的经验值应用到具体项目时一定要以屏规格书和RK3588对应BSP版本的驱动实现为准。不同BSP版本的属性名和节点名可能略有差异。我个人的体会是RK3588上的显示问题90%以上都能在设备树时序 VOP绑定 orientation属性 density属性这四项里找到答案。把两条命令记熟dumpsys SurfaceFlinger和dumpsys display几乎所有显示参数都能从这两条命令的输出里查到。调屏的时候先把kernel阶段调通让开机logo正常显示再去调Android上层的方向和密度一层一层往下走比一次性都改完再试要高效得多。
返回列表