iOS系统OpenGL ES的多任务、高分辨率及其它特性
使用OpenGL ES的许多方面都是平台无关的,但是在iOS上使用OpenGL ES的一些细节需要特别考虑。尤其是iOS应用使用OpenGL ES正确处理多任务,否则在它被移动到后台时有被终止的风险。在为iOS设备开发OpenGL ES内容时, 还应该考虑显示分辨率和其它设备特性。
实现一个多任务处理的OpenGL ES应用
当用户转换到另一个应用时,你的应用可以继续运行。iOS上多任务完整的讨论,请看:App States and Multitasking。当应用进入到后台时,OpenGL ES 应用必须要执行额外的工作。如果应用处理这些任务不恰当,它可能被iOS系统终止。同时,如果应用想释放OpenGL ES资源,那这些资源可以被前台应用使用。
后台应用可能不会在图形硬件上执行命令
iOS系统会阻止后台应用访问图形处理器,因此前台的应用总是能够给用户呈现最好的体验。你的应用不仅在进入后台被终止,而且如果在进入后台先前提交给GPU的命令被清除也会终止。你的应用必须确保之前提交的命令在进入后台之前全部执行完成。如果你使用的是GLKit的视图或视图控制器,只须在你的绘制方法中提交OpenGL ES命令,当你的应用进入后台时,它会自动正确的运行。默认情况下,GLKViewController类在应用不活跃时会停止动画定时器,来确保你的绘制方法不会被调用。如果你不是使用GLKit的视图或视图控制器或者你在GLKView绘制方法外提交OpenGL ES的命令,你必须要采取以下步骤保证你的应用在后台不会被终止。 1. 在应用的代理 applicationWillResignActive: 方法中,你的应用要停止动画定时器(如果有),将自己置于一个良好的状态,然后调用glFinish函数。 2. 在应用代理的 applicationDidEnterBackground: 方法中,你的应用可能要删除一些OpenGL ES对象,使内存和资源能让前台应用可用。调用glFinish函数确保资源立即被移除。3. 在你的应用程序退出 applicationDidEnterBackground: 方法,不准再有新 OpenGL ES的调用。如果有任何调用,会被iOS系统终止。4. 在应用的 applicationWillEnterForeground: 方法中,重新创建对象和重启动画定时器。
在进入后台前删除容易重新创建的资源
当你的应用程序进入后台时,你的应用永远不需要释放OpenGL ES对象。通常,你的应用程序应当避免处理它的内容。考虑两种场景:1. 一个用户正在玩你的游戏,并短暂离开查看他的日历。当玩家返回游戏,游戏的资源应该还在内存中,同时游戏可立即恢复。2. 当用户启动其它OpenGL ES应用时,你的OpenGL ES应用在后台。如果那个应用需要的内存比设备上可用的内存多,系统会自动终止应用程序,而不需要它执行任何额外的操作。
你的目标应该是设计你的应用是一个好应用:这意味着它要进入前台的时间尽可能的短,同时减少它在后台内存的占用。以下是你应当如何处理两种情况:1. 你的应用应当保持纹理、模型和其它资源在内存中,那些要花费长时间重新创建的资源应当不要丢弃,在应用进入后台的时候。2. 你应当丢弃那些可以快速和容易重新创建的的对象。查找对象会消耗巨大的内存。
简单的目标就是你的应用程序分配的framebuffer来保存渲染结果。当应用在后台时,它对用户是不可见的,并且可能不会使用OpenGL ES呈现任何新内容。这意味着应用程序的framebuffer消耗的内存被分配了,但没有用处。此外framebuffer的内容是临时的。大多应用程序在每次呈现新帧时都会重新创建framebuffer内容。这使得renderbuffer成为一个内存密集型资源,可以很容易的重新创建,当进入后台处理时,可以成为一个对象很好的候选。如果使用的是GLKit视图或视图控制器,在进入后台时,GLKViewController类会自动处理关联的视图framebuffer。如果手动为其它使用创建的framebuffer,你应当在应用进入后台时处理它们。无论在哪种情况下,你也应当考虑其它短暂资源在那时应用的处理。
支持高分辨率显示
默认情况下,GLKit视图的 contentScaleFactor属性与包含它的屏幕的拉伸相匹配,它关联的framebuffer被配置为以全分辨率呈现。更多的关于在UIKit中支持如何高分辨率显示,请看Supporting High-Resolution Screens In Views。如果用Core Animation 的图层呈现OpenGL ES的内容,它的拉伸因子默认是1.0。为了能够在Retina显示屏绘制全分辨率,你应当发迹CAEAGLLayer对象的拉伸因子去匹配屏幕的拉伸因子。当支持的设备是高分辨率时,你应当相应的调整应用的模型和纹理的资源。当运行在一个高分辨率设备时,你可能要选择更详细的模型和纹理渲染更好的图像。相反,在一个标准分辨率的设备上,你就可以选择比较小的模型和纹理。
当决定支持高分辨率显示时的一个重要因素是性能。在Retina显示屏上拉伸因子增加一倍,像素量增加四倍,从而使GPU处理的碎片数量增加4倍。如果你的应用对大量的单一片段进行计算,像素的增加可能会降低帧率。如果发现应用在一个较高的比例因子运行速度明显变慢,要考虑以下情况:1. 使用文档中的性能调优指导优化你的片段着色器;2. 在片段着色器中实现简单的算法。按这样做,你减少单个像素的质量来在高分辨率上渲染完整的图像;3. 在1.0和屏幕的比例系数之间使用分数比例系数,1.5的比例因子比一个1.0的比例因子提供更好的质量,同时需要填充的像素比一个缩放到2.0的图像少;4. 为GLKView对象的drawableColorFormat和drawableDepthFormat属性使用低精确度格式,这样做减少了操作底层renderbuffer的内存带宽;5. 使用较低的拉伸因子并启用多采样。另一个好处是,多采样还可以在不支持高分辨率显示器的设备上提供更高的质量。
支持多个界面方向
与任何应用程序一样,OpenGL ES应用程序应该支持与其内容相适应的用户界面方向。可以在info.plist中声明支持的界面方向,或者使用OpenGL ES内容的视图控制器的supportedInterfaceOrientations方法声明界面朝向。默认情况下,GLKViewController和GLKView自动处理方向的改变。当用户旋转设备到支持的方向,系统会动画方向改变,同时改变控制器视图的大小。当大小改变,GLKView对象相应地的调整它的framebuffer和viewport的大小。如果你要对这个改变做出响应,在GLKViewController或其子类中要实现viewWillLayoutSubviews或viewDidLayoutSubviews方法,或者如果你使用的自定义的GLKView子类中实现layoutSubviews方法。如果使用Core Animation的图层绘制OpenGL ES内容,你的应用仍然包含一个viewController去管理界面方向。