1. 常用优化工具
2. 常用优化方案
OpenGL ES优化的主要工作是在图形管道中找到影响性能的bottleneck,其bottleneck一般表现在以下几方面:
•在应用程序代码中,如冲突检测
•GPU与主内存间的数据传输
•在VP(Vertex Processor)中的顶点处理
•在FP(Fragment Processor)中的片断处理
可通过DS-5 Streamline来定位性能瓶颈(Locate bottleneck)。为了获取更好的性能,可从以下具体功能着手优化:
2.1 纹理(Texture)
高分辨率的纹理占用大量的内存,它是Mali GPU上的主要负荷,可从以下几方面进行优化:
•除非必要,尽量不要使用大纹理
•总是打开纹理映射(mipmapping),有时可能降低了渲染质量
•如果可能,排序三角形,当按render的次序render时,使其有相互覆盖的三角形放在一起
•压缩纹理,可减少内存占用、传输带宽,Mali-400 MP GPU支持ETC纹理压缩(每个像素占4bits,且不支持alpha通道),GPU硬件可解压ETC纹理,缺点是将降低图像质量
2.2抗锯齿(Anti-aliasing)
•GPU支持4x Full Scene Anti-Aliasing (FSAA),其性能损失微不足道;当创建context和rendering surface时,可通过选择EGL配置(EGL_SAMPLES=4)来激活4x FSAA
•Mali GPU还支持16x FSAA,其性能将下降到4x FSAA的1/4
2.3 画图模式(Draw Mode)
对于大的网格,一个顶点被包含在多个三角形中,这样的顶点被处理的次数依赖调用的画图函数:
•glDrawElements:每个顶点仅被处理一次,效率更高。
•glDrawArrays:每个顶点数据在每一个使用它的三角形中被传输和处理一次
按使用的次序存储顶点数据,可以改善顶点Cache效果,并且减少了从RAM到顶点Cache传输的数据量。
2.4顶点缓冲对象(Vertex Buffer Objects)
•使用顶点数组(Vertex Array)存储的顶点数据位于客户端内存(即主内存),当调用glDrawArrays或glDrawElements时,将把这些顶点数据从客户端内存copy到图形内存。
•Vertex Buffer Objects允许OpenGL ES2.0应用在高性能的图形内存中分配且Cahce顶点数据,然后从此内存中进行渲染。这样就避免了每当Draw一个原语时重发数据。
•Vertex Buffer Objects分类:
1) 数组缓冲对象(array buffer objects):由GL_ARRAY_BUFFER标识,用于存储顶点数据(Vertex Data)
2) 元素数组缓冲对象(element array buffer objects):由GL_ELEMENT_ARRAY_BUFFER标识,用于存原语索引(indices of primitive)
2.5 数据精度(Data Precision)
在可能的情况下,尽量使用低精度的数据,避免使用浮点和其它32位数据类型:
•定义顶点位置使用GL_SHORT
•定义Surface Normal使用GL_BYTE
•定义颜色使用GL_UNSIGNED_BYTE
2.6 处理的数据量(Volume of Data Processed)
要从以下几方面减少Mali GPU处理的数据量:
•只画当前帧看得见的原语:可在应用中通过clipping或frustum clulling来实现
•使用ETC压缩纹理
•根据深度排序几何体:按照从前到后的顺序排序几何体,根据深度排序draw调用。
2.7渲染目标(Render Targets)
以下因素与渲染目标有关:
•按照因素(cause-and-effect)顺序渲染所有的纹理
1)在纹理被使用之前render to textures
2)最后渲染后台缓冲区
•一次只绘制到一个渲染目标:确保绘制下一个目标之前,已经完成当前目标的所有调用
•不要在一帧中修改纹理:当调用API之前,设置好所有当前帧需要的纹理
2.8 处理管道(Processing Pipeline)
以下因素与图形处理管道有关:
• 使用eglSwapBuffers:
如果应用显示动画,确保通过调用eglSwapBuffers来结束一帧。应用接着产生下一帧,这样以确保在计算下一帧时,当前帧仍可稳定显示。
• 避免使用glReadPixels:
即使读取很少像素,对性能影响也比较大,因为它暂停了处理管理
• 限制glDrawElements中顶点个数:
在调用glDrawElements之后,在以前的操作(如:顶点着色、变换、光照)完成之后才开始创建多边形列表。为了使之并行,确保单次glDrawElements调用中包含的顶点数不要超过当前帧中所有顶点数的1/5。这在立即调用glDrawArrays之前或之后特别重要。
2.9着色器程序(Shader Programs)
•首先执行Shader编译:在应用程序启动时,且在开始向驱动发送顶点或纹理数据之前,完成Shading语言编译器所有相关的调用
•使用自定义着色器程序:把大的Shader程序采裁剪成每个Surface所需要的,而不使用大而全的Shader程序,小而精的Shader程序通常运行得更快
•考虑程序大小:可以使用Offline Shader Compiler检测程序大小。一个GPU指令可以包含一系列ESSL操作
•循环和条件分支:不要手动展开循环。相反,把数据放到数组中,然后在可能的地方使用for循环。当然,也可以使用if语句。
•避免使用过多的varyings:在shader编程时,在Fragment Shader程序中,尽量节约使用varings;因为在VP与内存或FP与内存间传递varings时需要消耗内存带宽
•避免使用过多的矩阵乘法:4x4的矩阵与4x1的向量相乘,需要执行16次乘法和12次加法,是非常昂贵的;如果需要一个向量与多个矩阵相乘,则向量依次与每个矩阵相乘,而不要先把所有的矩阵相乘,然后再与向量相乘
•评估程序的代价:常用的代价级别如下表所示,使用Offline Shader Compiler可以更精确地获取程序的代价。
2.10着色器运算(Shader Arithmetic)
•顶点处理器基于32位浮点值工作:Vertex Shader使用浮点表示整数。为了避免32位值,设置Vertex Shader程序的输出varing的精度为mediump或lowp。
•Fragment Shader使用16位浮点值工作:其构成为:sign;5位指数,以抵消15;10位尾数,用一个隐含的最显著1位
2.11 其它
• 使用点精灵:
而不是三角形或四边形来表示颗粒实体
• 使用适当尺寸的三角形:
避免使用长而细的三角形。FP(Fragment Processor 或Pixel Processor)总是处理4个邻近Fragment的组。因此处理1个像素宽度的Strip比处理2个像素宽度的Strip耗用更多的时间。
• 优化状态变化:
避免状态来回变化,可以把相同状态的调用组织在一起,以减少状态变化
• 清除整个Framebuffer:
总是调用glClear清除整个Framebuffer。如果可能,在清除framebuffer时,清除所有的buffer,如:color、depth, and stencil buffers。
void glClear(GLbitfield mask);
参数说明:
GLbitfield:可以使用 | 运算符组合不同的缓冲标志位,表明需要清除的缓冲,例如glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)表示要清除颜色缓冲以及深度缓冲,可以使用以下标志位:
1)GL_COLOR_BUFFER_BIT: 当前可写的颜色缓冲
2)GL_DEPTH_BUFFER_BIT: 深度缓冲
3)GL_ACCUM_BUFFER_BIT: 累积缓冲
4)GL_STENCIL_BUFFER_BIT: 模板缓冲
• 最小化draw调用:
当调用glDrawArrays或glDrawElements时,GPU驱动需要收集所有当前OpenGL ES状态、纹理和顶点属性数据;然后驱动处理这些数据并产生可在GPU硬件上执行的命令,以执行真正的draw调用。此操作可以耗费大量的时间,所以如果执行多次调用,它将成为rendering的性能瓶颈。如果多个对象具有相同的rendering参数,但使用不同的纹理,则可以把纹理合并到一个大的纹理中,并调整其对应的纹理坐标即可。
• 避免使用glFlush和glFinish:
除非你无法避开,否则不要调用glFlush或glFinish,而使用eglSwapBuffers来触发一帧的结束。(注:glFlush只是把命令发送给Server,但并不等待执行完成。如果需要等到Server执行完成时才返回,则需要调用glFinish,但它严重影响性能。)
3. 发现和消除bottleneck
基本方法:
1) 使用专业工具(如DS-5 Streamline)
2) 在值得怀疑的图形管理阶段,增加或减少负荷,然后观察性能变化情况
发现和消除bottleneck可参考以下方案:
4. ESSL限定值
OpenGL ES Shading Language规范定义了各种着色器资源(shader resources)大小的最小值,在Mali GPU实现中,其中一些值大于规范中定义的最小值。常用的如下表所示:
如果觉得《Mali GPU OpenGL ES 应用性能优化--基本方法》对你有帮助,请点赞、收藏,并留下你的观点哦!