6.2.7. 竖屏横用、横屏竖用

zx 平台支持屏幕旋转,支持竖屏横用和横屏竖用,兼容单 buffer 和双 buffer 的应用程序。

display engine 并不提供旋转功能,旋转是由显示驱动调用 graphics engine 实现的。支持顺时针旋转 0°/90°/180°/270°。

6.2.7.1. LCD 适配

无论是竖屏横用,还是横屏竖用,在适配 LCD 屏幕时,按照屏幕的物理宽高配置时序参数即可,不需要将时序参数中的宽高互换。

显示驱动在旋转时会根据旋转角度自动互换宽高。LCD 屏幕适配可参考 屏适配指南 章节。

6.2.7.2. 屏幕旋转

6.2.7.2.2. disp_conf头文件

disp_conf.h 头文件用于配置 GUI 使用的绘制 buf 个数。

/**
 * FB ROTATION options
 */

/* drawing buf for GUI, range [1, 2] */
#define AIC_FB_DRAW_BUF_NUM 2

小技巧

绘制 buf 的含义可查看后续实现原理章节。这里推荐设置为 2,能满足应用程序在不同平台上的兼容性。

6.2.7.3. 实现原理

在进行屏幕旋转时,显示驱动底层管理着两种 buffer

  • 上层 GUI 应用使用的绘制 buffer

  • display engine 使用的显示 buffer

竖屏横用 为例,底层的内存使用情况如下所示:

+--------------------+
|                    |
|      绘制 buf      |
|                    |
+---------+----------+
|         |
|         |
|         |
|显示 buf |
|         |
|         |
+---------+

这两块 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 来说是透明的。

横屏竖用的原理类似。

6.2.7.4. 场景选择

zx 平台在进行屏幕旋转时,兼容单 buffer 和双 buffer 的应用程序,也可指定使用单显示 buffer 还是双显示 buffer。

以下以一块 720x1280 的屏幕竖屏横用为例。

6.2.7.4.1. 双绘制 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

其底层的内存使用情况如下所示:

+-------------------------+
|      绘制 buf 0         |
+-------------------------+
|      绘制 buf 1         |
+-----+-------------------+
|     |
||
||
| buf |
| 0   |
|     |
+-----+
|     |
||
||
| buf |
| 1   |
|     |
+-----+

GUI 在绘制 buf0 绘制完界面后,显示驱动会把数据旋转到显示 buf0 进行显示,绘制 buf1 同理。

这种使用方式的优缺点如下:

  • 优势

    对应用非常友好,不需要修改上层应用,只修改 dts 配置即可达成竖屏横用。

  • 劣势

    占用的内存资源多,需要 4 块 buf,有一块绘制 buf 是可以节省下来的。720x1280 的屏幕显示 32 位 RGB 数据时,需要约 14M 的物理连续内存。

备注

显示 buffer 的双 buf 由 menuconfig 中的 Support double framebuffer 选项使能。

6.2.7.4.2. 单绘制 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

备注

该场景需要修改 disp_conf.h 头文件,将绘制 buf 修改为 1 个,并通过 menuconfig 中的 Support double framebuffer 选项使能显示双 buf。

其底层的内存使用情况如下所示:

+-------------------------+
|      绘制 buf 0         |
+-----+-------------------+
|     |
||
||
| buf |
| 0   |
|     |
+-----+
|     |
||
||
| buf |
| 1   |
|     |
+-----+

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");
}

这种使用方式能避免显示撕裂现象,能节省下一块绘制 buf,但需要修改应用程序。

6.2.7.4.3. 单绘制 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

备注

该场景需要修改 disp_conf.h 头文件,将绘制 buf 修改为 1 个,并取消 menuconfig 中的 Support double framebuffer 选。

其底层的内存使用情况如下所示:

+-------------------------+
|      绘制 buf 0         |
+-----+-------------------+
|     |
||
||
| buf |
| 0   |
|     |
+-----+

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");
}