(Apple Documentation) OpenGL ES Programming Guide - Configuring OpenGL ES Contexts(译)

OpenGL ES的每个实现都提供了一种创建渲染上下文的方法,渲染上下文用来管理OpenGL ES规范所需的状态。通过将此状态置于上下文中,多个应用程序可以轻松共享图形硬件而不会干扰到对方的状态。本章详细介绍了如何在iOS中创建和配置上下文。

EAGL是iOS中 OpenGL ES 渲染上下文的实现

在您的应用程序调用任何OpenGL ES函数之前,必须初始化 EAGLContext 对象。 EAGLContext类还提供了用于将OpenGL ES内容与Core Animation集成的方法。

当前上下文是OpenGL ES中函数调用后作用的目标

iOS应用中的每个线程都有一个当前上下文; 当您调用OpenGL ES函数时,将会修改这个上下文中的状态信息。若要设置线程的当前上下文,请在该线程上调用EAGLContext的类方法 setCurrentContext:。

[EAGLContext setCurrentContext: myContext];

调用EAGLContext类的currentContext方法则可以获取线程的当前上下文。

注意: 如果您的应用程序在同一个线程上切换上下文,请在设置新的当前上下文之前调用glFlush函数。 这可以确保先前提交的命令能及时的传递到图形硬件。

OpenGL ES会对EAGLContext对象进行强引用。 (如果使用手动引用计数,OpenGL ES将retains此对象。)当您调用 setCurrentContext: 方法更改当前上下文时,OpenGL ES将不再引用先前的上下文。(如果使用手动引用计数,OpenGL ES将释放EAGLContext对象。)为防止EAGLContext对象在不是当前上下文时被释放,您的应用必须确保持有这些对象。

每个上下文都与一个特定版本的OpenGL ES关联

每个 EAGLContext 对象仅支持一个版本的OpenGL ES。 例如,为OpenGL ES 1.1编写的代码与OpenGL ES 2.0或3.0上下文不兼容。 使用OpenGL ES 2.0功能的代码与OpenGL ES 3.0上下文兼容,并且为OpenGL ES 2.0扩展而设计的代码通常可以在OpenGL ES 3.0上下文中使用,只需稍作更改即可。 许多OpenGL ES 3.0中的新功能和硬件增强功能都需要OpenGL ES 3.0上下文。

您的应用需要在创建和初始化EAGLContext对象时决定支持哪个版本的OpenGL ES。 如果设备不支持所请求的OpenGL ES版本,则 initWithAPI: 方法会返回nil。 您的应用必须进行测试以确保在使用上下文之前已成功对它进行了初始化。

要在应用程序中支持多个版本的OpenGL ES作为渲染选项,您应首先尝试初始化最新版本的渲染上下文。 如果返回的对象为nil,则初始化旧版本的上下文。 2-1演示了如何执行此操作。

Listing 2-1 同一个app中支持不同版本的 OpenGL ES
EAGLContext* CreateBestEAGLContext()
{
   EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
   if (context == nil) {
      context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
   }
   return context;
}

上下文对象的API属性说明了上下文对象所支持的OpenGL ES版本。 您的应用应检查上下文对象的api属性,并使用它来选择正确的渲染路径。 通常做法是为每个渲染路径创建一个类。 您的应用程序在初始化时检查上下文对象并创建一次渲染器。

EAGL Sharegroup管理上下文中的OpenGL ES对象

虽然上下文保存着OpenGL ES的状态,但它不直接管理OpenGL ES对象。 相反,OpenGL ES对象由 EAGLSharegroup 对象创建和维护。 Every context contains an EAGLSharegroup object that it delegates object creation to。

当两个或多个上下文引用相同的sharegroup时,sharegroup的优势就会很明显,如图2-1所示。 当多个上下文连接到一个公共sharegroup时,任何上下文创建的OpenGL ES对象都可在所有上下文中使用; 如果在一个上下文中绑定到另一个上下文所创建的对象标识符,那么这两个上下文引用的OpenGL ES对象是相同的。 移动设备上的资源往往很少; 在多个上下文中创建相同内容的多个副本是很浪费的。 共享公共资源可以更好地利用设备上的可用图像资源。

sharegroup是一个不透明对象; 它没有您的应用可以调用的方法或属性。 使用了sharegroup对象的上下文将会对它进行强引用。

Figure 2-1 Two contexts sharing OpenGL ES objects
(Apple Documentation) OpenGL ES Programming Guide - Configuring OpenGL ES Contexts(译)_第1张图片Sharegroup 在两个场景下比较常见:

  • 当上下文之间共享的大多数资源不变时。
  • 当您希望应用程序能在非主线程上为渲染器创建新的OpenGL ES对象时。 在这种情况下,第二个上下文在单独的线程上运行,并专门用于获取数据和创建资源。 当资源加载后,第一个上下文可以绑定到相应的对象并立即使用它。GLKTextureLoader 类使用此模式提供异步纹理加载。

要创建多个引用同一个sharegroup的上下文,可以通过调用 initWithAPI: 来初始化第一个上下文, 接着这个上下文就会自动创建sharegroup对象。 之后创建上下文时,通过调用 initWithAPI:sharegroup: 来引用第一个上下文的sharegroup。

Listing 2-2 进行了演示。 第一个上下文是使用Listing 2-1中定义的便捷函数创建的。 通过从第一个上下文中提取API版本和共享组来创建第二个上下文。

要点:所有引用同一个sharegroup的上下文必须使用相同版本的OpenGL ES API。

Listing 2-2 Creating two contexts with a common sharegroup

EAGLContext* firstContext = CreateBestEAGLContext();
EAGLContext* secondContext = [[EAGLContext alloc] initWithAPI:[firstContext API] sharegroup: [firstContext sharegroup]];

当多个上下文共享sharegroup时,您的应用程序负责管理OpenGL ES对象的状态更改。 以下是规则:

  • 如果对象没有正在被修改,那么你的应用可以同时跨多个上下文访问该对象。
  • 当发送到上下文的命令正在修改对象时,那么该对象不得在任何其他上下文中读取或修改。
  • 修改对象后,所有上下文必须重新绑定该对象。 如果上下文在绑定之前引用它,则该对象的内容是未定义的。

以下是应用程序更新OpenGL ES对象时应遵循的步骤:

  1. 在可能正在使用该对象的每个上下文上调用glFlush。
  2. 在要修改对象的上下文中,调用一个或多个OpenGL ES函数来更改对象。
  3. 在接收状态修改命令的上下文中调用glFlush。
  4. 在每个其他上下文中,重新绑定(rebind)对象标识符。

注意:共享对象的另一种方法是使用单个渲染上下文和使用多个目标帧缓冲区。 在渲染时,您的应用程序绑定合适的帧缓冲区并根据需要渲染其帧。 由于所有OpenGL ES对象都是从单个上下文引用的,因此它们会看到相同的OpenGL ES数据。 此模式占用资源较少,但仅适用于可以仔细控制上下文状态的单线程应用程序。

你可能感兴趣的:(文章翻译)