1. DRM技术介绍

      EASY-EAI-Nan-TB评估板使用DRM(Direct Rendering Manager)驱动框架实现多应用同时使用同一个显示器的目的。

1.1 显示技术简介

      在传统的Linux内核中一般使用fbdev(Frame Buffer)驱动框架管理图形适配器的帧缓冲器,但最初的fb应用层表现得好像单个程序占用了整个显示屏设备,当两个或多个程序试图同时控制相同的硬件时,大多数时候会灾难性地结束。

图片

      使用DRM驱动后,所有应用层通过libdrm或其他库函数来使用显示设备,在内核底层,DRM通过管理Buffer队列渲染图形界面,此时处于用户空间的各个应用层均没有fbdev的概念,也不会争抢显存资源。

图片

1.2 libdrm

      通过libdrm库操作DRM驱动,是Linux应用的标准做法。在libdrm中,又把drm抽象成【CRTC】、【Encoder】、【Connector】三个对象,它们的特点如下:

图片

1.3 plane

      我们从显示设备看到的画面,其实是经过多个plane【叠在一起】合成之后的最终画面。

图片

*注:并不是所有主控都有三层plane,但都会有primary层。想知道某款主控芯片具体有多少个plane,就要去看其对应的规格书。

      Linux默认的显示方案:primary一般用作【UI层】,通常用来显示Qt程序或者桌面系统;overlay一般用作【视频层】,通常用来显示解码器输出的视频画面;cursor一般用作鼠标层,仅用于显示鼠标。

      但有部分的使用场景,需要用UI盖在【视频层】上面,则可以用下方的void set_uiLayer_on_top(bool onTop);接口实现此需求。

      由于直接调用libdrm去控制drm设备的过程过于麻烦且复杂,因此我司针对这种情况封装了一套易用的显示接口,可帮助用户忽略掉复杂的硬件操作,大幅度降低应用程序的开发难度。

1.4 硬件接线说明

      本接口需要配合显示设备共同使用,不同显示设备可以参考【相应】的外设使用说明文档。

      MIPI-DSI屏:《硬件外设接口(软件组件)/显示输出/MIPI-DSI》

  1. 快速上手

      通过串口调试ssh调试,进入开发板后台,运行lsb_release -a命令,可查看系统版本:

图片

    1. 开发环境准备

如果您初次阅读此文档,请阅读《入门指南/开发环境准备/Easy-Eai编译环境准备与更新》,并按照其相关的操作,进行编译环境的部署

在PC端Ubuntu系统中执行run脚本,进入EASY-EAI编译环境,具体如下所示。

cd ~/develop_environment
./run.sh 2404

图片

* 开发环境版本要与开发板【正在运行】的系统版本【一致】。

* 开发板是其它版本的固件,可以修改对应的./run.sh参数(如2204),进入到对应的编译环境;也可以把开发板烧录成与编译环境匹配的固件,具体操作可参考《固件烧录与更新》

2.2 源码下载以及例程编译

      在EASY-EAI编译环境下创建存放源码仓库的管理目录:

cd /opt
mkdir EASY-EAI-Toolkit
cd EASY-EAI-Toolkit

      通过git工具,在管理目录内克隆远程仓库

git clone https://github.com/EASY-EAI/EASY-EAI-Toolkit-1126B.git

图片

注:

* 此处可能会因网络原因造成卡顿,请耐心等待。

* 如果实在要在gitHub网页上下载,也要把整个仓库下载下来,不能单独下载本实例对应的目录。

      进入到对应的例程目录执行编译操作,具体命令如下所示:

cd EASY-EAI-Toolkit-1126B/Demos/media-display/
./build.sh cpres

注:

* 由于依赖库部署在板卡上,因此交叉编译过程中必须保持/mnt挂载。

图片

注:

* 若使用的是rockit的固件,需要在板卡中补充一下下列库:

sudo apt-get update && sudo apt-get install libdrm-dev -y

2.3 例程运行

      通过串口调试ssh调试,进入板卡后台,定位到例程部署的位置,如下所示:

cd /userdata/Demo/media-display

图片

      例程运行命令如下所示:

./test-display

2.4 运行效果

      例程运行效果如下所示:

图片

API的详细说明,以及API的调用(本例程源码),详细信息见下方说明。

3. 显示接口API说明

3.1 引用方式

      EASY EAI api库位于本仓库的easyeai-api目录中。为方便客户在本地工程中直接调用我们的EASY EAI api库,此处列出工程中需要链接的库以及头文件等,方便用户直接添加。

