深度探索Linux操作系统 —— Linux图形原理探讨3

简介: 深度探索Linux操作系统 —— Linux图形原理探讨

深度探索Linux操作系统 —— Linux图形原理探讨2:https://developer.aliyun.com/article/1598096

2、渲染Pipleline

    与 2D 渲染相比,3D 渲染要复杂得多。就如同有些复杂的绘画过程,要分成几个阶段一样,OpenGL 标准也将 3D 的渲染过程划分为一些阶段,并将由这些阶段组成的这一过程形象地称为 Pipleline

   应用程序建立基本的模型包括在对象坐标中的顶点数据、顶点的各种属性(比如颜色),以及如何连接这些顶点(如是连接成直线还是连接为三角形),等等,统一存储在顶点缓冲中,然后作为 Pipeline 的输入,这些输入就像原材料一样,经过 Pipeline 这台机器的加工,最终生成像素阵列,输出到后缓冲的 BO 中。


   OpenGL 的标准规定了一个参考的 Pipeline,但是各家 GPU 的实现与这个参考还是有很多差别的,有的 GPU 将相应的阶段合并,有的 GPU 将个别阶段又拆分了,有的可能增加了一些阶段,有的又砍了一些阶段。但是,大体上整个过程如图 8-7 所示。

1518b2fae7e3495e118e9bc2a71ec440.png



(1)顶点处理


   OpenGL 使用顶点的集合来定义或逼近对象,应用程序建模实际上就是组织这些顶点,当然也包括顶点的属性。Pipeline 的第一个阶段就是顶点处理(vertex operations),顶点处理单元将几何对象的顶点从对象坐标系变换到视点坐标系,也就是将三维空间的坐标投影到二维坐标,并为每个顶点赋颜色值,并进行光照处理等。


(2)图元装配


   显然,很多操作处理是不能以顶点单独进行处理的,比如裁减、光栅化等,需要将顶点组装成几何图形。Pipeline 将处理过的顶点连接成为一些最基本的图元,包括点、线和三角形等。这个过程成为图元装配( primitive assembly )。


   任何一个曲面都是多个平面无限逼近的,而最基本的是三点表示一个平面。所以,理论上,GPU 将曲面都划分为若干个三角形,也就是使用三角形进行装配。但是也不排除现代 GPU 的设计者们使用其他的更有效的图元,比如梯形,进行装配。


(3)光栅化


   我们前文提到,图形是使用像素阵列来表示的。所以,图元最终要转化为像素阵列,这个过程称为光栅化(rasterization),我们可以把光栅理解为像素的阵列。经过光栅化之后,图元被分解为一些片断(fragment),每个片段对应一个像素,其中有位置值(像素位置)、颜色、纹理坐标和深度等属性。


(4)片段处理


   在 Pipeline 更新帧缓冲之前,Pipeline 执行最后一系列的针对每个片段的操作。对于每一个片断,首先进行相关的测试,比如深度测试、模板测试。以深度测试为例,只有当片段的深度值小于深度缓存中与片段相对应的像素的深度值时,颜色缓冲、深度缓冲中的与片段相对应的像素的值才会被这个片段中对应的信息更新。


   Pipeline 可全部由软件实现(CPU),也可全部由硬件实现(GPU),或者二者混合,这完全取决于 GPU 的能力。对于 GPU 没有 3D 计算能力的,则 Pipeline 完全由软件实现。比如,Mesa 中的 _tnl_default_pipeline,即是一个纯软件的 Pipeline,Pipeline 中的每一个阶段均由 CPU 负责渲染:


   对于 3D 计算能力比较强的 GPU,如 ATI 的 GPU,Pipeline 完全由 GPU 实现。


   而有些 GPU 能力不那么强大,那么 CPU 就要参与图形渲染了,因此,Pipeline 一部分由 CPU 实现,一部分由 GPU 实现。


   以 Intel GPU 为例,Pipeline 的渲染过程大致如图 8-8 所示。


