配置OpenGL ES上下文
OpenGL ES规范中通过对OpenGL ES的每一个实现提供一种方式来创建渲染上下文,来管理所需的状态。通过将这种状态的情况下,多个应用程序可以轻松地共享显卡硬件而不受其他的状态干预。
本章详细介绍了在iOS环境如何创建和配置上下文。
EAGL是一个OpenGL ES渲染上下文的iOS的实现
应用程序可以调用任何的OpenGL ES的功能,但它必须初始化一个EAGLContext对象。该EAGLContext类还提供了用于集成OpenGLES的内容与核心动画的方法。
在当前上下文调用目标OpenGL ES函数
在iOS应用程序的每个线程都有一个当前上下文;当你调用一个OpenGL ES的功能,这就是上下文 它的状态是由调用改变。线程保持着strongEAGLContext对象。
在执行时:要设置一个线程的当前上下文,在该线程中调用EAGLContext类方法setCurrentContext。
[EAGLContextsetCurrentContext: myContext];
调用EAGLContext类方法currentContext检索线程的当前上下文。
注意:如果您的应用程序在同一个线程两个或多个上下文之间动态切换,在设置一个新的上下文作为当前上下文之前调用glFlush函数。这确保了先前提交的指令及时传递到图形硬件。
每个上下文都有OpenGL ES的特定版本
一个EAGLContext对象只支持一个版本的OpenGL ES的。例如,OpenGLES 1.1和OpenGLES2.0或3.0上下文是不兼容的。使用核心的OpenGLES2.0功能的代码兼容OpenGLES3.0的上下文,和OpenGLES 2.0的扩展以往可以在一被使用在OpenGLES3.0范围内有轻微的变化。许多新的OpenGLES3.0功能,增加的硬件功能需要一个OpenGLES3.0的上下文。
应用程序决定使用OpenGL ES的哪个版本时,它会创建支持和初始化EAGLContext对象。如果设备不支持OpenGLES中,initWithAPI的请求的版本:方法返回 无。应用必须进行测试,以确保上下文中使用它之前初始化成功。
为了在应用程序支持OpenGL ES的多个版本渲染选项,首先尝试 初始化希望的目标最新版本渲染上下文。如果返回的对象是零,初始化 较旧版本的上下文来代替。清单2-1演示了如何做到这一点。
清单2-1在同一应用程序中支持多个版本的OpenGL ES
EAGLContext*CreateBestEAGLContext()
{
EAGLContext*context = [[EAGLContext alloc]
initWithAPI:kEAGLRenderingAPIOpenGLES3];
if(context == nil) {
context= [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
}
returncontext;
}
一个上下文API的属性状态由OpenGL ES版本的上下文支持。应用程序将测试 上下文的API的属性,并使用它来选择正确的渲染路径。一个常见的模式实现是创建一个类的每个渲染路径;应用程序在初始化时测试上下文,并且每个渲染创建一次。
EAGL Sharegroup管理OpenGL ES对象上下文
虽然后台冻结了OpenGL ES的状态,它不直接管理的OpenGLES对象。相反, 由一个EAGLSharegroup对象创建和维护的OpenGLES对象。每个上下文包含一个EAGLSharegroup对象,委托其他对象创建。
共享组的优点是显而易见的,当两个或多个上下文指的是同一sharegroup, 如图2-1所示。当多个上下文连接到一个共同的sharegroup,OpenGLES的对象可在所有的环境中的任何上下文中创建的;如果绑定到同一个对象标识符在另一语境比创建它的一个,你引用相同的OpenGLES对象。资源往往是稀缺的移动设备;对多个上下文创建相同内容的多个副本是一种浪费。分享共同的资源使得在设备上更好地利用可用图形资源。
共享组是一个不透明的物体;它没有任何方法或您的应用程序可以调用属性。使用上下文共享组对象保持一个强有力的参考吧。
图2-1两个上下文共享的OpenGL ES对象
Sharegroups在两种特定的情况下非常有用:
● 当大多数的上下文之间共享的资源是不变的。
● 当应用程序想在别的线程而不是主线程中创建OpenGLES对象用于渲染。在这种情况下,第二个上下文在分离的线程里运行、获 数据和创建资源。资源被加载之后,第一个上下文可以立即绑定到对象并使用。GLKTextureLoader类使用这个模式来提供异步纹理加载。
若要在相同sharegroup里创建并引用多个上下文,第一个上下文必须通过调用initWithAPI:;一个sharegroup为上下文自动创建的。第二和后面的上下文是第一个上下文通过调用initWithAPI:sharegroup:方法来代替。 清单2-2显示了它们如何工作。第一个上下文使用便利函数创建,见清单2-1(第18页)。第二上下文是由第一个上下文通过从扩展的API版本和sharegroup创建。
重要提示:与同sharegroup相关联的所有上下文必须使用OpenGL ES的相同版本API作为初始上下文。
清单2-2 在一个共同的sharegroup里创建两个上下文
EAGLContext*firstContext = CreateBestEAGLContext();
EAGLContext*secondContext = [[EAGLContext alloc] initWithAPI:[firstContext API]
sharegroup:[firstContext sharegroup]];
应用程序负责管理状态更改为OpenGL ES的对象时的共享组是共享的 由多个上下文。下面是规则:
● 应用程序可以访问的对象横跨同时提供多个上下文对象不能被修改。
● 当对象是由发送到上下文中的命令修改,该对象在任何其他上下文中不能被读取或修改。
● 一个对象被修改后,所有的上下文必须绑定对象的变化。对象上下文在上下文绑定之前它的引用是不确定的。
下列步骤是应用程序应遵循,以更新的OpenGL ES对象:
1、 对可能使用对象的每个上下文中调用glFlush。
2、 在想要修改的对象的上下文,调用一个或多个OpenGL ES的函数来改变对象。
3、 对所收到的状态修改命令的上下文中调用glFlush。
4、 其他情况下,重新绑定的对象标识符
注:另一种共享的对象是使用单一的渲染上下文,多个目标帧缓冲。在渲染时,应用程序绑定相应的帧缓冲区,并根据需要显示帧。因为所有的OpenGLES对象都从一个单一上下文引用,他们看到同样的OpenGLES的数据。此模式使用更少的资源,但只适用于单线程的应用程序,在这里你可以仔细对照上下文的状态。