描述CMake写法Makefile写法
api.cmake${media_root}/display/api.cmake
${media_root}/rga/api.cmake
头文件目录${DISPLAY_INCLUDE_DIRS}
${RGA_INCLUDE_DIRS}
-I ../../easyeai-api/media/display
-I ../../easyeai-api/media/rga
源文件目录${RGA_SOURCE_DIRS}../../easyeai-api/media/rga
库文件目录${DISPLAY_LIBS_DIRS}../../easyeai-api/media/display
库链接参数${DISPLAY_LIBS}
${RGA_LIBS}
-ldisplay -ldrm -lrga -lpthread

      关于用到的RGA部分API,源代码路径为EASY-EAI-Toolkit-1126B/easyeai-api/media/rga/用户可通过源代码了解接口实现,甚至可对源码进行修改。

      而用于显示的部分接口,已经被封装成易用的API接口,相关的接口可以直接查阅EASY-EAI-Toolkit-1126B/easyeai-api/media/display/display.h。具体用法见下方描述:

3.2 初始化plane

      函数原型如下所示。

int disp_init();  //初始化overlay层
int uiLayer_init(); //初始化primary层

      具体介绍如下所示。

函数名:display()、uiLayer_init();
头文件easyeai-api/media/display/display.h
输入参数
返回值0:初始化成功
-1:屏幕硬件初始化失败
-2:plane初始化失败
注意事项
  1. 默认按全屏分辨率去初始化。
  2. 如果有Qt程序,它会去接管primary层。则不允许单独调用uiLayer_init()

3.3 向对应plane提交图像数据

      向overlay层提交数据,函数原型如下所示。

void window_commit(void *ptr/*default BGR888*/, int imgWidth, int imgHeight, int imgRotation); 
函数名:window_commit()
头文件easyeai-api/media/display/display.h
输入参数*ptr:待提交图像的数据指针
imgWidth:待提交图像的宽度
imgHeight:待提交图像的高度
imgRotation:需要把待提交图像旋转成什么角度,仅支持:0;
HAL_TRANSFORM_ROT_90;
HAL_TRANSFORM_ROT_180;
HAL_TRANSFORM_ROT_270。
返回值
注意事项
  1. 需要已调用disp_init()对屏幕进行初始化。
  2. 此接口内部有调用rga,需要与其它使用rga的接口搭配互斥锁使用。

      向primary层提交数据,函数原型如下所示。

void uiLayer_commit(void *ptr/*default BGR888*/, int imgWidth, int imgHeight);

      具体介绍如下所示。

函数名:uiLayer_commit()
头文件easyeai-api/media/display/display.h
输入参数*ptr:待提交图像的数据指针
imgWidth:待提交图像的宽度
imgHeight:待提交图像的高度
返回值
注意事项
  1. 需要已调用uiLayer_init()对屏幕进行初始化。
  2. 此接口内部有调用rga,需要与其它使用rga的接口搭配互斥锁使用。
  3. 如果有Qt程序,它会去接管primary层。则不允许单独调用uiLayer_commit。

      把图像commit上屏幕后,效果如下所示(会进行拉伸):

图片

3.4 释放单层资源

      函数原型如下所示。

void disp_release();
void uiLayer_release();

     具体介绍如下所示。

函数名:disp_release()/uiLayer_release()
头文件easyeai-api/media/display/display.h
输入参数
返回值
注意事项

3.5 释放所有资源

      函数原型如下所示。

void disp_exit(void);

      具体介绍如下所示。

函数名:disp_exitt()
头文件easyeai-api/media/display/display.h
输入参数
返回值
注意事项

3.6 把UI层(primary)置顶

     函数原型如下所示。

void set_uiLayer_on_top(bool onTop);

      具体介绍如下所示。

函数名:set_uiLayer_on_top()
头文件easyeai-api/media/display/display_pro.h
输入参数onToptrue:把UI层置顶
false:把UI层置底
返回值
注意事项

3.7 设置层间Alpha混合模式

      函数原型如下所示。

void set_alpha_blend_mode(int mode);

     具体介绍如下所示。

函数名:set_alpha_blend_mode()
头文件easyeai-api/media/display/display_pro.h
输入参数mode0:采用预乘模式混合
1:采用非预乘模式混合
返回值
注意事项

4. API测试案例

      示例代码路径为EASY-EAI-Toolkit-1126B/Demos/media-display/test-display.cpp

      以下为各个API的实际用例。

int main(int argc, char *argv[])
{
    if(disp_init()){
        fprintf(stderr, "display区域始化失败\n");
        return -2;        
    }
    printf("成功初始化display区域,正在显示BGR测试图像...\n");
    
    // 加载图像数据
    size_t image_size = 0;
    char *pbuf = load_test_image(&image_size);
    if (!pbuf) {
        return -1;
    }

    // 把图像显示在窗口里[采用拉伸缩放]
    window_commit(pbuf, 720, 1280, 0);
    printf("按Ctrl+C退出\n");
    
    // 保持显示
    while (1) {
        // 可以考虑在这里更新图像内容
        sleep(1);
    }

    free(pbuf);
    // disp_release(); //disp_exit();里已经包含了disp_release();动作

    disp_exit();
    
    return 0;
}

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