多任务,高分辨率和其他iOS功能
Implementing a Multitasking-Aware OpenGL ES App使用OpenGL ES的许多方面是平台中立的,但是在iOS上使用OpenGL ES的一些细节特别考虑。特别是,使用OpenGL ES的iOS应用程序必须正确处理多任务,或者在移动到后台时可能会被终止。在为iOS设备开发OpenGL ES内容时,您还应该考虑显示分辨率和其他设备功能。
实现多任务感知OpenGL ES应用程序
当用户切换到其他应用程序时,您的应用程序可以继续运行。有关iOS上多任务的全面讨论,请参阅应用程序状态和多任务。
当OpenGL ES应用程序移动到后台时,必须执行其他工作。如果应用程序不正确地处理这些任务,则可能会被iOS终止。此外,一个应用程序可能想要释放OpenGL ES资源,以便这些资源可用于前台应用程序。
后台应用程序可能无法在图形硬件上执行命令
如果OpenGL ES应用程序尝试在图形硬件上执行OpenGL ES命令,则会终止该应用程序。 iOS防止后台应用程序访问图形处理器,以便最前沿的应用程序始终能够向用户呈现出极好的体验。您的应用程序不仅可以在后台进行OpenGL ES调用时终止,还可以在以后提交的命令在后台刷新GPU。您的应用程序必须确保所有以前提交的命令在移动到后台之前已完成执行。
如果您使用GLKit视图并查看控制器,并且仅在绘图方法中提交OpenGL ES命令,则当应用程序移动到背景时,您的应用程序将自动正常运行。默认情况下,GLKViewController类在您的应用程序变为非活动状态时暂停其动画定时器,确保您的绘图方法不被调用。
如果您不使用GLKit视图或查看控制器,或者如果您在GLKView绘图方法之外提交OpenGL ES命令,则必须执行以下步骤以确保您的应用程序未在后台终止:
- 在应用程序委托的ApplicationWillResignActive:方法中,应用程序应该停止其动画定时器(如果有的话),将其置于已知的良好状态,然后调用glFinish函数。
- 在应用程序委托的applicationDidEnterBackground:方法中,您的应用程序可能需要删除一些OpenGL ES对象,以使内存和资源可用于前台应用程序。调用glFinish函数以确保资源立即被删除。
- 在您的应用程序退出其applicationDidEnterBackground:方法之后,它不能进行任何新的OpenGL ES调用。如果是OpenGL ES呼叫,则由iOS终止。
- 在您的应用程序的应用程序WillEnterForeground:方法中,重新创建任何对象并重新启动动画计时器。
总而言之,您的应用程序需要调用glFinish函数,以确保所有以前提交的命令都从命令缓冲区中排除,并由OpenGL ES执行。移动到后台后,您必须避免使用OpenGL ES,直到它回到前台。
在移动到背景之前删除轻松重新创建的资源
您的应用程序不需要在OpenGL ES对象移动到后台时释放。通常,您的应用程序应避免处理其内容。考虑两种情况:
- 用户正在玩游戏,并短暂退出以检查他们的日历。当玩家返回游戏时,游戏的资源仍然在内存中,游戏可以立即恢复
- 当用户启动另一个OpenGL ES应用程序时,您的OpenGL ES应用程序处于后台。如果该应用程序需要比设备上更多的内存,系统将自动终止您的应用程序,而不需要执行任何其他工作。
您的目标应该是将您的应用程序设计为一个好的公民:这意味着保持尽可能短的时间移动到前台,同时在后台减少其内存占用。
这是您应该如何处理这两种情况:
- 您的应用程序应保留内存中的纹理,模型和其他资源;在您的应用程序移动到后台时,不应该处理需要很长时间重新创建的资源
- 您的应用程序应该处理可以快速轻松重新创建的对象。寻找消耗大量内存的对象。
容易的目标是您的应用程序分配来支持呈现结果的帧缓冲区。当你的应用程序在后台时,用户看不到它,并且可能不会使用OpenGL ES渲染任何新的内容。这意味着应用程序的帧缓冲区消耗的内存是分配的,但没有用。另外,帧缓冲区的内容是暂时的;大多数应用程序在每次呈现新帧时重新创建帧缓冲区的内容。这使得renderbuffers成为可以轻松重新创建的内存密集型资源,成为当移动到后台时可以处理的对象的良好候选。
如果您使用GLKit视图和视图控制器,则当您的应用程序移动到后台时,GLKViewController类会自动处理其关联视图的帧缓冲区。如果您手动创建用于其他用途的帧缓冲区,那么当应用程序移动到后台时,您应该处理它们。在这两种情况下,您还应该考虑当时应用程序可以处理哪些其他临时资源。
支持高分辨率显示
默认情况下,GLKit视图的contentScaleFactor属性的值与包含它的屏幕的比例匹配,因此其关联的帧缓冲区配置为以显示的完整分辨率呈现。有关UIKit支持高分辨率显示的更多信息,请参阅在视图中支持高分辨率屏幕。
如果您使用Core Animation层提供OpenGL ES内容,则默认情况下其比例因子设置为1.0。为了绘制Retina显示屏的完整分辨率,您应该更改CAEAGLLayer对象的比例因子以符合屏幕的比例因子。
当支持具有高分辨率显示器的设备时,应该相应地调整应用的模型和纹理资产。在高分辨率设备上运行时,您可能需要选择更详细的模型和纹理来渲染更好的图像。相反,在标准分辨率设备上,您可以使用较小的模型和纹理。
重要提示:许多OpenGL ES API调用以屏幕像素表示维度。如果使用大于1.0的比例因子,则应在使用glScissor,glBlitFramebuffer,glLineWidth或glPointSize函数或gl_PointSize着色器变量时相应调整维度。
确定如何支持高分辨率显示器的一个重要因素是性能。视网膜显示屏上的比例因子倍增了像素数量的四倍,导致GPU处理了四倍的片段。如果您的应用程序执行许多每个片段的计算,像素的增加可能会降低帧速率。如果您发现您的应用程序在较高比例因子下运行速度显着较慢,请考虑以下选项之一
- 使用本文档中的性能调整指南优化片段着色器的性能。
- 在片段着色器中实现更简单的算法。通过这样做,您正在降低单个像素的质量,以更高的分辨率渲染整体图像。
- 使用1.0之间的分数比例因子和屏幕的比例因子。比例因子1.5提供比1.0的比例因子更好的质量,但是需要填充比图像缩放到2.0的像素少的像素。
- 对于GLKView对象的drawableColorFormat和drawableDepthFormat属性使用较低精度的格式。通过这样做,可以减少在底层渲染缓冲区上操作所需的内存带宽。
- 使用较小比例因子并启用多重采样。另外一个优点是,多采样也可以在不支持高分辨率显示器的设备上提供更高的质量。
要为GLKView对象启用多重采样,请更改其drawableMultisample属性的值。如果没有渲染到GLKit视图,则必须手动设置多采样缓冲区并在呈现最终图像之前对其进行解析(请参阅使用多重采样来提高图像质量)。
多次采样不是免费的;需要额外的内存来存储附加样本,并将样本解析为解析帧缓冲区需要时间。如果您向应用程序添加多重采样,请始终测试应用程序的性能,以确保其仍然可以接受。
支持多接口定向
像任何应用程序一样,OpenGL ES应用程序应支持与其内容相适应的用户界面方向。您可以在其信息属性列表中为您的应用程序声明支持的接口方向,或者使用supportedInterfaceOrientations方法来托管OpenGL ES内容的视图控制器。 (有关详细信息,请参阅iOS的View Controller编程指南。)
默认情况下,GLKViewController和GLKView类自动处理方向更改:当用户将设备旋转到受支持的方向时,系统会动态定向更改并更改视图控制器视图的大小。当其大小更改时,GLKView对象会相应调整其帧缓冲区和视口的大小。如果需要响应此更改,请在GLKViewController子类中实现viewWillLayoutSubviews或viewDidLayoutSubviews方法,如果使用自定义GLKView子类,则实现layoutSubviews方法。
如果您使用Core Animation图层绘制OpenGL ES内容,则应用程序仍应包含一个视图控制器来管理用户界面方向。
在外部显示器上呈现OpenGL ES内容
iOS设备可以连接到外部显示器。外部显示器的分辨率及其内容比例因子可能与主屏幕的分辨率和比例因子不同;您渲染框架的代码应该调整为匹配。
在外部显示器上绘制的步骤与在主屏幕上运行的程序几乎相同。
- 按照“多显示器编程指南”中的步骤,在外部显示器上创建一个窗口。
- 将窗口添加到适当的视图或查看控制器对象以用于渲染策略
- 如果使用GLKit渲染,请设置GLKViewController和GLKView(或您的自定义子类)的实例,并使用其rootViewController属性将其添加到窗口。
- 如果渲染到Core Animation图层,请将包含图层的视图添加为窗口的子视图。要使用动画循环进行渲染,请通过检索窗口的屏幕属性并调用其DisplayLinkWithTarget:selector:method来创建为外部显示优化的显示链接对象。