2. 野火demo 部署运行

前面章节讲了野火demo的编译打包,本章将介绍下linux图形显示、野火demo部署运行脚本等。

2.1. Linux图形显示

linux是一个基于命令行的操作系统,图形界面是一个应用程序(而windows的图形界面是操作系统的一部分)。 Linux中图形显示所涉及的知识,简单框图如下所示:

display001
display002

下面我们简单介绍一些图形相关的知识,包括内核驱动、图形API接口、显示管理器、窗口管理器、GUI应用工具,桌面环境等等。

2.1.1. DRM/KMS

Direct Rendering Manager(DRM)子系统用于linux内核显示、图形和合成子系统的管理。 通常使用该框架来控制显示接口和外部显示器(控制分辨率,频率,多屏显示等)、输出画面到显示面板、硬件渲染画面等。

DRM是在内核空间,用户空间使用,通常通过相应的 libdrm 库函数调用, 也可以直接ioctl访问设备文件或者使用sysfs文件DRM驱动通信, 使用OpenGL或Vulkan等图形API的应用程序可以通过这些设备文件与GPU进行交互,以实现硬件加速渲染等。

2.1.2. libdrm

libdrm库,为DRM驱动ioctl提供了包装函数,避免了将内核接口直接暴露给应用程序, 通过libdrm对显示资源进行统一访问,libdrm将命令传递到内核最终由DRM驱动接管各应用的请求并处理。

libdrm是一个底层库,通常被其他图形驱动程序调用,例如Mesa、X、libva和类似项目。

2.1.3. OpenGL

OpenGL是一组专门涉及2D和3D图形的硬件加速渲染的规范, 至于内部具体每个函数是如何实现,将由编写OpenGL库的人自行决定,实际通常是GPU的生产商。 OpenGL API实现通常是C语言,也有其他语言的实现,如Java、Golang和Rust等。

OpenGL ES(OpenGL for Embedded Systems)是适用于嵌入式设备的OpenGL规范,针对Android手机和iPhone等嵌入式设备。

EGL 是一个依赖于平台的API,是OpenGL ES和本地窗口系统之间的一个中间接口层,它主要根据具体系统实现。

2.1.4. Vulkan

Vulkan 是一个低开销、跨平台的2D和3D图形与计算的应用程序接口(API),能够跨平台高效访问GPU。

Vulkan的设计目标是提供一个更轻量级、更高效的图形API,以取代OpenGL等传统的图形API。 作为业内开放标准的现代GPU API,开发人员能够编写可移植到多个不同平台的应用程序。

2.1.5. Mesa

Mesa 也称为Mesa3D和Mesa 3D图形库,是OpenGL、Vulkan和其他图形API规范的开源实现。 Mesa将这些API规范转换为特定于供应商的图形硬件驱动程序。

Mesa项目最初是作为OpenGL规范的开源实现而开始。经过多年来发展,具有跨平台支持、高性能、开源和扩展性等特点,并且该项目已经扩展到实现更多的图形API, 包括OpenGL ES、OpenCL、OpenMAX、VDPAU、VA-API、Vulkan和EGL。

2.1.6. X Window System

大多数基于Linux的发行版都使用 X Window System (X11,或者简称X) , 它是基于客户端-服务器体系结构,可以在远程环境中使用。

X Window系统基于客户端-服务器体系结构,客户端和服务器可以在同一台机器上也可以不在同一台机器上,就需要一个在客户端和服务器之间传递消息的协议。 X11协议就是负责消息传递,当客户端和服务器在同一台机器上时,消息通过UNIX套接字进行交换,不同机器上通过网络(TCP/IP)。

X11是X Window System使用的协议,可扩展的,很容易添加新的功能(而且无需创建新协议或破坏现有客户端), 一些扩展:XRender,Xinput2,XKB,Composite等。

