竖屏横用、横屏竖用
ArtInChip 平台支持屏幕旋转,支持竖屏横用和横屏竖用,兼容单 buffer 和双 buffer 的应用程序。
display engine 并不提供旋转功能,旋转是由显示驱动调用 graphics engine 实现的。支持顺时针旋转 0°/90°/180°/270°。
LCD 适配
无论是竖屏横用,还是横屏竖用,在适配 LCD 屏幕时,按照屏幕的物理宽高配置时序参数即可,不需要将时序参数中的宽高互换。
显示驱动在旋转时会根据旋转角度自动互换宽高。LCD 屏幕适配可参考 屏适配指南 章节。
屏幕旋转
menuconfig
屏幕旋转的角度通过 menuconfig 进行配置,在 Luban-Lite 根目录下执行 scons --menuconfig,进入 menuconfig 的功能配置界面,按如下选择:
Board options → Graphics Support → Graphics support → [*] Display Support → framebuffer rotation degree (0)
如果设置为 0 度,则不调用 graphics engine 进行旋转。
disp_conf 头文件
disp_conf.h
头文件用于配置 GUI 使用的绘制 buf 个数。
FB ROTATION options
drawing buf for GUI, range [1, 2]
#define AIC_FB_DRAW_BUF_NUM 2
2
3
4
小技巧
绘制 buf 的含义可查看后续实现原理章节。这里推荐设置为 2,能满足应用程序在不同平台上的兼容性。
实现原理
在进行屏幕旋转时,显示驱动底层管理着两种 buffer:
- 上层 GUI 应用使用的绘制 buffer
- display engine 使用的显示 buffer
以竖屏横用为例,底层的内存使用情况如下所示:
+--------------------+
| |
| 绘制 buf |
| |
+---------+----------+
| |
| |
| |
|显示 buf |
| |
| |
+---------+
2
3
4
5
6
7
8
9
10
11
12
这两块 buf 在底层是一大块物理连续内存,对应 framebuffer。只是横屏和竖屏的 stride 不同,才会有不同的内存布局。
GUI 以横屏的方式在绘制 buf 中绘制好界面,然后调用 pan_display ioctl。
如果配置了屏幕旋转,底层显示驱动在接收到 pan_display ioctl 后会调用 graphics engine,将横屏的界面旋转为竖屏,并把数据 bitblt 到显示 buf 中。然后 display engine 将显示 buf 中的数据传送给 LCD 屏幕。
小技巧
对于 GUI 应用来说,它通过 ioctl 接口获取到的是横屏的参数。它以为此时外接了一块横屏,就会以横屏的方式绘制好界面。在编写应用程序时要注意,通过 ioctl 接口获得的参数与屏幕的实际宽高是相反的。此外,GUI 只能操作到绘制 buf ,显示 buf 对 GUI 来说是透明的。
横屏竖用的原理类似。
场景选择
ArtInChip 平台在进行屏幕旋转时,兼容单 buffer 和双 buffer 的应用程序。
以下以一块 720x1280 的屏幕竖屏横用为例。
双绘制 buffer 和双显示 buffer
menuconfig 配置:
Board options → Graphics Support → Graphics support → [*] Display Support → [*] Support double framebuffer → framebuffer rotation degree (90)
disp_conf.h 头文件配置:
FB ROTATION options
drawing buf for GUI, range [1, 2]
#define AIC_FB_DRAW_BUF_NUM 2
2
3
其底层的内存使用情况如下所示:
+-------------------------+
| 绘制 buf 0 |
+-------------------------+
| 绘制 buf 1 |
+-----+-------------------+
| |
| 显 |
| 示 |
| buf |
| 0 |
| |
+-----+
| |
| 显 |
| 示 |
| buf |
| 1 |
| |
+-----+
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GUI 在绘制 buf0 绘制完界面后,显示驱动会把数据旋转到显示 buf0 进行显示,绘制 buf1 同理。
这种使用方式的优缺点如下:
优势
对应用非常友好,不需要修改上层应用,只修改 dts 配置即可达成竖屏横用。劣势
占用的内存资源多,需要 4 块 buf,有一块绘制 buf 是可以节省下来的。720x1280 的屏幕显示 32 位 RGB 数据时,需要约 14M 的物理连续内存。
注解
显示 buffer 的双 buf 由 menuconfig 中的 Support double framebuffer 选项使能。
单绘制 buffer 和双显示 buffer
menuconfig 配置:
Board options → Graphics Support → Graphics support → [*] Display Support → [*] Support double framebuffer → framebuffer rotation degree (90)
disp_conf.h 头文件配置:
FB ROTATION options
drawing buf for GUI, range [1, 2]
#define AIC_FB_DRAW_BUF_NUM 1
2
3
注解
该场景需要修改 disp_conf.h 头文件,将绘制 buf 修改为 1 个,并通过 menuconfig 中的 Support double framebuffer
选项使能显示双 buf。
其底层的内存使用情况如下所示:
+-------------------------+
| 绘制 buf 0 |
+-----+-------------------+
| |
| 显 |
| 示 |
| buf |
| 0 |
| |
+-----+
| |
| 显 |
| 示 |
| buf |
| 1 |
| |
+-----+
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GUI 在绘制 buf0 绘制完界面后,在调用 ioctl pan_display 时,底层驱动会自动切换显示 buf,避免撕裂现象的发生,GUI 应用程序不需要关注显示 buf 的切换。
int buf_id = 0;
int zero = 0;
if (mpp_fb_ioctl(fbfd, FBIOPAN_DISPLAY, buf_id) == 0) {
if (mpp_fb_ioctl(fbfd, FBIO_WAITFORVSYNC, &zero) < 0) {
printf("ioctl FBIO_WAITFORVSYNC fail\n");
return;
}
} else {
printf("pan display err\n");
}
2
3
4
5
6
7
8
9
10
11
这种使用方式能避免显示撕裂现象,能节省下一块绘制 buf,但需要修改应用程序。
单绘制 buffer 和单显示 buffer
menuconfig 配置:
Board options → Graphics Support → Graphics support → [*] Display Support → framebuffer rotation degree (90)
disp_conf.h 头文件配置:
FB ROTATION options
drawing buf for GUI, range [1, 2]
#define AIC_FB_DRAW_BUF_NUM 1
2
3
注解
该场景需要修改 disp_conf.h 头文件,将绘制 buf 修改为 1 个,并取消 menuconfig 中的 Support double framebuffer 选。
其底层的内存使用情况如下所示:
+-------------------------+
| 绘制 buf 0 |
+-----+-------------------+
| |
| 显 |
| 示 |
| buf |
| 0 |
| |
+-----+
2
3
4
5
6
7
8
9
10
GUI 在绘制 buf0 绘制完界面后,需要手工调用 ioctl pan_display 才可以触发显示驱动把数据旋转到显示 buf0。
注解
因为 display engine 无法确定 CPU 绘制完成的时机,所以需要应用使用 ioctl pan_display 去手动触发更新。
这种方式优劣如下所示:
优势
占用的内存资源最小劣势
需要手动触发更新,必须修改应用; 只有一块显示 buf,撕裂现象不可避免,只能在一些特定的场景中使用。
int buf_id = 0;
int zero = 0;
if (mpp_fb_ioctl(fbfd, FBIOPAN_DISPLAY, buf_id) == 0) {
if (mpp_fb_ioctl(fbfd, FBIO_WAITFORVSYNC, &zero) < 0) {
printf("ioctl FBIO_WAITFORVSYNC fail\n");
return;
}
} else {
printf("pan display err\n");
}
2
3
4
5
6
7
8
9
10
11