李 亮,党利军,石歌颂,王 江,李锁在
(1.中电(海南)联合创新研究院,海南 澄迈 571924;2.中软信息系统工程有限公司,北京 102209)
视觉是人眼感知外界三维环境空间信息的重要手段,随着计算机图形学的发展,3D 图形图像显示技术被广泛应用于生产生活的多个领域,高性能高效率的 3D渲染计算研究对未来 PKS 体系抢占该领域市场高地、拓宽现有生态、保障国内安全生产有重大意义。本文通过在 PKS 体系上深入研究多种 3D 图形图像显示技术路线,比较 OpenGL 和Vulkan 两种 3D 图形应用程序编程接口(Application Programming Interfaces,API)的性能差异,为将来该技术在 PKS 的发展提供参考。
3D 图形图像显示技术路线指的是显卡和图形 API的组合,现如今,高性能显卡主要来自AMD 和 Nvidia这两个厂商。图形 API 又称图形库,其主要作用是通过调用显卡对图形进行计算,主流的图形库有三种,分别为:DirectX、OpenGL[1]和Vulkan[2],其中 DirectX 由微软公司创建,跨平台能力差,这三种图形库的细节如表 1所示。本文主要研究 OpenGL 和 Vulkan 这两种图形库。
OpenGL 是 1990 年代开发的首批图形框架之一,被认为是行业标准,同时在很长一段时间内,AMD 显卡加OpenGL 是PKS 体系唯一的 3D 图形图像显示技术路线。然而,随着晶体管尺寸的减小,中央处理器(CPU)开始面临丹纳德缩放等问题,CPU 的开发趋势偏向于并行和多核[3]。伴随着芯片设计厂商设计理念的转变,当时的 OpenGL 正在阻碍显卡性能的发挥,即使 OpenGL努力跟上潮流,但当时的 OpenGL 无法有效地使用多线程来渲染,意味着渲染密集型程序受到 CPU 单核性能的限制,未能发挥多个CPU 核心的计算优势。
表1 三种主流图形库细节一览表
为了解决 OpenGL 的不足,开放标准组织Khronos Group 于2015 年推出了一款新的图形框架 Vulkan 接口,这款接口相比 OpenGL 更为轻量化,且更贴近底层[4],可以更加充分利用多核 CPU 的核心计算优势,这与 PKS 体系芯片多 CPU 核心的发展方向非常契合。
本文主要探索与研究基于 PKS 体系的 3D 图形图像显示技术,主要工作包含以下几个方面:
(1)深入研究 PKS 体系上 OpenGL 和 Vulkan 的图形渲染流程和机制;
(2)在 PKS 体系上增加 Vulkan 图形库对 AMD 和Nvidia 的适配,拓宽 PKS 体系上 3D 图形图像显示的技术路线;
(3) 在 PKS 终端上通过三种开源基准工具对OpenGL 和 Vulkan 进行实验,实验结果为 PKS 未来在3D 显示技术的发展提供有意义的参考。
本节对 Linux 图形栈和图形底层 API,即 OpenGL和 Vulkan 进行介绍。
Linux 图形显示的基本流程如图1 所示,应用程序根据用户需求,将一系列渲染指令通过 OpenGL 或 Vulkan 等接口提交给 GPU 硬件。OpenGL 和 Vulkan 等图形库在 Linux 的实现可以有很多形式,这里以图形库的开源实现 Mesa 3D 为例,其实现包含软件实现和硬件加速。所有的 3D 渲染请求都会经过 Mesa 3D,它根据实际情况,选择通过软件或者硬件的方式响应应用程序的渲染请求。当系统存在基于直接渲染基础架构(Direct Render Infrastructure,DRI)的硬件渲染机制时,Mesa 3D 会通过 OpenGL 的接口实现 libGL-meas-DRI 调用DRI 提供的渲染功能。libGL-meas-DRI 会调用 libdrm,libdrm 会通过 ioctl 函数调用内核态的 DRI 驱动,这里称作直接渲染模块(Direct Rendering Module,DRM),内核中的 DRM 最终通过 GPU 完成渲染操作。
图1 Linux 图形显示的基本流程
当 GPU 绘制完成后,结果以图形缓存的形式返回给应用程序,应用程序将结果提交给 Wayland compositor,Wayland compositor 提供显示服务,通过内核模式设置(Kernel Mode Setting,KMS)确定显示的分辨率及深度,最终将结果显示在屏幕上。
具体到底层图形接口本身,OpenGL 和 Vulkan 之间的特性又有差异。在使用 OpenGL 时,只需关心应用层,因为 OpenGL 的驱动层设计十分臃肿复杂,对显卡厂商来说渲染效果是未知的,同时 OpenGL 的错误管理机制一直处于激活状态,造成能耗的增加。Vulkan 对驱动层的设计更为精简,将显卡内存的分配、释放和内存管理等操作交给应用层,把更多的控制权限交给应用层,虽然这种设计理念增加了在程序设计的复杂性,但却降低了驱动层的负载,从而实现更高性能和更平衡的CPU 计算和 GPU 渲染的使用。OpenGL 和 Vulkan 工作方式如图2 所示。
图2 OpenGL 和 Vulkan 工作方式对比
OpenGL 与 Vulkan 在设计理念上的另一差别是对并行运算的友好程度。早期的 OpenGL 不允许从一个以上的线程进行渲染调用[5],不能良好地发挥多个 CPU核心执行渲染指令的优势。在 OpenGL 诞生之初不是问题,因为当时的 CPU 都为单线程居多。现如今已是多核处理器的时代,如果应用程序受 CPU 限制,这样的设计会严重限制性能[6]。
3D 渲染指令包括绑定顶点缓冲区、绑定索引缓冲区、绑定着色器资源和发布基本体渲染的 API 函数。生成渲染指令是一项 CPU 密集型任务,应该尽可能高效率地完成。在 OpenGL 中,渲染指令是同时生成和执行的,不可能将它们分开。OpenGL 做法是使用 gl-DraweElements() 函数将渲染指令送到 GPU,然后立即执行。由于开发工程师经常希望控制渲染对象的顺序,因此只能使用一个线程。而在 Vulkan 中,生成渲染指令和执行它们之间有着明显的区别。指令在指令缓冲区(Command Buffer)中生成,然后将这些指令缓冲区提交到指令队列(Command Queen),仅在此时执行,Vulkan 的多线程工作模式如图3 所示。指令缓冲区可以由多个线程并行生成,这对于 Vulkan 提高多线程性能的能力很重要。
图3 Vulkan 多线程工作模式
指令缓冲区在不同的线程中生成,然后提交到主线程中的指令队列。主线程是实际执行渲染指令的线程。执行渲染指令是一种相对简单的 CPU 操作,因此它可以从单个线程中完成而不会损失过多的性能,这与生成真正占用 CPU 的渲染指令不同。
为了进一步探索 PKS 体系上的3D 图形图像显示技术,本节在 AMD 和 Nvidia 平台上对 OpenGL 和 Vulkan 进行基准性能测试。
绝大多数比较 OpenGL 和 Vulkan 性能的基准数据工具都是为 Android 和 Windows 平台设计,且没有开源代码,少数能在 ARM 加 Linux 平台上运行的游戏也不能同时支持 OpenGL 与 Vulkan,尽管如此,本项工作还是找到了 3 个开源跨平台的基准测工具。
3.1.1 OpenGL vs Vulkan
第一个基准测试工具被称为GL_vs_VK[7],通过绘制多个移动三角形、使用区域四叉树细节层次 (Level of Detail,LOD) 技术渲染地形图以及渲染阴影映射三个场景来执行测试。该工具源代码可以在文献[7]中找到。
(1)测试1:移动三角形。如图4 (a) 所示,该测试在屏幕上显示了许多具有随机颜色和速度的移动三角形,每个三角形都使用顶点缓冲区。测试1 为 OpenGL 和Vulkan 提供了单线程和多线程版本。可以控制在这个场景上绘制的三角形数量来改变 CPU 和 GPU 之间的工作量。本次测试执行了二十万个三角形的场景。
图4 测试 1 至测试 4 的场景
(2)测试2:细节层次。一个 1 024×1 024 的高度图地形被渲染为一个线框,如图4 (b) 所示。这个实现包括每个顶点的顶点缓冲区。为了尽量模拟真实游戏场景,靠近玩家的区域在游戏中具有更多定义的细节,而最远的对象则减少了定义。因此,靠近玩家的区域将具有更高的分辨率网格,而最远的区域将具有较低的分辨率。相机位于地图角落上方的固定位置。同时,模拟玩家围绕地图中心绕圈移动,显示网格变化。此外,地形以未填充三角形网格的形式绘制。
(3)测试3:阴影映射。这个测试阴影映射技术。该场景由一个棋盘地板组成,上面有深灰色和浅灰色的正方形,在地板上方绘制的立方体,以及一个位于棋盘中心的大球体,漂浮在图4 (c) 所示的立方体上方。该场景具有固定光源,而摄像机的位置围绕棋盘中心旋转,并且摄像机始终注视棋盘中心。该场景使用深度缓冲区的简单动态阴影映射技术从相机的角度渲染阴影。
3.1.2 Vkmark 和 Glmark2
其他两个基准测试工具分别为测试 OpenGL 和Vulkan 的Glmark2[8]和 Vkmark[9]。Glmark2 包含着不同着色技术、折射、纹理等场景的测试。Vkmark 和 Glmark2 出自同一位工程师,有部分测试场景相同,因此实验仅对比相同的场景。下面对两个测试工具相同的场景进行描述。
(1)测试4:纹理。在该场景中绘制一个旋转的立方体,并将纹理图像应用于对象的所有面,如图4 (d) 所示。该测试将 2D 图像应用于立方体的每个面,并且使用线性过滤方法。
(2)测试5 至测试8:Gouraud、Phong、Blinn-Phong和 Cel 四种着色场景。这四个测试场景将不同光照模型应用于 3D 图像。Gouraud 着色涉及计算 3D 模型上每个顶点的法线向量,然后,跨多个多边形计算表面插值以估计照明强度。在这个场景中,模型只应用了漫反射照明。Phong 着色改进了 Gouraud 着色模型,提供了更好的表面着色近似。这是通过在模型表面上为每个像素插入法线向量来完成,而不是在每个顶点之间插入颜色的 Gouraud 着色。此外,该模型还包含镜面光照,因此这种方法的计算成本更高。Blinn-Phong 着色方法通过修改镜面光照改进了 Phong 着色模型。在 Phong照明模型上,计算相机与光源反射之间的角度并将其投影到模型上。Cel 着色是一种属于非真实感渲染类的方法。本次测试场景呈现四种不同的绿色阴影。测试 5至测试8 的场景分别如图5 (a)~图5 (d) 所示。
图5 测试5 至测试8 四种着色模型场景
本次实验在两台 PKS 终端机上进行,单机共4 个CPU 核心,运行内存 32 GB,两台终端机分别搭载型号为 AMD Radeon 580 2048sp 和 Nvidia RTX 2080 Super两块图形显卡。实验环境软硬件平台的具体信息可参考表2。
表2 实验软硬件平台总结
实验首先使用 GL_vs_VK 工具在搭载 Nvidia RTX 2080 Super 和 AMD RX 580 2048sp 的 PKS 终端机上测试 OpenGL 和 Vulkan 的性能,共获得两组实验数据,性能评价指标是显示帧率(Frames Per Second,FPS)。实现选择 benchmark 模式,该模式先后运行三个测试场景,每个场景持续测试15 s,实验结果输出每个场景平均帧率。
图6 和图7 分别展示了 GL_vs_VK 工具在 Nvidia和 AMD 显卡上的实验结果,由于不同场景的实验结果相差过大,纵坐标采用指数形式展示。在单线程测试中的三个测试场景,Vulkan 显示性能均优于 OpenGL,Vulkan 的帧率是 OpenGL 的1.9 至2.4 倍。
图6 GL_vs_VK 工具在 Nvidia 显卡上对比实验结果
图7 GL_vs_VK 工具在 AMD 显卡上对比实验结果
在多线程测试中,OpenGL 和 Vulkan 均使用4 个线程进行渲染,OpenGL 多线程版本只在移动三角形场景提供,相比单线程,多线程有着1.2 倍左右的提升,于此同时 Vulkan 提升效果更为明显,性能提升范围在1.5 至2.6 倍。图8 为在4 线程模式下Vulkan 和 OpenGL 的使用率,可以看到,Vulkan 四个核心的使用率均在90% 左右,而 OpenGL 压力都在 CPU 3 上,其他核心只大约占用了 20%。这个现象说明了多线程 Vulkan 相比于单线程更能调动处理器的性能从而提高渲染效率,而多线程OpenGL 提升性能并不明显。
图8 多线程模式下 Vulkan 和 OpenGL 的 CPU 使用率差异
图9 展示了Glmark2 和Vkmark 基准测试工具在AMD 平台的的实验结果。实验结果包括五个场景,主要是测试纹理和着色的渲染能力。总的来看,Vulkan 在本次实验结果均高于 OpenGL,Vulkan 的帧率是OpenGL 的1.8 至1.9 倍。
图9 Glmark2 和 Vkmark 工具在 AMD 显卡上对比实验结果
本文在 PKS 体系上开展了 3D 图形图像显示的研究,深入研究了 OpenGL 和 Vulkan 两种图形库的结构、工作原理以及两者的差异。采用了三种基准测试工具和两种品牌的显卡在 PKS 终端机上对 OpenGL 和 Vulkan 进行性能比较,为 PKS 体系未来的 3D 图形图像显示技术发展提供重要参考。实验结果表明,在单线程模式下,Vulkan 的性能均优于 OpenGL,在多线程模式下,Vulkan 的性能提高更加显著,这是因为 OpenGL 将所有渲染操作集中于一个线程,而Vulkan 引入了 Command Buffer,每个线程可以向其提交渲染指令,充分发挥了多核处理器的优势,Vulkan 的特性更适合 PKS 体系未来3D 图形图像显示技术的发展方向。