Xorg 是一个开源的图形服务器,基于X Window System协议和一些系统库实现, 提供了基本的窗口管理和图形用户界面功能,是X Window System的服务端实现之一。

Xlib 或者X库是X协议的的一个简单的封装,GTK+、QT等使用该库来创建软件应用程序的图形前端。 XCB是Xlib的替代方案,提供了更简单、更灵活的API,可以帮助开发人员更轻松地创建X应用程序。

DIX(Device Independent X),是X Window System的一个核心组件,DIX包括了X服务器的核心代码,如事件处理、窗口管理、图形渲染等功能。

DDX(Device Dependent X)是X Window System的一个核心组件,它提供了与硬件设备相关的服务, 负责将X Window System的通用接口转换成与硬件设备相关的命令,并处理硬件设备的输入事件和输出事件。 开发人员需要根据具体的硬件设备选择合适的DDX驱动程序。

DRI (Direct Rendering Infrastructure), 是一个允许以安全高效的方式直接访问X Window System下的图形硬件框架。 它包括对x server、几个客户端库和内核(DRM,Direct Rendering Manager)的更改。 DRI最重要的用途是创建快速OpenGL实现,提供硬件加速。

X11的基础构架庞大复杂,这里只是简单说明下,更多说明请查看下参考链接。

2.1.7. Wayland

Wayland 是一种用于显示服务器与其客户端之间通信的协议,不依赖客户端-服务器体系结构,旨在提供一个现代、 安全的Linux和其他类Unix操作系统窗口系统取代X Window system。Weston是Wayland的参考实现,与X11相比,Weston是轻量级的,并且是一个快速的合成器,适用于许多嵌入式和移动端。

Wayland和X server的结构对比简单参考 这里

2.1.8. Qt

Qt是一个跨平台的应用程序开发框架,它提供了一个窗口部件库和一整套UI功能。 Qt可以通过窗口系统显示(x11,wayland),也可以直接显示通过一些插件,如QT EGLFS。

EGLFS是一个平台插件,可以在EGL和OpenGL ES之上运行Qt应用程序,而不需要通过X11或Wayland这样的实际窗口系统。 EGLFS还支持软件渲染窗口,如QWidget的内容使用CPU渲染成图像,然后上传到纹理中,并由插件进行合成。

2.1.9. 窗口管理器(Window Manager)

窗口管理器 是在图形用户界面中,控制窗口位置与外观的软件。 许多窗口管理器是为了桌面环境编写,与桌面环境一同发布的。例如: QT基础上实现的窗口管理器叫KDE,基于GTK基础上实现的窗口管理器是GNOME,但它们不仅仅包含窗口管理器,还是一个桌面环境,提供桌面、菜单等等。 同时也存在不少独立的窗口管理器,如Openbox、Awesome等。

窗口管理器作用就是实现窗口的最大/小化、移动、关闭等, 如果没有窗口管理器,一些GUI应用程序仍可以启动,但它就在屏幕中,不能移动、不能拖拽、没有边框。

2.1.10. 显示管理器(Display Manager)

显示管理器(Display Manager,DM),或者称为“登陆管理器”, 如 sddmlightdm 等, 是一个提供图形登录功能的程序,其作用仅仅只是在开机后,让你输入用户名和密码登陆,然后引导进入桌面。

一些桌面环境自带的显示管理器,如XDM(X Display Manage)、KDM(KDE Display Manager)、GDM(GNOME Display Manager,GDM)等等, 用户也可以自行更改系统的显示管理器。

2.1.11. 桌面环境

桌面环境是一个组件的组合体,提供常见的图形用户界面(GUI,graphical user interface)元素组件, 如图标、工具栏、壁纸和桌面小部件等等,在桌面环境中GUI程序共享图形用户界面。

桌面环境提供了一系列界面一致、操作方式一致的应用程序,使系统以更为友好的方式向用户提供服务。 并且,大多数桌面环境都有自己的一套集成的应用程序和实用程序,包括一个文件资源管理器、桌面搜索、菜单、壁纸、文本编辑器等等。