f275ddb938745c57568f1603ab4cf3cb.png


   1)首先,应用程序通过 glVertex 等 OpenGL API 将数据写入用户空间的顶点缓冲。


   2)当程序显示调用 glFlush,或者,当顶点缓冲满时,其将自动激活 glFlush,glFlush 将启动 Pipeline。以 intel_pipeline 为例,Pipeline 的前几个阶段是 CPU 负责的,因此,所有的输入来自用户空间的顶点缓冲,计算结果也输出到用户空间的顶点缓冲;在最后的 _intel_render_stage 阶段,按照 intel GPU 的要求,从公共的顶点缓冲中读取数据,使用 intel GPU 的 3D 驱动中提供的函数,重新组织一个符合 intel GPU 规范的顶点缓冲。


   3)glFlush 调用 3D 驱动中的函数 intel_glFlush 。intel_glFlush 首先将顶点缓冲和批量缓冲复制到内核空间对应的 BO,实际上就是相当于复制到了 GPU 的显存空间,这样 GPU 就可以访问了。然后,内核的 DRM 模块将按照 Intel GPU 的要求建立一个环形缓冲区(ring buffer)。


   4)准备好环形缓冲区后,内核中的 DRM 模块将环形缓冲区的信息,如缓冲区的头和尾的地址分别写入 GPU 的寄存器 Head Offset 和 Tail Offset 等。当 DRM 向寄存器 Tail Offset 写入数据时,将触发 GPU 读取并执行环形缓冲区中的命令,启动 GPU 中的 Pipeline 进行渲染。最后,GPU 的 Pipepline 将生成的像素阵列输入到帧缓冲。


建立数学模型


1.启动 Pipeline

在建模后,应用将顶点数据存入了顶点缓冲,加工需要的原材料已经准备好了,接下来就需要开动 Pipeline 这台加工机器了。那么,这个机器什么时候运转起来呢?通常是在程序中显示调用函数 glFlush 时。当然,一旦顶点缓冲已经充满了,也会自动调用 glFlush。读者可能有个疑问:我们编写程序时,有时并没有显示调用 glFlush 啊?没错,那是通常情况下,我们使用的都是启用了双缓冲的 OpenGL ,即前缓冲和后缓冲。对于启用双缓冲的 OpenGL 程序,OpenGL 规定,当程序在后缓冲渲染完成后,请求交换到前后缓冲时,使用 OpenGL 的 API glXSwapBuffers,而实际上,函数 glXSwapBuffers 已经替我们调用了 glFlush。


2.Pipeline 中的软件计算阶段

所谓的软件计算阶段,是指计算过程是由 CPU 来负责的。CPU 从上下文中获取上个阶段的状态信息,进行计算,然后将计算结果保存到上下文中,作为下一个阶段的输入。上下文的数据抽象为结构体 TNLcontext,其中非常重要的一个成员是结构体 vertex_buffer 。


3.Pipeline 中 GPU 相关的阶段

很难要求所有厂家的 GPU 都按照一个标准设计,所以在启动 GPU 中的硬件阶段之前,需要将 OpenGL 标准规定的标准格式的顶点缓冲中的数据按照具体的 GPU 的要求组织一下,然后再传递给 GPU 。


4.复制顶点数据和批量数据到内核空间

在 Pipeline 的软件阶段,所有阶段的计算结果都保存在用户空间,为了启动 Pipeline 的硬件阶段,显然需要将这些数据复制到内核空间的 BO,这样 GPU 才可以访问。_mesa_flush 最后将调用 3D 驱动中的函数 _intel_batchbuffer_flush 进行复制。


5.启动 GPU 中的 Pipeline

将数据复制到内核空间的BO后,接下来就需要通知GPU来读取这些数据,并执行GPU中的Pipeline。以Intel GPU为例,其规定需要将批量数据组织到一个环形缓冲区中,然后GPU从环形缓冲区中读取并执行命令,如图8-9所示。


a97b888109449d54ca0561d67969488b.png


   环形缓冲区也只是从内存中分配的一块用于显存的普通存储区,所以,当内核中的DRM模块组织好其中的数据后,GPU并不会自动到环形缓冲区中读取数据,而是需要通知GPU来读取。


   那么内核如何通知GPU呢?熟悉驱动开发的读者应该比较容易猜到,方法之一就是直接写GPU的寄存器。Intel GPU为环形缓冲区设计了专门的寄存器,典型的包括Head Offset、Tail Offset等。其中寄存器Head Offset中记录环形缓存区中有效数据的起始位置,寄存器Tail Offset中记录的则是环形缓存区中有效数据的结束位置。


   一旦内核中的DRM模块向寄存器Tail Offset中写入数据,GPU就将对比寄存器Head Offset和Tail Offset中的值。如果这两个寄存器中的值不相等,那么就说明环形缓冲区中已经存在有效的命令了,GPU中的命令解析单元(Command Parser)通过DMA的方式直接从环形缓冲区中读取命令,并根据命令的类型,定向给不同的处理引擎。如果是3D命令,则转发给GPU中的3D引擎;如果是2D命令,则转发给GPU中的BLT引擎;如果是控制显示的,则转发给Display引擎;等等。


