DRI1
首先要说,DRI1已经不在考虑使用了,这里说一下它的原理:
DRI1由于当时图形卡内存大小,只有一个屏幕front buffer+back buffer由所有DRI clients和X server使用,front buffer和back buffer就像现在显示系统的双缓冲一样,所有要做渲染操作的实体都直接渲染到back buffer,然后执行swap就更新画面,front变back,back变front。另外所有渲染实体在开始渲染时,都会独占DRM设备,就像互斥锁保护的内存资源,其他的渲染实体就要等,并且渲染实体在释放设备时,所有之前上传的数据(如纹理等)都会丢失,总之,性能不行。
DRI2
DRI2和DRI3现在都在使用,但是DRI3性能更好一些,说一下DRI2原理:
DRI2是进入compositor时代的设计,buffer开始变成离屏buffer,并且离屏buffer可以做直接渲染,DRM也经过了一次大更新;每个DRI client都有自己的back buffer(附带着深度和模版 缓冲区),DRI client在back buffer做完渲染后的swap也不再是直接显示出去,而是变成提交给compositor作为一个compose源,最终的屏幕内容是compositor根据各个源的叠加、透明、边界裁剪得到,并swap到真的front buffer。
为了管理各个DRI client都有自己的back buffer这个事儿,DRM加了新功能,内存管理TTM,但是后来又重写成GEM,这些东西到DRM的事儿里再说。但是有了这个内存管理之后,DRI2 client渲染时不再锁定整个DRM设备,并且在暂停渲染时也不必释放所有显存资源。
DRI3
DRI3 client申请自己的渲染buffer,而不是去调用X server来做申请,这带来了易于改变窗口大小、重复利用之前的buffer等特性(compositor刷帧只需要更新部分缓存内容即可);DRI3放弃了不安全的机遇GEM共享buffer的机制,转而使用DMA的fd来传递,并且DRI3PixmapFromBuffer和DRI3BufferFromPixmap可以完成X server buffer与DMA buffer的转换,同样一块内存,在DRI client和X server之间传递。DRI3还有Present扩展,新鲜程度没有激起我非常强的表述欲,就当没看见了。
作者:杨枫mind
链接:https://www.jianshu.com/p/7f83435b4be2
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Linux graphic subsystem(2)_DRI介绍
作者:wowo?发布于:2015-12-27 22:02 分类:图形子系统
渲染(Render)在电脑绘图中,是指:用软件从模型生成图像的过程。模型是用严格定义的语言或者数据结构对于三维物体的描述,它包括几何、视点、纹理以及照明信息。图像是数字图像或者位图图像。
上面的定义摘录自“百度百科”,它是着重提及“三维物体”,也就是我们常说的3D渲染。其实我们在GUI编程中习以为常的点、线、矩形等等的绘制,也是渲染的过程中,只不过是2D渲染。2D渲染面临的计算复杂度和性能问题没有3D厉害,因此渲染一般都是指3D渲染。
在计算机中,2D渲染一般是由CPU完成(也可以由专门的硬件模块完成)。3D渲染也可以由CPU完成,但面临性能问题,因此大多数平台都会使用单独硬件模块(GPU或者显卡)负责3D渲染。这种通过特定功能的硬件模块,来处理那些CPU不擅长的事务的方法,称作硬件加速(Hardware acceleration),相应的硬件模块,就是硬件加速模块。
众所周知,硬件设备是多种多样的,为了方便应用程序的开发,需要一个稳定的、最好是跨平台的API,定义渲染有关的行为和动作。OpenGL(Open Graphics Library)就是这类API的一种,也是最为广泛接纳的一种。
虽然OpenGL只是一个API,但由于3D绘图的复杂性,它也是相当的复杂的。不过,归根结底,它的目的有两个:
1)对上,屏蔽硬件细节,为应用程序提供相对稳定的、平台无关的3D图像处理API(当然,也可以是2D)。
2)对下,指引硬件相关的驱动软件,实现3D图像处理相关的功能。
另外,openGL的一个重要特性,是独立于操作系统和窗口系统而存在的,具体可以参考后面软件框架相关的章节。
通过第2章的介绍,linux系统中图形有关的软件层次已经呼之欲出,具体如下:
该层次图中大部分的内容,已经在第2章解释过了,这里再补充说明一下:
1)该图片没有体现3D渲染、硬件加速等有关的内容,而这些内容却是当下移动互联、智能化等产品比较关注的地方,也是linux平台相对薄弱的环节。后续会在软件框架有关的内容中再着重说明。
2)从层次结构的角度看,linux图形子系统是比较清晰的,但牵涉到每个层次上的实现的时候,就比较复杂了,因为有太多的选择了,这可归因于“提供机制,而非策略”的Unix软件准则。该准则为类Unix平台软件的多样性、针对性做出了很大的贡献,但在今天这种各类平台趋于整合的大趋势下,过多的实现会导致用户体验的不一致、开发者开发精力分散等弊端,值得我们思考。
3)虽然图形子系统的层次比较多,但不同的人可能关注的内容不太一样。例如对Linux系统工程师(驱动&中间件)而言,比较关注hardware、kernel和display server这三个层次。而对Application工程师来说,可能更比较关心GUI Toolkits。本文以及后续display subsystem的文章,主要以Linux系统工程师的视角,focus在hardware、kernel和display server(可能包括windows manager)上面。
以X window为例,将hardware、kernel和display server展开如下(可从“这里”查看比较清晰的SVG格式的原始图片):
From:?https://upload.wikimedia.org/wikipedia/commons/c/c2/Linux_Graphics_Stack_2013.svg
对于软件架构而言,这张来自维基百科的图片并不是特别合适,因为它包含了太多的细节,从而显得有些杂乱。不过瑕不掩瑜,对本文的描述,也足够了。从向到下,图中包括如下的软件的软件模块:
1)3D-game engine、Applications和Toolkits,应用软件,其中3D-game engine是3D application的一个特例。
2)Display Server
图片给出了两个display server:Wayland compositor和X-Server(X.Org)。X-Server是linux系统在PC时代使用比较广泛的display server,而Wayland compositor则是新设计的,计划在移动时代取代X-Server的一个新的display server。
3)libX/libXCB和libwayland-client
display server提供给Application(或者GUI Toolkits)的、访问server所提供功能的API。libX/libXCB对应X-server,libwayland-client对已Wayland compositor。
4)libGL
libGL是openGL接口的实现,3D application(如这里的3D-game engine)可以直接调用libGL进行3D渲染。
libGL可以是各种不同类型的openGL实现,如openGL(for PC场景)、openGL|ES(for嵌入式场景)、openVG(for Flash、SVG矢量图)。
libGL的实现,既可以是基于软件的,也可以是基于硬件的。其中Mesa 3D是OpenGL的一个开源本的实现,支持3D硬件加速。
5)libDRM和kernel DRM
DRI(Direct Render Infrastructure)的kernel实现,及其library。X-server或者Mesa 3D,可以通过DRI的接口,直接访问底层的图形设备(如GPU等)。
6)KMS(Kernel Mode Set)
一个用于控制显示设备属性的内核driver,如显示分辨率等。直接由X-server控制。
?
上篇文章(Linux graphic subsytem(1)_概述)介绍了linux图形子系统基本的软件框架,以及GUI、Windowing system、3D渲染等基本概念。文中提到了linux DRI(Direct Render Infrastructure)框架,但限于篇幅,没有过多介绍。
蜗蜗觉得,DRI在当前(或者说将来)的linux图形子系统中,有着举足轻重的地位,甚至可以说是新的linux图形框架核心思想的体现。本文将基于linux图形框架的发展历程,从Why、What和How三个角度,介绍DRI框架。
在GUI环境中,一个Application想要将自身的UI界面呈现给用户,需要2个步骤:
1)根据实际情况,将UI绘制出来,以一定的格式,保存在buffer中。该过程就是常说的“Rendering”。
不知道为什么,wowo一直觉得“Render”这个英文单词太专业、太抽象了,理解起来有些困难。时间久了,也就不再执著了,看到它时,就想象一下内存中的图像数据(RGB或YUV格式),Rendering就是生成它们的过程。
通常来说,Rendering有多种表现形式,但可归结为如下几类:
a)2D的点、线、面等绘图,例如,“通过一个for循环,生成一个大小为640x480、格式为RGB888、填充颜色为红色的矩形框”,就是一个2D rendering的例子。
b)3D渲染。该过程牵涉比较复杂的专业知识,这里先不举例了。
c)图片、视频等多媒体解码。
d)字体渲染,例如直接从字库中抽出。
2)将保存在buffer中的UI数据,显示在display device上。该过程一般称作“送显”。
然后问题就来了:这两个步骤中,display server要承担什么样的角色?回答这个问题之前,我们需要知道这样的一个理念:
在操作系统中,Application不应该直接访问硬件,通常的软件框架是(从上到下):Application<---->Service<---->Driver<---->Hardware。这样考虑的原因主要有二:安全性和共享硬件资源(例如显示设备只有一个,却有多个应用想要显示)。
对稍微有经验的软件开发人员(特别是系统工程师和驱动工程师)来说,这种理念就像杀人偿命、欠债还钱一样天经地义。但直到X server+3D出现之后,一切都不好了。因为X server大喊的着:“让我来!”,给出了这样的框架:
先不考虑上面的GLX、Utah GLX等术语,我们只需要理解一点即可:
基于OpenGL的3D program需要进行3D rendering的时候,需要通过X server的一个扩展(GLX),请求X server帮忙处理。X server再通过底层的driver(位于用户空间),通过kernel,访问硬件(如GPU)。
其它普通的2D rendering,如2D绘图、字体等,则直接请求X server帮忙完成。
看着不错哦,完全满足上面的理念。但计算机游戏、图形设备硬件等开发人员不乐意了:请让我们直接访问硬件!因为很多高性能的图形设备,要求相应的应用程序直接访问硬件,才能实现性能最优[1]。
好像每个人都是对的,怎么办?妥协的结果是,为3D Rendering另起炉灶,给出一个直接访问硬件的框架,DRI就应运而生了,如下:
上面好像讲的都是Rendering有关的内容,那送显呢?还是由display server统一处理比较好,因为显示设备是有限的,多个应用程序的多个界面都要争取这有限的资源,server会统一管理、叠加并显示到屏幕上。而这里叠加的过程,通常称作合成(Compositor),后续文章会重点说明。
DRI是因3D而生,但它却不仅仅是为3D而存在,这背后涉及了最近Linux图形系统设计思路的转变,即:
从以前的:X serve是宇宙的中心,其它的接口都要和我对话。
转变为:Linux kernel及其组件为中心,X server(如Wayland compositor等)只是角落里的一员,可有可无。
最终,基于DRI的linux图形系统如下(参考自[4][5]):
该框架以基于Wayland的Windowing system为例,描述了linux graphic系统在DRI框架下,通过两条路径(DRM和KMS),分别实现Rendering和送显两个显示步骤。从应用的角度,显示流程是:
1)Application(如3D game)根据用户动作,需要重绘界面,此时它会通过OpenGL|ES、EGL等接口,将一系列的绘图请求,提交给GPU。
a)OpenGL|ES、EGL的实现,可以有多种形式,这里以Mesa 3D为例,所有的3D rendering请求,都会经过该软件库,它会根据实际情况,通过硬件或者软件的方式,响应Application的rendering请求。
b)当系统存在基于DRI的硬件rendering机制时,Mesa 3D会通过libGL-meas-DRI,调用DRI提供的rendering功能。
c)libGL-meas-DRI会调用libdrm,libdrm会通过ioctl调用kernel态的DRI驱动,这里称作DRM(Direct Rendering Module)。
d)kernel的DRM模块,最终通过GPU完成rendering动作。
2)GPU绘制完成后,将rendering的结果返回给Application。
rendering的结果是以image buffer的形式返回给应用程序。
3)Application将这些绘制完成的图像buffer(可能不知一个)送给Wayland compositor,Wayland compositor会控制硬件,将buffer显示到屏幕上。
Wayland compositor会搜集系统Applications送来的所有image buffers,并处理buffer在屏幕上的坐标、叠加方式后,直接通过ioctl,交给kernel KMS(kernel mode setting)模块,该模块会控制显示控制器将图像显示到具体的显示设备上。
DRM是Direct Rendering Module的缩写,是DRI框架在kernel中的实现,负责管理GPU(或显卡,graphics card)及相应的graphics memory,主要功能有二:
1)统一管理、调度多个应用程序向显卡发送的命令请求,可以类比为管理CPU资源的进程管理(process management)模块。
2)统一管理显示有关的memory(memory可以是GPU专用的,也可以是system ram划给GPU的,后一种方法在嵌入式系统比较常用),该功能由GEM(Graphics Execution Manager)模块实现,主要包括:
a) 允许用户空间程序创建、管理、销毁video memory对象(称作“"GEM objects”,以handle为句柄)。
b)允许不同用户空间程序共享同一个"GEM objects”(需要将不唯一的handle转换为同一个driver唯一的GEM name,后续使用dma buf)。
c)处理CPU和GPU之间内存一致性的问题。
d)video memory都在kernel管理,便于给到display controller进行送显(Application只需要把句柄通过Wayland Compositor递给kernel即可,kernel会自行获取memory及其内容)。
KMS是Kernel Mode Setting的缩写,也称作Atomic KMS,它是一个在linux 4.2版本的kernel上,才最终定性的技术。从字面意义上理解,它要实现的功能比较简单,即:显示模式(display mode)的设置,包括屏幕分辨率(resolution)、颜色深的(color depth)、屏幕刷新率(refresh rate)等等。一般来说,是通过控制display controller的来实现上述功能的。
也许大家会有疑问:这些功能和DRI有什么关系?说实话,关系不大,之所以要在DRI框架里面提及KMS,完全是历史原因,导致KMS的代码,放到DRM中实现了。目前的kernel版本(如4.2之后),KMS和DRM基本上没有什么逻辑耦合(除了代码位于相同目录,以及通过相同的设备节点提供ioctl之外),可以当做独立模块看待。
继续上面的话题,只是简单的display mode设置的话,代码实现不复杂吧?还真不一定!相反,KMS有关的技术背景、软件实现等,是相当复杂的,因此也就不能三言两语说得清,我会在单独的文章中重点分析KMS。
[1]:?https://en.wikipedia.org/wiki/Direct_Rendering_Infrastructure
[2]:?https://en.wikipedia.org/wiki/Wayland_(display_server_protocol)
[3]:?Wayland