linux一些流行的桌面环境:GNOME、KDE、xface、LXDE、Budgie等等。

2.2. 鲁班猫板卡图形显示

鲁班猫RK系列板卡运行的系统是基于linux的发布版本,图形图像的显示也是一脉相承,但是一些库依赖具体硬件。

2.2.1. 显示支持

板卡显示需要通过显示控制器,它从存储器获取屏幕的像素颜色的值(帧缓冲区), 并通过硬件接口(如HDMI、MIPI DSI、DisplayPort或者并行接口)将其发送到显示面板。

LubanCat-Zero系列和lubancat-1、2系列(处理器是rk356x)是使用VOP2(Video Output Processor), 该VOP2有6个图层,三个Display Port,支持HDMI,MIPI,EDP,LVDS等接口。具体板卡上支持的显示接口参考下快速使用手册。

显示控制器是在linux的DRM子系统下,用户空间的接口就是Libdrm, 结构图 如下:

display002

libdrm API接口与mpp,rga库使用示例参考下 网盘 的Rockchip文档:Rockchip_Developer_Guide_Linux_Graphics_CN.pdf。

2.2.2. 渲染加速

除了显示控制器,一些SOC还有GPU,可以进行3D渲染硬件加速或者利用GPU的处理能力进行通用编程。

GPU提供了一个基于开放标准的完整图形加速平台,支持2D/3D渲染和GPGPU计算。 Rk356x是使用Mali-G52,支持OpenGL ES1.1/2.0/3.0,Vulkan 以及OpenCL。 Rk3588x系列使用Mali-G610,同样支持OpenGL ES 1.1/2.0/3.1/3.2,Vulkan 1.1,1.2以及OpenCL 1.1,1.2,2.0。

mali gpu的驱动是分成两部分,一部分在linux内核中,另外一部分以二进制文件在用户空间。 其 结构图 简单参考如下:

display002

在linux系统上使用OpenGL ES或者OpenCL接口,需要添加libmali库以及头文件,提供了opengles,egl,opencl接口。

除了GPU,RK系列板卡上还有一个独立的2D硬件加速器–RGA (Raster Graphic Acceleration Unit),可以不占用CPU资源下, 加速点/线绘制,执行图像缩放、旋转、bitBlt、alpha混合等常见的2D图形操作,用户空间使用通过 librga 库。

2.2.3. 鲁班猫系统镜像

鲁班猫RK系列板卡,使用的是瑞芯微rk356x和rk3588x系列处理器,系统是基于Rockchip SDK创建, Rockchip SDK提供了基于Buildroot/Yocto/Debian来创建linux系统, 详细参考下 网盘 中的Rockchip文档。

鲁班猫板卡提供的镜像主要是基于Linux发行版本,如Debian10,Debian11,ubuntu20.04等, 也提供有使用Buildroot构建的系统镜像,还有其他镜像,如OpenWrt系统镜像、安卓和鸿蒙镜像。

提示

鲁班猫提供的Debian/ubuntu系统镜像,使用Rockchip SDK创建, 默认已经安装libdrm、libmali、librga相关库,具体使用可以参考Rockchip文档。

2.3. Lubancat上部署运行Qt程序

在鲁班猫板卡上运行Qt程序,通过QPA(Qt Platform Abstraction)平台抽象显示,不同平台显示可以使用不同QPA插件, 一般Qt将根据平台选择一个默认的QPA插件(可以交叉编译库时configure配置), 也可以设置QT_QPA_PLATFORM环境变量或者-PLATFORM命令行参数选择不同的平台插件。

一般使用平台插件后端有:eglfs(需要OpenGL/EGL图形栈)、linuxfb(帧缓冲区接口)、 wayland和xcb。