3、交换前缓冲和后缓冲

   应用程序绘制完成后,需要将后缓冲交换(swap)到前缓冲,其中有三个问题需要考虑。


(1)谁来负责交换

   如果应用自己负责将后缓冲更新到前缓冲,那么当有多个应用同时更新前缓冲时如何协调?显然将交换动作交给更擅长窗口管理的X服务器统一协调更为合理。


   如果X服务器开启了复合扩展,更需要知道应用已经更新前缓冲了,因为X服务器需要通知复合管理器重新合成前缓冲。


   综上,应该由X服务器来负责交换前后缓冲。


   对于GPU支持交换的情况,X服务器通过2D驱动请求GPU进行交换。否则X服务器只能将前缓冲和后缓冲的BO映射到用户空间,使用CPU逐位复制。


(2)交换的时机

   与2D应用不同,3D程序通常涉及复杂的动画和图像,如果显示控制器正在扫描前缓冲的同时,X服务器更新了前缓冲,那么可能会导致屏幕出现撕裂(tearing)现象。所谓的撕裂就是指本应该分为两桢显示在屏幕上的图像同时显示在屏幕上,上半部分是一帧的上半部分,而下半部分是另外一帧的下半部分,情况严重的将导致屏幕出现闪烁(flicker)。


   以一个刷新率为60Hz的显示器为例,显示控制器每隔1/60秒从前缓冲读取数据传给显示器。每开始新的一帧扫描时,显示控制器都从前缓冲的最左上角的点,即第一行的第一个点开始,逐行进行扫描,直到扫描到图像右下角的点,即最后一行的最后一个点。经过这样一个过程之后,就完成了一帧图像的扫描。然后显示控制器回溯(retrace)到第一行的第一个点的位置,等待下一帧扫描开始,如图8-10所示。


d5e8daa6845f0a8ec4ba1ecd925227f1.png

   更新一帧图像远不需要1/60秒,从更新完最后一行的最右侧一个点,到开始扫描下一帧之间的间隙被称为垂直空闲(vertical blank),简称为"vblank"。显然,如果在vblank这段时间更新前缓冲,就不会导致上述撕裂和闪烁现象的出现了。


(3)交换的方法

   交换后缓冲和前缓冲通常有两种方法:第一是复制,在绘制完成后,X服务器将后缓冲中的数据复制到前缓冲,如图8-11所示。

97e887311c1f89927d879fbb09ff19b6.png


   但是这种方法效率相对较低,所以开发者们设计了页翻转模式(page flip)。页翻转模式不进行数据复制,而是将显示控制器指向后缓冲。后缓冲与前缓冲的角色进行互换,后缓冲摇身一变成为前缓冲,显示控制器将扫描后缓冲的数据到屏幕,而原来的前缓冲则变成了后缓冲,应用程序在前缓冲上进行绘制,如图8-12所示。

5608c7882508c6803bb2e3e303823c2f.png



   页翻转模式虽然效率高,但也不是所有的情况都适用。典型的,当一个应用处于全屏模式时,可以采用页翻转模式互换前缓冲和后缓冲。但是这对于使用复合管理器的图形系统来说,其实已经大大的提升效率了,因为复合管理器控制着整个屏幕的显示,所以复合管理器可以使用页翻转模式交换前缓冲和后缓冲。


  1. 应用发送交换请求
  2. X服务器处理交换请求

