织梦CMS - 轻松建站从此开始!

罗索

基于OpenGL ES的3D图形绘制管线优化问题

落鹤生 发布于 2010-06-26 22:12 点击:次 
采用最新的图形管线理论,将OpenGL ES的3D图形管线绘制过程划分为七个管线绘制部分(这七个部分归属于三个绘制阶段),分析每个绘制部分的主要工作,在此基础上针对各个阶段提出了相应的优化方法。
TAG:

莫 军 陈雷霆 《计算机应用研究》 2007年第01期

摘要:目前,在嵌入式设备上(如手机)的3D游戏开发总是基于一定的图形API来进行的。OpenGL ES是为嵌入式系统而开发的3D图形绘制编程接口。在基于嵌入式的3D游戏开发过程中,由于硬件资源的相对不足,要得到绘制效果较理想的图形,就需要优化 3D图形绘制过程。采用最新的图形管线理论,将OpenGL ES的3D图形管线绘制过程划分为七个管线绘制部分(这七个部分归属于三个绘制阶段),分析每个绘制部分的主要工作,在此基础上针对各个阶段提出了相应的优化方法。
关键词:OpenGL ES; 图形管线 ; 嵌入式3D游戏
中图法分类号:TP391.4文献标识码:A
文章编号:1001-3695(2007)01-0215-03

目前,在嵌入式设备上(如手机)的3D游戏开发总是基于一定的图形API来进行的,OpenGL ES是其中性能卓越的一种API,它被广泛地使用在许多手机3D游戏中,如MotoGP2,SpeedGun Stadium,GalacticRealms等。由于当前手机硬件性能相对较低,游戏总是会受到一些软硬件的限制,影响游戏画面的绘制效果和表现力。为了增强游戏的表现力,有必要对图形绘制过程的优化方法进行研究。本文在分析OpenGL ES图形管线绘制过程的基础上总结了3D游戏开发过程中相应的优化方法。

1、OpenGL ES 3D图形管线绘制过程

在现实世界中,管线概念的表现方式非常多,如输油管道、车间流水线、缆车等。一条管线通常包括多个阶段,无论其中某个阶段速度有多快,管线的整体快慢程度是由管线中最慢的那个阶段决定的。在图形绘制中也存在这种管线结构,最慢的管线阶段决定绘制速度,即图像更新速度。最慢的管线阶段称为瓶颈。瓶颈阶段会限制绘制过程中的整个吞吐量,从而影响总体绘制性能,因此它成为优化的主要对象。
图1是OpenGL ES 3D图形管线的绘制过程[1]。图中顶点部分是3D几何学所处理的顶点世界,像素部分是存储在帧缓冲里的像素世界。
CPU部分负责图形管线绘制过程中几何数据进出的转换。几何存储部分是连接设备驱动内存和图形内存的桥梁,它负责在处理过程中临时保存顶点的几何数据,为后面的处理作准备。OpenGL ES的几何存储支持的数据类型有Byte,Short,Fixed,Float[2]。几何处理器部分负责顶点和纹理坐标的对应转换。几何处理器与光栅器之间存在着一种称之为浮点型数据处理管线的结构,通过它把各种数据类型的坐标值转换成内部浮点数形式。光栅器要将每一个三角形的边及其内部区域光栅化,同时要负责图形管线的像素插值。片段处理器就是分析像素片段的阴影、着色,然后把这些结果放入帧缓冲。纹理存储就是采用某种格式保存纹理数据。OpenGL ES支持的格式有每像素8位,16位和32位[2]。纹理过滤采用LOD驱动。帧缓冲所处理的图形数据直接提供给LCD显示设备所用。外置存储芯片用于帧缓冲、VBO(Vertex Buffer Object)和纹理数据。OpenGL ES的驱动程序为这三者在外置存储芯片上分配空间。

2、3D图形管线绘制的优化

  3D图形管线绘制的优化包含两个主要步骤:①对管线的瓶颈位置进行定位;②以某种方式对该瓶颈阶段进行优化处理后,如果没有达到预期的性能目标,就继续重复步骤①。需要注意的是,瓶颈位置在优化之后有可能还处于优化前的位置。比较理想的状况是尽可能对瓶颈进行优化,保证瓶颈位置能够转移到另外一个阶段。在这个阶段再次成为瓶颈之前,必须对其他阶段进行优化处理。