linuxfb插件通过Linux的fbdev子系统直接写入帧缓冲区,不支持硬件渲染,显示性能可能会不好。 eglfs是qt自己实现的一个gui显示插件,eglfs使用opengles/egl进行gpu渲染后,直接送给drm去显示。

网盘提供的交叉编译库,提供了EGLFS,XCB,LinuxFB、wayland等平台插件, 下面以部署野火demo为例,简单介绍下这些插件。

2.3.1. LinuxFB

LinuxFB插件通过linux的FBDEV(Framebuffer Device)驱动显示。 使用LinuxFB,需要设置QT_QPA_PLATFORM环境变量,具体查看下:

run_linuxfb.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#! /bin/bash

# 导出qtdemo的安装目录
export APP_DIR=/usr/local/qt-app
# 指定qt库路径
export LD_LIBRARY_PATH=/opt/qt-everywhere-src-5.15.8/ext/lib
# 指定qt插件路径
export QT_QPA_PLATFORM_PLUGIN_PATH=/opt/qt-everywhere-src-5.15.8/ext/plugins

# 指定显示平台插件,通过QT_QPA_PLATFORM 或者-platform命令行选项指定其他设置
export QT_QPA_PLATFORM=LINUXFB
export QT_QPA_FB_DRM=1

# 鼠标设备
#export QT_QPA_FB_HIDECURSOR=1

# 键盘设备
#export QT_QPA_EVDEV_KEYBOARD_PARAMETERS

# 触摸配置
#export QT_QPA_FB_TSLIB=1
#export QT_QPA_EVDEV_TOUCHSCREEN_PARAMETERS=/dev/input/$eventx

# 字体库
# 屏幕旋转
#rotation=0
#export QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0:rotation=$rotation

#export QT_QPA_FB_FORCE_FULLSCREEN=0

echo "start FireApp..."

#运行FireApp
$APP_DIR/FireApp

里面的注释非常清晰,环境变量指定Qt库、插件库、字体等等路径,若不使用则为系统默认。

最最重要的一点就是 export QT_QPA_PLATFORM=linuxfb, 指定Qt以linuxfb的方式显示,输出设备默认为/dev/fb0,最后就是执行FireApp。

由于fbdev在Linux内核中已被弃用,我们使用的是DRM框架下模拟的FB设备,需要设置QT_QPA_FB_DRM环境变量为1。 该插件显示会全屏输出,设置QT_QPA_FB_FORCE_FULLSCREEN环境变量设置为0,将非全屏显示。

屏幕旋转需要在QT_QPA_PLATFORM环境变量中,加上旋转角度(0,90,180,270)即可:

rotation=0
export QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0:rotation=$rotation

更多环境变量设置参考下https://doc.qt.io/qt-5/embedded-linux.html#linuxfb。

2.3.2. EGLFS

使用EGLFS平台插件,需要设置下环境变量QT_QPA_PLATFORM,或者简单测试直接使用命令行指定 -platform eglfs:

# 下面仅仅是示例,一般还需要设置其他环境变量,具体参考下下面run_eglfs.sh脚本中的环境变量
LD_LIBRARY_PATH=/opt/qt-everywhere-src-5.15.8/ext/lib ./FireApp -platform eglfs

Demo目录的run_eglfs.sh,这个脚本则是指定Qt程序以eglfs的方式显示,并且指定使用KMS/DRM后端:

app_bin/run_eglfs.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#! /bin/bash

# 指定qt库路径
export LD_LIBRARY_PATH=/opt/qt-everywhere-src-5.15.8/ext/lib:$LD_LIBRARY_PATH

# 指定qt插件路径
export QT_QPA_PLATFORM_PLUGIN_PATH=/opt/qt-everywhere-src-5.15.8/ext/plugins

# 导出qtdemo的安装目录
export APP_DIR=/usr/local/qt-app