五、Wayland

   将所有图形全部交由 X 服务器绘制的这种设计,在以2D应用为主的时代,一切还相安无事。但是随着基于3D的应用越来越多,效率问题逐渐凸显出来。与2D程序不同,3D程序的数据量要大得多,所以应用与X服务器之间需要传递大量的数据。设想一下几个人过独木桥和万人争过独木桥的场景,显然,X曾经引以为傲的设计——通过网络通信的客户/服务器架构,成为性能的瓶颈。


   为了解决这个问题,X的开发者们设计了DRI机制,即应用程序不再将绘制图形的请求发送给X服务器,而是由应用程序自行绘制。这种设计与X最初的设计原则虽然有些格格不入,但是从某种程度上确实缓解了3D应用的效率问题。


   但是,好景不长,人们逐渐不再满足于看上去比较“呆板”的图形用户界面,人们追求具有更华丽的3D特效的图形用户界面,比如窗口弹出和关闭时的放大/缩小动画、窗口之间的透明等。于是开发者们为 X 设计了复合( Composite ) 扩展,并仿效窗口管理器设计了一个所谓的复合管理器(Composite Manager)来实现这些效果。


   我们以2D绘制过程为例来简要地看一下什么是复合扩展以及复合管理器,如图8-13所示。

eeae66e9e84c5bd77e4e1ca6989fab80.png



   开启复合扩展后,最大的一个区别是所有的窗口都不再共享一个前缓冲,而是有了各自的离屏区域。X服务器在各个窗口的离屏区域上进行绘制。在绘制好后,X服务器向另外一个特殊的应用复合管理器(Composite Manager)发出Damage通知。然后由复合管理器请求X服务器对这些离屏的窗口的缓冲区进行合成,最后请求X服务器显示到前缓冲。


   在这个复合过程中,就是制造那些绚丽效果的地方。比如在合成的过程中,我们使用如图8-14的方法,就可以使窗口看起来是以放大效果出现的。


bd7f46e5587db69c96a8fcdb7d262ed6.png


   使用复合管理后,绚丽的效果有了,但是仔细观察图8-13会发现,X被人诟病的基于网络通信的客户/服务器模式的问题又变得严重了。除了X服务器和应用之间的通信外,为了进行合成,X服务器和复合管理器之间又多了一层通信关系。


   事实上,在DRI的演进过程中,X不断被拆分和瘦身,开发者从X中移除了大量与渲染有关的功能到内核和各种程序库中。慢慢的,人们发现,X所做的事情已经大为减少,替代X已经不是一项不可能的任务。于是一部分开发者开始尝试为Linux开发替代X的窗口系统,Kristian Høgsberg提出了Wayland。事实上,这一个过程迟早要发生的,即使不是Wayland,也会涌现出如Yayland、Zayland等。


   Wayland并不是一个全新的事物,它是站在X这个巨人的肩膀上,在X的不断演进中进化而来的。虽然从名字上看,Wayland与X没有丝毫相干,但是实际上两者的联系可谓千丝万缕。Wayland的开发者Kristian Høgsberg曾经是X的DRI

的主要开发者之一。套用一句奔驰的广告语,“经典是对经典的继承,经典是对经典的背叛”,Wayland去掉了X的客户/服务器架构,但是继承了X为提高绘制效率不懈努力的成果:DRI。除了逻辑上设计上不同外,Wayland基本的渲染原理与我们前面讨论的2D和3D的渲染原理完全相同。基本上,基于Wayland的图形架构如图8-15所示。


357a661ac0f8e11a4c16e9d767c6776d.png


   Wayland本身是一个协议,其具体的实现包括一个合成器(Compositor)以及一套协议实现库。当然,图形库为了与合成器进行通信,在图形库中需要加入Wayland协议的相关模块,也就是图8-15中的Wayland backend部分,当然这些都可以基于Wayland提供的库,而不必从头再将wayland协议实现一遍。


   在Wayland下,所有的图形绘制完全由应用自己负责。其绘制过程与我们前面讨论的2D和3D的绘制过程完全相同,只不过2D的绘制部分也搬到图形库中了,绘制动作与合成器没有丝毫关系。而在绘制后,应用将前缓冲和后缓冲进行对调,并向合成器发送Damage通知,当然颜色缓冲不一定是前后两个,在具体实现中,有的图形系统可能使用3个、4个甚至更多。在收到Damage通知后,合成器将应用的前缓冲合成到自己的后缓冲中。而合成器的这个合成过程,与普通应用的绘制过程并无本质区别,也是通过图形库完成。


   在合成完成后,合成器对调后缓冲与前缓冲,并设置显示控制器指向新的前缓冲,即原来的后缓冲。此前的前缓冲作为新的后缓冲,并作为合成器下一次合成的现场;而原来的后缓冲则变成现在的前缓冲,用于显示控制器的扫描输出。