2.1瓶颈定位
由于优化过程非常耗时,因此要对图形管线中的每个阶段进行最优化处理,这在实际操作中是不可行的。如果对每个阶段均进行优化,虽然可以提高一定的性能,但同时会花费开发人员大量的时间,甚至还可能牺牲绘制质量;此外对每个阶段都进行优化的另一个缺点,那就是不知道管线的哪个阶段是瓶颈。实际上可以通过对瓶颈阶段进行优化处理来大幅度提高绘制质量而不影响总体性能。
一种瓶颈定位的方法是进行大量的阶段测试。阶段测试的一个方法是每测试一次只影响一个阶段,如果总的绘制时间受到影响,就可以找到瓶颈位置;阶段测试还有一个方法,就是在保持被测阶段工作负载的情况下,减少其他阶段的工作量,如果性能没有变化,那么瓶颈所在的位置就是工作量没有改变的阶段。
因此瓶颈定位的方法可转换为阶段测试问题。为了阐述方便,将图1的七个管线阶段粗略划分为三个阶段,即CPU阶段(CPU部分)、几何阶段(几何存储、几何处理器部分)和光栅阶段(光栅器、片段处理器、纹理存储和过滤、帧缓冲部分)。
CPU阶段的测试。如果当前使用的平台提供一种具有测量处理器工作负载的功能,就可以使用这个功能来考查当前程序是否使用了或接近100%的 CPU处理能力。另一种测试CPU受限的巧妙方法是,将导致其他阶段工作量极小甚至不工作的数据向下发送。由于不需要用图形硬件,因此可以有效地为当前运行程序设置一个速度上限。这样CPU就成为了瓶颈。
几何阶段的测试(所有阶段中最困难的)。因为如果改变这个阶段的工作负载,那么其他阶段的工作负载也会相应改变。只对几何阶段工作负载有影响的参数是光源类型和数量,如果禁止或移去场景中的所有光源,可使性能提高,那么瓶颈位置就在几何阶段。如果硬件中存在可编程的顶点着色器,就可以简单地使用顶点程序对每个顶点进行变换,而不需要计算光照,从而可以降低几何阶段的负荷。另外如果在此基础上性能有所提高,那么瓶颈就在几何阶段。
光栅阶段的测试。其最容易且最快,只需要简单地降低图像绘制的分辨率即可。由于填充像素的减少,从而减少了光栅阶段的工作负载。随着绘制分辨率的降低,如果总的绘制性能提高了,就可以说图形管线是填充受限,可以确定瓶颈就在光栅阶段。此外还可以通过关闭混合操作和深度缓冲来改变光栅阶段的工作负载,从而确定瓶颈位置是否在光栅阶段

