6.3.7. 竖屏横用、横屏竖用¶
ArtinChip 平台支持屏幕旋转,允许竖屏横用或横屏竖用,兼容单 buffer 和双 buffer 的应用程序。
display engine 并不提供旋转功能,旋转由显示驱动调用 graphics engine 实现。支持顺时针 0°/90°/180°/270° 旋转。
6.3.7.1. LCD 适配¶
无论是竖屏横用,还是横屏竖用,在适配 LCD 屏幕时,按照屏幕的真实宽高配置 display-timings 节点即可,不需要在屏端进行旋转。
LCD 屏幕适配可参考屏适配指南章节。
6.3.7.2. device tree¶
屏幕旋转的 device tree 配置集中在 fb0 节点。以 720x1280 屏幕 竖屏横用 为例:
&fb0 {
artinchip,uboot-logo-on=<1>;
rotation-degress = <270>;
height-virtual = <1440>; // 720 * 2
port {
fb0_out: endpoint {
remote-endpoint = <&de0_in>;
};
};
};
Required properties:
rotation-degress
framebuffer 旋转角度,支持顺时针 0°/90°/180°/270° 旋转。
Optional properties:
height-virtual
framebuffer 的内存高度。在设置旋转角度后,表示绘制 buf 的内存高度。
disp-buf-num
显示 buffer 个数,可通过双 buffer 来避免 LCD 撕裂。
小技巧
如果不设置 disp-buf-num 属性,显示 buffer 个数与 height-virtual 绑定。
height-virtual 不设置,height-virtual 缺省等于 height,显示 buffer 个数为 1
height-virtual 设置为 height 的两倍,使用双 framebuffer,显示 buffer 个数自动适配为 2
6.3.7.3. 实现原理¶
屏幕旋转时,显示驱动管理着两种 buffer
上层 GUI 应用使用的绘制 buffer
display engine 使用的显示 buffer
以 竖屏横用 为例,底层的内存使用情况如下所示:
+--------------------+
| |
| 绘制 buf |
| |
+---------+----------+
| |
| |
| |
|显示 buf |
| |
| |
+---------+
这两块 buf 其实是一大块物理连续内存,对应 /dev/fb0,只是横屏和竖屏的 stride 不同,才会有不同的内存布局。
GUI 以横屏的方式在绘制 buf 中绘制好界面,然后下发 ioctl FBIOPAN_DISPLAY
。
显示驱动在接收到 FBIOPAN_DISPLAY
后,调用 graphics engine 将横屏界面旋转为竖屏,并把数据 bitblt 到显示 buf 中。
最后 display engine 将显示 buf 中的数据传送给 LCD 屏幕。
小技巧
在编写 GUI 应用程序时要注意,通过标准接口获得的参数与屏幕的实际宽高是相反的。 GUI 获取到横屏的参数,认为外接了一块横屏才会以横屏的方式绘制界面。
此外,GUI 只能操作到绘制 buf ,显示 buf 对 GUI 来说是透明的。
横屏竖用的原理类似。
6.3.7.4. 场景选择¶
ArtinChip 平台在进行屏幕旋转时,兼容单 buffer 和双 buffer 的应用程序。
以一块 720x1280 的屏幕**竖屏横用**为例。
6.3.7.4.1. 双绘制 buffer 和双显示 buffer¶
&fb0 {
artinchip,uboot-logo-on=<1>;
rotation-degress = <270>;
height-virtual = <1440>; // 720 * 2
port {
fb0_out: endpoint {
remote-endpoint = <&de0_in>;
};
};
};
小技巧
该场景仅需要设置 rotation-degress (旋转角度)和 height-virtual (内存高度),并且 height-virtual 需要为横屏高度的 2 倍。此时 GUI 会使用双 framebuffer 的方式绘制界面,显示 buf 个数自动适配为 2。
内存使用情况如下所示:
+-------------------------+
| 绘制 buf 0 |
+-------------------------+
| 绘制 buf 1 |
+-----+-------------------+
| |
| 显 |
| 示 |
| buf |
| 0 |
| |
+-----+
| |
| 显 |
| 示 |
| buf |
| 1 |
| |
+-----+
GUI 在绘制 buf0 绘制完界面后,底层驱动会把数据旋转到显示 buf0 进行显示,绘制 buf1 同理。
这种使用方式的优缺点如下:
优势
对应用非常友好,不需要修改上层应用,只修改 dts 配置即可达成竖屏横用。
劣势
占用的内存资源多,需要 4 块 buf,有一块绘制 buf 是可以节省下来的。720x1280 的屏幕显示 32 位 RGB 数据时,需要约 14M 的物理连续内存。
小技巧
内存资源来源于 CMA 内存,需要确保 CMA 内存 size 满足需求,不然无法生成 /dev/fb0,详细配置可参看参数配置章节。
6.3.7.4.2. 单绘制 buffer 和双显示 buffer¶
&fb0 {
artinchip,uboot-logo-on=<1>;
rotation-degress = <270>;
disp-buf-num = <2>;
port {
fb0_out: endpoint {
remote-endpoint = <&de0_in>;
};
};
};
小技巧
该场景只有1块绘制 buf, 不需要设置 height-virtual ,但需要设置 disp-buf-num。
内存使用情况如下所示:
+-------------------------+
| 绘制 buf 0 |
+-----+-------------------+
| |
| 显 |
| 示 |
| buf |
| 0 |
| |
+-----+
| |
| 显 |
| 示 |
| buf |
| 1 |
| |
+-----+
GUI 绘制完界面,下发 ioctl FBIOPAN_DISPLAY
,底层驱动会自动切换显示 buf,避免撕裂现象的发生。GUI 应用程序不需要关注显示 buf 的切换。
这种使用方式能避免 LCD 撕裂,并节省一块绘制 buf,但需要修改应用程序。
struct fb_var_screeninfo var = {0};
int zero = 0;
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &var) < 0) {
printf("ioctl FBIOGET_VSCREENINFO fail\n");
return;
}
if (ioctl(fbfd, FBIOPAN_DISPLAY, &var) == 0) {
if (ioctl(fbfd, FBIO_WAITFORVSYNC, &zero) < 0) {
printf("ioctl FBIO_WAITFORVSYNC fail\n");
return;
}
} else {
printf("pan display err\n");
}
6.3.7.4.3. 单绘制 buffer 和单显示 buffer¶
&fb0 {
artinchip,uboot-logo-on=<1>;
rotation-degress = <270>;
port {
fb0_out: endpoint {
remote-endpoint = <&de0_in>;
};
};
};
小技巧
该场景只需要指定旋转角度。
其底层的内存使用情况如下所示:
+-------------------------+
| 绘制 buf 0 |
+-----+-------------------+
| |
| 显 |
| 示 |
| buf |
| 0 |
| |
+-----+
GUI 在绘制 buf0 绘制完界面后,需要下发 ioctl FBIOPAN_DISPLAY
才可以触发屏幕旋转。
注解
display engine 无法确定 CPU 绘制完成的时机,需要应用手动触发更新。
这种方式优劣如下所示:
优势
占用的内存资源最小
劣势
需要手动触发旋转,必须修改应用
只有一块显示 buf,撕裂现象不可避免
struct fb_var_screeninfo var = {0};
int zero = 0;
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &var) < 0) {
printf("ioctl FBIOGET_VSCREENINFO fail\n");
return;
}
if (ioctl(fbfd, FBIOPAN_DISPLAY, &var) == 0) {
if (ioctl(fbfd, FBIO_WAITFORVSYNC, &zero) < 0) {
printf("ioctl FBIO_WAITFORVSYNC fail\n");
return;
}
} else {
printf("pan display err\n");
}