相关实践学习
在云上部署ChatGLM2-6B大模型(GPU版)
ChatGLM2-6B是由智谱AI及清华KEG实验室于2023年6月发布的中英双语对话开源大模型。通过本实验,可以学习如何配置AIGC开发环境,如何部署ChatGLM2-6B大模型。
目录
相关文章
|
3月前
|
Ubuntu 物联网 Linux
从零安装一个Linux操作系统几种方法,以Ubuntu18.04为例
一切就绪后,我们就可以安装操作系统了。当系统通过优盘引导起来之后,我们就可以看到跟虚拟机中一样的安装向导了。之后,大家按照虚拟机中的顺序安装即可。 好了,今天主要介绍了Ubuntu Server版操作系统的安装过程,关于如何使用该操作系统,及操作系统更深层的原理,还请关注本号及相关圈子。
|
3月前
|
监控 Ubuntu Linux
什么Linux,Linux内核及Linux操作系统
上面只是简单的介绍了一下Linux操作系统的几个核心组件,其实Linux的整体架构要复杂的多。单纯从Linux内核的角度,它要管理CPU、内存、网卡、硬盘和输入输出等设备,因此内核本身分为进程调度,内存管理,虚拟文件系统,网络接口等4个核心子系统。
301 0
|
3月前
|
Unix 物联网 Linux
都什么年代了,你还不懂啥是Linux操作系统
至于华为鸿蒙操作系统是不是独树一帜,这个留给各位阅读本文的网友们来讨论
109 0
|
3月前
|
安全 Linux iOS开发
linux属于什么操作系统
Linux是一种自由和开放源代码的操作系统,具有高度的灵活性和可定制性。与常见的操作系统如Windows和macOS相比,Linux具有自由、安全和稳定等优势。Linux已广泛应用于服务器、桌面电脑、超级计算机和嵌入式设备等领域,并且在未来的发展前景广阔。由于其自由和开放源代码的特性,Linux还促进了计算机技术和社区的发展,为全球的计算机用户提供了更多的选择和可能性。
|
3月前
|
安全 Ubuntu Unix
关于Linux操作系统,你必须要知道的事
我们可以看到无论是Debian还是Buildroot都有各自的特点,为客户提供了更大的选择空间和灵活性,大家可以根据自己的需求选择合适的版本来满足终端用户的体验和功能需求。从平技术将会一直关注更多更安全、灵敏、易于开发的Linux版本,做好适配工作,不断为客户带来“简单开发、方便应用”的使用体验。
|
3月前
|
安全 Ubuntu Linux
如何安装Linux操作系统?
此时,您可以选择重新启动计算机,然后从硬盘上的Linux系统启动。以上是一个大致的安装过程。请注意,不同的Linux发行版可能会在细节上有所差异,因此在进行安装之前,请确保您阅读并理解了相应发行版的安装指南或文档。
|
3月前
|
Ubuntu Linux 开发者
Linux发行版比较:选择适合你的操作系统
在做出选择之前,建议您先在虚拟机或双系统环境中尝试不同的发行版,根据自己的体验和需求做出决策。选择适合自己的Linux发行版是一个个人化和主观的过程,最重要的是找到符合自己需求和喜好的发行版,让您在使用Linux系统时感到舒适和方便。
|
3月前
|
Ubuntu Unix Linux
玩机强化技能,动手安装Ubuntu Linux操作系统
(13)Ubuntu重启过程中,你将在关机画面中看到提示文字“Please remove the installation medium, then press ENTER:”,按下“Enter”键即可重启电脑。
|
3月前
|
Web App开发 Ubuntu Linux
Linux之Ubuntu操作系统安装
1、在Ubuntu系统下,可以使用自带的U盘启动制作软件制作启动盘。使用方法和rufus类似。 2、或者用dd命令制作启动盘,关于dd命令的使用方法可以百度查看。经过亲自实践,archlinux系统和红旗9.0系统的启动U盘就是用dd命令制作成功。
|
3月前
|
Ubuntu Linux Android开发
Ubuntu——一款备受瞩目的Linux操作系统
目前,要在Ubuntu上使用Windows下常用的工具,一个理想的解决方案是采用Deepin-wine。Deepin-wine是Windows模拟环境,允许用户在Ubuntu上轻松运行许多Windows软件。安装Deepin-wine后,您将能够使用以下列出的众多软件:
下一篇
oss云网关配置