作者:Nick
开始前的几点说明:
1.前言
GUI作为人机交互信息量最大的一种方式,无论在消费还是工业级产品上都大行其道。但同时由于它处在整个系统的核心位置,对外需要通过鼠标、键盘 、显示器进行I/O获取和控制,在内需要负责图形的生成,渲染,整个系统复杂度比较高。本文会从以下几个 方面来介绍GUI子系统:
2.Linux GUI子系统概述
GUI作为人机交互的一种方式,通过其承载的大量信息提高了信息交流的效率。这里我们不介绍鼠标、键盘等输入设备,只介绍输出显示这一子模块。生活中大家最常见的图形化界面估计就是图像化界面的桌面环境,即窗口系统,(如下图的Ubuntu、Xfce等)。
窗口系统一般都具备以下基本功能:
在实现方式上,大部分Linux下的窗口系统都是通过X来响应不同的交互请求及输出到显示器上。因此,整个应用层的GUI结构如下:
因此,在应用层面上,GUI系统的核心部分是X,X的总体功能一句话描述如下:通过指定的协议接受本地或远程的鼠标、键盘需求,并切输出相应的窗口画面到显示设备上。细分来讲,X主要由以下4个组件构成:
. GNOME (GNU Network Object Model Environment);
. KDE (K Desktop Enviroment)
. twm (Tab Window Manager)
. XFCE (XForms Common Environment)
. Display manager: 提供登陆许可环境以获得X Window的控制
我们再从开发者的角度来看一下GUI。以Qt为例,我们在使用Qt组件进行开发时,一般是利用组件中的各种类库,去响应各种事件输入(单双击鼠标、键盘操作)以及给出相应的输出到显示器上。其实际工作的时候,这些工作底层都是通过和window system(X)之间的交互实现的。
这些基本事件的响应,基本的图像单元的绘制,是window system通过封装成一个通用的GUI工具集提供给QT(如X的xlib)。对于Qt而言,这个window system可以是X,也可以是QT自行研发的QWS视窗系统。整个应用层的GUI系统则可看作如下:
3.Linux GUI子系统的构成及工作流程
从应用层深入到内核中去。暂不考虑在linux下的GUI,我们知道,单纯的显示图片的话,整个数据流的走向是这样的:
即按照一定时序时序,将图像信息从内存中输出到显示接口上。若在生成Frame buffer里面的图像数据时不仅通过软件memory处理,还用到了硬件加速的话,数据流则变为如下:
其中accelerate logic就是显卡部分(若是SOC的片内GPU模块,则是通过片内高速总线进行数据交互的,若若是独立显卡,一般是通过pci-e高速串行接口进行数据传输的)。把这个数据流走向放入Linux中,数据流和控制流都需要和用户层进行交互,也就是说,Linux下,必须得有相关的软件驱动给用户层提供相应的API。这也就是DRM(Direct Rendering Manager)和KMS(Kernel Mode Setting)的角色。
Linux原生系统中提供由DRM+KMS构成的DRI(Direct Rendering Infrastructure)中:
Kernel将这两大快的基本API抽出来封装成libdrm供X使用,整个应用层+kernel相关的GUI结构如下图:
整个data flow也替换成了上图的flow1~flow6。关于DRM和KMS的详细介绍我们会放到这个系列的第2篇,这里再提一下涉及到3D的GUI。在需要用到3D图形交互的场景,往往对着实时性要求较高,X中的server/client之间的数据协议解析以及数据交互导致的延时是这种场景不能容忍的。因此DRI是支持这种app越过X直接和内核交流的方式的。比如,Qt中可以直接通过opengl相关类库直接调用libdrm中API控制硬件中的Frambuffer软硬件,此时结构如下:
4.我们能做些什么
在一个常见的系统研发中,子系统中我们能做的基本就是适配,适配不同的CPU、适配不同的OS、适配不同的显示设备。而对于专业的GPU研发团队来说,则需要在现有DRI框架下,为自己的GPU逻辑设计专用的驱动,软硬件工作量庞大。作为一个高性能计算实验室,当然要将一些高速计算融进去。在本系列第3篇,我们将会在Xilinx的Zynq7000系列芯片上,利用其中的PL逻辑资源,设计非常简单的图像处理IP,加速DRM中的Framebuffer数据并通过HDMI显示到LCD上。