1. 多路显示移植的前置认知:RK3568到底能带几块屏
做显示相关开发的同学都有一个体会:单屏点亮只是入门,真正磨人的是多路显示的场景适配。这次我在开源鸿蒙OpenHarmony上给RK3568做多路显示移植,踩了不少坑,也把整个链路捋清楚了。RK3568这颗芯片在瑞芯微的产品线里属于中端偏上的定位,四核A55,带Mali-G52 GPU,显示方面内置了两个VOP(Video Output Processor),分别是VOP2和VOP2Lite。很多人以为一个芯片能输出几路画面纯粹看硬件接口数量,实际在移植OpenHarmony时还要看Display HAL层的合成器策略、HDF框架的display_model配置,以及内核drm驱动的encoder路由。
先说结论:RK3568在OpenHarmony系统里,官方默认支持三路显示同时输出,一路HDMI、一路LVDS或eDP、一路MIPI DSI。这只是“支持”,真正工程落地时,你需要根据板级原理图去适配不同接口组合,比如双MIPI DSI同显、HDMI与BT1120同时输出,或者LVDS加RGB888并行输出。而网上热词里提到的“rk3568 配置bt1120输出”“rk3568调试ov5695”其实都围绕一个底层能力:VOP2的四个视频端口(VideoPort)如何灵活路由到不同物理接口。这就是多路显示移植的核心逻辑,装好根基,后面所有配置都是围绕它展开的。
我这次移植的目标板卡配置为主控RK3568,外设包括一个HDMI接口、一个MIPI DSI屏幕、一组LVDS信号,以及一个BT1120转换芯片接高清摄像头预览。用OpenHarmony的Distributed Display能力做一路虚拟多屏,最后实现了四路显示输出。听起来很唬人,但实际上整个移植链条并不复杂,关键是把显示子系统的三层关系搞清楚:内核DRM层 → HDF的Display Device层 → 上层Surface/合成器层。下面我把每一层的关键改动都拆开讲,尽量把那些文档里没写明白的路数补齐。
2. 显示链路与OpenHarmony显示子系统架构梳理
2.1 RK3566/RK3568属同一显示处理族,但差异不能忽略
先解释一个通用的坑:RK3568和RK3566经常被当作同一个平台去配置设备树,因为两者很多寄存器地址一模一样。但它们对显示处理器的部分能力做了裁剪,RK3566没有双路HDMI,也没有PCIe,VOP2的VideoPort数量其实是一样的,四个VideoPort都在,只是RK3566去掉了其中两个视频端口的物理输出能力。简单说,你在RK3568上调好的多屏设备树,直接拿到RK3566板子上大概率第二路HDMI点不亮,这不是OpenHarmony的问题,是芯片本身物理通路就没接出来。
所以在移植之前,第一步不是改代码,而是对照芯片手册确认你的板级设计用了VOP2的哪几个VideoPort,每个VideoPort支持哪些物理协议。RK3568的VOP2四个VideoPort分配大致是这样的:
- VP0:支持HDMI、eDP、DP,最高4K@60。
- VP1:支持MIPI DSI、LVDS、RGB并行,最高2K@60。
- VP2:支持MIPI DSI、LVDS、RGB并行,最高2K@60。
- VP3:支持BT1120、BT656等视频输出协议,用于接外部转换芯片或采集显示。
在这个基础上,OpenHarmony的显示HAL才会去枚举drm下的plane、crtc、encoder和connector。如果设备树里某个display节点没有children子节点,那么HAL就不会识别到对应的connector,上层合成器也就无法把它作为一块独立屏幕来管理。
2.2 OpenHarmony显示子系统的HDF三层结构
OpenHarmony的显示子系统在整个框架里分了三层,和Linux标准DRM稍有不同。最底层是内核的DRM驱动,曝光crtc/encoder/connector/plane;中间层是HDF的Display Host驱动,它通过drm接口访问内核;最上层是Display HAL,实现了IDisplayDevice、IDisplayBuffer等标准接口,给上层Surface和合成器提供屏幕参数。
移植多路显示时,最容易出问题的地方就在中间这层:HDF的display_model配置里,每个display device节点需要指定对应的plane、crtc、connector的ID和虚拟设备的route。如果节点配置错,常见现象是dmesg里报“failed to find a suitable crtc”或者HAL层扫面设备时只检测到一块屏。
具体来说,OpenHarmony的display_hal驱动源码在drivers/peripheral/display/display_hal下,它的核心是disp_mgr.c里注册的g_deviceManager。这个deviceManager负责把所有probe到的display device挂到链上。多路显示移植时不需要改这个文件,反而要改的是产品仓里那个hdf_config/display/device_info/display_device.hcs。这个hcs文件定义了每个display设备的ID、name、以及connector类型。
2.3 合成器如何与多路显示协作
很多做嵌入式Linux显示的同学第一次接触OpenHarmony会有点懵,因为OpenHarmony里不是每个连接器直接与framebuffer一一对应。它还多了一层合成器(Composer)。你可以把合成器理解为一个软件路由中枢:底层有多个显示设备(也就是物理屏),每个设备有一个渲染目标,合成器决定每个Surface的内容最终落到哪个显示设备上。
在单屏场景中,合成器把UI内容合成到一个目标上,没啥存在感。但多屏场景中,合成器要维护一个“设备树映射表”,告诉上层“哪块屏幕是主屏”、“哪块屏幕扩展”、“哪块屏幕是同显镜像”。OpenHarmony标准的扩展屏接口在rosen模块里,通过Distributed Screen的能力可以实现跨设备投屏,但在同一设备上多物理屏扩展,就需要确认display_hal上报的屏幕数量是否正确。这块能力做得还算干净,只要底层显示设备上报正确,上层基本无需改动就能识别到多屏。
我在移植时遇到了一个比较隐蔽的问题:OpenHarmony的默认product配置在编译时通过build/tools/sysparam_permission配置Capability,其中对display的“display device count”做了一个上限。默认值我看过代码,是2。也就是说,即使底层内核和HAL都识别出了三块物理屏,上层Service仍然只会暴露两块屏。这个参数在哪改?在出现rosen/display接口只能查到两个屏时,去你产品仓的config.json或init.cfg里搜索display.dpi、display.max_device_count这类关键字,把对应值改成实际屏数。
RK3568平台默认OpenHarmony标准系统按双屏来配,要上三路及以上显示,必须同时改hcs和sysparam两个地方,光改一处都不行。这一点是很多人搞半天都找不到原因的根源,建议直接收藏。
3. 设备树里的显示节点:rk3568-multi-display.dtsi改造实录
3.1 最小可运行设备树节点的骨架
设备树是多路显示移植的第一战场。RK3568的官方SDK是基于Linux mainline的drm-next分支维护的,OpenHarmony内核源码里的rk3568设备树基本沿用了同一套体系。一个最小的多路显示设备树需要包含display-subsystem节点、vop、hdmi、mipi-dsi、lvds等节点,并且每个节点都要正确关联到对应的VP端口。
先给一个最常用的双路HDMI + MIPI DSI的设备树骨架,这是我实际板子上的配置,去掉了板级冗余后这样写:
&display_subsystem { status = "okay"; ports = <&vop_out>; }; &vop { status = "okay"; compatible = "rockchip,rk3568-vop"; reg = <0x0 0xfe040000 0x0 0x3000>, ...; interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>; rockchip,grf = <&sys_grf>; rockchip,vo1_grf = <&vo1_grf>; ports { #address-cells = <1>; #size-cells = <0>; vop_out: port@0 { reg = <0>; #address-cells = <1>; #size-cells = <0>; vp0_out_hdmi: endpoint@0 { reg = <0>; remote-endpoint = <&hdmi_in_vp0>; }; vp1_out_mipi_dsi: endpoint@1 { reg = <1>; remote-endpoint = <&dsi_in_vp1>; }; }; }; }; &hdmi { status = "okay"; hpd-gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>; pinctrl-names = "default"; pinctrl-0 = <&hdmitx_hpd>; ports { #address-cells = <1>; #size-cells = <0>; hdmi_in: port@0 { reg = <0>; hdmi_in_vp0: endpoint@0 { reg = <0>; remote-endpoint = <&vp0_out_hdmi>; }; }; }; };这里有一个关键细节:vop_out里每个endpoint的reg,代表它连接的是VOP2的哪个VideoPort。比如reg = <0>对应VP0,reg = <1>对应VP1。这个索引必须和驱动里的VOP2_VP0/VP1宏对上,否则即使remote-endpoint写对了,驱动遍历ports时也会因为索引错乱导致crtc找不到connector。
3.2 MIPI DSI与LVDS的同源复用配置
再来说说MIPI DSI和LVDS同源复用的问题。RK3568的VP1和VP2在物理上可以路由到MIPI DSI0/1、LVDS0/1、RGB24等接口,但同一个VideoPort同一时刻只能选择一种输出协议。很多板子会把LVDS0和MIPI DSI0设计成“二选一”模式,靠一个IO阻容器件切换。这种硬件设计在设备树上要格外注意:不能同时把LVDS和MIPI DSI都设置为okay,否则VOP2驱动在初始化时检测到两个encoder同时绑定同一路VP,会直接报“VP0 has more than one encoder”的错误,整路显示直接挂掉。
正确的做法是把不用的那个节点status改为disabled,并且在pinctrl层面把对应IO口释放掉。比如我用的是MIPI DSI0接5.5寸屏,同时LVDS0不用,设备树里写成:
&lvds0 { status = "disabled"; };如果硬件上非要同时使用MIPI DSI和LVDS,就必须分别绑到不同的VP上,比如MIPI DSI0绑VP1、LVDS0绑VP2,同时保证两个节点的clock和pinctrl不冲突。这个设计在原理图阶段就应该想清楚,到了移植阶段再去飞线基本上只能呵呵了。
3.3 BT1120输出节点与热词“rk3568 配置bt1120输出”
BT1120是一种16位并行视频输出协议,常见于把SoC的显示数据输出到外部的HDMI transmitter芯片或者采集卡。RK3568的VP3专门干这个活儿。我在这个项目里用VP3接BT1120,输出给一个外置高清编码模组做视频预览。设备树里BT1120输出的核心节点是vep6120这类外部编码芯片,但Soc侧的配置主要是两件事:一是把VP3的endpoint连接好,二是配置bt1120的pinctrl,把对应的数据线和时钟信号复用成function。
很多朋友照着网上的patch去配bt1120,结果发现数据不对,画面有严重花屏。这不一定是配置问题,而是BT1120输出是有“伪双沿”特性的,时钟信号的极性和数据建立保持时间要求比较高。RK3568的VP3在输出BT1120时,需要通过device tree里的rockchip,bt1120-clock-invert属性来控制时钟相位,如果外接芯片的采样时钟沿不匹配,就要把这个参数加上:
&vop { rockchip,bt1120-clock-invert = <1>; };这个参数不是标准DRM属性,而是瑞芯微自己加的vendor属性,在通用文档里查不到,但在rk356x.dtsi里能看到定义。如果照着标准写法怀疑人生,那多半就是多了这一步。
3.4 OV5695摄像头与显示复位引脚的“抢IO”问题
热词里还有一条是“rk3568调试ov5695”,这虽然不是显示输出,但我这次移植过程中同样踩了它和显示抢引脚的坑。OV5695是瑞芯微常用的一款500万像素MIPI摄像头,板子上把OV5695的reset引脚和HDMI的HPD引脚分配到了同一个gpio组。默认设备树里两个节点的pinctrl都试图申请这个gpio,导致HDMI热插拔检测失灵,表现为插拔HDMI时系统检测不到,但reboot后第一次开机偶尔能出画面。
这种问题属于典型的多功能引脚复用冲突,排查手段是在内核启动早期打开pinctrl的debugfs,用以下命令对比gpio占用:
mount -t debugfs none /sys/kernel/debug cat /sys/kernel/debug/gpio cat /sys/kernel/debug/pinctrl/pinctrl-rockchip-pinctrl/pinmux-pins如果看到某个pin被camera节点独占,就把OV5695的reset引脚在设备树里改成别的gpio,或者把reset时序改成内核控制而不是pinctrl控制。这个细节和显示移植放一起说,是为了提醒大家:多路显示移植不只是配一个显示节点,周边设备一旦出现IO冲突,现象很可能都被误判成“显示驱动坏了”。
4. 内核DRM驱动适配与补丁合入策略
4.1 从4.19内核到OpenHarmony标准内核的差异
OpenHarmony的kernel/linux仓库对应RK3568默认用的还是Linux 4.19到5.10之间的版本,不同分支有差异。我用的是5.10内核的OpenHarmony分支,原厂SDK的DRM驱动版本在drivers/gpu/drm/rockchip目录下,核心文件是rockchip_drm_vop2.c、rockchip_drm_vop2_regs.h这些。OpenHarmony合入瑞芯微补丁时,通常保留完整的drm框架,但个别宏定义会因为OpenHarmony的kernel config裁剪而缺失。
常见的一个坑是DRM_CONFIG_ROCKCHIP_VOP2_LITE没有开启。RK3568的Kconfig里默认把VOP2和VOP2Lite都编译进内核,但OpenHarmony——特别是标准系统——在某些产品定义里为了减包,裁剪了这个config。结果就是设备树里写了vop节点,内核日志里也能看到vop probe成功,但drm master注册时总缺少对应crtc。排查方法很直接:
zcat /proc/config.gz | grep ROCKCHIP确认CONFIG_ROCKCHIP_VOP2=y、CONFIG_ROCKCHIP_VOP2_LITE=y。如果裁剪了,直接在kernel的defconfig中添加下面两行,重新编译内核:
CONFIG_ROCKCHIP_VOP2=y CONFIG_ROCKCHIP_VOP2_LITE=y4.2 DRM connector轮询与HPD中断注册
多路显示中,HDMI的热插拔检测尤其重要。RK3568的HDMI控制器在DRM里作为一个connector注册,它既有hpd中断,也有轮询机制。设备树里如果hpd-gpios没有配置,驱动会自动启用轮询模式,周期性地读取HDMI的HPD电平。轮询模式下,画面可能出现轻微闪断,因为每次读取GPIO都会触发一次状态机转换。
我的建议是,只要板子上有独立的HPD引脚,就一定要在设备树里配hpd-gpios,并确保对应的pinctrl有上拉设置。调试HDMI HPD时最实用的命令是:
cat /sys/class/drm/card0-HDMI-A-1/status这个节点会实时显示connected/disconnected。如果手动插入HDMI但status不对,可以尝试往/sys/class/drm/card0-HDMI-A-1/status写一个force强制刷新:
echo detect > /sys/class/drm/card0-HDMI-A-1/status注意这不是标准接口行为,不同内核版本支持程度不同,但在瑞芯微的5.10内核上实测可用,很适合快速验证到底是硬件HPD问题还是驱动状态机问题。
4.3 VOP2与开机Logo阶段的显存分配
多路显示的系统起来后,开机Logo阶段是个很容易被忽略但又特别影响体验的环节。OpenHarmony的bootloader阶段由U-Boot负责点亮一块屏(通常是主屏),内核起来之后DRM接手重新做modeset。如果U-Boot和内核的显示顺序不匹配,会出现“内核起来后显示器黑一下才点亮”的现象。
解决思路有两个。一种是在内核cmdline里使用bootloader传参的display参数,让DRM保持U-Boot的显示分辨率。另一种是干脆关掉U-Boot的显示,让内核完全接管,这样虽然开机阶段黑屏,但避免了两级显示的自动协商问题。多路显示移植时我更推荐第二种,因为多屏情况下U-Boot通常只背一路LOGO,内核起来后各屏的resolution和extend逻辑重新编排,如果中间出现一次模式切换,很容易让下游LCD面板控制器进入异常状态。
5. OpenHarmony侧HCS配置与Display HAL调试验收
5.1 display_device.hcs中的多设备声明
设备树搞定以后,就轮到OpenHarmony的hcs配置。这是一个让很多从Linux转过来的开发者费解的东西——设备树明明已经声明了三路显示,为什么OpenHarmony还是只显示一路?核心原因就是display_device.hcs还没有把多设备暴露给HAL层。
hcs路径在产品仓中一般是vendor/你的产品/hdf_config/display/device_info/display_device.hcs,标准内容大概是这样的结构:
root { module = "display"; display_device_config { display_devices { device_0 { deviceId = 0; defaultPowerState = 1; type = 0; nonLocal = 0; inClientMode = 0; } device_1 { deviceId = 1; defaultPowerState = 1; type = 0; nonLocal = 0; inClientMode = 0; } device_2 { deviceId = 2; defaultPowerState = 1; type = 0; nonLocal = 0; inClientMode = 0; } } } }deviceId的顺序并不是随意写的,它需要和内核DRM检测到的connector枚举顺序对应。在没有显式配置fixed connector时,DRM会按照注册顺序给connector编号,通常HDMI先注册为card0-HDMI-A-1,MIPI DSI注册为card0-DSI-1,LVDS注册为card0-LVDS-1。这里的deviceId指的就是HAL层的逻辑设备编号,它和drm connector编号不是同一个值,但内部会通过一个数组映射。我在调试中发现,如果hcs里的设备数量比实际多,HAL层会有一个设备“假注册”,上层能枚举到但它无法完成power on,看看log里有没有“Device power on failed”这样的报错,基本就能定位。
5.2 Display HAL的编译开关与日志调级
OpenHarmony的Display HAL日志分级支持动态debug。默认HAL的日志打印很多,编译时如果发现hilog里只有“Display device 0 create success”而没有device 1/2的创建日志,说明hcs解析上层就把多设备过滤掉了,往往不是驱动问题而是编译配置问题。
在productdefine/产品的json中,有一个display部件的feature项,专门控制编译时是否启用多屏支持,比如:
"display": { "feature": [ "display_device_count=3", "multi_screen=enable" ] }如果没加multi_screen=enable,即使hcs和设备树都配了三路,上层Display Manager也只会按单屏逻辑处理。这个feature参数不同版本名字略有不同,派生产品可能叫display.screen.support或ohos.screen.multiple。最笨但最有效的办法是在你的产品仓里全局搜索display和screen相关的feature字段,逐个确认值。
5.3 SurfaceFlinger与多屏的扩展模式配置
OpenHarmony的图形栈从标准版本开始就引入了类似Android SurfaceFlinger的合成逻辑。在多屏环境下,默认的合成策略是“一块主屏+一块扩展屏”,如果连了三块甚至四块屏,第三块屏通常处于空转状态,就是说connector是connected的,但没有图层映射上去,画面保持黑色。
想让第三屏也参与合成,需要在系统属性中明确每个display设备的合成优先级。常见的地方是在init.rc或产品profile.config里配置:
ohos.boot.display.primary = 0 ohos.boot.display.extended = 1,2注意这里的数字是HAL层的deviceId,不是drm connector序号。配置之后重启系统,再用hidumper查看显示设备列表:
hidumper -s 10 -a "-screen"如果能看到屏幕列表包含三行,每行分别对应device0/1/2,说明HAL层合格。接下来再用SceneBoard or Rosens的截图命令验证每块屏的实际输出内容。
5.4 分辨率与刷新率的modeset踩坑
最后再补一个经验性的坑:多路显示时,不同屏幕的分辨率和刷新率如果相差太大,合成器在跨屏移动窗口时可能出现明显的掉帧。这不是驱动问题,而是合成器在导入不同分辨率的buffer时,需要做格式转换和缩放。RK3568的GPU虽然支持AFBC,但AFBC压缩格式在不同尺寸target之间重新映射时会增加GPU负载。
我的做法是尽量让所有屏幕的刷新率保持一致,比如主屏60Hz,扩展屏也强制60Hz,不要在扩展屏上跑30Hz。另外,如果外接的是4K电视,一定先把HDMI的EDID读取确认,RK3568的HDMI最大支持4K@60,但因为带宽和之引脚复用,4K输出同时又要跑MIPI DSI时,VOP2的带宽可能吃紧。这个可以通过调整drm mode的clock来验证,如果4K+1080p组合下出现画面撕裂,多半是总带宽超了,可以把4K降为2K试试。
6. 多路显示调试的通用排查路径与日志分析
6.1 一套可以按顺序执行的排查清单
多路显示移植过程中,几乎所有怪异问题都可以按下面的顺序排查。这套排查手法我用了很多年,从Linux DRM到OpenHarmony HDF都通用:
先确认硬件链接:所有屏的电源和信号线正常,用示波器或万用表量一下各路供电,尤其注意面板供电时序。很多时候不是软件问题,是屏的VDD没起来,导致DRM检测到时EDID读到的是空的。
内核dmesg过滤rockchip、drm、vop关键字,逐一检查probe是否成功,特别关注“no connector found”或“failed to get edid”。
查看sysfs节点,用/sys/class/drm/card0-*/status确认每个connector的实际连接状态。
确认HAL层通过hidumper -s 10 -a "-screen"能够看到对应设备。
如果HAL层少设备,回到display_device.hcs去看device节点数量和deviceId顺序。
如果HAL层有设备但屏幕无输出,用modetest或hdi_disp工具强制setmode测试,确认是否为modeset阶段失败。
这套顺序看起来平淡无奇,但效率极高。最大的好处是每一层都有明确的输出信息,可以避免两头猜。
6.2 从OpenHarmony日志快速定位问题模块
OpenHarmony中查看显示相关日志的分工比较明确。HDF内核模块日志走dmesg,HAL层走hilog,上层合成器走hilog的Display标签。实用命令组合是这样:
hilog | grep -i display hilog | grep -i rosens hilog | grep -i composer如果dmesg里一切正常但hilog里始终看不到“Device 2 connected”之类的日志,多半就是HAL层没有完成对第三个connector的绑定。这时候赶紧回到hcs去核对device数量。如果hilog里有Device 2 connected,但上层合成器没有为它创建输出表面,就去查上层的ScreenManager配置。
我还遇到过一种情况:日志里显示“Open display device 2 failed: permission denied”,这种诡异错误通常是Selinux权限问题。OpenHarmony默认开启Selinux,多屏场景下,新增的显示设备节点对应的/dev/dri/card0以及/sys/class/drm下的sysfs权限如果没有加入允许域,HAL进程就会被拦截。排查方法是在hilog里看AVC denied关键字,一旦看到类似“avc: denied { ioctl } for pid=xxx comm=render_service”的日志,立刻去vendor/etc/selinux下补充te规则。
6.3 三代屏同显压力测试中的显存与带宽观察
多路显示跑起来后,总带宽是否够用是长期稳定性必须关注的点。RK3568的DDR带宽在标准场景下足够支撑“4K HDMI + 1080p MIPI + 720p BT1120”的组合,但一旦四路全开,还是要注意总显存占用。可以用如下方式实时观察动态显存使用:
cat /sys/kernel/debug/dri/0/summary如果发现VOP的带宽利用率接近90%,建议降低某一路的FrameRate,或者把主屏的AFBC开启。平台默认对HDMI可能不启用AFBC,因为外部显示设备读取AFBC格式可能有兼容问题,但MIPI DSI内屏完全可以开。开启AFBC后,VOP2的带宽占用可以下降约30%,这对多屏同显场景是质的提升。开启方式是在对应的connector节点上加:
panel-timing { ... };其实不完全是这里,准确的说是需要在面板驱动里支持AFBC输出格式,这通常和外接屏控制IC的能力有关。如果面板控制IC不支持AFBC,VOP2会自动回退到线性格式,这也没问题,只是带宽占用会高一些。
7. 写在移植结束后的几条经验
多路显示移植到这个阶段,板子上的画面已经稳定跑起来了:HDMI接4K显示器、MIPI DSI接5.5寸触摸屏、LVDS口通过转接板接了一路工业屏、BT1120的输出到编码模组也能实时看到画面。四路显示同时工作在OpenHarmony上,这个组合在当前社区里不算常见成果,但一旦摸清链路,你会觉得RK3568这套显示系统设计得其实相当工整。
说说我的个人体会。第一,不要一开始就去调那些花哨的合成器参数,先把设备树到DRM的通路确认到每一层都有日志输出。第二,多路显示问题的最大特点就是“现象统一,原因分散”——屏幕上不出来东西,可能是设备树没配对,也可能是HCS少写一条,甚至可能是Selinux拦了权限。按层排查,不要跳步。第三,散热和电源真的不是玄学,四路显示同时输出时,RK3568的核心电压如果拉得不够稳,画面闪烁和带载掉帧的概率会明显上升。我做压力测试时给核心加了散热风扇,再配合调整DVFS策略,稳定性好了很多。
最后再分享一个小技巧:如果多路屏里有一路需要频繁插拔(比如HDMI),建议在OpenHarmony上层做一次热插拔监听,实时刷新扩展屏的surface布局。否则每次插拔都要手动切换显示模式,体验会打折扣。具体做法是利用OpenHarmony的DisplayManager接口监听CONNECT_CHANGE事件,在回调里重新设置扩展屏的显示区域。这个方法代码量不大,但能极大提升多屏方案的实际可用性。