2.2优化方法
一旦确定了瓶颈位置,就可以对瓶颈所处的阶段进行优化,提高整体性能。在优化过程中,如果实际性能已经接近图形硬件厂商所宣称的性能指标,就不需要对管线中的硬件加速部分进行优化[3]。
2.2.1CPU阶段的优化方法
对不同的CPU厂商而言,最优化技术通常也不尽相同,下面讨论一些通用的优化方法。
(1)避免使用浮点数类型。虽然OpenGL ES支持浮点数,但是当前手机上的CPU还没有一款是支持浮点数类型的。软件中的浮点数最终都必须转换成定点数,否则CPU不能处理,这一转换过程需要消耗大量CPU资源。由于避免使用浮点数类型,因此也要尽量避免使用除法和某些基本数学函数(如sin,arcsin等),因为它们都可能带来大量的浮点数类型的数据。对于数学函数,我们可以采用两种方法来解决:①函数查找表。这样不需要使用硬件资源来进行计算,其缺点是增加了CPU访问内存的次数。②使用麦克劳林或泰勒级数的前几项取得函数的近似值,其缺点是精度可能不够。
(2)采用更优化的编译模式。例如基于ARM的CPU,可以选择两种编译代码模式,即ARM和Thumb。具体选择哪种编译模式依靠内存带宽和内存与CPU之间的总线带宽决定。ARM是32位指令集,它比运行在32位平台上的Thumb指令集更快;此外Thumb模式下整型数据为16位,而 ARM是32位[1]。
(3)减少条件分支和多重循环。条件分支的开销非常高,减少条件分支的办法是采用条件移动指令,如这样的代码就有效地减少了分支:re=a>b?choice1: choice2。便多重循环导致高速缓存的性能下降,应尽量避免使用多重循环。
2.2.2几何阶段的优化方法
几何阶段主要负责几何数据的存储、变换、光照、裁减、投影、屏幕映射。几何数据存储、变换、光照比较容易优化,而剩余部分的优化就比较困难,甚至是不可能的。
(1)采用压缩图元方式存储顶点数据。这样可以减少数据阻塞,降低内存的使用。例如对于表面法向量来说,不需要使用全浮点型精度,因为全浮点型精度主要用于由字节值表示的明暗效果计算。
(2)使用索引顶点数组。OpenGL ES支持索引顶点数组(调用glDrawArrays函数)和非索引顶点数组(调用glDrawElements函数)[2]。例如,一个三角形需要传送三个顶点,由两个三角形组成的四边形在索引顶点数组中只需要传送四个顶点,而在非索引顶点数组中需要传送六个顶点。索引顶点数组中的顶点都是唯一的、不重复的。此外在调用glDrawArrays函数和glDrawElements函数时要注意,调用次数少但每次传送顶点数量多要比调用次数多但每次传送顶点数量少快些。
(3)使用顶点缓冲对象VBO。VBO可以避免重复发送存在于系统RAM中的顶点。在OpenGL ES扩展中调用ARB_vertex_buffer_objet来实现VBO。并非所有的硬件都支持VBO,在使用它之前要注意查询OpenGL ES驱动程序,以确定该硬件对其是否支持。
(4)光照计算的优化。①考虑光源类型。例如平行光源比点光源速度快,点光源要比聚光源速度快。②在计算光照时,需要对模型所有法线进行归一化处理。③如果把光源或材质的镜面反射分量设为(0,0,0),将可以避免光照方程中的高光计算,这部分的计算开销相当高。
2.2.3在光栅阶段的优化方法
光栅阶段主要包括光栅器、片段处理器、纹理的存储与过滤、帧缓冲。在这一阶段有较多的优化方法,这里只讨论部分基本优化方法。
(1) 打开背面裁减开关。对于封闭体和看不到背面的物体,应该打开背面裁减开关,这样可以将需要光栅化处理的三角形数量减少近50%。
(2) 合理利用Z缓冲器。一种不影响绘制质量的优化技术是在特定时间关闭Z缓冲器,如在清除帧缓冲器之后,不需要进行深度测试也可以直接绘制任何背景图像。诸如多边形对齐的BSP树之类的算法就不需要使用Z缓冲器。合理利用Z缓冲器还有另外一种情况。如果可以保证屏幕上的每个像素都被某个物体覆盖(如天空),就不需要清除颜色缓冲器,还可以通过牺牲一个比特的深度精度避免对Z缓冲器进行清除。在第一帧,正确地清除Z缓冲器,而且只绘制缓冲器的前面一半,即将深度归一化的设备坐标重新调节到-1.0~0.0范围;在第二帧,不用清除Z缓冲器,翻转观察方向和深度测试,然后设置深度范围,1.0为近平面,0.0为远平面;在第三帧,再次使用-1.0~0.0范围,随后每一帧都在这两个范围之间切换。这样,前一帧的Z深度值通常会被在这一帧中绘制的物体所覆盖,就好像清除了Z深度值[4]。
(3)采用图形硬件内部的纹理和像素格式。这样可以避免从一种格式转换到另外一种格式。当需要更新纹理时,在OpenGL ES中可以使用glTextSubImage2D函数来代替glText ̄Image2D函数,这样就可以避免内存分配与回收问题[2]。此外还可以采用纹理压缩技术,在OpenGL ES中可以调用glCompressedTextImage2D函数和glCompressedTextSubImage2D函数来压缩纹理[2]。压缩纹理的优点在于使用内存较小,可以提高高速缓存的利用率。

3、总结

本文分析了基于OpenGL ES的图形管线流程,初步讨论了各个阶段的图形管线优化方法,为在嵌入式设备上开发表现力更强的3D游戏进行了积极探索。在优化过程中还需要注意,如果不能对最慢的阶段作进一步优化,就要使其他阶段与最慢阶段的工作负载尽可能一样多,从而保持图形管线的平衡,这样并不影响整体性能,还充分利用了硬件资源。在3D游戏开发过程中要充分了解硬件平台的性能,任何超越硬件特性的优化都是不能实现的。例如,OpenGL ES具有一个VBO的扩展,VBO把数据加载到显卡的高性能显存中,这样大大降低了渲染时间,但是扩展要依赖较新的硬件,不是所有的图形卡都支持。

综上所述,图形管线优化的总体思路是:控制显存和带宽使用,保持图形管线的平衡,充分发挥硬件性能,软件优化不能超出硬件局限。

参考文献:
[1]Dave Astle, Dave Durnil. OpenGL ES Game Development[M]. Thomson Course Technology, 2005.95107.
[2]OpenGL ES Common/CommonLite Profile Specification version 1.0.02[DB/OL].http://www.opengles.org/translations/chinese_simple/opengles/ eglspec[1].1.1.pdf,20-040911.
[3]Cok Keith, Roger Corron, et al. Developing Efficient Graphics Software: The Yin and Yang of Graphics[EB/OL]. Course 6 Notes at SIGGRAPH 2000,http://www.sgi.com/software/opengl/advanced ̄00/notes /00_yin_yang.pdf,2000.
[4]Lindholm Erik,Mark Kilgard. A UserProgrammable Vertex Engine[C].Proceedings of SIGGRAPH 2001,2001.149158.

作者简介:
莫军(1974),男,硕士研究生,主要研究方向为嵌入式三维游戏引擎相关技术;陈雷霆(1966),男,教授,主要研究方向为数字图像处理、三维图形技术。
注:本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文 本文原文

(莫军,陈雷霆)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201006/9736.html]
本文出处:《计算机应用研究》 作者:莫军,陈雷霆
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容