# 指定显示平台插件,通过QT_QPA_PLATFORM 或者-platform命令行选项指定其他设置
export QT_QPA_PLATFORM=eglfs

# 此环境变量强制执行特定的插件,QT_QPA_EGLFS_INTEGRATION 设置为eglfs_kms将使用KMS / DRM后端
export QT_QPA_EGLFS_INTEGRATION=eglfs_kms

# KMS / DRM后端还通过JSON文件支持自定义配置,QT_QPA_EGLFS_KMS_CONFIG 指定配置文件的路径
export QT_QPA_EGLFS_KMS_CONFIG=/usr/local/qt-app/conf/cursor.json

# 指定将current选择一种分辨率与当前模式匹配的模式,QT_QPA_EGLFS_ALWAYS_SET_MODE
#export QT_QPA_EGLFS_ALWAYS_SET_MODE=1

# 默认情况下,KMS后端将使用旧版API,可以启用DRM atomic API,通过将QT_QPA_EGLFS_KMS_ATOMIC环境变量设置为1。
#export QT_QPA_EGLFS_KMS_ATOMIC=1

# 鼠标设备,
# QT_QPA_EVDEV_MOUSE_PARAMETERS
#export QT_QPA_EVDEV_MOUSE_PARAMETERS=abs
#export QT_QPA_EVDEV_MOUSE_PARAMETERS=/dev/input/event2

# hide/show cursor
#export QT_QPA_EGLFS_HIDECURSOR=1

# 键盘设备
# 触摸设备
# eglfs 启用tslib支持,QT_QPA_EGLFS_TSLIB
#export QT_QPA_EGLFS_TSLIB=1

# 字体库
#export QT_QPA_FONTDIR=/usr/share/fonts

# 界面旋转角度 0,90,180,270,(使用触摸屏幕,触摸也要旋转)
#export QT_QPA_EGLFS_ROTATION=-90

$APP_DIR/FireApp

如果运行上面这个脚本出现问题,可以设置下环境变量QT_QPA_EGLFS_DEBUG=1,查看下具体原因,一般而言是需要安装下面软件包:

sudo apt update
sudo apt-get install libegl* libgles*

通过设置环境变量QT_QPA_EGLFS_KMS_CONFIG,来自定义配置文件,例如run_eglfs.sh脚本设置的cursor.json文件内容:

{
"device": "/dev/dri/card0",
"hwcursor": false,
"outputs": [
    { "name": "HDMI1", "mode": "1920x1080" }
]
}

更多参数设置和说明,请参考下https://doc.qt.io/qt-5/embedded-linux.html#display-output。

2.3.3. XCB

Qt程序也可以运行显示,通过桌面窗口系统。 XCB是桌面Linux 平台上使用的X11插件,使用窗口系统显示Qt程序。

例程目录的run_xcb.sh,这个脚本则是指定Qt程序以XCB方式:

app_bin/run_xcb.sh
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#! /bin/bash

# 指定默认的显示器
export DISPLAY=:0
# 导出qtdemo的安装目录
export APP_DIR=/usr/local/qt-app
# 指定qt库路径
export LD_LIBRARY_PATH=/opt/qt-everywhere-src-5.15.8/ext/lib
# 指定qt插件路径
export QT_QPA_PLATFORM_PLUGIN_PATH=/opt/qt-everywhere-src-5.15.8/ext/plugins

# 指定平台,通过QT_QPA_PLATFORM 或者-platform命令行选项指定其他设置
export QT_QPA_PLATFORM=xcb

echo "start FireApp..."
#运行FireApp
$APP_DIR/FireApp

简单测试可以直接使用命令:

LD_LIBRARY_PATH=/opt/qt-everywhere-src-5.15.8/ext/lib ./FireApp -platform xcb

提示

以上部署测试都是通过shell脚本设置运行环境变量,也可以直接添加到系统配置中(直接添加环境变量到/etc/ld.so.conf,/etc/profile.d/xxx.sh)